diff options
384 files changed, 9153 insertions, 9235 deletions
diff --git a/.clang-format b/.clang-format index 9547fe1b77..dcfd0aad60 100644 --- a/.clang-format +++ b/.clang-format @@ -12,7 +12,15 @@ UseTab: Always TabWidth: 8 IndentWidth: 8 ContinuationIndentWidth: 8 -ColumnLimit: 80 + +# While we do want to enforce a character limit of 80 characters, we often +# allow lines to overflow that limit to prioritize readability. Setting a +# character limit here with penalties has been finicky and creates too many +# false positives. +# +# NEEDSWORK: It would be nice if we can find optimal settings to ensure we +# can re-enable the limit here. +ColumnLimit: 0 # C Language specifics Language: Cpp @@ -210,16 +218,11 @@ MaxEmptyLinesToKeep: 1 # No empty line at the start of a block. KeepEmptyLinesAtTheStartOfBlocks: false -# Penalties -# This decides what order things should be done if a line is too long -PenaltyBreakAssignment: 5 -PenaltyBreakBeforeFirstCallParameter: 5 -PenaltyBreakComment: 5 -PenaltyBreakFirstLessLess: 0 -PenaltyBreakOpenParenthesis: 300 -PenaltyBreakString: 5 -PenaltyExcessCharacter: 10 -PenaltyReturnTypeOnItsOwnLine: 300 - # Don't sort #include's SortIncludes: false + +# Remove optional braces of control statements (if, else, for, and while) +# according to the LLVM coding style. This avoids braces on simple +# single-statement bodies of statements but keeps braces if one side of +# if/else if/.../else cascade has multi-statement body. +RemoveBracesLLVM: true diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7dbf9f7f12..d122e79415 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -298,7 +298,7 @@ jobs: path: build - name: Test shell: pwsh - run: meson test -C build --list | Select-Object -Skip 1 | Select-String .* | Group-Object -Property { $_.LineNumber % 10 } | Where-Object Name -EQ ${{ matrix.nr }} | ForEach-Object { meson test -C build --no-rebuild --print-errorlogs $_.Group } + run: meson test -C build --no-rebuild --print-errorlogs --slice "$(1+${{ matrix.nr }})/10" regular: name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}}) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bb6d5b976c..af10ebb59a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -178,7 +178,7 @@ test:msvc-meson: - job: "build:msvc-meson" artifacts: true script: - - meson test -C build --list | Select-Object -Skip 1 | Select-String .* | Group-Object -Property { $_.LineNumber % $Env:CI_NODE_TOTAL + 1 } | Where-Object Name -EQ $Env:CI_NODE_INDEX | ForEach-Object { meson test -C build --no-rebuild --print-errorlogs $_.Group; if (!$?) { exit $LASTEXITCODE } } + - meson test -C build --no-rebuild --print-errorlogs --slice $Env:CI_NODE_INDEX/$Env:CI_NODE_TOTAL parallel: 10 test:fuzz-smoke-tests: diff --git a/Documentation/BreakingChanges.adoc b/Documentation/BreakingChanges.adoc index c6bd94986c..f8d2eba061 100644 --- a/Documentation/BreakingChanges.adoc +++ b/Documentation/BreakingChanges.adoc @@ -118,6 +118,53 @@ Cf. <2f5de416-04ba-c23d-1e0b-83bb655829a7@zombino.com>, <20170223155046.e7nxivfwqqoprsqj@LykOS.localdomain>, <CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@mail.gmail.com>. +* The default storage format for references in newly created repositories will + be changed from "files" to "reftable". The "reftable" format provides + multiple advantages over the "files" format: ++ + ** It is impossible to store two references that only differ in casing on + case-insensitive filesystems with the "files" format. This issue is common + on Windows and macOS platforms. As the "reftable" backend does not use + filesystem paths to encode reference names this problem goes away. + ** Similarly, macOS normalizes path names that contain unicode characters, + which has the consequence that you cannot store two names with unicode + characters that are encoded differently with the "files" backend. Again, + this is not an issue with the "reftable" backend. + ** Deleting references with the "files" backend requires Git to rewrite the + complete "packed-refs" file. In large repositories with many references + this file can easily be dozens of megabytes in size, in extreme cases it + may be gigabytes. The "reftable" backend uses tombstone markers for + deleted references and thus does not have to rewrite all of its data. + ** Repository housekeeping with the "files" backend typically performs + all-into-one repacks of references. This can be quite expensive, and + consequently housekeeping is a tradeoff between the number of loose + references that accumulate and slow down operations that read references, + and compressing those loose references into the "packed-refs" file. The + "reftable" backend uses geometric compaction after every write, which + amortizes costs and ensures that the backend is always in a + well-maintained state. + ** Operations that write multiple references at once are not atomic with the + "files" backend. Consequently, Git may see in-between states when it reads + references while a reference transaction is in the process of being + committed to disk. + ** Writing many references at once is slow with the "files" backend because + every reference is created as a separate file. The "reftable" backend + significantly outperforms the "files" backend by multiple orders of + magnitude. + ** The reftable backend uses a binary format with prefix compression for + reference names. As a result, the format uses less space compared to the + "packed-refs" file. ++ +Users that get immediate benefit from the "reftable" backend could continue to +opt-in to the "reftable" format manually by setting the "init.defaultRefFormat" +config. But defaults matter, and we think that overall users will have a better +experience with less platform-specific quirks when they use the new backend by +default. ++ +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. + === Removals * Support for grafting commits has long been superseded by git-replace(1). diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 6350949f2e..224f0978a8 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -298,6 +298,17 @@ For C programs: . since late 2021 with 44ba10d6, we have had variables declared in the for loop "for (int i = 0; i < 10; i++)". + . since late 2023 with 8277dbe987 we have been using the bool type + from <stdbool.h>. + + C99 features we have test balloons for: + + . since late 2024 with v2.48.0-rc0~20, we have test balloons for + compound literal syntax, e.g., (struct foo){ .member = value }; + our hope is that no platforms we care about have trouble using + them, and officially adopt its wider use in mid 2026. Do not add + more use of the syntax until that happens. + New C99 features that we cannot use yet: . %z and %zu as a printf() argument for a size_t (the %z being for @@ -613,8 +624,9 @@ For C programs: - `S_init()` initializes a structure without allocating the structure itself. - - `S_release()` releases a structure's contents without freeing the - structure. + - `S_release()` releases a structure's contents without reinitializing + the structure for immediate reuse, and without freeing the structure + itself. - `S_clear()` is equivalent to `S_release()` followed by `S_init()` such that the structure is directly usable after clearing it. When diff --git a/Documentation/RelNotes/2.51.0.adoc b/Documentation/RelNotes/2.51.0.adoc index 40920e6495..a89d459d2e 100644 --- a/Documentation/RelNotes/2.51.0.adoc +++ b/Documentation/RelNotes/2.51.0.adoc @@ -40,6 +40,33 @@ UI, Workflows & Features client, instead of retrying, it skipped it by mistake, which has been corrected. + * The reftable ref backend has matured enough; Git 3.0 will make it + the default format in a newly created repositories by default. + + * "netrc" credential helper has been improved to understand textual + service names (like smtp) in addition to the numeric port numbers + (like 25). + + * Lift the limitation to use changed-path filter in "git log" so that + it can be used for a pathspec with multiple literal paths. + + * Clean up the way how signature on commit objects are exported to + and imported from fast-import stream. + + * Remove unsupported, unused, and unsupportable old option from "git + log". + + * Document recently added "git imap-send --list" with an example. + + * "git pull" learned to pay attention to pull.autostash configuration + variable, which overrides rebase/merge.autostash. + + * "git for-each-ref" learns "--start-after" option to help + applications that want to page its output. + + * "git switch" and "git restore" are declared to be no longer + experimental. + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -65,6 +92,50 @@ Performance, Internal Implementation, Development Support etc. * "git push" and "git fetch" are taught to update refs in batches to gain performance. + * Some code paths in the "git prune" used to ignore passed in + repository object and used the_repository singleton instance + instead, which has been corrected. + + * Update ".clang-format" and ".editorconfig" to match our style guide + a bit better. + + * "make coccicheck" succeeds even when spatch made suggestions, which + has been updated to fail in such a case. + + * Code clean-up around object access API. + + * Define .precision to more canned parse-options type to avoid bugs + coming from using a variable with a wrong type to capture the + parsed values. + + * Flipping the default hash function to SHA-256 at Git 3.0 boundary + is planned. + + * Declare weather-balloon we raised for "bool" type 18 months ago a + success and officially allow using the type in our codebase. + + * GIT_TEST_INSTALLED was not honored in the recent topic related to + SHA256 hashes, which has been corrected. + + * The pop_most_recent_commit() function can have quite expensive + worst case performance characteristics, which has been optimized by + using prio-queue data structure. + + * Move structure definition from unrelated header file to where it + belongs. + + * To help our developers, document what C99 language features are + being considered for adoption, in addition to what past experiments + have already decided. + + * The reftable unit tests are now ported to the "clar" unit testing + framework. + + * Redefine where the multi-pack-index sits in the object subsystem, + which recently was restructured to allow multiple backends that + support a single object source that belongs to one repository. A + midx does span mulitple "object sources". + Fixes since v2.50 ----------------- @@ -117,8 +188,101 @@ including security updates, are included in this release. * Remove unnecessary check from "git daemon" code. (merge 0c856224d2 cb/daemon-fd-check-fix later to maint). - * Leakfix. - (merge b0e9d25865 jk/fix-leak-send-pack later to maint). + * Use of sysctl() system call to learn the total RAM size used on + BSDs has been corrected. + (merge 781c1cf571 cb/total-ram-bsd-fix later to maint). + + * Drop FreeBSD 4 support and declare that we support only FreeBSD 12 + or later, which has memmem() supported. + (merge 0392f976a7 bs/config-mak-freebsd later to maint). + + * A diff-filter with negative-only specification like "git log + --diff-filter=d" did not trigger correctly, which has been fixed. + (merge 375ac087c5 jk/all-negative-diff-filter-fix later to maint). + + * A failure to open the index file for writing due to conflicting + access did not state what went wrong, which has been corrected. + (merge 9455397a5c hy/read-cache-lock-error-fix later to maint). + + * Tempfile removal fix in the codepath to sign commits with SSH keys. + (merge 4498127b04 re/ssh-sign-buffer-fix later to maint). + + * Code and test clean-up around string-list API. + (merge 6e5b26c3ff sj/string-list later to maint). + + * "git apply -N" should start from the current index and register + only new files, but it instead started from an empty index, which + has been corrected. + (merge 2b49d97fcb rp/apply-intent-to-add-fix later to maint). + + * Leakfix with a new and a bit invasive test on pack-bitmap files. + (merge bfd5522e98 ly/load-bitmap-leakfix later to maint). + + * "git fetch --prune" used to be O(n^2) expensive when there are many + refs, which has been corrected. + (merge 87d8d8c5d0 ph/fetch-prune-optim later to maint). + + * When a ref creation at refs/heads/foo/bar fails, the files backend + now removes refs/heads/foo/ if the directory is otherwise not used. + (merge a3a7f20516 ps/refs-files-remove-empty-parent later to maint). + + * "pack-objects" has been taught to avoid pointing into objects in + cruft packs from midx. + + * "git remote" now detects remote names that overlap with each other + (e.g., remote nickname "outer" and "outer/inner" are used at the + same time), as it will lead to overlapping remote-tracking + branches. + (merge a5a727c448 jk/remote-avoid-overlapping-names later to maint). + + * The gpg.program configuration variable, which names a pathname to + the (custom) GPG compatible program, can now be spelled with ~tilde + expansion. + (merge 7d275cd5c0 jb/gpg-program-variable-is-a-pathname later to maint). + + * Our <sane-ctype.h> header file relied on that the system-supplied + <ctype.h> header is not later included, which would override our + macro definitions, but "amazon linux" broke this assumption. Fix + this by preemptively including <ctype.h> near the beginning of + <sane-ctype.h> ourselves. + (merge 9d3b33125f ps/sane-ctype-workaround later to maint). + + * Clean-up compat/bswap.h mess. + (merge f4ac32c03a ss/compat-bswap-revamp later to maint). + + * Meson-based build did not handle libexecdir setting correctly, + which has been corrected. + (merge 056dbe8612 rj/meson-libexecdir-fix later to maint). + + * Document that we do not require "real" name when signing your + patches off. + (merge 1f0fed312a bc/contribution-under-non-real-names later to maint). + + * "git commit" that concludes a conflicted merge failed to notice and remove + existing comment added automatically (like "# Conflicts:") when the + core.commentstring is set to 'auto'. + (merge 92b7c7c9f5 ac/auto-comment-char-fix later to maint). + + * "git rebase -i" with bogus rebase.instructionFormat configuration + failed to produce the todo file after recording the state files, + leading to confused "git status"; this has been corrected. + (merge ade14bffd7 ow/rebase-verify-insn-fmt-before-initializing-state later to maint). + + * A few file descriptors left unclosed upon program completion in a + few test helper programs are now closed. + (merge 0f1b33815b hl/test-helper-fd-close later to maint). + + * Interactive prompt code did not correctly strip CRLF from the end + of line on Windows. + (merge 711a20827b js/prompt-crlf-fix later to maint). + + * The config API had a set of convenience wrapper functions that + implicitly use the_repository instance; they have been removed and + inlined at the calling sites. + + * "git add/etc -p" now honor the diff.context configuration variable, + and also they learn to honor the -U<n> command-line option. + (merge 2b3ae04011 lm/add-p-context later to maint). * Other code cleanup, docfix, build fix, etc. (merge b257adb571 lo/my-first-ow-doc-update later to maint). @@ -136,3 +300,23 @@ including security updates, are included in this release. (merge ff73f375bb jg/mailinfo-leakfix later to maint). (merge 996f14c02b jj/doc-branch-markup-fix later to maint). (merge 1e77de1864 cb/ci-freebsd-update-to-14.3 later to maint). + (merge b0e9d25865 jk/fix-leak-send-pack later to maint). + (merge f3a9558c8c bs/remote-helpers-doc-markup-fix later to maint). + (merge c4e9775c60 kh/doc-config-subcommands later to maint). + (merge de404249ab ps/perlless-test-fixes later to maint). + (merge 953049eed8 ts/merge-orig-head-doc-fix later to maint). + (merge 0c83bbc704 rj/freebsd-sysinfo-build-fix later to maint). + (merge ad7780b38f ps/doc-pack-refs-auto-with-files-backend-fix later to maint). + (merge f4fa8a3687 rh/doc-glob-pathspec-fix later to maint). + (merge b27be108c8 ja/doc-git-log-markup later to maint). + (merge 14d7583beb pw/config-kvi-remove-path later to maint). + (merge f31abb421d jc/do-not-scan-argv-without-parsing later to maint). + (merge 26552cb62a jk/unleak-reflog-expire-entry later to maint). + (merge 339d95fda9 jc/ci-print-test-failures-fix later to maint). + (merge 8c3add51a8 cb/meson-avoid-broken-macos-pcre2 later to maint). + (merge 5247da07b8 ps/meson-clar-decls-fix later to maint). + (merge f3ef347bb2 ch/t7450-recursive-clone-test-fix later to maint). + (merge 4ac3302a1a jc/doc-release-vs-clear later to maint). + (merge 3bdd897413 ms/meson-with-ancient-git-wo-ls-files-dedup later to maint). + (merge cca758d324 kh/doc-fast-import-historical later to maint). + (merge 9b0781196a jc/test-hashmap-is-still-here later to maint). diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 958e3cc3d5..86ca7f6a78 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -408,8 +408,15 @@ your patch differs from project to project, so it may be different from that of the project you are accustomed to. [[real-name]] -Also notice that a real name is used in the `Signed-off-by` trailer. Please -don't hide your real name. +Please use a known identity in the `Signed-off-by` trailer, since we cannot +accept anonymous contributions. It is common, but not required, to use some form +of your real name. We realize that some contributors are not comfortable doing +so or prefer to contribute under a pseudonym or preferred name and we can accept +your patch either way, as long as the name and email you use are distinctive, +identifying, and not misleading. + +The goal of this policy is to allow us to have sufficient information to contact +you if questions arise about your contribution. [[commit-trailers]] If you like, you can put extra trailers at the end: diff --git a/Documentation/asciidoc.conf.in b/Documentation/asciidoc.conf.in index 9d9139306e..ff9ea0a294 100644 --- a/Documentation/asciidoc.conf.in +++ b/Documentation/asciidoc.conf.in @@ -43,7 +43,7 @@ ifdef::doctype-book[] endif::doctype-book[] [literal-inlinemacro] -{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'<emphasis>\1</emphasis>', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@\\\*\/_^\$]+\.?)+|,)',r'\1<literal>\2</literal>', re.sub(r'(\.\.\.?)([^\]$.])', r'<literal>\1</literal>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))} +{eval:re.sub(r'(<[-a-zA-Z0-9.]+>)', r'<emphasis>\1</emphasis>', re.sub(r'([\[\s|()>]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@\\\*\/_^\$%]+\.?)+|,)',r'\1<literal>\2</literal>', re.sub(r'(\.\.\.?)([^\]$.])', r'<literal>\1</literal>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))} endif::backend-docbook[] diff --git a/Documentation/asciidoctor-extensions.rb.in b/Documentation/asciidoctor-extensions.rb.in index 8b7b161349..fe64a62d96 100644 --- a/Documentation/asciidoctor-extensions.rb.in +++ b/Documentation/asciidoctor-extensions.rb.in @@ -73,7 +73,7 @@ module Git elsif type == :monospaced node.text.gsub(/(\.\.\.?)([^\]$\.])/, '<literal>\1</literal>\2') .gsub(/^\.\.\.?$/, '<literal>\0</literal>') - .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@/_^\$\\\*]+\.{0,2})+|,)}, '\1<literal>\2</literal>') + .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@/_^\$\\\*%]+\.{0,2})+|,)}, '\1<literal>\2</literal>') .gsub(/(<[-a-zA-Z0-9.]+>)/, '<emphasis>\1</emphasis>') else open, close, supports_phrase = QUOTE_TAGS[type] @@ -102,7 +102,7 @@ module Git if node.type == :monospaced node.text.gsub(/(\.\.\.?)([^\]$.])/, '<code>\1</code>\2') .gsub(/^\.\.\.?$/, '<code>\0</code>') - .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$\\\*]+\.{0,2})+)}, '\1<code>\2</code>') + .gsub(%r{([\[\s|()>.]|^|\]|>)(\.?([-a-zA-Z0-9:+=~@,/_^\$\\\*%]+\.{0,2})+)}, '\1<code>\2</code>') .gsub(/(<[-a-zA-Z0-9.]+>)/, '<em>\1</em>') else diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc index 9fde1ab63a..3fbe83eef1 100644 --- a/Documentation/config/core.adoc +++ b/Documentation/config/core.adoc @@ -696,12 +696,6 @@ core.unsetenvvars:: Defaults to `PERL5LIB` to account for the fact that Git for Windows insists on using its own Perl interpreter. -core.restrictinheritedhandles:: - Windows-only: override whether spawned processes inherit only standard - file handles (`stdin`, `stdout` and `stderr`) or all handles. Can be - `auto`, `true` or `false`. Defaults to `auto`, which means `true` on - Windows 7 and later, and `false` on older Windows versions. - core.createObject:: You can set this to 'link', in which case a hardlink followed by a delete of the source are used to make sure that object creation diff --git a/Documentation/config/feature.adoc b/Documentation/config/feature.adoc index cb49ff2604..924f5ff4e3 100644 --- a/Documentation/config/feature.adoc +++ b/Documentation/config/feature.adoc @@ -24,6 +24,12 @@ reusing objects from multiple packs instead of just one. * `pack.usePathWalk` may speed up packfile creation and make the packfiles be significantly smaller in the presence of certain filename collisions with Git's default name-hash. ++ +* `init.defaultRefFormat=reftable` causes newly initialized repositories to use +the reftable format for storing references. This new format solves issues with +case-insensitive filesystems, compresses better and performs significantly +better with many use cases. Refer to Documentation/technical/reftable.adoc for +more information on this new storage format. feature.manyFiles:: Enable config options that optimize for repos with many files in the diff --git a/Documentation/config/gpg.adoc b/Documentation/config/gpg.adoc index 5cf32b179d..240e46c050 100644 --- a/Documentation/config/gpg.adoc +++ b/Documentation/config/gpg.adoc @@ -1,5 +1,5 @@ gpg.program:: - Use this custom program instead of "`gpg`" found on `$PATH` when + Pathname of the program to use instead of "`gpg`" when making or verifying a PGP signature. The program must support the same command-line interface as GPG, namely, to verify a detached signature, "`gpg --verify $signature - <$file`" is run, and the diff --git a/Documentation/config/log.adoc b/Documentation/config/log.adoc index a9b160e7de..16e00e8d29 100644 --- a/Documentation/config/log.adoc +++ b/Documentation/config/log.adoc @@ -1,5 +1,5 @@ -log.abbrevCommit:: - If true, makes +`log.abbrevCommit`:: + If `true`, make ifndef::with-breaking-changes[] linkgit:git-log[1], linkgit:git-show[1], and linkgit:git-whatchanged[1] @@ -10,62 +10,67 @@ endif::with-breaking-changes[] assume `--abbrev-commit`. You may override this option with `--no-abbrev-commit`. -log.date:: - Set the default date-time mode for the 'log' command. - Setting a value for log.date is similar to using 'git log''s +`log.date`:: + Set the default date-time mode for the `log` command. + Setting a value for log.date is similar to using `git log`'s `--date` option. See linkgit:git-log[1] for details. + If the format is set to "auto:foo" and the pager is in use, format "foo" will be used for the date format. Otherwise, "default" will be used. -log.decorate:: +`log.decorate`:: Print out the ref names of any commits that are shown by the log - command. If 'short' is specified, the ref name prefixes 'refs/heads/', - 'refs/tags/' and 'refs/remotes/' will not be printed. If 'full' is - specified, the full ref name (including prefix) will be printed. - If 'auto' is specified, then if the output is going to a terminal, - the ref names are shown as if 'short' were given, otherwise no ref - names are shown. This is the same as the `--decorate` option - of the `git log`. + command. Possible values are: ++ +---- +`short`;; the ref name prefixes `refs/heads/`, `refs/tags/` and + `refs/remotes/` are not printed. +`full`;; the full ref name (including prefix) are printed. +`auto`;; if the output is going to a terminal, + the ref names are shown as if `short` were given, otherwise no ref + names are shown. +---- ++ +This is the same as the `--decorate` option of the `git log`. -log.initialDecorationSet:: +`log.initialDecorationSet`:: By default, `git log` only shows decorations for certain known ref namespaces. If 'all' is specified, then show all refs as decorations. -log.excludeDecoration:: +`log.excludeDecoration`:: Exclude the specified patterns from the log decorations. This is similar to the `--decorate-refs-exclude` command-line option, but the config option can be overridden by the `--decorate-refs` option. -log.diffMerges:: +`log.diffMerges`:: Set diff format to be used when `--diff-merges=on` is specified, see `--diff-merges` in linkgit:git-log[1] for details. Defaults to `separate`. -log.follow:: +`log.follow`:: If `true`, `git log` will act as if the `--follow` option was used when a single <path> is given. This has the same limitations as `--follow`, i.e. it cannot be used to follow multiple files and does not work well on non-linear history. -log.graphColors:: +`log.graphColors`:: A list of colors, separated by commas, that can be used to draw history lines in `git log --graph`. -log.showRoot:: +`log.showRoot`:: If true, the initial commit will be shown as a big creation event. This is equivalent to a diff against an empty tree. Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which normally hide the root commit will now show it. True by default. -log.showSignature:: +`log.showSignature`:: If true, makes linkgit:git-log[1], linkgit:git-show[1], and linkgit:git-whatchanged[1] assume `--show-signature`. -log.mailmap:: +`log.mailmap`:: If true, makes linkgit:git-log[1], linkgit:git-show[1], and linkgit:git-whatchanged[1] assume `--use-mailmap`, otherwise assume `--no-use-mailmap`. True by default. diff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc index 9349e09261..125c930f72 100644 --- a/Documentation/config/pull.adoc +++ b/Documentation/config/pull.adoc @@ -29,5 +29,21 @@ pull.octopus:: The default merge strategy to use when pulling multiple branches at once. +pull.autoStash:: + When set to true, automatically create a temporary stash entry + to record the local changes before the operation begins, and + restore them after the operation completes. When your "git + pull" rebases (instead of merges), this may be convenient, since + unlike merging pull that tolerates local changes that do not + interfere with the merge, rebasing pull refuses to work with any + local changes. ++ +If `pull.autostash` is set (either to true or false), +`merge.autostash` and `rebase.autostash` are ignored. If +`pull.autostash` is not set at all, depending on the value of +`pull.rebase`, `merge.autostash` or `rebase.autostash` is used +instead. Can be overridden by the `--[no-]autostash` command line +option. + pull.twohead:: The default merge strategy to use when pulling a single branch. diff --git a/Documentation/config/repack.adoc b/Documentation/config/repack.adoc index c79af6d7b8..e9e78dcb19 100644 --- a/Documentation/config/repack.adoc +++ b/Documentation/config/repack.adoc @@ -39,3 +39,10 @@ repack.cruftThreads:: a cruft pack and the respective parameters are not given over the command line. See similarly named `pack.*` configuration variables for defaults and meaning. + +repack.midxMustContainCruft:: + When set to true, linkgit:git-repack[1] will unconditionally include + cruft pack(s), if any, in the multi-pack index when invoked with + `--write-midx`. When false, cruft packs are only included in the MIDX + when necessary (e.g., because they might be required to form a + reachability closure with MIDX bitmaps). Defaults to true. diff --git a/Documentation/config/sendemail.adoc b/Documentation/config/sendemail.adoc index 54f1248e64..4722334657 100644 --- a/Documentation/config/sendemail.adoc +++ b/Documentation/config/sendemail.adoc @@ -31,8 +31,8 @@ sendemail.confirm:: values. sendemail.mailmap:: - If true, makes linkgit:git-send-email[1] assume `--mailmap`, - otherwise assume `--no-mailmap`. False by default. + If `true`, makes linkgit:git-send-email[1] assume `--mailmap`, + otherwise assume `--no-mailmap`. `False` by default. sendemail.mailmap.file:: The location of a linkgit:git-send-email[1] specific augmenting @@ -96,6 +96,11 @@ sendemail.xmailer:: linkgit:git-send-email[1] command-line options. See its documentation for details. +sendemail.outlookidfix:: + If `true`, makes linkgit:git-send-email[1] assume `--outlook-id-fix`, + and if `false` assume `--no-outlook-id-fix`. If not specified, it will + behave the same way as if `--outlook-id-fix` is not specified. + sendemail.signedOffCc (deprecated):: Deprecated alias for `sendemail.signedOffByCc`. diff --git a/Documentation/diff-context-options.adoc b/Documentation/diff-context-options.adoc new file mode 100644 index 0000000000..e161260358 --- /dev/null +++ b/Documentation/diff-context-options.adoc @@ -0,0 +1,10 @@ +`-U<n>`:: +`--unified=<n>`:: + Generate diffs with _<n>_ lines of context. Defaults to `diff.context` + or 3 if the config option is unset. + +`--inter-hunk-context=<n>`:: + Show the context between diff hunks, up to the specified _<number>_ + of lines, thereby fusing hunks that are close to each other. + Defaults to `diff.interHunkContext` or 0 if the config option + is unset. diff --git a/Documentation/diff-options.adoc b/Documentation/diff-options.adoc index 640eb6e7db..f3a35d8141 100644 --- a/Documentation/diff-options.adoc +++ b/Documentation/diff-options.adoc @@ -37,32 +37,32 @@ endif::git-diff[] endif::git-format-patch[] ifdef::git-log[] --m:: +`-m`:: Show diffs for merge commits in the default format. This is similar to `--diff-merges=on`, except `-m` will produce no output unless `-p` is given as well. --c:: +`-c`:: Produce combined diff output for merge commits. Shortcut for `--diff-merges=combined -p`. ---cc:: +`--cc`:: Produce dense combined diff output for merge commits. Shortcut for `--diff-merges=dense-combined -p`. ---dd:: +`--dd`:: Produce diff with respect to first parent for both merge and regular commits. Shortcut for `--diff-merges=first-parent -p`. ---remerge-diff:: +`--remerge-diff`:: Produce remerge-diff output for merge commits. Shortcut for `--diff-merges=remerge -p`. ---no-diff-merges:: +`--no-diff-merges`:: Synonym for `--diff-merges=off`. ---diff-merges=<format>:: +`--diff-merges=<format>`:: Specify diff format to be used for merge commits. Default is {diff-merges-default} unless `--first-parent` is in use, in which case `first-parent` is the default. @@ -70,48 +70,54 @@ ifdef::git-log[] The following formats are supported: + -- -off, none:: +`off`:: +`none`:: Disable output of diffs for merge commits. Useful to override implied value. -on, m:: +`on`:: +`m`:: Make diff output for merge commits to be shown in the default format. The default format can be changed using `log.diffMerges` configuration variable, whose default value is `separate`. -first-parent, 1:: +`first-parent`:: +`1`:: Show full diff with respect to first parent. This is the same format as `--patch` produces for non-merge commits. -separate:: +`separate`:: Show full diff with respect to each of parents. Separate log entry and diff is generated for each parent. -combined, c:: +`combined`:: +`c`:: Show differences from each of the parents to the merge result simultaneously instead of showing pairwise diff between a parent and the result one at a time. Furthermore, it lists only files which were modified from all parents. -dense-combined, cc:: +`dense-combined`:: +`cc`:: Further compress output produced by `--diff-merges=combined` by omitting uninteresting hunks whose contents in the parents have only two variants and the merge result picks one of them without modification. -remerge, r:: - Remerge two-parent merge commits to create a temporary tree +`remerge`:: +`r`:: Remerge two-parent merge commits to create a temporary tree object--potentially containing files with conflict markers and such. A diff is then shown between that temporary tree and the actual merge commit. +-- + The output emitted when this option is used is subject to change, and so is its interaction with other options (unless explicitly documented). --- ---combined-all-paths:: + +`--combined-all-paths`:: Cause combined diffs (used for merge commits) to list the name of the file from all parents. It thus only has effect when `--diff-merges=[dense-]combined` is in use, and diff --git a/Documentation/git-add.adoc b/Documentation/git-add.adoc index eba0b419ce..b7a735824d 100644 --- a/Documentation/git-add.adoc +++ b/Documentation/git-add.adoc @@ -104,6 +104,8 @@ This effectively runs `add --interactive`, but bypasses the initial command menu and directly jumps to the `patch` subcommand. See ``Interactive mode'' for details. +include::diff-context-options.adoc[] + `-e`:: `--edit`:: Open the diff vs. the index in an editor and let the user diff --git a/Documentation/git-apply.adoc b/Documentation/git-apply.adoc index 952518b8af..6c71ee69da 100644 --- a/Documentation/git-apply.adoc +++ b/Documentation/git-apply.adoc @@ -75,13 +75,14 @@ OPTIONS tree. If `--check` is in effect, merely check that it would apply cleanly to the index entry. +-N:: --intent-to-add:: When applying the patch only to the working tree, mark new files to be added to the index later (see `--intent-to-add` - option in linkgit:git-add[1]). This option is ignored unless - running in a Git repository and `--index` is not specified. - Note that `--index` could be implied by other options such - as `--cached` or `--3way`. + option in linkgit:git-add[1]). This option is ignored if + `--index` or `--cached` are used, and has no effect outside a Git + repository. Note that `--index` could be implied by other options + such as `--3way`. -3:: --3way:: diff --git a/Documentation/git-checkout.adoc b/Documentation/git-checkout.adoc index ee83b6d9ba..40e02cfd65 100644 --- a/Documentation/git-checkout.adoc +++ b/Documentation/git-checkout.adoc @@ -289,6 +289,8 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode. Note that this option uses the no overlay mode by default (see also `--overlay`), and currently doesn't support overlay mode. +include::diff-context-options.adoc[] + `--ignore-other-worktrees`:: `git checkout` refuses when the wanted branch is already checked out or otherwise in use by another worktree. This option makes diff --git a/Documentation/git-commit.adoc b/Documentation/git-commit.adoc index dc219025f1..ae988a883b 100644 --- a/Documentation/git-commit.adoc +++ b/Documentation/git-commit.adoc @@ -76,6 +76,8 @@ OPTIONS which changes to commit. See linkgit:git-add[1] for details. +include::diff-context-options.adoc[] + `-C <commit>`:: `--reuse-message=<commit>`:: Take an existing _<commit>_ object, and reuse the log message diff --git a/Documentation/git-config.adoc b/Documentation/git-config.adoc index 936e0c5130..511b2e26bf 100644 --- a/Documentation/git-config.adoc +++ b/Documentation/git-config.adoc @@ -10,9 +10,9 @@ SYNOPSIS -------- [verse] 'git config list' [<file-option>] [<display-option>] [--includes] -'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name> -'git config set' [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value> -'git config unset' [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> +'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<pattern>] [--fixed-value] [--default=<default>] [--url=<url>] <name> +'git config set' [<file-option>] [--type=<type>] [--all] [--value=<pattern>] [--fixed-value] <name> <value> +'git config unset' [<file-option>] [--all] [--value=<pattern>] [--fixed-value] <name> 'git config rename-section' [<file-option>] <old-name> <new-name> 'git config remove-section' [<file-option>] <name> 'git config edit' [<file-option>] @@ -26,7 +26,7 @@ escaped. Multiple lines can be added to an option by using the `--append` option. If you want to update or unset an option which can occur on multiple -lines, a `value-pattern` (which is an extended regular expression, +lines, `--value=<pattern>` (which is an extended regular expression, unless the `--fixed-value` option is given) needs to be given. Only the existing values that match the pattern are updated or unset. If you want to handle the lines that do *not* match the pattern, just @@ -109,7 +109,7 @@ OPTIONS --replace-all:: Default behavior is to replace at most one line. This replaces - all lines matching the key (and optionally the `value-pattern`). + all lines matching the key (and optionally `--value=<pattern>`). --append:: Adds a new line to the option without altering any existing @@ -200,11 +200,19 @@ See also <<FILES>>. section in linkgit:gitrevisions[7] for a more complete list of ways to spell blob names. +`--value=<pattern>`:: +`--no-value`:: + With `get`, `set`, and `unset`, match only against + _<pattern>_. The pattern is an extended regular expression unless + `--fixed-value` is given. ++ +Use `--no-value` to unset _<pattern>_. + --fixed-value:: - When used with the `value-pattern` argument, treat `value-pattern` as + When used with `--value=<pattern>`, treat _<pattern>_ as an exact string instead of a regular expression. This will restrict the name/value pairs that are matched to only those where the value - is exactly equal to the `value-pattern`. + is exactly equal to _<pattern>_. --type <type>:: 'git config' will ensure that any input or output is valid under the given @@ -259,6 +267,12 @@ Valid `<type>`'s include: Output only the names of config variables for `list` or `get`. +`--show-names`:: +`--no-show-names`:: + With `get`, show config keys in addition to their values. The + default is `--no-show-names` unless `--url` is given and there + are no subsections in _<name>_. + --show-origin:: Augment the output of all queried config options with the origin type (file, standard input, blob, command line) and diff --git a/Documentation/git-fast-export.adoc b/Documentation/git-fast-export.adoc index 43bbb4f63c..297b57bb2e 100644 --- a/Documentation/git-fast-export.adoc +++ b/Documentation/git-fast-export.adoc @@ -50,6 +50,23 @@ resulting tag will have an invalid signature. is the same as how earlier versions of this command without this option behaved. + +When exported, a signature starts with: ++ +gpgsig <git-hash-algo> <signature-format> ++ +where <git-hash-algo> is the Git object hash so either "sha1" or +"sha256", and <signature-format> is the signature type, so "openpgp", +"x509", "ssh" or "unknown". ++ +For example, an OpenPGP signature on a SHA-1 commit starts with +`gpgsig sha1 openpgp`, while an SSH signature on a SHA-256 commit +starts with `gpgsig sha256 ssh`. ++ +While all the signatures of a commit are exported, an importer may +choose to accept only some of them. For example +linkgit:git-fast-import[1] currently stores at most one signature per +Git hash algorithm in each commit. ++ NOTE: This is highly experimental and the format of the data stream may change in the future without compatibility guarantees. diff --git a/Documentation/git-fast-import.adoc b/Documentation/git-fast-import.adoc index 250d866652..6f9763c11b 100644 --- a/Documentation/git-fast-import.adoc +++ b/Documentation/git-fast-import.adoc @@ -182,7 +182,7 @@ amount of memory usage and processing time. Assuming the frontend is able to keep up with fast-import and feed it a constant stream of data, import times for projects holding 10+ years of history and containing 100,000+ individual commits are generally completed in just 1-2 -hours on quite modest (~$2,000 USD) hardware. +hours on quite modest hardware (~$2,000 USD in 2007). Most bottlenecks appear to be in foreign source data access (the source just cannot extract revisions fast enough) or disk IO (fast-import @@ -445,7 +445,7 @@ one). original-oid? ('author' (SP <name>)? SP LT <email> GT SP <when> LF)? 'committer' (SP <name>)? SP LT <email> GT SP <when> LF - ('gpgsig' SP <alg> LF data)? + ('gpgsig' SP <algo> SP <format> LF data)? ('encoding' SP <encoding> LF)? data ('from' SP <commit-ish> LF)? @@ -518,13 +518,39 @@ their syntax. ^^^^^^^^ The optional `gpgsig` command is used to include a PGP/GPG signature -that signs the commit data. +or other cryptographic signature that signs the commit data. -Here <alg> specifies which hashing algorithm is used for this -signature, either `sha1` or `sha256`. +.... + 'gpgsig' SP <git-hash-algo> SP <signature-format> LF data +.... + +The `gpgsig` command takes two arguments: + +* `<git-hash-algo>` specifies which Git object format this signature + applies to, either `sha1` or `sha256`. This allows to know which + representation of the commit was signed (the SHA-1 or the SHA-256 + version) which helps with both signature verification and + interoperability between repos with different hash functions. + +* `<signature-format>` specifies the type of signature, such as + `openpgp`, `x509`, `ssh`, or `unknown`. This is a convenience for + tools that process the stream, so they don't have to parse the ASCII + armor to identify the signature type. + +A commit may have at most one signature for the SHA-1 object format +(stored in the "gpgsig" header) and one for the SHA-256 object format +(stored in the "gpgsig-sha256" header). + +See below for a detailed description of the `data` command which +contains the raw signature data. + +Signatures are not yet checked in the current implementation +though. (Already setting the `extensions.compatObjectFormat` +configuration option might help with verifying both SHA-1 and SHA-256 +object format signatures when it will be implemented.) -NOTE: This is highly experimental and the format of the data stream may -change in the future without compatibility guarantees. +NOTE: This is highly experimental and the format of the `gpgsig` +command may change in the future without compatibility guarantees. `encoding` ^^^^^^^^^^ diff --git a/Documentation/git-for-each-ref.adoc b/Documentation/git-for-each-ref.adoc index 5ef89fc0fe..060940904d 100644 --- a/Documentation/git-for-each-ref.adoc +++ b/Documentation/git-for-each-ref.adoc @@ -7,14 +7,14 @@ git-for-each-ref - Output information on each ref SYNOPSIS -------- -[verse] -'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl] +[synopsis] +git for-each-ref [--count=<count>] [--shell|--perl|--python|--tcl] [(--sort=<key>)...] [--format=<format>] - [--include-root-refs] [ --stdin | <pattern>... ] - [--points-at=<object>] + [--include-root-refs] [--points-at=<object>] [--merged[=<object>]] [--no-merged[=<object>]] [--contains[=<object>]] [--no-contains[=<object>]] - [--exclude=<pattern> ...] + [(--exclude=<pattern>)...] [--start-after=<marker>] + [ --stdin | <pattern>... ] DESCRIPTION ----------- @@ -108,6 +108,15 @@ TAB %(refname)`. --include-root-refs:: List root refs (HEAD and pseudorefs) apart from regular refs. +--start-after=<marker>:: + Allows paginating the output by skipping references up to and including the + specified marker. When paging, it should be noted that references may be + deleted, modified or added between invocations. Output will only yield those + references which follow the marker lexicographically. Output begins from the + first reference that would come after the marker alphabetically. Cannot be + used with `--sort=<key>` or `--stdin` options, or the _<pattern>_ argument(s) + to limit the refs. + FIELD NAMES ----------- diff --git a/Documentation/git-imap-send.adoc b/Documentation/git-imap-send.adoc index 17147f93c3..278e5ccd36 100644 --- a/Documentation/git-imap-send.adoc +++ b/Documentation/git-imap-send.adoc @@ -68,6 +68,34 @@ include::includes/cmd-config-section-rest.adoc[] include::config/imap.adoc[] +GETTING A LIST OF AVAILABLE FOLDERS +----------------------------------- + +In order to send an email to a specific folder, you need to know the correct name of +intended folder in your mailbox. The names like "Junk", "Trash" etc. displayed by +various email clients need not be the actual names of the folders stored in the mail +server of your email provider. + +In order to get the correct folder name to be used with `git imap-send`, you can run +`git imap-send --list`. This will display a list of valid folder names. An example +of such an output when run on a Gmail account is: + +......................... +* LIST (\HasNoChildren) "/" "INBOX" +* LIST (\HasChildren \Noselect) "/" "[Gmail]" +* LIST (\All \HasNoChildren) "/" "[Gmail]/All Mail" +* LIST (\Drafts \HasNoChildren) "/" "[Gmail]/Drafts" +* LIST (\HasNoChildren \Important) "/" "[Gmail]/Important" +* LIST (\HasNoChildren \Sent) "/" "[Gmail]/Sent Mail" +* LIST (\HasNoChildren \Junk) "/" "[Gmail]/Spam" +* LIST (\Flagged \HasNoChildren) "/" "[Gmail]/Starred" +* LIST (\HasNoChildren \Trash) "/" "[Gmail]/Trash" +......................... + +Here, you can observe that the correct name for the "Junk" folder is `[Gmail]/Spam` +and for the "Trash" folder is `[Gmail]/Trash`. Similar logic can be used to determine +other folders as well. + EXAMPLES -------- Using tunnel mode: diff --git a/Documentation/git-log.adoc b/Documentation/git-log.adoc index ae8a7e2d63..b6f3d92c43 100644 --- a/Documentation/git-log.adoc +++ b/Documentation/git-log.adoc @@ -8,8 +8,8 @@ git-log - Show commit logs SYNOPSIS -------- -[verse] -'git log' [<options>] [<revision-range>] [[--] <path>...] +[synopsis] +git log [<options>] [<revision-range>] [[--] <path>...] DESCRIPTION ----------- @@ -27,28 +27,34 @@ each commit introduces are shown. OPTIONS ------- ---follow:: +`--follow`:: Continue listing the history of a file beyond renames (works only for a single file). ---no-decorate:: ---decorate[=short|full|auto|no]:: - Print out the ref names of any commits that are shown. If 'short' is - specified, the ref name prefixes 'refs/heads/', 'refs/tags/' and - 'refs/remotes/' will not be printed. If 'full' is specified, the - full ref name (including prefix) will be printed. If 'auto' is - specified, then if the output is going to a terminal, the ref names - are shown as if 'short' were given, otherwise no ref names are - shown. The option `--decorate` is short-hand for `--decorate=short`. - Default to configuration value of `log.decorate` if configured, - otherwise, `auto`. - ---decorate-refs=<pattern>:: ---decorate-refs-exclude=<pattern>:: +`--no-decorate`:: +`--decorate[=(short|full|auto|no)]`:: + Print out the ref names of any commits that are shown. Possible values + are: ++ +---- +`short`;; the ref name prefixes `refs/heads/`, `refs/tags/` and + `refs/remotes/` are not printed. +`full`;; the full ref name (including prefix) is printed. +`auto`:: if the output is going to a terminal, the ref names + are shown as if `short` were given, otherwise no ref names are + shown. +---- ++ +The option `--decorate` is short-hand for `--decorate=short`. Default to +configuration value of `log.decorate` if configured, otherwise, `auto`. + +`--decorate-refs=<pattern>`:: +`--decorate-refs-exclude=<pattern>`:: For each candidate reference, do not use it for decoration if it - matches any patterns given to `--decorate-refs-exclude` or if it - doesn't match any of the patterns given to `--decorate-refs`. The - `log.excludeDecoration` config option allows excluding refs from + matches any of the _<pattern>_ parameters given to + `--decorate-refs-exclude` or if it doesn't match any of the + _<pattern>_ parameters given to `--decorate-refs`. + The `log.excludeDecoration` config option allows excluding refs from the decorations, but an explicit `--decorate-refs` pattern will override a match in `log.excludeDecoration`. + @@ -56,51 +62,51 @@ If none of these options or config settings are given, then references are used as decoration if they match `HEAD`, `refs/heads/`, `refs/remotes/`, `refs/stash/`, or `refs/tags/`. ---clear-decorations:: +`--clear-decorations`:: When specified, this option clears all previous `--decorate-refs` or `--decorate-refs-exclude` options and relaxes the default decoration filter to include all references. This option is assumed if the config value `log.initialDecorationSet` is set to `all`. ---source:: +`--source`:: Print out the ref name given on the command line by which each commit was reached. ---[no-]mailmap:: ---[no-]use-mailmap:: +`--[no-]mailmap`:: +`--[no-]use-mailmap`:: Use mailmap file to map author and committer names and email addresses to canonical real names and email addresses. See linkgit:git-shortlog[1]. ---full-diff:: +`--full-diff`:: Without this flag, `git log -p <path>...` shows commits that touch the specified paths, and diffs about the same specified paths. With this, the full diff is shown for commits that touch - the specified paths; this means that "<path>..." limits only + the specified paths; this means that "`<path>...`" limits only commits, and doesn't limit diff for those commits. + Note that this affects all diff-based output types, e.g. those produced by `--stat`, etc. ---log-size:: - Include a line ``log size <number>'' in the output for each commit, - where <number> is the length of that commit's message in bytes. +`--log-size`:: + Include a line `log size <number>` in the output for each commit, + where _<number>_ is the length of that commit's message in bytes. Intended to speed up tools that read log messages from `git log` output by allowing them to allocate space in advance. include::line-range-options.adoc[] -<revision-range>:: +_<revision-range>_:: Show only commits in the specified revision range. When no - <revision-range> is specified, it defaults to `HEAD` (i.e. the + _<revision-range>_ is specified, it defaults to `HEAD` (i.e. the whole history leading to the current commit). `origin..HEAD` specifies all the commits reachable from the current commit (i.e. `HEAD`), but not from `origin`. For a complete list of - ways to spell <revision-range>, see the 'Specifying Ranges' + ways to spell _<revision-range>_, see the 'Specifying Ranges' section of linkgit:gitrevisions[7]. -[--] <path>...:: +`[--] <path>...`:: Show only commits that are enough to explain how the files that match the specified paths came to be. See 'History Simplification' below for details and other simplification @@ -145,14 +151,14 @@ EXAMPLES `git log --since="2 weeks ago" -- gitk`:: - Show the changes during the last two weeks to the file 'gitk'. + Show the changes during the last two weeks to the file `gitk`. The `--` is necessary to avoid confusion with the *branch* named - 'gitk' + `gitk` `git log --name-status release..test`:: - Show the commits that are in the "test" branch but not yet - in the "release" branch, along with the list of paths + Show the commits that are in the "`test`" branch but not yet + in the "`release`" branch, along with the list of paths each commit modifies. `git log --follow builtin/rev-list.c`:: @@ -164,7 +170,7 @@ EXAMPLES `git log --branches --not --remotes=origin`:: Shows all commits that are in any of local branches but not in - any of remote-tracking branches for 'origin' (what you have that + any of remote-tracking branches for `origin` (what you have that origin doesn't). `git log master --not --remotes=*/master`:: @@ -200,11 +206,11 @@ CONFIGURATION See linkgit:git-config[1] for core variables and linkgit:git-diff[1] for settings related to diff generation. -format.pretty:: +`format.pretty`:: Default for the `--format` option. (See 'Pretty Formats' above.) Defaults to `medium`. -i18n.logOutputEncoding:: +`i18n.logOutputEncoding`:: Encoding to use when displaying logs. (See 'Discussion' above.) Defaults to the value of `i18n.commitEncoding` if set, and UTF-8 otherwise. diff --git a/Documentation/git-merge.adoc b/Documentation/git-merge.adoc index d53923c3b7..a055384ad6 100644 --- a/Documentation/git-merge.adoc +++ b/Documentation/git-merge.adoc @@ -28,8 +28,8 @@ Assume the following history exists and the current branch is `master`: ------------ - A---B---C topic - / + A---B---C topic + / D---E---F---G master ------------ @@ -38,11 +38,11 @@ Then `git merge topic` will replay the changes made on the its current commit (`C`) on top of `master`, and record the result in a new commit along with the names of the two parent commits and a log message from the user describing the changes. Before the operation, -`ORIG_HEAD` is set to the tip of the current branch (`C`). +`ORIG_HEAD` is set to the tip of the current branch (`G`). ------------ - A---B---C topic - / \ + A---B---C topic + / \ D---E---F---G---H master ------------ diff --git a/Documentation/git-pack-objects.adoc b/Documentation/git-pack-objects.adoc index b1c5aa27da..eba014c406 100644 --- a/Documentation/git-pack-objects.adoc +++ b/Documentation/git-pack-objects.adoc @@ -87,13 +87,21 @@ base-name:: reference was included in the resulting packfile. This can be useful to send new tags to native Git clients. ---stdin-packs:: +--stdin-packs[=<mode>]:: Read the basenames of packfiles (e.g., `pack-1234abcd.pack`) from the standard input, instead of object names or revision arguments. The resulting pack contains all objects listed in the included packs (those not beginning with `^`), excluding any objects listed in the excluded packs (beginning with `^`). + +When `mode` is "follow", objects from packs not listed on stdin receive +special treatment. Objects within unlisted packs will be included if +those objects are (1) reachable from the included packs, and (2) not +found in any excluded packs. This mode is useful, for example, to +resurrect once-unreachable objects found in cruft packs to generate +packs which are closed under reachability up to the boundary set by the +excluded packs. ++ Incompatible with `--revs`, or options that imply `--revs` (such as `--all`), with the exception of `--unpacked`, which is compatible. diff --git a/Documentation/git-pack-refs.adoc b/Documentation/git-pack-refs.adoc index 652c549771..42b90051e6 100644 --- a/Documentation/git-pack-refs.adoc +++ b/Documentation/git-pack-refs.adoc @@ -66,7 +66,10 @@ Pack refs as needed depending on the current state of the ref database. The behavior depends on the ref format used by the repository and may change in the future. + - - "files": No special handling for `--auto` has been implemented. + - "files": Loose references are packed into the `packed-refs` file + based on the ratio of loose references to the size of the + `packed-refs` file. The bigger the `packed-refs` file, the more loose + references need to exist before we repack. + - "reftable": Tables are compacted such that they form a geometric sequence. For two tables N and N+1, where N+1 is newer, this diff --git a/Documentation/git-reset.adoc b/Documentation/git-reset.adoc index 53ab88c545..50e8a0ba6f 100644 --- a/Documentation/git-reset.adoc +++ b/Documentation/git-reset.adoc @@ -125,6 +125,8 @@ OPTIONS separated with _NUL_ character and all other characters are taken literally (including newlines and quotes). +include::diff-context-options.adoc[] + `--`:: Do not interpret any more arguments as options. diff --git a/Documentation/git-restore.adoc b/Documentation/git-restore.adoc index 877b7772e6..961eef0137 100644 --- a/Documentation/git-restore.adoc +++ b/Documentation/git-restore.adoc @@ -28,8 +28,6 @@ otherwise from the index. Use `--source` to restore from a different commit. See "Reset, restore and revert" in linkgit:git[1] for the differences between the three commands. -THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE. - OPTIONS ------- `-s <tree>`:: @@ -52,6 +50,8 @@ leave out at most one of _<rev-A>__ and _<rev-B>_, in which case it defaults to Mode" section of linkgit:git-add[1] to learn how to operate the `--patch` mode. +include::diff-context-options.adoc[] + `-W`:: `--worktree`:: `-S`:: diff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc index 7bd09c254b..5335502d68 100644 --- a/Documentation/git-send-email.adoc +++ b/Documentation/git-send-email.adoc @@ -280,12 +280,14 @@ must be used for each option. Path to a store of trusted CA certificates for SMTP SSL/TLS certificate validation (either a directory that has been processed by `c_rehash`, or a single file containing one or more PEM format - certificates concatenated together: see verify(1) -CAfile and - -CApath for more information on these). Set it to an empty string - to disable certificate verification. Defaults to the value of the - `sendemail.smtpSSLCertPath` configuration variable, if set, or the - backing SSL library's compiled-in default otherwise (which should - be the best choice on most platforms). + certificates concatenated together: see the description of the + `-CAfile` _<file>_ and the `-CApath` _<dir>_ options of + https://docs.openssl.org/master/man1/openssl-verify/ + [OpenSSL's verify(1) manual page] for more information on these). + Set it to an empty string to disable certificate verification. + Defaults to the value of the `sendemail.smtpSSLCertPath` configuration + variable, if set, or the backing SSL library's compiled-in default + otherwise (which should be the best choice on most platforms). --smtp-user=<user>:: Username for SMTP-AUTH. Default is the value of `sendemail.smtpUser`; @@ -598,9 +600,20 @@ available online. Community maintained credential helpers are also available: - https://github.com/AdityaGarg8/git-credential-email[git-credential-yahoo] (cross platform, dedicated helper for authenticating Yahoo accounts) + - https://github.com/AdityaGarg8/git-credential-email[git-credential-aol] + (cross platform, dedicated helper for authenticating AOL accounts) + You can also see linkgit:gitcredentials[7] for more OAuth based authentication helpers. +Proton Mail does not provide an SMTP server to send emails. If you are a paid +customer of Proton Mail, you can use +https://proton.me/mail/bridge[Proton Mail Bridge] +officially provided by Proton Mail to create a local SMTP server for sending +emails. For both free and paid users, community maintained projects like +https://github.com/AdityaGarg8/git-credential-email[git-protonmail] can be +used. + Note: the following core Perl modules that may be installed with your distribution of Perl are required: @@ -614,6 +627,35 @@ These additional Perl modules are also required: https://metacpan.org/pod/Authen::SASL[Authen::SASL] and https://metacpan.org/pod/Mail::Address[Mail::Address]. +Exploiting the `sendmailCmd` option of `git send-email` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Apart from sending emails via an SMTP server, `git send-email` can also send +emails through any application that supports sendmail-like commands. You can +read documentation of `--sendmail-cmd=<command>` above for more information. +This ability can be very useful if you want to use another application as an +SMTP client for `git send-email`, or if your email provider uses proprietary +APIs instead of SMTP to send emails. + +As an example, lets see how to configure https://marlam.de/msmtp/[msmtp], a +popular SMTP client found in many Linux distributions. Edit `~/.gitconfig` +to instruct `git-send-email` to use it for sending emails. + +---- +[sendemail] + sendmailCmd = /usr/bin/msmtp # Change this to the path where msmtp is installed +---- + +Links of a few such community maintained helpers are: + + - https://marlam.de/msmtp/[msmtp] + (popular SMTP client with many features, available for Linux and macOS) + + - https://github.com/AdityaGarg8/git-credential-email[git-protonmail] + (cross platform client that can send emails using the ProtonMail API) + + - https://github.com/AdityaGarg8/git-credential-email[git-msgraph] + (cross platform client that can send emails using the Microsoft Graph API) SEE ALSO -------- diff --git a/Documentation/git-stash.adoc b/Documentation/git-stash.adoc index e5e6c9d37f..e2300a19a2 100644 --- a/Documentation/git-stash.adoc +++ b/Documentation/git-stash.adoc @@ -222,6 +222,8 @@ to learn how to operate the `--patch` mode. The `--patch` option implies `--keep-index`. You can use `--no-keep-index` to override this. +include::diff-context-options.adoc[] + -S:: --staged:: This option is only valid for `push` and `save` commands. diff --git a/Documentation/git-switch.adoc b/Documentation/git-switch.adoc index 9f62abf9e2..87707e9265 100644 --- a/Documentation/git-switch.adoc +++ b/Documentation/git-switch.adoc @@ -29,8 +29,6 @@ Switching branches does not require a clean index and working tree however if the operation leads to loss of local changes, unless told otherwise with `--discard-changes` or `--merge`. -THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE. - OPTIONS ------- _<branch>_:: diff --git a/Documentation/gitremote-helpers.adoc b/Documentation/gitremote-helpers.adoc index d0be008e5e..39cdece16e 100644 --- a/Documentation/gitremote-helpers.adoc +++ b/Documentation/gitremote-helpers.adoc @@ -498,7 +498,7 @@ set by Git if the remote helper has the 'option' capability. ask for the tag specifically. Some helpers may be able to use this option to avoid a second network connection. -'option dry-run' {'true'|'false'}: +'option dry-run' {'true'|'false'}:: If true, pretend the operation completed successfully, but don't actually change any repository data. For most helpers this only applies to the 'push', if supported. diff --git a/Documentation/glossary-content.adoc b/Documentation/glossary-content.adoc index 575c18f776..e423e4765b 100644 --- a/Documentation/glossary-content.adoc +++ b/Documentation/glossary-content.adoc @@ -418,9 +418,8 @@ full pathname may have special meaning: - A leading "`**`" followed by a slash means match in all directories. For example, "`**/foo`" matches file or directory - "`foo`" anywhere, the same as pattern "`foo`". "`**/foo/bar`" - matches file or directory "`bar`" anywhere that is directly - under directory "`foo`". + "`foo`" anywhere. "`**/foo/bar`" matches file or directory "`bar`" + anywhere that is directly under directory "`foo`". - A trailing "`/**`" matches everything inside. For example, "`abc/**`" matches all files inside directory "abc", relative diff --git a/Documentation/line-range-format.adoc b/Documentation/line-range-format.adoc index 9b51e9fb66..3cc2a14544 100644 --- a/Documentation/line-range-format.adoc +++ b/Documentation/line-range-format.adoc @@ -1,30 +1,30 @@ -'<start>' and '<end>' can take one of these forms: +_<start>_ and _<end>_ can take one of these forms: -- number +- _<number>_ + -If '<start>' or '<end>' is a number, it specifies an +If _<start>_ or _<end>_ is a number, it specifies an absolute line number (lines count from 1). + -- `/regex/` +- `/<regex>/` + This form will use the first line matching the given -POSIX regex. If '<start>' is a regex, it will search from the end of +POSIX _<regex>_. If _<start>_ is a regex, it will search from the end of the previous `-L` range, if any, otherwise from the start of file. -If '<start>' is `^/regex/`, it will search from the start of file. -If '<end>' is a regex, it will search -starting at the line given by '<start>'. +If _<start>_ is `^/<regex>/`, it will search from the start of file. +If _<end>_ is a regex, it will search starting at the line given by +_<start>_. + -- +offset or -offset +- `+<offset>` or `-<offset>` + -This is only valid for '<end>' and will specify a number -of lines before or after the line given by '<start>'. +This is only valid for _<end>_ and will specify a number +of lines before or after the line given by _<start>_. + -If `:<funcname>` is given in place of '<start>' and '<end>', it is a +If `:<funcname>` is given in place of _<start>_ and _<end>_, it is a regular expression that denotes the range from the first funcname line -that matches '<funcname>', up to the next funcname line. `:<funcname>` +that matches _<funcname>_, up to the next funcname line. `:<funcname>` searches from the end of the previous `-L` range, if any, otherwise from the start of file. `^:<funcname>` searches from the start of file. The function names are determined in the same way as `git diff` diff --git a/Documentation/line-range-options.adoc b/Documentation/line-range-options.adoc index f275df3b69..c44ba05320 100644 --- a/Documentation/line-range-options.adoc +++ b/Documentation/line-range-options.adoc @@ -1,12 +1,12 @@ --L<start>,<end>:<file>:: --L:<funcname>:<file>:: +`-L<start>,<end>:<file>`:: +`-L:<funcname>:<file>`:: - Trace the evolution of the line range given by '<start>,<end>', - or by the function name regex '<funcname>', within the '<file>'. You may + Trace the evolution of the line range given by `<start>,<end>`, + or by the function name regex _<funcname>_, within the _<file>_. You may not give any pathspec limiters. This is currently limited to a walk starting from a single revision, i.e., you may only give zero or one positive revision arguments, and - '<start>' and '<end>' (or '<funcname>') must exist in the starting revision. + _<start>_ and _<end>_ (or _<funcname>_) must exist in the starting revision. You can specify this option more than once. Implies `--patch`. Patch output can be suppressed using `--no-patch`, but other diff formats (namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`, diff --git a/Documentation/meson.build b/Documentation/meson.build index 2fe1a1369d..4404c623f0 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -375,8 +375,7 @@ foreach manpage, category : manpages output: fs.stem(manpage) + '.xml', ) - manpage_path = fs.stem(manpage) + '.' + category.to_string() - manpage_target = custom_target( + custom_target( command: [ xmlto, '-m', '@INPUT0@', @@ -392,7 +391,7 @@ foreach manpage, category : manpages 'manpage-normal.xsl', 'manpage-bold-literal.xsl', ], - output: manpage_path, + output: fs.stem(manpage) + '.' + category.to_string(), install: true, install_dir: get_option('mandir') / 'man' + category.to_string(), ) diff --git a/Documentation/pretty-formats.adoc b/Documentation/pretty-formats.adoc index 07475de8c3..9ed0417fc8 100644 --- a/Documentation/pretty-formats.adoc +++ b/Documentation/pretty-formats.adoc @@ -2,11 +2,11 @@ PRETTY FORMATS -------------- If the commit is a merge, and if the pretty-format -is not 'oneline', 'email' or 'raw', an additional line is -inserted before the 'Author:' line. This line begins with +is not `oneline`, `email` or `raw`, an additional line is +inserted before the `Author:` line. This line begins with "Merge: " and the hashes of ancestral commits are printed, separated by spaces. Note that the listed commits may not -necessarily be the list of the *direct* parent commits if you +necessarily be the list of the 'direct' parent commits if you have limited your view of history: for example, if you are only interested in changes related to a certain directory or file. @@ -14,24 +14,24 @@ file. There are several built-in formats, and you can define additional formats by setting a pretty.<name> config option to either another format name, or a -'format:' string, as described below (see +`format:` string, as described below (see linkgit:git-config[1]). Here are the details of the built-in formats: -* 'oneline' +* `oneline` <hash> <title-line> + This is designed to be as compact as possible. -* 'short' +* `short` commit <hash> Author: <author> <title-line> -* 'medium' +* `medium` commit <hash> Author: <author> @@ -41,7 +41,7 @@ This is designed to be as compact as possible. <full-commit-message> -* 'full' +* `full` commit <hash> Author: <author> @@ -51,7 +51,7 @@ This is designed to be as compact as possible. <full-commit-message> -* 'fuller' +* `fuller` commit <hash> Author: <author> @@ -63,18 +63,18 @@ This is designed to be as compact as possible. <full-commit-message> -* 'reference' +* `reference` <abbrev-hash> (<title-line>, <short-author-date>) + This format is used to refer to another commit in a commit message and -is the same as `--pretty='format:%C(auto)%h (%s, %ad)'`. By default, +is the same as ++--pretty=\'format:%C(auto)%h (%s, %ad)'++. By default, the date is formatted with `--date=short` unless another `--date` option is explicitly specified. As with any `format:` with format placeholders, its output is not affected by other options like `--decorate` and `--walk-reflogs`. -* 'email' +* `email` From <hash> <date> From: <author> @@ -83,30 +83,30 @@ placeholders, its output is not affected by other options like <full-commit-message> -* 'mboxrd' +* `mboxrd` + -Like 'email', but lines in the commit message starting with "From " +Like `email`, but lines in the commit message starting with "From " (preceded by zero or more ">") are quoted with ">" so they aren't confused as starting a new commit. -* 'raw' +* `raw` + -The 'raw' format shows the entire commit exactly as +The `raw` format shows the entire commit exactly as stored in the commit object. Notably, the hashes are -displayed in full, regardless of whether --abbrev or ---no-abbrev are used, and 'parents' information show the +displayed in full, regardless of whether `--abbrev` or +`--no-abbrev` are used, and 'parents' information show the true parent commits, without taking grafts or history simplification into account. Note that this format affects the way commits are displayed, but not the way the diff is shown e.g. with `git log --raw`. To get full object names in a raw diff format, use `--no-abbrev`. -* 'format:<format-string>' +* `format:<format-string>` + -The 'format:<format-string>' format allows you to specify which information +The `format:<format-string>` format allows you to specify which information you want to show. It works a little bit like printf format, -with the notable exception that you get a newline with '%n' -instead of '\n'. +with the notable exception that you get a newline with `%n` +instead of `\n`. + E.g, 'format:"The author of %h was %an, %ar%nThe title was >>%s<<%n"' would show something like this: @@ -120,158 +120,161 @@ The title was >>t4119: test autocomputing -p<n> for traditional diff input.<< The placeholders are: - Placeholders that expand to a single literal character: -'%n':: newline -'%%':: a raw '%' -'%x00':: '%x' followed by two hexadecimal digits is replaced with a +++%n++:: newline +++%%++:: a raw ++%++ +++%x00++:: ++%x++ followed by two hexadecimal digits is replaced with a byte with the hexadecimal digits' value (we will call this "literal formatting code" in the rest of this document). - Placeholders that affect formatting of later placeholders: -'%Cred':: switch color to red -'%Cgreen':: switch color to green -'%Cblue':: switch color to blue -'%Creset':: reset color -'%C(...)':: color specification, as described under Values in the +++%Cred++:: switch color to red +++%Cgreen++:: switch color to green +++%Cblue++:: switch color to blue +++%Creset++:: reset color +++%C(++_<spec>_++)++:: color specification, as described under Values in the "CONFIGURATION FILE" section of linkgit:git-config[1]. By default, colors are shown only when enabled for log output (by `color.diff`, `color.ui`, or `--color`, and respecting the `auto` settings of the former if we are going to a - terminal). `%C(auto,...)` is accepted as a historical - synonym for the default (e.g., `%C(auto,red)`). Specifying - `%C(always,...)` will show the colors even when color is + terminal). ++%C(auto,++_<spec>_++)++ is accepted as a historical + synonym for the default (e.g., ++%C(auto,red)++). Specifying + ++%C(always,++_<spec>_++)++ will show the colors even when color is not otherwise enabled (though consider just using - `--color=always` to enable color for the whole output, + `--color=always` to enable color for the whole output, including this format and anything else git might color). - `auto` alone (i.e. `%C(auto)`) will turn on auto coloring + `auto` alone (i.e. ++%C(auto)++) will turn on auto coloring on the next placeholders until the color is switched again. -'%m':: left (`<`), right (`>`) or boundary (`-`) mark -'%w([<w>[,<i1>[,<i2>]]])':: switch line wrapping, like the -w option of +++%m++:: left (`<`), right (`>`) or boundary (`-`) mark +++%w(++`[<w>[,<i1>[,<i2>]]]`++)++:: switch line wrapping, like the `-w` option of linkgit:git-shortlog[1]. -'%<( <N> [,trunc|ltrunc|mtrunc])':: make the next placeholder take at +++%<(++`<n>[,(trunc|ltrunc|mtrunc)]`++)++:: make the next placeholder take at least N column widths, padding spaces on the right if necessary. Optionally - truncate (with ellipsis '..') at the left (ltrunc) `..ft`, + truncate (with ellipsis `..`) at the left (ltrunc) `..ft`, the middle (mtrunc) `mi..le`, or the end (trunc) `rig..`, if the output is longer than - N columns. + _<n>_ columns. Note 1: that truncating - only works correctly with N >= 2. - Note 2: spaces around the N and M (see below) + only works correctly with _<n>_ >= 2. + Note 2: spaces around the _<n>_ and _<m>_ (see below) values are optional. Note 3: Emojis and other wide characters will take two display columns, which may over-run column boundaries. Note 4: decomposed character combining marks may be misplaced at padding boundaries. -'%<|( <M> )':: make the next placeholder take at least until Mth +++%<|(++_<m>_ ++)++:: make the next placeholder take at least until _<m>_ th display column, padding spaces on the right if necessary. - Use negative M values for column positions measured + Use negative _<m>_ values for column positions measured from the right hand edge of the terminal window. -'%>( <N> )', '%>|( <M> )':: similar to '%<( <N> )', '%<|( <M> )' respectively, +++%>(++_<n>_++)++:: +++%>|(++_<m>_++)++:: similar to ++%<(++_<n>_++)++, ++%<|(++_<m>_++)++ respectively, but padding spaces on the left -'%>>( <N> )', '%>>|( <M> )':: similar to '%>( <N> )', '%>|( <M> )' +++%>>(++_<n>_++)++:: +++%>>|(++_<m>_++)++:: similar to ++%>(++_<n>_++)++, ++%>|(++_<m>_++)++ respectively, except that if the next placeholder takes more spaces than given and there are spaces on its left, use those spaces -'%><( <N> )', '%><|( <M> )':: similar to '%<( <N> )', '%<|( <M> )' +++%><(++_<n>_++)++:: +++%><|(++_<m>_++)++:: similar to ++%<(++_<n>_++)++, ++%<|(++_<m>_++)++ respectively, but padding both sides (i.e. the text is centered) - Placeholders that expand to information extracted from the commit: -'%H':: commit hash -'%h':: abbreviated commit hash -'%T':: tree hash -'%t':: abbreviated tree hash -'%P':: parent hashes -'%p':: abbreviated parent hashes -'%an':: author name -'%aN':: author name (respecting .mailmap, see linkgit:git-shortlog[1] ++%H+:: commit hash ++%h+:: abbreviated commit hash ++%T+:: tree hash ++%t+:: abbreviated tree hash ++%P+:: parent hashes ++%p+:: abbreviated parent hashes ++%an+:: author name ++%aN+:: author name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) -'%ae':: author email -'%aE':: author email (respecting .mailmap, see linkgit:git-shortlog[1] ++%ae+:: author email ++%aE+:: author email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) -'%al':: author email local-part (the part before the '@' sign) -'%aL':: author local-part (see '%al') respecting .mailmap, see ++%al+:: author email local-part (the part before the `@` sign) ++%aL+:: author local-part (see +%al+) respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) -'%ad':: author date (format respects --date= option) -'%aD':: author date, RFC2822 style -'%ar':: author date, relative -'%at':: author date, UNIX timestamp -'%ai':: author date, ISO 8601-like format -'%aI':: author date, strict ISO 8601 format -'%as':: author date, short format (`YYYY-MM-DD`) -'%ah':: author date, human style (like the `--date=human` option of ++%ad+:: author date (format respects --date= option) ++%aD+:: author date, RFC2822 style ++%ar+:: author date, relative ++%at+:: author date, UNIX timestamp ++%ai+:: author date, ISO 8601-like format ++%aI+:: author date, strict ISO 8601 format ++%as+:: author date, short format (`YYYY-MM-DD`) ++%ah+:: author date, human style (like the `--date=human` option of linkgit:git-rev-list[1]) -'%cn':: committer name -'%cN':: committer name (respecting .mailmap, see ++%cn+:: committer name ++%cN+:: committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) -'%ce':: committer email -'%cE':: committer email (respecting .mailmap, see ++%ce+:: committer email ++%cE+:: committer email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) -'%cl':: committer email local-part (the part before the '@' sign) -'%cL':: committer local-part (see '%cl') respecting .mailmap, see ++%cl+:: committer email local-part (the part before the `@` sign) ++%cL+:: committer local-part (see +%cl+) respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) -'%cd':: committer date (format respects --date= option) -'%cD':: committer date, RFC2822 style -'%cr':: committer date, relative -'%ct':: committer date, UNIX timestamp -'%ci':: committer date, ISO 8601-like format -'%cI':: committer date, strict ISO 8601 format -'%cs':: committer date, short format (`YYYY-MM-DD`) -'%ch':: committer date, human style (like the `--date=human` option of ++%cd+:: committer date (format respects --date= option) ++%cD+:: committer date, RFC2822 style ++%cr+:: committer date, relative ++%ct+:: committer date, UNIX timestamp ++%ci+:: committer date, ISO 8601-like format ++%cI+:: committer date, strict ISO 8601 format ++%cs+:: committer date, short format (`YYYY-MM-DD`) ++%ch+:: committer date, human style (like the `--date=human` option of linkgit:git-rev-list[1]) -'%d':: ref names, like the --decorate option of linkgit:git-log[1] -'%D':: ref names without the " (", ")" wrapping. -'%(decorate[:<options>])':: ++%d+:: ref names, like the --decorate option of linkgit:git-log[1] ++%D+:: ref names without the " (", ")" wrapping. +++%(decorate++`[:<option>,...]`++)++:: ref names with custom decorations. The `decorate` string may be followed by a colon and zero or more comma-separated options. Option values may contain literal formatting codes. These must be used for commas (`%x2C`) and closing parentheses (`%x29`), due to their role in the option syntax. + -** 'prefix=<value>': Shown before the list of ref names. Defaults to "{nbsp}`(`". -** 'suffix=<value>': Shown after the list of ref names. Defaults to "`)`". -** 'separator=<value>': Shown between ref names. Defaults to "`,`{nbsp}". -** 'pointer=<value>': Shown between HEAD and the branch it points to, if any. - Defaults to "{nbsp}`->`{nbsp}". -** 'tag=<value>': Shown before tag names. Defaults to "`tag:`{nbsp}". +** `prefix=<value>`: Shown before the list of ref names. Defaults to "{nbsp}+(+". +** `suffix=<value>`: Shown after the list of ref names. Defaults to "+)+". +** `separator=<value>`: Shown between ref names. Defaults to "+,+{nbsp}". +** `pointer=<value>`: Shown between HEAD and the branch it points to, if any. + Defaults to "{nbsp}+->+{nbsp}". +** `tag=<value>`: Shown before tag names. Defaults to "`tag:`{nbsp}". + For example, to produce decorations with no wrapping or tag annotations, and spaces as separators: + -`%(decorate:prefix=,suffix=,tag=,separator= )` +++%(decorate:prefix=,suffix=,tag=,separator= )++ -'%(describe[:<options>])':: +++%(describe++`[:<option>,...]`++)++:: human-readable name, like linkgit:git-describe[1]; empty string for undescribable commits. The `describe` string may be followed by a colon and zero or more comma-separated options. Descriptions can be inconsistent when tags are added or removed at the same time. + -** 'tags[=<bool-value>]': Instead of only considering annotated tags, +** `tags[=<bool-value>]`: Instead of only considering annotated tags, consider lightweight tags as well. -** 'abbrev=<number>': Instead of using the default number of hexadecimal digits +** `abbrev=<number>`: Instead of using the default number of hexadecimal digits (which will vary according to the number of objects in the repository with a default of 7) of the abbreviated object name, use <number> digits, or as many digits as needed to form a unique object name. -** 'match=<pattern>': Only consider tags matching the given - `glob(7)` pattern, excluding the "refs/tags/" prefix. -** 'exclude=<pattern>': Do not consider tags matching the given - `glob(7)` pattern, excluding the "refs/tags/" prefix. +** `match=<pattern>`: Only consider tags matching the given + `glob(7)` _<pattern>_, excluding the `refs/tags/` prefix. +** `exclude=<pattern>`: Do not consider tags matching the given + `glob(7)` _<pattern>_, excluding the `refs/tags/` prefix. -'%S':: ref name given on the command line by which the commit was reached ++%S+:: ref name given on the command line by which the commit was reached (like `git log --source`), only works with `git log` -'%e':: encoding -'%s':: subject -'%f':: sanitized subject line, suitable for a filename -'%b':: body -'%B':: raw body (unwrapped subject and body) ++%e+:: encoding ++%s+:: subject ++%f+:: sanitized subject line, suitable for a filename ++%b+:: body ++%B+:: raw body (unwrapped subject and body) ifndef::git-rev-list[] -'%N':: commit notes ++%N+:: commit notes endif::git-rev-list[] -'%GG':: raw verification message from GPG for a signed commit -'%G?':: show "G" for a good (valid) signature, ++%GG+:: raw verification message from GPG for a signed commit ++%G?+:: show "G" for a good (valid) signature, "B" for a bad signature, "U" for a good signature with unknown validity, "X" for a good signature that has expired, @@ -279,86 +282,86 @@ endif::git-rev-list[] "R" for a good signature made by a revoked key, "E" if the signature cannot be checked (e.g. missing key) and "N" for no signature -'%GS':: show the name of the signer for a signed commit -'%GK':: show the key used to sign a signed commit -'%GF':: show the fingerprint of the key used to sign a signed commit -'%GP':: show the fingerprint of the primary key whose subkey was used ++%GS+:: show the name of the signer for a signed commit ++%GK+:: show the key used to sign a signed commit ++%GF+:: show the fingerprint of the key used to sign a signed commit ++%GP+:: show the fingerprint of the primary key whose subkey was used to sign a signed commit -'%GT':: show the trust level for the key used to sign a signed commit -'%gD':: reflog selector, e.g., `refs/stash@{1}` or `refs/stash@{2 ++%GT+:: show the trust level for the key used to sign a signed commit ++%gD+:: reflog selector, e.g., `refs/stash@{1}` or `refs/stash@{2 minutes ago}`; the format follows the rules described for the `-g` option. The portion before the `@` is the refname as given on the command line (so `git log -g refs/heads/master` would yield `refs/heads/master@{0}`). -'%gd':: shortened reflog selector; same as `%gD`, but the refname ++%gd+:: shortened reflog selector; same as `%gD`, but the refname portion is shortened for human readability (so `refs/heads/master` becomes just `master`). -'%gn':: reflog identity name -'%gN':: reflog identity name (respecting .mailmap, see ++%gn+:: reflog identity name ++%gN+:: reflog identity name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) -'%ge':: reflog identity email -'%gE':: reflog identity email (respecting .mailmap, see ++%ge+:: reflog identity email ++%gE+:: reflog identity email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1]) -'%gs':: reflog subject -'%(trailers[:<options>])':: ++%gs+:: reflog subject +++%(trailers++`[:<option>,...]`++)++:: display the trailers of the body as interpreted by linkgit:git-interpret-trailers[1]. The `trailers` string may be followed by a colon and zero or more comma-separated options. If any option is provided multiple times, the last occurrence wins. + -** 'key=<key>': only show trailers with specified <key>. Matching is done +** `key=<key>`: only show trailers with specified <key>. Matching is done case-insensitively and trailing colon is optional. If option is given multiple times trailer lines matching any of the keys are shown. This option automatically enables the `only` option so that non-trailer lines in the trailer block are hidden. If that is not desired it can be disabled with `only=false`. E.g., - `%(trailers:key=Reviewed-by)` shows trailer lines with key + +%(trailers:key=Reviewed-by)+ shows trailer lines with key `Reviewed-by`. -** 'only[=<bool>]': select whether non-trailer lines from the trailer +** `only[=<bool>]`: select whether non-trailer lines from the trailer block should be included. -** 'separator=<sep>': specify the separator inserted between trailer +** `separator=<sep>`: specify the separator inserted between trailer lines. Defaults to a line feed character. The string <sep> may contain the literal formatting codes described above. To use comma as separator one must use `%x2C` as it would otherwise be parsed as - next option. E.g., `%(trailers:key=Ticket,separator=%x2C )` + next option. E.g., +%(trailers:key=Ticket,separator=%x2C )+ shows all trailer lines whose key is "Ticket" separated by a comma and a space. -** 'unfold[=<bool>]': make it behave as if interpret-trailer's `--unfold` +** `unfold[=<bool>]`: make it behave as if interpret-trailer's `--unfold` option was given. E.g., - `%(trailers:only,unfold=true)` unfolds and shows all trailer lines. -** 'keyonly[=<bool>]': only show the key part of the trailer. -** 'valueonly[=<bool>]': only show the value part of the trailer. -** 'key_value_separator=<sep>': specify the separator inserted between + +%(trailers:only,unfold=true)+ unfolds and shows all trailer lines. +** `keyonly[=<bool>]`: only show the key part of the trailer. +** `valueonly[=<bool>]`: only show the value part of the trailer. +** `key_value_separator=<sep>`: specify the separator inserted between the key and value of each trailer. Defaults to ": ". Otherwise it - shares the same semantics as 'separator=<sep>' above. + shares the same semantics as `separator=<sep>` above. NOTE: Some placeholders may depend on other options given to the -revision traversal engine. For example, the `%g*` reflog options will +revision traversal engine. For example, the +%g*+ reflog options will insert an empty string unless we are traversing reflog entries (e.g., by -`git log -g`). The `%d` and `%D` placeholders will use the "short" +`git log -g`). The +%d+ and +%D+ placeholders will use the "short" decoration format if `--decorate` was not already provided on the command line. The boolean options accept an optional value `[=<bool-value>]`. The -values taken by `--type=bool` git-config[1], like `yes` and `off`, +values taken by `--type=bool` linkgit:git-config[1], like `yes` and `off`, are all accepted. Giving a boolean option without `=<value>` is equivalent to giving it with `=true`. -If you add a `+` (plus sign) after '%' of a placeholder, a line-feed +If you add a `+` (plus sign) after +%+ of a placeholder, a line-feed is inserted immediately before the expansion if and only if the placeholder expands to a non-empty string. -If you add a `-` (minus sign) after '%' of a placeholder, all consecutive +If you add a `-` (minus sign) after +%+ of a placeholder, all consecutive line-feeds immediately preceding the expansion are deleted if and only if the placeholder expands to an empty string. -If you add a ` ` (space) after '%' of a placeholder, a space +If you add a `' '` (space) after +%+ of a placeholder, a space is inserted immediately before the expansion if and only if the placeholder expands to a non-empty string. -* 'tformat:' +* `tformat:` + -The 'tformat:' format works exactly like 'format:', except that it +The `tformat:` format works exactly like `format:`, except that it provides "terminator" semantics instead of "separator" semantics. In other words, each commit has the message terminator character (usually a newline) appended, rather than a separator placed between entries. @@ -378,7 +381,7 @@ $ git log -2 --pretty=tformat:%h 4da45bef \ 7134973 --------------------- + -In addition, any unrecognized string that has a `%` in it is interpreted +In addition, any unrecognized string that has a +%+ in it is interpreted as if it has `tformat:` in front of it. For example, these two are equivalent: + diff --git a/Documentation/pretty-options.adoc b/Documentation/pretty-options.adoc index b36e96abe2..8aac51dbe7 100644 --- a/Documentation/pretty-options.adoc +++ b/Documentation/pretty-options.adoc @@ -1,38 +1,38 @@ ---pretty[=<format>]:: ---format=<format>:: +`--pretty[=<format>]`:: +`--format=<format>`:: Pretty-print the contents of the commit logs in a given format, - where '<format>' can be one of 'oneline', 'short', 'medium', - 'full', 'fuller', 'reference', 'email', 'raw', 'format:<string>' - and 'tformat:<string>'. When '<format>' is none of the above, - and has '%placeholder' in it, it acts as if - '--pretty=tformat:<format>' were given. + where '<format>' can be one of `oneline`, `short`, `medium`, + `full`, `fuller`, `reference`, `email`, `raw`, `format:<string>` + and `tformat:<string>`. When _<format>_ is none of the above, + and has `%<placeholder>` in it, it acts as if + `--pretty=tformat:<format>` were given. + See the "PRETTY FORMATS" section for some additional details for each -format. When '=<format>' part is omitted, it defaults to 'medium'. +format. When `=<format>` part is omitted, it defaults to `medium`. + -Note: you can specify the default pretty format in the repository +NOTE: you can specify the default pretty format in the repository configuration (see linkgit:git-config[1]). ---abbrev-commit:: +`--abbrev-commit`:: Instead of showing the full 40-byte hexadecimal commit object name, show a prefix that names the object uniquely. - "--abbrev=<n>" (which also modifies diff output, if it is displayed) + `--abbrev=<n>` (which also modifies diff output, if it is displayed) option can be used to specify the minimum length of the prefix. + -This should make "--pretty=oneline" a whole lot more readable for +This should make `--pretty=oneline` a whole lot more readable for people using 80-column terminals. ---no-abbrev-commit:: +`--no-abbrev-commit`:: Show the full 40-byte hexadecimal commit object name. This negates `--abbrev-commit`, either explicit or implied by other options such - as "--oneline". It also overrides the `log.abbrevCommit` variable. + as `--oneline`. It also overrides the `log.abbrevCommit` variable. ---oneline:: - This is a shorthand for "--pretty=oneline --abbrev-commit" +`--oneline`:: + This is a shorthand for `--pretty=oneline --abbrev-commit` used together. ---encoding=<encoding>:: +`--encoding=<encoding>`:: Commit objects record the character encoding used for the log message in their encoding header; this option can be used to tell the command to re-code the commit log message in the encoding @@ -44,22 +44,22 @@ people using 80-column terminals. to convert the commit, we will quietly output the original object verbatim. ---expand-tabs=<n>:: ---expand-tabs:: ---no-expand-tabs:: +`--expand-tabs=<n>`:: +`--expand-tabs`:: +`--no-expand-tabs`:: Perform a tab expansion (replace each tab with enough spaces - to fill to the next display column that is a multiple of '<n>') + to fill to the next display column that is a multiple of _<n>_) in the log message before showing it in the output. `--expand-tabs` is a short-hand for `--expand-tabs=8`, and `--no-expand-tabs` is a short-hand for `--expand-tabs=0`, which disables tab expansion. + By default, tabs are expanded in pretty formats that indent the log -message by 4 spaces (i.e. 'medium', which is the default, 'full', -and 'fuller'). +message by 4 spaces (i.e. `medium`, which is the default, `full`, +and `fuller`). ifndef::git-rev-list[] ---notes[=<ref>]:: +`--notes[=<ref>]`:: Show the notes (see linkgit:git-notes[1]) that annotate the commit, when showing the commit log message. This is the default ifndef::with-breaking-changes[] @@ -80,28 +80,29 @@ to display. The ref can specify the full refname when it begins with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise `refs/notes/` is prefixed to form the full name of the ref. + -Multiple --notes options can be combined to control which notes are -being displayed. Examples: "--notes=foo" will show only notes from -"refs/notes/foo"; "--notes=foo --notes" will show both notes from +Multiple `--notes` options can be combined to control which notes are +being displayed. Examples: "`--notes=foo`" will show only notes from +`refs/notes/foo`; "`--notes=foo --notes`" will show both notes from "refs/notes/foo" and from the default notes ref(s). ---no-notes:: +`--no-notes`:: Do not show notes. This negates the above `--notes` option, by resetting the list of notes refs from which notes are shown. Options are parsed in the order given on the command line, so e.g. - "--notes --notes=foo --no-notes --notes=bar" will only show notes - from "refs/notes/bar". + "`--notes --notes=foo --no-notes --notes=bar`" will only show notes + from `refs/notes/bar`. ---show-notes-by-default:: +`--show-notes-by-default`:: Show the default notes unless options for displaying specific notes are given. ---show-notes[=<ref>]:: ---[no-]standard-notes:: - These options are deprecated. Use the above --notes/--no-notes +`--show-notes[=<ref>]`:: +`--standard-notes`:: +`--no-standard-notes`:: + These options are deprecated. Use the above `--notes`/`--no-notes` options instead. endif::git-rev-list[] ---show-signature:: +`--show-signature`:: Check the validity of a signed commit object by passing the signature to `gpg --verify` and show the output. diff --git a/Documentation/rev-list-description.adoc b/Documentation/rev-list-description.adoc index a9efa7fa27..82c680e570 100644 --- a/Documentation/rev-list-description.adoc +++ b/Documentation/rev-list-description.adoc @@ -26,8 +26,8 @@ endif::git-log[] means "list all the commits which are reachable from 'foo' or 'bar', but not from 'baz'". -A special notation "'<commit1>'..'<commit2>'" can be used as a -short-hand for "^'<commit1>' '<commit2>'". For example, either of +A special notation "`<commit1>..<commit2>`" can be used as a +short-hand for "`^<commit1> <commit2>`". For example, either of the following may be used interchangeably: ifdef::git-rev-list[] @@ -43,7 +43,7 @@ $ git log HEAD ^origin ----------------------------------------------------------------------- endif::git-log[] -Another special notation is "'<commit1>'...'<commit2>'" which is useful +Another special notation is "`<commit1>...<commit2>`" which is useful for merges. The resulting set of commits is the symmetric difference between the two operands. The following two commands are equivalent: diff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc index ae8765644c..d9665d82c8 100644 --- a/Documentation/rev-list-options.adoc +++ b/Documentation/rev-list-options.adoc @@ -6,60 +6,60 @@ special notations explained in the description, additional commit limiting may be applied. Using more options generally further limits the output (e.g. -`--since=<date1>` limits to commits newer than `<date1>`, and using it +`--since=<date1>` limits to commits newer than _<date1>_, and using it with `--grep=<pattern>` further limits to commits whose log message -has a line that matches `<pattern>`), unless otherwise noted. +has a line that matches _<pattern>_), unless otherwise noted. Note that these are applied before commit ordering and formatting options, such as `--reverse`. --<number>:: --n <number>:: ---max-count=<number>:: - Limit the number of commits to output. +`-<number>`:: +`-n <number>`:: +`--max-count=<number>`:: + Limit the output to _<number>_ commits. ---skip=<number>:: - Skip 'number' commits before starting to show the commit output. +`--skip=<number>`:: + Skip _<number>_ commits before starting to show the commit output. ---since=<date>:: ---after=<date>:: - Show commits more recent than a specific date. +`--since=<date>`:: +`--after=<date>`:: + Show commits more recent than _<date>_. ---since-as-filter=<date>:: - Show all commits more recent than a specific date. This visits +`--since-as-filter=<date>`:: + Show all commits more recent than _<date>_. This visits all commits in the range, rather than stopping at the first commit which - is older than a specific date. + is older than _<date>_. ---until=<date>:: ---before=<date>:: - Show commits older than a specific date. +`--until=<date>`:: +`--before=<date>`:: + Show commits older than _<date>_. ifdef::git-rev-list[] ---max-age=<timestamp>:: ---min-age=<timestamp>:: +`--max-age=<timestamp>`:: +`--min-age=<timestamp>`:: Limit the commits output to specified time range. endif::git-rev-list[] ---author=<pattern>:: ---committer=<pattern>:: +`--author=<pattern>`:: +`--committer=<pattern>`:: Limit the commits output to ones with author/committer - header lines that match the specified pattern (regular - expression). With more than one `--author=<pattern>`, - commits whose author matches any of the given patterns are + header lines that match the _<pattern>_ regular + expression. With more than one `--author=<pattern>`, + commits whose author matches any of the _<pattern>_ are chosen (similarly for multiple `--committer=<pattern>`). ---grep-reflog=<pattern>:: +`--grep-reflog=<pattern>`:: Limit the commits output to ones with reflog entries that - match the specified pattern (regular expression). With + match the _<pattern>_ regular expression. With more than one `--grep-reflog`, commits whose reflog message matches any of the given patterns are chosen. It is an error to use this option unless `--walk-reflogs` is in use. ---grep=<pattern>:: +`--grep=<pattern>`:: Limit the commits output to ones with a log message that - matches the specified pattern (regular expression). With + matches the _<pattern>_ regular expression. With more than one `--grep=<pattern>`, commits whose message - matches any of the given patterns are chosen (but see + matches any of the _<pattern>_ are chosen (but see `--all-match`). ifndef::git-rev-list[] + @@ -67,35 +67,35 @@ When `--notes` is in effect, the message from the notes is matched as if it were part of the log message. endif::git-rev-list[] ---all-match:: +`--all-match`:: Limit the commits output to ones that match all given `--grep`, instead of ones that match at least one. ---invert-grep:: +`--invert-grep`:: Limit the commits output to ones with a log message that do not - match the pattern specified with `--grep=<pattern>`. + match the _<pattern>_ specified with `--grep=<pattern>`. --i:: ---regexp-ignore-case:: +`-i`:: +`--regexp-ignore-case`:: Match the regular expression limiting patterns without regard to letter case. ---basic-regexp:: +`--basic-regexp`:: Consider the limiting patterns to be basic regular expressions; this is the default. --E:: ---extended-regexp:: +`-E`:: +`--extended-regexp`:: Consider the limiting patterns to be extended regular expressions instead of the default basic regular expressions. --F:: ---fixed-strings:: +`-F`:: +`--fixed-strings`:: Consider the limiting patterns to be fixed strings (don't interpret pattern as a regular expression). --P:: ---perl-regexp:: +`-P`:: +`--perl-regexp`:: Consider the limiting patterns to be Perl-compatible regular expressions. + @@ -103,20 +103,20 @@ Support for these types of regular expressions is an optional compile-time dependency. If Git wasn't compiled with support for them providing this option will cause it to die. ---remove-empty:: +`--remove-empty`:: Stop when a given path disappears from the tree. ---merges:: +`--merges`:: Print only merge commits. This is exactly the same as `--min-parents=2`. ---no-merges:: +`--no-merges`:: Do not print commits with more than one parent. This is exactly the same as `--max-parents=1`. ---min-parents=<number>:: ---max-parents=<number>:: ---no-min-parents:: ---no-max-parents:: +`--min-parents=<number>`:: +`--max-parents=<number>`:: +`--no-min-parents`:: +`--no-max-parents`:: Show only commits which have at least (or at most) that many parent commits. In particular, `--max-parents=1` is the same as `--no-merges`, `--min-parents=2` is the same as `--merges`. `--max-parents=0` @@ -126,7 +126,7 @@ providing this option will cause it to die. again. Equivalent forms are `--min-parents=0` (any commit has 0 or more parents) and `--max-parents=-1` (negative numbers denote no upper limit). ---first-parent:: +`--first-parent`:: When finding commits to include, follow only the first parent commit upon seeing a merge commit. This option can give a better overview when viewing the evolution of @@ -141,14 +141,14 @@ This option also changes default diff format for merge commits to `first-parent`, see `--diff-merges=first-parent` for details. endif::git-log[] ---exclude-first-parent-only:: +`--exclude-first-parent-only`:: When finding commits to exclude (with a '{caret}'), follow only the first parent commit upon seeing a merge commit. This can be used to find the set of changes in a topic branch from the point where it diverged from the remote branch, given that arbitrary merges can be valid topic branch changes. ---not:: +`--not`:: Reverses the meaning of the '{caret}' prefix (or lack thereof) for all following revision specifiers, up to the next `--not`. When used on the command line before --stdin, the revisions passed @@ -156,37 +156,37 @@ endif::git-log[] via standard input, the revisions passed on the command line will not be affected by it. ---all:: +`--all`:: Pretend as if all the refs in `refs/`, along with `HEAD`, are - listed on the command line as '<commit>'. + listed on the command line as _<commit>_. ---branches[=<pattern>]:: +`--branches[=<pattern>]`:: Pretend as if all the refs in `refs/heads` are listed - on the command line as '<commit>'. If '<pattern>' is given, limit - branches to ones matching given shell glob. If pattern lacks '?', + on the command line as _<commit>_. If _<pattern>_ is given, limit + branches to ones matching given shell glob. If _<pattern>_ lacks '?', '{asterisk}', or '[', '/{asterisk}' at the end is implied. ---tags[=<pattern>]:: +`--tags[=<pattern>]`:: Pretend as if all the refs in `refs/tags` are listed - on the command line as '<commit>'. If '<pattern>' is given, limit + on the command line as _<commit>_. If _<pattern>_ is given, limit tags to ones matching given shell glob. If pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the end is implied. ---remotes[=<pattern>]:: +`--remotes[=<pattern>]`:: Pretend as if all the refs in `refs/remotes` are listed - on the command line as '<commit>'. If '<pattern>' is given, limit + on the command line as _<commit>_. If _<pattern>_ is given, limit remote-tracking branches to ones matching given shell glob. If pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the end is implied. ---glob=<glob-pattern>:: - Pretend as if all the refs matching shell glob '<glob-pattern>' - are listed on the command line as '<commit>'. Leading 'refs/', +`--glob=<glob-pattern>`:: + Pretend as if all the refs matching shell glob _<glob-pattern>_ + are listed on the command line as _<commit>_. Leading 'refs/', is automatically prepended if missing. If pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the end is implied. ---exclude=<glob-pattern>:: +`--exclude=<glob-pattern>`:: - Do not include refs matching '<glob-pattern>' that the next `--all`, + Do not include refs matching _<glob-pattern>_ that the next `--all`, `--branches`, `--tags`, `--remotes`, or `--glob` would otherwise consider. Repetitions of this option accumulate exclusion patterns up to the next `--all`, `--branches`, `--tags`, `--remotes`, or @@ -199,7 +199,7 @@ respectively, and they must begin with `refs/` when applied to `--glob` or `--all`. If a trailing '/{asterisk}' is intended, it must be given explicitly. ---exclude-hidden=[fetch|receive|uploadpack]:: +`--exclude-hidden=(fetch|receive|uploadpack)`:: Do not include refs that would be hidden by `git-fetch`, `git-receive-pack` or `git-upload-pack` by consulting the appropriate `fetch.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs` @@ -207,11 +207,11 @@ explicitly. linkgit:git-config[1]). This option affects the next pseudo-ref option `--all` or `--glob` and is cleared after processing them. ---reflog:: +`--reflog`:: Pretend as if all objects mentioned by reflogs are listed on the - command line as `<commit>`. + command line as _<commit>_. ---alternate-refs:: +`--alternate-refs`:: Pretend as if all objects mentioned as ref tips of alternate repositories were listed on the command line. An alternate repository is any repository whose object directory is specified @@ -219,7 +219,7 @@ explicitly. be modified by `core.alternateRefsCommand`, etc. See linkgit:git-config[1]. ---single-worktree:: +`--single-worktree`:: By default, all working trees will be examined by the following options when there are more than one (see linkgit:git-worktree[1]): `--all`, `--reflog` and @@ -227,19 +227,19 @@ explicitly. This option forces them to examine the current working tree only. ---ignore-missing:: +`--ignore-missing`:: Upon seeing an invalid object name in the input, pretend as if the bad input was not given. ifndef::git-rev-list[] ---bisect:: +`--bisect`:: Pretend as if the bad bisection ref `refs/bisect/bad` was listed and as if it was followed by `--not` and the good bisection refs `refs/bisect/good-*` on the command line. endif::git-rev-list[] ---stdin:: +`--stdin`:: In addition to getting arguments from the command line, read them from standard input as well. This accepts commits and pseudo-options like `--all` and `--glob=`. When a `--` separator @@ -249,15 +249,15 @@ endif::git-rev-list[] influence any subsequent command line arguments. ifdef::git-rev-list[] ---quiet:: +`--quiet`:: Don't print anything to standard output. This form is primarily meant to allow the caller to test the exit status to see if a range of objects is fully connected (or not). It is faster than redirecting stdout to `/dev/null` as the output does not have to be formatted. ---disk-usage:: ---disk-usage=human:: +`--disk-usage`:: +`--disk-usage=human`:: Suppress normal output; instead, print the sum of the bytes used for on-disk storage by the selected commits or objects. This is equivalent to piping the output into `git cat-file @@ -269,11 +269,11 @@ ifdef::git-rev-list[] in human-readable string(e.g. 12.24 Kib, 3.50 Mib). endif::git-rev-list[] ---cherry-mark:: +`--cherry-mark`:: Like `--cherry-pick` (see below) but mark equivalent commits with `=` rather than omitting them, and inequivalent ones with `+`. ---cherry-pick:: +`--cherry-pick`:: Omit any commit that introduces the same change as another commit on the ``other side'' when the set of commits are limited with symmetric difference. @@ -286,8 +286,8 @@ cherry-picked from the other branch (for example, ``3rd on b'' may be cherry-picked from branch A). With this option, such pairs of commits are excluded from the output. ---left-only:: ---right-only:: +`--left-only`:: +`--right-only`:: List only commits on the respective side of a symmetric difference, i.e. only those which would be marked `<` resp. `>` by `--left-right`. @@ -298,20 +298,20 @@ commits from `B` which are in `A` or are patch-equivalent to a commit in More precisely, `--cherry-pick --right-only --no-merges` gives the exact list. ---cherry:: +`--cherry`:: A synonym for `--right-only --cherry-mark --no-merges`; useful to limit the output to the commits on our side and mark those that have been applied to the other side of a forked history with `git log --cherry upstream...mybranch`, similar to `git cherry upstream mybranch`. --g:: ---walk-reflogs:: +`-g`:: +`--walk-reflogs`:: Instead of walking the commit ancestry chain, walk reflog entries from the most recent one to older ones. When this option is used you cannot specify commits to - exclude (that is, '{caret}commit', 'commit1..commit2', - and 'commit1\...commit2' notations cannot be used). + exclude (that is, `^<commit>`, `<commit1>..<commit2>`, + and `<commit1>...<commit2>` notations cannot be used). + With `--pretty` format other than `oneline` and `reference` (for obvious reasons), this causes the output to have two extra lines of information @@ -340,29 +340,29 @@ See also linkgit:git-reflog[1]. + Under `--pretty=reference`, this information will not be shown at all. ---merge:: +`--merge`:: Show commits touching conflicted paths in the range `HEAD...<other>`, where `<other>` is the first existing pseudoref in `MERGE_HEAD`, `CHERRY_PICK_HEAD`, `REVERT_HEAD` or `REBASE_HEAD`. Only works when the index has unmerged entries. This option can be used to show relevant commits when resolving conflicts from a 3-way merge. ---boundary:: +`--boundary`:: Output excluded boundary commits. Boundary commits are prefixed with `-`. ifdef::git-rev-list[] ---use-bitmap-index:: +`--use-bitmap-index`:: Try to speed up the traversal using the pack bitmap index (if one is available). Note that when traversing with `--objects`, trees and blobs will not have their associated path printed. ---progress=<header>:: +`--progress=<header>`:: Show progress reports on stderr as objects are considered. The `<header>` text will be printed with each progress update. --z:: +`-z`:: Instead of being newline-delimited, each outputted object and its accompanying metadata is delimited using NUL bytes. Output is printed in the following form: @@ -397,56 +397,56 @@ is how to do it, as there are various strategies to simplify the history. The following options select the commits to be shown: -<paths>:: +`<paths>`:: Commits modifying the given <paths> are selected. ---simplify-by-decoration:: +`--simplify-by-decoration`:: Commits that are referred by some branch or tag are selected. Note that extra commits can be shown to give a meaningful history. The following options affect the way the simplification is performed: -Default mode:: +`Default mode`:: Simplifies the history to the simplest history explaining the final state of the tree. Simplest because it prunes some side branches if the end result is the same (i.e. merging branches with the same content) ---show-pulls:: +`--show-pulls`:: Include all commits from the default mode, but also any merge commits that are not TREESAME to the first parent but are TREESAME to a later parent. This mode is helpful for showing the merge commits that "first introduced" a change to a branch. ---full-history:: +`--full-history`:: Same as the default mode, but does not prune some history. ---dense:: +`--dense`:: Only the selected commits are shown, plus some to have a meaningful history. ---sparse:: +`--sparse`:: All commits in the simplified history are shown. ---simplify-merges:: +`--simplify-merges`:: Additional option to `--full-history` to remove some needless merges from the resulting history, as there are no selected commits contributing to this merge. ---ancestry-path[=<commit>]:: - When given a range of commits to display (e.g. 'commit1..commit2' - or 'commit2 {caret}commit1'), and a commit <commit> in that range, +`--ancestry-path[=<commit>]`:: + When given a range of commits to display (e.g. `<commit1>..<commit2>` + or `<commit2> ^<commit1>`), and a commit _<commit>_ in that range, only display commits in that range - that are ancestors of <commit>, descendants of <commit>, or - <commit> itself. If no commit is specified, use 'commit1' (the - excluded part of the range) as <commit>. Can be passed multiple + that are ancestors of _<commit>_, descendants of _<commit>_, or + _<commit>_ itself. If no commit is specified, use _<commit1>_ (the + excluded part of the range) as _<commit>_. Can be passed multiple times; if so, a commit is included if it is any of the commits given or if it is an ancestor or descendant of one of them. A more detailed explanation follows. -Suppose you specified `foo` as the <paths>. We shall call commits +Suppose you specified `foo` as the _<paths>_. We shall call commits that modify `foo` !TREESAME, and the rest TREESAME. (In a diff filtered for `foo`, they look different and equal, respectively.) @@ -466,22 +466,22 @@ The horizontal line of history A---Q is taken to be the first parent of each merge. The commits are: * `I` is the initial commit, in which `foo` exists with contents - ``asdf'', and a file `quux` exists with contents ``quux''. Initial + `asdf`, and a file `quux` exists with contents `quux`. Initial commits are compared to an empty tree, so `I` is !TREESAME. -* In `A`, `foo` contains just ``foo''. +* In `A`, `foo` contains just `foo`. * `B` contains the same change as `A`. Its merge `M` is trivial and hence TREESAME to all parents. -* `C` does not change `foo`, but its merge `N` changes it to ``foobar'', +* `C` does not change `foo`, but its merge `N` changes it to `foobar`, so it is not TREESAME to any parent. -* `D` sets `foo` to ``baz''. Its merge `O` combines the strings from - `N` and `D` to ``foobarbaz''; i.e., it is not TREESAME to any parent. +* `D` sets `foo` to `baz`. Its merge `O` combines the strings from + `N` and `D` to `foobarbaz`; i.e., it is not TREESAME to any parent. -* `E` changes `quux` to ``xyzzy'', and its merge `P` combines the - strings to ``quux xyzzy''. `P` is TREESAME to `O`, but not to `E`. +* `E` changes `quux` to `xyzzy`, and its merge `P` combines the + strings to `quux xyzzy`. `P` is TREESAME to `O`, but not to `E`. * `X` is an independent root commit that added a new file `side`, and `Y` modified it. `Y` is TREESAME to `X`. Its merge `Q` added `side` to `P`, and @@ -517,7 +517,7 @@ Parent/child relations are only visible with `--parents`, but that does not affect the commits selected in default mode, so we have shown the parent lines. ---full-history without parent rewriting:: +`--full-history` without parent rewriting:: This mode differs from the default in one point: always follow all parents of a merge, even if it is TREESAME to one of them. Even if more than one side of the merge has commits that are @@ -536,7 +536,7 @@ Note that without parent rewriting, it is not really possible to talk about the parent/child relationships between the commits, so we show them disconnected. ---full-history with parent rewriting:: +`--full-history` with parent rewriting:: Ordinary commits are only included if they are !TREESAME (though this can be changed, see `--sparse` below). + @@ -560,18 +560,18 @@ rewritten to contain `E`'s parent `I`. The same happened for `C` and In addition to the above settings, you can change whether TREESAME affects inclusion: ---dense:: +`--dense`:: Commits that are walked are included if they are not TREESAME to any parent. ---sparse:: +`--sparse`:: All commits that are walked are included. + Note that without `--full-history`, this still simplifies merges: if one of the parents is TREESAME, we follow only that one, so the other sides of the merge are never walked. ---simplify-merges:: +`--simplify-merges`:: First, build a history graph in the same way that `--full-history` with parent rewriting does (see above). + @@ -618,9 +618,9 @@ Note the major differences in `N`, `P`, and `Q` over `--full-history`: There is another simplification mode available: ---ancestry-path[=<commit>]:: +`--ancestry-path[=<commit>]`:: Limit the displayed commits to those which are an ancestor of - <commit>, or which are a descendant of <commit>, or are <commit> + _<commit>_, or which are a descendant of _<commit>_, or are _<commit>_ itself. + As an example use case, consider the following commit history: @@ -636,15 +636,15 @@ As an example use case, consider the following commit history: A regular 'D..M' computes the set of commits that are ancestors of `M`, but excludes the ones that are ancestors of `D`. This is useful to see what happened to the history leading to `M` since `D`, in the sense -that ``what does `M` have that did not exist in `D`''. The result in this +that "what does `M` have that did not exist in `D`". The result in this example would be all the commits, except `A` and `B` (and `D` itself, of course). + When we want to find out what commits in `M` are contaminated with the bug introduced by `D` and need fixing, however, we might want to view -only the subset of 'D..M' that are actually descendants of `D`, i.e. +only the subset of `D..M` that are actually descendants of `D`, i.e. excluding `C` and `K`. This is exactly what the `--ancestry-path` -option does. Applied to the 'D..M' range, it results in: +option does. Applied to the `D..M` range, it results in: + ----------------------------------------------------------------------- E-------F @@ -655,7 +655,7 @@ option does. Applied to the 'D..M' range, it results in: ----------------------------------------------------------------------- + We can also use `--ancestry-path=D` instead of `--ancestry-path` which -means the same thing when applied to the 'D..M' range but is just more +means the same thing when applied to the `D..M` range but is just more explicit. + If we instead are interested in a given topic within this range, and all @@ -770,7 +770,7 @@ into the important branch. This commit may have information about why the change `X` came to override the changes from `A` and `B` in its commit message. ---show-pulls:: +`--show-pulls`:: In addition to the commits shown in the default history, show each merge commit that is not TREESAME to its first parent but is TREESAME to a later parent. @@ -819,7 +819,7 @@ ifdef::git-rev-list[] Bisection Helpers ~~~~~~~~~~~~~~~~~ ---bisect:: +`--bisect`:: Limit output to the one commit object which is roughly halfway between included and excluded commits. Note that the bad bisection ref `refs/bisect/bad` is added to the included commits (if it @@ -843,7 +843,7 @@ introduces a regression is thus reduced to a binary search: repeatedly generate and test new 'midpoint's until the commit chain is of length one. ---bisect-vars:: +`--bisect-vars`:: This calculates the same as `--bisect`, except that refs in `refs/bisect/` are not used, and except that this outputs text ready to be eval'ed by the shell. These lines will assign the @@ -855,7 +855,7 @@ one. `bisect_bad`, and the number of commits we are bisecting right now to `bisect_all`. ---bisect-all:: +`--bisect-all`:: This outputs all the commit objects between the included and excluded commits, ordered by their distance to the included and excluded commits. Refs in `refs/bisect/` are not used. The farthest @@ -878,15 +878,15 @@ Commit Ordering By default, the commits are shown in reverse chronological order. ---date-order:: +`--date-order`:: Show no parents before all of its children are shown, but otherwise show commits in the commit timestamp order. ---author-date-order:: +`--author-date-order`:: Show no parents before all of its children are shown, but otherwise show commits in the author timestamp order. ---topo-order:: +`--topo-order`:: Show no parents before all of its children are shown, and avoid showing commits on multiple lines of history intermixed. @@ -910,8 +910,8 @@ With `--topo-order`, they would show 8 6 5 3 7 4 2 1 (or 8 7 4 2 6 5 avoid showing the commits from two parallel development track mixed together. ---reverse:: - Output the commits chosen to be shown (see Commit Limiting +`--reverse`:: + Output the commits chosen to be shown (see 'Commit Limiting' section above) in reverse order. Cannot be combined with `--walk-reflogs`. endif::git-shortlog[] @@ -923,39 +923,39 @@ Object Traversal These options are mostly targeted for packing of Git repositories. ifdef::git-rev-list[] ---objects:: +`--objects`:: Print the object IDs of any object referenced by the listed - commits. `--objects foo ^bar` thus means ``send me + commits. `--objects foo ^bar` thus means "send me all object IDs which I need to download if I have the commit - object _bar_ but not _foo_''. See also `--object-names` below. + object `bar` but not `foo`". See also `--object-names` below. ---in-commit-order:: +`--in-commit-order`:: Print tree and blob ids in order of the commits. The tree and blob ids are printed after they are first referenced by a commit. ---objects-edge:: +`--objects-edge`:: Similar to `--objects`, but also print the IDs of excluded - commits prefixed with a ``-'' character. This is used by + commits prefixed with a "`-`" character. This is used by linkgit:git-pack-objects[1] to build a ``thin'' pack, which records objects in deltified form based on objects contained in these excluded commits to reduce network traffic. ---objects-edge-aggressive:: +`--objects-edge-aggressive`:: Similar to `--objects-edge`, but it tries harder to find excluded commits at the cost of increased time. This is used instead of `--objects-edge` to build ``thin'' packs for shallow repositories. ---indexed-objects:: +`--indexed-objects`:: Pretend as if all trees and blobs used by the index are listed on the command line. Note that you probably want to use `--objects`, too. ---unpacked:: +`--unpacked`:: Only useful with `--objects`; print the object IDs that are not in packs. ---object-names:: +`--object-names`:: Only useful with `--objects`; print the names of the object IDs that are found. This is the default behavior. Note that the "name" of each object is ambiguous, and mostly intended as a @@ -964,52 +964,52 @@ ifdef::git-rev-list[] to remove newlines; and if an object would appear multiple times with different names, only one name is shown. ---no-object-names:: +`--no-object-names`:: Only useful with `--objects`; does not print the names of the object IDs that are found. This inverts `--object-names`. This flag allows the output to be more easily parsed by commands such as linkgit:git-cat-file[1]. ---filter=<filter-spec>:: +`--filter=<filter-spec>`:: Only useful with one of the `--objects*`; omits objects (usually - blobs) from the list of printed objects. The '<filter-spec>' + blobs) from the list of printed objects. The _<filter-spec>_ may be one of the following: + -The form '--filter=blob:none' omits all blobs. +The form `--filter=blob:none` omits all blobs. + -The form '--filter=blob:limit=<n>[kmg]' omits blobs of size at least n -bytes or units. n may be zero. The suffixes k, m, and g can be used -to name units in KiB, MiB, or GiB. For example, 'blob:limit=1k' +The form `--filter=blob:limit=<n>[kmg]` omits blobs of size at least _<n>_ +bytes or units. _<n>_ may be zero. The suffixes `k`, `m`, and `g` can be used +to name units in KiB, MiB, or GiB. For example, `blob:limit=1k` is the same as 'blob:limit=1024'. + -The form '--filter=object:type=(tag|commit|tree|blob)' omits all objects +The form `--filter=object:type=(tag|commit|tree|blob)` omits all objects which are not of the requested type. + -The form '--filter=sparse:oid=<blob-ish>' uses a sparse-checkout -specification contained in the blob (or blob-expression) '<blob-ish>' +The form `--filter=sparse:oid=<blob-ish>` uses a sparse-checkout +specification contained in the blob (or blob-expression) _<blob-ish>_ to omit blobs that would not be required for a sparse checkout on the requested refs. + -The form '--filter=tree:<depth>' omits all blobs and trees whose depth -from the root tree is >= <depth> (minimum depth if an object is located -at multiple depths in the commits traversed). <depth>=0 will not include +The form `--filter=tree:<depth>` omits all blobs and trees whose depth +from the root tree is >= _<depth>_ (minimum depth if an object is located +at multiple depths in the commits traversed). _<depth>_=0 will not include any trees or blobs unless included explicitly in the command-line (or -standard input when --stdin is used). <depth>=1 will include only the +standard input when `--stdin` is used). _<depth>_=1 will include only the tree and blobs which are referenced directly by a commit reachable from -<commit> or an explicitly-given object. <depth>=2 is like <depth>=1 +_<commit>_ or an explicitly-given object. _<depth>_=2 is like <depth>=1 while also including trees and blobs one more level removed from an explicitly-given commit or tree. + -Note that the form '--filter=sparse:path=<path>' that wants to read +Note that the form `--filter=sparse:path=<path>` that wants to read from an arbitrary path on the filesystem has been dropped for security reasons. + -Multiple '--filter=' flags can be specified to combine filters. Only +Multiple `--filter=` flags can be specified to combine filters. Only objects which are accepted by every filter are included. + -The form '--filter=combine:<filter1>+<filter2>+...<filterN>' can also be +The form `--filter=combine:<filter1>+<filter2>+...<filterN>` can also be used to combined several filters, but this is harder than just repeating -the '--filter' flag and is usually not necessary. Filters are joined by +the `--filter` flag and is usually not necessary. Filters are joined by '{plus}' and individual filters are %-encoded (i.e. URL-encoded). Besides the '{plus}' and '%' characters, the following characters are reserved and also must be encoded: `~!@#$^&*()[]{}\;",<>?`+'`+ @@ -1017,52 +1017,52 @@ as well as all characters with ASCII code <= `0x20`, which includes space and newline. + Other arbitrary characters can also be encoded. For instance, -'combine:tree:3+blob:none' and 'combine:tree%3A3+blob%3Anone' are +`combine:tree:3+blob:none` and `combine:tree%3A3+blob%3Anone` are equivalent. ---no-filter:: +`--no-filter`:: Turn off any previous `--filter=` argument. ---filter-provided-objects:: +`--filter-provided-objects`:: Filter the list of explicitly provided objects, which would otherwise always be printed even if they did not match any of the filters. Only useful with `--filter=`. ---filter-print-omitted:: +`--filter-print-omitted`:: Only useful with `--filter=`; prints a list of the objects omitted by the filter. Object IDs are prefixed with a ``~'' character. ---missing=<missing-action>:: +`--missing=<missing-action>`:: A debug option to help with future "partial clone" development. This option specifies how missing objects are handled. + -The form '--missing=error' requests that rev-list stop with an error if +The form `--missing=error` requests that rev-list stop with an error if a missing object is encountered. This is the default action. + -The form '--missing=allow-any' will allow object traversal to continue +The form `--missing=allow-any` will allow object traversal to continue if a missing object is encountered. Missing objects will silently be omitted from the results. + -The form '--missing=allow-promisor' is like 'allow-any', but will only +The form `--missing=allow-promisor` is like `allow-any`, but will only allow object traversal to continue for EXPECTED promisor missing objects. Unexpected missing objects will raise an error. + -The form '--missing=print' is like 'allow-any', but will also print a +The form `--missing=print` is like `allow-any`, but will also print a list of the missing objects. Object IDs are prefixed with a ``?'' character. + -The form '--missing=print-info' is like 'print', but will also print additional +The form `--missing=print-info` is like `print`, but will also print additional information about the missing object inferred from its containing object. The information is all printed on the same line with the missing object ID in the form: `?<oid> [<token>=<value>]...`. The `<token>=<value>` pairs containing -additional information are separated from each other by a SP. The value is -encoded in a token specific fashion, but SP or LF contained in value are always +additional information are separated from each other by a _SP_. The value is +encoded in a token specific fashion, but _SP_ or _LF_ contained in value are always expected to be represented in such a way that the resulting encoded value does not have either of these two problematic bytes. Each `<token>=<value>` may be one of the following: + -- * The `path=<path>` shows the path of the missing object inferred from a - containing object. A path containing SP or special characters is enclosed in + containing object. A path containing _SP_ or special characters is enclosed in double-quotes in the C style as needed. + * The `type=<type>` shows the type of the missing object inferred from a @@ -1073,7 +1073,7 @@ If some tips passed to the traversal are missing, they will be considered as missing too, and the traversal will ignore them. In case we cannot get their Object ID though, an error will be raised. ---exclude-promisor-objects:: +`--exclude-promisor-objects`:: (For internal use only.) Prefilter object traversal at promisor boundary. This is used with partial clone. This is stronger than `--missing=allow-promisor` because it limits the @@ -1081,7 +1081,7 @@ we cannot get their Object ID though, an error will be raised. objects. endif::git-rev-list[] ---no-walk[=(sorted|unsorted)]:: +`--no-walk[=(sorted|unsorted)]`:: Only show the given commits, but do not traverse their ancestors. This has no effect if a range is specified. If the argument `unsorted` is given, the commits are shown in the order they were @@ -1090,7 +1090,7 @@ endif::git-rev-list[] by commit time. Cannot be combined with `--graph`. ---do-walk:: +`--do-walk`:: Overrides a previous `--no-walk`. endif::git-shortlog[] @@ -1111,10 +1111,10 @@ endif::git-rev-list[] include::pretty-options.adoc[] ---relative-date:: +`--relative-date`:: Synonym for `--date=relative`. ---date=<format>:: +`--date=<format>`:: Only takes effect for dates shown in human-readable format, such as when using `--pretty`. `log.date` config variable sets a default value for the log command's `--date` option. By default, dates @@ -1164,12 +1164,12 @@ omitted. 1970). As with `--raw`, this is always in UTC and therefore `-local` has no effect. -`--date=format:...` feeds the format `...` to your system `strftime`, -except for %s, %z, and %Z, which are handled internally. +`--date=format:<format>` feeds the _<format>_ to your system `strftime`, +except for `%s`, `%z`, and `%Z`, which are handled internally. Use `--date=format:%c` to show the date in your system locale's -preferred format. See the `strftime` manual for a complete list of +preferred format. See the `strftime`(3) manual for a complete list of format placeholders. When using `-local`, the correct syntax is -`--date=format-local:...`. +`--date=format-local:<format>`. `--date=default` is the default format, and is based on ctime(3) output. It shows a single line with three-letter day of the week, @@ -1179,33 +1179,33 @@ the local time zone is used, e.g. `Thu Jan 1 00:00:00 1970 +0000`. -- ifdef::git-rev-list[] ---header:: +`--header`:: Print the contents of the commit in raw-format; each record is separated with a NUL character. ---no-commit-header:: +`--no-commit-header`:: Suppress the header line containing "commit" and the object ID printed before the specified format. This has no effect on the built-in formats; only custom formats are affected. ---commit-header:: +`--commit-header`:: Overrides a previous `--no-commit-header`. endif::git-rev-list[] ---parents:: +`--parents`:: Print also the parents of the commit (in the form "commit parent..."). Also enables parent rewriting, see 'History Simplification' above. ---children:: +`--children`:: Print also the children of the commit (in the form "commit child..."). Also enables parent rewriting, see 'History Simplification' above. ifdef::git-rev-list[] ---timestamp:: +`--timestamp`:: Print the raw commit timestamp. endif::git-rev-list[] ---left-right:: +`--left-right`:: Mark which side of a symmetric difference a commit is reachable from. Commits from the left side are prefixed with `<` and those from the right with `>`. If combined with `--boundary`, those @@ -1234,7 +1234,7 @@ you would get an output like this: -xxxxxxx... 1st on a ----------------------------------------------------------------------- ---graph:: +`--graph`:: Draw a text-based graphical representation of the commit history on the left hand side of the output. This may cause extra lines to be printed in between commits, in order for the graph history @@ -1246,15 +1246,15 @@ This enables parent rewriting, see 'History Simplification' above. This implies the `--topo-order` option by default, but the `--date-order` option may also be specified. ---show-linear-break[=<barrier>]:: - When --graph is not used, all history branches are flattened +`--show-linear-break[=<barrier>]`:: + When `--graph` is not used, all history branches are flattened which can make it hard to see that the two consecutive commits do not belong to a linear branch. This option puts a barrier - in between them in that case. If `<barrier>` is specified, it + in between them in that case. If _<barrier>_ is specified, it is the string that will be shown instead of the default one. ifdef::git-rev-list[] ---count:: +`--count`:: Print a number stating how many commits would have been listed, and suppress all other output. When used together with `--left-right`, instead print the counts for left and diff --git a/Documentation/user-manual.adoc b/Documentation/user-manual.adoc index 8d00a9e822..7696987117 100644 --- a/Documentation/user-manual.adoc +++ b/Documentation/user-manual.adoc @@ -4270,7 +4270,7 @@ So, look into `builtin/cat-file.c`, search for `cmd_cat_file()` and look what it does. ------------------------------------------------------------------ - git_config(git_default_config); + repo_config(the_repository, git_default_config); if (argc != 3) usage("git cat-file [-t|-s|-e|-p|<type>] <sha1>"); if (get_sha1(argv[2], sha1)) @@ -114,8 +114,6 @@ include shared.mak # # Define NO_INTPTR_T if you don't have intptr_t or uintptr_t. # -# Define NO_UINTMAX_T if you don't have uintmax_t. -# # Define NEEDS_SOCKET if linking with libc is not enough (SunOS, # Patrick Mauritz). # @@ -1364,29 +1362,28 @@ CLAR_TEST_SUITES += u-oid-array CLAR_TEST_SUITES += u-oidmap CLAR_TEST_SUITES += u-oidtree CLAR_TEST_SUITES += u-prio-queue +CLAR_TEST_SUITES += u-reftable-basics +CLAR_TEST_SUITES += u-reftable-block +CLAR_TEST_SUITES += u-reftable-merged +CLAR_TEST_SUITES += u-reftable-pq +CLAR_TEST_SUITES += u-reftable-readwrite +CLAR_TEST_SUITES += u-reftable-stack +CLAR_TEST_SUITES += u-reftable-table CLAR_TEST_SUITES += u-reftable-tree CLAR_TEST_SUITES += u-strbuf CLAR_TEST_SUITES += u-strcmp-offset +CLAR_TEST_SUITES += u-string-list CLAR_TEST_SUITES += u-strvec CLAR_TEST_SUITES += u-trailer CLAR_TEST_SUITES += u-urlmatch-normalization CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X) CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES)) CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/clar/clar.o -CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/lib-oid.o +CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o +CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o -UNIT_TEST_PROGRAMS += t-reftable-basics -UNIT_TEST_PROGRAMS += t-reftable-block -UNIT_TEST_PROGRAMS += t-reftable-merged -UNIT_TEST_PROGRAMS += t-reftable-pq -UNIT_TEST_PROGRAMS += t-reftable-readwrite -UNIT_TEST_PROGRAMS += t-reftable-record -UNIT_TEST_PROGRAMS += t-reftable-stack -UNIT_TEST_PROGRAMS += t-reftable-table -UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS)) UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o -UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o # xdiff and reftable libs may in turn depend on what is in libgit.a GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE) @@ -1918,9 +1915,6 @@ endif ifdef NO_INTPTR_T COMPAT_CFLAGS += -DNO_INTPTR_T endif -ifdef NO_UINTMAX_T - BASIC_CFLAGS += -Duintmax_t=uint32_t -endif ifdef NO_SOCKADDR_STORAGE ifdef NO_IPV6 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in @@ -3473,11 +3467,14 @@ endif coccicheck-test: $(COCCI_TEST_RES_GEN) coccicheck: coccicheck-test + ifdef SPATCH_CONCAT_COCCI -coccicheck: contrib/coccinelle/ALL.cocci.patch +COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = contrib/coccinelle/ALL.cocci.patch else -coccicheck: $(COCCICHECK_PATCHES_INTREE) +COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = $(COCCICHECK_PATCHES_INTREE) endif +coccicheck: $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES) + ! grep -q ^ $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES) /dev/null # See contrib/coccinelle/README coccicheck-pending: coccicheck-test diff --git a/add-interactive.c b/add-interactive.c index 97ff35b6f1..3e692b47ec 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -36,11 +36,14 @@ 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) +void init_add_i_state(struct add_i_state *s, struct repository *r, + struct add_p_opt *add_p_opt) { const char *value; s->r = r; + s->context = -1; + s->interhunkcontext = -1; if (repo_config_get_value(r, "color.interactive", &value)) s->use_color = -1; @@ -78,9 +81,27 @@ void init_add_i_state(struct add_i_state *s, struct repository *r) repo_config_get_string(r, "diff.algorithm", &s->interactive_diff_algorithm); + if (!repo_config_get_int(r, "diff.context", &s->context)) + if (s->context < 0) + die(_("%s cannot be negative"), "diff.context"); + if (!repo_config_get_int(r, "diff.interHunkContext", &s->interhunkcontext)) + if (s->interhunkcontext < 0) + die(_("%s cannot be negative"), "diff.interHunkContext"); + repo_config_get_bool(r, "interactive.singlekey", &s->use_single_key); if (s->use_single_key) setbuf(stdin, NULL); + + if (add_p_opt->context != -1) { + if (add_p_opt->context < 0) + die(_("%s cannot be negative"), "--unified"); + s->context = add_p_opt->context; + } + if (add_p_opt->interhunkcontext != -1) { + if (add_p_opt->interhunkcontext < 0) + die(_("%s cannot be negative"), "--inter-hunk-context"); + s->interhunkcontext = add_p_opt->interhunkcontext; + } } void clear_add_i_state(struct add_i_state *s) @@ -969,6 +990,10 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps, opts->prompt = N_("Patch update"); count = list_and_choose(s, files, opts); if (count > 0) { + struct add_p_opt add_p_opt = { + .context = s->context, + .interhunkcontext = s->interhunkcontext, + }; struct strvec args = STRVEC_INIT; struct pathspec ps_selected = { 0 }; @@ -979,7 +1004,7 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps, parse_pathspec(&ps_selected, PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL, PATHSPEC_LITERAL_PATH, "", args.v); - res = run_add_p(s->r, ADD_P_ADD, NULL, &ps_selected); + res = run_add_p(s->r, ADD_P_ADD, &add_p_opt, NULL, &ps_selected); strvec_clear(&args); clear_pathspec(&ps_selected); } @@ -1014,10 +1039,13 @@ static int run_diff(struct add_i_state *s, const struct pathspec *ps, if (count > 0) { struct child_process cmd = CHILD_PROCESS_INIT; - strvec_pushl(&cmd.args, "git", "diff", "-p", "--cached", - oid_to_hex(!is_initial ? &oid : - s->r->hash_algo->empty_tree), - "--", NULL); + strvec_pushl(&cmd.args, "git", "diff", "-p", "--cached", NULL); + if (s->context != -1) + strvec_pushf(&cmd.args, "--unified=%i", s->context); + if (s->interhunkcontext != -1) + strvec_pushf(&cmd.args, "--inter-hunk-context=%i", s->interhunkcontext); + strvec_pushl(&cmd.args, oid_to_hex(!is_initial ? &oid : + s->r->hash_algo->empty_tree), "--", NULL); for (i = 0; i < files->items.nr; i++) if (files->selected[i]) strvec_push(&cmd.args, @@ -1110,7 +1138,8 @@ static void command_prompt_help(struct add_i_state *s) _("(empty) select nothing")); } -int run_add_i(struct repository *r, const struct pathspec *ps) +int run_add_i(struct repository *r, const struct pathspec *ps, + struct add_p_opt *add_p_opt) { struct add_i_state s = { NULL }; struct print_command_item_data data = { "[", "]" }; @@ -1153,7 +1182,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps) ->util = util; } - init_add_i_state(&s, r); + init_add_i_state(&s, r, add_p_opt); /* * When color was asked for, use the prompt color for diff --git a/add-interactive.h b/add-interactive.h index 693f125e8e..4213dcd67b 100644 --- a/add-interactive.h +++ b/add-interactive.h @@ -3,6 +3,13 @@ #include "color.h" +struct add_p_opt { + int context; + int interhunkcontext; +}; + +#define ADD_P_OPT_INIT { .context = -1, .interhunkcontext = -1 } + struct add_i_state { struct repository *r; int use_color; @@ -18,14 +25,17 @@ struct add_i_state { int use_single_key; char *interactive_diff_filter, *interactive_diff_algorithm; + int context, interhunkcontext; }; -void init_add_i_state(struct add_i_state *s, struct repository *r); +void init_add_i_state(struct add_i_state *s, struct repository *r, + struct add_p_opt *add_p_opt); void clear_add_i_state(struct add_i_state *s); struct repository; struct pathspec; -int run_add_i(struct repository *r, const struct pathspec *ps); +int run_add_i(struct repository *r, const struct pathspec *ps, + struct add_p_opt *add_p_opt); enum add_p_mode { ADD_P_ADD, @@ -36,6 +46,7 @@ enum add_p_mode { }; int run_add_p(struct repository *r, enum add_p_mode mode, - const char *revision, const struct pathspec *ps); + struct add_p_opt *o, const char *revision, + const struct pathspec *ps); #endif diff --git a/add-patch.c b/add-patch.c index 95c67d8c80..302e6ba7d9 100644 --- a/add-patch.c +++ b/add-patch.c @@ -414,7 +414,6 @@ static int normalize_marker(const char *p) static int parse_diff(struct add_p_state *s, const struct pathspec *ps) { struct strvec args = STRVEC_INIT; - const char *diff_algorithm = s->s.interactive_diff_algorithm; struct strbuf *plain = &s->plain, *colored = NULL; struct child_process cp = CHILD_PROCESS_INIT; char *p, *pend, *colored_p = NULL, *colored_pend = NULL, marker = '\0'; @@ -424,8 +423,12 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) int res; strvec_pushv(&args, s->mode->diff_cmd); - if (diff_algorithm) - strvec_pushf(&args, "--diff-algorithm=%s", diff_algorithm); + if (s->s.context != -1) + strvec_pushf(&args, "--unified=%i", s->s.context); + if (s->s.interhunkcontext != -1) + strvec_pushf(&args, "--inter-hunk-context=%i", s->s.interhunkcontext); + if (s->s.interactive_diff_algorithm) + strvec_pushf(&args, "--diff-algorithm=%s", s->s.interactive_diff_algorithm); if (s->revision) { struct object_id oid; strvec_push(&args, @@ -1760,14 +1763,15 @@ soft_increment: } int run_add_p(struct repository *r, enum add_p_mode mode, - const char *revision, const struct pathspec *ps) + struct add_p_opt *o, const char *revision, + const struct pathspec *ps) { struct add_p_state s = { { r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }; size_t i, binary_count = 0; - init_add_i_state(&s.s, r); + init_add_i_state(&s.s, r, o); if (mode == ADD_P_STASH) s.mode = &patch_mode_stash; @@ -48,9 +48,9 @@ struct gitdiff_data { static void git_apply_config(void) { - git_config_get_string("apply.whitespace", &apply_default_whitespace); - git_config_get_string("apply.ignorewhitespace", &apply_default_ignorewhitespace); - git_config(git_xmerge_config, NULL); + repo_config_get_string(the_repository, "apply.whitespace", &apply_default_whitespace); + repo_config_get_string(the_repository, "apply.ignorewhitespace", &apply_default_ignorewhitespace); + repo_config(the_repository, git_xmerge_config, NULL); } static int parse_whitespace_option(struct apply_state *state, const char *option) @@ -4568,7 +4568,7 @@ static int create_file(struct apply_state *state, struct patch *patch) if (patch->conflicted_threeway) return add_conflicted_stages_file(state, patch); - else if (state->update_index) + else if (state->check_index || (state->ita_only && patch->is_new > 0)) return add_index_file(state, path, mode, buf, size); return 0; } @@ -4836,7 +4836,7 @@ static int apply_patch(struct apply_state *state, LOCK_DIE_ON_ERROR); } - if (state->check_index && read_apply_cache(state) < 0) { + if ((state->check_index || state->update_index) && read_apply_cache(state) < 0) { error(_("unable to read index file")); res = -128; goto end; diff --git a/archive-tar.c b/archive-tar.c index 249164ea77..73b63ddc41 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -537,7 +537,7 @@ void init_tar_archiver(void) tar_filter_config("tar.tgz.remote", "true", NULL); tar_filter_config("tar.tar.gz.command", internal_gzip_command, NULL); tar_filter_config("tar.tar.gz.remote", "true", NULL); - git_config(git_tar_config, NULL); + repo_config(the_repository, git_tar_config, NULL); for (i = 0; i < nr_tar_filters; i++) { /* omit any filters that never had a command configured */ if (tar_filters[i]->filter_command) diff --git a/archive-zip.c b/archive-zip.c index df8866d5ba..dbd90d9c3d 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -632,7 +632,7 @@ static int write_zip_archive(const struct archiver *ar UNUSED, { int err; - git_config(archive_zip_config, NULL); + repo_config(the_repository, archive_zip_config, NULL); dos_time(&args->time, &zip_date, &zip_time); @@ -760,8 +760,8 @@ int write_archive(int argc, const char **argv, const char *prefix, const char **argv_copy; int rc; - git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable); - git_config(git_default_config, NULL); + repo_config_get_bool(the_repository, "uploadarchive.allowunreachable", &remote_allow_unreachable); + repo_config(the_repository, git_default_config, NULL); describe_status.max_invocations = 1; ctx.date_mode.type = DATE_NORMAL; @@ -27,14 +27,6 @@ struct commit_list *filter_skipped(struct commit_list *list, #define FIND_BISECTION_ALL (1u<<0) #define FIND_BISECTION_FIRST_PARENT_ONLY (1u<<1) -struct rev_list_info { - struct rev_info *revs; - int flags; - int show_timestamp; - int hdr_termination; - const char *header_prefix; -}; - /* * enum bisect_error represents the following return codes: * BISECT_OK: success code. Internally, it means that next @@ -1311,7 +1311,7 @@ static void add_bloom_key(struct blame_bloom_data *bd, } bd->keys[bd->nr] = xmalloc(sizeof(struct bloom_key)); - fill_bloom_key(path, strlen(path), bd->keys[bd->nr], bd->settings); + bloom_key_fill(bd->keys[bd->nr], path, strlen(path), bd->settings); bd->nr++; } @@ -107,7 +107,7 @@ int load_bloom_filter_from_graph(struct commit_graph *g, * Not considered to be cryptographically secure. * Implemented as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm */ -uint32_t murmur3_seeded_v2(uint32_t seed, const char *data, size_t len) +static uint32_t murmur3_seeded_v2(uint32_t seed, const char *data, size_t len) { const uint32_t c1 = 0xcc9e2d51; const uint32_t c2 = 0x1b873593; @@ -221,9 +221,7 @@ static uint32_t murmur3_seeded_v1(uint32_t seed, const char *data, size_t len) return seed; } -void fill_bloom_key(const char *data, - size_t len, - struct bloom_key *key, +void bloom_key_fill(struct bloom_key *key, const char *data, size_t len, const struct bloom_filter_settings *settings) { int i; @@ -243,7 +241,7 @@ void fill_bloom_key(const char *data, key->hashes[i] = hash0 + i * hash1; } -void clear_bloom_key(struct bloom_key *key) +void bloom_key_clear(struct bloom_key *key) { FREE_AND_NULL(key->hashes); } @@ -280,6 +278,55 @@ void deinit_bloom_filters(void) deep_clear_bloom_filter_slab(&bloom_filters, free_one_bloom_filter); } +struct bloom_keyvec *bloom_keyvec_new(const char *path, size_t len, + const struct bloom_filter_settings *settings) +{ + struct bloom_keyvec *vec; + const char *p; + size_t sz; + size_t nr = 1; + + p = path; + while (*p) { + /* + * At this point, the path is normalized to use Unix-style + * path separators. This is required due to how the + * changed-path Bloom filters store the paths. + */ + if (*p == '/') + nr++; + p++; + } + + sz = sizeof(struct bloom_keyvec); + sz += nr * sizeof(struct bloom_key); + vec = (struct bloom_keyvec *)xcalloc(1, sz); + if (!vec) + return NULL; + vec->count = nr; + + bloom_key_fill(&vec->key[0], path, len, settings); + nr = 1; + p = path + len - 1; + while (p > path) { + if (*p == '/') { + bloom_key_fill(&vec->key[nr++], path, p - path, settings); + } + p--; + } + assert(nr == vec->count); + return vec; +} + +void bloom_keyvec_free(struct bloom_keyvec *vec) +{ + if (!vec) + return; + for (size_t nr = 0; nr < vec->count; nr++) + bloom_key_clear(&vec->key[nr]); + free(vec); +} + static int pathmap_cmp(const void *hashmap_cmp_fn_data UNUSED, const struct hashmap_entry *eptr, const struct hashmap_entry *entry_or_key, @@ -500,9 +547,9 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, hashmap_for_each_entry(&pathmap, &iter, e, entry) { struct bloom_key key; - fill_bloom_key(e->path, strlen(e->path), &key, settings); + bloom_key_fill(&key, e->path, strlen(e->path), settings); add_key_to_filter(&key, filter, settings); - clear_bloom_key(&key); + bloom_key_clear(&key); } cleanup: @@ -540,3 +587,26 @@ int bloom_filter_contains(const struct bloom_filter *filter, return 1; } + +int bloom_filter_contains_vec(const struct bloom_filter *filter, + const struct bloom_keyvec *vec, + const struct bloom_filter_settings *settings) +{ + int ret = 1; + + for (size_t nr = 0; ret > 0 && nr < vec->count; nr++) + ret = bloom_filter_contains(filter, &vec->key[nr], settings); + + return ret; +} + +uint32_t test_bloom_murmur3_seeded(uint32_t seed, const char *data, size_t len, + int version) +{ + assert(version == 1 || version == 2); + + if (version == 2) + return murmur3_seeded_v2(seed, data, len); + else + return murmur3_seeded_v1(seed, data, len); +} @@ -74,24 +74,40 @@ struct bloom_key { uint32_t *hashes; }; +/* + * A bloom_keyvec is a vector of bloom_keys, which + * can be used to store multiple keys for a single + * pathspec item. + */ +struct bloom_keyvec { + size_t count; + struct bloom_key key[FLEX_ARRAY]; +}; + int load_bloom_filter_from_graph(struct commit_graph *g, struct bloom_filter *filter, uint32_t graph_pos); +void bloom_key_fill(struct bloom_key *key, const char *data, size_t len, + const struct bloom_filter_settings *settings); +void bloom_key_clear(struct bloom_key *key); + /* - * Calculate the murmur3 32-bit hash value for the given data - * using the given seed. - * Produces a uniformly distributed hash value. - * Not considered to be cryptographically secure. - * Implemented as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm + * bloom_keyvec_new - Allocate and populate a bloom_keyvec with keys for the + * given path. + * + * This function splits the input path by '/' and generates a bloom key for each + * prefix, in reverse order of specificity. For example, given the input + * "a/b/c", it will generate bloom keys for: + * - "a/b/c" + * - "a/b" + * - "a" + * + * The resulting keys are stored in a newly allocated bloom_keyvec. */ -uint32_t murmur3_seeded_v2(uint32_t seed, const char *data, size_t len); - -void fill_bloom_key(const char *data, - size_t len, - struct bloom_key *key, - const struct bloom_filter_settings *settings); -void clear_bloom_key(struct bloom_key *key); +struct bloom_keyvec *bloom_keyvec_new(const char *path, size_t len, + const struct bloom_filter_settings *settings); +void bloom_keyvec_free(struct bloom_keyvec *vec); void add_key_to_filter(const struct bloom_key *key, struct bloom_filter *filter, @@ -137,4 +153,18 @@ int bloom_filter_contains(const struct bloom_filter *filter, const struct bloom_key *key, const struct bloom_filter_settings *settings); +/* + * bloom_filter_contains_vec - Check if all keys in a key vector are in the + * Bloom filter. + * + * Returns 1 if **all** keys in the vector are present in the filter, + * 0 if **any** key is not present. + */ +int bloom_filter_contains_vec(const struct bloom_filter *filter, + const struct bloom_keyvec *v, + const struct bloom_filter_settings *settings); + +uint32_t test_bloom_murmur3_seeded(uint32_t seed, const char *data, size_t len, + int version); + #endif @@ -116,7 +116,7 @@ static int install_branch_config_multiple_remotes(int flag, const char *local, } strbuf_addf(&key, "branch.%s.remote", local); - if (git_config_set_gently(key.buf, origin ? origin : ".") < 0) + if (repo_config_set_gently(the_repository, key.buf, origin ? origin : ".") < 0) goto out_err; strbuf_reset(&key); @@ -127,16 +127,16 @@ static int install_branch_config_multiple_remotes(int flag, const char *local, * more than one is provided, use CONFIG_REGEX_NONE to preserve what * we've written so far. */ - if (git_config_set_gently(key.buf, NULL) < 0) + if (repo_config_set_gently(the_repository, key.buf, NULL) < 0) goto out_err; for_each_string_list_item(item, remotes) - if (git_config_set_multivar_gently(key.buf, item->string, CONFIG_REGEX_NONE, 0) < 0) + if (repo_config_set_multivar_gently(the_repository, key.buf, item->string, CONFIG_REGEX_NONE, 0) < 0) goto out_err; if (rebasing) { strbuf_reset(&key); strbuf_addf(&key, "branch.%s.rebase", local); - if (git_config_set_gently(key.buf, "true") < 0) + if (repo_config_set_gently(the_repository, key.buf, "true") < 0) goto out_err; } strbuf_release(&key); @@ -355,7 +355,7 @@ int read_branch_desc(struct strbuf *buf, const char *branch_name) char *v = NULL; struct strbuf name = STRBUF_INIT; strbuf_addf(&name, "branch.%s.description", branch_name); - if (git_config_get_string(name.buf, &v)) { + if (repo_config_get_string(the_repository, name.buf, &v)) { strbuf_release(&name); return -1; } diff --git a/builtin/add.c b/builtin/add.c index 7c292ffdc6..0235854f80 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -7,6 +7,7 @@ #include "builtin.h" #include "advice.h" #include "config.h" +#include "environment.h" #include "lockfile.h" #include "editor.h" #include "dir.h" @@ -29,6 +30,7 @@ static const char * const builtin_add_usage[] = { NULL }; static int patch_interactive, add_interactive, edit_interactive; +static struct add_p_opt add_p_opt = ADD_P_OPT_INIT; static int take_worktree_changes; static int add_renormalize; static int pathspec_file_nul; @@ -157,7 +159,7 @@ static int refresh(struct repository *repo, int verbose, const struct pathspec * int interactive_add(struct repository *repo, const char **argv, const char *prefix, - int patch) + int patch, struct add_p_opt *add_p_opt) { struct pathspec pathspec; int ret; @@ -169,9 +171,9 @@ int interactive_add(struct repository *repo, prefix, argv); if (patch) - ret = !!run_add_p(repo, ADD_P_ADD, NULL, &pathspec); + ret = !!run_add_p(repo, ADD_P_ADD, add_p_opt, NULL, &pathspec); else - ret = !!run_add_i(repo, &pathspec); + ret = !!run_add_i(repo, &pathspec, add_p_opt); clear_pathspec(&pathspec); return ret; @@ -253,6 +255,8 @@ static struct option builtin_add_options[] = { OPT_GROUP(""), OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")), OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")), + OPT_DIFF_UNIFIED(&add_p_opt.context), + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")), OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0), OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")), @@ -394,6 +398,11 @@ int cmd_add(int argc, prepare_repo_settings(repo); repo->settings.command_requires_full_index = 0; + if (add_p_opt.context < -1) + die(_("'%s' cannot be negative"), "--unified"); + if (add_p_opt.interhunkcontext < -1) + die(_("'%s' cannot be negative"), "--inter-hunk-context"); + if (patch_interactive) add_interactive = 1; if (add_interactive) { @@ -401,7 +410,12 @@ int cmd_add(int argc, die(_("options '%s' and '%s' cannot be used together"), "--dry-run", "--interactive/--patch"); if (pathspec_from_file) die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch"); - exit(interactive_add(repo, argv + 1, prefix, patch_interactive)); + exit(interactive_add(repo, argv + 1, prefix, patch_interactive, &add_p_opt)); + } else { + if (add_p_opt.context != -1) + die(_("the option '%s' requires '%s'"), "--unified", "--interactive/--patch"); + if (add_p_opt.interhunkcontext != -1) + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--interactive/--patch"); } if (edit_interactive) { diff --git a/builtin/am.c b/builtin/am.c index a800003340..6073d64ae9 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -162,18 +162,18 @@ static void am_state_init(struct am_state *state) state->prec = 4; - git_config_get_bool("am.threeway", &state->threeway); + repo_config_get_bool(the_repository, "am.threeway", &state->threeway); state->utf8 = 1; - git_config_get_bool("am.messageid", &state->message_id); + repo_config_get_bool(the_repository, "am.messageid", &state->message_id); state->scissors = SCISSORS_UNSET; state->quoted_cr = quoted_cr_unset; strvec_init(&state->git_apply_opts); - if (!git_config_get_bool("commit.gpgsign", &gpgsign)) + if (!repo_config_get_bool(the_repository, "commit.gpgsign", &gpgsign)) state->sign_commit = gpgsign ? "" : NULL; } @@ -965,7 +965,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format, { if (keep_cr < 0) { keep_cr = 0; - git_config_get_bool("am.keepcr", &keep_cr); + repo_config_get_bool(the_repository, "am.keepcr", &keep_cr); } switch (patch_format) { @@ -2406,6 +2406,7 @@ int cmd_am(int argc, .type = OPTION_CALLBACK, .long_name = "show-current-patch", .value = &resume_mode, + .precision = sizeof(resume_mode), .argh = "(diff|raw)", .help = N_("show the patch being applied"), .flags = PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, @@ -2444,7 +2445,7 @@ int cmd_am(int argc, show_usage_with_options_if_asked(argc, argv, usage, options); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); am_state_init(&state); diff --git a/builtin/apply.c b/builtin/apply.c index a1e20c593d..d642a40251 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -29,7 +29,7 @@ int cmd_apply(int argc, * cf. https://lore.kernel.org/git/xmqqcypfcmn4.fsf@gitster.g/ */ if (!the_hash_algo) - repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT); argc = apply_parse_options(argc, argv, &state, &force_apply, &options, diff --git a/builtin/blame.c b/builtin/blame.c index 91586e6852..5b10e84b66 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -197,9 +197,7 @@ static void commit_info_destroy(struct commit_info *ci) strbuf_release(&ci->summary); } -static void get_commit_info(struct commit *commit, - struct commit_info *ret, - int detailed) +static void get_commit_info(struct commit *commit, struct commit_info *ret) { int len; const char *subject, *encoding; @@ -211,11 +209,6 @@ static void get_commit_info(struct commit *commit, &ret->author, &ret->author_mail, &ret->author_time, &ret->author_tz); - if (!detailed) { - repo_unuse_commit_buffer(the_repository, commit, message); - return; - } - get_ac_line(message, "\ncommitter ", &ret->committer, &ret->committer_mail, &ret->committer_time, &ret->committer_tz); @@ -263,7 +256,7 @@ static int emit_one_suspect_detail(struct blame_origin *suspect, int repeat) return 0; suspect->commit->object.flags |= METAINFO_SHOWN; - get_commit_info(suspect->commit, &ci, 1); + get_commit_info(suspect->commit, &ci); printf("author %s\n", ci.author.buf); printf("author-mail %s\n", ci.author_mail.buf); printf("author-time %"PRItime"\n", ci.author_time); @@ -471,7 +464,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP); const char *default_color = NULL, *color = NULL, *reset = NULL; - get_commit_info(suspect->commit, &ci, 1); + get_commit_info(suspect->commit, &ci); oid_to_hex_r(hex, &suspect->commit->object.oid); cp = blame_nth_line(sb, ent->lno); @@ -665,7 +658,7 @@ static void find_alignment(struct blame_scoreboard *sb, int *option) if (!(suspect->commit->object.flags & METAINFO_SHOWN)) { struct commit_info ci = COMMIT_INFO_INIT; suspect->commit->object.flags |= METAINFO_SHOWN; - get_commit_info(suspect->commit, &ci, 1); + get_commit_info(suspect->commit, &ci); if (*option & OUTPUT_SHOW_EMAIL) num = utf8_strwidth(ci.author_mail.buf); else @@ -947,7 +940,7 @@ int cmd_blame(int argc, const char *const *opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage; setup_default_color_by_age(); - git_config(git_blame_config, &output_option); + repo_config(the_repository, git_blame_config, &output_option); repo_init_revisions(the_repository, &revs, NULL); revs.date_mode = blame_date_mode; revs.diffopt.flags.allow_textconv = 1; diff --git a/builtin/branch.c b/builtin/branch.c index c150131bd9..fa5ced452e 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -699,7 +699,7 @@ static int edit_branch_description(const char *branch_name) strbuf_addf(&name, "branch.%s.description", branch_name); if (buf.len || exists) - git_config_set(name.buf, buf.len ? buf.buf : NULL); + repo_config_set(the_repository, name.buf, buf.len ? buf.buf : NULL); strbuf_release(&name); strbuf_release(&buf); @@ -791,7 +791,7 @@ int cmd_branch(int argc, * Try to set sort keys from config. If config does not set any, * fall back on default (refname) sorting. */ - git_config(git_branch_config, &sorting_options); + repo_config(the_repository, git_branch_config, &sorting_options); if (!sorting_options.nr) string_list_append(&sorting_options, "refname"); @@ -987,10 +987,10 @@ int cmd_branch(int argc, strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.remote", branch->name); - git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE); + repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE); strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.merge", branch->name); - git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE); + repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE); strbuf_release(&buf); } else if (!noncreate_actions && argc > 0 && argc <= 2) { const char *branch_name = argv[0]; diff --git a/builtin/cat-file.c b/builtin/cat-file.c index aa1498aa60..fce0b06451 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -1095,7 +1095,7 @@ int cmd_cat_file(int argc, OPT_END() }; - git_config(git_cat_file_config, NULL); + repo_config(the_repository, git_cat_file_config, NULL); batch.buffer_output = -1; diff --git a/builtin/check-attr.c b/builtin/check-attr.c index 7cf275b893..51ed48ce43 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -119,7 +119,7 @@ int cmd_check_attr(int argc, if (!is_bare_repository()) setup_work_tree(); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, check_attr_options, check_attr_usage, PARSE_OPT_KEEP_DASHDASH); diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c index 7b7831d13a..644c9a414f 100644 --- a/builtin/check-ignore.c +++ b/builtin/check-ignore.c @@ -2,6 +2,7 @@ #include "builtin.h" #include "config.h" #include "dir.h" +#include "environment.h" #include "gettext.h" #include "quote.h" #include "pathspec.h" @@ -159,7 +160,7 @@ int cmd_check_ignore(int argc, int num_ignored; struct dir_struct dir = DIR_INIT; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, check_ignore_options, check_ignore_usage, 0); diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c index be2cebe121..9cc5c59830 100644 --- a/builtin/check-mailmap.c +++ b/builtin/check-mailmap.c @@ -1,6 +1,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "ident.h" #include "mailmap.h" @@ -56,7 +57,7 @@ int cmd_check_mailmap(int argc, int i; struct string_list mailmap = STRING_LIST_INIT_NODUP; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, check_mailmap_options, check_mailmap_usage, 0); if (argc == 0 && !use_stdin) diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c index da9345a44b..e0772b718b 100644 --- a/builtin/checkout--worker.c +++ b/builtin/checkout--worker.c @@ -4,6 +4,7 @@ #include "builtin.h" #include "config.h" #include "entry.h" +#include "environment.h" #include "gettext.h" #include "parallel-checkout.h" #include "parse-options.h" @@ -132,7 +133,7 @@ int cmd_checkout__worker(int argc, checkout_worker_usage, checkout_worker_options); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, checkout_worker_options, checkout_worker_usage, 0); if (argc > 0) diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 7f74bc702f..188128aebd 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -9,6 +9,7 @@ #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "lockfile.h" #include "quote.h" diff --git a/builtin/checkout.c b/builtin/checkout.c index f95eb64ffb..f9453473fe 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -61,6 +61,8 @@ static const char * const restore_usage[] = { struct checkout_opts { int patch_mode; + int patch_context; + int patch_interhunk_context; int quiet; int merge; int force; @@ -104,7 +106,12 @@ struct checkout_opts { struct tree *source_tree; }; -#define CHECKOUT_OPTS_INIT { .conflict_style = -1, .merge = -1 } +#define CHECKOUT_OPTS_INIT { \ + .conflict_style = -1, \ + .merge = -1, \ + .patch_context = -1, \ + .patch_interhunk_context = -1, \ +} struct branch_info { char *name; /* The short name used */ @@ -291,7 +298,7 @@ static int checkout_merged(int pos, const struct checkout *state, read_mmblob(&ours, &threeway[1]); read_mmblob(&theirs, &threeway[2]); - git_config_get_bool("merge.renormalize", &renormalize); + repo_config_get_bool(the_repository, "merge.renormalize", &renormalize); ll_opts.renormalize = renormalize; ll_opts.conflict_style = conflict_style; merge_status = ll_merge(&result_buf, path, &ancestor, "base", @@ -539,6 +546,10 @@ static int checkout_paths(const struct checkout_opts *opts, if (opts->patch_mode) { enum add_p_mode patch_mode; + struct add_p_opt add_p_opt = { + .context = opts->patch_context, + .interhunkcontext = opts->patch_interhunk_context, + }; const char *rev = new_branch_info->name; char rev_oid[GIT_MAX_HEXSZ + 1]; @@ -564,8 +575,8 @@ static int checkout_paths(const struct checkout_opts *opts, else BUG("either flag must have been set, worktree=%d, index=%d", opts->checkout_worktree, opts->checkout_index); - return !!run_add_p(the_repository, patch_mode, rev, - &opts->pathspec); + return !!run_add_p(the_repository, patch_mode, &add_p_opt, + rev, &opts->pathspec); } repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR); @@ -1738,6 +1749,8 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts, N_("checkout their version for unmerged files"), 3, PARSE_OPT_NONEG), OPT_BOOL('p', "patch", &opts->patch_mode, N_("select hunks interactively")), + OPT_DIFF_UNIFIED(&opts->patch_context), + OPT_DIFF_INTERHUNK_CONTEXT(&opts->patch_interhunk_context), OPT_BOOL(0, "ignore-skip-worktree-bits", &opts->ignore_skipworktree, N_("do not limit pathspecs to sparse entries only")), OPT_PATHSPEC_FROM_FILE(&opts->pathspec_from_file), @@ -1764,7 +1777,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix, opts->prefix = prefix; opts->show_progress = -1; - git_config(git_checkout_config, opts); + repo_config(the_repository, git_checkout_config, opts); if (the_repository->gitdir) { prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; @@ -1780,6 +1793,18 @@ static int checkout_main(int argc, const char **argv, const char *prefix, argc = parse_options(argc, argv, prefix, options, usagestr, parseopt_flags); + if (opts->patch_context < -1) + die(_("'%s' cannot be negative"), "--unified"); + if (opts->patch_interhunk_context < -1) + die(_("'%s' cannot be negative"), "--inter-hunk-context"); + + if (!opts->patch_mode) { + if (opts->patch_context != -1) + die(_("the option '%s' requires '%s'"), "--unified", "--patch"); + if (opts->patch_interhunk_context != -1) + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch"); + } + if (opts->show_progress < 0) { if (opts->quiet) opts->show_progress = 0; diff --git a/builtin/clean.c b/builtin/clean.c index 053c94fc6b..a1977b92dc 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -13,6 +13,7 @@ #include "abspath.h" #include "config.h" #include "dir.h" +#include "environment.h" #include "gettext.h" #include "parse-options.h" #include "path.h" @@ -949,7 +950,7 @@ int cmd_clean(int argc, OPT_END() }; - git_config(git_clean_config, NULL); + repo_config(the_repository, git_clean_config, NULL); argc = parse_options(argc, argv, prefix, options, builtin_clean_usage, 0); diff --git a/builtin/clone.c b/builtin/clone.c index 6d08abed37..c990f398ef 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -762,16 +762,16 @@ static int write_one_config(const char *key, const char *value, { /* * give git_clone_config a chance to write config values back to the - * environment, since git_config_set_multivar_gently only deals with + * environment, since repo_config_set_multivar_gently only deals with * config-file writes */ int apply_failed = git_clone_config(key, value, ctx, data); if (apply_failed) return apply_failed; - return git_config_set_multivar_gently(key, - value ? value : "true", - CONFIG_REGEX_NONE, 0); + return repo_config_set_multivar_gently(the_repository, key, + value ? value : "true", + CONFIG_REGEX_NONE, 0); } static void write_config(struct string_list *config) @@ -822,12 +822,12 @@ static void write_refspec_config(const char *src_ref_prefix, /* Configure the remote */ if (value.len) { strbuf_addf(&key, "remote.%s.fetch", remote_name); - git_config_set_multivar(key.buf, value.buf, "^$", 0); + repo_config_set_multivar(the_repository, key.buf, value.buf, "^$", 0); strbuf_reset(&key); if (option_mirror) { strbuf_addf(&key, "remote.%s.mirror", remote_name); - git_config_set(key.buf, "true"); + repo_config_set(the_repository, key.buf, "true"); strbuf_reset(&key); } } @@ -1001,7 +1001,7 @@ int cmd_clone(int argc, packet_trace_identity("clone"); - git_config(git_clone_config, NULL); + repo_config(the_repository, git_clone_config, NULL); argc = parse_options(argc, argv, prefix, builtin_clone_options, builtin_clone_usage, 0); @@ -1150,7 +1150,7 @@ int cmd_clone(int argc, strbuf_reset(&sb); } - if (!git_config_get_bool("submodule.stickyRecursiveClone", &val) && + if (!repo_config_get_bool(the_repository, "submodule.stickyRecursiveClone", &val) && val) string_list_append(&option_config, "submodule.recurse=true"); @@ -1242,7 +1242,7 @@ int cmd_clone(int argc, * re-read config after init_db and write_config to pick up any config * injected by --template and --config, respectively. */ - git_config(git_clone_config, NULL); + repo_config(the_repository, git_clone_config, NULL); /* * If option_reject_shallow is specified from CLI option, @@ -1294,18 +1294,18 @@ int cmd_clone(int argc, src_ref_prefix = "refs/"; strbuf_addstr(&branch_top, src_ref_prefix); - git_config_set("core.bare", "true"); + repo_config_set(the_repository, "core.bare", "true"); } else if (!option_rev) { strbuf_addf(&branch_top, "refs/remotes/%s/", remote_name); } strbuf_addf(&key, "remote.%s.url", remote_name); - git_config_set(key.buf, repo); + repo_config_set(the_repository, key.buf, repo); strbuf_reset(&key); if (!option_tags) { strbuf_addf(&key, "remote.%s.tagOpt", remote_name); - git_config_set(key.buf, "--no-tags"); + repo_config_set(the_repository, key.buf, "--no-tags"); strbuf_reset(&key); } @@ -1467,7 +1467,7 @@ int cmd_clone(int argc, warning(_("failed to fetch objects from bundle URI '%s'"), bundle_uri); else if (has_heuristic) - git_config_set_gently("fetch.bundleuri", bundle_uri); + repo_config_set_gently(the_repository, "fetch.bundleuri", bundle_uri); remote_state_clear(the_repository->remote_state); free(the_repository->remote_state); diff --git a/builtin/column.c b/builtin/column.c index ce6443d5fa..87dce3c6e5 100644 --- a/builtin/column.c +++ b/builtin/column.c @@ -42,9 +42,9 @@ int cmd_column(int argc, /* This one is special and must be the first one */ if (argc > 1 && starts_with(argv[1], "--command=")) { command = argv[1] + 10; - git_config(column_config, (void *)command); + repo_config(the_repository, column_config, (void *)command); } else - git_config(column_config, NULL); + repo_config(the_repository, column_config, NULL); memset(&copts, 0, sizeof(copts)); copts.padding = 1; diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c index 25018a0b9d..4992ac146e 100644 --- a/builtin/commit-graph.c +++ b/builtin/commit-graph.c @@ -2,6 +2,7 @@ #include "builtin.h" #include "commit.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "parse-options.h" @@ -265,7 +266,7 @@ static int graph_write(int argc, const char **argv, const char *prefix, trace2_cmd_mode("write"); - git_config(git_commit_graph_write_config, &opts); + repo_config(the_repository, git_commit_graph_write_config, &opts); argc = parse_options(argc, argv, prefix, options, @@ -347,7 +348,7 @@ int cmd_commit_graph(int argc, }; struct option *options = parse_options_concat(builtin_commit_graph_options, common_opts); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); disable_replace_refs(); save_commit_buffer = 0; diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index 31cfd9bd15..5189e685a7 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -6,6 +6,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "object-name.h" @@ -125,7 +126,7 @@ int cmd_commit_tree(int argc, }; int ret; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); show_usage_with_options_if_asked(argc, argv, commit_tree_usage, options); diff --git a/builtin/commit.c b/builtin/commit.c index fba0dded64..b5b9608813 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -19,6 +19,7 @@ #include "environment.h" #include "diff.h" #include "commit.h" +#include "add-interactive.h" #include "gettext.h" #include "revision.h" #include "wt-status.h" @@ -122,6 +123,7 @@ static const char *edit_message, *use_message; static char *fixup_message, *fixup_commit, *squash_message; static const char *fixup_prefix; static int all, also, interactive, patch_interactive, only, amend, signoff; +static struct add_p_opt add_p_opt = ADD_P_OPT_INIT; static int edit_flag = -1; /* unspecified */ static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; static int config_commit_verbose = -1; /* unspecified */ @@ -207,9 +209,9 @@ static void status_init_config(struct wt_status *s, config_fn_t fn) { wt_status_prepare(the_repository, s); init_diff_ui_defaults(); - git_config(fn, s); + repo_config(the_repository, fn, s); determine_whence(s); - s->hints = advice_enabled(ADVICE_STATUS_HINTS); /* must come after git_config() */ + s->hints = advice_enabled(ADVICE_STATUS_HINTS); /* must come after repo_config() */ } static void rollback_index_files(void) @@ -354,6 +356,11 @@ static const char *prepare_index(const char **argv, const char *prefix, const char *ret; char *path = NULL; + if (add_p_opt.context < -1) + die(_("'%s' cannot be negative"), "--unified"); + if (add_p_opt.interhunkcontext < -1) + die(_("'%s' cannot be negative"), "--inter-hunk-context"); + if (is_status) refresh_flags |= REFRESH_UNMERGED; parse_pathspec(&pathspec, 0, @@ -400,7 +407,7 @@ static const char *prepare_index(const char **argv, const char *prefix, old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT)); setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1); - if (interactive_add(the_repository, argv, prefix, patch_interactive) != 0) + if (interactive_add(the_repository, argv, prefix, patch_interactive, &add_p_opt) != 0) die(_("interactive add failed")); the_repository->index_file = old_repo_index_file; @@ -424,6 +431,11 @@ static const char *prepare_index(const char **argv, const char *prefix, commit_style = COMMIT_NORMAL; ret = get_lock_file_path(&index_lock); goto out; + } else { + if (add_p_opt.context != -1) + die(_("the option '%s' requires '%s'"), "--unified", "--interactive/--patch"); + if (add_p_opt.interhunkcontext != -1) + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--interactive/--patch"); } /* @@ -688,6 +700,10 @@ static void adjust_comment_line_char(const struct strbuf *sb) char candidates[] = "#;@!$%^&|:"; char *candidate; const char *p; + size_t cutoff; + + /* Ignore comment chars in trailing comments (e.g., Conflicts:) */ + cutoff = sb->len - ignored_log_message_bytes(sb->buf, sb->len); if (!memchr(sb->buf, candidates[0], sb->len)) { free(comment_line_str_to_free); @@ -700,7 +716,7 @@ static void adjust_comment_line_char(const struct strbuf *sb) candidate = strchr(candidates, *p); if (candidate) *candidate = ' '; - for (p = sb->buf; *p; p++) { + for (p = sb->buf; p + 1 < sb->buf + cutoff; p++) { if ((p[0] == '\n' || p[0] == '\r') && p[1]) { candidate = strchr(candidates, p[1]); if (candidate) @@ -1722,6 +1738,8 @@ int cmd_commit(int argc, OPT_BOOL('i', "include", &also, N_("add specified files to index for commit")), OPT_BOOL(0, "interactive", &interactive, N_("interactively add files")), OPT_BOOL('p', "patch", &patch_interactive, N_("interactively add changes")), + OPT_DIFF_UNIFIED(&add_p_opt.context), + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), OPT_BOOL('o', "only", &only, N_("commit only specified files")), OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit and commit-msg hooks")), OPT_BOOL(0, "dry-run", &dry_run, N_("show what would be committed")), diff --git a/builtin/config.c b/builtin/config.c index f70d635477..59fb113b07 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -17,9 +17,9 @@ static const char *const builtin_config_usage[] = { N_("git config list [<file-option>] [<display-option>] [--includes]"), - N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"), - N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), - N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"), + N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<pattern>] [--fixed-value] [--default=<default>] [--url=<url>] <name>"), + N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<pattern>] [--fixed-value] <name> <value>"), + N_("git config unset [<file-option>] [--all] [--value=<pattern>] [--fixed-value] <name>"), N_("git config rename-section [<file-option>] <old-name> <new-name>"), N_("git config remove-section [<file-option>] <name>"), N_("git config edit [<file-option>]"), @@ -33,17 +33,17 @@ static const char *const builtin_config_list_usage[] = { }; static const char *const builtin_config_get_usage[] = { - N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"), + N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<pattern>] [--fixed-value] [--default=<default>] <name>"), NULL }; static const char *const builtin_config_set_usage[] = { - N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), + N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<pattern>] [--fixed-value] <name> <value>"), NULL }; static const char *const builtin_config_unset_usage[] = { - N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"), + N_("git config unset [<file-option>] [--all] [--value=<pattern>] [--fixed-value] <name>"), NULL }; @@ -966,12 +966,12 @@ static int cmd_config_set(int argc, const char **argv, const char *prefix, value = normalize_value(argv[0], argv[1], type, &default_kvi); if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) { - ret = git_config_set_multivar_in_file_gently(location_opts.source.file, - argv[0], value, value_pattern, - comment, flags); + ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file, + argv[0], value, value_pattern, + comment, flags); } else { - ret = git_config_set_in_file_gently(location_opts.source.file, - argv[0], comment, value); + ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file, + argv[0], comment, value); if (ret == CONFIG_NOTHING_SET) error(_("cannot overwrite multiple values with a single value\n" " Use a regexp, --add or --replace-all to change %s."), argv[0]); @@ -1010,12 +1010,12 @@ static int cmd_config_unset(int argc, const char **argv, const char *prefix, check_write(&location_opts.source); if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) - ret = git_config_set_multivar_in_file_gently(location_opts.source.file, - argv[0], NULL, value_pattern, - NULL, flags); + ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file, + argv[0], NULL, value_pattern, + NULL, flags); else - ret = git_config_set_in_file_gently(location_opts.source.file, argv[0], - NULL, NULL); + ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file, argv[0], + NULL, NULL); location_options_release(&location_opts); return ret; @@ -1091,7 +1091,7 @@ static int show_editor(struct config_location_options *opts) die(_("editing stdin is not supported")); if (opts->source.blob) die(_("editing blobs is not supported")); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); config_file = opts->source.file ? xstrdup(opts->source.file) : repo_git_path(the_repository, "config"); @@ -1296,7 +1296,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix) check_write(&location_opts.source); check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi); - ret = git_config_set_in_file_gently(location_opts.source.file, argv[0], comment, value); + ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file, argv[0], comment, value); if (ret == CONFIG_NOTHING_SET) error(_("cannot overwrite multiple values with a single value\n" " Use a regexp, --add or --replace-all to change %s."), argv[0]); @@ -1305,26 +1305,26 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix) check_write(&location_opts.source); check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi); - ret = git_config_set_multivar_in_file_gently(location_opts.source.file, - argv[0], value, argv[2], - comment, flags); + ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file, + argv[0], value, argv[2], + comment, flags); } else if (actions == ACTION_ADD) { check_write(&location_opts.source); check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi); - ret = git_config_set_multivar_in_file_gently(location_opts.source.file, - argv[0], value, - CONFIG_REGEX_NONE, - comment, flags); + ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file, + argv[0], value, + CONFIG_REGEX_NONE, + comment, flags); } else if (actions == ACTION_REPLACE_ALL) { check_write(&location_opts.source); check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi); - ret = git_config_set_multivar_in_file_gently(location_opts.source.file, - argv[0], value, argv[2], - comment, flags | CONFIG_FLAGS_MULTI_REPLACE); + ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file, + argv[0], value, argv[2], + comment, flags | CONFIG_FLAGS_MULTI_REPLACE); } else if (actions == ACTION_GET) { check_argc(argc, 1, 2); @@ -1350,19 +1350,19 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix) check_write(&location_opts.source); check_argc(argc, 1, 2); if (argc == 2) - ret = git_config_set_multivar_in_file_gently(location_opts.source.file, - argv[0], NULL, argv[1], - NULL, flags); + ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file, + argv[0], NULL, argv[1], + NULL, flags); else - ret = git_config_set_in_file_gently(location_opts.source.file, - argv[0], NULL, NULL); + ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file, + argv[0], NULL, NULL); } else if (actions == ACTION_UNSET_ALL) { check_write(&location_opts.source); check_argc(argc, 1, 2); - ret = git_config_set_multivar_in_file_gently(location_opts.source.file, - argv[0], NULL, argv[1], - NULL, flags | CONFIG_FLAGS_MULTI_REPLACE); + ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file, + argv[0], NULL, argv[1], + NULL, flags | CONFIG_FLAGS_MULTI_REPLACE); } else if (actions == ACTION_RENAME_SECTION) { check_write(&location_opts.source); diff --git a/builtin/count-objects.c b/builtin/count-objects.c index e70a01c628..a61d3b46aa 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -7,6 +7,7 @@ #include "builtin.h" #include "config.h" #include "dir.h" +#include "environment.h" #include "gettext.h" #include "path.h" #include "parse-options.h" @@ -106,7 +107,7 @@ int cmd_count_objects(int argc, OPT_END(), }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, opts, count_objects_usage, 0); /* we do not take arguments other than flags for now */ diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c index 5065ff4660..65cc619bec 100644 --- a/builtin/credential-cache--daemon.c +++ b/builtin/credential-cache--daemon.c @@ -307,7 +307,7 @@ int cmd_credential_cache_daemon(int argc, OPT_END() }; - git_config_get_bool("credentialcache.ignoresighup", &ignore_sighup); + repo_config_get_bool(the_repository, "credentialcache.ignoresighup", &ignore_sighup); argc = parse_options(argc, argv, prefix, options, usage, 0); socket_path = argv[0]; diff --git a/builtin/credential-store.c b/builtin/credential-store.c index e669e99dbf..b74e06cc93 100644 --- a/builtin/credential-store.c +++ b/builtin/credential-store.c @@ -66,7 +66,7 @@ static void rewrite_credential_file(const char *fn, struct credential *c, { int timeout_ms = 1000; - git_config_get_int("credentialstore.locktimeoutms", &timeout_ms); + repo_config_get_int(the_repository, "credentialstore.locktimeoutms", &timeout_ms); if (hold_lock_file_for_update_timeout(&credential_lock, fn, 0, timeout_ms) < 0) die_errno(_("unable to get credential storage lock in %d ms"), timeout_ms); if (extra) diff --git a/builtin/credential.c b/builtin/credential.c index 2e11b15dde..a295c80b36 100644 --- a/builtin/credential.c +++ b/builtin/credential.c @@ -3,6 +3,7 @@ #include "git-compat-util.h" #include "credential.h" #include "builtin.h" +#include "environment.h" #include "config.h" static const char usage_msg[] = @@ -16,7 +17,7 @@ int cmd_credential(int argc, const char *op; struct credential c = CREDENTIAL_INIT; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); show_usage_if_asked(argc, argv, usage_msg); if (argc != 2) diff --git a/builtin/describe.c b/builtin/describe.c index fbf305d762..d7dd8139de 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -623,7 +623,7 @@ int cmd_describe(int argc, OPT_END(), }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, describe_usage, 0); if (abbrev < 0) abbrev = DEFAULT_ABBREV; diff --git a/builtin/diff-files.c b/builtin/diff-files.c index 99b1749723..ea91347ce2 100644 --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@ -31,7 +31,7 @@ int cmd_diff_files(int argc, show_usage_if_asked(argc, argv, diff_files_usage); - git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ + repo_config(the_repository, git_diff_basic_config, NULL); /* no "diff" UI options */ prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/diff-index.c b/builtin/diff-index.c index 81c0bc8ed7..522dacfc4c 100644 --- a/builtin/diff-index.c +++ b/builtin/diff-index.c @@ -28,7 +28,7 @@ int cmd_diff_index(int argc, show_usage_if_asked(argc, argv, diff_cache_usage); - git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ + repo_config(the_repository, git_diff_basic_config, NULL); /* no "diff" UI options */ prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index e31cc797fe..49dd4d00eb 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -124,7 +124,7 @@ int cmd_diff_tree(int argc, show_usage_if_asked(argc, argv, diff_tree_usage); - git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ + repo_config(the_repository, git_diff_basic_config, NULL); /* no "diff" UI options */ prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/diff.c b/builtin/diff.c index c6231edce4..9a89e25a98 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -483,10 +483,10 @@ int cmd_diff(int argc, * configurable via a command line option. */ if (nongit) - repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT); init_diff_ui_defaults(); - git_config(git_diff_ui_config, NULL); + repo_config(the_repository, git_diff_ui_config, NULL); prefix = precompose_argv_prefix(argc, argv, prefix); repo_init_revisions(the_repository, &rev, prefix); diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 6a3a17a8cd..c06ee0b213 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -9,6 +9,7 @@ #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "refs.h" @@ -29,6 +30,7 @@ #include "quote.h" #include "remote.h" #include "blob.h" +#include "gpg-interface.h" static const char *const fast_export_usage[] = { N_("git fast-export [<rev-list-opts>]"), @@ -652,6 +654,38 @@ static const char *find_commit_multiline_header(const char *msg, return strbuf_detach(&val, NULL); } +static void print_signature(const char *signature, const char *object_hash) +{ + if (!signature) + return; + + printf("gpgsig %s %s\ndata %u\n%s\n", + object_hash, + get_signature_format(signature), + (unsigned)strlen(signature), + signature); +} + +static const char *append_signatures_for_header(struct string_list *signatures, + const char *pos, + const char *header, + const char *object_hash) +{ + const char *signature; + const char *start = pos; + const char *end = pos; + + while ((signature = find_commit_multiline_header(start + 1, + header, + &end))) { + string_list_append(signatures, signature)->util = (void *)object_hash; + free((char *)signature); + start = end; + } + + return end; +} + static void handle_commit(struct commit *commit, struct rev_info *rev, struct string_list *paths_of_changed_objects) { @@ -660,7 +694,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev, const char *author, *author_end, *committer, *committer_end; const char *encoding = NULL; size_t encoding_len; - const char *signature_alg = NULL, *signature = NULL; + struct string_list signatures = STRING_LIST_INIT_DUP; const char *message; char *reencoded = NULL; struct commit_list *p; @@ -700,10 +734,11 @@ static void handle_commit(struct commit *commit, struct rev_info *rev, } if (*commit_buffer_cursor == '\n') { - if ((signature = find_commit_multiline_header(commit_buffer_cursor + 1, "gpgsig", &commit_buffer_cursor))) - signature_alg = "sha1"; - else if ((signature = find_commit_multiline_header(commit_buffer_cursor + 1, "gpgsig-sha256", &commit_buffer_cursor))) - signature_alg = "sha256"; + const char *after_sha1 = append_signatures_for_header(&signatures, commit_buffer_cursor, + "gpgsig", "sha1"); + const char *after_sha256 = append_signatures_for_header(&signatures, commit_buffer_cursor, + "gpgsig-sha256", "sha256"); + commit_buffer_cursor = (after_sha1 > after_sha256) ? after_sha1 : after_sha256; } message = strstr(commit_buffer_cursor, "\n\n"); @@ -769,30 +804,30 @@ static void handle_commit(struct commit *commit, struct rev_info *rev, printf("%.*s\n%.*s\n", (int)(author_end - author), author, (int)(committer_end - committer), committer); - if (signature) { + if (signatures.nr) { switch (signed_commit_mode) { case SIGN_ABORT: die("encountered signed commit %s; use " "--signed-commits=<mode> to handle it", oid_to_hex(&commit->object.oid)); case SIGN_WARN_VERBATIM: - warning("exporting signed commit %s", - oid_to_hex(&commit->object.oid)); + warning("exporting %"PRIuMAX" signature(s) for commit %s", + (uintmax_t)signatures.nr, oid_to_hex(&commit->object.oid)); /* fallthru */ case SIGN_VERBATIM: - printf("gpgsig %s\ndata %u\n%s", - signature_alg, - (unsigned)strlen(signature), - signature); + for (size_t i = 0; i < signatures.nr; i++) { + struct string_list_item *item = &signatures.items[i]; + print_signature(item->string, item->util); + } break; case SIGN_WARN_STRIP: - warning("stripping signature from commit %s", + warning("stripping signature(s) from commit %s", oid_to_hex(&commit->object.oid)); /* fallthru */ case SIGN_STRIP: break; } - free((char *)signature); + string_list_clear(&signatures, 0); } if (!reencoded && encoding) printf("encoding %.*s\n", (int)encoding_len, encoding); @@ -1327,7 +1362,7 @@ int cmd_fast_export(int argc, usage_with_options (fast_export_usage, options); /* we handle encodings */ - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); repo_init_revisions(the_repository, &revs, prefix); init_revision_sources(&revision_sources); diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 89f57898b1..2c35f9345d 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -29,6 +29,7 @@ #include "commit-reach.h" #include "khash.h" #include "date.h" +#include "gpg-interface.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1) @@ -2716,15 +2717,82 @@ static struct hash_list *parse_merge(unsigned int *count) return list; } +struct signature_data { + char *hash_algo; /* "sha1" or "sha256" */ + char *sig_format; /* "openpgp", "x509", "ssh", or "unknown" */ + struct strbuf data; /* The actual signature data */ +}; + +static void parse_one_signature(struct signature_data *sig, const char *v) +{ + char *args = xstrdup(v); /* Will be freed when sig->hash_algo is freed */ + char *space = strchr(args, ' '); + + if (!space) + die("Expected gpgsig format: 'gpgsig <hash-algo> <signature-format>', " + "got 'gpgsig %s'", args); + *space = '\0'; + + sig->hash_algo = args; + sig->sig_format = space + 1; + + /* Validate hash algorithm */ + if (strcmp(sig->hash_algo, "sha1") && + strcmp(sig->hash_algo, "sha256")) + die("Unknown git hash algorithm in gpgsig: '%s'", sig->hash_algo); + + /* Validate signature format */ + if (!valid_signature_format(sig->sig_format)) + die("Invalid signature format in gpgsig: '%s'", sig->sig_format); + if (!strcmp(sig->sig_format, "unknown")) + warning("'unknown' signature format in gpgsig"); + + /* Read signature data */ + read_next_command(); + parse_data(&sig->data, 0, NULL); +} + +static void add_gpgsig_to_commit(struct strbuf *commit_data, + const char *header, + struct signature_data *sig) +{ + struct string_list siglines = STRING_LIST_INIT_NODUP; + + if (!sig->hash_algo) + return; + + strbuf_addstr(commit_data, header); + string_list_split_in_place(&siglines, sig->data.buf, "\n", -1); + strbuf_add_separated_string_list(commit_data, "\n ", &siglines); + strbuf_addch(commit_data, '\n'); + string_list_clear(&siglines, 1); + strbuf_release(&sig->data); + free(sig->hash_algo); +} + +static void store_signature(struct signature_data *stored_sig, + struct signature_data *new_sig, + const char *hash_type) +{ + if (stored_sig->hash_algo) { + warning("multiple %s signatures found, " + "ignoring additional signature", + hash_type); + strbuf_release(&new_sig->data); + free(new_sig->hash_algo); + } else { + *stored_sig = *new_sig; + } +} + static void parse_new_commit(const char *arg) { - static struct strbuf sig = STRBUF_INIT; static struct strbuf msg = STRBUF_INIT; - struct string_list siglines = STRING_LIST_INIT_NODUP; + struct signature_data sig_sha1 = { NULL, NULL, STRBUF_INIT }; + struct signature_data sig_sha256 = { NULL, NULL, STRBUF_INIT }; struct branch *b; char *author = NULL; char *committer = NULL; - char *sig_alg = NULL; char *encoding = NULL; struct hash_list *merge_list = NULL; unsigned int merge_count; @@ -2748,13 +2816,23 @@ static void parse_new_commit(const char *arg) } if (!committer) die("Expected committer but didn't get one"); - if (skip_prefix(command_buf.buf, "gpgsig ", &v)) { - sig_alg = xstrdup(v); - read_next_command(); - parse_data(&sig, 0, NULL); + + /* Process signatures (up to 2: one "sha1" and one "sha256") */ + while (skip_prefix(command_buf.buf, "gpgsig ", &v)) { + struct signature_data sig = { NULL, NULL, STRBUF_INIT }; + + parse_one_signature(&sig, v); + + if (!strcmp(sig.hash_algo, "sha1")) + store_signature(&sig_sha1, &sig, "SHA-1"); + else if (!strcmp(sig.hash_algo, "sha256")) + store_signature(&sig_sha256, &sig, "SHA-256"); + else + BUG("parse_one_signature() returned unknown hash algo"); + read_next_command(); - } else - strbuf_setlen(&sig, 0); + } + if (skip_prefix(command_buf.buf, "encoding ", &v)) { encoding = xstrdup(v); read_next_command(); @@ -2828,23 +2906,14 @@ static void parse_new_commit(const char *arg) strbuf_addf(&new_data, "encoding %s\n", encoding); - if (sig_alg) { - if (!strcmp(sig_alg, "sha1")) - strbuf_addstr(&new_data, "gpgsig "); - else if (!strcmp(sig_alg, "sha256")) - strbuf_addstr(&new_data, "gpgsig-sha256 "); - else - die("Expected gpgsig algorithm sha1 or sha256, got %s", sig_alg); - string_list_split_in_place(&siglines, sig.buf, "\n", -1); - strbuf_add_separated_string_list(&new_data, "\n ", &siglines); - strbuf_addch(&new_data, '\n'); - } + + add_gpgsig_to_commit(&new_data, "gpgsig ", &sig_sha1); + add_gpgsig_to_commit(&new_data, "gpgsig-sha256 ", &sig_sha256); + strbuf_addch(&new_data, '\n'); strbuf_addbuf(&new_data, &msg); - string_list_clear(&siglines, 1); free(author); free(committer); - free(sig_alg); free(encoding); if (!store_object(OBJ_COMMIT, &new_data, NULL, &b->oid, next_mark)) @@ -3523,25 +3592,25 @@ static void git_pack_config(void) int limit; unsigned long packsizelimit_value; - if (!git_config_get_ulong("pack.depth", &max_depth)) { + if (!repo_config_get_ulong(the_repository, "pack.depth", &max_depth)) { if (max_depth > MAX_DEPTH) max_depth = MAX_DEPTH; } - if (!git_config_get_int("pack.indexversion", &indexversion_value)) { + if (!repo_config_get_int(the_repository, "pack.indexversion", &indexversion_value)) { pack_idx_opts.version = indexversion_value; if (pack_idx_opts.version > 2) git_die_config(the_repository, "pack.indexversion", "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version); } - if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value)) + if (!repo_config_get_ulong(the_repository, "pack.packsizelimit", &packsizelimit_value)) max_packsize = packsizelimit_value; - if (!git_config_get_int("fastimport.unpacklimit", &limit)) + if (!repo_config_get_int(the_repository, "fastimport.unpacklimit", &limit)) unpack_limit = limit; - else if (!git_config_get_int("transfer.unpacklimit", &limit)) + else if (!repo_config_get_int(the_repository, "transfer.unpacklimit", &limit)) unpack_limit = limit; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); } static const char fast_import_usage[] = diff --git a/builtin/fetch.c b/builtin/fetch.c index d231a669d7..24645c4653 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1340,9 +1340,10 @@ static int prune_refs(struct display_state *display_state, int result = 0; struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map); struct strbuf err = STRBUF_INIT; - const char *dangling_msg = dry_run - ? _(" (%s will become dangling)") - : _(" (%s has become dangling)"); + struct string_list refnames = STRING_LIST_INIT_NODUP; + + for (ref = stale_refs; ref; ref = ref->next) + string_list_append(&refnames, ref->name); if (!dry_run) { if (transaction) { @@ -1353,15 +1354,9 @@ static int prune_refs(struct display_state *display_state, goto cleanup; } } else { - struct string_list refnames = STRING_LIST_INIT_NODUP; - - for (ref = stale_refs; ref; ref = ref->next) - string_list_append(&refnames, ref->name); - result = refs_delete_refs(get_main_ref_store(the_repository), "fetch: prune", &refnames, 0); - string_list_clear(&refnames, 0); } } @@ -1373,12 +1368,14 @@ static int prune_refs(struct display_state *display_state, _("(none)"), ref->name, &ref->new_oid, &ref->old_oid, summary_width); - refs_warn_dangling_symref(get_main_ref_store(the_repository), - stderr, dangling_msg, ref->name); } + string_list_sort(&refnames); + refs_warn_dangling_symrefs(get_main_ref_store(the_repository), + stderr, " ", dry_run, &refnames); } cleanup: + string_list_clear(&refnames, 0); strbuf_release(&err); free_refs(stale_refs); return result; @@ -1998,7 +1995,7 @@ static int add_remote_or_group(const char *name, struct string_list *list) struct remote_group_data g; g.name = name; g.list = list; - git_config(get_remote_group, &g); + repo_config(the_repository, get_remote_group, &g); if (list->nr == prev_nr) { struct remote *remote = remote_get(name); if (!remote_is_configured(remote, 0)) @@ -2420,7 +2417,7 @@ int cmd_fetch(int argc, free(anon); } - git_config(git_fetch_config, &config); + repo_config(the_repository, git_fetch_config, &config); if (the_repository->gitdir) { prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; @@ -2511,7 +2508,7 @@ int cmd_fetch(int argc, if (!max_jobs) max_jobs = online_cpus(); - if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri) && + if (!repo_config_get_string_tmp(the_repository, "fetch.bundleuri", &bundle_uri) && fetch_bundle_uri(the_repository, bundle_uri, NULL)) warning(_("failed to fetch bundles from '%s'"), bundle_uri); @@ -2686,12 +2683,12 @@ int cmd_fetch(int argc, * but respect config settings disabling it. */ int opt_val; - if (git_config_get_int("gc.autopacklimit", &opt_val)) + if (repo_config_get_int(the_repository, "gc.autopacklimit", &opt_val)) opt_val = -1; if (opt_val != 0) git_config_push_parameter("gc.autoPackLimit=1"); - if (git_config_get_int("maintenance.incremental-repack.auto", &opt_val)) + if (repo_config_get_int(the_repository, "maintenance.incremental-repack.auto", &opt_val)) opt_val = -1; if (opt_val != 0) git_config_push_parameter("maintenance.incremental-repack.auto=-1"); diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 3b6aac2cf7..edb93c0b3a 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -53,7 +53,7 @@ int cmd_fmt_merge_msg(int argc, int ret; struct fmt_merge_msg_opts opts; - git_config(fmt_merge_msg_config, NULL); + repo_config(the_repository, fmt_merge_msg_config, NULL); argc = parse_options(argc, argv, prefix, options, fmt_merge_msg_usage, 0); if (argc > 0) diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 3d2207ec77..8b5fe7b65e 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "commit.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "object.h" #include "parse-options.h" @@ -13,6 +14,7 @@ static char const * const for_each_ref_usage[] = { N_("git for-each-ref [--points-at <object>]"), N_("git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"), N_("git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"), + N_("git for-each-ref [--start-after <marker>]"), NULL }; @@ -44,6 +46,7 @@ int cmd_for_each_ref(int argc, OPT_GROUP(""), OPT_INTEGER( 0 , "count", &format.array_opts.max_count, N_("show only <n> matched refs")), OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")), + OPT_STRING( 0 , "start-after", &filter.start_after, N_("start-after"), N_("start iteration after the provided marker")), OPT__COLOR(&format.use_color, N_("respect format colors")), OPT_REF_FILTER_EXCLUDE(&filter), OPT_REF_SORT(&sorting_options), @@ -79,6 +82,9 @@ int cmd_for_each_ref(int argc, if (verify_ref_format(&format)) usage_with_options(for_each_ref_usage, opts); + if (filter.start_after && sorting_options.nr > 1) + die(_("cannot use --start-after with custom sort options")); + sorting = ref_sorting_options(&sorting_options); ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase); filter.ignore_case = icase; @@ -100,6 +106,9 @@ int cmd_for_each_ref(int argc, filter.name_patterns = argv; } + if (filter.start_after && filter.name_patterns && filter.name_patterns[0]) + die(_("cannot use --start-after with patterns")); + if (include_root_refs) flags |= FILTER_REFS_ROOT_REFS | FILTER_REFS_DETACHED_HEAD; diff --git a/builtin/fsck.c b/builtin/fsck.c index e9112d884f..543a2cdb5c 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -988,7 +988,7 @@ int cmd_fsck(int argc, if (name_objects) fsck_enable_object_names(&fsck_walk_options); - git_config(git_fsck_config, &fsck_obj_options); + repo_config(the_repository, git_fsck_config, &fsck_obj_options); prepare_repo_settings(the_repository); if (check_references) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 0820e524f1..242c594646 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -5,6 +5,7 @@ #include "abspath.h" #include "config.h" #include "dir.h" +#include "environment.h" #include "gettext.h" #include "parse-options.h" #include "fsmonitor-ll.h" @@ -1547,7 +1548,7 @@ int cmd_fsmonitor__daemon(int argc, OPT_END() }; - git_config(fsmonitor_config, NULL); + repo_config(the_repository, fsmonitor_config, NULL); argc = parse_options(argc, argv, prefix, options, builtin_fsmonitor__daemon_usage, 0); diff --git a/builtin/gc.c b/builtin/gc.c index 6eefefc63d..0edd94a76f 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -114,7 +114,7 @@ static int gc_config_is_timestamp_never(const char *var) const char *value; timestamp_t expire; - if (!git_config_get_value(var, &value) && value) { + if (!repo_config_get_value(the_repository, var, &value) && value) { if (parse_expiry_date(value, &expire)) die(_("failed to parse '%s' value '%s'"), var, value); return expire == 0; @@ -178,7 +178,7 @@ static void gc_config(struct gc_config *cfg) char *owned = NULL; unsigned long ulongval; - if (!git_config_get_value("gc.packrefs", &value)) { + if (!repo_config_get_value(the_repository, "gc.packrefs", &value)) { if (value && !strcmp(value, "notbare")) cfg->pack_refs = -1; else @@ -189,13 +189,13 @@ static void gc_config(struct gc_config *cfg) gc_config_is_timestamp_never("gc.reflogexpireunreachable")) cfg->prune_reflogs = 0; - git_config_get_int("gc.aggressivewindow", &cfg->aggressive_window); - git_config_get_int("gc.aggressivedepth", &cfg->aggressive_depth); - git_config_get_int("gc.auto", &cfg->gc_auto_threshold); - git_config_get_int("gc.autopacklimit", &cfg->gc_auto_pack_limit); - git_config_get_bool("gc.autodetach", &cfg->detach_auto); - git_config_get_bool("gc.cruftpacks", &cfg->cruft_packs); - git_config_get_ulong("gc.maxcruftsize", &cfg->max_cruft_size); + repo_config_get_int(the_repository, "gc.aggressivewindow", &cfg->aggressive_window); + repo_config_get_int(the_repository, "gc.aggressivedepth", &cfg->aggressive_depth); + repo_config_get_int(the_repository, "gc.auto", &cfg->gc_auto_threshold); + repo_config_get_int(the_repository, "gc.autopacklimit", &cfg->gc_auto_pack_limit); + repo_config_get_bool(the_repository, "gc.autodetach", &cfg->detach_auto); + repo_config_get_bool(the_repository, "gc.cruftpacks", &cfg->cruft_packs); + repo_config_get_ulong(the_repository, "gc.maxcruftsize", &cfg->max_cruft_size); if (!repo_config_get_expiry(the_repository, "gc.pruneexpire", &owned)) { free(cfg->prune_expire); @@ -212,23 +212,23 @@ static void gc_config(struct gc_config *cfg) cfg->gc_log_expire = owned; } - git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold); - git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size); + repo_config_get_ulong(the_repository, "gc.bigpackthreshold", &cfg->big_pack_threshold); + repo_config_get_ulong(the_repository, "pack.deltacachesize", &cfg->max_delta_cache_size); - if (!git_config_get_ulong("core.deltabasecachelimit", &ulongval)) + if (!repo_config_get_ulong(the_repository, "core.deltabasecachelimit", &ulongval)) cfg->delta_base_cache_limit = ulongval; - if (!git_config_get_string("gc.repackfilter", &owned)) { + if (!repo_config_get_string(the_repository, "gc.repackfilter", &owned)) { free(cfg->repack_filter); cfg->repack_filter = owned; } - if (!git_config_get_string("gc.repackfilterto", &owned)) { + if (!repo_config_get_string(the_repository, "gc.repackfilterto", &owned)) { free(cfg->repack_filter_to); cfg->repack_filter_to = owned; } - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); } enum schedule_priority { @@ -332,7 +332,7 @@ static int reflog_expire_condition(struct gc_config *cfg UNUSED) }; int limit = 100; - git_config_get_int("maintenance.reflog-expire.auto", &limit); + repo_config_get_int(the_repository, "maintenance.reflog-expire.auto", &limit); if (!limit) return 0; if (limit < 0) @@ -346,6 +346,7 @@ static int reflog_expire_condition(struct gc_config *cfg UNUSED) count_reflog_entries, &data); reflog_expiry_cleanup(&data.policy); + reflog_clear_expire_config(&data.policy.opts); return data.count >= data.limit; } @@ -378,7 +379,7 @@ static int worktree_prune_condition(struct gc_config *cfg) struct dirent *d; DIR *dir = NULL; - git_config_get_int("maintenance.worktree-prune.auto", &limit); + repo_config_get_int(the_repository, "maintenance.worktree-prune.auto", &limit); if (limit <= 0) { should_prune = limit < 0; goto out; @@ -423,7 +424,7 @@ static int rerere_gc_condition(struct gc_config *cfg UNUSED) int should_gc = 0, limit = 1; DIR *dir = NULL; - git_config_get_int("maintenance.rerere-gc.auto", &limit); + repo_config_get_int(the_repository, "maintenance.rerere-gc.auto", &limit); if (limit <= 0) { should_gc = limit < 0; goto out; @@ -539,7 +540,7 @@ static uint64_t total_ram(void) return total; } #elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM) || defined(HW_PHYSMEM64)) - int64_t physical_memory; + uint64_t physical_memory; int mib[2]; size_t length; @@ -551,9 +552,16 @@ static uint64_t total_ram(void) # else mib[1] = HW_PHYSMEM; # endif - length = sizeof(int64_t); - if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0)) + length = sizeof(physical_memory); + if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0)) { + if (length == 4) { + uint32_t mem; + + if (!sysctl(mib, 2, &mem, &length, NULL, 0)) + physical_memory = mem; + } return physical_memory; + } #elif defined(GIT_WINDOWS_NATIVE) MEMORYSTATUSEX memInfo; @@ -998,7 +1006,7 @@ int cmd_gc(int argc, if (opts.detach <= 0 && !skip_foreground_tasks) gc_foreground_tasks(&opts, &cfg); - if (!repository_format_precious_objects) { + if (!the_repository->repository_format_precious_objects) { struct child_process repack_cmd = CHILD_PROCESS_INIT; repack_cmd.git_cmd = 1; @@ -1154,8 +1162,8 @@ static int should_write_commit_graph(struct gc_config *cfg UNUSED) data.num_not_in_graph = 0; data.limit = 100; - git_config_get_int("maintenance.commit-graph.auto", - &data.limit); + repo_config_get_int(the_repository, "maintenance.commit-graph.auto", + &data.limit); if (!data.limit) return 0; @@ -1293,8 +1301,8 @@ static int loose_object_auto_condition(struct gc_config *cfg UNUSED) { int count = 0; - git_config_get_int("maintenance.loose-objects.auto", - &loose_object_auto_limit); + repo_config_get_int(the_repository, "maintenance.loose-objects.auto", + &loose_object_auto_limit); if (!loose_object_auto_limit) return 0; @@ -1406,8 +1414,8 @@ static int incremental_repack_auto_condition(struct gc_config *cfg UNUSED) if (!the_repository->settings.core_multi_pack_index) return 0; - git_config_get_int("maintenance.incremental-repack.auto", - &incremental_repack_auto_limit); + repo_config_get_int(the_repository, "maintenance.incremental-repack.auto", + &incremental_repack_auto_limit); if (!incremental_repack_auto_limit) return 0; @@ -1756,7 +1764,7 @@ static void initialize_task_config(struct maintenance_run_opts *opts, if (opts->schedule) { strategy = none_strategy; - if (!git_config_get_string_tmp("maintenance.strategy", &config_str)) { + if (!repo_config_get_string_tmp(the_repository, "maintenance.strategy", &config_str)) { if (!strcasecmp(config_str, "incremental")) strategy = incremental_strategy; } @@ -1770,7 +1778,7 @@ static void initialize_task_config(struct maintenance_run_opts *opts, strbuf_reset(&config_name); strbuf_addf(&config_name, "maintenance.%s.enabled", tasks[i].name); - if (!git_config_get_bool(config_name.buf, &config_value)) + if (!repo_config_get_bool(the_repository, config_name.buf, &config_value)) strategy.tasks[i].enabled = config_value; if (!strategy.tasks[i].enabled) continue; @@ -1779,7 +1787,7 @@ static void initialize_task_config(struct maintenance_run_opts *opts, strbuf_reset(&config_name); strbuf_addf(&config_name, "maintenance.%s.schedule", tasks[i].name); - if (!git_config_get_string_tmp(config_name.buf, &config_str)) + if (!repo_config_get_string_tmp(the_repository, config_name.buf, &config_str)) strategy.tasks[i].schedule = parse_schedule(config_str); if (strategy.tasks[i].schedule < opts->schedule) continue; @@ -1904,13 +1912,13 @@ static int maintenance_register(int argc, const char **argv, const char *prefix, options); /* Disable foreground maintenance */ - git_config_set("maintenance.auto", "false"); + repo_config_set(the_repository, "maintenance.auto", "false"); /* Set maintenance strategy, if unset */ - if (git_config_get("maintenance.strategy")) - git_config_set("maintenance.strategy", "incremental"); + if (repo_config_get(the_repository, "maintenance.strategy")) + repo_config_set(the_repository, "maintenance.strategy", "incremental"); - if (!git_config_get_string_multi(key, &list)) { + if (!repo_config_get_string_multi(the_repository, key, &list)) { for_each_string_list_item(item, list) { if (!strcmp(maintpath, item->string)) { found = 1; @@ -1929,7 +1937,7 @@ static int maintenance_register(int argc, const char **argv, const char *prefix, } if (!config_file) die(_("$HOME not set")); - rc = git_config_set_multivar_in_file_gently( + rc = repo_config_set_multivar_in_file_gently(the_repository, config_file, "maintenance.repo", maintpath, CONFIG_REGEX_NONE, NULL, 0); free(global_config_file); @@ -1979,7 +1987,7 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi } if (!(config_file ? git_configset_get_string_multi(&cs, key, &list) - : git_config_get_string_multi(key, &list))) { + : repo_config_get_string_multi(the_repository, key, &list))) { for_each_string_list_item(item, list) { if (!strcmp(maintpath, item->string)) { found = 1; @@ -1998,7 +2006,7 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi } if (!config_file) die(_("$HOME not set")); - rc = git_config_set_multivar_in_file_gently( + rc = repo_config_set_multivar_in_file_gently(the_repository, config_file, key, NULL, maintpath, NULL, CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE); free(global_config_file); @@ -2335,7 +2343,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit die(_("failed to create directories for '%s'"), filename); if ((long)lock_file_timeout_ms < 0 && - git_config_get_ulong("gc.launchctlplistlocktimeoutms", + repo_config_get_ulong(the_repository, "gc.launchctlplistlocktimeoutms", &lock_file_timeout_ms)) lock_file_timeout_ms = 150; diff --git a/builtin/grep.c b/builtin/grep.c index 39273d9c0f..5df6537333 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -9,6 +9,7 @@ #include "builtin.h" #include "abspath.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "config.h" @@ -1035,7 +1036,7 @@ int cmd_grep(int argc, grep_prefix = prefix; grep_init(&opt, the_repository); - git_config(grep_cmd_config, &opt); + repo_config(the_repository, grep_cmd_config, &opt); /* * If there is no -- then the paths must exist in the working @@ -1058,7 +1059,7 @@ int cmd_grep(int argc, if (use_index && !startup_info->have_repository) { int fallback = 0; - git_config_get_bool("grep.fallbacktonoindex", &fallback); + repo_config_get_bool(the_repository, "grep.fallbacktonoindex", &fallback); if (fallback) use_index = 0; else diff --git a/builtin/hash-object.c b/builtin/hash-object.c index e28f000221..5d900a6b8c 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -8,6 +8,7 @@ #include "builtin.h" #include "abspath.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "object-file.h" @@ -104,14 +105,14 @@ int cmd_hash_object(int argc, prefix = setup_git_directory_gently(&nongit); if (nongit && !the_hash_algo) - repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT); if (vpath && prefix) { vpath_free = prefix_filename(prefix, vpath); vpath = vpath_free; } - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); if (stdin_paths) { if (hashstdin) diff --git a/builtin/help.c b/builtin/help.c index c257079ceb..c09cbc8912 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -6,6 +6,7 @@ #include "builtin.h" #include "config.h" +#include "environment.h" #include "exec-cmd.h" #include "gettext.h" #include "pager.h" @@ -210,7 +211,7 @@ static enum help_format parse_help_format(const char *format) if (!strcmp(format, "web") || !strcmp(format, "html")) return HELP_FORMAT_WEB; /* - * Please update _git_config() in git-completion.bash when you + * Please update _repo_config() in git-completion.bash when you * add new help formats. */ die(_("unrecognized help format '%s'"), format); @@ -706,7 +707,7 @@ int cmd_help(int argc, } setup_git_directory_gently(&nongit); - git_config(git_help_config, NULL); + repo_config(the_repository, git_help_config, NULL); if (parsed_help_format != HELP_FORMAT_NONE) help_format = parsed_help_format; diff --git a/builtin/hook.c b/builtin/hook.c index 672d2e37e8..7afec380d2 100644 --- a/builtin/hook.c +++ b/builtin/hook.c @@ -1,6 +1,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hook.h" #include "parse-options.h" @@ -55,7 +56,7 @@ static int run(int argc, const char **argv, const char *prefix, strvec_push(&opt.args, argv[i]); /* Need to take into account core.hooksPath */ - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); hook_name = argv[0]; if (!ignore_missing) diff --git a/builtin/index-pack.c b/builtin/index-pack.c index dabeb825a6..f91c301bba 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -1917,7 +1917,7 @@ int cmd_index_pack(int argc, reset_pack_idx_option(&opts); opts.flags |= WRITE_REV; - git_config(git_index_pack_config, &opts); + repo_config(the_repository, git_index_pack_config, &opts); if (prefix && chdir(prefix)) die(_("Cannot come back to cwd")); @@ -2035,7 +2035,7 @@ int cmd_index_pack(int argc, * choice but to guess the object hash. */ if (!the_repository->hash_algo) - repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT); opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY); if (rev_index) { diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c index 44d8ccddc9..41b0750e5a 100644 --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@ -6,6 +6,7 @@ */ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" +#include "environment.h" #include "gettext.h" #include "parse-options.h" #include "string-list.h" @@ -220,7 +221,7 @@ int cmd_interpret_trailers(int argc, OPT_END() }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, git_interpret_trailers_usage, 0); diff --git a/builtin/log.c b/builtin/log.c index 24a57c20a4..c2f8bbf863 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -221,7 +221,7 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f struct string_list *include = decoration_filter->include_ref_pattern; const struct string_list *config_exclude; - if (!git_config_get_string_multi("log.excludeDecoration", + if (!repo_config_get_string_multi(the_repository, "log.excludeDecoration", &config_exclude)) { struct string_list_item *item; for_each_string_list_item(item, config_exclude) @@ -235,7 +235,7 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f * since the command-line takes precedent. */ if (use_default_decoration_filter && - !git_config_get_string("log.initialdecorationset", &value) && + !repo_config_get_string(the_repository, "log.initialdecorationset", &value) && !strcmp("all", value)) use_default_decoration_filter = 0; free(value); @@ -391,129 +391,6 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, cmd_log_init_finish(argc, argv, prefix, rev, opt, cfg); } -/* - * This gives a rough estimate for how many commits we - * will print out in the list. - */ -static int estimate_commit_count(struct commit_list *list) -{ - int n = 0; - - while (list) { - struct commit *commit = list->item; - unsigned int flags = commit->object.flags; - list = list->next; - if (!(flags & (TREESAME | UNINTERESTING))) - n++; - } - return n; -} - -static void show_early_header(struct rev_info *rev, const char *stage, int nr) -{ - if (rev->shown_one) { - rev->shown_one = 0; - if (rev->commit_format != CMIT_FMT_ONELINE) - putchar(rev->diffopt.line_termination); - } - fprintf(rev->diffopt.file, _("Final output: %d %s\n"), nr, stage); -} - -static struct itimerval early_output_timer; - -static void log_show_early(struct rev_info *revs, struct commit_list *list) -{ - int i = revs->early_output; - int show_header = 1; - int no_free = revs->diffopt.no_free; - - revs->diffopt.no_free = 0; - sort_in_topological_order(&list, revs->sort_order); - while (list && i) { - struct commit *commit = list->item; - switch (simplify_commit(revs, commit)) { - case commit_show: - if (show_header) { - int n = estimate_commit_count(list); - show_early_header(revs, "incomplete", n); - show_header = 0; - } - log_tree_commit(revs, commit); - i--; - break; - case commit_ignore: - break; - case commit_error: - revs->diffopt.no_free = no_free; - diff_free(&revs->diffopt); - return; - } - list = list->next; - } - - /* Did we already get enough commits for the early output? */ - if (!i) { - revs->diffopt.no_free = 0; - diff_free(&revs->diffopt); - return; - } - - /* - * ..if no, then repeat it twice a second until we - * do. - * - * NOTE! We don't use "it_interval", because if the - * reader isn't listening, we want our output to be - * throttled by the writing, and not have the timer - * trigger every second even if we're blocked on a - * reader! - */ - early_output_timer.it_value.tv_sec = 0; - early_output_timer.it_value.tv_usec = 500000; - setitimer(ITIMER_REAL, &early_output_timer, NULL); -} - -static void early_output(int signal UNUSED) -{ - show_early_output = log_show_early; -} - -static void setup_early_output(void) -{ - struct sigaction sa; - - /* - * Set up the signal handler, minimally intrusively: - * we only set a single volatile integer word (not - * using sigatomic_t - trying to avoid unnecessary - * system dependencies and headers), and using - * SA_RESTART. - */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = early_output; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(SIGALRM, &sa, NULL); - - /* - * If we can get the whole output in less than a - * tenth of a second, don't even bother doing the - * early-output thing.. - * - * This is a one-time-only trigger. - */ - early_output_timer.it_value.tv_sec = 0; - early_output_timer.it_value.tv_usec = 100000; - setitimer(ITIMER_REAL, &early_output_timer, NULL); -} - -static void finish_early_output(struct rev_info *rev) -{ - int n = estimate_commit_count(rev->commits); - signal(SIGALRM, SIG_IGN); - show_early_header(rev, "done", n); -} - static int cmd_log_walk_no_free(struct rev_info *rev) { struct commit *commit; @@ -521,15 +398,9 @@ static int cmd_log_walk_no_free(struct rev_info *rev) int saved_dcctc = 0; int result; - if (rev->early_output) - setup_early_output(); - if (prepare_revision_walk(rev)) die(_("revision walk setup failed")); - if (rev->early_output) - finish_early_output(rev); - /* * For --check and --exit-code, the exit code is based on CHECK_FAILED * and HAS_CHANGES being accumulated in rev->diffopt, so be careful to @@ -659,10 +530,10 @@ int cmd_whatchanged(int argc, log_config_init(&cfg); init_diff_ui_defaults(); - git_config(git_log_config, &cfg); + repo_config(the_repository, git_log_config, &cfg); repo_init_revisions(the_repository, &rev, prefix); - git_config(grep_config, &rev.grep_filter); + repo_config(the_repository, grep_config, &rev.grep_filter); rev.diff = 1; rev.simplify_history = 0; @@ -790,7 +661,7 @@ int cmd_show(int argc, log_config_init(&cfg); init_diff_ui_defaults(); - git_config(git_log_config, &cfg); + repo_config(the_repository, git_log_config, &cfg); if (the_repository->gitdir) { prepare_repo_settings(the_repository); @@ -799,7 +670,7 @@ int cmd_show(int argc, memset(&match_all, 0, sizeof(match_all)); repo_init_revisions(the_repository, &rev, prefix); - git_config(grep_config, &rev.grep_filter); + repo_config(the_repository, grep_config, &rev.grep_filter); rev.diff = 1; rev.always_show_header = 1; @@ -907,11 +778,11 @@ int cmd_log_reflog(int argc, log_config_init(&cfg); init_diff_ui_defaults(); - git_config(git_log_config, &cfg); + repo_config(the_repository, git_log_config, &cfg); repo_init_revisions(the_repository, &rev, prefix); init_reflog_walk(&rev.reflog_info); - git_config(grep_config, &rev.grep_filter); + repo_config(the_repository, grep_config, &rev.grep_filter); rev.verbose_header = 1; memset(&opt, 0, sizeof(opt)); @@ -952,10 +823,10 @@ int cmd_log(int argc, log_config_init(&cfg); init_diff_ui_defaults(); - git_config(git_log_config, &cfg); + repo_config(the_repository, git_log_config, &cfg); repo_init_revisions(the_repository, &rev, prefix); - git_config(grep_config, &rev.grep_filter); + repo_config(the_repository, grep_config, &rev.grep_filter); rev.always_show_header = 1; memset(&opt, 0, sizeof(opt)); @@ -2158,9 +2029,9 @@ int cmd_format_patch(int argc, format_config_init(&cfg); init_diff_ui_defaults(); init_display_notes(&cfg.notes_opt); - git_config(git_format_config, &cfg); + repo_config(the_repository, git_format_config, &cfg); repo_init_revisions(the_repository, &rev, prefix); - git_config(grep_config, &rev.grep_filter); + repo_config(the_repository, grep_config, &rev.grep_filter); rev.show_notes = cfg.show_notes; memcpy(&rev.notes_opt, &cfg.notes_opt, sizeof(cfg.notes_opt)); diff --git a/builtin/ls-files.c b/builtin/ls-files.c index ff975e7be0..c06a6f33e4 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -11,6 +11,7 @@ #include "builtin.h" #include "config.h" #include "convert.h" +#include "environment.h" #include "quote.h" #include "dir.h" #include "gettext.h" diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index 01a4d4daa1..df09000b30 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -112,7 +112,7 @@ int cmd_ls_remote(int argc, * depending on what object hash the remote uses. */ if (!the_repository->hash_algo) - repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT); packet_trace_identity("ls-remote"); diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 4d616dd528..5d55731ca3 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -7,6 +7,7 @@ #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "object-name.h" @@ -375,7 +376,7 @@ int cmd_ls_tree(int argc, struct object_context obj_context = {0}; int ret; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, ls_tree_options, ls_tree_usage, 0); diff --git a/builtin/merge-base.c b/builtin/merge-base.c index 123c81515e..3f82781245 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -2,6 +2,7 @@ #include "builtin.h" #include "config.h" #include "commit.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "object-name.h" @@ -167,7 +168,7 @@ int cmd_merge_base(int argc, OPT_END() }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0); if (cmdmode == 'a') { diff --git a/builtin/merge-file.c b/builtin/merge-file.c index b8b25a14e6..46775d0c79 100644 --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@ -97,7 +97,7 @@ int cmd_merge_file(int argc, if (startup_info->have_repository) { /* Read the configuration file */ - git_config(git_xmerge_config, NULL); + repo_config(the_repository, git_xmerge_config, NULL); if (0 <= git_xmerge_style) xmp.style = git_xmerge_style; } diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index cf8b06cadc..203f0e6456 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -1,6 +1,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" +#include "environment.h" #include "tree-walk.h" #include "xdiff-interface.h" #include "help.h" @@ -683,7 +684,7 @@ int cmd_merge_tree(int argc, if (argc != expected_remaining_argc) usage_with_options(merge_tree_usage, mt_options); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); /* Do the relevant type of merge */ if (o.mode == MODE_REAL) diff --git a/builtin/merge.c b/builtin/merge.c index 18b22c0a26..dc4cb8fb14 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -1392,7 +1392,7 @@ int cmd_merge(int argc, skip_prefix(branch, "refs/heads/", &branch); init_diff_ui_defaults(); - git_config(git_merge_config, NULL); + repo_config(the_repository, git_merge_config, NULL); if (!branch || is_null_oid(&head_oid)) head_commit = NULL; diff --git a/builtin/mktag.c b/builtin/mktag.c index 12552bbb21..7cf6e1230a 100644 --- a/builtin/mktag.c +++ b/builtin/mktag.c @@ -98,7 +98,7 @@ int cmd_mktag(int argc, fsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY, FSCK_WARN); /* config might set fsck.extraHeaderEntry=* again */ - git_config(git_fsck_config, &fsck_options); + repo_config(the_repository, git_fsck_config, &fsck_options); if (fsck_tag_standalone(NULL, buf.buf, buf.len, &fsck_options, &tagged_oid, &tagged_type)) die(_("tag on stdin did not pass our strict fsck check")); diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c index aa25b06f9d..d3b9e98be3 100644 --- a/builtin/multi-pack-index.c +++ b/builtin/multi-pack-index.c @@ -2,6 +2,7 @@ #include "builtin.h" #include "abspath.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "parse-options.h" #include "midx.h" @@ -143,7 +144,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE; - git_config(git_multi_pack_index_write_config, NULL); + repo_config(the_repository, git_multi_pack_index_write_config, NULL); options = add_common_options(builtin_multi_pack_index_write_options); @@ -290,7 +291,7 @@ int cmd_multi_pack_index(int argc, disable_replace_refs(); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); if (the_repository && the_repository->objects && diff --git a/builtin/mv.c b/builtin/mv.c index 07548fe96a..d43925097b 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -239,7 +239,7 @@ int cmd_mv(int argc, struct strbuf pathbuf = STRBUF_INIT; int ret; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_mv_options, builtin_mv_usage, 0); diff --git a/builtin/name-rev.c b/builtin/name-rev.c index ff199638de..74512e54a3 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -600,7 +600,7 @@ int cmd_name_rev(int argc, mem_pool_init(&string_pool, 0); init_commit_rev_name(&rev_names); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0); #ifndef WITH_BREAKING_CHANGES diff --git a/builtin/notes.c b/builtin/notes.c index a3580b4aa3..6fb4144da3 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -874,7 +874,7 @@ static int git_config_get_notes_strategy(const char *key, { char *value; - if (git_config_get_string(key, &value)) + if (repo_config_get_string(the_repository, key, &value)) return 1; if (parse_notes_merge_strategy(value, strategy)) git_die_config(the_repository, key, _("unknown notes merge strategy %s"), value); @@ -1146,7 +1146,7 @@ int cmd_notes(int argc, OPT_END() }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, git_notes_usage, PARSE_OPT_SUBCOMMAND_OPTIONAL); if (!fn) { diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 7ff79d6b37..53a2256250 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -284,6 +284,12 @@ static struct oidmap configured_exclusions; static struct oidset excluded_by_config; static int name_hash_version = -1; +enum stdin_packs_mode { + STDIN_PACKS_MODE_NONE, + STDIN_PACKS_MODE_STANDARD, + STDIN_PACKS_MODE_FOLLOW, +}; + /** * Check whether the name_hash_version chosen by user input is appropriate, * and also validate whether it is compatible with other features. @@ -1700,8 +1706,8 @@ static int want_object_in_pack_mtime(const struct object_id *oid, uint32_t found_mtime) { int want; + struct odb_source *source; struct list_head *pos; - struct multi_pack_index *m; if (!exclude && local) { /* @@ -1729,9 +1735,13 @@ static int want_object_in_pack_mtime(const struct object_id *oid, *found_offset = 0; } - for (m = get_multi_pack_index(the_repository); m; m = m->next) { + odb_prepare_alternates(the_repository->objects); + + for (source = the_repository->objects->sources; source; source = source->next) { + struct multi_pack_index *m = get_multi_pack_index(source); struct pack_entry e; - if (fill_midx_entry(the_repository, oid, &e, m)) { + + if (m && fill_midx_entry(the_repository, oid, &e, m)) { want = want_object_in_pack_one(e.p, oid, exclude, found_pack, found_offset, found_mtime); if (want != -1) return want; @@ -3735,7 +3745,6 @@ static int add_object_entry_from_pack(const struct object_id *oid, return 0; if (p) { - struct rev_info *revs = _data; struct object_info oi = OBJECT_INFO_INIT; oi.typep = &type; @@ -3743,6 +3752,7 @@ static int add_object_entry_from_pack(const struct object_id *oid, die(_("could not get type of object %s in pack %s"), oid_to_hex(oid), p->pack_name); } else if (type == OBJ_COMMIT) { + struct rev_info *revs = _data; /* * commits in included packs are used as starting points for the * subsequent revision walk @@ -3758,32 +3768,48 @@ static int add_object_entry_from_pack(const struct object_id *oid, return 0; } -static void show_commit_pack_hint(struct commit *commit UNUSED, - void *data UNUSED) +static void show_object_pack_hint(struct object *object, const char *name, + void *data) { - /* nothing to do; commits don't have a namehash */ + enum stdin_packs_mode mode = *(enum stdin_packs_mode *)data; + if (mode == STDIN_PACKS_MODE_FOLLOW) { + if (object->type == OBJ_BLOB && + !has_object(the_repository, &object->oid, 0)) + return; + add_object_entry(&object->oid, object->type, name, 0); + } else { + struct object_entry *oe = packlist_find(&to_pack, &object->oid); + if (!oe) + return; + + /* + * Our 'to_pack' list was constructed by iterating all + * objects packed in included packs, and so doesn't have + * a non-zero hash field that you would typically pick + * up during a reachability traversal. + * + * Make a best-effort attempt to fill in the ->hash and + * ->no_try_delta fields here in order to perhaps + * improve the delta selection process. + */ + oe->hash = pack_name_hash_fn(name); + oe->no_try_delta = name && no_try_delta(name); + + stdin_packs_hints_nr++; + } } -static void show_object_pack_hint(struct object *object, const char *name, - void *data UNUSED) +static void show_commit_pack_hint(struct commit *commit, void *data) { - struct object_entry *oe = packlist_find(&to_pack, &object->oid); - if (!oe) + enum stdin_packs_mode mode = *(enum stdin_packs_mode *)data; + + if (mode == STDIN_PACKS_MODE_FOLLOW) { + show_object_pack_hint((struct object *)commit, "", data); return; + } - /* - * Our 'to_pack' list was constructed by iterating all objects packed in - * included packs, and so doesn't have a non-zero hash field that you - * would typically pick up during a reachability traversal. - * - * Make a best-effort attempt to fill in the ->hash and ->no_try_delta - * here using a now in order to perhaps improve the delta selection - * process. - */ - oe->hash = pack_name_hash_fn(name); - oe->no_try_delta = name && no_try_delta(name); + /* nothing to do; commits don't have a namehash */ - stdin_packs_hints_nr++; } static int pack_mtime_cmp(const void *_a, const void *_b) @@ -3803,7 +3829,7 @@ static int pack_mtime_cmp(const void *_a, const void *_b) return 0; } -static void read_packs_list_from_stdin(void) +static void read_packs_list_from_stdin(struct rev_info *revs) { struct strbuf buf = STRBUF_INIT; struct string_list include_packs = STRING_LIST_INIT_DUP; @@ -3811,24 +3837,6 @@ static void read_packs_list_from_stdin(void) struct string_list_item *item = NULL; struct packed_git *p; - struct rev_info revs; - - repo_init_revisions(the_repository, &revs, NULL); - /* - * Use a revision walk to fill in the namehash of objects in the include - * packs. To save time, we'll avoid traversing through objects that are - * in excluded packs. - * - * That may cause us to avoid populating all of the namehash fields of - * all included objects, but our goal is best-effort, since this is only - * an optimization during delta selection. - */ - revs.no_kept_objects = 1; - revs.keep_pack_cache_flags |= IN_CORE_KEEP_PACKS; - revs.blob_objects = 1; - revs.tree_objects = 1; - revs.tag_objects = 1; - revs.ignore_missing_links = 1; while (strbuf_getline(&buf, stdin) != EOF) { if (!buf.len) @@ -3898,25 +3906,55 @@ static void read_packs_list_from_stdin(void) struct packed_git *p = item->util; for_each_object_in_pack(p, add_object_entry_from_pack, - &revs, + revs, FOR_EACH_OBJECT_PACK_ORDER); } + strbuf_release(&buf); + string_list_clear(&include_packs, 0); + string_list_clear(&exclude_packs, 0); +} + +static void add_unreachable_loose_objects(struct rev_info *revs); + +static void read_stdin_packs(enum stdin_packs_mode mode, int rev_list_unpacked) +{ + struct rev_info revs; + + repo_init_revisions(the_repository, &revs, NULL); + /* + * Use a revision walk to fill in the namehash of objects in the include + * packs. To save time, we'll avoid traversing through objects that are + * in excluded packs. + * + * That may cause us to avoid populating all of the namehash fields of + * all included objects, but our goal is best-effort, since this is only + * an optimization during delta selection. + */ + revs.no_kept_objects = 1; + revs.keep_pack_cache_flags |= IN_CORE_KEEP_PACKS; + revs.blob_objects = 1; + revs.tree_objects = 1; + revs.tag_objects = 1; + revs.ignore_missing_links = 1; + + /* avoids adding objects in excluded packs */ + ignore_packed_keep_in_core = 1; + read_packs_list_from_stdin(&revs); + if (rev_list_unpacked) + add_unreachable_loose_objects(&revs); + if (prepare_revision_walk(&revs)) die(_("revision walk setup failed")); traverse_commit_list(&revs, show_commit_pack_hint, show_object_pack_hint, - NULL); + &mode); trace2_data_intmax("pack-objects", the_repository, "stdin_packs_found", stdin_packs_found_nr); trace2_data_intmax("pack-objects", the_repository, "stdin_packs_hints", stdin_packs_hints_nr); - - strbuf_release(&buf); - string_list_clear(&include_packs, 0); - string_list_clear(&exclude_packs, 0); } static void add_cruft_object_entry(const struct object_id *oid, enum object_type type, @@ -4022,7 +4060,6 @@ static void mark_pack_kept_in_core(struct string_list *packs, unsigned keep) } } -static void add_unreachable_loose_objects(void); static void add_objects_in_unpacked_packs(void); static void enumerate_cruft_objects(void) @@ -4032,7 +4069,7 @@ static void enumerate_cruft_objects(void) _("Enumerating cruft objects"), 0); add_objects_in_unpacked_packs(); - add_unreachable_loose_objects(); + add_unreachable_loose_objects(NULL); stop_progress(&progress_state); } @@ -4310,8 +4347,9 @@ static void add_objects_in_unpacked_packs(void) } static int add_loose_object(const struct object_id *oid, const char *path, - void *data UNUSED) + void *data) { + struct rev_info *revs = data; enum object_type type = odb_read_object_info(the_repository->objects, oid, NULL); if (type < 0) { @@ -4332,6 +4370,10 @@ static int add_loose_object(const struct object_id *oid, const char *path, } else { add_object_entry(oid, type, "", 0); } + + if (revs && type == OBJ_COMMIT) + add_pending_oid(revs, NULL, oid, 0); + return 0; } @@ -4340,10 +4382,10 @@ static int add_loose_object(const struct object_id *oid, const char *path, * add_object_entry will weed out duplicates, so we just add every * loose object we find. */ -static void add_unreachable_loose_objects(void) +static void add_unreachable_loose_objects(struct rev_info *revs) { for_each_loose_file_in_source(the_repository->objects->sources, - add_loose_object, NULL, NULL, NULL); + add_loose_object, NULL, NULL, revs); } static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid) @@ -4691,7 +4733,7 @@ static void get_object_list(struct rev_info *revs, int ac, const char **av) if (keep_unreachable) add_objects_in_unpacked_packs(); if (pack_loose_unreachable) - add_unreachable_loose_objects(); + add_unreachable_loose_objects(NULL); if (unpack_unreachable) loosen_unused_packed_objects(); @@ -4798,6 +4840,23 @@ static int is_not_in_promisor_pack(struct commit *commit, void *data) { return is_not_in_promisor_pack_obj((struct object *) commit, data); } +static int parse_stdin_packs_mode(const struct option *opt, const char *arg, + int unset) +{ + enum stdin_packs_mode *mode = opt->value; + + if (unset) + *mode = STDIN_PACKS_MODE_NONE; + else if (!arg || !*arg) + *mode = STDIN_PACKS_MODE_STANDARD; + else if (!strcmp(arg, "follow")) + *mode = STDIN_PACKS_MODE_FOLLOW; + else + die(_("invalid value for '%s': '%s'"), opt->long_name, arg); + + return 0; +} + int cmd_pack_objects(int argc, const char **argv, const char *prefix, @@ -4808,7 +4867,7 @@ int cmd_pack_objects(int argc, struct strvec rp = STRVEC_INIT; int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0; int rev_list_index = 0; - int stdin_packs = 0; + enum stdin_packs_mode stdin_packs = STDIN_PACKS_MODE_NONE; struct string_list keep_pack_list = STRING_LIST_INIT_NODUP; struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT; @@ -4863,6 +4922,9 @@ int cmd_pack_objects(int argc, OPT_SET_INT_F(0, "indexed-objects", &rev_list_index, N_("include objects referred to by the index"), 1, PARSE_OPT_NONEG), + OPT_CALLBACK_F(0, "stdin-packs", &stdin_packs, N_("mode"), + N_("read packs from stdin"), + PARSE_OPT_OPTARG, parse_stdin_packs_mode), OPT_BOOL(0, "stdin-packs", &stdin_packs, N_("read packs from stdin")), OPT_BOOL(0, "stdout", &pack_to_stdout, @@ -4940,7 +5002,7 @@ int cmd_pack_objects(int argc, reset_pack_idx_option(&pack_idx_opts); pack_idx_opts.flags |= WRITE_REV; - git_config(git_pack_config, NULL); + repo_config(the_repository, git_pack_config, NULL); if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0)) pack_idx_opts.flags &= ~WRITE_REV; @@ -5028,9 +5090,10 @@ int cmd_pack_objects(int argc, strvec_push(&rp, "--unpacked"); } - if (exclude_promisor_objects && exclude_promisor_objects_best_effort) - die(_("options '%s' and '%s' cannot be used together"), - "--exclude-promisor-objects", "--exclude-promisor-objects-best-effort"); + die_for_incompatible_opt2(exclude_promisor_objects, + "--exclude-promisor-objects", + exclude_promisor_objects_best_effort, + "--exclude-promisor-objects-best-effort"); if (exclude_promisor_objects) { use_internal_rev_list = 1; fetch_if_missing = 0; @@ -5068,13 +5131,14 @@ int cmd_pack_objects(int argc, if (!pack_to_stdout && thin) die(_("--thin cannot be used to build an indexable pack")); - if (keep_unreachable && unpack_unreachable) - die(_("options '%s' and '%s' cannot be used together"), "--keep-unreachable", "--unpack-unreachable"); + die_for_incompatible_opt2(keep_unreachable, "--keep-unreachable", + unpack_unreachable, "--unpack-unreachable"); if (!rev_list_all || !rev_list_reflog || !rev_list_index) unpack_unreachable_expiration = 0; - if (stdin_packs && filter_options.choice) - die(_("cannot use --filter with --stdin-packs")); + die_for_incompatible_opt2(stdin_packs, "--stdin-packs", + filter_options.choice, "--filter"); + if (stdin_packs && use_internal_rev_list) die(_("cannot use internal rev list with --stdin-packs")); @@ -5082,8 +5146,8 @@ int cmd_pack_objects(int argc, if (cruft) { if (use_internal_rev_list) die(_("cannot use internal rev list with --cruft")); - if (stdin_packs) - die(_("cannot use --stdin-packs with --cruft")); + die_for_incompatible_opt2(stdin_packs, "--stdin-packs", + cruft, "--cruft"); } /* @@ -5151,11 +5215,7 @@ int cmd_pack_objects(int argc, progress_state = start_progress(the_repository, _("Enumerating objects"), 0); if (stdin_packs) { - /* avoids adding objects in excluded packs */ - ignore_packed_keep_in_core = 1; - read_packs_list_from_stdin(); - if (rev_list_unpacked) - add_unreachable_loose_objects(); + read_stdin_packs(stdin_packs, rev_list_unpacked); } else if (cruft) { read_cruft_objects(); } else if (!use_internal_rev_list) { diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c index e47bae1c80..5e28d0f9e8 100644 --- a/builtin/pack-refs.c +++ b/builtin/pack-refs.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "parse-options.h" #include "refs.h" diff --git a/builtin/patch-id.c b/builtin/patch-id.c index cdef2ec10a..d26e9d0c1e 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -3,6 +3,7 @@ #include "builtin.h" #include "config.h" #include "diff.h" +#include "environment.h" #include "gettext.h" #include "hash.h" #include "hex.h" @@ -235,7 +236,7 @@ int cmd_patch_id(int argc, OPT_END() }; - git_config(git_patch_id_config, &config); + repo_config(the_repository, git_patch_id_config, &config); /* verbatim implies stable */ if (config.verbatim) @@ -254,7 +255,7 @@ int cmd_patch_id(int argc, * the code that computes patch IDs to always use SHA1. */ if (!the_hash_algo) - repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT); generate_id_list(opts ? opts > 1 : config.stable, opts ? opts == 3 : config.verbatim); diff --git a/builtin/prune.c b/builtin/prune.c index bf5d3bb152..55635a891f 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "builtin.h" @@ -64,7 +63,7 @@ static void perform_reachability_traversal(struct rev_info *revs) return; if (show_progress) - progress = start_delayed_progress(the_repository, + progress = start_delayed_progress(revs->repo, _("Checking connectivity"), 0); mark_reachable_objects(revs, 1, expire, progress); stop_progress(&progress); @@ -78,7 +77,7 @@ static int is_object_reachable(const struct object_id *oid, perform_reachability_traversal(revs); - obj = lookup_object(the_repository, oid); + obj = lookup_object(revs->repo, oid); return obj && (obj->flags & SEEN); } @@ -99,8 +98,8 @@ static int prune_object(const struct object_id *oid, const char *fullpath, if (st.st_mtime > expire) return 0; if (show_only || verbose) { - enum object_type type = odb_read_object_info(the_repository->objects, - oid, NULL); + enum object_type type = + odb_read_object_info(revs->repo->objects, oid, NULL); printf("%s %s\n", oid_to_hex(oid), (type > 0) ? type_name(type) : "unknown"); } @@ -154,7 +153,7 @@ static void remove_temporary_files(const char *path) int cmd_prune(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { struct rev_info revs; int exclude_promisor_objects = 0; @@ -173,20 +172,19 @@ int cmd_prune(int argc, expire = TIME_MAX; save_commit_buffer = 0; disable_replace_refs(); - repo_init_revisions(the_repository, &revs, prefix); argc = parse_options(argc, argv, prefix, options, prune_usage, 0); - if (repository_format_precious_objects) + repo_init_revisions(repo, &revs, prefix); + if (repo->repository_format_precious_objects) die(_("cannot prune in a precious-objects repo")); while (argc--) { struct object_id oid; const char *name = *argv++; - if (!repo_get_oid(the_repository, name, &oid)) { - struct object *object = parse_object_or_die(the_repository, &oid, - name); + if (!repo_get_oid(repo, name, &oid)) { + struct object *object = parse_object_or_die(repo, &oid, name); add_pending_object(&revs, object, ""); } else @@ -200,16 +198,16 @@ int cmd_prune(int argc, revs.exclude_promisor_objects = 1; } - for_each_loose_file_in_source(the_repository->objects->sources, + for_each_loose_file_in_source(repo->objects->sources, prune_object, prune_cruft, prune_subdir, &revs); prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0); - remove_temporary_files(repo_get_object_directory(the_repository)); - s = mkpathdup("%s/pack", repo_get_object_directory(the_repository)); + remove_temporary_files(repo_get_object_directory(repo)); + s = mkpathdup("%s/pack", repo_get_object_directory(repo)); remove_temporary_files(s); free(s); - if (is_repository_shallow(the_repository)) { + if (is_repository_shallow(repo)) { perform_reachability_traversal(&revs); prune_shallow(show_only ? PRUNE_SHOW_ONLY : 0); } diff --git a/builtin/pull.c b/builtin/pull.c index c593f324fe..5ebd529620 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -11,6 +11,7 @@ #include "builtin.h" #include "advice.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "merge.h" @@ -90,7 +91,8 @@ static char *opt_ff; static const char *opt_verify_signatures; static const char *opt_verify; static int opt_autostash = -1; -static int config_autostash; +static int config_rebase_autostash; +static int config_pull_autostash = -1; static int check_trust_level = 1; static struct strvec opt_strategies = STRVEC_INIT; static struct strvec opt_strategy_opts = STRVEC_INIT; @@ -312,7 +314,7 @@ static const char *config_get_ff(void) { const char *value; - if (git_config_get_value("pull.ff", &value)) + if (repo_config_get_value(the_repository, "pull.ff", &value)) return NULL; switch (git_parse_maybe_bool(value)) { @@ -343,7 +345,7 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified) if (curr_branch) { char *key = xstrfmt("branch.%s.rebase", curr_branch->name); - if (!git_config_get_value(key, &value)) { + if (!repo_config_get_value(the_repository, key, &value)) { enum rebase_type ret = parse_config_rebase(key, value, 1); free(key); return ret; @@ -352,7 +354,7 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified) free(key); } - if (!git_config_get_value("pull.rebase", &value)) + if (!repo_config_get_value(the_repository, "pull.rebase", &value)) return parse_config_rebase("pull.rebase", value, 1); *rebase_unspecified = 1; @@ -367,7 +369,18 @@ static int git_pull_config(const char *var, const char *value, const struct config_context *ctx, void *cb) { if (!strcmp(var, "rebase.autostash")) { - config_autostash = git_config_bool(var, value); + /* + * run_rebase() also reads this option. The reason we handle it here is + * that when pull.rebase is true, a fast-forward may occur without + * invoking run_rebase(). We need to ensure that autostash is set even + * in the fast-forward case. + * + * run_merge() handles merge.autostash, so we don't handle it here. + */ + config_rebase_autostash = git_config_bool(var, value); + return 0; + } else if (!strcmp(var, "pull.autostash")) { + config_pull_autostash = git_config_bool(var, value); return 0; } else if (!strcmp(var, "submodule.recurse")) { recurse_submodules = git_config_bool(var, value) ? @@ -999,13 +1012,15 @@ int cmd_pull(int argc, if (!getenv("GIT_REFLOG_ACTION")) set_reflog_message(argc, argv); - git_config(git_pull_config, NULL); + repo_config(the_repository, git_pull_config, NULL); if (the_repository->gitdir) { prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; } argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0); + if (opt_autostash == -1) + opt_autostash = config_pull_autostash; if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT) recurse_submodules = recurse_submodules_cli; @@ -1052,7 +1067,7 @@ int cmd_pull(int argc, if (opt_rebase) { if (opt_autostash == -1) - opt_autostash = config_autostash; + opt_autostash = config_rebase_autostash; if (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index)) die(_("Updating an unborn branch with changes added to the index.")); diff --git a/builtin/push.c b/builtin/push.c index 92d530e5c4..d0794b7b30 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -598,7 +598,7 @@ int cmd_push(int argc, }; packet_trace_identity("push"); - git_config(git_push_config, &flags); + repo_config(the_repository, git_push_config, &flags); argc = parse_options(argc, argv, prefix, options, push_usage, 0); push_options = (push_options_cmdline.nr ? &push_options_cmdline diff --git a/builtin/range-diff.c b/builtin/range-diff.c index 32ddb6613f..a563abff5f 100644 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@ -54,7 +54,7 @@ int cmd_range_diff(int argc, struct object_id oid; const char *three_dots = NULL; - git_config(git_diff_ui_config, NULL); + repo_config(the_repository, git_diff_ui_config, NULL); repo_diff_setup(the_repository, &diffopt); diff --git a/builtin/read-tree.c b/builtin/read-tree.c index a8f352f7cd..34f7a59f38 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -6,6 +6,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "lockfile.h" @@ -168,7 +169,7 @@ int cmd_read_tree(int argc, opts.src_index = the_repository->index; opts.dst_index = the_repository->index; - git_config(git_read_tree_config, NULL); + repo_config(the_repository, git_read_tree_config, NULL); argc = parse_options(argc, argv, cmd_prefix, read_tree_options, read_tree_usage, 0); diff --git a/builtin/rebase.c b/builtin/rebase.c index 2e8c4ee678..3c85768d29 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -293,15 +293,6 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) &revisions, &shortrevisions)) goto cleanup; - if (init_basic_state(&replay, - opts->head_name ? opts->head_name : "detached HEAD", - opts->onto, &opts->orig_head->object.oid)) - goto cleanup; - - if (!opts->upstream && opts->squash_onto) - write_file(path_squash_onto(), "%s\n", - oid_to_hex(opts->squash_onto)); - strvec_pushl(&make_script_args, "", revisions, NULL); if (opts->restrict_revision) strvec_pushf(&make_script_args, "^%s", @@ -310,21 +301,30 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) ret = sequencer_make_script(the_repository, &todo_list.buf, make_script_args.nr, make_script_args.v, flags); - - if (ret) + if (ret) { error(_("could not generate todo list")); - else { - discard_index(the_repository->index); - if (todo_list_parse_insn_buffer(the_repository, &replay, - todo_list.buf.buf, &todo_list)) - BUG("unusable todo list"); - - ret = complete_action(the_repository, &replay, flags, - shortrevisions, opts->onto_name, opts->onto, - &opts->orig_head->object.oid, &opts->exec, - opts->autosquash, opts->update_refs, &todo_list); + goto cleanup; } + if (init_basic_state(&replay, + opts->head_name ? opts->head_name : "detached HEAD", + opts->onto, &opts->orig_head->object.oid)) + goto cleanup; + + if (!opts->upstream && opts->squash_onto) + write_file(path_squash_onto(), "%s\n", + oid_to_hex(opts->squash_onto)); + + discard_index(the_repository->index); + if (todo_list_parse_insn_buffer(the_repository, &replay, + todo_list.buf.buf, &todo_list)) + BUG("unusable todo list"); + + ret = complete_action(the_repository, &replay, flags, + shortrevisions, opts->onto_name, opts->onto, + &opts->orig_head->object.oid, &opts->exec, + opts->autosquash, opts->update_refs, &todo_list); + cleanup: replay_opts_release(&replay); free(revisions); @@ -340,7 +340,7 @@ static int run_sequencer_rebase(struct rebase_options *opts) unsigned flags = 0; int abbreviate_commands = 0, ret = 0; - git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands); + repo_config_get_bool(the_repository, "rebase.abbreviatecommands", &abbreviate_commands); flags |= opts->keep_empty ? TODO_LIST_KEEP_EMPTY : 0; flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0; @@ -1128,6 +1128,7 @@ int cmd_rebase(int argc, .short_name = 'n', .long_name = "no-stat", .value = &options.flags, + .precision = sizeof(options.flags), .help = N_("do not show diffstat of what changed upstream"), .flags = PARSE_OPT_NOARG, .defval = REBASE_DIFFSTAT, @@ -1244,7 +1245,7 @@ int cmd_rebase(int argc, prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; - git_config(rebase_config, &options); + repo_config(the_repository, rebase_config, &options); /* options.gpg_sign_opt will be either "-S" or NULL */ gpg_sign = options.gpg_sign_opt ? "" : NULL; FREE_AND_NULL(options.gpg_sign_opt); diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index bd9baf81e5..1113137a6f 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -2203,7 +2203,7 @@ static struct command *read_head_info(struct packet_reader *reader, use_push_options = 1; hash = parse_feature_value(feature_list, "object-format", &len, NULL); if (!hash) { - hash = hash_algos[GIT_HASH_SHA1].name; + hash = hash_algos[GIT_HASH_SHA1_LEGACY].name; len = strlen(hash); } if (xstrncmpz(the_hash_algo->name, hash, len)) @@ -2613,7 +2613,7 @@ int cmd_receive_pack(int argc, if (!enter_repo(service_dir, 0)) die("'%s' does not appear to be a git repository", service_dir); - git_config(receive_pack_config, NULL); + repo_config(the_repository, receive_pack_config, NULL); if (cert_nonce_seed) push_cert_nonce = prepare_push_cert_nonce(service_dir, time(NULL)); diff --git a/builtin/reflog.c b/builtin/reflog.c index 3acaf3e32c..1db26aa65f 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -202,7 +202,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix, OPT_END() }; - git_config(reflog_expire_config, &opts); + repo_config(the_repository, reflog_expire_config, &opts); save_commit_buffer = 0; do_all = status = 0; @@ -283,6 +283,9 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix, &cb); free(ref); } + + reflog_clear_expire_config(&opts); + return status; } diff --git a/builtin/refs.c b/builtin/refs.c index 998d2a2c1c..c7ad0a2963 100644 --- a/builtin/refs.c +++ b/builtin/refs.c @@ -88,7 +88,7 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix, if (argc) usage(_("'git refs verify' takes no arguments")); - git_config(git_fsck_config, &fsck_refs_options); + repo_config(the_repository, git_fsck_config, &fsck_refs_options); prepare_repo_settings(the_repository); worktrees = get_worktrees_without_reading_head(); diff --git a/builtin/remote.c b/builtin/remote.c index 7cbda285eb..43a122740a 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -132,7 +132,7 @@ static void add_branch(const char *key, const char *branchname, else strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s", branchname, remotename, branchname); - git_config_set_multivar(key, tmp->buf, "^$", 0); + repo_config_set_multivar(the_repository, key, tmp->buf, "^$", 0); } static const char mirror_advice[] = @@ -157,6 +157,21 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not) return 0; } +static int check_remote_collision(struct remote *remote, void *data) +{ + const char *name = data; + const char *p; + + if (skip_prefix(name, remote->name, &p) && *p == '/') + die(_("remote name '%s' is a subset of existing remote '%s'"), + name, remote->name); + if (skip_prefix(remote->name, name, &p) && *p == '/') + die(_("remote name '%s' is a superset of existing remote '%s'"), + name, remote->name); + + return 0; +} + static int add(int argc, const char **argv, const char *prefix, struct repository *repo UNUSED) { @@ -208,8 +223,10 @@ static int add(int argc, const char **argv, const char *prefix, if (!valid_remote_name(name)) die(_("'%s' is not a valid remote name"), name); + for_each_remote(check_remote_collision, (void *)name); + strbuf_addf(&buf, "remote.%s.url", name); - git_config_set(buf.buf, url); + repo_config_set(the_repository, buf.buf, url); if (!mirror || mirror & MIRROR_FETCH) { strbuf_reset(&buf); @@ -225,14 +242,14 @@ static int add(int argc, const char **argv, const char *prefix, if (mirror & MIRROR_PUSH) { strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.mirror", name); - git_config_set(buf.buf, "true"); + repo_config_set(the_repository, buf.buf, "true"); } if (fetch_tags != TAGS_DEFAULT) { strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.tagOpt", name); - git_config_set(buf.buf, - fetch_tags == TAGS_SET ? "--tags" : "--no-tags"); + repo_config_set(the_repository, buf.buf, + fetch_tags == TAGS_SET ? "--tags" : "--no-tags"); } if (fetch && fetch_remote(name)) { @@ -353,7 +370,7 @@ static void read_branches(void) { if (branch_list.nr) return; - git_config(config_read_branches, NULL); + repo_config(the_repository, config_read_branches, NULL); } struct ref_states { @@ -634,15 +651,15 @@ static int migrate_file(struct remote *remote) strbuf_addf(&buf, "remote.%s.url", remote->name); for (i = 0; i < remote->url.nr; i++) - git_config_set_multivar(buf.buf, remote->url.v[i], "^$", 0); + repo_config_set_multivar(the_repository, buf.buf, remote->url.v[i], "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.push", remote->name); for (i = 0; i < remote->push.nr; i++) - git_config_set_multivar(buf.buf, remote->push.items[i].raw, "^$", 0); + repo_config_set_multivar(the_repository, buf.buf, remote->push.items[i].raw, "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", remote->name); for (i = 0; i < remote->fetch.nr; i++) - git_config_set_multivar(buf.buf, remote->fetch.items[i].raw, "^$", 0); + repo_config_set_multivar(the_repository, buf.buf, remote->fetch.items[i].raw, "^$", 0); #ifndef WITH_BREAKING_CHANGES if (remote->origin == REMOTE_REMOTES) unlink_or_warn(repo_git_path_replace(the_repository, &buf, @@ -690,12 +707,12 @@ static void handle_push_default(const char* old_name, const char* new_name) .origin = STRBUF_INIT, .linenr = -1, }; - git_config(config_read_push_default, &push_default); + repo_config(the_repository, config_read_push_default, &push_default); if (push_default.scope >= CONFIG_SCOPE_COMMAND) ; /* pass */ else if (push_default.scope >= CONFIG_SCOPE_LOCAL) { - int result = git_config_set_gently("remote.pushDefault", - new_name); + int result = repo_config_set_gently(the_repository, "remote.pushDefault", + new_name); if (new_name && result && result != CONFIG_NOTHING_SET) die(_("could not set '%s'"), "remote.pushDefault"); else if (!new_name && result && result != CONFIG_NOTHING_SET) @@ -771,7 +788,7 @@ static int mv(int argc, const char **argv, const char *prefix, if (oldremote->fetch.nr) { strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", rename.new_name); - git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE); + repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE); strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name); for (i = 0; i < oldremote->fetch.nr; i++) { char *ptr; @@ -791,7 +808,7 @@ static int mv(int argc, const char **argv, const char *prefix, "\tPlease update the configuration manually if necessary."), buf2.buf); - git_config_set_multivar(buf.buf, buf2.buf, "^$", 0); + repo_config_set_multivar(the_repository, buf.buf, buf2.buf, "^$", 0); } } @@ -802,12 +819,12 @@ static int mv(int argc, const char **argv, const char *prefix, if (info->remote_name && !strcmp(info->remote_name, rename.old_name)) { strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.remote", item->string); - git_config_set(buf.buf, rename.new_name); + repo_config_set(the_repository, buf.buf, rename.new_name); } if (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) { strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.pushRemote", item->string); - git_config_set(buf.buf, rename.new_name); + repo_config_set(the_repository, buf.buf, rename.new_name); } } @@ -934,7 +951,7 @@ static int rm(int argc, const char **argv, const char *prefix, strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.%s", item->string, *k); - result = git_config_set_gently(buf.buf, NULL); + result = repo_config_set_gently(the_repository, buf.buf, NULL); if (result && result != CONFIG_NOTHING_SET) die(_("could not unset '%s'"), buf.buf); } @@ -942,7 +959,7 @@ static int rm(int argc, const char **argv, const char *prefix, if (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) { strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.pushremote", item->string); - result = git_config_set_gently(buf.buf, NULL); + result = repo_config_set_gently(the_repository, buf.buf, NULL); if (result && result != CONFIG_NOTHING_SET) die(_("could not unset '%s'"), buf.buf); } @@ -1268,7 +1285,7 @@ static int get_one_entry(struct remote *remote, void *priv) strbuf_addf(&promisor_config, "remote.%s.partialclonefilter", remote->name); strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url.v[0]); - if (!git_config_get_string_tmp(promisor_config.buf, &partial_clone_filter)) + if (!repo_config_get_string_tmp(the_repository, promisor_config.buf, &partial_clone_filter)) strbuf_addf(&remote_info_buf, " [%s]", partial_clone_filter); strbuf_release(&promisor_config); @@ -1503,7 +1520,7 @@ static int set_head(int argc, const char **argv, const char *prefix, struct strbuf config_name = STRBUF_INIT; strbuf_addf(&config_name, "remote.%s.followremotehead", remote->name); - git_config_set(config_name.buf, "warn"); + repo_config_set(the_repository, config_name.buf, "warn"); strbuf_release(&config_name); } @@ -1521,9 +1538,6 @@ static int prune_remote(const char *remote, int dry_run) struct ref_states states = REF_STATES_INIT; struct string_list refs_to_prune = STRING_LIST_INIT_NODUP; struct string_list_item *item; - const char *dangling_msg = dry_run - ? _(" %s will become dangling!") - : _(" %s has become dangling!"); get_remote_ref_states(remote, &states, GET_REF_STATES); @@ -1555,7 +1569,7 @@ static int prune_remote(const char *remote, int dry_run) } refs_warn_dangling_symrefs(get_main_ref_store(the_repository), - stdout, dangling_msg, &refs_to_prune); + stdout, " ", dry_run, &refs_to_prune); string_list_clear(&refs_to_prune, 0); free_remote_ref_states(&states); @@ -1623,7 +1637,7 @@ static int update(int argc, const char **argv, const char *prefix, strvec_push(&cmd.args, argv[i]); if (strcmp(cmd.args.v[cmd.args.nr-1], "default") == 0) { - git_config(get_remote_default, &default_defined); + repo_config(the_repository, get_remote_default, &default_defined); if (!default_defined) { strvec_pop(&cmd.args); strvec_push(&cmd.args, "--all"); @@ -1636,8 +1650,8 @@ static int update(int argc, const char **argv, const char *prefix, static int remove_all_fetch_refspecs(const char *key) { - return git_config_set_multivar_gently(key, NULL, NULL, - CONFIG_FLAGS_MULTI_REPLACE); + return repo_config_set_multivar_gently(the_repository, key, NULL, NULL, + CONFIG_FLAGS_MULTI_REPLACE); } static void add_branches(struct remote *remote, const char **branches, @@ -1793,10 +1807,10 @@ static int set_url(int argc, const char **argv, const char *prefix, /* Special cases that add new entry. */ if ((!oldurl && !delete_mode) || add_mode) { if (add_mode) - git_config_set_multivar(name_buf.buf, newurl, + repo_config_set_multivar(the_repository, name_buf.buf, newurl, "^$", 0); else - git_config_set(name_buf.buf, newurl); + repo_config_set(the_repository, name_buf.buf, newurl); goto out; } @@ -1817,10 +1831,10 @@ static int set_url(int argc, const char **argv, const char *prefix, regfree(&old_regex); if (!delete_mode) - git_config_set_multivar(name_buf.buf, newurl, oldurl, 0); + repo_config_set_multivar(the_repository, name_buf.buf, newurl, oldurl, 0); else - git_config_set_multivar(name_buf.buf, NULL, oldurl, - CONFIG_FLAGS_MULTI_REPLACE); + repo_config_set_multivar(the_repository, name_buf.buf, NULL, oldurl, + CONFIG_FLAGS_MULTI_REPLACE); out: strbuf_release(&name_buf); return 0; diff --git a/builtin/repack.c b/builtin/repack.c index 9bbf032b6d..a4def39197 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -39,6 +39,7 @@ static int write_bitmaps = -1; static int use_delta_islands; static int run_update_server_info = 1; static char *packdir, *packtmp_name, *packtmp; +static int midx_must_contain_cruft = 1; static const char *const git_repack_usage[] = { N_("git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n" @@ -108,6 +109,10 @@ static int repack_config(const char *var, const char *value, free(cruft_po_args->threads); return git_config_string(&cruft_po_args->threads, var, value); } + if (!strcmp(var, "repack.midxmustcontaincruft")) { + midx_must_contain_cruft = git_config_bool(var, value); + return 0; + } return git_default_config(var, value, ctx, cb); } @@ -218,9 +223,9 @@ 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_local_multi_pack_index(the_repository); + struct multi_pack_index *m = get_multi_pack_index(the_repository->objects->sources); strbuf_addf(&buf, "%s.pack", base_name); - if (m && midx_contains_pack(m, buf.buf)) + if (m && m->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); @@ -690,6 +695,77 @@ static void free_pack_geometry(struct pack_geometry *geometry) free(geometry->pack); } +static int midx_has_unknown_packs(char **midx_pack_names, + size_t midx_pack_names_nr, + struct string_list *include, + struct pack_geometry *geometry, + struct existing_packs *existing) +{ + size_t i; + + string_list_sort(include); + + for (i = 0; i < midx_pack_names_nr; i++) { + const char *pack_name = midx_pack_names[i]; + + /* + * Determine whether or not each MIDX'd pack from the existing + * MIDX (if any) is represented in the new MIDX. For each pack + * in the MIDX, it must either be: + * + * - In the "include" list of packs to be included in the new + * MIDX. Note this function is called before the include + * list is populated with any cruft pack(s). + * + * - Below the geometric split line (if using pack geometry), + * indicating that the pack won't be included in the new + * MIDX, but its contents were rolled up as part of the + * geometric repack. + * + * - In the existing non-kept packs list (if not using pack + * geometry), and marked as non-deleted. + */ + if (string_list_has_string(include, pack_name)) { + continue; + } else if (geometry) { + struct strbuf buf = STRBUF_INIT; + uint32_t j; + + for (j = 0; j < geometry->split; j++) { + strbuf_reset(&buf); + strbuf_addstr(&buf, pack_basename(geometry->pack[j])); + strbuf_strip_suffix(&buf, ".pack"); + strbuf_addstr(&buf, ".idx"); + + if (!strcmp(pack_name, buf.buf)) { + strbuf_release(&buf); + break; + } + } + + strbuf_release(&buf); + + if (j < geometry->split) + continue; + } else { + struct string_list_item *item; + + item = string_list_lookup(&existing->non_kept_packs, + pack_name); + if (item && !pack_is_marked_for_deletion(item)) + continue; + } + + /* + * If we got to this point, the MIDX includes some pack that we + * don't know about. + */ + return 1; + } + + return 0; +} + struct midx_snapshot_ref_data { struct tempfile *f; struct oidset seen; @@ -758,6 +834,8 @@ static void midx_snapshot_refs(struct tempfile *f) static void midx_included_packs(struct string_list *include, struct existing_packs *existing, + char **midx_pack_names, + size_t midx_pack_names_nr, struct string_list *names, struct pack_geometry *geometry) { @@ -811,26 +889,56 @@ static void midx_included_packs(struct string_list *include, } } - for_each_string_list_item(item, &existing->cruft_packs) { + if (midx_must_contain_cruft || + midx_has_unknown_packs(midx_pack_names, midx_pack_names_nr, + include, geometry, existing)) { /* - * When doing a --geometric repack, there is no need to check - * for deleted packs, since we're by definition not doing an - * ALL_INTO_ONE repack (hence no packs will be deleted). - * Otherwise we must check for and exclude any packs which are - * enqueued for deletion. + * If there are one or more unknown pack(s) present (see + * midx_has_unknown_packs() for what makes a pack + * "unknown") in the MIDX before the repack, keep them + * as they may be required to form a reachability + * closure if the MIDX is bitmapped. * - * So we could omit the conditional below in the --geometric - * case, but doing so is unnecessary since no packs are marked - * as pending deletion (since we only call - * `mark_packs_for_deletion()` when doing an all-into-one - * repack). + * For example, a cruft pack can be required to form a + * reachability closure if the MIDX is bitmapped and one + * or more of the bitmap's selected commits reaches a + * once-cruft object that was later made reachable. */ - if (pack_is_marked_for_deletion(item)) - continue; + for_each_string_list_item(item, &existing->cruft_packs) { + /* + * When doing a --geometric repack, there is no + * need to check for deleted packs, since we're + * by definition not doing an ALL_INTO_ONE + * repack (hence no packs will be deleted). + * Otherwise we must check for and exclude any + * packs which are enqueued for deletion. + * + * So we could omit the conditional below in the + * --geometric case, but doing so is unnecessary + * since no packs are marked as pending + * deletion (since we only call + * `mark_packs_for_deletion()` when doing an + * all-into-one repack). + */ + if (pack_is_marked_for_deletion(item)) + continue; - strbuf_reset(&buf); - strbuf_addf(&buf, "%s.idx", item->string); - string_list_insert(include, buf.buf); + strbuf_reset(&buf); + strbuf_addf(&buf, "%s.idx", item->string); + string_list_insert(include, buf.buf); + } + } else { + /* + * Modern versions of Git (with the appropriate + * configuration setting) will write new copies of + * once-cruft objects when doing a --geometric repack. + * + * If the MIDX has no cruft pack, new packs written + * during a --geometric repack will not rely on the + * cruft pack to form a reachability closure, so we can + * avoid including them in the MIDX in that case. + */ + ; } strbuf_release(&buf); @@ -1145,6 +1253,8 @@ int cmd_repack(int argc, struct tempfile *refs_snapshot = NULL; int i, ext, ret; int show_progress; + char **midx_pack_names = NULL; + size_t midx_pack_names_nr = 0; /* variables to be filled by option parsing */ int delete_redundant = 0; @@ -1230,7 +1340,7 @@ int cmd_repack(int argc, list_objects_filter_init(&po_args.filter_options); - git_config(repack_config, &cruft_po_args); + repo_config(the_repository, repack_config, &cruft_po_args); argc = parse_options(argc, argv, prefix, builtin_repack_options, git_repack_usage, 0); @@ -1240,7 +1350,7 @@ int cmd_repack(int argc, po_args.depth = xstrdup_or_null(opt_depth); po_args.threads = xstrdup_or_null(opt_threads); - if (delete_redundant && repository_format_precious_objects) + if (delete_redundant && the_repository->repository_format_precious_objects) die(_("cannot delete packs in a precious-objects repo")); die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A", @@ -1362,7 +1472,10 @@ int cmd_repack(int argc, !(pack_everything & PACK_CRUFT)) strvec_push(&cmd.args, "--pack-loose-unreachable"); } else if (geometry.split_factor) { - strvec_push(&cmd.args, "--stdin-packs"); + if (midx_must_contain_cruft) + strvec_push(&cmd.args, "--stdin-packs"); + else + strvec_push(&cmd.args, "--stdin-packs=follow"); strvec_push(&cmd.args, "--unpacked"); } else { strvec_push(&cmd.args, "--unpacked"); @@ -1402,8 +1515,25 @@ int cmd_repack(int argc, if (ret) goto cleanup; - if (!names.nr && !po_args.quiet) - printf_ln(_("Nothing new to pack.")); + if (!names.nr) { + if (!po_args.quiet) + printf_ln(_("Nothing new to pack.")); + /* + * If we didn't write any new packs, the non-cruft packs + * may refer to once-unreachable objects in the cruft + * pack(s). + * + * If there isn't already a MIDX, the one we write + * must include the cruft pack(s), in case the + * non-cruft pack(s) refer to once-cruft objects. + * + * If there is already a MIDX, we can punt here, since + * midx_has_unknown_packs() will make the decision for + * us. + */ + if (!get_multi_pack_index(the_repository->objects->sources)) + midx_must_contain_cruft = 1; + } if (pack_everything & PACK_CRUFT) { const char *pack_prefix = find_pack_prefix(packdir, packtmp); @@ -1484,6 +1614,19 @@ int cmd_repack(int argc, string_list_sort(&names); + if (get_multi_pack_index(the_repository->objects->sources)) { + struct multi_pack_index *m = + get_multi_pack_index(the_repository->objects->sources); + + ALLOC_ARRAY(midx_pack_names, + m->num_packs + m->num_packs_in_base); + + for (; m; m = m->base_midx) + for (uint32_t i = 0; i < m->num_packs; i++) + midx_pack_names[midx_pack_names_nr++] = + xstrdup(m->pack_names[i]); + } + close_object_store(the_repository->objects); /* @@ -1525,7 +1668,8 @@ int cmd_repack(int argc, if (write_midx) { struct string_list include = STRING_LIST_INIT_DUP; - midx_included_packs(&include, &existing, &names, &geometry); + midx_included_packs(&include, &existing, midx_pack_names, + midx_pack_names_nr, &names, &geometry); ret = write_midx_included_packs(&include, &geometry, &names, refs_snapshot ? get_tempfile_path(refs_snapshot) : NULL, @@ -1576,6 +1720,9 @@ cleanup: string_list_clear(&names, 1); existing_packs_release(&existing); free_pack_geometry(&geometry); + for (size_t i = 0; i < midx_pack_names_nr; i++) + free(midx_pack_names[i]); + free(midx_pack_names); pack_objects_args_release(&po_args); pack_objects_args_release(&cruft_po_args); diff --git a/builtin/replace.c b/builtin/replace.c index 7c46d05ec1..900b560a77 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -11,6 +11,7 @@ #include "builtin.h" #include "config.h" #include "editor.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "refs.h" @@ -575,7 +576,7 @@ int cmd_replace(int argc, }; disable_replace_refs(); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0); diff --git a/builtin/rerere.c b/builtin/rerere.c index 1312e79d89..a056cb791b 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -66,7 +66,7 @@ int cmd_rerere(int argc, argc = parse_options(argc, argv, prefix, options, rerere_usage, 0); - git_config(git_xmerge_config, NULL); + repo_config(the_repository, git_xmerge_config, NULL); if (autoupdate == 1) flags = RERERE_AUTOUPDATE; diff --git a/builtin/reset.c b/builtin/reset.c index dc50ffc1ac..ed35802af1 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -346,6 +346,7 @@ int cmd_reset(int argc, struct object_id oid; struct pathspec pathspec; int intent_to_add = 0; + struct add_p_opt add_p_opt = ADD_P_OPT_INIT; const struct option options[] = { OPT__QUIET(&quiet, N_("be quiet, only report errors")), OPT_BOOL(0, "no-refresh", &no_refresh, @@ -370,6 +371,8 @@ int cmd_reset(int argc, PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater), OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")), + OPT_DIFF_UNIFIED(&add_p_opt.context), + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that removed paths will be added later")), OPT_PATHSPEC_FROM_FILE(&pathspec_from_file), @@ -377,7 +380,7 @@ int cmd_reset(int argc, OPT_END() }; - git_config(git_reset_config, NULL); + repo_config(the_repository, git_reset_config, NULL); argc = parse_options(argc, argv, prefix, options, git_reset_usage, PARSE_OPT_KEEP_DASHDASH); @@ -420,6 +423,11 @@ int cmd_reset(int argc, oidcpy(&oid, &tree->object.oid); } + if (add_p_opt.context < -1) + die(_("'%s' cannot be negative"), "--unified"); + if (add_p_opt.interhunkcontext < -1) + die(_("'%s' cannot be negative"), "--inter-hunk-context"); + prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; @@ -427,9 +435,14 @@ int cmd_reset(int argc, if (reset_type != NONE) die(_("options '%s' and '%s' cannot be used together"), "--patch", "--{hard,mixed,soft}"); trace2_cmd_mode("patch-interactive"); - update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, rev, - &pathspec); + update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, + &add_p_opt, rev, &pathspec); goto cleanup; + } else { + if (add_p_opt.context != -1) + die(_("the option '%s' requires '%s'"), "--unified", "--patch"); + if (add_p_opt.interhunkcontext != -1) + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch"); } /* git reset tree [--] paths... can be used to diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 4d0c460f18..99f876ba85 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -28,6 +28,14 @@ #include "quote.h" #include "strbuf.h" +struct rev_list_info { + struct rev_info *revs; + int flags; + int show_timestamp; + int hdr_termination; + const char *header_prefix; +}; + static const char rev_list_usage[] = "git rev-list [<options>] <commit>... [--] [<path>...]\n" "\n" @@ -636,7 +644,7 @@ int cmd_rev_list(int argc, show_usage_if_asked(argc, argv, rev_list_usage); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); repo_init_revisions(the_repository, &revs, prefix); revs.abbrev = DEFAULT_ABBREV; revs.commit_format = CMIT_FMT_UNSPECIFIED; @@ -652,17 +660,21 @@ int cmd_rev_list(int argc, * * Let "--missing" to conditionally set fetch_if_missing. */ + /* - * NEEDSWORK: These loops that attempt to find presence of - * options without understanding that the options they are - * skipping are broken (e.g., it would not know "--grep + * NEEDSWORK: The next loop is utterly broken. It tries to + * notice an option is used, but without understanding if each + * option takes an argument, which fundamentally would not + * work. It would not know "--grep * --exclude-promisor-objects" is not triggering - * "--exclude-promisor-objects" option). We really need - * setup_revisions() to have a mechanism to allow and disallow - * some sets of options for different commands (like rev-list, - * replay, etc). Such a mechanism should do an early parsing - * of options and be able to manage the `--missing=...` and - * `--exclude-promisor-objects` options below. + * "--exclude-promisor-objects" option, for example. + * + * We really need setup_revisions() to have a mechanism to + * allow and disallow some sets of options for different + * commands (like rev-list, replay, etc). Such a mechanism + * should do an early parsing of options and be able to manage + * the `--missing=...` and `--exclude-promisor-objects` + * options below. */ for (i = 1; i < argc; i++) { const char *arg = argv[i]; diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 490da33bec..44ff1b8342 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -734,7 +734,7 @@ int cmd_rev_parse(int argc, /* No options; just report on whether we're in a git repo or not. */ if (argc == 1) { setup_git_directory(); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); return 0; } @@ -769,7 +769,7 @@ int cmd_rev_parse(int argc, /* The rest of the options require a git repository. */ if (!did_repo_setup) { prefix = setup_git_directory(); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); did_repo_setup = 1; prepare_repo_settings(the_repository); diff --git a/builtin/rm.c b/builtin/rm.c index a6565a69cf..05d89e98c3 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -9,6 +9,7 @@ #include "builtin.h" #include "advice.h" #include "config.h" +#include "environment.h" #include "lockfile.h" #include "dir.h" #include "gettext.h" @@ -271,7 +272,7 @@ int cmd_rm(int argc, struct pathspec pathspec; char *seen; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_rm_options, builtin_rm_usage, 0); diff --git a/builtin/send-pack.c b/builtin/send-pack.c index 28b69d26b4..8b81c8a848 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "config.h" +#include "environment.h" #include "hex.h" #include "pkt-line.h" #include "run-command.h" diff --git a/builtin/shortlog.c b/builtin/shortlog.c index fe15e11497..b91acf45c8 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -419,9 +419,9 @@ int cmd_shortlog(int argc, * git/nongit so that we do not have to do this. */ if (nongit && !the_hash_algo) - repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); shortlog_init(&log); repo_init_revisions(the_repository, &rev, prefix); parse_options_start(&ctx, argc, argv, prefix, options, diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 525b231d87..1ab7db9d2c 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -710,7 +710,7 @@ int cmd_show_branch(int ac, init_commit_name_slab(&name_slab); - git_config(git_show_branch_config, NULL); + repo_config(the_repository, git_show_branch_config, NULL); /* If nothing is specified, try the default first */ if (ac == 1 && default_args.nr) { diff --git a/builtin/show-index.c b/builtin/show-index.c index 9d4ecf5e7b..2c3e2940ce 100644 --- a/builtin/show-index.c +++ b/builtin/show-index.c @@ -47,7 +47,7 @@ int cmd_show_index(int argc, * the index file passed in and use that instead. */ if (!the_hash_algo) - repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT); hashsz = the_hash_algo->rawsz; diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 117709cb07..0b6f9edf86 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -1,6 +1,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "refs/refs-internal.h" @@ -324,7 +325,7 @@ struct repository *repo UNUSED) OPT_END() }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, show_ref_options, show_ref_usage, 0); diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 1bf01591b2..8c333b3e2e 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -1082,7 +1082,7 @@ int cmd_sparse_checkout(int argc, builtin_sparse_checkout_options, builtin_sparse_checkout_usage, 0); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); prepare_repo_settings(the_repository); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/stash.c b/builtin/stash.c index e2f95cc2eb..1977e50df2 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -979,7 +979,7 @@ static int show_stash(int argc, const char **argv, const char *prefix, int do_usage = 0; init_diff_ui_defaults(); - git_config(git_diff_ui_config, NULL); + repo_config(the_repository, git_diff_ui_config, NULL); repo_init_revisions(the_repository, &rev, prefix); argc = parse_options(argc, argv, prefix, options, git_stash_show_usage, @@ -1301,7 +1301,8 @@ done: } static int stash_patch(struct stash_info *info, const struct pathspec *ps, - struct strbuf *out_patch, int quiet) + struct strbuf *out_patch, int quiet, + struct add_p_opt *add_p_opt) { int ret = 0; struct child_process cp_read_tree = CHILD_PROCESS_INIT; @@ -1326,7 +1327,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps, old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT)); setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1); - ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps); + ret = !!run_add_p(the_repository, ADD_P_STASH, add_p_opt, NULL, ps); the_repository->index_file = old_repo_index_file; if (old_index_env && *old_index_env) @@ -1421,8 +1422,8 @@ done: } static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_buf, - int include_untracked, int patch_mode, int only_staged, - struct stash_info *info, struct strbuf *patch, + int include_untracked, int patch_mode, struct add_p_opt *add_p_opt, + int only_staged, struct stash_info *info, struct strbuf *patch, int quiet) { int ret = 0; @@ -1503,7 +1504,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b untracked_commit_option = 1; } if (patch_mode) { - ret = stash_patch(info, ps, patch, quiet); + ret = stash_patch(info, ps, patch, quiet, add_p_opt); if (ret < 0) { if (!quiet) fprintf_ln(stderr, _("Cannot save the current " @@ -1578,7 +1579,7 @@ static int create_stash(int argc, const char **argv, const char *prefix UNUSED, if (!check_changes_tracked_files(&ps)) return 0; - ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, 0, &info, + ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, NULL, 0, &info, NULL, 0); if (!ret) printf_ln("%s", oid_to_hex(&info.w_commit)); @@ -1589,7 +1590,8 @@ static int create_stash(int argc, const char **argv, const char *prefix UNUSED, } static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int quiet, - int keep_index, int patch_mode, int include_untracked, int only_staged) + int keep_index, int patch_mode, struct add_p_opt *add_p_opt, + int include_untracked, int only_staged) { int ret = 0; struct stash_info info = STASH_INFO_INIT; @@ -1659,8 +1661,8 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q if (stash_msg) strbuf_addstr(&stash_msg_buf, stash_msg); - if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, only_staged, - &info, &patch, quiet)) { + if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, + add_p_opt, only_staged, &info, &patch, quiet)) { ret = -1; goto done; } @@ -1833,6 +1835,7 @@ static int push_stash(int argc, const char **argv, const char *prefix, const char *stash_msg = NULL; char *pathspec_from_file = NULL; struct pathspec ps; + struct add_p_opt add_p_opt = ADD_P_OPT_INIT; struct option options[] = { OPT_BOOL('k', "keep-index", &keep_index, N_("keep index")), @@ -1840,6 +1843,8 @@ static int push_stash(int argc, const char **argv, const char *prefix, N_("stash staged changes only")), OPT_BOOL('p', "patch", &patch_mode, N_("stash in patch mode")), + OPT_DIFF_UNIFIED(&add_p_opt.context), + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), OPT__QUIET(&quiet, N_("quiet mode")), OPT_BOOL('u', "include-untracked", &include_untracked, N_("include untracked files in stash")), @@ -1895,8 +1900,20 @@ static int push_stash(int argc, const char **argv, const char *prefix, die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file"); } + if (!patch_mode) { + if (add_p_opt.context != -1) + die(_("the option '%s' requires '%s'"), "--unified", "--patch"); + if (add_p_opt.interhunkcontext != -1) + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch"); + } + + if (add_p_opt.context < -1) + die(_("'%s' cannot be negative"), "--unified"); + if (add_p_opt.interhunkcontext < -1) + die(_("'%s' cannot be negative"), "--inter-hunk-context"); + ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode, - include_untracked, only_staged); + &add_p_opt, include_untracked, only_staged); clear_pathspec(&ps); free(pathspec_from_file); @@ -1921,6 +1938,7 @@ static int save_stash(int argc, const char **argv, const char *prefix, const char *stash_msg = NULL; struct pathspec ps; struct strbuf stash_msg_buf = STRBUF_INIT; + struct add_p_opt add_p_opt = ADD_P_OPT_INIT; struct option options[] = { OPT_BOOL('k', "keep-index", &keep_index, N_("keep index")), @@ -1928,6 +1946,8 @@ static int save_stash(int argc, const char **argv, const char *prefix, N_("stash staged changes only")), OPT_BOOL('p', "patch", &patch_mode, N_("stash in patch mode")), + OPT_DIFF_UNIFIED(&add_p_opt.context), + OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext), OPT__QUIET(&quiet, N_("quiet mode")), OPT_BOOL('u', "include-untracked", &include_untracked, N_("include untracked files in stash")), @@ -1946,8 +1966,22 @@ static int save_stash(int argc, const char **argv, const char *prefix, stash_msg = strbuf_join_argv(&stash_msg_buf, argc, argv, ' '); memset(&ps, 0, sizeof(ps)); + + if (add_p_opt.context < -1) + die(_("'%s' cannot be negative"), "--unified"); + if (add_p_opt.interhunkcontext < -1) + die(_("'%s' cannot be negative"), "--inter-hunk-context"); + + if (!patch_mode) { + if (add_p_opt.context != -1) + die(_("the option '%s' requires '%s'"), "--unified", "--patch"); + if (add_p_opt.interhunkcontext != -1) + die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch"); + } + ret = do_push_stash(&ps, stash_msg, quiet, keep_index, - patch_mode, include_untracked, only_staged); + patch_mode, &add_p_opt, include_untracked, + only_staged); strbuf_release(&stash_msg_buf); return ret; @@ -2358,7 +2392,7 @@ int cmd_stash(int argc, const char **args_copy; int ret; - git_config(git_stash_config, NULL); + repo_config(the_repository, git_stash_config, NULL); argc = parse_options(argc, argv, prefix, options, git_stash_usage, PARSE_OPT_SUBCOMMAND_OPTIONAL | diff --git a/builtin/stripspace.c b/builtin/stripspace.c index e147f3ff92..4a566cbc5d 100644 --- a/builtin/stripspace.c +++ b/builtin/stripspace.c @@ -55,7 +55,7 @@ int cmd_stripspace(int argc, if (mode == STRIP_COMMENTS || mode == COMMENT_LINES) { setup_git_directory_gently(&nongit); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); } if (strbuf_read(&buf, 0, 1024) < 0) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index d8a6fa47e5..28f34f7bc1 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -53,7 +53,7 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int struct strbuf remotesb = STRBUF_INIT; strbuf_addf(&remotesb, "remote.%s.url", remote); - if (git_config_get_string(remotesb.buf, &remoteurl)) { + if (repo_config_get_string(the_repository, remotesb.buf, &remoteurl)) { if (!quiet) warning(_("could not look up configuration '%s'. " "Assuming this repository is its own " @@ -458,7 +458,7 @@ static void init_submodule(const char *path, const char *prefix, */ if (!is_submodule_active(the_repository, path)) { strbuf_addf(&sb, "submodule.%s.active", sub->name); - git_config_set_gently(sb.buf, "true"); + repo_config_set_gently(the_repository, sb.buf, "true"); strbuf_reset(&sb); } @@ -468,7 +468,7 @@ static void init_submodule(const char *path, const char *prefix, * .gitmodules, so look it up directly. */ strbuf_addf(&sb, "submodule.%s.url", sub->name); - if (git_config_get_string(sb.buf, &url)) { + if (repo_config_get_string(the_repository, sb.buf, &url)) { if (!sub->url) die(_("No url found for submodule path '%s' in .gitmodules"), displaypath); @@ -484,7 +484,7 @@ static void init_submodule(const char *path, const char *prefix, free(oldurl); } - if (git_config_set_gently(sb.buf, url)) + if (repo_config_set_gently(the_repository, sb.buf, url)) die(_("Failed to register url for submodule path '%s'"), displaypath); if (!(flags & OPT_QUIET)) @@ -496,7 +496,7 @@ static void init_submodule(const char *path, const char *prefix, /* Copy "update" setting when it is not set yet */ strbuf_addf(&sb, "submodule.%s.update", sub->name); - if (git_config_get_string_tmp(sb.buf, &upd) && + if (repo_config_get_string_tmp(the_repository, sb.buf, &upd) && sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) { if (sub->update_strategy.type == SM_UPDATE_COMMAND) { fprintf(stderr, _("warning: command update mode suggested for submodule '%s'\n"), @@ -506,7 +506,7 @@ static void init_submodule(const char *path, const char *prefix, upd = submodule_update_type_to_string(sub->update_strategy.type); } - if (git_config_set_gently(sb.buf, upd)) + if (repo_config_set_gently(the_repository, sb.buf, upd)) die(_("Failed to register update mode for submodule path '%s'"), displaypath); } strbuf_release(&sb); @@ -549,7 +549,7 @@ static int module_init(int argc, const char **argv, const char *prefix, * If there are no path args and submodule.active is set then, * by default, only initialize 'active' modules. */ - if (!argc && !git_config_get("submodule.active")) + if (!argc && !repo_config_get(the_repository, "submodule.active")) module_list_active(&list); info.prefix = prefix; @@ -649,7 +649,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, "--ignore-submodules=dirty", "--quiet", "--", path, NULL); - git_config(git_diff_basic_config, NULL); + repo_config(the_repository, git_diff_basic_config, NULL); repo_init_revisions(the_repository, &rev, NULL); rev.abbrev = 0; @@ -1034,7 +1034,7 @@ static void prepare_submodule_summary(struct summary_cb *info, config_key = xstrfmt("submodule.%s.ignore", sub->name); - if (!git_config_get_string_tmp(config_key, &value)) + if (!repo_config_get_string_tmp(the_repository, config_key, &value)) ignore_all = !strcmp(value, "all"); else if (sub->ignore) ignore_all = !strcmp(sub->ignore, "all"); @@ -1108,7 +1108,7 @@ static int compute_summary_module_list(struct object_id *head_oid, if (info->argc) strvec_pushv(&diff_args, info->argv); - git_config(git_diff_basic_config, NULL); + repo_config(the_repository, git_diff_basic_config, NULL); repo_init_revisions(the_repository, &rev, info->prefix); rev.abbrev = 0; precompose_argv_prefix(diff_args.nr, diff_args.v, NULL); @@ -1262,7 +1262,7 @@ static void sync_submodule(const char *path, const char *prefix, strbuf_reset(&sb); strbuf_addf(&sb, "submodule.%s.url", sub->name); - if (git_config_set_gently(sb.buf, super_config_url)) + if (repo_config_set_gently(the_repository, sb.buf, super_config_url)) die(_("failed to register url for submodule path '%s'"), displaypath); @@ -1280,7 +1280,7 @@ static void sync_submodule(const char *path, const char *prefix, submodule_to_gitdir(the_repository, &sb, path); strbuf_addstr(&sb, "/config"); - if (git_config_set_in_file_gently(sb.buf, remote_key, NULL, sub_origin_url)) + if (repo_config_set_in_file_gently(the_repository, sb.buf, remote_key, NULL, sub_origin_url)) die(_("failed to update remote for submodule '%s'"), path); @@ -1623,11 +1623,11 @@ static void prepare_possible_alternates(const char *sm_name, char *sm_alternate = NULL, *error_strategy = NULL; struct submodule_alternate_setup sas = SUBMODULE_ALTERNATE_SETUP_INIT; - git_config_get_string("submodule.alternateLocation", &sm_alternate); + repo_config_get_string(the_repository, "submodule.alternateLocation", &sm_alternate); if (!sm_alternate) return; - git_config_get_string("submodule.alternateErrorStrategy", &error_strategy); + repo_config_get_string(the_repository, "submodule.alternateErrorStrategy", &error_strategy); if (!error_strategy) error_strategy = xstrdup("die"); @@ -1808,14 +1808,14 @@ static int clone_submodule(const struct module_clone_data *clone_data, die(_("could not get submodule directory for '%s'"), clone_data_path); /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */ - git_config_get_string("submodule.alternateLocation", &sm_alternate); + repo_config_get_string(the_repository, "submodule.alternateLocation", &sm_alternate); if (sm_alternate) - git_config_set_in_file(p, "submodule.alternateLocation", - sm_alternate); - git_config_get_string("submodule.alternateErrorStrategy", &error_strategy); + repo_config_set_in_file(the_repository, p, "submodule.alternateLocation", + sm_alternate); + repo_config_get_string(the_repository, "submodule.alternateErrorStrategy", &error_strategy); if (error_strategy) - git_config_set_in_file(p, "submodule.alternateErrorStrategy", - error_strategy); + repo_config_set_in_file(the_repository, p, "submodule.alternateErrorStrategy", + error_strategy); free(sm_alternate); free(error_strategy); @@ -2522,7 +2522,7 @@ static int ensure_core_worktree(const char *path) abs_path = absolute_pathdup(path); rel_path = relative_path(abs_path, subrepo.gitdir, &sb); - git_config_set_in_file(cfg_file, "core.worktree", rel_path); + repo_config_set_in_file(the_repository, cfg_file, "core.worktree", rel_path); free(cfg_file); free(abs_path); @@ -2830,7 +2830,7 @@ static int module_update(int argc, const char **argv, const char *prefix, }; update_clone_config_from_gitmodules(&opt.max_jobs); - git_config(git_update_clone_config, &opt.max_jobs); + repo_config(the_repository, git_update_clone_config, &opt.max_jobs); argc = parse_options(argc, argv, prefix, module_update_options, git_submodule_helper_usage, 0); @@ -2878,7 +2878,7 @@ static int module_update(int argc, const char **argv, const char *prefix, * If there are no path args and submodule.active is set then, * by default, only initialize 'active' modules. */ - if (!argc && !git_config_get("submodule.active")) + if (!argc && !repo_config_get(the_repository, "submodule.active")) module_list_active(&list); info.prefix = opt.prefix; @@ -3128,7 +3128,7 @@ static int module_create_branch(int argc, const char **argv, const char *prefix, NULL }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); track = git_branch_track; argc = parse_options(argc, argv, prefix, options, usage, 0); @@ -3309,7 +3309,7 @@ static void configure_added_submodule(struct add_data *add_data) struct child_process add_gitmodules = CHILD_PROCESS_INIT; key = xstrfmt("submodule.%s.url", add_data->sm_name); - git_config_set_gently(key, add_data->realrepo); + repo_config_set_gently(the_repository, key, add_data->realrepo); free(key); add_submod.git_cmd = 1; @@ -3349,19 +3349,19 @@ static void configure_added_submodule(struct add_data *add_data) * is_submodule_active(), since that function needs to find * out the value of "submodule.active" again anyway. */ - if (!git_config_get("submodule.active")) { + if (!repo_config_get(the_repository, "submodule.active")) { /* * If the submodule being added isn't already covered by the * current configured pathspec, set the submodule's active flag */ if (!is_submodule_active(the_repository, add_data->sm_path)) { key = xstrfmt("submodule.%s.active", add_data->sm_name); - git_config_set_gently(key, "true"); + repo_config_set_gently(the_repository, key, "true"); free(key); } } else { key = xstrfmt("submodule.%s.active", add_data->sm_name); - git_config_set_gently(key, "true"); + repo_config_set_gently(the_repository, key, "true"); free(key); } } diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c index 299d23d76a..231e41e715 100644 --- a/builtin/symbolic-ref.c +++ b/builtin/symbolic-ref.c @@ -1,6 +1,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "refs.h" #include "parse-options.h" @@ -59,7 +60,7 @@ int cmd_symbolic_ref(int argc, OPT_END(), }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, git_symbolic_ref_usage, 0); if (msg && !*msg) diff --git a/builtin/tag.c b/builtin/tag.c index 8fbe9e7be0..f0665af3ac 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -546,7 +546,7 @@ int cmd_tag(int argc, * Try to set sort keys from config. If config does not set any, * fall back on default (refname) sorting. */ - git_config(git_tag_config, &sorting_options); + repo_config(the_repository, git_tag_config, &sorting_options); if (!sorting_options.nr) string_list_append(&sorting_options, "refname"); diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c index 4360872ae0..87877a9fab 100644 --- a/builtin/unpack-file.c +++ b/builtin/unpack-file.c @@ -1,6 +1,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "config.h" +#include "environment.h" #include "hex.h" #include "object-file.h" #include "object-name.h" @@ -43,7 +44,7 @@ int cmd_unpack_file(int argc, if (repo_get_oid(the_repository, argv[1], &oid)) die("Not a valid object name %s", argv[1]); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); puts(create_temp_file(&oid)); return 0; diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 1d405d156e..7ae7c82b6c 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -622,7 +622,7 @@ int cmd_unpack_objects(int argc, disable_replace_refs(); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); quiet = !isatty(2); diff --git a/builtin/update-index.c b/builtin/update-index.c index 538b619ba4..2380f3ccd6 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -981,6 +981,7 @@ int cmd_update_index(int argc, .type = OPTION_SET_INT, .long_name = "assume-unchanged", .value = &mark_valid_only, + .precision = sizeof(mark_valid_only), .help = N_("mark files as \"not changing\""), .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, .defval = MARK_FLAG, @@ -989,6 +990,7 @@ int cmd_update_index(int argc, .type = OPTION_SET_INT, .long_name = "no-assume-unchanged", .value = &mark_valid_only, + .precision = sizeof(mark_valid_only), .help = N_("clear assumed-unchanged bit"), .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, .defval = UNMARK_FLAG, @@ -997,6 +999,7 @@ int cmd_update_index(int argc, .type = OPTION_SET_INT, .long_name = "skip-worktree", .value = &mark_skip_worktree_only, + .precision = sizeof(mark_skip_worktree_only), .help = N_("mark files as \"index-only\""), .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, .defval = MARK_FLAG, @@ -1005,6 +1008,7 @@ int cmd_update_index(int argc, .type = OPTION_SET_INT, .long_name = "no-skip-worktree", .value = &mark_skip_worktree_only, + .precision = sizeof(mark_skip_worktree_only), .help = N_("clear skip-worktree bit"), .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, .defval = UNMARK_FLAG, @@ -1079,6 +1083,7 @@ int cmd_update_index(int argc, .type = OPTION_SET_INT, .long_name = "fsmonitor-valid", .value = &mark_fsmonitor_only, + .precision = sizeof(mark_fsmonitor_only), .help = N_("mark files as fsmonitor valid"), .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, .defval = MARK_FLAG, @@ -1087,6 +1092,7 @@ int cmd_update_index(int argc, .type = OPTION_SET_INT, .long_name = "no-fsmonitor-valid", .value = &mark_fsmonitor_only, + .precision = sizeof(mark_fsmonitor_only), .help = N_("clear fsmonitor valid bit"), .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, .defval = UNMARK_FLAG, @@ -1097,7 +1103,7 @@ int cmd_update_index(int argc, show_usage_with_options_if_asked(argc, argv, update_index_usage, options); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); prepare_repo_settings(r); the_repository->settings.command_requires_full_index = 0; diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 1e6131e04a..195437e7c6 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -3,6 +3,7 @@ #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hash.h" #include "hex.h" @@ -769,7 +770,7 @@ int cmd_update_ref(int argc, OPT_END(), }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, options, git_update_ref_usage, 0); if (msg && !*msg) diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c index ba702d30ef..4c12968a83 100644 --- a/builtin/update-server-info.c +++ b/builtin/update-server-info.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "parse-options.h" #include "server-info.h" diff --git a/builtin/var.c b/builtin/var.c index ada642a9fe..a2d790d453 100644 --- a/builtin/var.c +++ b/builtin/var.c @@ -11,6 +11,7 @@ #include "attr.h" #include "config.h" #include "editor.h" +#include "environment.h" #include "ident.h" #include "pager.h" #include "refs.h" @@ -226,11 +227,11 @@ int cmd_var(int argc, usage(var_usage); if (strcmp(argv[1], "-l") == 0) { - git_config(show_config, NULL); + repo_config(the_repository, show_config, NULL); list_vars(); return 0; } - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); git_var = get_git_var(argv[1]); if (!git_var) diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c index 5f749a30da..62398acd72 100644 --- a/builtin/verify-commit.c +++ b/builtin/verify-commit.c @@ -7,6 +7,7 @@ */ #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "object-name.h" #include "commit.h" diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c index 34e4ed715f..65fd6629a0 100644 --- a/builtin/verify-pack.c +++ b/builtin/verify-pack.c @@ -1,6 +1,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "run-command.h" #include "parse-options.h" @@ -81,7 +82,7 @@ int cmd_verify_pack(int argc, OPT_END() }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, prefix, verify_pack_options, verify_pack_usage, 0); if (argc < 1) diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c index ed1c40338f..cd6bc11095 100644 --- a/builtin/verify-tag.c +++ b/builtin/verify-tag.c @@ -7,6 +7,7 @@ */ #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "tag.h" #include "object-name.h" diff --git a/builtin/worktree.c b/builtin/worktree.c index 2dceeeed8b..812774a5ca 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -379,13 +379,13 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir) if (!git_configset_get_bool(&cs, "core.bare", &bare) && bare && - git_config_set_multivar_in_file_gently( + repo_config_set_multivar_in_file_gently(the_repository, to_file, "core.bare", NULL, "true", NULL, 0)) error(_("failed to unset '%s' in '%s'"), "core.bare", to_file); if (!git_configset_get(&cs, "core.worktree") && - git_config_set_in_file_gently(to_file, - "core.worktree", NULL, NULL)) + repo_config_set_in_file_gently(the_repository, to_file, + "core.worktree", NULL, NULL)) error(_("failed to unset '%s' in '%s'"), "core.worktree", to_file); @@ -1448,7 +1448,7 @@ int cmd_worktree(int ac, OPT_END() }; - git_config(git_worktree_config, NULL); + repo_config(the_repository, git_worktree_config, NULL); if (!prefix) prefix = ""; diff --git a/builtin/write-tree.c b/builtin/write-tree.c index 5a8dc377ec..e3bd1a40db 100644 --- a/builtin/write-tree.c +++ b/builtin/write-tree.c @@ -6,6 +6,7 @@ #define USE_THE_REPOSITORY_VARIABLE #include "builtin.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "tree.h" @@ -35,6 +36,7 @@ int cmd_write_tree(int argc, .type = OPTION_BIT, .long_name = "ignore-cache-tree", .value = &flags, + .precision = sizeof(flags), .help = N_("only useful for debugging"), .flags = PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, .defval = WRITE_TREE_IGNORE_CACHE_TREE, @@ -42,7 +44,7 @@ int cmd_write_tree(int argc, OPT_END() }; - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); argc = parse_options(argc, argv, cmd_prefix, write_tree_options, write_tree_usage, 0); @@ -95,7 +95,7 @@ int read_bundle_header_fd(int fd, struct bundle_header *header, * by an "object-format=" capability, which is being handled in * `parse_capability()`. */ - header->hash_algo = &hash_algos[GIT_HASH_SHA1]; + header->hash_algo = &hash_algos[GIT_HASH_SHA1_LEGACY]; /* The bundle header ends with an empty line */ while (!strbuf_getwholeline_fd(&buf, fd, '\n') && @@ -507,7 +507,7 @@ int create_bundle(struct repository *r, const char *path, * SHA1. * 2. @filter is required because we parsed an object filter. */ - if (the_hash_algo != &hash_algos[GIT_HASH_SHA1] || revs.filter.choice) + if (the_hash_algo != &hash_algos[GIT_HASH_SHA1_LEGACY] || revs.filter.choice) min_version = 3; if (argc > 1) { diff --git a/checkout.c b/checkout.c index 0b1cf8b40b..1588b116ee 100644 --- a/checkout.c +++ b/checkout.c @@ -52,7 +52,7 @@ char *unique_tracking_name(const char *name, struct object_id *oid, { struct tracking_name_data cb_data = TRACKING_NAME_DATA_INIT; const char *default_remote = NULL; - if (!git_config_get_string_tmp("checkout.defaultremote", &default_remote)) + if (!repo_config_get_string_tmp(the_repository, "checkout.defaultremote", &default_remote)) cb_data.default_remote = default_remote; cb_data.src_ref = xstrfmt("refs/heads/%s", name); cb_data.dst_oid = oid; diff --git a/ci/print-test-failures.sh b/ci/print-test-failures.sh index dc910e5160..5545e77c13 100755 --- a/ci/print-test-failures.sh +++ b/ci/print-test-failures.sh @@ -41,7 +41,7 @@ do case "$CI_TYPE" in github-actions) mkdir -p failed-test-artifacts - echo "FAILED_TEST_ARTIFACTS=${TEST_OUTPUT_DIRECTORY:t}/failed-test-artifacts" >>$GITHUB_ENV + echo "FAILED_TEST_ARTIFACTS=${TEST_OUTPUT_DIRECTORY:-t}/failed-test-artifacts" >>$GITHUB_ENV cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/ tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir" continue diff --git a/ci/run-style-check.sh b/ci/run-style-check.sh index 6cd4b1d934..0832c19df0 100755 --- a/ci/run-style-check.sh +++ b/ci/run-style-check.sh @@ -5,21 +5,5 @@ baseCommit=$1 -# Remove optional braces of control statements (if, else, for, and while) -# according to the LLVM coding style. This avoids braces on simple -# single-statement bodies of statements but keeps braces if one side of -# if/else if/.../else cascade has multi-statement body. -# -# As this rule comes with a warning [1], we want to experiment with it -# before adding it in-tree. since the CI job for the style check is allowed -# to fail, appending the rule here allows us to validate its efficacy. -# While also ensuring that end-users are not affected directly. -# -# [1]: https://clang.llvm.org/docs/ClangFormatStyleOptions.html#removebracesllvm -{ - cat .clang-format - echo "RemoveBracesLLVM: true" -} >/tmp/clang-format-rules - -git clang-format --style=file:/tmp/clang-format-rules \ +git clang-format --style=file:.clang-format \ --diff --extensions c,h "$baseCommit" diff --git a/commit-graph.c b/commit-graph.c index bd7b6f5338..e0d92b816f 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -4,6 +4,7 @@ #include "git-compat-util.h" #include "config.h" #include "csum-file.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "lockfile.h" @@ -31,6 +31,7 @@ #include "parse.h" #include "object-file.h" #include "object-file-convert.h" +#include "prio-queue.h" static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **); @@ -739,20 +740,27 @@ void commit_list_sort_by_date(struct commit_list **list) commit_list_sort(list, commit_list_compare_by_date); } -struct commit *pop_most_recent_commit(struct commit_list **list, +struct commit *pop_most_recent_commit(struct prio_queue *queue, unsigned int mark) { - struct commit *ret = pop_commit(list); + struct commit *ret = prio_queue_peek(queue); + int get_pending = 1; struct commit_list *parents = ret->parents; while (parents) { struct commit *commit = parents->item; if (!repo_parse_commit(the_repository, commit) && !(commit->object.flags & mark)) { commit->object.flags |= mark; - commit_list_insert_by_date(commit, list); + if (get_pending) + prio_queue_replace(queue, commit); + else + prio_queue_put(queue, commit); + get_pending = 0; } parents = parents->next; } + if (get_pending) + prio_queue_get(queue); return ret; } @@ -2,6 +2,7 @@ #define COMMIT_H #include "object.h" +#include "add-interactive.h" struct signature_check; struct strbuf; @@ -201,10 +202,10 @@ const char *repo_logmsg_reencode(struct repository *r, const char *skip_blank_lines(const char *msg); -/** Removes the first commit from a list sorted by date, and adds all - * of its parents. - **/ -struct commit *pop_most_recent_commit(struct commit_list **list, +struct prio_queue; + +/* Removes the first commit from a prio_queue and adds its parents. */ +struct commit *pop_most_recent_commit(struct prio_queue *queue, unsigned int mark); struct commit *pop_commit(struct commit_list **stack); @@ -257,7 +258,7 @@ int for_each_commit_graft(each_commit_graft_fn, void *); int interactive_add(struct repository *repo, const char **argv, const char *prefix, - int patch); + int patch, struct add_p_opt *add_p_opt); struct commit_extra_header { struct commit_extra_header *next; diff --git a/compat/bswap.h b/compat/bswap.h index b34054f2bd..28635ebc69 100644 --- a/compat/bswap.h +++ b/compat/bswap.h @@ -32,78 +32,35 @@ static inline uint64_t default_bswap64(uint64_t val) ((val & (uint64_t)0xff00000000000000ULL) >> 56)); } +/* + * __has_builtin is available since Clang 10 and GCC 10. + * Below is a fallback for older compilers. + */ +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + #undef bswap32 #undef bswap64 -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - -#define bswap32 git_bswap32 -static inline uint32_t git_bswap32(uint32_t x) -{ - uint32_t result; - if (__builtin_constant_p(x)) - result = default_swab32(x); - else - __asm__("bswap %0" : "=r" (result) : "0" (x)); - return result; -} - -#define bswap64 git_bswap64 -#if defined(__x86_64__) -static inline uint64_t git_bswap64(uint64_t x) -{ - uint64_t result; - if (__builtin_constant_p(x)) - result = default_bswap64(x); - else - __asm__("bswap %q0" : "=r" (result) : "0" (x)); - return result; -} -#else -static inline uint64_t git_bswap64(uint64_t x) -{ - union { uint64_t i64; uint32_t i32[2]; } tmp, result; - if (__builtin_constant_p(x)) - result.i64 = default_bswap64(x); - else { - tmp.i64 = x; - result.i32[0] = git_bswap32(tmp.i32[1]); - result.i32[1] = git_bswap32(tmp.i32[0]); - } - return result.i64; -} -#endif - -#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64)) +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64)) #include <stdlib.h> #define bswap32(x) _byteswap_ulong(x) #define bswap64(x) _byteswap_uint64(x) -#endif +#define GIT_LITTLE_ENDIAN 1234 +#define GIT_BIG_ENDIAN 4321 +#define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN -#if defined(bswap32) +#elif __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) -#undef ntohl -#undef htonl -#define ntohl(x) bswap32(x) -#define htonl(x) bswap32(x) +#define bswap32(x) __builtin_bswap32((x)) +#define bswap64(x) __builtin_bswap64((x)) #endif -#if defined(bswap64) - -#undef ntohll -#undef htonll -#define ntohll(x) bswap64(x) -#define htonll(x) bswap64(x) - -#else - -#undef ntohll -#undef htonll - #if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) # define GIT_BYTE_ORDER __BYTE_ORDER @@ -116,7 +73,13 @@ static inline uint64_t git_bswap64(uint64_t x) # define GIT_LITTLE_ENDIAN LITTLE_ENDIAN # define GIT_BIG_ENDIAN BIG_ENDIAN -#else +#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) + +# define GIT_BYTE_ORDER __BYTE_ORDER__ +# define GIT_LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +# define GIT_BIG_ENDIAN __ORDER_BIG_ENDIAN__ + +#elif !defined(GIT_BYTE_ORDER) # define GIT_BIG_ENDIAN 4321 # define GIT_LITTLE_ENDIAN 1234 @@ -135,14 +98,33 @@ static inline uint64_t git_bswap64(uint64_t x) #endif +#undef ntohl +#undef htonl +#undef ntohll +#undef htonll + #if GIT_BYTE_ORDER == GIT_BIG_ENDIAN -# define ntohll(n) (n) -# define htonll(n) (n) +# define ntohl(x) (x) +# define htonl(x) (x) +# define ntohll(x) (x) +# define htonll(x) (x) #else -# define ntohll(n) default_bswap64(n) -# define htonll(n) default_bswap64(n) -#endif +# if defined(bswap32) +# define ntohl(x) bswap32(x) +# define htonl(x) bswap32(x) +# else +# define ntohl(x) default_swab32(x) +# define htonl(x) default_swab32(x) +# endif + +# if defined(bswap64) +# define ntohll(x) bswap64(x) +# define htonll(x) bswap64(x) +# else +# define ntohll(x) default_bswap64(x) +# define htonll(x) default_bswap64(x) +# endif #endif static inline uint16_t get_be16(const void *ptr) diff --git a/compat/mingw-posix.h b/compat/mingw-posix.h index 88e0cf9292..631a208684 100644 --- a/compat/mingw-posix.h +++ b/compat/mingw-posix.h @@ -96,6 +96,7 @@ struct sigaction { unsigned sa_flags; }; #define SA_RESTART 0 +#define SA_NOCLDSTOP 1 struct itimerval { struct timeval it_value, it_interval; diff --git a/compat/mingw.c b/compat/mingw.c index 8a9972a1ca..8538e3d172 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -244,7 +244,6 @@ enum hide_dotfiles_type { HIDE_DOTFILES_DOTGITONLY }; -static int core_restrict_inherited_handles = -1; static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; static char *unset_environment_variables; @@ -268,15 +267,6 @@ int mingw_core_config(const char *var, const char *value, return 0; } - if (!strcmp(var, "core.restrictinheritedhandles")) { - if (value && !strcasecmp(value, "auto")) - core_restrict_inherited_handles = -1; - else - core_restrict_inherited_handles = - git_config_bool(var, value); - return 0; - } - return 0; } @@ -588,13 +578,24 @@ static int mingw_open_existing(const wchar_t *filename, int oflags, ...) &security_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); + if (err == ERROR_ACCESS_DENIED) { + DWORD attrs = GetFileAttributesW(filename); + if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) + handle = CreateFileW(filename, access, + FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, + &security_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL| FILE_FLAG_BACKUP_SEMANTICS, NULL); + } - /* See `mingw_open_append()` for why we have this conversion. */ - if (err == ERROR_INVALID_PARAMETER) - err = ERROR_PATH_NOT_FOUND; + if (handle == INVALID_HANDLE_VALUE) { + err = GetLastError(); - errno = err_win_to_posix(err); - return -1; + /* See `mingw_open_append()` for why we have this conversion. */ + if (err == ERROR_INVALID_PARAMETER) + err = ERROR_PATH_NOT_FOUND; + + errno = err_win_to_posix(err); + return -1; + } } fd = _open_osfhandle((intptr_t)handle, oflags | O_BINARY); @@ -1656,7 +1657,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen const char *dir, int prepend_cmd, int fhin, int fhout, int fherr) { - static int restrict_handle_inheritance = -1; STARTUPINFOEXW si; PROCESS_INFORMATION pi; LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL; @@ -1676,16 +1676,6 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen /* Make sure to override previous errors, if any */ errno = 0; - if (restrict_handle_inheritance < 0) - restrict_handle_inheritance = core_restrict_inherited_handles; - /* - * The following code to restrict which handles are inherited seems - * to work properly only on Windows 7 and later, so let's disable it - * on Windows Vista and 2008. - */ - if (restrict_handle_inheritance < 0) - restrict_handle_inheritance = GetVersion() >> 16 >= 7601; - do_unset_environment_variables(); /* Determine whether or not we are associated to a console */ @@ -1787,7 +1777,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen wenvblk = make_environment_block(deltaenv); memset(&pi, 0, sizeof(pi)); - if (restrict_handle_inheritance && stdhandles_count && + if (stdhandles_count && (InitializeProcThreadAttributeList(NULL, 1, 0, &size) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) && (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST) @@ -1808,52 +1798,13 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen &si.StartupInfo, &pi); /* - * On Windows 2008 R2, it seems that specifying certain types of handles - * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an - * error. Rather than playing finicky and fragile games, let's just try - * to detect this situation and simply try again without restricting any - * handle inheritance. This is still better than failing to create - * processes. + * On the off-chance that something with the file handle restriction + * went wrong, silently fall back to trying without it. */ - if (!ret && restrict_handle_inheritance && stdhandles_count) { + if (!ret && stdhandles_count) { DWORD err = GetLastError(); struct strbuf buf = STRBUF_INIT; - if (err != ERROR_NO_SYSTEM_RESOURCES && - /* - * On Windows 7 and earlier, handles on pipes and character - * devices are inherited automatically, and cannot be - * specified in the thread handle list. Rather than trying - * to catch each and every corner case (and running the - * chance of *still* forgetting a few), let's just fall - * back to creating the process without trying to limit the - * handle inheritance. - */ - !(err == ERROR_INVALID_PARAMETER && - GetVersion() >> 16 < 9200) && - !getenv("SUPPRESS_HANDLE_INHERITANCE_WARNING")) { - DWORD fl = 0; - int i; - - setenv("SUPPRESS_HANDLE_INHERITANCE_WARNING", "1", 1); - - for (i = 0; i < stdhandles_count; i++) { - HANDLE h = stdhandles[i]; - strbuf_addf(&buf, "handle #%d: %p (type %lx, " - "handle info (%d) %lx\n", i, h, - GetFileType(h), - GetHandleInformation(h, &fl), - fl); - } - strbuf_addstr(&buf, "\nThis is a bug; please report it " - "at\nhttps://github.com/git-for-windows/" - "git/issues/new\n\n" - "To suppress this warning, please set " - "the environment variable\n\n" - "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1" - "\n"); - } - restrict_handle_inheritance = 0; flags &= ~EXTENDED_STARTUPINFO_PRESENT; ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, TRUE, flags, wenvblk, dir ? wdir : NULL, @@ -2326,7 +2277,9 @@ repeat: * current system doesn't support FileRenameInfoEx. Keep us * from using it in future calls and retry. */ - if (gle == ERROR_INVALID_PARAMETER) { + if (gle == ERROR_INVALID_PARAMETER || + gle == ERROR_NOT_SUPPORTED || + gle == ERROR_INVALID_FUNCTION) { supports_file_rename_info_ex = 0; goto repeat; } @@ -2561,7 +2514,9 @@ int setitimer(int type UNUSED, struct itimerval *in, struct itimerval *out) int sigaction(int sig, struct sigaction *in, struct sigaction *out) { - if (sig != SIGALRM) + if (sig == SIGCHLD) + return -1; + else if (sig != SIGALRM) return errno = EINVAL, error("sigaction only implemented for SIGALRM"); if (out) diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c index 12e38e0ea3..43b3be0114 100644 --- a/compat/precompose_utf8.c +++ b/compat/precompose_utf8.c @@ -56,8 +56,8 @@ void probe_utf8_pathname_composition(void) close(output_fd); repo_git_path_replace(the_repository, &path, "%s", auml_nfd); precomposed_unicode = access(path.buf, R_OK) ? 0 : 1; - git_config_set("core.precomposeunicode", - precomposed_unicode ? "true" : "false"); + repo_config_set(the_repository, "core.precomposeunicode", + precomposed_unicode ? "true" : "false"); repo_git_path_replace(the_repository, &path, "%s", auml_nfc); if (unlink(path.buf)) die_errno(_("failed to unlink '%s'"), path.buf); @@ -75,7 +75,7 @@ const char *precompose_string_if_needed(const char *in) iconv_t ic_prec; char *out; if (precomposed_unicode < 0) - git_config_get_bool("core.precomposeunicode", &precomposed_unicode); + repo_config_get_bool(the_repository, "core.precomposeunicode", &precomposed_unicode); if (precomposed_unicode != 1) return in; ic_prec = iconv_open(repo_encoding, path_encoding); @@ -6,12 +6,8 @@ * */ -#define USE_THE_REPOSITORY_VARIABLE -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "abspath.h" -#include "advice.h" #include "date.h" #include "branch.h" #include "config.h" @@ -20,11 +16,8 @@ #include "environment.h" #include "gettext.h" #include "git-zlib.h" -#include "ident.h" #include "repository.h" #include "lockfile.h" -#include "mailmap.h" -#include "attr.h" #include "exec-cmd.h" #include "strbuf.h" #include "quote.h" @@ -32,7 +25,6 @@ #include "string-list.h" #include "object-name.h" #include "odb.h" -#include "pager.h" #include "path.h" #include "utf8.h" #include "color.h" @@ -41,7 +33,6 @@ #include "strvec.h" #include "trace2.h" #include "wildmatch.h" -#include "ws.h" #include "write-or-die.h" struct config_source { @@ -56,7 +47,6 @@ struct config_source { } u; enum config_origin_type origin_type; const char *name; - const char *path; enum config_error_action default_error_action; int linenr; int eof; @@ -71,9 +61,6 @@ struct config_source { }; #define CONFIG_SOURCE_INIT { 0 } -static int pack_compression_seen; -static int zlib_compression_seen; - /* * Config that comes from trusted scopes, namely: * - CONFIG_SCOPE_SYSTEM (e.g. /etc/gitconfig) @@ -173,14 +160,14 @@ static int handle_path_include(const struct key_value_info *kvi, if (!is_absolute_path(path)) { char *slash; - if (!kvi || !kvi->path) { + if (!kvi || kvi->origin_type != CONFIG_ORIGIN_FILE) { ret = error(_("relative config includes must come from files")); goto cleanup; } - slash = find_last_dir_sep(kvi->path); + slash = find_last_dir_sep(kvi->filename); if (slash) - strbuf_add(&buf, kvi->path, slash - kvi->path + 1); + strbuf_add(&buf, kvi->filename, slash - kvi->filename + 1); strbuf_addstr(&buf, path); path = buf.buf; } @@ -208,11 +195,12 @@ static void add_trailing_starstar_for_dir(struct strbuf *pat) } static int prepare_include_condition_pattern(const struct key_value_info *kvi, - struct strbuf *pat) + struct strbuf *pat, + size_t *out) { struct strbuf path = STRBUF_INIT; char *expanded; - int prefix = 0; + size_t prefix = 0; expanded = interpolate_path(pat->buf, 1); if (expanded) { @@ -224,11 +212,11 @@ static int prepare_include_condition_pattern(const struct key_value_info *kvi, if (pat->buf[0] == '.' && is_dir_sep(pat->buf[1])) { const char *slash; - if (!kvi || !kvi->path) + if (!kvi || kvi->origin_type != CONFIG_ORIGIN_FILE) return error(_("relative config include " "conditionals must come from files")); - strbuf_realpath(&path, kvi->path, 1); + strbuf_realpath(&path, kvi->filename, 1); slash = find_last_dir_sep(path.buf); if (!slash) BUG("how is this possible?"); @@ -239,8 +227,10 @@ static int prepare_include_condition_pattern(const struct key_value_info *kvi, add_trailing_starstar_for_dir(pat); + *out = prefix; + strbuf_release(&path); - return prefix; + return 0; } static int include_by_gitdir(const struct key_value_info *kvi, @@ -249,7 +239,8 @@ static int include_by_gitdir(const struct key_value_info *kvi, { struct strbuf text = STRBUF_INIT; struct strbuf pattern = STRBUF_INIT; - int ret = 0, prefix; + size_t prefix; + int ret = 0; const char *git_dir; int already_tried_absolute = 0; @@ -260,12 +251,11 @@ static int include_by_gitdir(const struct key_value_info *kvi, strbuf_realpath(&text, git_dir, 1); strbuf_add(&pattern, cond, cond_len); - prefix = prepare_include_condition_pattern(kvi, &pattern); - -again: - if (prefix < 0) + ret = prepare_include_condition_pattern(kvi, &pattern, &prefix); + if (ret < 0) goto done; +again: if (prefix > 0) { /* * perform literal matching on the prefix part so that @@ -633,7 +623,6 @@ void kvi_from_param(struct key_value_info *out) out->linenr = -1; out->origin_type = CONFIG_ORIGIN_CMDLINE; out->scope = CONFIG_SCOPE_COMMAND; - out->path = NULL; } int git_config_parse_parameter(const char *text, @@ -734,7 +723,6 @@ int git_config_from_parameters(config_fn_t fn, void *data) if (env) { unsigned long count; char *endp; - int i; count = strtoul(env, &endp, 10); if (*endp) { @@ -746,10 +734,10 @@ int git_config_from_parameters(config_fn_t fn, void *data) goto out; } - for (i = 0; i < count; i++) { + for (unsigned long i = 0; i < count; i++) { const char *key, *value; - strbuf_addf(&envvar, "GIT_CONFIG_KEY_%d", i); + strbuf_addf(&envvar, "GIT_CONFIG_KEY_%lu", i); key = getenv_safe(&to_free, envvar.buf); if (!key) { ret = error(_("missing config key %s"), envvar.buf); @@ -757,7 +745,7 @@ int git_config_from_parameters(config_fn_t fn, void *data) } strbuf_reset(&envvar); - strbuf_addf(&envvar, "GIT_CONFIG_VALUE_%d", i); + strbuf_addf(&envvar, "GIT_CONFIG_VALUE_%lu", i); value = getenv_safe(&to_free, envvar.buf); if (!value) { ret = error(_("missing config value %s"), envvar.buf); @@ -1036,7 +1024,6 @@ static void kvi_from_source(struct config_source *cs, out->origin_type = cs->origin_type; out->linenr = cs->linenr; out->scope = scope; - out->path = cs->path; } static int git_parse_source(struct config_source *cs, config_fn_t fn, @@ -1262,80 +1249,6 @@ double git_config_double(const char *name, const char *value, return ret; } -static const struct fsync_component_name { - const char *name; - enum fsync_component component_bits; -} fsync_component_names[] = { - { "loose-object", FSYNC_COMPONENT_LOOSE_OBJECT }, - { "pack", FSYNC_COMPONENT_PACK }, - { "pack-metadata", FSYNC_COMPONENT_PACK_METADATA }, - { "commit-graph", FSYNC_COMPONENT_COMMIT_GRAPH }, - { "index", FSYNC_COMPONENT_INDEX }, - { "objects", FSYNC_COMPONENTS_OBJECTS }, - { "reference", FSYNC_COMPONENT_REFERENCE }, - { "derived-metadata", FSYNC_COMPONENTS_DERIVED_METADATA }, - { "committed", FSYNC_COMPONENTS_COMMITTED }, - { "added", FSYNC_COMPONENTS_ADDED }, - { "all", FSYNC_COMPONENTS_ALL }, -}; - -static enum fsync_component parse_fsync_components(const char *var, const char *string) -{ - enum fsync_component current = FSYNC_COMPONENTS_PLATFORM_DEFAULT; - enum fsync_component positive = 0, negative = 0; - - while (string) { - int i; - size_t len; - const char *ep; - int negated = 0; - int found = 0; - - string = string + strspn(string, ", \t\n\r"); - ep = strchrnul(string, ','); - len = ep - string; - if (!strcmp(string, "none")) { - current = FSYNC_COMPONENT_NONE; - goto next_name; - } - - if (*string == '-') { - negated = 1; - string++; - len--; - if (!len) - warning(_("invalid value for variable %s"), var); - } - - if (!len) - break; - - for (i = 0; i < ARRAY_SIZE(fsync_component_names); ++i) { - const struct fsync_component_name *n = &fsync_component_names[i]; - - if (strncmp(n->name, string, len)) - continue; - - found = 1; - if (negated) - negative |= n->component_bits; - else - positive |= n->component_bits; - } - - if (!found) { - char *component = xstrndup(string, len); - warning(_("ignoring unknown core.fsync component '%s'"), component); - free(component); - } - -next_name: - string = ep; - } - - return (current & ~negative) | positive; -} - int git_config_bool_or_int(const char *name, const char *value, const struct key_value_info *kvi, int *is_bool) { @@ -1393,433 +1306,6 @@ int git_config_color(char *dest, const char *var, const char *value) return 0; } -static int git_default_core_config(const char *var, const char *value, - const struct config_context *ctx, void *cb) -{ - /* This needs a better name */ - if (!strcmp(var, "core.filemode")) { - trust_executable_bit = git_config_bool(var, value); - return 0; - } - if (!strcmp(var, "core.trustctime")) { - trust_ctime = git_config_bool(var, value); - return 0; - } - if (!strcmp(var, "core.checkstat")) { - if (!value) - return config_error_nonbool(var); - if (!strcasecmp(value, "default")) - check_stat = 1; - else if (!strcasecmp(value, "minimal")) - check_stat = 0; - else - return error(_("invalid value for '%s': '%s'"), - var, value); - } - - if (!strcmp(var, "core.quotepath")) { - quote_path_fully = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.symlinks")) { - has_symlinks = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.ignorecase")) { - ignore_case = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.attributesfile")) { - FREE_AND_NULL(git_attributes_file); - return git_config_pathname(&git_attributes_file, var, value); - } - - if (!strcmp(var, "core.bare")) { - is_bare_repository_cfg = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.ignorestat")) { - assume_unchanged = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.abbrev")) { - if (!value) - return config_error_nonbool(var); - if (!strcasecmp(value, "auto")) - default_abbrev = -1; - else if (!git_parse_maybe_bool_text(value)) - default_abbrev = GIT_MAX_HEXSZ; - else { - int abbrev = git_config_int(var, value, ctx->kvi); - if (abbrev < minimum_abbrev) - return error(_("abbrev length out of range: %d"), abbrev); - default_abbrev = abbrev; - } - return 0; - } - - if (!strcmp(var, "core.disambiguate")) - return set_disambiguate_hint_config(var, value); - - if (!strcmp(var, "core.loosecompression")) { - int level = git_config_int(var, value, ctx->kvi); - if (level == -1) - level = Z_DEFAULT_COMPRESSION; - else if (level < 0 || level > Z_BEST_COMPRESSION) - die(_("bad zlib compression level %d"), level); - zlib_compression_level = level; - zlib_compression_seen = 1; - return 0; - } - - if (!strcmp(var, "core.compression")) { - int level = git_config_int(var, value, ctx->kvi); - if (level == -1) - level = Z_DEFAULT_COMPRESSION; - else if (level < 0 || level > Z_BEST_COMPRESSION) - die(_("bad zlib compression level %d"), level); - if (!zlib_compression_seen) - zlib_compression_level = level; - if (!pack_compression_seen) - pack_compression_level = level; - return 0; - } - - if (!strcmp(var, "core.autocrlf")) { - if (value && !strcasecmp(value, "input")) { - auto_crlf = AUTO_CRLF_INPUT; - return 0; - } - auto_crlf = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.safecrlf")) { - int eol_rndtrp_die; - if (value && !strcasecmp(value, "warn")) { - global_conv_flags_eol = CONV_EOL_RNDTRP_WARN; - return 0; - } - eol_rndtrp_die = git_config_bool(var, value); - global_conv_flags_eol = eol_rndtrp_die ? - CONV_EOL_RNDTRP_DIE : 0; - return 0; - } - - if (!strcmp(var, "core.eol")) { - if (value && !strcasecmp(value, "lf")) - core_eol = EOL_LF; - else if (value && !strcasecmp(value, "crlf")) - core_eol = EOL_CRLF; - else if (value && !strcasecmp(value, "native")) - core_eol = EOL_NATIVE; - else - core_eol = EOL_UNSET; - return 0; - } - - if (!strcmp(var, "core.checkroundtripencoding")) { - FREE_AND_NULL(check_roundtrip_encoding); - return git_config_string(&check_roundtrip_encoding, var, value); - } - - if (!strcmp(var, "core.editor")) { - FREE_AND_NULL(editor_program); - return git_config_string(&editor_program, var, value); - } - - if (!strcmp(var, "core.commentchar") || - !strcmp(var, "core.commentstring")) { - if (!value) - return config_error_nonbool(var); - else if (!strcasecmp(value, "auto")) - auto_comment_line_char = 1; - 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); - auto_comment_line_char = 0; - } else - return error(_("%s must have at least one character"), var); - return 0; - } - - if (!strcmp(var, "core.askpass")) { - FREE_AND_NULL(askpass_program); - return git_config_string(&askpass_program, var, value); - } - - if (!strcmp(var, "core.excludesfile")) { - FREE_AND_NULL(excludes_file); - return git_config_pathname(&excludes_file, var, value); - } - - if (!strcmp(var, "core.whitespace")) { - if (!value) - return config_error_nonbool(var); - whitespace_rule_cfg = parse_whitespace_rule(value); - return 0; - } - - if (!strcmp(var, "core.fsync")) { - if (!value) - return config_error_nonbool(var); - fsync_components = parse_fsync_components(var, value); - return 0; - } - - if (!strcmp(var, "core.fsyncmethod")) { - if (!value) - return config_error_nonbool(var); - if (!strcmp(value, "fsync")) - fsync_method = FSYNC_METHOD_FSYNC; - else if (!strcmp(value, "writeout-only")) - fsync_method = FSYNC_METHOD_WRITEOUT_ONLY; - else if (!strcmp(value, "batch")) - fsync_method = FSYNC_METHOD_BATCH; - else - warning(_("ignoring unknown core.fsyncMethod value '%s'"), value); - - } - - if (!strcmp(var, "core.fsyncobjectfiles")) { - if (fsync_object_files < 0) - warning(_("core.fsyncObjectFiles is deprecated; use core.fsync instead")); - fsync_object_files = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.createobject")) { - if (!value) - return config_error_nonbool(var); - if (!strcmp(value, "rename")) - object_creation_mode = OBJECT_CREATION_USES_RENAMES; - else if (!strcmp(value, "link")) - object_creation_mode = OBJECT_CREATION_USES_HARDLINKS; - else - die(_("invalid mode for object creation: %s"), value); - return 0; - } - - if (!strcmp(var, "core.sparsecheckout")) { - core_apply_sparse_checkout = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.sparsecheckoutcone")) { - core_sparse_checkout_cone = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.precomposeunicode")) { - precomposed_unicode = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.protecthfs")) { - protect_hfs = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.protectntfs")) { - protect_ntfs = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "core.maxtreedepth")) { - max_allowed_tree_depth = git_config_int(var, value, ctx->kvi); - return 0; - } - - /* Add other config variables here and to Documentation/config.adoc. */ - return platform_core_config(var, value, ctx, cb); -} - -static int git_default_sparse_config(const char *var, const char *value) -{ - if (!strcmp(var, "sparse.expectfilesoutsideofpatterns")) { - sparse_expect_files_outside_of_patterns = git_config_bool(var, value); - return 0; - } - - /* Add other config variables here and to Documentation/config/sparse.adoc. */ - return 0; -} - -static int git_default_i18n_config(const char *var, const char *value) -{ - if (!strcmp(var, "i18n.commitencoding")) { - FREE_AND_NULL(git_commit_encoding); - return git_config_string(&git_commit_encoding, var, value); - } - - if (!strcmp(var, "i18n.logoutputencoding")) { - FREE_AND_NULL(git_log_output_encoding); - return git_config_string(&git_log_output_encoding, var, value); - } - - /* Add other config variables here and to Documentation/config.adoc. */ - return 0; -} - -static int git_default_branch_config(const char *var, const char *value) -{ - if (!strcmp(var, "branch.autosetupmerge")) { - if (value && !strcmp(value, "always")) { - git_branch_track = BRANCH_TRACK_ALWAYS; - return 0; - } else if (value && !strcmp(value, "inherit")) { - git_branch_track = BRANCH_TRACK_INHERIT; - return 0; - } else if (value && !strcmp(value, "simple")) { - git_branch_track = BRANCH_TRACK_SIMPLE; - return 0; - } - git_branch_track = git_config_bool(var, value); - return 0; - } - if (!strcmp(var, "branch.autosetuprebase")) { - if (!value) - return config_error_nonbool(var); - else if (!strcmp(value, "never")) - autorebase = AUTOREBASE_NEVER; - else if (!strcmp(value, "local")) - autorebase = AUTOREBASE_LOCAL; - else if (!strcmp(value, "remote")) - autorebase = AUTOREBASE_REMOTE; - else if (!strcmp(value, "always")) - autorebase = AUTOREBASE_ALWAYS; - else - return error(_("malformed value for %s"), var); - return 0; - } - - /* Add other config variables here and to Documentation/config.adoc. */ - return 0; -} - -static int git_default_push_config(const char *var, const char *value) -{ - if (!strcmp(var, "push.default")) { - if (!value) - return config_error_nonbool(var); - else if (!strcmp(value, "nothing")) - push_default = PUSH_DEFAULT_NOTHING; - else if (!strcmp(value, "matching")) - push_default = PUSH_DEFAULT_MATCHING; - else if (!strcmp(value, "simple")) - push_default = PUSH_DEFAULT_SIMPLE; - else if (!strcmp(value, "upstream")) - push_default = PUSH_DEFAULT_UPSTREAM; - else if (!strcmp(value, "tracking")) /* deprecated */ - push_default = PUSH_DEFAULT_UPSTREAM; - else if (!strcmp(value, "current")) - push_default = PUSH_DEFAULT_CURRENT; - else { - error(_("malformed value for %s: %s"), var, value); - return error(_("must be one of nothing, matching, simple, " - "upstream or current")); - } - return 0; - } - - /* Add other config variables here and to Documentation/config.adoc. */ - return 0; -} - -static int git_default_mailmap_config(const char *var, const char *value) -{ - if (!strcmp(var, "mailmap.file")) { - FREE_AND_NULL(git_mailmap_file); - return git_config_pathname(&git_mailmap_file, var, value); - } - - if (!strcmp(var, "mailmap.blob")) { - FREE_AND_NULL(git_mailmap_blob); - return git_config_string(&git_mailmap_blob, var, value); - } - - /* Add other config variables here and to Documentation/config.adoc. */ - return 0; -} - -static int git_default_attr_config(const char *var, const char *value) -{ - if (!strcmp(var, "attr.tree")) { - FREE_AND_NULL(git_attr_tree); - return git_config_string(&git_attr_tree, var, value); - } - - /* - * Add other attribute related config variables here and to - * Documentation/config/attr.adoc. - */ - return 0; -} - -int git_default_config(const char *var, const char *value, - const struct config_context *ctx, void *cb) -{ - if (starts_with(var, "core.")) - return git_default_core_config(var, value, ctx, cb); - - if (starts_with(var, "user.") || - starts_with(var, "author.") || - starts_with(var, "committer.")) - return git_ident_config(var, value, ctx, cb); - - if (starts_with(var, "i18n.")) - return git_default_i18n_config(var, value); - - if (starts_with(var, "branch.")) - return git_default_branch_config(var, value); - - if (starts_with(var, "push.")) - return git_default_push_config(var, value); - - if (starts_with(var, "mailmap.")) - return git_default_mailmap_config(var, value); - - if (starts_with(var, "attr.")) - return git_default_attr_config(var, value); - - if (starts_with(var, "advice.") || starts_with(var, "color.advice")) - return git_default_advice_config(var, value); - - if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) { - pager_use_color = git_config_bool(var,value); - return 0; - } - - if (!strcmp(var, "pack.packsizelimit")) { - pack_size_limit_cfg = git_config_ulong(var, value, ctx->kvi); - return 0; - } - - if (!strcmp(var, "pack.compression")) { - int level = git_config_int(var, value, ctx->kvi); - if (level == -1) - level = Z_DEFAULT_COMPRESSION; - else if (level < 0 || level > Z_BEST_COMPRESSION) - die(_("bad pack compression level %d"), level); - pack_compression_level = level; - pack_compression_seen = 1; - return 0; - } - - if (starts_with(var, "sparse.")) - return git_default_sparse_config(var, value); - - /* Add other config variables here and to Documentation/config.adoc. */ - return 0; -} - /* * All source specific fields in the union, die_on_error, name and the callbacks * fgetc, ungetc, ftell of top need to be initialized before calling @@ -1850,17 +1336,19 @@ static int do_config_from(struct config_source *top, config_fn_t fn, static int do_config_from_file(config_fn_t fn, const enum config_origin_type origin_type, - const char *name, const char *path, FILE *f, - void *data, enum config_scope scope, + const char *name, FILE *f, void *data, + enum config_scope scope, const struct config_options *opts) { struct config_source top = CONFIG_SOURCE_INIT; int ret; + if (origin_type == CONFIG_ORIGIN_FILE && (!name || !*name)) + BUG("missing filename for CONFIG_ORIGIN_FILE"); + top.u.file = f; top.origin_type = origin_type; top.name = name; - top.path = path; top.default_error_action = CONFIG_ERROR_DIE; top.do_fgetc = config_file_fgetc; top.do_ungetc = config_file_ungetc; @@ -1875,8 +1363,8 @@ static int do_config_from_file(config_fn_t fn, static int git_config_from_stdin(config_fn_t fn, void *data, enum config_scope scope) { - return do_config_from_file(fn, CONFIG_ORIGIN_STDIN, "", NULL, stdin, - data, scope, NULL); + return do_config_from_file(fn, CONFIG_ORIGIN_STDIN, "", stdin, data, + scope, NULL); } int git_config_from_file_with_options(config_fn_t fn, const char *filename, @@ -1891,7 +1379,7 @@ int git_config_from_file_with_options(config_fn_t fn, const char *filename, f = fopen_or_warn(filename, "r"); if (f) { ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename, - filename, f, data, scope, opts); + f, data, scope, opts); fclose(f); } return ret; @@ -1916,7 +1404,6 @@ int git_config_from_mem(config_fn_t fn, top.u.buf.pos = 0; top.origin_type = origin_type; top.name = name; - top.path = NULL; top.default_error_action = CONFIG_ERROR_ERROR; top.do_fgetc = config_buf_fgetc; top.do_ungetc = config_buf_ungetc; @@ -2125,13 +1612,13 @@ int config_with_options(config_fn_t fn, void *data, static void configset_iter(struct config_set *set, config_fn_t fn, void *data) { - int i, value_index; + int value_index; struct string_list *values; struct config_set_element *entry; struct configset_list *list = &set->list; struct config_context ctx = CONFIG_CONTEXT_INIT; - for (i = 0; i < list->nr; i++) { + for (size_t i = 0; i < list->nr; i++) { entry = list->items[i].e; value_index = list->items[i].value_index; values = &entry->value_list; @@ -2748,7 +2235,7 @@ void git_die_config(struct repository *r, const char *key, const char *err, ...) } /* - * Find all the stuff for git_config_set() below. + * Find all the stuff for repo_config_set() below. */ struct config_store_data { @@ -2981,10 +2468,11 @@ static ssize_t write_pair(int fd, const char *key, const char *value, */ static void maybe_remove_section(struct config_store_data *store, size_t *begin_offset, size_t *end_offset, - int *seen_ptr) + unsigned *seen_ptr) { size_t begin; - int i, seen, section_seen = 0; + int section_seen = 0; + unsigned int i, seen; /* * First, ensure that this is the first key, and that there are no @@ -3227,7 +2715,8 @@ int repo_config_set_multivar_in_file_gently(struct repository *r, } else { struct stat st; size_t copy_begin, copy_end; - int i, new_line = 0; + unsigned i; + int new_line = 0; struct config_options opts; if (!value_pattern) @@ -122,14 +122,12 @@ struct key_value_info { int linenr; enum config_origin_type origin_type; enum config_scope scope; - const char *path; }; #define KVI_INIT { \ .filename = NULL, \ .linenr = -1, \ .origin_type = CONFIG_ORIGIN_UNKNOWN, \ .scope = CONFIG_SCOPE_UNKNOWN, \ - .path = NULL, \ } /* Captures additional information that a config callback can use. */ @@ -165,9 +163,6 @@ struct config_context { typedef int (*config_fn_t)(const char *, const char *, const struct config_context *, void *); -int git_default_config(const char *, const char *, - const struct config_context *, void *); - /** * Read a specific file in git-config format. * This function takes the same callback and data parameters as `repo_config`. @@ -718,140 +713,4 @@ NORETURN void git_die_config_linenr(const char *key, const char *filename, int l lookup_config(mapping, ARRAY_SIZE(mapping), var) int lookup_config(const char **mapping, int nr_mapping, const char *var); -# ifdef USE_THE_REPOSITORY_VARIABLE -static inline void git_config(config_fn_t fn, void *data) -{ - repo_config(the_repository, fn, data); -} - -static inline void git_config_clear(void) -{ - repo_config_clear(the_repository); -} - -static inline int git_config_get(const char *key) -{ - return repo_config_get(the_repository, key); -} - -static inline int git_config_get_value(const char *key, const char **value) -{ - return repo_config_get_value(the_repository, key, value); -} - -static inline int git_config_get_value_multi(const char *key, const struct string_list **dest) -{ - return repo_config_get_value_multi(the_repository, key, dest); -} - -static inline int git_config_get_string_multi(const char *key, - const struct string_list **dest) -{ - return repo_config_get_string_multi(the_repository, key, dest); -} - -static inline int git_config_get_string(const char *key, char **dest) -{ - return repo_config_get_string(the_repository, key, dest); -} - -static inline int git_config_get_string_tmp(const char *key, const char **dest) -{ - return repo_config_get_string_tmp(the_repository, key, dest); -} - -static inline int git_config_get_int(const char *key, int *dest) -{ - return repo_config_get_int(the_repository, key, dest); -} - -static inline int git_config_get_ulong(const char *key, unsigned long *dest) -{ - return repo_config_get_ulong(the_repository, key, dest); -} - -static inline int git_config_get_bool(const char *key, int *dest) -{ - return repo_config_get_bool(the_repository, key, dest); -} - -static inline int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest) -{ - return repo_config_get_bool_or_int(the_repository, key, is_bool, dest); -} - -static inline int git_config_get_maybe_bool(const char *key, int *dest) -{ - return repo_config_get_maybe_bool(the_repository, key, dest); -} - -static inline int git_config_get_pathname(const char *key, char **dest) -{ - return repo_config_get_pathname(the_repository, key, dest); -} - -static inline void git_config_set_in_file(const char *config_filename, - const char *key, const char *value) -{ - repo_config_set_in_file(the_repository, config_filename, key, value); -} - -static inline int git_config_set_gently(const char *key, const char *value) -{ - return repo_config_set_gently(the_repository, key, value); -} - -static inline void git_config_set(const char *key, const char *value) -{ - repo_config_set(the_repository, key, value); -} - -static inline int git_config_set_in_file_gently( - const char *config_filename, - const char *key, - const char *comment, - const char *value) -{ - return repo_config_set_in_file_gently(the_repository, config_filename, - key, comment, value); -} - -static inline int git_config_set_multivar_in_file_gently( - const char *config_filename, - const char *key, const char *value, - const char *value_pattern, - const char *comment, - unsigned flags) -{ - return repo_config_set_multivar_in_file_gently(the_repository, config_filename, - key, value, value_pattern, - comment, flags); -} - -static inline void git_config_set_multivar_in_file( - const char *config_filename, - const char *key, - const char *value, - const char *value_pattern, - unsigned flags) -{ - repo_config_set_multivar_in_file(the_repository, config_filename, - key, value, value_pattern, flags); -} - -static inline int git_config_set_multivar_gently(const char *key, const char *value, - const char *value_pattern, unsigned flags) -{ - return repo_config_set_multivar_gently(the_repository, key, value, - value_pattern, flags); -} - -static inline void git_config_set_multivar(const char *key, const char *value, - const char *value_pattern, unsigned flags) -{ - repo_config_set_multivar(the_repository, key, value, - value_pattern, flags); -} -# endif /* USE_THE_REPOSITORY_VARIABLE */ - #endif /* CONFIG_H */ diff --git a/config.mak.uname b/config.mak.uname index b1c5c4d5e8..1691c6ae6e 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -302,16 +302,13 @@ ifeq ($(uname_S),FreeBSD) ifeq ($(firstword $(subst -, ,$(uname_R))),10.1) OLD_ICONV = YesPlease endif - NO_MEMMEM = YesPlease + ifeq ($(shell v=$(uname_R) && test $${v%%.*} -lt 12 && echo 1),1) + NO_MEMMEM = UnfortunatelyYes + endif BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease USE_ST_TIMESPEC = YesPlease - ifeq ($(shell expr "$(uname_R)" : '4\.'),2) - PTHREAD_LIBS = -pthread - NO_UINTMAX_T = YesPlease - NO_STRTOUMAX = YesPlease - endif PYTHON_PATH = /usr/local/bin/python PERL_PATH = /usr/local/bin/perl HAVE_PATHS_H = YesPlease diff --git a/configure.ac b/configure.ac index f6caab919a..cfb50112bf 100644 --- a/configure.ac +++ b/configure.ac @@ -1068,32 +1068,6 @@ AC_CHECK_LIB([iconv], [locale_charset], GIT_CONF_SUBST([CHARSET_LIB]) # -# Define HAVE_SYSINFO=YesPlease if sysinfo is available. -# -AC_DEFUN([HAVE_SYSINFO_SRC], [ -AC_LANG_PROGRAM([[ -#include <stdint.h> -#include <sys/sysinfo.h> -]], [[ -struct sysinfo si; -uint64_t t = 0; -if (!sysinfo(&si)) { - t = si.totalram; - if (si.mem_unit > 1) - t *= (uint64_t)si.mem_unit; -} -return t; -]])]) - -AC_MSG_CHECKING([for sysinfo]) -AC_COMPILE_IFELSE([HAVE_SYSINFO_SRC], - [AC_MSG_RESULT([yes]) - HAVE_SYSINFO=YesPlease], - [AC_MSG_RESULT([no]) - HAVE_SYSINFO=]) -GIT_CONF_SUBST([HAVE_SYSINFO]) - -# # Define HAVE_CLOCK_GETTIME=YesPlease if clock_gettime is available. GIT_CHECK_FUNC(clock_gettime, [HAVE_CLOCK_GETTIME=YesPlease], @@ -1148,14 +1122,6 @@ GIT_CHECK_FUNC(strlcpy, [NO_STRLCPY=YesPlease]) GIT_CONF_SUBST([NO_STRLCPY]) # -# Define NO_UINTMAX_T if your platform does not have uintmax_t -AC_CHECK_TYPE(uintmax_t, -[NO_UINTMAX_T=], -[NO_UINTMAX_T=YesPlease],[ -#include <inttypes.h> -]) -GIT_CONF_SUBST([NO_UINTMAX_T]) -# # Define NO_STRTOUMAX if you don't have strtoumax in the C library. GIT_CHECK_FUNC(strtoumax, [NO_STRTOUMAX=], @@ -1221,6 +1187,41 @@ AC_COMPILE_IFELSE([BSD_SYSCTL_SRC], HAVE_BSD_SYSCTL=]) GIT_CONF_SUBST([HAVE_BSD_SYSCTL]) +# +# Define HAVE_SYSINFO=YesPlease if sysinfo is available. +# + +HAVE_SYSINFO= +# on a *BSD system, sysctl() takes precedence over the +# sysinfo() compatibility library (if installed). + +if test -z "$HAVE_BSD_SYSCTL"; then + + AC_DEFUN([HAVE_SYSINFO_SRC], [ + AC_LANG_PROGRAM([[ + #include <stdint.h> + #include <sys/sysinfo.h> + ]], [[ + struct sysinfo si; + uint64_t t = 0; + if (!sysinfo(&si)) { + t = si.totalram; + if (si.mem_unit > 1) + t *= (uint64_t)si.mem_unit; + } + return t; + ]])]) + + AC_MSG_CHECKING([for sysinfo]) + AC_COMPILE_IFELSE([HAVE_SYSINFO_SRC], + [AC_MSG_RESULT([yes]) + HAVE_SYSINFO=YesPlease], + [AC_MSG_RESULT([no]) + HAVE_SYSINFO=]) + GIT_CONF_SUBST([HAVE_SYSINFO]) + +fi + ## Other checks. # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link. # Enable it on Windows. By default, symrefs are still used. @@ -251,7 +251,7 @@ static void process_capabilities(struct packet_reader *reader, size_t *linelen) reader->hash_algo = &hash_algos[hash_algo]; free(hash_name); } else { - reader->hash_algo = &hash_algos[GIT_HASH_SHA1]; + reader->hash_algo = &hash_algos[GIT_HASH_SHA1_LEGACY]; } } @@ -500,7 +500,7 @@ static void send_capabilities(int fd_out, struct packet_reader *reader) reader->hash_algo = &hash_algos[hash_algo]; packet_write_fmt(fd_out, "object-format=%s", reader->hash_algo->name); } else { - reader->hash_algo = &hash_algos[GIT_HASH_SHA1]; + reader->hash_algo = &hash_algos[GIT_HASH_SHA1_LEGACY]; } if (server_feature_v2("promisor-remote", &promisor_remote_info)) { char *reply = promisor_remote_reply(promisor_remote_info); @@ -665,7 +665,7 @@ int server_supports_hash(const char *desired, int *feature_supported) if (feature_supported) *feature_supported = !!hash; if (!hash) { - hash = hash_algos[GIT_HASH_SHA1].name; + hash = hash_algos[GIT_HASH_SHA1_LEGACY].name; len = strlen(hash); } while (hash) { @@ -1028,7 +1028,7 @@ static int git_proxy_command_options(const char *var, const char *value, static int git_use_proxy(const char *host) { git_proxy_command = getenv("GIT_PROXY_COMMAND"); - git_config(git_proxy_command_options, (void*)host); + repo_config(the_repository, git_proxy_command_options, (void*)host); return (git_proxy_command && *git_proxy_command); } @@ -1154,7 +1154,7 @@ static const char *get_ssh_command(void) if ((ssh = getenv("GIT_SSH_COMMAND"))) return ssh; - if (!git_config_get_string_tmp("core.sshcommand", &ssh)) + if (!repo_config_get_string_tmp(the_repository, "core.sshcommand", &ssh)) return ssh; return NULL; @@ -1173,7 +1173,7 @@ static void override_ssh_variant(enum ssh_variant *ssh_variant) { const char *variant = getenv("GIT_SSH_VARIANT"); - if (!variant && git_config_get_string_tmp("ssh.variant", &variant)) + if (!variant && repo_config_get_string_tmp(the_repository, "ssh.variant", &variant)) return; if (!strcmp(variant, "auto")) diff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/contrib/coccinelle/config_fn_ctx.pending.cocci index 6d3d1000a9..54f09fcbcd 100644 --- a/contrib/coccinelle/config_fn_ctx.pending.cocci +++ b/contrib/coccinelle/config_fn_ctx.pending.cocci @@ -83,7 +83,7 @@ int fn(const char *C1, const char *C2, // The previous rules don't catch all callbacks, especially if they're defined -// in a separate file from the git_config() call. Fix these manually. +// in a separate file from the repo_config() call. Fix these manually. @@ identifier C1, C2, D; attribute name UNUSED; diff --git a/contrib/credential/netrc/git-credential-netrc.perl b/contrib/credential/netrc/git-credential-netrc.perl index 9fb998ae09..3c0a532d0e 100755 --- a/contrib/credential/netrc/git-credential-netrc.perl +++ b/contrib/credential/netrc/git-credential-netrc.perl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl use strict; use warnings; @@ -267,8 +267,16 @@ sub load_netrc { if (!defined $nentry->{machine}) { next; } - if (defined $nentry->{port} && $nentry->{port} =~ m/^\d+$/) { - $num_port = $nentry->{port}; + if (defined $nentry->{port}) { + $num_port = Git::port_num($nentry->{port}); + unless ($num_port) { + printf(STDERR "ignoring invalid port `%s' " . + "from netrc file\n", $nentry->{port}); + } + # Since we've already validated and converted + # the port to its numerical value, do not + # capture it as the `protocol' value, as used + # to be the case for symbolic port names. delete $nentry->{port}; } diff --git a/contrib/credential/netrc/test.pl b/contrib/credential/netrc/test.pl index 67a0ede564..8a7fc2588a 100755 --- a/contrib/credential/netrc/test.pl +++ b/contrib/credential/netrc/test.pl @@ -45,7 +45,7 @@ chmod 0600, $netrc; diag "Testing with invalid data\n"; $cred = run_credential(['-f', $netrc, 'get'], "bad data"); -ok(scalar keys %$cred == 4, "Got first found keys with bad data"); +ok(scalar keys %$cred == 3, "Got first found keys with bad data"); diag "Testing netrc file for a missing corovamilkbar entry\n"; $cred = run_credential(['-f', $netrc, 'get'], @@ -64,12 +64,12 @@ is($cred->{username}, 'carol', "Got correct Github username"); diag "Testing netrc file for a username-specific entry\n"; $cred = run_credential(['-f', $netrc, 'get'], - { host => 'imap', username => 'bob' }); + { host => 'imap:993', username => 'bob' }); -ok(scalar keys %$cred == 2, "Got 2 username-specific keys"); +# Only the password field gets returned. +ok(scalar keys %$cred == 1, "Got 1 username-specific keys"); is($cred->{password}, 'bobwillknow', "Got correct user-specific password"); -is($cred->{protocol}, 'imaps', "Got correct user-specific protocol"); diag "Testing netrc file for a host:port-specific entry\n"; $cred = run_credential(['-f', $netrc, 'get'], @@ -1326,7 +1326,7 @@ void convert_attrs(struct index_state *istate, "eol", "text", "working-tree-encoding", NULL); user_convert_tail = &user_convert; - git_config(read_convert_config, NULL); + repo_config(the_repository, read_convert_config, NULL); } git_check_attr(istate, path, check); @@ -402,7 +402,7 @@ static int run_service(const char *dir, struct daemon_service *service, if (service->overridable) { strbuf_addf(&var, "daemon.%s", service->config_name); - git_config_get_bool(var.buf, &enabled); + repo_config_get_bool(the_repository, var.buf, &enabled); strbuf_release(&var); } if (!enabled) { @@ -915,11 +915,9 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen) static void child_handler(int signo UNUSED) { /* - * Otherwise empty handler because systemcalls will get interrupted - * upon signal receipt - * SysV needs the handler to be rearmed + * Otherwise empty handler because systemcalls should get interrupted + * upon signal receipt. */ - signal(SIGCHLD, child_handler); } static int set_reuse_addr(int sockfd) @@ -1115,6 +1113,7 @@ static void socksetup(struct string_list *listen_addr, int listen_port, struct s static int service_loop(struct socketlist *socklist) { + struct sigaction sa; struct pollfd *pfd; CALLOC_ARRAY(pfd, socklist->nr); @@ -1124,7 +1123,10 @@ static int service_loop(struct socketlist *socklist) pfd[i].events = POLLIN; } - signal(SIGCHLD, child_handler); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = child_handler; + sigaction(SIGCHLD, &sa, NULL); for (;;) { check_dead_children(); @@ -4091,8 +4091,8 @@ void connect_work_tree_and_git_dir(const char *work_tree_, write_file(gitfile_sb.buf, "gitdir: %s", relative_path(git_dir, work_tree, &rel_path)); /* Update core.worktree setting */ - git_config_set_in_file(cfg_sb.buf, "core.worktree", - relative_path(work_tree, git_dir, &rel_path)); + repo_config_set_in_file(the_repository, cfg_sb.buf, "core.worktree", + relative_path(work_tree, git_dir, &rel_path)); strbuf_release(&gitfile_sb); strbuf_release(&cfg_sb); @@ -50,7 +50,7 @@ const char *git_sequence_editor(void) const char *editor = getenv("GIT_SEQUENCE_EDITOR"); if (!editor) - git_config_get_string_tmp("sequence.editor", &editor); + repo_config_get_string_tmp(the_repository, "sequence.editor", &editor); if (!editor) editor = git_editor(); diff --git a/environment.c b/environment.c index 7bf0390a33..ae1427bb9e 100644 --- a/environment.c +++ b/environment.c @@ -12,22 +12,34 @@ #include "git-compat-util.h" #include "abspath.h" +#include "advice.h" +#include "attr.h" #include "branch.h" +#include "color.h" #include "convert.h" #include "environment.h" #include "gettext.h" #include "git-zlib.h" +#include "ident.h" +#include "mailmap.h" +#include "object-name.h" #include "repository.h" #include "config.h" #include "refs.h" #include "fmt-merge-msg.h" #include "commit.h" #include "strvec.h" +#include "pager.h" #include "path.h" +#include "quote.h" #include "chdir-notify.h" #include "setup.h" +#include "ws.h" #include "write-or-die.h" +static int pack_compression_seen; +static int zlib_compression_seen; + int trust_executable_bit = 1; int trust_ctime = 1; int check_stat = 1; @@ -37,7 +49,6 @@ int ignore_case; int assume_unchanged; int is_bare_repository_cfg = -1; /* unspecified */ int warn_on_object_refname_ambiguity = 1; -int repository_format_precious_objects; char *git_commit_encoding; char *git_log_output_encoding; char *apply_default_whitespace; @@ -232,3 +243,503 @@ int print_sha1_ellipsis(void) } return cached_result; } + +static const struct fsync_component_name { + const char *name; + enum fsync_component component_bits; +} fsync_component_names[] = { + { "loose-object", FSYNC_COMPONENT_LOOSE_OBJECT }, + { "pack", FSYNC_COMPONENT_PACK }, + { "pack-metadata", FSYNC_COMPONENT_PACK_METADATA }, + { "commit-graph", FSYNC_COMPONENT_COMMIT_GRAPH }, + { "index", FSYNC_COMPONENT_INDEX }, + { "objects", FSYNC_COMPONENTS_OBJECTS }, + { "reference", FSYNC_COMPONENT_REFERENCE }, + { "derived-metadata", FSYNC_COMPONENTS_DERIVED_METADATA }, + { "committed", FSYNC_COMPONENTS_COMMITTED }, + { "added", FSYNC_COMPONENTS_ADDED }, + { "all", FSYNC_COMPONENTS_ALL }, +}; + +static enum fsync_component parse_fsync_components(const char *var, const char *string) +{ + enum fsync_component current = FSYNC_COMPONENTS_PLATFORM_DEFAULT; + enum fsync_component positive = 0, negative = 0; + + while (string) { + size_t len; + const char *ep; + int negated = 0; + int found = 0; + + string = string + strspn(string, ", \t\n\r"); + ep = strchrnul(string, ','); + len = ep - string; + if (!strcmp(string, "none")) { + current = FSYNC_COMPONENT_NONE; + goto next_name; + } + + if (*string == '-') { + negated = 1; + string++; + len--; + if (!len) + warning(_("invalid value for variable %s"), var); + } + + if (!len) + break; + + for (size_t i = 0; i < ARRAY_SIZE(fsync_component_names); ++i) { + const struct fsync_component_name *n = &fsync_component_names[i]; + + if (strncmp(n->name, string, len)) + continue; + + found = 1; + if (negated) + negative |= n->component_bits; + else + positive |= n->component_bits; + } + + if (!found) { + char *component = xstrndup(string, len); + warning(_("ignoring unknown core.fsync component '%s'"), component); + free(component); + } + +next_name: + string = ep; + } + + return (current & ~negative) | positive; +} + +static int git_default_core_config(const char *var, const char *value, + const struct config_context *ctx, void *cb) +{ + /* This needs a better name */ + if (!strcmp(var, "core.filemode")) { + trust_executable_bit = git_config_bool(var, value); + return 0; + } + if (!strcmp(var, "core.trustctime")) { + trust_ctime = git_config_bool(var, value); + return 0; + } + if (!strcmp(var, "core.checkstat")) { + if (!value) + return config_error_nonbool(var); + if (!strcasecmp(value, "default")) + check_stat = 1; + else if (!strcasecmp(value, "minimal")) + check_stat = 0; + else + return error(_("invalid value for '%s': '%s'"), + var, value); + } + + if (!strcmp(var, "core.quotepath")) { + quote_path_fully = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.symlinks")) { + has_symlinks = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.ignorecase")) { + ignore_case = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.attributesfile")) { + FREE_AND_NULL(git_attributes_file); + return git_config_pathname(&git_attributes_file, var, value); + } + + if (!strcmp(var, "core.bare")) { + is_bare_repository_cfg = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.ignorestat")) { + assume_unchanged = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.abbrev")) { + if (!value) + return config_error_nonbool(var); + if (!strcasecmp(value, "auto")) + default_abbrev = -1; + else if (!git_parse_maybe_bool_text(value)) + default_abbrev = GIT_MAX_HEXSZ; + else { + int abbrev = git_config_int(var, value, ctx->kvi); + if (abbrev < minimum_abbrev) + return error(_("abbrev length out of range: %d"), abbrev); + default_abbrev = abbrev; + } + return 0; + } + + if (!strcmp(var, "core.disambiguate")) + return set_disambiguate_hint_config(var, value); + + if (!strcmp(var, "core.loosecompression")) { + int level = git_config_int(var, value, ctx->kvi); + if (level == -1) + level = Z_DEFAULT_COMPRESSION; + else if (level < 0 || level > Z_BEST_COMPRESSION) + die(_("bad zlib compression level %d"), level); + zlib_compression_level = level; + zlib_compression_seen = 1; + return 0; + } + + if (!strcmp(var, "core.compression")) { + int level = git_config_int(var, value, ctx->kvi); + if (level == -1) + level = Z_DEFAULT_COMPRESSION; + else if (level < 0 || level > Z_BEST_COMPRESSION) + die(_("bad zlib compression level %d"), level); + if (!zlib_compression_seen) + zlib_compression_level = level; + if (!pack_compression_seen) + pack_compression_level = level; + return 0; + } + + if (!strcmp(var, "core.autocrlf")) { + if (value && !strcasecmp(value, "input")) { + auto_crlf = AUTO_CRLF_INPUT; + return 0; + } + auto_crlf = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.safecrlf")) { + int eol_rndtrp_die; + if (value && !strcasecmp(value, "warn")) { + global_conv_flags_eol = CONV_EOL_RNDTRP_WARN; + return 0; + } + eol_rndtrp_die = git_config_bool(var, value); + global_conv_flags_eol = eol_rndtrp_die ? + CONV_EOL_RNDTRP_DIE : 0; + return 0; + } + + if (!strcmp(var, "core.eol")) { + if (value && !strcasecmp(value, "lf")) + core_eol = EOL_LF; + else if (value && !strcasecmp(value, "crlf")) + core_eol = EOL_CRLF; + else if (value && !strcasecmp(value, "native")) + core_eol = EOL_NATIVE; + else + core_eol = EOL_UNSET; + return 0; + } + + if (!strcmp(var, "core.checkroundtripencoding")) { + FREE_AND_NULL(check_roundtrip_encoding); + return git_config_string(&check_roundtrip_encoding, var, value); + } + + if (!strcmp(var, "core.editor")) { + FREE_AND_NULL(editor_program); + return git_config_string(&editor_program, var, value); + } + + if (!strcmp(var, "core.commentchar") || + !strcmp(var, "core.commentstring")) { + if (!value) + return config_error_nonbool(var); + else if (!strcasecmp(value, "auto")) + auto_comment_line_char = 1; + 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); + auto_comment_line_char = 0; + } else + return error(_("%s must have at least one character"), var); + return 0; + } + + if (!strcmp(var, "core.askpass")) { + FREE_AND_NULL(askpass_program); + return git_config_string(&askpass_program, var, value); + } + + if (!strcmp(var, "core.excludesfile")) { + FREE_AND_NULL(excludes_file); + return git_config_pathname(&excludes_file, var, value); + } + + if (!strcmp(var, "core.whitespace")) { + if (!value) + return config_error_nonbool(var); + whitespace_rule_cfg = parse_whitespace_rule(value); + return 0; + } + + if (!strcmp(var, "core.fsync")) { + if (!value) + return config_error_nonbool(var); + fsync_components = parse_fsync_components(var, value); + return 0; + } + + if (!strcmp(var, "core.fsyncmethod")) { + if (!value) + return config_error_nonbool(var); + if (!strcmp(value, "fsync")) + fsync_method = FSYNC_METHOD_FSYNC; + else if (!strcmp(value, "writeout-only")) + fsync_method = FSYNC_METHOD_WRITEOUT_ONLY; + else if (!strcmp(value, "batch")) + fsync_method = FSYNC_METHOD_BATCH; + else + warning(_("ignoring unknown core.fsyncMethod value '%s'"), value); + + } + + if (!strcmp(var, "core.fsyncobjectfiles")) { + if (fsync_object_files < 0) + warning(_("core.fsyncObjectFiles is deprecated; use core.fsync instead")); + fsync_object_files = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.createobject")) { + if (!value) + return config_error_nonbool(var); + if (!strcmp(value, "rename")) + object_creation_mode = OBJECT_CREATION_USES_RENAMES; + else if (!strcmp(value, "link")) + object_creation_mode = OBJECT_CREATION_USES_HARDLINKS; + else + die(_("invalid mode for object creation: %s"), value); + return 0; + } + + if (!strcmp(var, "core.sparsecheckout")) { + core_apply_sparse_checkout = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.sparsecheckoutcone")) { + core_sparse_checkout_cone = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.precomposeunicode")) { + precomposed_unicode = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.protecthfs")) { + protect_hfs = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.protectntfs")) { + protect_ntfs = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "core.maxtreedepth")) { + max_allowed_tree_depth = git_config_int(var, value, ctx->kvi); + return 0; + } + + /* Add other config variables here and to Documentation/config.adoc. */ + return platform_core_config(var, value, ctx, cb); +} + +static int git_default_sparse_config(const char *var, const char *value) +{ + if (!strcmp(var, "sparse.expectfilesoutsideofpatterns")) { + sparse_expect_files_outside_of_patterns = git_config_bool(var, value); + return 0; + } + + /* Add other config variables here and to Documentation/config/sparse.adoc. */ + return 0; +} + +static int git_default_i18n_config(const char *var, const char *value) +{ + if (!strcmp(var, "i18n.commitencoding")) { + FREE_AND_NULL(git_commit_encoding); + return git_config_string(&git_commit_encoding, var, value); + } + + if (!strcmp(var, "i18n.logoutputencoding")) { + FREE_AND_NULL(git_log_output_encoding); + return git_config_string(&git_log_output_encoding, var, value); + } + + /* Add other config variables here and to Documentation/config.adoc. */ + return 0; +} + +static int git_default_branch_config(const char *var, const char *value) +{ + if (!strcmp(var, "branch.autosetupmerge")) { + if (value && !strcmp(value, "always")) { + git_branch_track = BRANCH_TRACK_ALWAYS; + return 0; + } else if (value && !strcmp(value, "inherit")) { + git_branch_track = BRANCH_TRACK_INHERIT; + return 0; + } else if (value && !strcmp(value, "simple")) { + git_branch_track = BRANCH_TRACK_SIMPLE; + return 0; + } + git_branch_track = git_config_bool(var, value); + return 0; + } + if (!strcmp(var, "branch.autosetuprebase")) { + if (!value) + return config_error_nonbool(var); + else if (!strcmp(value, "never")) + autorebase = AUTOREBASE_NEVER; + else if (!strcmp(value, "local")) + autorebase = AUTOREBASE_LOCAL; + else if (!strcmp(value, "remote")) + autorebase = AUTOREBASE_REMOTE; + else if (!strcmp(value, "always")) + autorebase = AUTOREBASE_ALWAYS; + else + return error(_("malformed value for %s"), var); + return 0; + } + + /* Add other config variables here and to Documentation/config.adoc. */ + return 0; +} + +static int git_default_push_config(const char *var, const char *value) +{ + if (!strcmp(var, "push.default")) { + if (!value) + return config_error_nonbool(var); + else if (!strcmp(value, "nothing")) + push_default = PUSH_DEFAULT_NOTHING; + else if (!strcmp(value, "matching")) + push_default = PUSH_DEFAULT_MATCHING; + else if (!strcmp(value, "simple")) + push_default = PUSH_DEFAULT_SIMPLE; + else if (!strcmp(value, "upstream")) + push_default = PUSH_DEFAULT_UPSTREAM; + else if (!strcmp(value, "tracking")) /* deprecated */ + push_default = PUSH_DEFAULT_UPSTREAM; + else if (!strcmp(value, "current")) + push_default = PUSH_DEFAULT_CURRENT; + else { + error(_("malformed value for %s: %s"), var, value); + return error(_("must be one of nothing, matching, simple, " + "upstream or current")); + } + return 0; + } + + /* Add other config variables here and to Documentation/config.adoc. */ + return 0; +} + +static int git_default_mailmap_config(const char *var, const char *value) +{ + if (!strcmp(var, "mailmap.file")) { + FREE_AND_NULL(git_mailmap_file); + return git_config_pathname(&git_mailmap_file, var, value); + } + + if (!strcmp(var, "mailmap.blob")) { + FREE_AND_NULL(git_mailmap_blob); + return git_config_string(&git_mailmap_blob, var, value); + } + + /* Add other config variables here and to Documentation/config.adoc. */ + return 0; +} + +static int git_default_attr_config(const char *var, const char *value) +{ + if (!strcmp(var, "attr.tree")) { + FREE_AND_NULL(git_attr_tree); + return git_config_string(&git_attr_tree, var, value); + } + + /* + * Add other attribute related config variables here and to + * Documentation/config/attr.adoc. + */ + return 0; +} + +int git_default_config(const char *var, const char *value, + const struct config_context *ctx, void *cb) +{ + if (starts_with(var, "core.")) + return git_default_core_config(var, value, ctx, cb); + + if (starts_with(var, "user.") || + starts_with(var, "author.") || + starts_with(var, "committer.")) + return git_ident_config(var, value, ctx, cb); + + if (starts_with(var, "i18n.")) + return git_default_i18n_config(var, value); + + if (starts_with(var, "branch.")) + return git_default_branch_config(var, value); + + if (starts_with(var, "push.")) + return git_default_push_config(var, value); + + if (starts_with(var, "mailmap.")) + return git_default_mailmap_config(var, value); + + if (starts_with(var, "attr.")) + return git_default_attr_config(var, value); + + if (starts_with(var, "advice.") || starts_with(var, "color.advice")) + return git_default_advice_config(var, value); + + if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) { + pager_use_color = git_config_bool(var,value); + return 0; + } + + if (!strcmp(var, "pack.packsizelimit")) { + pack_size_limit_cfg = git_config_ulong(var, value, ctx->kvi); + return 0; + } + + if (!strcmp(var, "pack.compression")) { + int level = git_config_int(var, value, ctx->kvi); + if (level == -1) + level = Z_DEFAULT_COMPRESSION; + else if (level < 0 || level > Z_BEST_COMPRESSION) + die(_("bad pack compression level %d"), level); + pack_compression_level = level; + pack_compression_seen = 1; + return 0; + } + + if (starts_with(var, "sparse.")) + return git_default_sparse_config(var, value); + + /* Add other config variables here and to Documentation/config.adoc. */ + return 0; +} diff --git a/environment.h b/environment.h index 9a3d05d414..8cfce41015 100644 --- a/environment.h +++ b/environment.h @@ -104,6 +104,9 @@ int use_optional_locks(void); const char *get_git_namespace(void); const char *strip_namespace(const char *namespaced_ref); +int git_default_config(const char *, const char *, + const struct config_context *, void *); + /* * TODO: All the below state either explicitly or implicitly relies on * `the_repository`. We should eventually get rid of these and make the @@ -189,8 +192,6 @@ extern enum object_creation_mode object_creation_mode; extern int grafts_keep_true_parents; -extern int repository_format_precious_objects; - const char *get_log_output_encoding(void); const char *get_commit_output_encoding(void); diff --git a/fetch-pack.c b/fetch-pack.c index 5e74235fc0..46c39f85c4 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -34,6 +34,7 @@ #include "commit-graph.h" #include "sigchain.h" #include "mergesort.h" +#include "prio-queue.h" static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; @@ -601,7 +602,7 @@ done: return count ? retval : 0; } -static struct commit_list *complete; +static struct prio_queue complete = { compare_commits_by_commit_date }; static int mark_complete(const struct object_id *oid) { @@ -609,7 +610,7 @@ static int mark_complete(const struct object_id *oid) if (commit && !(commit->object.flags & COMPLETE)) { commit->object.flags |= COMPLETE; - commit_list_insert(commit, &complete); + prio_queue_put(&complete, commit); } return 0; } @@ -626,9 +627,12 @@ static int mark_complete_oid(const char *refname UNUSED, static void mark_recent_complete_commits(struct fetch_pack_args *args, timestamp_t cutoff) { - while (complete && cutoff <= complete->item->date) { + while (complete.nr) { + struct commit *item = prio_queue_peek(&complete); + if (item->date < cutoff) + break; print_verbose(args, _("Marking %s as complete"), - oid_to_hex(&complete->item->object.oid)); + oid_to_hex(&item->object.oid)); pop_most_recent_commit(&complete, COMPLETE); } } @@ -798,7 +802,6 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator, refs_for_each_rawref(get_main_ref_store(the_repository), mark_complete_oid, NULL); for_each_cached_alternate(NULL, mark_alternate_complete); - commit_list_sort_by_date(&complete); if (cutoff) mark_recent_complete_commits(args, cutoff); } @@ -1343,7 +1346,7 @@ static void write_fetch_command_and_capabilities(struct strbuf *req_buf, die(_("mismatched algorithms: client %s; server %s"), the_hash_algo->name, hash_name); packet_buf_write(req_buf, "object-format=%s", the_hash_algo->name); - } else if (hash_algo_by_ptr(the_hash_algo) != GIT_HASH_SHA1) { + } else if (hash_algo_by_ptr(the_hash_algo) != GIT_HASH_SHA1_LEGACY) { die(_("the server does not support algorithm '%s'"), the_hash_algo->name); } @@ -1901,22 +1904,22 @@ static int fetch_pack_config_cb(const char *var, const char *value, static void fetch_pack_config(void) { - git_config_get_int("fetch.unpacklimit", &fetch_unpack_limit); - git_config_get_int("transfer.unpacklimit", &transfer_unpack_limit); - git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta); - git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects); - git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects); - git_config_get_bool("transfer.advertisesid", &advertise_sid); + repo_config_get_int(the_repository, "fetch.unpacklimit", &fetch_unpack_limit); + repo_config_get_int(the_repository, "transfer.unpacklimit", &transfer_unpack_limit); + repo_config_get_bool(the_repository, "repack.usedeltabaseoffset", &prefer_ofs_delta); + repo_config_get_bool(the_repository, "fetch.fsckobjects", &fetch_fsck_objects); + repo_config_get_bool(the_repository, "transfer.fsckobjects", &transfer_fsck_objects); + repo_config_get_bool(the_repository, "transfer.advertisesid", &advertise_sid); if (!uri_protocols.nr) { char *str; - if (!git_config_get_string("fetch.uriprotocols", &str) && str) { + if (!repo_config_get_string(the_repository, "fetch.uriprotocols", &str) && str) { string_list_split(&uri_protocols, str, ',', -1); free(str); } } - git_config(fetch_pack_config_cb, NULL); + repo_config(the_repository, fetch_pack_config_cb, NULL); } static void fetch_pack_setup(void) @@ -3,6 +3,7 @@ #include "git-compat-util.h" #include "date.h" #include "dir.h" +#include "environment.h" #include "hex.h" #include "odb.h" #include "path.h" @@ -287,7 +287,7 @@ const char *fsck_describe_object(struct fsck_options *options, struct key_value_info; /* - * git_config() callback for use by fsck-y tools that want to support + * repo_config() callback for use by fsck-y tools that want to support * fsck.<msg> fsck.skipList etc. */ int git_fsck_config(const char *var, const char *value, diff --git a/fsmonitor.c b/fsmonitor.c index 98b2b476f0..d07dc18967 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -43,7 +43,7 @@ static int fsmonitor_hook_version(void) { int hook_version; - if (git_config_get_int("core.fsmonitorhookversion", &hook_version)) + if (repo_config_get_int(the_repository, "core.fsmonitorhookversion", &hook_version)) return -1; if (hook_version == HOOK_INTERFACE_VERSION1 || diff --git a/git-compat-util.h b/git-compat-util.h index 5bd69ec040..9408f463e3 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -897,16 +897,16 @@ static inline size_t xsize_t(off_t len) * is done via tolower(), so it is strictly ASCII (no multi-byte characters or * locale-specific conversions). */ -static inline int skip_iprefix(const char *str, const char *prefix, +static inline bool skip_iprefix(const char *str, const char *prefix, const char **out) { do { if (!*prefix) { *out = str; - return 1; + return true; } } while (tolower(*str++) == tolower(*prefix++)); - return 0; + return false; } /* @@ -914,7 +914,7 @@ static inline int skip_iprefix(const char *str, const char *prefix, * comparison is done via tolower(), so it is strictly ASCII (no multi-byte * characters or locale-specific conversions). */ -static inline int skip_iprefix_mem(const char *buf, size_t len, +static inline bool skip_iprefix_mem(const char *buf, size_t len, const char *prefix, const char **out, size_t *outlen) { @@ -922,10 +922,10 @@ static inline int skip_iprefix_mem(const char *buf, size_t len, if (!*prefix) { *out = buf; *outlen = len; - return 1; + return true; } } while (len-- > 0 && tolower(*buf++) == tolower(*prefix++)); - return 0; + return false; } static inline int strtoul_ui(char const *s, int base, unsigned int *result) diff --git a/git-gui/.gitignore b/git-gui/.gitignore index ff6e0be4b4..5130b4f018 100644 --- a/git-gui/.gitignore +++ b/git-gui/.gitignore @@ -1,8 +1,8 @@ .DS_Store config.mak -Git Gui.app* git-gui.tcl GIT-GUI-BUILD-OPTIONS GIT-VERSION-FILE git-gui +git-gui--askpass lib/tclIndex diff --git a/git-gui/GIT-GUI-BUILD-OPTIONS.in b/git-gui/GIT-GUI-BUILD-OPTIONS.in index 5fd885c2bf..3c112af578 100644 --- a/git-gui/GIT-GUI-BUILD-OPTIONS.in +++ b/git-gui/GIT-GUI-BUILD-OPTIONS.in @@ -4,4 +4,3 @@ GITGUI_RELATIVE=@GITGUI_RELATIVE@ SHELL_PATH=@SHELL_PATH@ TCLTK_PATH=@TCLTK_PATH@ TCL_PATH=@TCL_PATH@ -TKEXECUTABLE=@TKEXECUTABLE@ diff --git a/git-gui/Makefile b/git-gui/Makefile index 8672dd2d6b..27bbe051de 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -12,7 +12,6 @@ GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN . $@ uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') -uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') SCRIPT_SH = git-gui.sh @@ -54,8 +53,6 @@ INSTALL_R0 = $(INSTALL) -m 644 # space is required here INSTALL_R1 = INSTALL_X0 = $(INSTALL) -m 755 # space is required here INSTALL_X1 = -INSTALL_A0 = find # space is required here -INSTALL_A1 = | cpio -pud INSTALL_L0 = rm -f # space is required here INSTALL_L1 = && ln # space is required here INSTALL_L2 = @@ -80,8 +77,6 @@ ifndef V INSTALL_R1 = && echo ' ' INSTALL 644 `basename $$src` && $(INSTALL) -m 644 $$src INSTALL_X0 = src= INSTALL_X1 = && echo ' ' INSTALL 755 `basename $$src` && $(INSTALL) -m 755 $$src - INSTALL_A0 = src= - INSTALL_A1 = && echo ' ' INSTALL ' ' `basename "$$src"` && find "$$src" | cpio -pud INSTALL_L0 = dst= INSTALL_L1 = && src= @@ -102,18 +97,6 @@ else TCL_PATH ?= $(dir $(TCLTK_PATH))$(notdir $(subst wish,tclsh,$(TCLTK_PATH))) endif -ifeq ($(uname_S),Darwin) - TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app - ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n) - TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish.app - ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n) - TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app - endif - endif - TKEXECUTABLE = $(TKFRAMEWORK)/Contents/MacOS/$(shell basename "$(TKFRAMEWORK)" .app) - TKEXECUTABLE_SQ = $(subst ','\'',$(TKEXECUTABLE)) -endif - ifeq ($(findstring $(firstword -$(MAKEFLAGS)),s),s) QUIET_GEN = endif @@ -131,16 +114,10 @@ libdir_SQ = $(subst ','\'',$(gg_libdir)) exedir = $(dir $(gitexecdir))share/git-gui/lib GITGUI_RELATIVE := -GITGUI_MACOSXAPP := ifeq ($(exedir),$(gg_libdir)) GITGUI_RELATIVE := 1 endif -ifeq ($(uname_S),Darwin) - ifeq ($(shell test -d $(TKFRAMEWORK) && echo y),y) - GITGUI_MACOSXAPP := YesPlease - endif -endif ifneq (,$(findstring MINGW,$(uname_S))) ifeq ($(shell expr "$(uname_R)" : '1\.'),2) NO_MSGFMT=1 @@ -149,20 +126,6 @@ endif GITGUI_RELATIVE := 1 endif -ifdef GITGUI_MACOSXAPP -GITGUI_MAIN := git-gui.tcl - -git-gui: generate-macos-wrapper.sh GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS - $(QUIET_GEN)$(SHELL_PATH) generate-macos-wrapper.sh "$@" ./GIT-GUI-BUILD-OPTIONS ./GIT-VERSION-FILE - -Git\ Gui.app: GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS \ - macosx/Info.plist \ - macosx/git-gui.icns \ - macosx/AppMain.tcl \ - $(TKEXECUTABLE) - $(QUIET_GEN)$(SHELL_PATH) generate-macos-app.sh . "$@" ./GIT-GUI-BUILD-OPTIONS ./GIT-VERSION-FILE -endif - ifdef GITGUI_WINDOWS_WRAPPER GITGUI_MAIN := git-gui.tcl @@ -170,7 +133,7 @@ git-gui: windows/git-gui.sh cp $< $@ endif -$(GITGUI_MAIN): git-gui.sh GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS +$(GITGUI_MAIN): git-gui.sh GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS generate-git-gui.sh $(QUIET_GEN)$(SHELL_PATH) generate-git-gui.sh "$<" "$@" ./GIT-GUI-BUILD-OPTIONS ./GIT-VERSION-FILE XGETTEXT ?= xgettext @@ -207,18 +170,17 @@ GIT-GUI-BUILD-OPTIONS: FORCE -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ -e 's|@TCLTK_PATH@|$(TCLTK_PATH_SQ)|' \ -e 's|@TCL_PATH@|$(TCL_PATH_SQ)|' \ - -e 's|@TKEXECUTABLE@|$(TKEXECUTABLE_SQ)|' \ $@.in >$@+ @if grep -q '^[A-Z][A-Z_]*=@.*@$$' $@+; then echo "Unsubstituted build options in $@" >&2 && exit 1; fi @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi -ifdef GITGUI_MACOSXAPP -all:: git-gui Git\ Gui.app -endif +git-gui--askpass: git-gui--askpass.sh GIT-GUI-BUILD-OPTIONS generate-script.sh + $(QUIET_GEN)$(SHELL_PATH) generate-script.sh $@ $< ./GIT-GUI-BUILD-OPTIONS + ifdef GITGUI_WINDOWS_WRAPPER all:: git-gui endif -all:: $(GITGUI_MAIN) lib/tclIndex $(ALL_MSGFILES) +all:: $(GITGUI_MAIN) git-gui--askpass lib/tclIndex $(ALL_MSGFILES) install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) @@ -230,10 +192,6 @@ ifdef GITGUI_WINDOWS_WRAPPER endif $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(libdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_R0)lib/tclIndex $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)' -ifdef GITGUI_MACOSXAPP - $(QUIET)$(INSTALL_A0)'Git Gui.app' $(INSTALL_A1) '$(DESTDIR_SQ)$(libdir_SQ)' - $(QUIET)$(INSTALL_X0)git-gui.tcl $(INSTALL_X1) '$(DESTDIR_SQ)$(libdir_SQ)' -endif $(QUIET)$(foreach p,$(ALL_LIBFILES) $(NONTCL_LIBFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)' &&) true $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(msgsdir_SQ)' $(INSTALL_D1) $(QUIET)$(foreach p,$(ALL_MSGFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(msgsdir_SQ)' &&) true @@ -248,10 +206,6 @@ ifdef GITGUI_WINDOWS_WRAPPER endif $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(libdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)'/tclIndex $(REMOVE_F1) -ifdef GITGUI_MACOSXAPP - $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)/Git Gui.app' $(REMOVE_F1) - $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)'/git-gui.tcl $(REMOVE_F1) -endif $(QUIET)$(foreach p,$(ALL_LIBFILES) $(NONTCL_LIBFILES), $(REMOVE_F0)'$(DESTDIR_SQ)$(libdir_SQ)'/$(notdir $p) $(REMOVE_F1) &&) true $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(msgsdir_SQ)' $(QUIET)$(foreach p,$(ALL_MSGFILES), $(REMOVE_F0)'$(DESTDIR_SQ)$(msgsdir_SQ)'/$(notdir $p) $(REMOVE_F1) &&) true @@ -265,11 +219,8 @@ dist-version: GIT-VERSION-FILE @sed 's|^GITGUI_VERSION=||' <GIT-VERSION-FILE >$(TARDIR)/version clean:: - $(RM_RF) $(GITGUI_MAIN) lib/tclIndex po/*.msg $(PO_TEMPLATE) + $(RM_RF) $(GITGUI_MAIN) git-gui--askpass lib/tclIndex po/*.msg $(PO_TEMPLATE) $(RM_RF) GIT-VERSION-FILE GIT-GUI-BUILD-OPTIONS -ifdef GITGUI_MACOSXAPP - $(RM_RF) 'Git Gui.app'* git-gui -endif ifdef GITGUI_WINDOWS_WRAPPER $(RM_RF) git-gui endif diff --git a/git-gui/generate-macos-app.sh b/git-gui/generate-macos-app.sh deleted file mode 100755 index 71b9fa67a4..0000000000 --- a/git-gui/generate-macos-app.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -set -e - -SOURCE_DIR="$1" -OUTPUT="$2" -BUILD_OPTIONS="$3" -VERSION_FILE="$4" - -. "$BUILD_OPTIONS" -. "$VERSION_FILE" - -rm -rf "$OUTPUT" "$OUTPUT+" - -mkdir -p "$OUTPUT+/Contents/MacOS" -mkdir -p "$OUTPUT+/Contents/Resources/Scripts" - -cp "$TKEXECUTABLE" "$OUTPUT+/Contents/MacOS" -cp "$SOURCE_DIR/macosx/git-gui.icns" "$OUTPUT+/Contents/Resources" -sed \ - -e "s/@@GITGUI_VERSION@@/$GITGUI_VERSION/g" \ - -e "s/@@GITGUI_TKEXECUTABLE@@/$(basename "$TKEXECUTABLE")/g" \ - "$SOURCE_DIR/macosx/Info.plist" \ - >"$OUTPUT+/Contents/Info.plist" -sed \ - -e "s|@@gitexecdir@@|$GITGUI_GITEXECDIR|" \ - -e "s|@@GITGUI_LIBDIR@@|$GITGUI_LIBDIR|" \ - "$SOURCE_DIR/macosx/AppMain.tcl" \ - >"$OUTPUT+/Contents/Resources/Scripts/AppMain.tcl" -mv "$OUTPUT+" "$OUTPUT" diff --git a/git-gui/generate-macos-wrapper.sh b/git-gui/generate-macos-wrapper.sh deleted file mode 100755 index 0304937f41..0000000000 --- a/git-gui/generate-macos-wrapper.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -set -e - -if test "$#" -ne 3 -then - echo >&2 "usage: $0 <OUTPUT> <BUILD_OPTIONS> <VERSION_FILE>" - exit 1 -fi - -OUTPUT="$1" -BUILD_OPTIONS="$2" -VERSION_FILE="$3" - -. "$BUILD_OPTIONS" - -rm -f "$OUTPUT" "$OUTPUT+" - -( - echo "#!$SHELL_PATH" - cat "$BUILD_OPTIONS" "$VERSION_FILE" - cat <<-'EOF' - if test "z$*" = zversion || - test "z$*" = z--version - then - echo "git-gui version $GITGUI_VERSION" - else - libdir="${GIT_GUI_LIB_DIR:-$GITGUI_LIBDIR}" - exec "$libdir/Git Gui.app/Contents/MacOS/$(basename "$TKEXECUTABLE")" "$0" "$@" - fi - EOF -) >"$OUTPUT+" - -chmod +x "$OUTPUT+" -mv "$OUTPUT+" "$OUTPUT" diff --git a/git-gui/generate-script.sh b/git-gui/generate-script.sh new file mode 100755 index 0000000000..0dd2da92e3 --- /dev/null +++ b/git-gui/generate-script.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +if test $# -ne 3 +then + echo >&2 "USAGE: $0 <OUTPUT> <INPUT> <GIT-GUI-BUILD-OPTIONS>" + exit 1 +fi + +OUTPUT="$1" +INPUT="$2" +BUILD_OPTIONS="$3" + +. "$BUILD_OPTIONS" + +sed \ + -e "1s|#!.*/sh|#!$SHELL_PATH|" \ + -e "1,3s|^exec wish|exec '$TCLTK_PATH'|" \ + "$INPUT" >"$OUTPUT" + +chmod a+x "$OUTPUT" diff --git a/git-gui/git-gui--askpass b/git-gui/git-gui--askpass.sh index 71a536d232..71a536d232 100755 --- a/git-gui/git-gui--askpass +++ b/git-gui/git-gui--askpass.sh diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index c77c05edde..a931d7f7c9 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -30,9 +30,7 @@ along with this program; if not, see <https://www.gnu.org/licenses/>.}] ## ## Tcl/Tk sanity check -if {[catch {package require Tcl 8.5} err] - || [catch {package require Tk 8.5} err] -} { +if {[catch {package require Tcl 8.6-} err]} { catch {wm withdraw .} tk_messageBox \ -icon error \ @@ -76,21 +74,33 @@ proc is_Cygwin {} { } ###################################################################### +## Enable Tcl8 profile in Tcl9, allowing consumption of data that has +## bytes not conforming to the assumed encoding profile. + +if {[package vcompare $::tcl_version 9.0] >= 0} { + rename open _strict_open + proc open args { + set f [_strict_open {*}$args] + chan configure $f -profile tcl8 + return $f + } + proc convertfrom args { + return [encoding convertfrom -profile tcl8 {*}$args] + } +} else { + proc convertfrom args { + return [encoding convertfrom {*}$args] + } +} + +###################################################################### ## ## PATH lookup. Sanitize $PATH, assure exec/open use only that if {[is_Windows]} { set _path_sep {;} - set _search_exe .exe } else { set _path_sep {:} - set _search_exe {} -} - -if {[is_Windows]} { - set gitguidir [file dirname [info script]] - regsub -all ";" $gitguidir "\\;" gitguidir - set env(PATH) "$gitguidir;$env(PATH)" } set _search_path {} @@ -114,15 +124,15 @@ set env(PATH) [join $_search_path $_path_sep] if {[is_Windows]} { proc _which {what args} { - global _search_exe _search_path + global _search_path if {[lsearch -exact $args -script] >= 0} { set suffix {} - } elseif {[string match *$_search_exe [string tolower $what]]} { + } elseif {[string match *.exe [string tolower $what]]} { # The search string already has the file extension set suffix {} } else { - set suffix $_search_exe + set suffix .exe } foreach p $_search_path { @@ -187,7 +197,9 @@ if {[is_Windows]} { set command_line [string trim [string range $arg0 1 end]] lset args 0 "| [sanitize_command_line $command_line 0]" } - uplevel 1 real_open $args + set fd [real_open {*}$args] + fconfigure $fd -eofchar {} + return $fd } } else { @@ -365,7 +377,6 @@ set _appname {Git Gui} set _gitdir {} set _gitworktree {} set _isbare {} -set _gitexec {} set _githtmldir {} set _reponame {} set _shellpath {@@SHELL_PATH@@} @@ -430,20 +441,6 @@ proc gitdir {args} { return [eval [list file join $_gitdir] $args] } -proc gitexec {args} { - global _gitexec - if {$_gitexec eq {}} { - if {[catch {set _gitexec [git --exec-path]} err]} { - error "Git not installed?\n\n$err" - } - set _gitexec [file normalize $_gitexec] - } - if {$args eq {}} { - return $_gitexec - } - return [eval [list file join $_gitexec] $args] -} - proc githtmldir {args} { global _githtmldir if {$_githtmldir eq {}} { @@ -576,56 +573,6 @@ proc _trace_exec {cmd} { #'" fix poor old emacs font-lock mode -proc _git_cmd {name} { - global _git_cmd_path - - if {[catch {set v $_git_cmd_path($name)}]} { - switch -- $name { - version - - --version - - --exec-path { return [list $::_git $name] } - } - - set p [gitexec git-$name$::_search_exe] - if {[file exists $p]} { - set v [list $p] - } elseif {[is_Windows] && [file exists [gitexec git-$name]]} { - # Try to determine what sort of magic will make - # git-$name go and do its thing, because native - # Tcl on Windows doesn't know it. - # - set p [gitexec git-$name] - set f [safe_open_file $p r] - set s [gets $f] - close $f - - switch -glob -- [lindex $s 0] { - #!*sh { set i sh } - #!*perl { set i perl } - #!*python { set i python } - default { error "git-$name is not supported: $s" } - } - - upvar #0 _$i interp - if {![info exists interp]} { - set interp [_which $i] - } - if {$interp eq {}} { - error "git-$name requires $i (not in PATH)" - } - set v [concat [list $interp] [lrange $s 1 end] [list $p]] - } else { - # Assume it is builtin to git somehow and we - # aren't actually able to see a file for it. - # - set v [list $::_git $name] - } - set _git_cmd_path($name) $v - } - return $v -} - -# Run a shell command connected via pipes on stdout. # This is for use with textconv filters and uses sh -c "..." to allow it to # contain a command with arguments. We presume this # to be a shellscript that the configured shell (/bin/sh by default) knows @@ -644,8 +591,6 @@ proc _lappend_nice {cmd_var} { set _nice [_which nice] if {[catch {safe_exec [list $_nice git version]}]} { set _nice {} - } elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} { - set _nice {} } } if {$_nice ne {}} { @@ -659,7 +604,7 @@ proc git {args} { proc git_redir {cmd redir} { set fd [git_read $cmd $redir] - fconfigure $fd -translation binary -encoding utf-8 + fconfigure $fd -encoding utf-8 set result [string trimright [read $fd] "\n"] close $fd if {$::_trace} { @@ -676,35 +621,34 @@ proc safe_open_command {cmd {redir {}}} { } err]} { error $err } - fconfigure $fd -eofchar {} return $fd } proc git_read {cmd {redir {}}} { - set cmdp [_git_cmd [lindex $cmd 0]] - set cmd [lrange $cmd 1 end] + global _git + set cmdp [concat [list $_git] $cmd] - return [safe_open_command [concat $cmdp $cmd] $redir] + return [safe_open_command $cmdp $redir] } proc git_read_nice {cmd} { + global _git set opt [list] _lappend_nice opt - set cmdp [_git_cmd [lindex $cmd 0]] - set cmd [lrange $cmd 1 end] + set cmdp [concat [list $_git] $cmd] - return [safe_open_command [concat $opt $cmdp $cmd]] + return [safe_open_command [concat $opt $cmdp]] } proc git_write {cmd} { + global _git set cmd [make_arglist_safe $cmd] - set cmdp [_git_cmd [lindex $cmd 0]] - set cmd [lrange $cmd 1 end] + set cmdp [concat [list $_git] $cmd] - _trace_exec [concat $cmdp $cmd] - return [open [concat [list | ] $cmdp $cmd] w] + _trace_exec $cmdp + return [open [concat [list | ] $cmdp] w] } proc githook_read {hook_name args} { @@ -744,27 +688,8 @@ proc sq {value} { proc load_current_branch {} { global current_branch is_detached - set fd [safe_open_file [gitdir HEAD] r] - fconfigure $fd -translation binary -encoding utf-8 - if {[gets $fd ref] < 1} { - set ref {} - } - close $fd - - set pfx {ref: refs/heads/} - set len [string length $pfx] - if {[string equal -length $len $pfx $ref]} { - # We're on a branch. It might not exist. But - # HEAD looks good enough to be a branch. - # - set current_branch [string range $ref $len end] - set is_detached 0 - } else { - # Assume this is a detached head. - # - set current_branch HEAD - set is_detached 1 - } + set current_branch [git branch --show-current] + set is_detached [expr [string length $current_branch] == 0] } auto_load tk_optionMenu @@ -914,18 +839,9 @@ proc apply_config {} { font configure ${font}italic -slant italic } - global use_ttk NS - set use_ttk 0 - set NS {} - if {$repo_config(gui.usettk)} { - set use_ttk [package vsatisfies [package provide Tk] 8.5] - if {$use_ttk} { - set NS ttk - bind [winfo class .] <<ThemeChanged>> [list InitTheme] - pave_toplevel . - color::sync_with_theme - } - } + bind [winfo class .] <<ThemeChanged>> [list InitTheme] + pave_toplevel . + color::sync_with_theme global comment_string set comment_string [get_config core.commentstring] @@ -992,6 +908,8 @@ if {$_git eq {}} { ## ## version check +set MIN_GIT_VERSION 2.36 + if {[catch {set _git_version [git --version]} err]} { catch {wm withdraw .} tk_messageBox \ @@ -1002,9 +920,10 @@ if {[catch {set _git_version [git --version]} err]} { $err -[appname] requires Git 1.5.0 or later." +[appname] requires Git $MIN_GIT_VERSION or later." exit 1 } + if {![regsub {^git version } $_git_version {} _git_version]} { catch {wm withdraw .} tk_messageBox \ @@ -1029,85 +948,21 @@ proc get_trimmed_version {s} { set _real_git_version $_git_version set _git_version [get_trimmed_version $_git_version] -if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} { - catch {wm withdraw .} - if {[tk_messageBox \ - -icon warning \ - -type yesno \ - -default no \ - -title "[appname]: warning" \ - -message [mc "Git version cannot be determined. - -%s claims it is version '%s'. - -%s requires at least Git 1.5.0 or later. - -Assume '%s' is version 1.5.0? -" $_git $_real_git_version [appname] $_real_git_version]] eq {yes}} { - set _git_version 1.5.0 - } else { - exit 1 - } -} -unset _real_git_version - -proc git-version {args} { - global _git_version - - switch [llength $args] { - 0 { - return $_git_version - } - - 2 { - set op [lindex $args 0] - set vr [lindex $args 1] - set cm [package vcompare $_git_version $vr] - return [expr $cm $op 0] - } - - 4 { - set type [lindex $args 0] - set name [lindex $args 1] - set parm [lindex $args 2] - set body [lindex $args 3] - - if {($type ne {proc} && $type ne {method})} { - error "Invalid arguments to git-version" - } - if {[llength $body] < 2 || [lindex $body end-1] ne {default}} { - error "Last arm of $type $name must be default" - } - - foreach {op vr cb} [lrange $body 0 end-2] { - if {[git-version $op $vr]} { - return [uplevel [list $type $name $parm $cb]] - } - } - - return [uplevel [list $type $name $parm [lindex $body end]]] - } - - default { - error "git-version >= x" - } +if {[catch {set vcheck [package vcompare $_git_version $MIN_GIT_VERSION]}] || + [expr $vcheck < 0] } { - } -} - -if {[git-version < 1.5]} { + set msg1 [mc "Insufficient git version, require: "] + set msg2 [mc "git returned:"] + set message "$msg1 $MIN_GIT_VERSION\n$msg2 $_real_git_version" catch {wm withdraw .} tk_messageBox \ -icon error \ -type ok \ -title [mc "git-gui: fatal error"] \ - -message "[appname] requires Git 1.5.0 or later. - -You are using [git-version]: - -[git --version]" + -message $message exit 1 } +unset _real_git_version ###################################################################### ## @@ -1161,7 +1016,7 @@ proc _parse_config {arr_name args} { [concat config \ $args \ --null --list]] - fconfigure $fd_rc -translation binary -encoding utf-8 + fconfigure $fd_rc -encoding utf-8 set buf [read $fd_rc] close $fd_rc } @@ -1270,12 +1125,12 @@ citool { ## ## execution environment -set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] - # Suggest our implementation of askpass, if none is set +set argv0dir [file dirname [file normalize $::argv0]] if {![info exists env(SSH_ASKPASS)]} { - set env(SSH_ASKPASS) [gitexec git-gui--askpass] + set env(SSH_ASKPASS) [file join $argv0dir git-gui--askpass] } +unset argv0dir ###################################################################### ## @@ -1295,9 +1150,23 @@ if {[catch { load_config 1 apply_config choose_repository::pick + if {![file isdirectory $_gitdir]} { + exit 1 + } set picked 1 } +# Use object format as hash algorithm (either "sha1" or "sha256") +set hashalgorithm [git rev-parse --show-object-format] +if {$hashalgorithm eq "sha1"} { + set hashlength 40 +} elseif {$hashalgorithm eq "sha256"} { + set hashlength 64 +} else { + puts stderr "Unknown hash algorithm: $hashalgorithm" + exit 1 +} + # we expand the _gitdir when it's just a single dot (i.e. when we're being # run from the .git dir itself) lest the routines to find the worktree # get confused @@ -1314,20 +1183,7 @@ if {![file isdirectory $_gitdir]} { load_config 0 apply_config -# v1.7.0 introduced --show-toplevel to return the canonical work-tree -if {[package vcompare $_git_version 1.7.0] >= 0} { - set _gitworktree [git rev-parse --show-toplevel] -} else { - # try to set work tree from environment, core.worktree or use - # cdup to obtain a relative path to the top of the worktree. If - # run from the top, the ./ prefix ensures normalize expands pwd. - if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { - set _gitworktree [get_config core.worktree] - if {$_gitworktree eq ""} { - set _gitworktree [file normalize ./[git rev-parse --show-cdup]] - } - } -} +set _gitworktree [git rev-parse --show-toplevel] if {$_prefix ne {}} { if {$_gitworktree eq {}} { @@ -1391,8 +1247,8 @@ set is_conflict_diff 0 set last_revert {} set last_revert_enc {} -set nullid "0000000000000000000000000000000000000000" -set nullid2 "0000000000000000000000000000000000000001" +set nullid [string repeat 0 $hashlength] +set nullid2 "[string repeat 0 [expr $hashlength - 1]]1" ###################################################################### ## @@ -1553,18 +1409,7 @@ proc rescan_stage2 {fd after} { close $fd } - if {[package vcompare $::_git_version 1.6.3] >= 0} { - set ls_others [list --exclude-standard] - } else { - set ls_others [list --exclude-per-directory=.gitignore] - if {[have_info_exclude]} { - lappend ls_others "--exclude-from=[gitdir info exclude]" - } - set user_exclude [get_config core.excludesfile] - if {$user_exclude ne {} && [file readable $user_exclude]} { - lappend ls_others "--exclude-from=[file normalize $user_exclude]" - } - } + set ls_others [list --exclude-standard] set buf_rdi {} set buf_rdf {} @@ -1572,22 +1417,18 @@ proc rescan_stage2 {fd after} { set rescan_active 2 ui_status [mc "Scanning for modified files ..."] - if {[git-version >= "1.7.2"]} { - set fd_di [git_read [list diff-index --cached --ignore-submodules=dirty -z [PARENT]]] - } else { - set fd_di [git_read [list diff-index --cached -z [PARENT]]] - } + set fd_di [git_read [list diff-index --cached --ignore-submodules=dirty -z [PARENT]]] set fd_df [git_read [list diff-files -z]] - fconfigure $fd_di -blocking 0 -translation binary -encoding binary - fconfigure $fd_df -blocking 0 -translation binary -encoding binary + fconfigure $fd_di -blocking 0 -translation binary + fconfigure $fd_df -blocking 0 -translation binary fileevent $fd_di readable [list read_diff_index $fd_di $after] fileevent $fd_df readable [list read_diff_files $fd_df $after] if {[is_config_true gui.displayuntracked]} { set fd_lo [git_read [concat ls-files --others -z $ls_others]] - fconfigure $fd_lo -blocking 0 -translation binary -encoding binary + fconfigure $fd_lo -blocking 0 -translation binary fileevent $fd_lo readable [list read_ls_others $fd_lo $after] incr rescan_active } @@ -1601,7 +1442,6 @@ proc load_message {file {encoding {}}} { if {[catch {set fd [safe_open_file $f r]}]} { return 0 } - fconfigure $fd -eofchar {} if {$encoding ne {}} { fconfigure $fd -encoding $encoding } @@ -1658,7 +1498,7 @@ proc run_prepare_commit_msg_hook {} { ui_status [mc "Calling prepare-commit-msg hook..."] set pch_error {} - fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fconfigure $fd_ph -blocking 0 -translation binary fileevent $fd_ph readable \ [list prepare_commit_msg_hook_wait $fd_ph] @@ -1704,7 +1544,7 @@ proc read_diff_index {fd after} { set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }] set p [string range $buf_rdi $z1 [expr {$z2 - 1}]] merge_state \ - [encoding convertfrom utf-8 $p] \ + [convertfrom utf-8 $p] \ [lindex $i 4]? \ [list [lindex $i 0] [lindex $i 2]] \ [list] @@ -1737,7 +1577,7 @@ proc read_diff_files {fd after} { set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }] set p [string range $buf_rdf $z1 [expr {$z2 - 1}]] merge_state \ - [encoding convertfrom utf-8 $p] \ + [convertfrom utf-8 $p] \ ?[lindex $i 4] \ [list] \ [list [lindex $i 0] [lindex $i 2]] @@ -1760,7 +1600,7 @@ proc read_ls_others {fd after} { set pck [split $buf_rlo "\0"] set buf_rlo [lindex $pck end] foreach p [lrange $pck 0 end-1] { - set p [encoding convertfrom utf-8 $p] + set p [convertfrom utf-8 $p] if {[string index $p end] eq {/}} { set p [string range $p 0 end-1] } @@ -1845,10 +1685,9 @@ proc short_path {path} { } set next_icon_id 0 -set null_sha1 [string repeat 0 40] proc merge_state {path new_state {head_info {}} {index_info {}}} { - global file_states next_icon_id null_sha1 + global file_states next_icon_id nullid set s0 [string index $new_state 0] set s1 [string index $new_state 1] @@ -1870,7 +1709,7 @@ proc merge_state {path new_state {head_info {}} {index_info {}}} { elseif {$s1 eq {_}} {set s1 _} if {$s0 eq {A} && $s1 eq {_} && $head_info eq {}} { - set head_info [list 0 $null_sha1] + set head_info [list 0 $nullid] } elseif {$s0 ne {_} && [string index $state 0] eq {_} && $head_info eq {}} { set head_info $index_info @@ -2323,7 +2162,7 @@ proc do_quit {{rc {1}}} { global ui_comm is_quitting repo_config commit_type global GITGUI_BCK_exists GITGUI_BCK_i global ui_comm_spell - global ret_code use_ttk + global ret_code if {$is_quitting} return set is_quitting 1 @@ -2381,13 +2220,8 @@ proc do_quit {{rc {1}}} { } set cfg_geometry [list] lappend cfg_geometry [wm geometry .] - if {$use_ttk} { - lappend cfg_geometry [.vpane sashpos 0] - lappend cfg_geometry [.vpane.files sashpos 0] - } else { - lappend cfg_geometry [lindex [.vpane sash coord 0] 0] - lappend cfg_geometry [lindex [.vpane.files sash coord 0] 1] - } + lappend cfg_geometry [.vpane sashpos 0] + lappend cfg_geometry [.vpane.files sashpos 0] if {[catch {set rc_geometry $repo_config(gui.geometry)}]} { set rc_geometry {} } @@ -3203,7 +3037,7 @@ blame { if {$head eq {}} { load_current_branch } else { - if {[regexp {^[0-9a-f]{1,39}$} $head]} { + if {[regexp [string map "@@ [expr $hashlength - 1]" {^[0-9a-f]{1,@@}$}] $head]} { if {[catch { set head [git rev-parse --verify $head] } err]} { @@ -3269,13 +3103,12 @@ default { # -- Branch Control # -${NS}::frame .branch -if {!$use_ttk} {.branch configure -borderwidth 1 -relief sunken} -${NS}::label .branch.l1 \ +ttk::frame .branch +ttk::label .branch.l1 \ -text [mc "Current Branch:"] \ -anchor w \ -justify left -${NS}::label .branch.cb \ +ttk::label .branch.cb \ -textvariable current_branch \ -anchor w \ -justify left @@ -3285,13 +3118,9 @@ pack .branch -side top -fill x # -- Main Window Layout # -${NS}::panedwindow .vpane -orient horizontal -${NS}::panedwindow .vpane.files -orient vertical -if {$use_ttk} { - .vpane add .vpane.files -} else { - .vpane add .vpane.files -sticky nsew -height 100 -width 200 -} +ttk::panedwindow .vpane -orient horizontal +ttk::panedwindow .vpane.files -orient vertical +.vpane add .vpane.files pack .vpane -anchor n -side top -fill both -expand 1 # -- Working Directory File List @@ -3308,8 +3137,8 @@ ttext $ui_workdir \ -xscrollcommand {.vpane.files.workdir.sx set} \ -yscrollcommand {.vpane.files.workdir.sy set} \ -state disabled -${NS}::scrollbar .vpane.files.workdir.sx -orient h -command [list $ui_workdir xview] -${NS}::scrollbar .vpane.files.workdir.sy -orient v -command [list $ui_workdir yview] +ttk::scrollbar .vpane.files.workdir.sx -orient h -command [list $ui_workdir xview] +ttk::scrollbar .vpane.files.workdir.sy -orient v -command [list $ui_workdir yview] pack .vpane.files.workdir.title -side top -fill x pack .vpane.files.workdir.sx -side bottom -fill x pack .vpane.files.workdir.sy -side right -fill y @@ -3330,8 +3159,8 @@ ttext $ui_index \ -xscrollcommand {.vpane.files.index.sx set} \ -yscrollcommand {.vpane.files.index.sy set} \ -state disabled -${NS}::scrollbar .vpane.files.index.sx -orient h -command [list $ui_index xview] -${NS}::scrollbar .vpane.files.index.sy -orient v -command [list $ui_index yview] +ttk::scrollbar .vpane.files.index.sx -orient h -command [list $ui_index xview] +ttk::scrollbar .vpane.files.index.sy -orient v -command [list $ui_index yview] pack .vpane.files.index.title -side top -fill x pack .vpane.files.index.sx -side bottom -fill x pack .vpane.files.index.sy -side right -fill y @@ -3341,10 +3170,6 @@ pack $ui_index -side left -fill both -expand 1 # .vpane.files add .vpane.files.workdir .vpane.files add .vpane.files.index -if {!$use_ttk} { - .vpane.files paneconfigure .vpane.files.workdir -sticky news - .vpane.files paneconfigure .vpane.files.index -sticky news -} proc set_selection_colors {w has_focus} { foreach tag [list in_diff in_sel] { @@ -3365,78 +3190,63 @@ unset i # -- Diff and Commit Area # -if {$have_tk85} { - ${NS}::panedwindow .vpane.lower -orient vertical - ${NS}::frame .vpane.lower.commarea - ${NS}::frame .vpane.lower.diff -relief sunken -borderwidth 1 -height 500 - .vpane.lower add .vpane.lower.diff - .vpane.lower add .vpane.lower.commarea - .vpane add .vpane.lower - if {$use_ttk} { - .vpane.lower pane .vpane.lower.diff -weight 1 - .vpane.lower pane .vpane.lower.commarea -weight 0 - } else { - .vpane.lower paneconfigure .vpane.lower.diff -stretch always - .vpane.lower paneconfigure .vpane.lower.commarea -stretch never - } -} else { - frame .vpane.lower -height 300 -width 400 - frame .vpane.lower.commarea - frame .vpane.lower.diff -relief sunken -borderwidth 1 - pack .vpane.lower.diff -fill both -expand 1 - pack .vpane.lower.commarea -side bottom -fill x - .vpane add .vpane.lower - .vpane paneconfigure .vpane.lower -sticky nsew -} +ttk::panedwindow .vpane.lower -orient vertical +ttk::frame .vpane.lower.commarea +ttk::frame .vpane.lower.diff -relief sunken -borderwidth 1 -height 500 +.vpane.lower add .vpane.lower.diff +.vpane.lower add .vpane.lower.commarea +.vpane add .vpane.lower +.vpane.lower pane .vpane.lower.diff -weight 1 +.vpane.lower pane .vpane.lower.commarea -weight 0 # -- Commit Area Buttons # -${NS}::frame .vpane.lower.commarea.buttons -${NS}::label .vpane.lower.commarea.buttons.l -text {} \ +ttk::frame .vpane.lower.commarea.buttons +ttk::label .vpane.lower.commarea.buttons.l -text {} \ -anchor w \ -justify left pack .vpane.lower.commarea.buttons.l -side top -fill x pack .vpane.lower.commarea.buttons -side left -fill y -${NS}::button .vpane.lower.commarea.buttons.rescan -text [mc Rescan] \ +ttk::button .vpane.lower.commarea.buttons.rescan -text [mc Rescan] \ -command ui_do_rescan pack .vpane.lower.commarea.buttons.rescan -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.rescan conf -state} -${NS}::button .vpane.lower.commarea.buttons.incall -text [mc "Stage Changed"] \ +ttk::button .vpane.lower.commarea.buttons.incall -text [mc "Stage Changed"] \ -command do_add_all pack .vpane.lower.commarea.buttons.incall -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.incall conf -state} if {![is_enabled nocommitmsg]} { - ${NS}::button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \ + ttk::button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \ -command do_signoff pack .vpane.lower.commarea.buttons.signoff -side top -fill x } -${NS}::button .vpane.lower.commarea.buttons.commit -text [commit_btn_caption] \ +ttk::button .vpane.lower.commarea.buttons.commit -text [commit_btn_caption] \ -command do_commit pack .vpane.lower.commarea.buttons.commit -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.commit conf -state} if {![is_enabled nocommit]} { - ${NS}::button .vpane.lower.commarea.buttons.push -text [mc Push] \ + ttk::button .vpane.lower.commarea.buttons.push -text [mc Push] \ -command do_push_anywhere pack .vpane.lower.commarea.buttons.push -side top -fill x } # -- Commit Message Buffer # -${NS}::frame .vpane.lower.commarea.buffer -${NS}::frame .vpane.lower.commarea.buffer.header +ttk::frame .vpane.lower.commarea.buffer +ttk::frame .vpane.lower.commarea.buffer.header set ui_comm .vpane.lower.commarea.buffer.frame.t set ui_coml .vpane.lower.commarea.buffer.header.l if {![is_enabled nocommit]} { - ${NS}::checkbutton .vpane.lower.commarea.buffer.header.amend \ + ttk::checkbutton .vpane.lower.commarea.buffer.header.amend \ -text [mc "Amend Last Commit"] \ -variable commit_type_is_amend \ -command do_select_commit_type @@ -3444,7 +3254,7 @@ if {![is_enabled nocommit]} { [list .vpane.lower.commarea.buffer.header.amend conf -state] } -${NS}::label $ui_coml \ +ttk::label $ui_coml \ -anchor w \ -justify left proc trace_commit_type {varname args} { @@ -3479,10 +3289,10 @@ ttext $ui_comm \ -font font_diff \ -xscrollcommand {.vpane.lower.commarea.buffer.frame.sbx set} \ -yscrollcommand {.vpane.lower.commarea.buffer.frame.sby set} -${NS}::scrollbar .vpane.lower.commarea.buffer.frame.sbx \ +ttk::scrollbar .vpane.lower.commarea.buffer.frame.sbx \ -orient horizontal \ -command [list $ui_comm xview] -${NS}::scrollbar .vpane.lower.commarea.buffer.frame.sby \ +ttk::scrollbar .vpane.lower.commarea.buffer.frame.sby \ -orient vertical \ -command [list $ui_comm yview] @@ -3605,9 +3415,9 @@ ttext $ui_diff \ -yscrollcommand {.vpane.lower.diff.body.sby set} \ -state disabled catch {$ui_diff configure -tabstyle wordprocessor} -${NS}::scrollbar .vpane.lower.diff.body.sbx -orient horizontal \ +ttk::scrollbar .vpane.lower.diff.body.sbx -orient horizontal \ -command [list $ui_diff xview] -${NS}::scrollbar .vpane.lower.diff.body.sby -orient vertical \ +ttk::scrollbar .vpane.lower.diff.body.sby -orient vertical \ -command [list $ui_diff yview] pack .vpane.lower.diff.body.sbx -side bottom -fill x pack .vpane.lower.diff.body.sby -side right -fill y @@ -3908,29 +3718,14 @@ proc on_ttk_pane_mapped {w pane pos} { bind $w <Map> {} after 0 [list after idle [list $w sashpos $pane $pos]] } -proc on_tk_pane_mapped {w pane x y} { - bind $w <Map> {} - after 0 [list after idle [list $w sash place $pane $x $y]] -} proc on_application_mapped {} { - global repo_config use_ttk + global repo_config bind . <Map> {} set gm $repo_config(gui.geometry) - if {$use_ttk} { - bind .vpane <Map> \ - [list on_ttk_pane_mapped %W 0 [lindex $gm 1]] - bind .vpane.files <Map> \ - [list on_ttk_pane_mapped %W 0 [lindex $gm 2]] - } else { - bind .vpane <Map> \ - [list on_tk_pane_mapped %W 0 \ - [lindex $gm 1] \ - [lindex [.vpane sash coord 0] 1]] - bind .vpane.files <Map> \ - [list on_tk_pane_mapped %W 0 \ - [lindex [.vpane.files sash coord 0] 0] \ - [lindex $gm 2]] - } + bind .vpane <Map> \ + [list on_ttk_pane_mapped %W 0 [lindex $gm 1]] + bind .vpane.files <Map> \ + [list on_ttk_pane_mapped %W 0 [lindex $gm 2]] wm geometry . [lindex $gm 0] } if {[info exists repo_config(gui.geometry)]} { diff --git a/git-gui/lib/about.tcl b/git-gui/lib/about.tcl index cfa50fca87..122ebfb71d 100644 --- a/git-gui/lib/about.tcl +++ b/git-gui/lib/about.tcl @@ -4,19 +4,19 @@ proc do_about {} { global appvers copyright oguilib global tcl_patchLevel tk_patchLevel - global ui_comm_spell NS use_ttk + global ui_comm_spell set w .about_dialog Dialog $w wm geometry $w "+[winfo rootx .]+[winfo rooty .]" pack [git_logo $w.git_logo] -side left -fill y -padx 10 -pady 10 - ${NS}::label $w.header -text [mc "About %s" [appname]] \ + ttk::label $w.header -text [mc "About %s" [appname]] \ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.close -text {Close} \ + ttk::frame $w.buttons + ttk::button $w.buttons.close -text {Close} \ -default active \ -command [list destroy $w] pack $w.buttons.close -side right @@ -44,7 +44,7 @@ proc do_about {} { set d {} append d "git wrapper: $::_git\n" - append d "git exec dir: [gitexec]\n" + append d "git exec dir: [git --exec-path]\n" append d "git-gui lib: $oguilib" paddedlabel $w.vers -text $v diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl index d6fd8bea91..4477b84eae 100644 --- a/git-gui/lib/blame.tcl +++ b/git-gui/lib/blame.tcl @@ -63,7 +63,7 @@ field tooltip_timer {} ; # Current timer event for our tooltip field tooltip_commit {} ; # Commit(s) in tooltip constructor new {i_commit i_path i_jump} { - global cursor_ptr M1B M1T have_tk85 use_ttk NS + global cursor_ptr M1B M1T variable active_color variable group_colors @@ -203,18 +203,17 @@ constructor new {i_commit i_path i_jump} { -width 80 \ -xscrollcommand [list $w.file_pane.out.sbx set] \ -font font_diff - if {$have_tk85} { $w_file configure -inactiveselectbackground darkblue - } + $w_file tag conf found \ -background yellow set w_columns [list $w_amov $w_asim $w_line $w_file] - ${NS}::scrollbar $w.file_pane.out.sbx \ + ttk::scrollbar $w.file_pane.out.sbx \ -orient h \ -command [list $w_file xview] - ${NS}::scrollbar $w.file_pane.out.sby \ + ttk::scrollbar $w.file_pane.out.sby \ -orient v \ -command [list scrollbar2many $w_columns yview] eval grid $w_columns $w.file_pane.out.sby -sticky nsew @@ -264,10 +263,10 @@ constructor new {i_commit i_path i_jump} { -background $active_color \ -font font_ui $w_cviewer tag raise sel - ${NS}::scrollbar $w.file_pane.cm.sbx \ + ttk::scrollbar $w.file_pane.cm.sbx \ -orient h \ -command [list $w_cviewer xview] - ${NS}::scrollbar $w.file_pane.cm.sby \ + ttk::scrollbar $w.file_pane.cm.sby \ -orient v \ -command [list $w_cviewer yview] pack $w.file_pane.cm.sby -side right -fill y @@ -426,6 +425,7 @@ method _kill {} { method _load {jump} { variable group_colors + global hashlength _hide_tooltip $this @@ -436,7 +436,7 @@ method _load {jump} { $i conf -state normal $i delete 0.0 end foreach g [$i tag names] { - if {[regexp {^g[0-9a-f]{40}$} $g]} { + if {[regexp [string map "@@ $hashlength" {^g[0-9a-f]{@@}$}] $g]} { $i tag delete $g } } @@ -470,7 +470,7 @@ method _load {jump} { $w_path conf -text [escape_path $path] set do_textconv 0 - if {![is_config_false gui.textconv] && [git-version >= 1.7.2]} { + if {![is_config_false gui.textconv]} { set filter [gitattr $path diff set] set textconv [get_config [join [list diff $filter textconv] .]] if {$filter ne {set} && $textconv ne {}} { @@ -483,7 +483,6 @@ method _load {jump} { } else { set fd [safe_open_file $path r] } - fconfigure $fd -eofchar {} } else { if {$do_textconv ne 0} { set fd [git_read [list cat-file --textconv "$commit:$path"]] @@ -493,13 +492,14 @@ method _load {jump} { } fconfigure $fd \ -blocking 0 \ - -translation lf \ -encoding [get_path_encoding $path] fileevent $fd readable [cb _read_file $fd $jump] set current_fd $fd } method _history_menu {} { + global hashlength + set m $w.backmenu if {[winfo exists $m]} { $m delete 0 end @@ -513,7 +513,7 @@ method _history_menu {} { set c [lindex $e 0] set f [lindex $e 1] - if {[regexp {^[0-9a-f]{40}$} $c]} { + if {[regexp [string map "@@ $hashlength" {^[0-9a-f]{@@}$}] $c]} { set t [string range $c 0 8]... } elseif {$c eq {}} { set t {Working Directory} @@ -618,7 +618,7 @@ method _exec_blame {cur_w cur_d options cur_s} { lappend options -- $path set fd [git_read_nice [concat blame $options]] - fconfigure $fd -blocking 0 -translation lf -encoding utf-8 + fconfigure $fd -blocking 0 -encoding utf-8 fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d] set current_fd $fd set blame_lines 0 @@ -627,6 +627,7 @@ method _exec_blame {cur_w cur_d options cur_s} { method _read_blame {fd cur_w cur_d} { upvar #0 $cur_d line_data variable group_colors + global hashlength nullid if {$fd ne $current_fd} { catch {close $fd} @@ -635,7 +636,7 @@ method _read_blame {fd cur_w cur_d} { $cur_w conf -state normal while {[gets $fd line] >= 0} { - if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \ + if {[regexp [string map "@@ $hashlength" {^([a-z0-9]{@@}) (\d+) (\d+) (\d+)$}] $line line \ cmit original_line final_line line_count]} { set r_commit $cmit set r_orig_line $original_line @@ -648,7 +649,7 @@ method _read_blame {fd cur_w cur_d} { set oln $r_orig_line set cmit $r_commit - if {[regexp {^0{40}$} $cmit]} { + if {$cmit eq $nullid} { set commit_abbr work set commit_type curr_commit } elseif {$cmit eq $commit} { @@ -807,9 +808,7 @@ method _read_blame {fd cur_w cur_d} { # thorough copy search; insert before the threshold set original_options [linsert $original_options 0 -C] } - if {[git-version >= 1.5.3]} { - lappend original_options -w ; # ignore indentation changes - } + lappend original_options -w ; # ignore indentation changes _exec_blame $this $w_amov @amov_data \ $original_options \ @@ -857,9 +856,7 @@ method _fullcopyblame {} { set threshold [get_config gui.copyblamethreshold] set original_options [list -C -C "-C$threshold"] - if {[git-version >= 1.5.3]} { - lappend original_options -w ; # ignore indentation changes - } + lappend original_options -w ; # ignore indentation changes # Find the line range set pos @$::cursorX,$::cursorY @@ -987,7 +984,7 @@ method _showcommit {cur_w lno} { set msg {} catch { set fd [git_read [list cat-file commit $cmit]] - fconfigure $fd -encoding binary -translation lf + fconfigure $fd -encoding iso8859-1 # By default commits are assumed to be in utf-8 set enc utf-8 while {[gets $fd line] > 0} { @@ -1000,7 +997,7 @@ method _showcommit {cur_w lno} { set enc [tcl_encoding $enc] if {$enc ne {}} { - set msg [encoding convertfrom $enc $msg] + set msg [convertfrom $enc $msg] } set msg [string trim $msg] } @@ -1144,7 +1141,6 @@ method _blameparent {} { fconfigure $fd \ -blocking 0 \ - -encoding binary \ -translation binary fileevent $fd readable [cb _read_diff_load_commit \ $fd $cparent $new_path $r_orig_line] @@ -1298,7 +1294,7 @@ method _open_tooltip {cur_w} { # On MacOS raising a window causes it to acquire focus. # Tk 8.5 on MacOS seems to properly support wm transient, # so we can safely counter the effect there. - if {$::have_tk85 && [is_MacOSX]} { + if {[is_MacOSX]} { update if {$w eq {}} { raise . diff --git a/git-gui/lib/branch.tcl b/git-gui/lib/branch.tcl index 39e0f2dc98..97c9ec1c00 100644 --- a/git-gui/lib/branch.tcl +++ b/git-gui/lib/branch.tcl @@ -8,7 +8,7 @@ proc load_all_heads {} { set rh_len [expr {[string length $rh] + 1}] set all_heads [list] set fd [git_read [list for-each-ref --format=%(refname) $rh]] - fconfigure $fd -translation binary -encoding utf-8 + fconfigure $fd -encoding utf-8 while {[gets $fd line] > 0} { if {!$some_heads_tracking || ![is_tracking_branch $line]} { lappend all_heads [string range $line $rh_len end] @@ -25,7 +25,7 @@ proc load_all_tags {} { --sort=-taggerdate \ --format=%(refname) \ refs/tags]] - fconfigure $fd -translation binary -encoding utf-8 + fconfigure $fd -encoding utf-8 while {[gets $fd line] > 0} { if {![regsub ^refs/tags/ $line {} name]} continue lappend all_tags $name diff --git a/git-gui/lib/branch_checkout.tcl b/git-gui/lib/branch_checkout.tcl index d06037decc..1e6b757b35 100644 --- a/git-gui/lib/branch_checkout.tcl +++ b/git-gui/lib/branch_checkout.tcl @@ -10,7 +10,6 @@ field opt_fetch 1; # refetch tracking branch if used? field opt_detach 0; # force a detached head case? constructor dialog {} { - global use_ttk NS make_dialog top w wm withdraw $w wm title $top [mc "%s (%s): Checkout Branch" [appname] [reponame]] @@ -18,16 +17,16 @@ constructor dialog {} { wm geometry $top "+[winfo rootx .]+[winfo rooty .]" } - ${NS}::label $w.header -text [mc "Checkout Branch"] \ + ttk::label $w.header -text [mc "Checkout Branch"] \ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.create -text [mc Checkout] \ + ttk::frame $w.buttons + ttk::button $w.buttons.create -text [mc Checkout] \ -default active \ -command [cb _checkout] pack $w.buttons.create -side right - ${NS}::button $w.buttons.cancel -text [mc Cancel] \ + ttk::button $w.buttons.cancel -text [mc Cancel] \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 @@ -36,14 +35,14 @@ constructor dialog {} { $w_rev bind_listbox <Double-Button-1> [cb _checkout] pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5 - ${NS}::labelframe $w.options -text [mc Options] + ttk::labelframe $w.options -text [mc Options] - ${NS}::checkbutton $w.options.fetch \ + ttk::checkbutton $w.options.fetch \ -text [mc "Fetch Tracking Branch"] \ -variable @opt_fetch pack $w.options.fetch -anchor nw - ${NS}::checkbutton $w.options.detach \ + ttk::checkbutton $w.options.detach \ -text [mc "Detach From Local Branch"] \ -variable @opt_detach pack $w.options.detach -anchor nw diff --git a/git-gui/lib/branch_create.tcl b/git-gui/lib/branch_create.tcl index ba367d551d..9fded28b5c 100644 --- a/git-gui/lib/branch_create.tcl +++ b/git-gui/lib/branch_create.tcl @@ -16,7 +16,7 @@ field opt_fetch 1; # refetch tracking branch if used? field reset_ok 0; # did the user agree to reset? constructor dialog {} { - global repo_config use_ttk NS + global repo_config make_dialog top w wm withdraw $w @@ -25,39 +25,37 @@ constructor dialog {} { wm geometry $top "+[winfo rootx .]+[winfo rooty .]" } - ${NS}::label $w.header -text [mc "Create New Branch"] \ + ttk::label $w.header -text [mc "Create New Branch"] \ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.create -text [mc Create] \ + ttk::frame $w.buttons + ttk::button $w.buttons.create -text [mc Create] \ -default active \ -command [cb _create] pack $w.buttons.create -side right - ${NS}::button $w.buttons.cancel -text [mc Cancel] \ + ttk::button $w.buttons.cancel -text [mc Cancel] \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::labelframe $w.desc -text [mc "Branch Name"] - ${NS}::radiobutton $w.desc.name_r \ + ttk::labelframe $w.desc -text [mc "Branch Name"] + ttk::radiobutton $w.desc.name_r \ -text [mc "Name:"] \ -value user \ -variable @name_type - if {!$use_ttk} {$w.desc.name_r configure -anchor w} set w_name $w.desc.name_t - ${NS}::entry $w_name \ + ttk::entry $w_name \ -width 40 \ -textvariable @name \ -validate key \ -validatecommand [cb _validate %d %S] grid $w.desc.name_r $w_name -sticky we -padx {0 5} - ${NS}::radiobutton $w.desc.match_r \ + ttk::radiobutton $w.desc.match_r \ -text [mc "Match Tracking Branch Name"] \ -value match \ -variable @name_type - if {!$use_ttk} {$w.desc.match_r configure -anchor w} grid $w.desc.match_r -sticky we -padx {0 5} -columnspan 2 grid columnconfigure $w.desc 1 -weight 1 @@ -66,34 +64,34 @@ constructor dialog {} { set w_rev [::choose_rev::new $w.rev [mc "Starting Revision"]] pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5 - ${NS}::labelframe $w.options -text [mc Options] + ttk::labelframe $w.options -text [mc Options] - ${NS}::frame $w.options.merge - ${NS}::label $w.options.merge.l -text [mc "Update Existing Branch:"] + ttk::frame $w.options.merge + ttk::label $w.options.merge.l -text [mc "Update Existing Branch:"] pack $w.options.merge.l -side left - ${NS}::radiobutton $w.options.merge.no \ + ttk::radiobutton $w.options.merge.no \ -text [mc No] \ -value none \ -variable @opt_merge pack $w.options.merge.no -side left - ${NS}::radiobutton $w.options.merge.ff \ + ttk::radiobutton $w.options.merge.ff \ -text [mc "Fast Forward Only"] \ -value ff \ -variable @opt_merge pack $w.options.merge.ff -side left - ${NS}::radiobutton $w.options.merge.reset \ + ttk::radiobutton $w.options.merge.reset \ -text [mc Reset] \ -value reset \ -variable @opt_merge pack $w.options.merge.reset -side left pack $w.options.merge -anchor nw - ${NS}::checkbutton $w.options.fetch \ + ttk::checkbutton $w.options.fetch \ -text [mc "Fetch Tracking Branch"] \ -variable @opt_fetch pack $w.options.fetch -anchor nw - ${NS}::checkbutton $w.options.checkout \ + ttk::checkbutton $w.options.checkout \ -text [mc "Checkout After Creation"] \ -variable @opt_checkout pack $w.options.checkout -anchor nw diff --git a/git-gui/lib/branch_delete.tcl b/git-gui/lib/branch_delete.tcl index a5051637bb..deac74a644 100644 --- a/git-gui/lib/branch_delete.tcl +++ b/git-gui/lib/branch_delete.tcl @@ -9,7 +9,7 @@ field w_check ; # revision picker for merge test field w_delete ; # delete button constructor dialog {} { - global current_branch use_ttk NS + global current_branch make_dialog top w wm withdraw $w @@ -18,25 +18,25 @@ constructor dialog {} { wm geometry $top "+[winfo rootx .]+[winfo rooty .]" } - ${NS}::label $w.header -text [mc "Delete Local Branch"] \ + ttk::label $w.header -text [mc "Delete Local Branch"] \ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons + ttk::frame $w.buttons set w_delete $w.buttons.delete - ${NS}::button $w_delete \ + ttk::button $w_delete \ -text [mc Delete] \ -default active \ -state disabled \ -command [cb _delete] pack $w_delete -side right - ${NS}::button $w.buttons.cancel \ + ttk::button $w.buttons.cancel \ -text [mc Cancel] \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::labelframe $w.list -text [mc "Local Branches"] + ttk::labelframe $w.list -text [mc "Local Branches"] set w_heads $w.list.l slistbox $w_heads \ -height 10 \ diff --git a/git-gui/lib/branch_rename.tcl b/git-gui/lib/branch_rename.tcl index 3a2d79a9cc..7a3b39d6a3 100644 --- a/git-gui/lib/branch_rename.tcl +++ b/git-gui/lib/branch_rename.tcl @@ -8,7 +8,7 @@ field oldname field newname constructor dialog {} { - global current_branch use_ttk NS + global current_branch make_dialog top w wm withdraw $w @@ -20,31 +20,27 @@ constructor dialog {} { set oldname $current_branch set newname [get_config gui.newbranchtemplate] - ${NS}::label $w.header -text [mc "Rename Branch"]\ + ttk::label $w.header -text [mc "Rename Branch"]\ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.rename -text [mc Rename] \ + ttk::frame $w.buttons + ttk::button $w.buttons.rename -text [mc Rename] \ -default active \ -command [cb _rename] pack $w.buttons.rename -side right - ${NS}::button $w.buttons.cancel -text [mc Cancel] \ + ttk::button $w.buttons.cancel -text [mc Cancel] \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::frame $w.rename - ${NS}::label $w.rename.oldname_l -text [mc "Branch:"] - if {$use_ttk} { - ttk::combobox $w.rename.oldname_m -textvariable @oldname \ - -values [load_all_heads] -state readonly - } else { - eval tk_optionMenu $w.rename.oldname_m @oldname [load_all_heads] - } + ttk::frame $w.rename + ttk::label $w.rename.oldname_l -text [mc "Branch:"] + ttk::combobox $w.rename.oldname_m -textvariable @oldname \ + -values [load_all_heads] -state readonly - ${NS}::label $w.rename.newname_l -text [mc "New Name:"] - ${NS}::entry $w.rename.newname_t \ + ttk::label $w.rename.newname_l -text [mc "New Name:"] + ttk::entry $w.rename.newname_t \ -width 40 \ -textvariable @newname \ -validate key \ diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl index 6fc8d4d637..fe72de025e 100644 --- a/git-gui/lib/browser.tcl +++ b/git-gui/lib/browser.tcl @@ -21,7 +21,7 @@ field browser_busy 1 field ls_buf {}; # Buffered record output from ls-tree constructor new {commit {path {}}} { - global cursor_ptr M1B use_ttk NS + global cursor_ptr M1B make_dialog top w wm withdraw $top wm title $top [mc "%s (%s): File Browser" [appname] [reponame]] @@ -35,15 +35,14 @@ constructor new {commit {path {}}} { set browser_commit $commit set browser_path "$browser_commit:[escape_path $path]" - ${NS}::label $w.path \ + ttk::label $w.path \ -textvariable @browser_path \ -anchor w \ -justify left \ -font font_uibold - if {!$use_ttk} { $w.path configure -borderwidth 1 -relief sunken} pack $w.path -anchor w -side top -fill x - ${NS}::frame $w.list + ttk::frame $w.list set w_list $w.list.l text $w_list -background white -foreground black \ -borderwidth 0 \ @@ -55,18 +54,17 @@ constructor new {commit {path {}}} { -xscrollcommand [list $w.list.sbx set] \ -yscrollcommand [list $w.list.sby set] rmsel_tag $w_list - ${NS}::scrollbar $w.list.sbx -orient h -command [list $w_list xview] - ${NS}::scrollbar $w.list.sby -orient v -command [list $w_list yview] + ttk::scrollbar $w.list.sbx -orient h -command [list $w_list xview] + ttk::scrollbar $w.list.sby -orient v -command [list $w_list yview] pack $w.list.sbx -side bottom -fill x pack $w.list.sby -side right -fill y pack $w_list -side left -fill both -expand 1 pack $w.list -side top -fill both -expand 1 - ${NS}::label $w.status \ + ttk::label $w.status \ -textvariable @browser_status \ -anchor w \ -justify left - if {!$use_ttk} { $w.status configure -borderwidth 1 -relief sunken} pack $w.status -anchor w -side bottom -fill x bind $w_list <Button-1> "[cb _click 0 @%x,%y];break" @@ -197,7 +195,7 @@ method _ls {tree_id {name {}}} { $w conf -state disabled set fd [git_read [list ls-tree -z $tree_id]] - fconfigure $fd -blocking 0 -translation binary -encoding utf-8 + fconfigure $fd -blocking 0 -encoding utf-8 fileevent $fd readable [cb _read $fd] } @@ -269,7 +267,6 @@ field w ; # widget path field w_rev ; # mega-widget to pick the initial revision constructor dialog {} { - global use_ttk NS make_dialog top w wm withdraw $top wm title $top [mc "%s (%s): Browse Branch Files" [appname] [reponame]] @@ -278,18 +275,18 @@ constructor dialog {} { wm transient $top . } - ${NS}::label $w.header \ + ttk::label $w.header \ -text [mc "Browse Branch Files"] \ -font font_uibold \ -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.browse -text [mc Browse] \ + ttk::frame $w.buttons + ttk::button $w.buttons.browse -text [mc Browse] \ -default active \ -command [cb _open] pack $w.buttons.browse -side right - ${NS}::button $w.buttons.cancel -text [mc Cancel] \ + ttk::button $w.buttons.cancel -text [mc Cancel] \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 diff --git a/git-gui/lib/checkout_op.tcl b/git-gui/lib/checkout_op.tcl index 87ed0b4858..449e89e2bc 100644 --- a/git-gui/lib/checkout_op.tcl +++ b/git-gui/lib/checkout_op.tcl @@ -151,7 +151,7 @@ method _finish_fetch {ok} { } method _update_ref {} { - global null_sha1 current_branch repo_config + global nullid current_branch repo_config set ref $new_ref set new $new_hash @@ -177,7 +177,7 @@ method _update_ref {} { } set reflog_msg "branch: Created from $new_expr" - set cur $null_sha1 + set cur $nullid if {($repo_config(branch.autosetupmerge) eq {true} || $repo_config(branch.autosetupmerge) eq {always}) @@ -462,7 +462,7 @@ If you wanted to be on a branch, create one now starting from 'This Detached Che if {$fd_ph ne {}} { global pch_error set pch_error {} - fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fconfigure $fd_ph -blocking 0 -translation binary fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph] } else { _update_repo_state $this diff --git a/git-gui/lib/choose_font.tcl b/git-gui/lib/choose_font.tcl index ebe50bd7d0..a90908a8ec 100644 --- a/git-gui/lib/choose_font.tcl +++ b/git-gui/lib/choose_font.tcl @@ -17,7 +17,6 @@ variable all_families [list] ; # All fonts known to Tk constructor pick {path title a_family a_size} { variable all_families - global use_ttk NS set v_family $a_family set v_size $a_size @@ -33,25 +32,25 @@ constructor pick {path title a_family a_size} { wm title $top "[appname] ([reponame]): $title" wm geometry $top "+[winfo rootx $path]+[winfo rooty $path]" - ${NS}::label $w.header -text $title -font font_uibold -anchor center + ttk::label $w.header -text $title -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.select \ + ttk::frame $w.buttons + ttk::button $w.buttons.select \ -text [mc Select] \ -default active \ -command [cb _select] - ${NS}::button $w.buttons.cancel \ + ttk::button $w.buttons.cancel \ -text [mc Cancel] \ -command [list destroy $w] pack $w.buttons.select -side right pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::frame $w.inner + ttk::frame $w.inner - ${NS}::frame $w.inner.family - ${NS}::label $w.inner.family.l \ + ttk::frame $w.inner.family + ttk::label $w.inner.family.l \ -text [mc "Font Family"] \ -anchor w set w_family $w.inner.family.v @@ -66,13 +65,13 @@ constructor pick {path title a_family a_size} { -height 10 \ -yscrollcommand [list $w.inner.family.sby set] rmsel_tag $w_family - ${NS}::scrollbar $w.inner.family.sby -command [list $w_family yview] + ttk::scrollbar $w.inner.family.sby -command [list $w_family yview] pack $w.inner.family.l -side top -fill x pack $w.inner.family.sby -side right -fill y pack $w_family -fill both -expand 1 - ${NS}::frame $w.inner.size - ${NS}::label $w.inner.size.l \ + ttk::frame $w.inner.size + ttk::label $w.inner.size.l \ -text [mc "Font Size"] \ -anchor w tspinbox $w.inner.size.v \ @@ -88,8 +87,8 @@ constructor pick {path title a_family a_size} { grid columnconfigure $w.inner 0 -weight 1 pack $w.inner -fill both -expand 1 -padx 5 -pady 5 - ${NS}::frame $w.example - ${NS}::label $w.example.l \ + ttk::frame $w.example + ttk::label $w.example.l \ -text [mc "Font Example"] \ -anchor w set w_example $w.example.t diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 5b361cc424..7e1462a20c 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -10,22 +10,12 @@ field w_next ; # Next button field w_quit ; # Quit button field o_cons ; # Console object (if active) -# Status mega-widget instance during _do_clone2 (used by _copy_files and -# _link_files). Widget is destroyed before _do_clone2 calls -# _do_clone_checkout -field o_status - -# Operation displayed by status mega-widget during _do_clone_checkout => -# _readtree_wait => _postcheckout_wait => _do_clone_submodules => -# _do_validate_submodule_cloning. The status mega-widget is a different -# instance than that stored in $o_status in earlier operations. -field o_status_op - field w_types ; # List of type buttons in clone field w_recentlist ; # Listbox containing recent repositories field w_localpath ; # Entry widget bound to local_path field done 0 ; # Finished picking the repository? +field clone_ok false ; # clone succeeeded field local_path {} ; # Where this repository is locally field origin_url {} ; # Where we are cloning from field origin_name origin ; # What we shall call 'origin' @@ -35,7 +25,7 @@ field readtree_err ; # Error output from read-tree (if any) field sorted_recent ; # recent repositories (sorted) constructor pick {} { - global M1T M1B use_ttk NS + global M1T M1B if {[set maxrecent [get_config gui.maxrecentrepo]] eq {}} { set maxrecent 10 @@ -88,7 +78,7 @@ constructor pick {} { set w_body $w.body set opts $w_body.options - ${NS}::frame $w_body + ttk::frame $w_body text $opts \ -cursor $::cursor_ptr \ -relief flat \ @@ -158,8 +148,8 @@ constructor pick {} { set lenrecent $maxrecent } - ${NS}::label $w_body.space - ${NS}::label $w_body.recentlabel \ + ttk::label $w_body.space + ttk::label $w_body.recentlabel \ -anchor w \ -text [mc "Open Recent Repository:"] set w_recentlist $w_body.recentlist @@ -199,10 +189,10 @@ constructor pick {} { } pack $w_body -fill x -padx 10 -pady 10 - ${NS}::frame $w.buttons + ttk::frame $w.buttons set w_next $w.buttons.next set w_quit $w.buttons.quit - ${NS}::button $w_quit \ + ttk::button $w_quit \ -text [mc "Quit"] \ -command exit pack $w_quit -side right -padx 5 @@ -303,10 +293,9 @@ method _open_recent_path {p} { } method _next {action} { - global NS destroy $w_body if {![winfo exists $w_next]} { - ${NS}::button $w_next -default active + ttk::button $w_next -default active set pos -before if {[tk windowingsystem] eq "win32"} { set pos -after } pack $w_next -side right -padx 5 $pos $w_quit @@ -323,7 +312,7 @@ method _write_local_path {args} { } method _git_init {} { - if {[catch {file mkdir $local_path} err]} { + if {[catch {git init $local_path} err]} { error_popup [strcat \ [mc "Failed to create repository %s:" $local_path] \ "\n\n$err"] @@ -337,13 +326,6 @@ method _git_init {} { return 0 } - if {[catch {git init} err]} { - error_popup [strcat \ - [mc "Failed to create repository %s:" $local_path] \ - "\n\n$err"] - return 0 - } - _append_recentrepos [pwd] set ::_gitdir .git set ::_prefix {} @@ -360,44 +342,29 @@ proc _is_git {path {outdir_var ""}} { return 1 } -proc _objdir {path} { - set objdir [file join $path .git objects] - if {[file isdirectory $objdir]} { - return $objdir - } - - set objdir [file join $path objects] - if {[file isdirectory $objdir]} { - return $objdir - } - - return {} -} - ###################################################################### ## ## Create New Repository method _do_new {} { - global use_ttk NS $w_next conf \ -state disabled \ -command [cb _do_new2] \ -text [mc "Create"] - ${NS}::frame $w_body - ${NS}::label $w_body.h \ + ttk::frame $w_body + ttk::label $w_body.h \ -font font_uibold -anchor center \ -text [mc "Create New Repository"] pack $w_body.h -side top -fill x -pady 10 pack $w_body -fill x -padx 10 - ${NS}::frame $w_body.where - ${NS}::label $w_body.where.l -text [mc "Directory:"] - ${NS}::entry $w_body.where.t \ + ttk::frame $w_body.where + ttk::label $w_body.where.l -text [mc "Directory:"] + ttk::entry $w_body.where.t \ -textvariable @local_path \ -width 50 - ${NS}::button $w_body.where.b \ + ttk::button $w_body.where.b \ -text [mc "Browse"] \ -command [cb _new_local_path] set w_localpath $w_body.where.t @@ -463,56 +430,55 @@ proc _new_ok {p} { ## Clone Existing Repository method _do_clone {} { - global use_ttk NS $w_next conf \ -state disabled \ -command [cb _do_clone2] \ -text [mc "Clone"] - ${NS}::frame $w_body - ${NS}::label $w_body.h \ + ttk::frame $w_body + ttk::label $w_body.h \ -font font_uibold -anchor center \ -text [mc "Clone Existing Repository"] pack $w_body.h -side top -fill x -pady 10 pack $w_body -fill x -padx 10 set args $w_body.args - ${NS}::frame $w_body.args + ttk::frame $w_body.args pack $args -fill both - ${NS}::label $args.origin_l -text [mc "Source Location:"] - ${NS}::entry $args.origin_t \ + ttk::label $args.origin_l -text [mc "Source Location:"] + ttk::entry $args.origin_t \ -textvariable @origin_url \ -width 50 - ${NS}::button $args.origin_b \ + ttk::button $args.origin_b \ -text [mc "Browse"] \ -command [cb _open_origin] grid $args.origin_l $args.origin_t $args.origin_b -sticky ew - ${NS}::label $args.where_l -text [mc "Target Directory:"] - ${NS}::entry $args.where_t \ + ttk::label $args.where_l -text [mc "Target Directory:"] + ttk::entry $args.where_t \ -textvariable @local_path \ -width 50 - ${NS}::button $args.where_b \ + ttk::button $args.where_b \ -text [mc "Browse"] \ -command [cb _new_local_path] grid $args.where_l $args.where_t $args.where_b -sticky ew set w_localpath $args.where_t - ${NS}::label $args.type_l -text [mc "Clone Type:"] - ${NS}::frame $args.type_f + ttk::label $args.type_l -text [mc "Clone Type:"] + ttk::frame $args.type_f set w_types [list] - lappend w_types [${NS}::radiobutton $args.type_f.hardlink \ + lappend w_types [ttk::radiobutton $args.type_f.hardlink \ -state disabled \ -text [mc "Standard (Fast, Semi-Redundant, Hardlinks)"] \ -variable @clone_type \ -value hardlink] - lappend w_types [${NS}::radiobutton $args.type_f.full \ + lappend w_types [ttk::radiobutton $args.type_f.full \ -state disabled \ -text [mc "Full Copy (Slower, Redundant Backup)"] \ -variable @clone_type \ -value full] - lappend w_types [${NS}::radiobutton $args.type_f.shared \ + lappend w_types [ttk::radiobutton $args.type_f.shared \ -state disabled \ -text [mc "Shared (Fastest, Not Recommended, No Backup)"] \ -variable @clone_type \ @@ -520,7 +486,7 @@ method _do_clone {} { foreach r $w_types { pack $r -anchor w } - ${NS}::checkbutton $args.type_f.recursive \ + ttk::checkbutton $args.type_f.recursive \ -text [mc "Recursively clone submodules too"] \ -variable @recursive \ -onvalue true -offvalue false @@ -588,6 +554,25 @@ method _update_clone {args} { method _do_clone2 {} { if {[file isdirectory $origin_url]} { set origin_url [file normalize $origin_url] + if {$clone_type eq {hardlink}} { + # cannot use hardlinks if this is a linked worktree (.gitfile or git-new-workdir) + if {[git -C $origin_url rev-parse --is-inside-work-tree] == {true}} { + set islink 0 + set dotgit [file join $origin_url .git] + if {[file isfile $dotgit]} { + set islink 1 + } else { + set objdir [file join $dotgit objects] + if {[file exists $objdir] && [file type $objdir] == {link}} { + set islink 1 + } + } + if {$islink} { + info_popup [mc "Hardlinks are unavailable. Falling back to copying."] + set clone_type full + } + } + } } if {$clone_type eq {hardlink} && ![file isdirectory $origin_url]} { @@ -599,14 +584,6 @@ method _do_clone2 {} { return } - if {$clone_type eq {hardlink} || $clone_type eq {shared}} { - set objdir [_objdir $origin_url] - if {$objdir eq {}} { - error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] - return - } - } - set giturl $origin_url if {[file exists $local_path]} { @@ -614,459 +591,86 @@ method _do_clone2 {} { return } - if {![_git_init $this]} return - set local_path [pwd] - - if {[catch { - git config remote.$origin_name.url $giturl - git config remote.$origin_name.fetch +refs/heads/*:refs/remotes/$origin_name/* - } err]} { - error_popup [strcat [mc "Failed to configure origin"] "\n\n$err"] - return + set clone_options {--progress} + if {$recursive} { + append clone_options { --recurse-submodules} } destroy $w_body $w_next switch -exact -- $clone_type { - hardlink { - set o_status [status_bar::two_line $w_body] - pack $w_body -fill x -padx 10 -pady 10 - - set status_op [$o_status start \ - [mc "Counting objects"] \ - [mc "buckets"]] - update - - if {[file exists [file join $objdir info alternates]]} { - set pwd [pwd] - if {[catch { - file mkdir [gitdir objects info] - set f_in [safe_open_file [file join $objdir info alternates] r] - set f_cp [safe_open_file [gitdir objects info alternates] w] - fconfigure $f_in -translation binary -encoding binary - fconfigure $f_cp -translation binary -encoding binary - cd $objdir - while {[gets $f_in line] >= 0} { - puts $f_cp [file normalize $line] - } - close $f_in - close $f_cp - cd $pwd - } err]} { - catch {cd $pwd} - _clone_failed $this [mc "Unable to copy objects/info/alternates: %s" $err] - $status_op stop - return - } + full { + append clone_options { --no-hardlinks --no-local} } - - set tolink [list] - set buckets [glob \ - -tails \ - -nocomplain \ - -directory [file join $objdir] ??] - set bcnt [expr {[llength $buckets] + 2}] - set bcur 1 - $status_op update $bcur $bcnt - update - - file mkdir [file join .git objects pack] - foreach i [glob -tails -nocomplain \ - -directory [file join $objdir pack] *] { - lappend tolink [file join pack $i] - } - $status_op update [incr bcur] $bcnt - update - - foreach i $buckets { - file mkdir [file join .git objects $i] - foreach j [glob -tails -nocomplain \ - -directory [file join $objdir $i] *] { - lappend tolink [file join $i $j] - } - $status_op update [incr bcur] $bcnt - update - } - $status_op stop - - if {$tolink eq {}} { - info_popup [strcat \ - [mc "Nothing to clone from %s." $origin_url] \ - "\n" \ - [mc "The 'master' branch has not been initialized."] \ - ] - destroy $w_body - set done 1 - return - } - - set i [lindex $tolink 0] - if {[catch { - file link -hard \ - [file join .git objects $i] \ - [file join $objdir $i] - } err]} { - info_popup [mc "Hardlinks are unavailable. Falling back to copying."] - set i [_copy_files $this $objdir $tolink] - } else { - set i [_link_files $this $objdir [lrange $tolink 1 end]] + shared { + append clone_options { --shared} } - if {!$i} return - - destroy $w_body - - set o_status {} } - full { + + if {[catch { set o_cons [console::embed \ $w_body \ [mc "Cloning from %s" $origin_url]] pack $w_body -fill both -expand 1 -padx 10 $o_cons exec \ - [list git fetch --no-tags -k $origin_name] \ - [cb _do_clone_tags] - } - shared { - set fd [safe_open_file [gitdir objects info alternates] w] - fconfigure $fd -translation binary - puts $fd $objdir - close $fd - } - } - - if {$clone_type eq {hardlink} || $clone_type eq {shared}} { - if {![_clone_refs $this]} return - set pwd [pwd] - if {[catch { - cd $origin_url - set HEAD [git rev-parse --verify HEAD^0] - } err]} { - _clone_failed $this [mc "Not a Git repository: %s" [file tail $origin_url]] - return 0 - } - cd $pwd - _do_clone_checkout $this $HEAD - } -} - -method _copy_files {objdir tocopy} { - set status_op [$o_status start \ - [mc "Copying objects"] \ - [mc "KiB"]] - set tot 0 - set cmp 0 - foreach p $tocopy { - incr tot [file size [file join $objdir $p]] - } - foreach p $tocopy { - if {[catch { - set f_in [safe_open_file [file join $objdir $p] r] - set f_cp [safe_open_file [file join .git objects $p] w] - fconfigure $f_in -translation binary -encoding binary - fconfigure $f_cp -translation binary -encoding binary - - while {![eof $f_in]} { - incr cmp [fcopy $f_in $f_cp -size 16384] - $status_op update \ - [expr {$cmp / 1024}] \ - [expr {$tot / 1024}] - update - } - - close $f_in - close $f_cp - } err]} { - _clone_failed $this [mc "Unable to copy object: %s" $err] - $status_op stop - return 0 - } - } - $status_op stop - return 1 -} - -method _link_files {objdir tolink} { - set total [llength $tolink] - set status_op [$o_status start \ - [mc "Linking objects"] \ - [mc "objects"]] - for {set i 0} {$i < $total} {} { - set p [lindex $tolink $i] - if {[catch { - file link -hard \ - [file join .git objects $p] \ - [file join $objdir $p] - } err]} { - _clone_failed $this [mc "Unable to hardlink object: %s" $err] - $status_op stop - return 0 - } - - incr i - if {$i % 5 == 0} { - $status_op update $i $total - update - } - } - $status_op stop - return 1 -} - -method _clone_refs {} { - set pwd [pwd] - if {[catch {cd $origin_url} err]} { - error_popup [mc "Not a Git repository: %s" [file tail $origin_url]] - return 0 - } - set fd_in [git_read [list for-each-ref \ - --tcl \ - {--format=list %(refname) %(objectname) %(*objectname)}]] - cd $pwd - - set fd [safe_open_file [gitdir packed-refs] w] - fconfigure $fd -translation binary - puts $fd "# pack-refs with: peeled" - while {[gets $fd_in line] >= 0} { - set line [eval $line] - set refn [lindex $line 0] - set robj [lindex $line 1] - set tobj [lindex $line 2] - - if {[regsub ^refs/heads/ $refn \ - "refs/remotes/$origin_name/" refn]} { - puts $fd "$robj $refn" - } elseif {[string match refs/tags/* $refn]} { - puts $fd "$robj $refn" - if {$tobj ne {}} { - puts $fd "^$tobj" - } - } - } - close $fd_in - close $fd - return 1 -} - -method _do_clone_tags {ok} { - if {$ok} { - $o_cons exec \ - [list git fetch --tags -k $origin_name] \ - [cb _do_clone_HEAD] - } else { - $o_cons done $ok - _clone_failed $this [mc "Cannot fetch branches and objects. See console output for details."] + [list git clone {*}$clone_options $origin_url $local_path] \ + [cb _do_clone2_done] + } err]} { + error_popup [strcat [mc "Clone failed."] "\n" $err] + return } -} -method _do_clone_HEAD {ok} { - if {$ok} { - $o_cons exec \ - [list git fetch $origin_name HEAD] \ - [cb _do_clone_full_end] - } else { - $o_cons done $ok - _clone_failed $this [mc "Cannot fetch tags. See console output for details."] + tkwait variable @done + if {!$clone_ok} { + error_popup [mc "Clone failed."] + return } } -method _do_clone_full_end {ok} { +method _do_clone2_done {ok} { $o_cons done $ok - if {$ok} { - destroy $w_body - - set HEAD {} - if {[file exists [gitdir FETCH_HEAD]]} { - set fd [safe_open_file [gitdir FETCH_HEAD] r] - while {[gets $fd line] >= 0} { - if {[regexp "^(.{40})\t\t" $line line HEAD]} { - break - } - } - close $fd - } - - catch {git pack-refs} - _do_clone_checkout $this $HEAD - } else { - _clone_failed $this [mc "Cannot determine HEAD. See console output for details."] - } -} - -method _clone_failed {{why {}}} { - if {[catch {file delete -force $local_path} err]} { - set why [strcat \ - $why \ - "\n\n" \ - [mc "Unable to cleanup %s" $local_path] \ - "\n\n" \ - $err] - } - if {$why ne {}} { - update - error_popup [strcat [mc "Clone failed."] "\n" $why] - } -} - -method _do_clone_checkout {HEAD} { - if {$HEAD eq {}} { - info_popup [strcat \ - [mc "No default branch obtained."] \ - "\n" \ - [mc "The 'master' branch has not been initialized."] \ - ] - set done 1 - return - } - if {[catch { - git update-ref HEAD $HEAD^0 + if {[catch { + cd $local_path + set ::_gitdir .git + set ::_prefix {} + _append_recentrepos [pwd] } err]} { - info_popup [strcat \ - [mc "Cannot resolve %s as a commit." $HEAD^0] \ - "\n $err" \ - "\n" \ - [mc "The 'master' branch has not been initialized."] \ - ] - set done 1 - return - } - - set status [status_bar::two_line $w_body] - pack $w_body -fill x -padx 10 -pady 10 - - # We start the status operation here. - # - # This function calls _readtree_wait as a callback. - # - # _readtree_wait in turn either calls _do_clone_submodules directly, - # or calls _postcheckout_wait as a callback which then calls - # _do_clone_submodules. - # - # _do_clone_submodules calls _do_validate_submodule_cloning. - # - # _do_validate_submodule_cloning stops the status operation. - # - # There are no other calls into this chain from other code. - - set o_status_op [$status start \ - [mc "Creating working directory"] \ - [mc "files"]] - - set readtree_err {} - set fd [git_read [list read-tree \ - -m \ - -u \ - -v \ - HEAD \ - HEAD \ - ] \ - [list 2>@1]] - fconfigure $fd -blocking 0 -translation binary - fileevent $fd readable [cb _readtree_wait $fd] -} - -method _readtree_wait {fd} { - set buf [read $fd] - $o_status_op update_meter $buf - append readtree_err $buf - - fconfigure $fd -blocking 1 - if {![eof $fd]} { - fconfigure $fd -blocking 0 - return - } - - if {[catch {close $fd}]} { - set err $readtree_err - regsub {^fatal: } $err {} err - error_popup [strcat \ - [mc "Initial file checkout failed."] \ - "\n\n$err"] - return - } - - # -- Run the post-checkout hook. - # - set fd_ph [githook_read post-checkout [string repeat 0 40] \ - [git rev-parse HEAD] 1] - if {$fd_ph ne {}} { - global pch_error - set pch_error {} - fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} - fileevent $fd_ph readable [cb _postcheckout_wait $fd_ph] - } else { - _do_clone_submodules $this - } -} - -method _postcheckout_wait {fd_ph} { - global pch_error - - append pch_error [read $fd_ph] - fconfigure $fd_ph -blocking 1 - if {[eof $fd_ph]} { - if {[catch {close $fd_ph}]} { - hook_failed_popup post-checkout $pch_error 0 + set ok 0 } - unset pch_error - _do_clone_submodules $this - return } - fconfigure $fd_ph -blocking 0 -} - -method _do_clone_submodules {} { - if {$recursive eq {true}} { - $o_status_op stop - set o_status_op {} - - destroy $w_body - - set o_cons [console::embed \ - $w_body \ - [mc "Cloning submodules"]] - pack $w_body -fill both -expand 1 -padx 10 - $o_cons exec \ - [list git submodule update --init --recursive] \ - [cb _do_validate_submodule_cloning] - } else { - set done 1 + if {!$ok} { + set ::_gitdir {} + set ::_prefix {} } + set clone_ok $ok + set done 1 } -method _do_validate_submodule_cloning {ok} { - if {$ok} { - $o_cons done $ok - set done 1 - } else { - _clone_failed $this [mc "Cannot clone submodules."] - } -} ###################################################################### ## ## Open Existing Repository method _do_open {} { - global NS $w_next conf \ -state disabled \ -command [cb _do_open2] \ -text [mc "Open"] - ${NS}::frame $w_body - ${NS}::label $w_body.h \ + ttk::frame $w_body + ttk::label $w_body.h \ -font font_uibold -anchor center \ -text [mc "Open Existing Repository"] pack $w_body.h -side top -fill x -pady 10 pack $w_body -fill x -padx 10 - ${NS}::frame $w_body.where - ${NS}::label $w_body.where.l -text [mc "Repository:"] - ${NS}::entry $w_body.where.t \ + ttk::frame $w_body.where + ttk::label $w_body.where.l -text [mc "Repository:"] + ttk::entry $w_body.where.t \ -textvariable @local_path \ -width 50 - ${NS}::button $w_body.where.b \ + ttk::button $w_body.where.b \ -text [mc "Browse"] \ -command [cb _open_local_path] diff --git a/git-gui/lib/choose_rev.tcl b/git-gui/lib/choose_rev.tcl index 8ae7e8a5c4..cd355cc92a 100644 --- a/git-gui/lib/choose_rev.tcl +++ b/git-gui/lib/choose_rev.tcl @@ -32,7 +32,7 @@ proc new_unmerged {path {title {}}} { } constructor _new {path unmerged_only title} { - global current_branch is_detached use_ttk NS + global current_branch is_detached if {![info exists ::all_remotes]} { load_all_remotes @@ -41,65 +41,60 @@ constructor _new {path unmerged_only title} { set w $path if {$title ne {}} { - ${NS}::labelframe $w -text $title + ttk::labelframe $w -text $title } else { - ${NS}::frame $w + ttk::frame $w } bind $w <Destroy> [cb _delete %W] if {$is_detached} { - ${NS}::radiobutton $w.detachedhead_r \ + ttk::radiobutton $w.detachedhead_r \ -text [mc "This Detached Checkout"] \ -value HEAD \ -variable @revtype - if {!$use_ttk} {$w.detachedhead_r configure -anchor w} grid $w.detachedhead_r -sticky we -padx {0 5} -columnspan 2 } - ${NS}::radiobutton $w.expr_r \ + ttk::radiobutton $w.expr_r \ -text [mc "Revision Expression:"] \ -value expr \ -variable @revtype - ${NS}::entry $w.expr_t \ + ttk::entry $w.expr_t \ -width 50 \ -textvariable @c_expr \ -validate key \ -validatecommand [cb _validate %d %S] grid $w.expr_r $w.expr_t -sticky we -padx {0 5} - ${NS}::frame $w.types - ${NS}::radiobutton $w.types.head_r \ + ttk::frame $w.types + ttk::radiobutton $w.types.head_r \ -text [mc "Local Branch"] \ -value head \ -variable @revtype pack $w.types.head_r -side left - ${NS}::radiobutton $w.types.trck_r \ + ttk::radiobutton $w.types.trck_r \ -text [mc "Tracking Branch"] \ -value trck \ -variable @revtype pack $w.types.trck_r -side left - ${NS}::radiobutton $w.types.tag_r \ + ttk::radiobutton $w.types.tag_r \ -text [mc "Tag"] \ -value tag \ -variable @revtype pack $w.types.tag_r -side left set w_filter $w.types.filter - ${NS}::entry $w_filter \ + ttk::entry $w_filter \ -width 12 \ -textvariable @filter \ -validate key \ -validatecommand [cb _filter %P] pack $w_filter -side right - pack [${NS}::label $w.types.filter_icon \ + pack [ttk::label $w.types.filter_icon \ -image ::choose_rev::img_find \ ] -side right grid $w.types -sticky we -padx {0 5} -columnspan 2 - if {$use_ttk} { - ttk::frame $w.list -style SListbox.TFrame -padding 2 - } else { - frame $w.list - } + ttk::frame $w.list -style SListbox.TFrame -padding 2 set w_list $w.list.l listbox $w_list \ -font font_diff \ @@ -109,9 +104,7 @@ constructor _new {path unmerged_only title} { -exportselection false \ -xscrollcommand [cb _sb_set $w.list.sbx h] \ -yscrollcommand [cb _sb_set $w.list.sby v] - if {$use_ttk} { - $w_list configure -relief flat -highlightthickness 0 -borderwidth 0 - } + $w_list configure -relief flat -highlightthickness 0 -borderwidth 0 pack $w_list -fill both -expand 1 grid $w.list -sticky nswe -padx {20 5} -columnspan 2 bind $w_list <Any-Motion> [cb _show_tooltip @%x,%y] @@ -154,7 +147,7 @@ constructor _new {path unmerged_only title} { refs/remotes \ refs/tags \ ]] - fconfigure $fr_fd -translation lf -encoding utf-8 + fconfigure $fr_fd -encoding utf-8 while {[gets $fr_fd line] > 0} { set line [eval $line] if {[lindex $line 1 0] eq {tag}} { @@ -238,12 +231,10 @@ constructor _new {path unmerged_only title} { } method none {text} { - global NS use_ttk if {![winfo exists $w.none_r]} { - ${NS}::radiobutton $w.none_r \ + ttk::radiobutton $w.none_r \ -value none \ -variable @revtype - if {!$use_ttk} {$w.none_r configure -anchor w} grid $w.none_r -sticky we -padx {0 5} -columnspan 2 } $w.none_r configure -text $text @@ -429,7 +420,6 @@ method _delete {current} { } method _sb_set {sb orient first last} { - global NS set old_focus [focus -lastfor $w] if {$first == 0 && $last == 1} { @@ -445,10 +435,10 @@ method _sb_set {sb orient first last} { if {![winfo exists $sb]} { if {$orient eq {h}} { - ${NS}::scrollbar $sb -orient h -command [list $w_list xview] + ttk::scrollbar $sb -orient h -command [list $w_list xview] pack $sb -fill x -side bottom -before $w_list } else { - ${NS}::scrollbar $sb -orient v -command [list $w_list yview] + ttk::scrollbar $sb -orient v -command [list $w_list yview] pack $sb -fill y -side right -before $w_list } if {$old_focus ne {}} { @@ -580,7 +570,7 @@ method _reflog_last {name} { set last {} if {[catch {set last [file mtime [gitdir $name]]}] && ![catch {set g [safe_open_file [gitdir logs $name] r]}]} { - fconfigure $g -translation binary + fconfigure $g -encoding iso8859-1 while {[gets $g line] >= 0} { if {[regexp {> ([1-9][0-9]*) } $line line when]} { set last $when diff --git a/git-gui/lib/class.tcl b/git-gui/lib/class.tcl index f08506f383..0b1e67103f 100644 --- a/git-gui/lib/class.tcl +++ b/git-gui/lib/class.tcl @@ -136,7 +136,6 @@ proc delete_this {{t {}}} { proc make_dialog {t w args} { upvar $t top $w pfx this this - global use_ttk uplevel [linsert $args 0 make_toplevel $t $w] catch {wm attributes $top -type dialog} pave_toplevel $pfx diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl index 60d66172a1..89eb8c7b73 100644 --- a/git-gui/lib/commit.tcl +++ b/git-gui/lib/commit.tcl @@ -28,7 +28,7 @@ You are currently in the middle of a merge that has not been fully completed. Y set name "" set email "" set fd [git_read [list cat-file commit $curHEAD]] - fconfigure $fd -encoding binary -translation lf + fconfigure $fd -encoding iso8859-1 # By default commits are assumed to be in utf-8 set enc utf-8 while {[gets $fd line] > 0} { @@ -43,9 +43,9 @@ You are currently in the middle of a merge that has not been fully completed. Y set enc [tcl_encoding $enc] if {$enc ne {}} { - set msg [encoding convertfrom $enc $msg] - set name [encoding convertfrom $enc $name] - set email [encoding convertfrom $enc $email] + set msg [convertfrom $enc $msg] + set name [convertfrom $enc $name] + set email [convertfrom $enc $email] } if {$name ne {} && $email ne {}} { set commit_author [list name $name email $email date $time] @@ -208,30 +208,6 @@ You must stage at least 1 file before you can commit. # -- A message is required. # set msg [$ui_comm get 1.0 end] - # Strip trailing whitespace - regsub -all -line {[ \t\r]+$} $msg {} msg - # Strip comment lines - global comment_string - set cmt_rx [strcat {(^|\n)} [regsub -all {\W} $comment_string {\\&}] {[^\n]*}] - regsub -all $cmt_rx $msg {\1} msg - # Strip leading empty lines - regsub {^\n*} $msg {} msg - # Compress consecutive empty lines - regsub -all {\n{3,}} $msg "\n\n" msg - # Strip trailing empty line - regsub {\n\n$} $msg "\n" msg - if {$msg eq {}} { - error_popup [mc "Please supply a commit message. - -A good commit message has the following format: - -- First line: Describe in one sentence what you did. -- Second line: Blank -- Remaining lines: Describe why this change is good. -"] - unlock_index - return - } # -- Build the message file. # @@ -254,7 +230,7 @@ A good commit message has the following format: ui_status [mc "Calling pre-commit hook..."] set pch_error {} - fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fconfigure $fd_ph -blocking 0 -translation binary fileevent $fd_ph readable \ [list commit_prehook_wait $fd_ph $curHEAD $msg_p] } @@ -309,7 +285,7 @@ Do you really want to proceed with your Commit?"] ui_status [mc "Calling commit-msg hook..."] set pch_error {} - fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fconfigure $fd_ph -blocking 0 -translation binary fileevent $fd_ph readable \ [list commit_commitmsg_wait $fd_ph $curHEAD $msg_p] } @@ -334,7 +310,52 @@ proc commit_commitmsg_wait {fd_ph curHEAD msg_p} { fconfigure $fd_ph -blocking 0 } +proc wash_commit_message {msg} { + # Strip trailing whitespace + regsub -all -line {[ \t\r]+$} $msg {} msg + # Strip comment lines + global comment_string + set cmt_rx [strcat {(^|\n)} [regsub -all {\W} $comment_string {\\&}] {[^\n]*}] + regsub -all $cmt_rx $msg {\1} msg + # Strip leading and trailing empty lines (puts adds one \n) + set msg [string trim $msg \n] + # Compress consecutive empty lines + regsub -all {\n{3,}} $msg \n\n msg + + return $msg +} + proc commit_writetree {curHEAD msg_p} { + # -- Process the commit message after hooks have run. + # + set msg_fd [safe_open_file $msg_p r] + setup_commit_encoding $msg_fd 1 + set msg [read $msg_fd] + close $msg_fd + + # Process the message (strip whitespace, comments, etc.) + set msg [wash_commit_message $msg] + + if {$msg eq {}} { + error_popup [mc "Please supply a commit message. + +A good commit message has the following format: + +- First line: Describe in one sentence what you did. +- Second line: Blank +- Remaining lines: Describe why this change is good. +"] + unlock_index + return + } + + # Write the processed message back to the file + set msg_wt [safe_open_file $msg_p w] + fconfigure $msg_wt -translation lf + setup_commit_encoding $msg_wt + puts $msg_wt $msg + close $msg_wt + ui_status [mc "Committing changes..."] set fd_wt [git_read [list write-tree]] fileevent $fd_wt readable \ @@ -348,6 +369,7 @@ proc commit_committree {fd_wt curHEAD msg_p} { global file_states selected_paths rescan_active global repo_config global env + global hashlength gets $fd_wt tree_id if {[catch {close $fd_wt} err]} { @@ -362,12 +384,12 @@ proc commit_committree {fd_wt curHEAD msg_p} { # if {$commit_type eq {normal}} { set fd_ot [git_read [list cat-file commit $PARENT]] - fconfigure $fd_ot -encoding binary -translation lf + fconfigure $fd_ot -encoding iso8859-1 set old_tree [gets $fd_ot] close $fd_ot if {[string equal -length 5 {tree } $old_tree] - && [string length $old_tree] == 45} { + && [string length $old_tree] == [expr {$hashlength + 5}]} { set old_tree [string range $old_tree 5 end] } else { error [mc "Commit %s appears to be corrupt" $PARENT] @@ -461,7 +483,7 @@ A rescan will be automatically started now. if {$fd_ph ne {}} { global pch_error set pch_error {} - fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fconfigure $fd_ph -blocking 0 -translation binary fileevent $fd_ph readable \ [list commit_postcommit_wait $fd_ph $cmt_id] } diff --git a/git-gui/lib/console.tcl b/git-gui/lib/console.tcl index a017cfeadd..267699408c 100644 --- a/git-gui/lib/console.tcl +++ b/git-gui/lib/console.tcl @@ -27,20 +27,20 @@ constructor embed {path title} { } method _init {} { - global M1B use_ttk NS + global M1B if {$is_toplevel} { make_dialog top w -autodelete 0 wm title $top "[appname] ([reponame]): $t_short" } else { - ${NS}::frame $w + ttk::frame $w } set console_cr 1.0 set w_t $w.m.t - ${NS}::frame $w.m - ${NS}::label $w.m.l1 \ + ttk::frame $w.m + ttk::label $w.m.l1 \ -textvariable @t_long \ -anchor w \ -justify left \ @@ -78,7 +78,7 @@ method _init {} { " if {$is_toplevel} { - ${NS}::button $w.ok -text [mc "Close"] \ + ttk::button $w.ok -text [mc "Close"] \ -state disabled \ -command [list destroy $w] pack $w.ok -side bottom -anchor e -pady 10 -padx 10 @@ -207,14 +207,13 @@ method done {ok} { } method _sb_set {sb orient first last} { - global NS if {![winfo exists $sb]} { if {$first == $last || ($first == 0 && $last == 1)} return if {$orient eq {h}} { - ${NS}::scrollbar $sb -orient h -command [list $w_t xview] + ttk::scrollbar $sb -orient h -command [list $w_t xview] pack $sb -fill x -side bottom -before $w_t } else { - ${NS}::scrollbar $sb -orient v -command [list $w_t yview] + ttk::scrollbar $sb -orient v -command [list $w_t yview] pack $sb -fill y -side right -before $w_t } } diff --git a/git-gui/lib/database.tcl b/git-gui/lib/database.tcl index 1fc0ea00b3..78732d8651 100644 --- a/git-gui/lib/database.tcl +++ b/git-gui/lib/database.tcl @@ -2,7 +2,6 @@ # Copyright (C) 2006, 2007 Shawn Pearce proc do_stats {} { - global use_ttk NS set fd [git_read [list count-objects -v]] while {[gets $fd line] > 0} { if {[regexp {^([^:]+): (\d+)$} $line _ name value]} { @@ -26,18 +25,18 @@ proc do_stats {} { wm withdraw $w wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.close -text [mc Close] \ + ttk::frame $w.buttons + ttk::button $w.buttons.close -text [mc Close] \ -default active \ -command [list destroy $w] - ${NS}::button $w.buttons.gc -text [mc "Compress Database"] \ + ttk::button $w.buttons.gc -text [mc "Compress Database"] \ -default normal \ -command "destroy $w;do_gc" pack $w.buttons.close -side right pack $w.buttons.gc -side left pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::labelframe $w.stat -text [mc "Database Statistics"] + ttk::labelframe $w.stat -text [mc "Database Statistics"] foreach s { {count {mc "Number of loose objects"}} {size {mc "Disk space used by loose objects"} { KiB}} @@ -54,8 +53,8 @@ proc do_stats {} { set value "$value[lindex $s 2]" } - ${NS}::label $w.stat.l_$name -text [mc "%s:" $label] -anchor w - ${NS}::label $w.stat.v_$name -text $value -anchor w + ttk::label $w.stat.l_$name -text [mc "%s:" $label] -anchor w + ttk::label $w.stat.v_$name -text $value -anchor w grid $w.stat.l_$name $w.stat.v_$name -sticky we -padx {0 5} } pack $w.stat -pady 10 -padx 10 diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl index 84f0468c7c..442737ba4f 100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@ -2,15 +2,13 @@ # Copyright (C) 2006, 2007 Shawn Pearce proc apply_tab_size {{firsttab {}}} { - global have_tk85 repo_config ui_diff + global repo_config ui_diff set w [font measure font_diff "0"] - if {$have_tk85 && $firsttab != 0} { + if {$firsttab != 0} { $ui_diff configure -tabs [list [expr {$firsttab * $w}] [expr {($firsttab + $repo_config(gui.tabsize)) * $w}]] - } elseif {$have_tk85 || $repo_config(gui.tabsize) != 8} { - $ui_diff configure -tabs [expr {$repo_config(gui.tabsize) * $w}] } else { - $ui_diff configure -tabs {} + $ui_diff configure -tabs [expr {$repo_config(gui.tabsize) * $w}] } } @@ -193,7 +191,6 @@ proc show_other_diff {path w m cont_info} { file { set fd [safe_open_file $path r] fconfigure $fd \ - -eofchar {} \ -encoding [get_path_encoding $path] set content [read $fd $max_sz] close $fd @@ -280,9 +277,7 @@ proc start_show_diff {cont_info {add_opts {}}} { if {$w eq $ui_index} { lappend cmd diff-index lappend cmd --cached - if {[git-version >= "1.7.2"]} { - lappend cmd --ignore-submodules=dirty - } + lappend cmd --ignore-submodules=dirty } elseif {$w eq $ui_workdir} { if {[string first {U} $m] >= 0} { lappend cmd diff @@ -290,17 +285,14 @@ proc start_show_diff {cont_info {add_opts {}}} { lappend cmd diff-files } } - if {![is_config_false gui.textconv] && [git-version >= 1.6.1]} { + if {![is_config_false gui.textconv]} { lappend cmd --textconv } if {[string match {160000 *} [lindex $s 2]] || [string match {160000 *} [lindex $s 3]]} { set is_submodule_diff 1 - - if {[git-version >= "1.6.6"]} { - lappend cmd --submodule - } + lappend cmd --submodule } lappend cmd -p @@ -319,14 +311,6 @@ proc start_show_diff {cont_info {add_opts {}}} { lappend cmd $path } - if {$is_submodule_diff && [git-version < "1.6.6"]} { - if {$w eq $ui_index} { - set cmd [list submodule summary --cached -- $path] - } else { - set cmd [list submodule summary --files -- $path] - } - } - if {[catch {set fd [git_read_nice $cmd]} err]} { set diff_active 0 unlock_index @@ -340,6 +324,8 @@ proc start_show_diff {cont_info {add_opts {}}} { # '++' lines which is not bijective. Thus, we need to maintain a state # across lines. set ::conflict_in_pre_image 0 + + # git-diff has eol==\n, \r if present is part of the text fconfigure $fd \ -blocking 0 \ -encoding [get_path_encoding $path] \ diff --git a/git-gui/lib/error.tcl b/git-gui/lib/error.tcl index 8968a57f33..fc0b5ad5e0 100644 --- a/git-gui/lib/error.tcl +++ b/git-gui/lib/error.tcl @@ -71,13 +71,12 @@ proc ask_popup {msg} { } proc hook_failed_popup {hook msg {is_fatal 1}} { - global use_ttk NS set w .hookfail Dialog $w wm withdraw $w - ${NS}::frame $w.m - ${NS}::label $w.m.l1 -text [mc "%s hook failed:" $hook] \ + ttk::frame $w.m + ttk::label $w.m.l1 -text [mc "%s hook failed:" $hook] \ -anchor w \ -justify left \ -font font_uibold @@ -89,10 +88,10 @@ proc hook_failed_popup {hook msg {is_fatal 1}} { -width 80 -height 10 \ -font font_diff \ -yscrollcommand [list $w.m.sby set] - ${NS}::scrollbar $w.m.sby -command [list $w.m.t yview] + ttk::scrollbar $w.m.sby -command [list $w.m.t yview] pack $w.m.l1 -side top -fill x if {$is_fatal} { - ${NS}::label $w.m.l2 \ + ttk::label $w.m.l2 \ -text [mc "You must correct the above errors before committing."] \ -anchor w \ -justify left \ @@ -106,7 +105,7 @@ proc hook_failed_popup {hook msg {is_fatal 1}} { $w.m.t insert 1.0 $msg $w.m.t conf -state disabled - ${NS}::button $w.ok -text OK \ + ttk::button $w.ok -text OK \ -width 15 \ -command "destroy $w" pack $w.ok -side bottom -anchor e -pady 10 -padx 10 diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl index 857864ff2b..7aa09c7728 100644 --- a/git-gui/lib/index.tcl +++ b/git-gui/lib/index.tcl @@ -22,8 +22,6 @@ proc _close_updateindex {fd} { } proc rescan_on_error {err {after {}}} { - global use_ttk NS - set w .indexfried Dialog $w wm withdraw $w @@ -35,14 +33,14 @@ proc rescan_on_error {err {after {}}} { -borderwidth 0 -highlightthickness 0 \ -background [get_bg_color $w] $w.msg tag configure bold -font font_uibold -justify center - ${NS}::scrollbar $w.vs -command [list $w.msg yview] + ttk::scrollbar $w.vs -command [list $w.msg yview] $w.msg insert end $s bold \n\n$err {} $w.msg configure -state disabled - ${NS}::button $w.continue \ + ttk::button $w.continue \ -text [mc "Continue"] \ -command [list destroy $w] - ${NS}::button $w.unlock \ + ttk::button $w.unlock \ -text [mc "Unlock Index"] \ -command "destroy $w; _delete_indexlock" grid $w.msg - $w.vs -sticky news @@ -80,7 +78,6 @@ proc update_indexinfo {msg path_list after} { -blocking 0 \ -buffering full \ -buffersize 512 \ - -encoding binary \ -translation binary fileevent $fd writable [list \ write_update_indexinfo \ @@ -149,7 +146,6 @@ proc update_index {msg path_list after} { -blocking 0 \ -buffering full \ -buffersize 512 \ - -encoding binary \ -translation binary fileevent $fd writable [list \ write_update_index \ @@ -229,7 +225,6 @@ proc checkout_index {msg path_list after capture_error} { -blocking 0 \ -buffering full \ -buffersize 512 \ - -encoding binary \ -translation binary fileevent $fd writable [list \ write_checkout_index \ diff --git a/git-gui/lib/line.tcl b/git-gui/lib/line.tcl index a026de954c..5980ae805c 100644 --- a/git-gui/lib/line.tcl +++ b/git-gui/lib/line.tcl @@ -9,18 +9,17 @@ field ctext field linenum {} constructor new {i_w i_text args} { - global use_ttk NS set w $i_w set ctext $i_text - ${NS}::frame $w - ${NS}::label $w.l -text [mc "Goto Line:"] + ttk::frame $w + ttk::label $w.l -text [mc "Goto Line:"] tentry $w.ent \ -textvariable ${__this}::linenum \ -background lightgreen \ -validate key \ -validatecommand [cb _validate %P] - ${NS}::button $w.bn -text [mc Go] -command [cb _goto] + ttk::button $w.bn -text [mc Go] -command [cb _goto] pack $w.l -side left pack $w.bn -side right diff --git a/git-gui/lib/merge.tcl b/git-gui/lib/merge.tcl index 44c3f93584..3490beddae 100644 --- a/git-gui/lib/merge.tcl +++ b/git-gui/lib/merge.tcl @@ -112,16 +112,7 @@ method _start {} { close $fh set _last_merged_branch $branch - if {[git-version >= "2.5.0"]} { - set cmd [list git merge --strategy=recursive FETCH_HEAD] - } else { - set cmd [list git] - lappend cmd merge - lappend cmd --strategy=recursive - lappend cmd [git_redir [list fmt-merge-msg] [list <[gitdir FETCH_HEAD]]] - lappend cmd HEAD - lappend cmd $name - } + set cmd [list git merge --strategy=recursive FETCH_HEAD] ui_status [mc "Merging %s and %s..." $current_branch $stitle] set cons [console::new [mc "Merge"] "merge $stitle"] @@ -145,7 +136,7 @@ method _finish {cons ok} { constructor dialog {} { global current_branch - global M1B use_ttk NS + global M1B if {![_can_merge $this]} { delete_this @@ -160,21 +151,21 @@ constructor dialog {} { set _start [cb _start] - ${NS}::label $w.header \ + ttk::label $w.header \ -text [mc "Merge Into %s" $current_branch] \ -font font_uibold pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.visualize \ + ttk::frame $w.buttons + ttk::button $w.buttons.visualize \ -text [mc Visualize] \ -command [cb _visualize] pack $w.buttons.visualize -side left - ${NS}::button $w.buttons.merge \ + ttk::button $w.buttons.merge \ -text [mc Merge] \ -command $_start pack $w.buttons.merge -side right - ${NS}::button $w.buttons.cancel \ + ttk::button $w.buttons.cancel \ -text [mc "Cancel"] \ -command [cb _cancel] pack $w.buttons.cancel -side right -padx 5 diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl index 2c9bb3af40..44be4ed3ff 100644 --- a/git-gui/lib/mergetool.tcl +++ b/git-gui/lib/mergetool.tcl @@ -90,7 +90,7 @@ proc merge_load_stages {path cont} { set merge_stages_fd [git_read [list ls-files -u -z -- $path]] - fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary + fconfigure $merge_stages_fd -blocking 0 -translation binary fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont] } @@ -370,7 +370,7 @@ proc merge_tool_start {cmdline target backup stages} { ui_status [mc "Running merge tool..."] - fconfigure $mtool_fd -blocking 0 -translation binary -encoding binary + fconfigure $mtool_fd -blocking 0 -translation binary fileevent $mtool_fd readable [list read_mtool_output $mtool_fd] } diff --git a/git-gui/lib/option.tcl b/git-gui/lib/option.tcl index e43971bfa3..487d70691d 100644 --- a/git-gui/lib/option.tcl +++ b/git-gui/lib/option.tcl @@ -91,7 +91,7 @@ proc save_config {} { proc do_options {} { global repo_config global_config font_descs global repo_config_new global_config_new - global ui_comm_spell use_ttk NS + global ui_comm_spell array unset repo_config_new array unset global_config_new @@ -115,23 +115,23 @@ proc do_options {} { wm transient $w [winfo parent $w] wm geometry $w "+[winfo rootx .]+[winfo rooty .]" - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.restore -text [mc "Restore Defaults"] \ + ttk::frame $w.buttons + ttk::button $w.buttons.restore -text [mc "Restore Defaults"] \ -default normal \ -command do_restore_defaults pack $w.buttons.restore -side left - ${NS}::button $w.buttons.save -text [mc Save] \ + ttk::button $w.buttons.save -text [mc Save] \ -default active \ -command [list do_save_config $w] pack $w.buttons.save -side right - ${NS}::button $w.buttons.cancel -text [mc "Cancel"] \ + ttk::button $w.buttons.cancel -text [mc "Cancel"] \ -default normal \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::labelframe $w.repo -text [mc "%s Repository" [reponame]] - ${NS}::labelframe $w.global -text [mc "Global (All Repositories)"] + ttk::labelframe $w.repo -text [mc "%s Repository" [reponame]] + ttk::labelframe $w.global -text [mc "Global (All Repositories)"] pack $w.repo -side left -fill both -expand 1 -pady 5 -padx 5 pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 @@ -170,7 +170,7 @@ proc do_options {} { foreach f {repo global} { switch -glob -- $type { b { - ${NS}::checkbutton $w.$f.$optid -text $text \ + ttk::checkbutton $w.$f.$optid -text $text \ -variable ${f}_config_new($name) \ -onvalue true \ -offvalue false @@ -178,8 +178,8 @@ proc do_options {} { } i-* { regexp -- {-(\d+)\.\.(\d+)$} $type _junk min max - ${NS}::frame $w.$f.$optid - ${NS}::label $w.$f.$optid.l -text [mc "%s:" $text] + ttk::frame $w.$f.$optid + ttk::label $w.$f.$optid.l -text [mc "%s:" $text] pack $w.$f.$optid.l -side left -anchor w -fill x tspinbox $w.$f.$optid.v \ -textvariable ${f}_config_new($name) \ @@ -193,9 +193,9 @@ proc do_options {} { } c - t { - ${NS}::frame $w.$f.$optid - ${NS}::label $w.$f.$optid.l -text [mc "%s:" $text] - ${NS}::entry $w.$f.$optid.v \ + ttk::frame $w.$f.$optid + ttk::label $w.$f.$optid.l -text [mc "%s:" $text] + ttk::entry $w.$f.$optid.v \ -width 20 \ -textvariable ${f}_config_new($name) pack $w.$f.$optid.l -side left -anchor w @@ -206,7 +206,7 @@ proc do_options {} { menu $w.$f.$optid.m build_encoding_menu $w.$f.$optid.m \ [list set ${f}_config_new($name)] 1 - ${NS}::button $w.$f.$optid.b \ + ttk::button $w.$f.$optid.b \ -text [mc "Change"] \ -command [list popup_btn_menu \ $w.$f.$optid.m $w.$f.$optid.b] @@ -216,17 +216,11 @@ proc do_options {} { } s { set opts [eval [lindex $option 3]] - ${NS}::frame $w.$f.$optid - ${NS}::label $w.$f.$optid.l -text [mc "%s:" $text] - if {$use_ttk} { - ttk::combobox $w.$f.$optid.v \ - -textvariable ${f}_config_new($name) \ - -values $opts -state readonly - } else { - eval tk_optionMenu $w.$f.$optid.v \ - ${f}_config_new($name) \ - $opts - } + ttk::frame $w.$f.$optid + ttk::label $w.$f.$optid.l -text [mc "%s:" $text] + ttk::combobox $w.$f.$optid.v \ + -textvariable ${f}_config_new($name) \ + -values $opts -state readonly pack $w.$f.$optid.l -side left -anchor w -fill x pack $w.$f.$optid.v -side right -anchor e -padx 5 pack $w.$f.$optid -side top -anchor w -fill x @@ -250,17 +244,11 @@ proc do_options {} { set ${f}_config_new(gui.spellingdictionary) $value } - ${NS}::frame $w.$f.$optid - ${NS}::label $w.$f.$optid.l -text [mc "Spelling Dictionary:"] - if {$use_ttk} { - ttk::combobox $w.$f.$optid.v \ - -textvariable ${f}_config_new(gui.spellingdictionary) \ - -values $all_dicts -state readonly - } else { - eval tk_optionMenu $w.$f.$optid.v \ - ${f}_config_new(gui.spellingdictionary) \ - $all_dicts - } + ttk::frame $w.$f.$optid + ttk::label $w.$f.$optid.l -text [mc "Spelling Dictionary:"] + ttk::combobox $w.$f.$optid.v \ + -textvariable ${f}_config_new(gui.spellingdictionary) \ + -values $all_dicts -state readonly pack $w.$f.$optid.l -side left -anchor w -fill x pack $w.$f.$optid.v -side right -anchor e -padx 5 pack $w.$f.$optid -side top -anchor w -fill x @@ -278,9 +266,9 @@ proc do_options {} { set global_config_new(gui.$font^^size) \ [font configure $font -size] - ${NS}::frame $w.global.$name - ${NS}::label $w.global.$name.l -text [mc "%s:" $text] - ${NS}::button $w.global.$name.b \ + ttk::frame $w.global.$name + ttk::label $w.global.$name.l -text [mc "%s:" $text] + ttk::button $w.global.$name.b \ -text [mc "Change Font"] \ -command [list \ tchoosefont \ @@ -289,9 +277,9 @@ proc do_options {} { global_config_new(gui.$font^^family) \ global_config_new(gui.$font^^size) \ ] - ${NS}::label $w.global.$name.f -textvariable global_config_new(gui.$font^^family) - ${NS}::label $w.global.$name.s -textvariable global_config_new(gui.$font^^size) - ${NS}::label $w.global.$name.pt -text [mc "pt."] + ttk::label $w.global.$name.f -textvariable global_config_new(gui.$font^^family) + ttk::label $w.global.$name.s -textvariable global_config_new(gui.$font^^size) + ttk::label $w.global.$name.pt -text [mc "pt."] pack $w.global.$name.l -side left -anchor w pack $w.global.$name.b -side right -anchor e pack $w.global.$name.pt -side right -anchor w diff --git a/git-gui/lib/remote.tcl b/git-gui/lib/remote.tcl index cf796d1601..9b49b6e462 100644 --- a/git-gui/lib/remote.tcl +++ b/git-gui/lib/remote.tcl @@ -233,8 +233,6 @@ proc make_sure_remote_submenues_exist {remote_m} { proc update_all_remotes_menu_entry {} { global all_remotes - if {[git-version < 1.6.6]} { return } - set have_remote 0 foreach r $all_remotes { incr have_remote diff --git a/git-gui/lib/remote_add.tcl b/git-gui/lib/remote_add.tcl index 480a6b30d0..bff1376cb3 100644 --- a/git-gui/lib/remote_add.tcl +++ b/git-gui/lib/remote_add.tcl @@ -13,7 +13,7 @@ field location {}; # location of the remote the user has chosen field opt_action fetch; # action to do after registering the remote locally constructor dialog {} { - global repo_config use_ttk NS + global repo_config make_dialog top w wm withdraw $top @@ -22,34 +22,34 @@ constructor dialog {} { wm geometry $top "+[winfo rootx .]+[winfo rooty .]" } - ${NS}::label $w.header -text [mc "Add New Remote"] \ + ttk::label $w.header -text [mc "Add New Remote"] \ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.create -text [mc Add] \ + ttk::frame $w.buttons + ttk::button $w.buttons.create -text [mc Add] \ -default active \ -command [cb _add] pack $w.buttons.create -side right - ${NS}::button $w.buttons.cancel -text [mc Cancel] \ + ttk::button $w.buttons.cancel -text [mc Cancel] \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::labelframe $w.desc -text [mc "Remote Details"] + ttk::labelframe $w.desc -text [mc "Remote Details"] - ${NS}::label $w.desc.name_l -text [mc "Name:"] + ttk::label $w.desc.name_l -text [mc "Name:"] set w_name $w.desc.name_t - ${NS}::entry $w_name \ + ttk::entry $w_name \ -width 40 \ -textvariable @name \ -validate key \ -validatecommand [cb _validate_name %d %S] grid $w.desc.name_l $w_name -sticky we -padx {0 5} - ${NS}::label $w.desc.loc_l -text [mc "Location:"] + ttk::label $w.desc.loc_l -text [mc "Location:"] set w_loc $w.desc.loc_t - ${NS}::entry $w_loc \ + ttk::entry $w_loc \ -width 40 \ -textvariable @location grid $w.desc.loc_l $w_loc -sticky we -padx {0 5} @@ -57,21 +57,21 @@ constructor dialog {} { grid columnconfigure $w.desc 1 -weight 1 pack $w.desc -anchor nw -fill x -pady 5 -padx 5 - ${NS}::labelframe $w.action -text [mc "Further Action"] + ttk::labelframe $w.action -text [mc "Further Action"] - ${NS}::radiobutton $w.action.fetch \ + ttk::radiobutton $w.action.fetch \ -text [mc "Fetch Immediately"] \ -value fetch \ -variable @opt_action pack $w.action.fetch -anchor nw - ${NS}::radiobutton $w.action.push \ + ttk::radiobutton $w.action.push \ -text [mc "Initialize Remote Repository and Push"] \ -value push \ -variable @opt_action pack $w.action.push -anchor nw - ${NS}::radiobutton $w.action.none \ + ttk::radiobutton $w.action.none \ -text [mc "Do Nothing Else Now"] \ -value none \ -variable @opt_action diff --git a/git-gui/lib/remote_branch_delete.tcl b/git-gui/lib/remote_branch_delete.tcl index c8c99b17a8..f0814efdd7 100644 --- a/git-gui/lib/remote_branch_delete.tcl +++ b/git-gui/lib/remote_branch_delete.tcl @@ -23,7 +23,7 @@ field full_cache field cached constructor dialog {} { - global all_remotes M1B use_ttk NS + global all_remotes M1B make_dialog top w wm title $top [mc "%s (%s): Delete Branch Remotely" [appname] [reponame]] @@ -31,32 +31,28 @@ constructor dialog {} { wm geometry $top "+[winfo rootx .]+[winfo rooty .]" } - ${NS}::label $w.header -text [mc "Delete Branch Remotely"] \ + ttk::label $w.header -text [mc "Delete Branch Remotely"] \ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.delete -text [mc Delete] \ + ttk::frame $w.buttons + ttk::button $w.buttons.delete -text [mc Delete] \ -default active \ -command [cb _delete] pack $w.buttons.delete -side right - ${NS}::button $w.buttons.cancel -text [mc "Cancel"] \ + ttk::button $w.buttons.cancel -text [mc "Cancel"] \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::labelframe $w.dest -text [mc "From Repository"] + ttk::labelframe $w.dest -text [mc "From Repository"] if {$all_remotes ne {}} { - ${NS}::radiobutton $w.dest.remote_r \ + ttk::radiobutton $w.dest.remote_r \ -text [mc "Remote:"] \ -value remote \ -variable @urltype - if {$use_ttk} { - ttk::combobox $w.dest.remote_m -textvariable @remote \ - -values $all_remotes -state readonly - } else { - eval tk_optionMenu $w.dest.remote_m @remote $all_remotes - } + ttk::combobox $w.dest.remote_m -textvariable @remote \ + -values $all_remotes -state readonly grid $w.dest.remote_r $w.dest.remote_m -sticky w if {[lsearch -sorted -exact $all_remotes origin] != -1} { set remote origin @@ -68,11 +64,11 @@ constructor dialog {} { } else { set urltype url } - ${NS}::radiobutton $w.dest.url_r \ + ttk::radiobutton $w.dest.url_r \ -text [mc "Arbitrary Location:"] \ -value url \ -variable @urltype - ${NS}::entry $w.dest.url_t \ + ttk::entry $w.dest.url_t \ -width 50 \ -textvariable @url \ -validate key \ @@ -85,19 +81,19 @@ constructor dialog {} { grid columnconfigure $w.dest 1 -weight 1 pack $w.dest -anchor nw -fill x -pady 5 -padx 5 - ${NS}::labelframe $w.heads -text [mc "Branches"] + ttk::labelframe $w.heads -text [mc "Branches"] slistbox $w.heads.l \ -height 10 \ -width 70 \ -listvariable @head_list \ -selectmode extended - ${NS}::frame $w.heads.footer - ${NS}::label $w.heads.footer.status \ + ttk::frame $w.heads.footer + ttk::label $w.heads.footer.status \ -textvariable @status \ -anchor w \ -justify left - ${NS}::button $w.heads.footer.rescan \ + ttk::button $w.heads.footer.rescan \ -text [mc "Rescan"] \ -command [cb _rescan] pack $w.heads.footer.status -side left -fill x @@ -107,8 +103,8 @@ constructor dialog {} { pack $w.heads.l -side left -fill both -expand 1 pack $w.heads -fill both -expand 1 -pady 5 -padx 5 - ${NS}::labelframe $w.validate -text [mc "Delete Only If"] - ${NS}::radiobutton $w.validate.head_r \ + ttk::labelframe $w.validate -text [mc "Delete Only If"] + ttk::radiobutton $w.validate.head_r \ -text [mc "Merged Into:"] \ -value head \ -variable @checktype @@ -116,7 +112,7 @@ constructor dialog {} { trace add variable @head_list write [cb _write_head_list] trace add variable @check_head write [cb _write_check_head] grid $w.validate.head_r $w.validate.head_m -sticky w - ${NS}::radiobutton $w.validate.always_r \ + ttk::radiobutton $w.validate.always_r \ -text [mc "Always (Do not perform merge checks)"] \ -value always \ -variable @checktype @@ -311,7 +307,6 @@ method _load {cache uri} { set active_ls [git_read [list ls-remote $uri]] fconfigure $active_ls \ -blocking 0 \ - -translation lf \ -encoding utf-8 fileevent $active_ls readable [cb _read $cache $active_ls] } else { @@ -323,6 +318,8 @@ method _load {cache uri} { } method _read {cache fd} { + global hashlength + if {$fd ne $active_ls} { catch {close $fd} return @@ -330,7 +327,7 @@ method _read {cache fd} { while {[gets $fd line] >= 0} { if {[string match {*^{}} $line]} continue - if {[regexp {^([0-9a-f]{40}) (.*)$} $line _junk obj ref]} { + if {[regexp [string map "@@ $hashlength" {^([0-9a-f]{@@}) (.*)$}] $line _junk obj ref]} { if {[regsub ^refs/heads/ $ref {} abr]} { lappend head_list $abr lappend head_cache($cache) $abr diff --git a/git-gui/lib/search.tcl b/git-gui/lib/search.tcl index ef1e55521d..47a0d8c961 100644 --- a/git-gui/lib/search.tcl +++ b/git-gui/lib/search.tcl @@ -21,7 +21,6 @@ field smarktop field smarkbot constructor new {i_w i_text args} { - global use_ttk NS set w $i_w set ctext $i_text @@ -44,14 +43,14 @@ constructor new {i_w i_text args} { set history [list] - ${NS}::frame $w - ${NS}::label $w.l -text [mc Find:] + ttk::frame $w + ttk::label $w.l -text [mc Find:] tentry $w.ent -textvariable ${__this}::searchstring -background lightgreen - ${NS}::button $w.bn -text [mc Next] -command [cb find_next] - ${NS}::button $w.bp -text [mc Prev] -command [cb find_prev] - ${NS}::checkbutton $w.re -text [mc RegExp] \ + ttk::button $w.bn -text [mc Next] -command [cb find_next] + ttk::button $w.bp -text [mc Prev] -command [cb find_prev] + ttk::checkbutton $w.re -text [mc RegExp] \ -variable ${__this}::regexpsearch -command [cb _incrsearch] - ${NS}::checkbutton $w.cs -text [mc Case] \ + ttk::checkbutton $w.cs -text [mc Case] \ -variable ${__this}::casesensitive -command [cb _incrsearch] pack $w.l -side left pack $w.cs -side right diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 1d01d9cbfa..431665059e 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -3,27 +3,41 @@ proc do_windows_shortcut {} { global _gitworktree - set fn [tk_getSaveFile \ - -parent . \ - -title [mc "%s (%s): Create Desktop Icon" [appname] [reponame]] \ - -initialfile "Git [reponame].lnk"] - if {$fn != {}} { - if {[file extension $fn] ne {.lnk}} { - set fn ${fn}.lnk - } - # Use git-gui.exe if available (ie: git-for-windows) - set cmdLine [list [_which git-gui]] - if {$cmdLine eq {}} { - set cmdLine [list [info nameofexecutable] \ - [file normalize $::argv0]] - } - if {[catch { - win32_create_lnk $fn $cmdLine \ - [file normalize $_gitworktree] - } err]} { - error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] + + set desktop [safe_exec [list cygpath -mD]] + set link_file "Git [reponame].lnk" + set link_path [file normalize [file join $desktop $link_file]] + + # on Windows, tk_getSaveFile dereferences .lnk files, so no simple + # filename chooser is available. Use the default or quit. + if {[file exists $link_path]} { + set answer [tk_messageBox \ + -type yesno \ + -title [mc "%s (%s): Create Desktop Icon" [appname] [reponame]] \ + -default yes \ + -message [mc "Replace existing shortcut: %s?" $link_file]] + if {$answer == no} { + return } } + + # Use git-gui.exe if found, fall back to wish + launcher + set link_arguments {} + set link_target [safe_exec [list cygpath -m /cmd/git-gui.exe]] + if {![file executable $link_target]} { + set link_target [_which git-gui] + } + if {![file executable $link_target]} { + set link_target [file normalize [info nameofexecutable]] + set link_arguments [file normalize $::argv0] + } + set cmdLine [list $link_target $link_arguments] + if {[catch { + win32_create_lnk $link_path $cmdLine \ + [file normalize $_gitworktree] + } err]} { + error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] + } } proc do_cygwin_shortcut {} { diff --git a/git-gui/lib/spellcheck.tcl b/git-gui/lib/spellcheck.tcl index 538d61c792..634656820d 100644 --- a/git-gui/lib/spellcheck.tcl +++ b/git-gui/lib/spellcheck.tcl @@ -33,7 +33,6 @@ constructor init {pipe_fd ui_text ui_menu} { method _connect {pipe_fd} { fconfigure $pipe_fd \ -encoding utf-8 \ - -eofchar {} \ -translation lf if {[gets $pipe_fd s_version] <= 0} { diff --git a/git-gui/lib/sshkey.tcl b/git-gui/lib/sshkey.tcl index c3e681b899..7a6526d3db 100644 --- a/git-gui/lib/sshkey.tcl +++ b/git-gui/lib/sshkey.tcl @@ -18,7 +18,7 @@ proc find_ssh_key {} { } proc do_ssh_key {} { - global sshkey_title have_tk85 sshkey_fd use_ttk NS + global sshkey_title sshkey_fd set w .sshkey_dialog if {[winfo exists $w]} { @@ -38,9 +38,9 @@ proc do_ssh_key {} { set gen_state disabled } - ${NS}::frame $w.header - ${NS}::label $w.header.lbl -textvariable sshkey_title -anchor w - ${NS}::button $w.header.gen -text [mc "Generate Key"] \ + ttk::frame $w.header + ttk::label $w.header.lbl -textvariable sshkey_title -anchor w + ttk::button $w.header.gen -text [mc "Generate Key"] \ -command [list make_ssh_key $w] -state $gen_state pack $w.header.lbl -side left -expand 1 -fill x pack $w.header.gen -side right @@ -48,17 +48,14 @@ proc do_ssh_key {} { text $w.contents -width 60 -height 10 -wrap char -relief sunken pack $w.contents -fill both -expand 1 - if {$have_tk85} { - set clr darkblue - if {$use_ttk} { set clr [ttk::style lookup . -selectbackground] } - $w.contents configure -inactiveselectbackground $clr - } + set clr [ttk::style lookup . -selectbackground] + $w.contents configure -inactiveselectbackground $clr - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.close -text [mc Close] \ + ttk::frame $w.buttons + ttk::button $w.buttons.close -text [mc Close] \ -default active -command [list destroy $w] pack $w.buttons.close -side right - ${NS}::button $w.buttons.copy -text [mc "Copy To Clipboard"] \ + ttk::button $w.buttons.copy -text [mc "Copy To Clipboard"] \ -command [list tk_textCopy $w.contents] pack $w.buttons.copy -side left pack $w.buttons -side bottom -fill x -pady 5 -padx 5 diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index d32b14142f..f5c0204a2d 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,7 +39,6 @@ field operations ; # list of current ongoing operations field completed_operation_count constructor new {path} { - global use_ttk NS set w $path set w_l $w.l set w_c $w.c @@ -51,11 +50,8 @@ constructor new {path} { set operations [list] set completed_operation_count 0 - ${NS}::frame $w - if {!$use_ttk} { - $w configure -borderwidth 1 -relief sunken - } - ${NS}::label $w_l \ + ttk::frame $w + ttk::label $w_l \ -textvariable @status_bar_text \ -anchor w \ -justify left @@ -72,7 +68,6 @@ method _oneline_pack {} { } constructor two_line {path} { - global NS set w $path set w_l $w.l set w_c $w.c @@ -84,8 +79,8 @@ constructor two_line {path} { set operations [list] set completed_operation_count 0 - ${NS}::frame $w - ${NS}::label $w_l \ + ttk::frame $w + ttk::label $w_l \ -textvariable @status_bar_text \ -anchor w \ -justify left diff --git a/git-gui/lib/themed.tcl b/git-gui/lib/themed.tcl index f43d84e54f..c18e201d85 100644 --- a/git-gui/lib/themed.tcl +++ b/git-gui/lib/themed.tcl @@ -21,10 +21,10 @@ namespace eval color { set inactive_select_bg [convert_rgb_to_gray $select_bg] set inactive_select_fg $select_fg - set color::select_bg $select_bg - set color::select_fg $select_fg - set color::inactive_select_bg $inactive_select_bg - set color::inactive_select_fg $inactive_select_fg + set ::color::select_bg $select_bg + set ::color::select_fg $select_fg + set ::color::inactive_select_bg $inactive_select_bg + set ::color::inactive_select_fg $inactive_select_fg proc add_option {key val} { option add $key $val widgetDefault @@ -190,8 +190,7 @@ proc InitEntryFrame {} { } proc gold_frame {w args} { - global use_ttk - if {$use_ttk && ![is_MacOSX]} { + if {![is_MacOSX]} { eval [linsert $args 0 ttk::frame $w -style Gold.TFrame] } else { eval [linsert $args 0 frame $w -background gold] @@ -199,8 +198,7 @@ proc gold_frame {w args} { } proc tlabel {w args} { - global use_ttk - if {$use_ttk && ![is_MacOSX]} { + if {![is_MacOSX]} { set cmd [list ttk::label $w -style Color.TLabel] foreach {k v} $args { switch -glob -- $k { @@ -216,17 +214,7 @@ proc tlabel {w args} { # The padded label gets used in the about class. proc paddedlabel {w args} { - global use_ttk - if {$use_ttk} { - eval [linsert $args 0 ttk::label $w -style Padded.TLabel] - } else { - eval [linsert $args 0 label $w \ - -padx 5 -pady 5 \ - -justify left \ - -anchor w \ - -borderwidth 1 \ - -relief solid] - } + eval [linsert $args 0 ttk::label $w -style Padded.TLabel] } # Create a toplevel for use as a dialog. @@ -242,8 +230,7 @@ proc Dialog {w args} { # Tk toplevels are not themed - so pave it over with a themed frame to get # the base color correct per theme. proc pave_toplevel {w} { - global use_ttk - if {$use_ttk && ![winfo exists $w.!paving]} { + if {![winfo exists $w.!paving]} { set paving [ttk::frame $w.!paving] place $paving -x 0 -y 0 -relwidth 1 -relheight 1 lower $paving @@ -254,20 +241,11 @@ proc pave_toplevel {w} { # On many themes the border for a scrolled listbox needs to go around the # listbox and the scrollbar. proc slistbox {w args} { - global use_ttk NS - if {$use_ttk} { - set f [ttk::frame $w -style SListbox.TFrame -padding 2] - } else { - set f [frame $w -relief flat] - } + set f [ttk::frame $w -style SListbox.TFrame -padding 2] if {[catch { - if {$use_ttk} { - eval [linsert $args 0 listbox $f.list -relief flat \ - -highlightthickness 0 -borderwidth 0] - } else { - eval [linsert $args 0 listbox $f.list] - } - ${NS}::scrollbar $f.vs -command [list $f.list yview] + eval [linsert $args 0 listbox $f.list -relief flat \ + -highlightthickness 0 -borderwidth 0] + ttk::scrollbar $f.vs -command [list $f.list yview] $f.list configure -yscrollcommand [list $f.vs set] grid $f.list $f.vs -sticky news grid rowconfigure $f 0 -weight 1 @@ -285,67 +263,42 @@ proc slistbox {w args} { # fetch the background color from a widget. proc get_bg_color {w} { - global use_ttk - if {$use_ttk} { - set bg [ttk::style lookup [winfo class $w] -background] - } else { - set bg [$w cget -background] - } + set bg [ttk::style lookup [winfo class $w] -background] return $bg } -# ttk::spinbox didn't get added until 8.6 +# ttk::spinbox proc tspinbox {w args} { - global use_ttk - if {$use_ttk && [llength [info commands ttk::spinbox]] > 0} { - eval [linsert $args 0 ttk::spinbox $w] - } else { - eval [linsert $args 0 spinbox $w] - } + eval [linsert $args 0 ttk::spinbox $w] } # Create a text widget with any theme specific properties. proc ttext {w args} { - global use_ttk - if {$use_ttk} { - switch -- [ttk_get_current_theme] { - "vista" - "xpnative" { - lappend args -highlightthickness 0 -borderwidth 0 - } + switch -- [ttk_get_current_theme] { + "vista" - "xpnative" { + lappend args -highlightthickness 0 -borderwidth 0 } } set w [eval [linsert $args 0 text $w]] - if {$use_ttk} { - if {[winfo class [winfo parent $w]] eq "EntryFrame"} { - bind $w <FocusIn> {[winfo parent %W] state focus} - bind $w <FocusOut> {[winfo parent %W] state !focus} - } + if {[winfo class [winfo parent $w]] eq "EntryFrame"} { + bind $w <FocusIn> {[winfo parent %W] state focus} + bind $w <FocusOut> {[winfo parent %W] state !focus} } return $w } # themed frame suitable for surrounding a text field. proc textframe {w args} { - global use_ttk - if {$use_ttk} { - if {[catch {ttk::style layout EntryFrame}]} { - InitEntryFrame - } - eval [linsert $args 0 ttk::frame $w -class EntryFrame -style EntryFrame] - } else { - eval [linsert $args 0 frame $w] + if {[catch {ttk::style layout EntryFrame}]} { + InitEntryFrame } + eval [linsert $args 0 ttk::frame $w -class EntryFrame -style EntryFrame] return $w } proc tentry {w args} { - global use_ttk - if {$use_ttk} { - InitTheme - ttk::entry $w -style Edged.Entry - } else { - entry $w - } + InitTheme + ttk::entry $w -style Edged.Entry rename $w _$w interp alias {} $w {} tentry_widgetproc $w @@ -353,25 +306,14 @@ proc tentry {w args} { return $w } proc tentry_widgetproc {w cmd args} { - global use_ttk switch -- $cmd { state { - if {$use_ttk} { - return [uplevel 1 [list _$w $cmd] $args] - } else { - if {[lsearch -exact $args pressed] != -1} { - _$w configure -background lightpink - } else { - _$w configure -background lightgreen - } - } + return [uplevel 1 [list _$w $cmd] $args] } configure { - if {$use_ttk} { - if {[set n [lsearch -exact $args -background]] != -1} { - set args [lreplace $args $n [incr n]] - if {[llength $args] == 0} {return} - } + if {[set n [lsearch -exact $args -background]] != -1} { + set args [lreplace $args $n [incr n]] + if {[llength $args] == 0} {return} } return [uplevel 1 [list _$w $cmd] $args] } diff --git a/git-gui/lib/tools_dlg.tcl b/git-gui/lib/tools_dlg.tcl index c05413ce43..73236215b5 100644 --- a/git-gui/lib/tools_dlg.tcl +++ b/git-gui/lib/tools_dlg.tcl @@ -16,7 +16,7 @@ field ask_branch 0; # ask for a revision field ask_args 0; # ask for additional args constructor dialog {} { - global repo_config use_ttk NS + global repo_config make_dialog top w wm title $top [mc "%s (%s): Add Tool" [appname] [reponame]] @@ -25,41 +25,41 @@ constructor dialog {} { wm transient $top . } - ${NS}::label $w.header -text [mc "Add New Tool Command"] \ + ttk::label $w.header -text [mc "Add New Tool Command"] \ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::checkbutton $w.buttons.global \ + ttk::frame $w.buttons + ttk::checkbutton $w.buttons.global \ -text [mc "Add globally"] \ -variable @add_global pack $w.buttons.global -side left -padx 5 - ${NS}::button $w.buttons.create -text [mc Add] \ + ttk::button $w.buttons.create -text [mc Add] \ -default active \ -command [cb _add] pack $w.buttons.create -side right - ${NS}::button $w.buttons.cancel -text [mc Cancel] \ + ttk::button $w.buttons.cancel -text [mc Cancel] \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::labelframe $w.desc -text [mc "Tool Details"] + ttk::labelframe $w.desc -text [mc "Tool Details"] - ${NS}::label $w.desc.name_cmnt -anchor w\ + ttk::label $w.desc.name_cmnt -anchor w\ -text [mc "Use '/' separators to create a submenu tree:"] grid x $w.desc.name_cmnt -sticky we -padx {0 5} -pady {0 2} - ${NS}::label $w.desc.name_l -text [mc "Name:"] + ttk::label $w.desc.name_l -text [mc "Name:"] set w_name $w.desc.name_t - ${NS}::entry $w_name \ + ttk::entry $w_name \ -width 40 \ -textvariable @name \ -validate key \ -validatecommand [cb _validate_name %d %S] grid $w.desc.name_l $w_name -sticky we -padx {0 5} - ${NS}::label $w.desc.cmd_l -text [mc "Command:"] + ttk::label $w.desc.cmd_l -text [mc "Command:"] set w_cmd $w.desc.cmd_t - ${NS}::entry $w_cmd \ + ttk::entry $w_cmd \ -width 40 \ -textvariable @command grid $w.desc.cmd_l $w_cmd -sticky we -padx {0 5} -pady {0 3} @@ -67,30 +67,30 @@ constructor dialog {} { grid columnconfigure $w.desc 1 -weight 1 pack $w.desc -anchor nw -fill x -pady 5 -padx 5 - ${NS}::checkbutton $w.confirm \ + ttk::checkbutton $w.confirm \ -text [mc "Show a dialog before running"] \ -variable @confirm -command [cb _check_enable_dlg] - ${NS}::labelframe $w.dlg -labelwidget $w.confirm + ttk::labelframe $w.dlg -labelwidget $w.confirm - ${NS}::checkbutton $w.dlg.askbranch \ + ttk::checkbutton $w.dlg.askbranch \ -text [mc "Ask the user to select a revision (sets \$REVISION)"] \ -variable @ask_branch -state disabled pack $w.dlg.askbranch -anchor w -padx 15 - ${NS}::checkbutton $w.dlg.askargs \ + ttk::checkbutton $w.dlg.askargs \ -text [mc "Ask the user for additional arguments (sets \$ARGS)"] \ -variable @ask_args -state disabled pack $w.dlg.askargs -anchor w -padx 15 pack $w.dlg -anchor nw -fill x -pady {0 8} -padx 5 - ${NS}::checkbutton $w.noconsole \ + ttk::checkbutton $w.noconsole \ -text [mc "Don't show the command output window"] \ -variable @no_console pack $w.noconsole -anchor w -padx 5 - ${NS}::checkbutton $w.needsfile \ + ttk::checkbutton $w.needsfile \ -text [mc "Run only if a diff is selected (\$FILENAME not empty)"] \ -variable @needs_file pack $w.needsfile -anchor w -padx 5 @@ -179,7 +179,7 @@ field w ; # widget path field w_names ; # name list constructor dialog {} { - global repo_config global_config system_config use_ttk NS + global repo_config global_config system_config load_config 1 @@ -190,21 +190,21 @@ constructor dialog {} { wm transient $top . } - ${NS}::label $w.header -text [mc "Remove Tool Commands"] \ + ttk::label $w.header -text [mc "Remove Tool Commands"] \ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.create -text [mc Remove] \ + ttk::frame $w.buttons + ttk::button $w.buttons.create -text [mc Remove] \ -default active \ -command [cb _remove] pack $w.buttons.create -side right - ${NS}::button $w.buttons.cancel -text [mc Cancel] \ + ttk::button $w.buttons.cancel -text [mc Cancel] \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::frame $w.list + ttk::frame $w.list set w_names $w.list.l slistbox $w_names \ -height 10 \ @@ -227,7 +227,7 @@ constructor dialog {} { } if {$local_cnt > 0} { - ${NS}::label $w.colorlbl -foreground blue \ + ttk::label $w.colorlbl -foreground blue \ -text [mc "(Blue denotes repository-local tools)"] pack $w.colorlbl -fill x -pady 5 -padx 5 } @@ -272,7 +272,7 @@ field is_ok 0; # ok to start field argstr {}; # arguments constructor dialog {fullname} { - global M1B use_ttk NS + global M1B set title [get_config "guitool.$fullname.title"] if {$title eq {}} { @@ -292,7 +292,7 @@ constructor dialog {fullname} { set prompt [mc "Run Command: %s" $command] } - ${NS}::label $w.header -text $prompt -font font_uibold -anchor center + ttk::label $w.header -text $prompt -font font_uibold -anchor center pack $w.header -side top -fill x set argprompt [get_config "guitool.$fullname.argprompt"] @@ -306,10 +306,10 @@ constructor dialog {fullname} { set argprompt [mc "Arguments"] } - ${NS}::labelframe $w.arg -text $argprompt + ttk::labelframe $w.arg -text $argprompt set w_args $w.arg.txt - ${NS}::entry $w_args \ + ttk::entry $w_args \ -width 40 \ -textvariable @argstr pack $w_args -padx 5 -pady 5 -fill both @@ -330,18 +330,18 @@ constructor dialog {fullname} { pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5 } - ${NS}::frame $w.buttons + ttk::frame $w.buttons if {$is_ask_revs} { - ${NS}::button $w.buttons.visualize \ + ttk::button $w.buttons.visualize \ -text [mc Visualize] \ -command [cb _visualize] pack $w.buttons.visualize -side left } - ${NS}::button $w.buttons.ok \ + ttk::button $w.buttons.ok \ -text [mc OK] \ -command [cb _start] pack $w.buttons.ok -side right - ${NS}::button $w.buttons.cancel \ + ttk::button $w.buttons.cancel \ -text [mc "Cancel"] \ -command [cb _cancel] pack $w.buttons.cancel -side right -padx 5 diff --git a/git-gui/lib/transport.tcl b/git-gui/lib/transport.tcl index a1a424aab5..020d09e112 100644 --- a/git-gui/lib/transport.tcl +++ b/git-gui/lib/transport.tcl @@ -120,7 +120,7 @@ trace add variable push_remote write \ proc do_push_anywhere {} { global all_remotes current_branch global push_urltype push_remote push_url push_thin push_tags - global push_force use_ttk NS + global push_force set w .push_setup toplevel $w @@ -129,22 +129,22 @@ proc do_push_anywhere {} { wm geometry $w "+[winfo rootx .]+[winfo rooty .]" pave_toplevel $w - ${NS}::label $w.header -text [mc "Push Branches"] \ + ttk::label $w.header -text [mc "Push Branches"] \ -font font_uibold -anchor center pack $w.header -side top -fill x - ${NS}::frame $w.buttons - ${NS}::button $w.buttons.create -text [mc Push] \ + ttk::frame $w.buttons + ttk::button $w.buttons.create -text [mc Push] \ -default active \ -command [list start_push_anywhere_action $w] pack $w.buttons.create -side right - ${NS}::button $w.buttons.cancel -text [mc "Cancel"] \ + ttk::button $w.buttons.cancel -text [mc "Cancel"] \ -default normal \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 - ${NS}::labelframe $w.source -text [mc "Source Branches"] + ttk::labelframe $w.source -text [mc "Source Branches"] slistbox $w.source.l \ -height 10 \ -width 70 \ @@ -159,20 +159,16 @@ proc do_push_anywhere {} { pack $w.source.l -side left -fill both -expand 1 pack $w.source -fill both -expand 1 -pady 5 -padx 5 - ${NS}::labelframe $w.dest -text [mc "Destination Repository"] + ttk::labelframe $w.dest -text [mc "Destination Repository"] if {$all_remotes ne {}} { - ${NS}::radiobutton $w.dest.remote_r \ + ttk::radiobutton $w.dest.remote_r \ -text [mc "Remote:"] \ -value remote \ -variable push_urltype - if {$use_ttk} { - ttk::combobox $w.dest.remote_m -state readonly \ - -exportselection false \ - -textvariable push_remote \ - -values $all_remotes - } else { - eval tk_optionMenu $w.dest.remote_m push_remote $all_remotes - } + ttk::combobox $w.dest.remote_m -state readonly \ + -exportselection false \ + -textvariable push_remote \ + -values $all_remotes grid $w.dest.remote_r $w.dest.remote_m -sticky w if {[lsearch -sorted -exact $all_remotes origin] != -1} { set push_remote origin @@ -183,11 +179,11 @@ proc do_push_anywhere {} { } else { set push_urltype url } - ${NS}::radiobutton $w.dest.url_r \ + ttk::radiobutton $w.dest.url_r \ -text [mc "Arbitrary Location:"] \ -value url \ -variable push_urltype - ${NS}::entry $w.dest.url_t \ + ttk::entry $w.dest.url_t \ -width 50 \ -textvariable push_url \ -validate key \ @@ -202,16 +198,16 @@ proc do_push_anywhere {} { grid columnconfigure $w.dest 1 -weight 1 pack $w.dest -anchor nw -fill x -pady 5 -padx 5 - ${NS}::labelframe $w.options -text [mc "Transfer Options"] - ${NS}::checkbutton $w.options.force \ + ttk::labelframe $w.options -text [mc "Transfer Options"] + ttk::checkbutton $w.options.force \ -text [mc "Force overwrite existing branch (may discard changes)"] \ -variable push_force grid $w.options.force -columnspan 2 -sticky w - ${NS}::checkbutton $w.options.thin \ + ttk::checkbutton $w.options.thin \ -text [mc "Use thin pack (for slow network connections)"] \ -variable push_thin grid $w.options.thin -columnspan 2 -sticky w - ${NS}::checkbutton $w.options.tags \ + ttk::checkbutton $w.options.tags \ -text [mc "Include tags"] \ -variable push_tags grid $w.options.tags -columnspan 2 -sticky w diff --git a/git-gui/macosx/AppMain.tcl b/git-gui/macosx/AppMain.tcl deleted file mode 100644 index b6c6dc3500..0000000000 --- a/git-gui/macosx/AppMain.tcl +++ /dev/null @@ -1,29 +0,0 @@ -set gitexecdir {@@gitexecdir@@} -if { [info exists ::env(GIT_GUI_LIB_DIR) ] } { - set gitguilib $::env(GIT_GUI_LIB_DIR) -} else { - set gitguilib {@@GITGUI_LIBDIR@@} -} - -set env(PATH) "$gitexecdir:$env(PATH)" - -if {[string first -psn [lindex $argv 0]] == 0} { - lset argv 0 [file join $gitexecdir git-gui] -} - -if {[file tail [lindex $argv 0]] eq {gitk}} { - set argv0 [lindex $argv 0] - set AppMain_source $argv0 -} else { - set argv0 [file join $gitexecdir [file tail [lindex $argv 0]]] - set AppMain_source [file join $gitguilib git-gui.tcl] - if {[info exists env(PWD)]} { - cd $env(PWD) - } elseif {[pwd] eq {/}} { - cd $env(HOME) - } -} - -unset gitexecdir gitguilib -set argv [lrange $argv 1 end] -source $AppMain_source diff --git a/git-gui/macosx/Info.plist b/git-gui/macosx/Info.plist deleted file mode 100644 index 1ade121c4c..0000000000 --- a/git-gui/macosx/Info.plist +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundleDevelopmentRegion</key> - <string>English</string> - <key>CFBundleExecutable</key> - <string>@@GITGUI_TKEXECUTABLE@@</string> - <key>CFBundleGetInfoString</key> - <string>Git Gui @@GITGUI_VERSION@@ © 2006-2007 Shawn Pearce, et. al.</string> - <key>CFBundleIconFile</key> - <string>git-gui.icns</string> - <key>CFBundleIdentifier</key> - <string>cz.or.repo.git-gui</string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundleName</key> - <string>Git Gui</string> - <key>CFBundlePackageType</key> - <string>APPL</string> - <key>CFBundleShortVersionString</key> - <string>@@GITGUI_VERSION@@</string> - <key>CFBundleSignature</key> - <string>GITg</string> - <key>CFBundleVersion</key> - <string>@@GITGUI_VERSION@@</string> - <key>NSHighResolutionCapable</key> - <true/> -</dict> -</plist> diff --git a/git-gui/macosx/git-gui.icns b/git-gui/macosx/git-gui.icns Binary files differdeleted file mode 100644 index 77d88a77a7..0000000000 --- a/git-gui/macosx/git-gui.icns +++ /dev/null diff --git a/git-gui/meson.build b/git-gui/meson.build index cdae85e4b9..320ba09ecf 100644 --- a/git-gui/meson.build +++ b/git-gui/meson.build @@ -19,17 +19,6 @@ build_options_config.set_quoted('GITGUI_LIBDIR', get_option('prefix') / get_opti build_options_config.set_quoted('SHELL_PATH', fs.as_posix(shell.full_path())) build_options_config.set_quoted('TCLTK_PATH', fs.as_posix(wish.full_path())) build_options_config.set_quoted('TCL_PATH', fs.as_posix(tclsh.full_path())) -if target_machine.system() == 'darwin' - tkexecutables = [ - '/Library/Frameworks/Tk.framework/Resources/Wish.app/Contents/MacOS/Wish', - '/System/Library/Frameworks/Tk.framework/Resources/Wish.app/Contents/MacOS/Wish', - '/System/Library/Frameworks/Tk.framework/Resources/Wish Shell.app/Contents/MacOS/Wish Shell', - ] - tkexecutable = find_program(tkexecutables) - build_options_config.set_quoted('TKEXECUTABLE', tkexecutable.full_path()) -else - build_options_config.set('TKEXECUTABLE', '') -endif build_options = configure_file( input: 'GIT-GUI-BUILD-OPTIONS.in', @@ -49,14 +38,6 @@ version_file = custom_target( build_always_stale: true, ) -configure_file( - input: 'git-gui--askpass', - output: 'git-gui--askpass', - copy: true, - install: true, - install_dir: get_option('libexecdir') / 'git-core', -) - gitgui_main = 'git-gui' gitgui_main_install_dir = get_option('libexecdir') / 'git-core' @@ -70,55 +51,23 @@ if target_machine.system() == 'windows' install: true, install_dir: get_option('libexecdir') / 'git-core', ) -elif target_machine.system() == 'darwin' - gitgui_main = 'git-gui.tcl' - gitgui_main_install_dir = get_option('datadir') / 'git-gui/lib' - - custom_target( - output: 'git-gui', - command: [ - shell, - meson.current_source_dir() / 'generate-macos-wrapper.sh', - '@OUTPUT@', - meson.current_build_dir() / 'GIT-GUI-BUILD-OPTIONS', - meson.current_build_dir() / 'GIT-VERSION-FILE', - ], - depends: [ - version_file, - ], - depend_files: [ - build_options, - ], - install: true, - install_dir: get_option('libexecdir') / 'git-core', - ) - - custom_target( - output: 'Git Gui.app', - command: [ - shell, - meson.current_source_dir() / 'generate-macos-app.sh', - meson.current_source_dir(), - meson.current_build_dir() / 'Git Gui.app', - meson.current_build_dir() / 'GIT-GUI-BUILD-OPTIONS', - meson.current_build_dir() / 'GIT-VERSION-FILE', - ], - depends: [ - version_file, - ], - depend_files: [ - build_options, - 'macosx/AppMain.tcl', - 'macosx/Info.plist', - 'macosx/git-gui.icns', - ], - build_by_default: true, - install: true, - install_dir: get_option('datadir') / 'git-gui/lib', - ) endif custom_target( + output: 'git-gui--askpass', + input: 'git-gui--askpass.sh', + command: [ + shell, + meson.current_source_dir() / 'generate-script.sh', + '@OUTPUT@', + '@INPUT@', + meson.current_build_dir() / 'GIT-GUI-BUILD-OPTIONS', + ], + install: true, + install_dir: get_option('libexecdir') / 'git-core', +) + +custom_target( input: 'git-gui.sh', output: gitgui_main, command: [ diff --git a/git-gui/po/bg.po b/git-gui/po/bg.po index 27b05038e4..21f5bd54e9 100644 --- a/git-gui/po/bg.po +++ b/git-gui/po/bg.po @@ -1,15 +1,15 @@ # Bulgarian translation of git-gui po-file. -# Copyright (C) 2012, 2013, 2014, 2015, 2016, 2024 Alexander Shopov <ash@kambanaria.org>. +# Copyright (C) 2012, 2013, 2014, 2015, 2016, 2024, 2025 Alexander Shopov <ash@kambanaria.org>. # This file is distributed under the same license as the git package. -# Alexander Shopov <ash@kambanaria.org>, 2012, 2013, 2014, 2015, 2016, 2024. +# Alexander Shopov <ash@kambanaria.org>, 2012, 2013, 2014, 2015, 2016, 2024, 2025. # # msgid "" msgstr "" "Project-Id-Version: git-gui master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-02-08 22:54+0100\n" -"PO-Revision-Date: 2024-12-22 15:44+0100\n" +"POT-Creation-Date: 2025-07-22 17:37+0200\n" +"PO-Revision-Date: 2025-07-28 11:56+0200\n" "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n" "Language-Team: Bulgarian <dict@fsa-bg.org>\n" "Language: bg\n" @@ -18,88 +18,58 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: git-gui.sh:847 #, tcl-format msgid "Invalid font specified in %s:" msgstr "Указан е неправилен шрифт в „%s“:" -#: git-gui.sh:901 msgid "Main Font" msgstr "Основен шрифт" -#: git-gui.sh:902 msgid "Diff/Console Font" msgstr "Шрифт за разликите/конзолата" -#: git-gui.sh:917 git-gui.sh:931 git-gui.sh:944 git-gui.sh:1034 git-gui.sh:1053 -#: git-gui.sh:3212 msgid "git-gui: fatal error" msgstr "git-gui: фатална грешка" -#: git-gui.sh:918 msgid "Cannot find git in PATH." msgstr "Командата git липсва в пътя (PATH)." -#: git-gui.sh:945 msgid "Cannot parse Git version string:" msgstr "Низът с версията на Git не може да се анализира:" -#: git-gui.sh:970 -#, tcl-format -msgid "" -"Git version cannot be determined.\n" -"\n" -"%s claims it is version '%s'.\n" -"\n" -"%s requires at least Git 1.5.0 or later.\n" -"\n" -"Assume '%s' is version 1.5.0?\n" -msgstr "" -"Версията на Git не може да се определи.\n" -"\n" -"Версията на „%s“ изглежда, че е „%s“.\n" -"\n" -"„%s“ изисква Git, версия поне 1.5.0.\n" -"\n" -"Да се приеме ли, че „%s“ е версия „1.5.0“?\n" +msgid "Insufficient git version, require: " +msgstr "Прекалено ниска версия на git, необходима е поне: " + +msgid "git returned:" +msgstr "git върна:" -#: git-gui.sh:1267 msgid "Git directory not found:" msgstr "Директорията на Git не е открита:" -#: git-gui.sh:1301 msgid "Cannot move to top of working directory:" msgstr "Не може да се премине към родителската директория." -#: git-gui.sh:1309 msgid "Cannot use bare repository:" msgstr "Голо хранилище не може да се използва:" -#: git-gui.sh:1317 msgid "No working directory" msgstr "Работната директория липсва" -#: git-gui.sh:1491 lib/checkout_op.tcl:306 msgid "Refreshing file status..." msgstr "Обновяване на състоянието на файла…" -#: git-gui.sh:1551 msgid "Scanning for modified files ..." msgstr "Проверка за променени файлове…" -#: git-gui.sh:1629 msgid "Calling prepare-commit-msg hook..." msgstr "Куката „prepare-commit-msg“ се изпълнява в момента…" -#: git-gui.sh:1646 msgid "Commit declined by prepare-commit-msg hook." msgstr "Подаването е отхвърлено от куката „prepare-commit-msg“." -#: git-gui.sh:1804 lib/browser.tcl:252 msgid "Ready." msgstr "Готово." -#: git-gui.sh:1968 #, tcl-format msgid "" "Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files." @@ -108,696 +78,630 @@ msgstr "" "извеждане(gui.maxfilesdisplayed = %s), съответно не са показани всички %s " "файла." -#: git-gui.sh:2091 msgid "Unmodified" msgstr "Непроменен" -#: git-gui.sh:2093 msgid "Modified, not staged" msgstr "Променен, но не е в индекса" -#: git-gui.sh:2094 git-gui.sh:2106 msgid "Staged for commit" msgstr "В индекса за подаване" -#: git-gui.sh:2095 git-gui.sh:2107 msgid "Portions staged for commit" msgstr "Части са в индекса за подаване" -#: git-gui.sh:2096 git-gui.sh:2108 msgid "Staged for commit, missing" msgstr "В индекса за подаване, но липсва" -#: git-gui.sh:2098 msgid "File type changed, not staged" msgstr "Видът на файла е сменен, но не е в индекса" -#: git-gui.sh:2099 git-gui.sh:2100 msgid "File type changed, old type staged for commit" msgstr "Видът на файла е сменен, но новият вид не е в индекса" -#: git-gui.sh:2101 msgid "File type changed, staged" msgstr "Видът на файла е сменен и е в индекса" -#: git-gui.sh:2102 msgid "File type change staged, modification not staged" msgstr "Видът на файла е сменен в индекса, но не и съдържанието" -#: git-gui.sh:2103 msgid "File type change staged, file missing" msgstr "Видът на файла е сменен в индекса, но файлът липсва" -#: git-gui.sh:2105 msgid "Untracked, not staged" msgstr "Неследен" -#: git-gui.sh:2110 msgid "Missing" msgstr "Липсващ" -#: git-gui.sh:2111 msgid "Staged for removal" msgstr "В индекса за изтриване" -#: git-gui.sh:2112 msgid "Staged for removal, still present" msgstr "В индекса за изтриване, но още го има" -#: git-gui.sh:2114 git-gui.sh:2115 git-gui.sh:2116 git-gui.sh:2117 -#: git-gui.sh:2118 git-gui.sh:2119 msgid "Requires merge resolution" msgstr "Изисква коригиране при сливане" -#: git-gui.sh:2164 msgid "Couldn't find gitk in PATH" msgstr "Командата „gitk“ липсва в пътищата, определени от променливата PATH." -#: git-gui.sh:2210 git-gui.sh:2245 #, tcl-format msgid "Starting %s... please wait..." msgstr "Стартиране на „%s“…, изчакайте…" -#: git-gui.sh:2224 msgid "Couldn't find git gui in PATH" msgstr "" "Командата „git gui“ липсва в пътищата, определени от променливата PATH." -#: git-gui.sh:2726 lib/choose_repository.tcl:53 msgid "Repository" msgstr "Хранилище" -#: git-gui.sh:2727 msgid "Edit" msgstr "Редактиране" -#: git-gui.sh:2729 lib/choose_rev.tcl:567 msgid "Branch" msgstr "Клон" -#: git-gui.sh:2732 lib/choose_rev.tcl:554 msgid "Commit@@noun" msgstr "Подаване" -#: git-gui.sh:2735 lib/merge.tcl:127 lib/merge.tcl:174 msgid "Merge" msgstr "Сливане" -#: git-gui.sh:2736 lib/choose_rev.tcl:563 msgid "Remote" msgstr "Отдалечено хранилище" -#: git-gui.sh:2739 msgid "Tools" msgstr "Команди" -#: git-gui.sh:2748 msgid "Explore Working Copy" msgstr "Разглеждане на работното копие" -#: git-gui.sh:2763 msgid "Git Bash" msgstr "Bash за Git" -#: git-gui.sh:2772 msgid "Browse Current Branch's Files" msgstr "Разглеждане на файловете в текущия клон" -#: git-gui.sh:2776 msgid "Browse Branch Files..." msgstr "Разглеждане на текущия клон…" -#: git-gui.sh:2781 msgid "Visualize Current Branch's History" msgstr "Визуализация на историята на текущия клон" -#: git-gui.sh:2785 msgid "Visualize All Branch History" msgstr "Визуализация на историята на всички клонове" -#: git-gui.sh:2792 #, tcl-format msgid "Browse %s's Files" msgstr "Разглеждане на файловете в „%s“" -#: git-gui.sh:2794 #, tcl-format msgid "Visualize %s's History" msgstr "Визуализация на историята на „%s“" -#: git-gui.sh:2799 lib/database.tcl:40 msgid "Database Statistics" msgstr "Статистика на базата от данни" -#: git-gui.sh:2802 lib/database.tcl:33 msgid "Compress Database" msgstr "Компресиране на базата от данни" -#: git-gui.sh:2805 msgid "Verify Database" msgstr "Проверка на базата от данни" -#: git-gui.sh:2812 git-gui.sh:2816 git-gui.sh:2820 msgid "Create Desktop Icon" msgstr "Добавяне на икона на работния плот" -#: git-gui.sh:2828 lib/choose_repository.tcl:209 lib/choose_repository.tcl:217 msgid "Quit" msgstr "Спиране на програмата" -#: git-gui.sh:2836 msgid "Undo" msgstr "Отмяна" -#: git-gui.sh:2839 msgid "Redo" msgstr "Повторение" -#: git-gui.sh:2843 git-gui.sh:3461 msgid "Cut" msgstr "Отрязване" -#: git-gui.sh:2846 git-gui.sh:3464 git-gui.sh:3540 git-gui.sh:3633 -#: lib/console.tcl:69 msgid "Copy" msgstr "Копиране" -#: git-gui.sh:2849 git-gui.sh:3467 msgid "Paste" msgstr "Поставяне" -#: git-gui.sh:2852 git-gui.sh:3470 lib/remote_branch_delete.tcl:39 -#: lib/branch_delete.tcl:28 msgid "Delete" msgstr "Изтриване" -#: git-gui.sh:2856 git-gui.sh:3474 git-gui.sh:3637 lib/console.tcl:71 msgid "Select All" msgstr "Избиране на всичко" -#: git-gui.sh:2865 msgid "Create..." msgstr "Създаване…" -#: git-gui.sh:2871 msgid "Checkout..." msgstr "Изтегляне…" -#: git-gui.sh:2877 msgid "Rename..." msgstr "Преименуване…" -#: git-gui.sh:2882 msgid "Delete..." msgstr "Изтриване…" -#: git-gui.sh:2887 msgid "Reset..." msgstr "Отмяна на промените…" -#: git-gui.sh:2897 msgid "Done" msgstr "Готово" -#: git-gui.sh:2899 msgid "Commit@@verb" msgstr "Подаване" -#: git-gui.sh:2908 git-gui.sh:3400 msgid "Amend Last Commit" msgstr "Поправяне на последното подаване" -#: git-gui.sh:2918 git-gui.sh:3361 lib/remote_branch_delete.tcl:101 msgid "Rescan" msgstr "Обновяване" -#: git-gui.sh:2924 msgid "Stage To Commit" msgstr "Към индекса за подаване" -#: git-gui.sh:2930 msgid "Stage Changed Files To Commit" msgstr "Всички променени файлове към индекса за подаване" -#: git-gui.sh:2936 msgid "Unstage From Commit" msgstr "Изваждане от индекса за подаване" -#: git-gui.sh:2942 lib/index.tcl:521 msgid "Revert Changes" msgstr "Връщане на оригинала" -#: git-gui.sh:2950 git-gui.sh:3700 git-gui.sh:3731 msgid "Show Less Context" msgstr "По-малко контекст" -#: git-gui.sh:2954 git-gui.sh:3704 git-gui.sh:3735 msgid "Show More Context" msgstr "Повече контекст" -#: git-gui.sh:2961 git-gui.sh:3374 git-gui.sh:3485 msgid "Sign Off" msgstr "Подписване" -#: git-gui.sh:2977 msgid "Local Merge..." msgstr "Локално сливане…" -#: git-gui.sh:2982 msgid "Abort Merge..." msgstr "Преустановяване на сливане…" -#: git-gui.sh:2994 git-gui.sh:3022 msgid "Add..." msgstr "Добавяне…" -#: git-gui.sh:2998 msgid "Push..." msgstr "Изтласкване…" -#: git-gui.sh:3002 msgid "Delete Branch..." msgstr "Изтриване на клон…" -#: git-gui.sh:3012 git-gui.sh:3666 msgid "Options..." msgstr "Опции…" -#: git-gui.sh:3023 msgid "Remove..." msgstr "Премахване…" -#: git-gui.sh:3032 lib/choose_repository.tcl:67 msgid "Help" msgstr "Помощ" -#: git-gui.sh:3036 git-gui.sh:3040 lib/choose_repository.tcl:61 -#: lib/choose_repository.tcl:70 lib/about.tcl:14 #, tcl-format msgid "About %s" msgstr "Относно „%s“" -#: git-gui.sh:3064 msgid "Online Documentation" msgstr "Документация в Интернет" -#: git-gui.sh:3067 lib/choose_repository.tcl:64 lib/choose_repository.tcl:73 msgid "Show SSH Key" msgstr "Показване на ключа за SSH" -#: git-gui.sh:3097 git-gui.sh:3229 msgid "usage:" msgstr "употреба:" -#: git-gui.sh:3101 git-gui.sh:3233 msgid "Usage" msgstr "Употреба" -#: git-gui.sh:3182 lib/blame.tcl:575 msgid "Error" msgstr "Грешка" -#: git-gui.sh:3213 #, tcl-format msgid "fatal: cannot stat path %s: No such file or directory" msgstr "ФАТАЛНА ГРЕШКА: пътят „%s“ липсва: такъв файл или директория няма" -#: git-gui.sh:3246 msgid "Current Branch:" msgstr "Текущ клон:" -#: git-gui.sh:3271 msgid "Unstaged Changes" msgstr "Промени извън индекса" -#: git-gui.sh:3293 msgid "Staged Changes (Will Commit)" msgstr "Промени в индекса (за подаване)" -#: git-gui.sh:3367 msgid "Stage Changed" msgstr "Индексът е променен" -#: git-gui.sh:3386 lib/transport.tcl:137 msgid "Push" msgstr "Изтласкване" -#: git-gui.sh:3413 msgid "Initial Commit Message:" msgstr "Първоначално съобщение при подаване:" -#: git-gui.sh:3414 msgid "Amended Commit Message:" msgstr "Поправено съобщение при подаване:" -#: git-gui.sh:3415 msgid "Amended Initial Commit Message:" msgstr "Поправено първоначално съобщение при подаване:" -#: git-gui.sh:3416 msgid "Amended Merge Commit Message:" msgstr "Поправено съобщение при подаване със сливане:" -#: git-gui.sh:3417 msgid "Merge Commit Message:" msgstr "Съобщение при подаване със сливане:" -#: git-gui.sh:3418 msgid "Commit Message:" msgstr "Съобщение при подаване:" -#: git-gui.sh:3477 git-gui.sh:3641 lib/console.tcl:73 msgid "Copy All" msgstr "Копиране на всичко" -#: git-gui.sh:3501 lib/blame.tcl:106 msgid "File:" msgstr "Файл:" -#: git-gui.sh:3549 lib/choose_repository.tcl:1100 msgid "Open" msgstr "Отваряне" -#: git-gui.sh:3629 msgid "Refresh" msgstr "Обновяване" -#: git-gui.sh:3650 msgid "Decrease Font Size" msgstr "По-дребен шрифт" -#: git-gui.sh:3654 msgid "Increase Font Size" msgstr "По-едър шрифт" -#: git-gui.sh:3662 lib/blame.tcl:296 msgid "Encoding" msgstr "Кодиране" -#: git-gui.sh:3673 msgid "Apply/Reverse Hunk" msgstr "Прилагане/връщане на парче" -#: git-gui.sh:3678 msgid "Apply/Reverse Line" msgstr "Прилагане/връщане на ред" -#: git-gui.sh:3684 git-gui.sh:3794 git-gui.sh:3805 msgid "Revert Hunk" msgstr "Връщане на парче" -#: git-gui.sh:3689 git-gui.sh:3801 git-gui.sh:3812 msgid "Revert Line" msgstr "Връщане на ред" -#: git-gui.sh:3694 git-gui.sh:3791 msgid "Undo Last Revert" msgstr "Отмяна на последното връщане" -#: git-gui.sh:3713 msgid "Run Merge Tool" msgstr "Изпълнение на програмата за сливане" -#: git-gui.sh:3718 msgid "Use Remote Version" msgstr "Версия от отдалеченото хранилище" -#: git-gui.sh:3722 msgid "Use Local Version" msgstr "Локална версия" -#: git-gui.sh:3726 msgid "Revert To Base" msgstr "Връщане към родителската версия" -#: git-gui.sh:3744 msgid "Visualize These Changes In The Submodule" msgstr "Визуализиране на промените в подмодула" -#: git-gui.sh:3748 msgid "Visualize Current Branch History In The Submodule" msgstr "Визуализация на историята на текущия клон в историята за подмодула" -#: git-gui.sh:3752 msgid "Visualize All Branch History In The Submodule" msgstr "Визуализация на историята на всички клони в историята за подмодула" -#: git-gui.sh:3757 msgid "Start git gui In The Submodule" msgstr "Стартиране на „git gui“ за подмодула" -#: git-gui.sh:3793 msgid "Unstage Hunk From Commit" msgstr "Изваждане на парчето от подаването" -#: git-gui.sh:3797 msgid "Unstage Lines From Commit" msgstr "Изваждане на редовете от подаването" -#: git-gui.sh:3798 git-gui.sh:3809 msgid "Revert Lines" msgstr "Връщане на редовете" -#: git-gui.sh:3800 msgid "Unstage Line From Commit" msgstr "Изваждане на реда от подаването" -#: git-gui.sh:3804 msgid "Stage Hunk For Commit" msgstr "Добавяне на парчето за подаване" -#: git-gui.sh:3808 msgid "Stage Lines For Commit" msgstr "Добавяне на редовете за подаване" -#: git-gui.sh:3811 msgid "Stage Line For Commit" msgstr "Добавяне на реда за подаване" -#: git-gui.sh:3861 msgid "Initializing..." msgstr "Инициализиране…" -#: git-gui.sh:4017 +msgid "git-gui - a graphical user interface for Git." +msgstr "git-gui — графичен интерфейс за Git." + #, tcl-format -msgid "" -"Possible environment issues exist.\n" -"\n" -"The following environment variables are probably\n" -"going to be ignored by any Git subprocess run\n" -"by %s:\n" -"\n" -msgstr "" -"Възможно е да има проблем със средата.\n" -"\n" -"Най-вероятно следните променливи няма да се\n" -"вземат под внимание от подпроцесите на Git\n" -"от %s:\n" -"\n" +msgid "%s (%s): File Viewer" +msgstr "%s (%s): Преглед на файлове" -#: git-gui.sh:4046 -msgid "" -"\n" -"This is due to a known issue with the\n" -"Tcl binary distributed by Cygwin." -msgstr "" -"\n" -"Това е познат проблем и се дължи на\n" -"версията на Tcl включена в Cygwin." +msgid "Commit:" +msgstr "Подаване:" + +msgid "Copy Commit" +msgstr "Копиране на подаване" + +msgid "Find Text..." +msgstr "Търсене на текст…" + +msgid "Goto Line..." +msgstr "Към ред…" + +msgid "Do Full Copy Detection" +msgstr "Пълно търсене на копиране" + +msgid "Show History Context" +msgstr "Показване на контекста от историята" + +msgid "Blame Parent Commit" +msgstr "Анотиране на родителското подаване" -#: git-gui.sh:4051 #, tcl-format -msgid "" -"\n" -"\n" -"A good replacement for %s\n" -"is placing values for the user.name and\n" -"user.email settings into your personal\n" -"~/.gitconfig file.\n" -msgstr "" -"\n" -"\n" -"Добър заместител на „%s“\n" -"е да поставите настройките „user.name“ и\n" -"„user.email“ в личния си файл „~/.gitconfig“.\n" +msgid "Reading %s..." +msgstr "Чете се „%s“…" -#: lib/spellcheck.tcl:57 -msgid "Unsupported spell checker" -msgstr "Тази програма за проверка на правописа не се поддържа" +msgid "Loading copy/move tracking annotations..." +msgstr "Зареждане на анотациите за проследяване на копирането/преместването…" -#: lib/spellcheck.tcl:65 -msgid "Spell checking is unavailable" -msgstr "Липсва програма за проверка на правописа" +msgid "lines annotated" +msgstr "реда анотирани" -#: lib/spellcheck.tcl:68 -msgid "Invalid spell checking configuration" -msgstr "Неправилни настройки на проверката на правописа" +msgid "Loading original location annotations..." +msgstr "Зареждане на анотациите за първоначалното местоположение…" + +msgid "Annotation complete." +msgstr "Анотирането завърши." + +msgid "Busy" +msgstr "Операцията не е завършила" + +msgid "Annotation process is already running." +msgstr "В момента тече процес на анотиране." + +msgid "Running thorough copy detection..." +msgstr "Изпълнява се цялостен процес на откриване на копиране…" + +msgid "Loading annotation..." +msgstr "Зареждане на анотации…" + +msgid "Author:" +msgstr "Автор:" + +msgid "Committer:" +msgstr "Подал:" + +msgid "Original File:" +msgstr "Първоначален файл:" + +msgid "Cannot find HEAD commit:" +msgstr "Подаването за връх „HEAD“ не може да се открие:" + +msgid "Cannot find parent commit:" +msgstr "Родителското подаване не може да се открие" + +msgid "Unable to display parent" +msgstr "Родителят не може да се покаже" + +msgid "Error loading diff:" +msgstr "Грешка при зареждане на разлика:" + +msgid "Originally By:" +msgstr "Първоначално от:" + +msgid "In File:" +msgstr "Във файл:" + +msgid "Copied Or Moved Here By:" +msgstr "Копирано или преместено тук от:" -#: lib/spellcheck.tcl:70 #, tcl-format -msgid "Reverting dictionary to %s." -msgstr "Ползване на речник за език „%s“." +msgid "%s (%s): Checkout Branch" +msgstr "%s (%s): Клон за изтегляне" -#: lib/spellcheck.tcl:73 -msgid "Spell checker silently failed on startup" -msgstr "Програмата за правопис даже не стартира успешно." +msgid "Checkout Branch" +msgstr "Клон за изтегляне" -#: lib/spellcheck.tcl:80 -msgid "Unrecognized spell checker" -msgstr "Непозната програма за проверка на правописа" +msgid "Checkout" +msgstr "Изтегляне" -#: lib/spellcheck.tcl:186 -msgid "No Suggestions" -msgstr "Няма предложения" +msgid "Cancel" +msgstr "Отказване" -#: lib/spellcheck.tcl:388 -msgid "Unexpected EOF from spell checker" -msgstr "Неочакван край на файл от програмата за проверка на правописа" +msgid "Revision" +msgstr "Версия" -#: lib/spellcheck.tcl:392 -msgid "Spell Checker Failed" -msgstr "Грешка в програмата за проверка на правописа" +msgid "Options" +msgstr "Опции" + +msgid "Fetch Tracking Branch" +msgstr "Изтегляне на промените от следения клон" + +msgid "Detach From Local Branch" +msgstr "Изтриване от локалния клон" -#: lib/transport.tcl:6 lib/remote_add.tcl:132 #, tcl-format -msgid "fetch %s" -msgstr "доставяне на „%s“" +msgid "%s (%s): Create Branch" +msgstr "%s (%s): Създаване на клон" + +msgid "Create New Branch" +msgstr "Създаване на нов клон" + +msgid "Create" +msgstr "Създаване" + +msgid "Branch Name" +msgstr "Име на клона" + +msgid "Name:" +msgstr "Име:" + +msgid "Match Tracking Branch Name" +msgstr "Съвпадане по името на следения клон" + +msgid "Starting Revision" +msgstr "Начална версия" + +msgid "Update Existing Branch:" +msgstr "Обновяване на съществуващ клон:" + +msgid "No" +msgstr "Не" + +msgid "Fast Forward Only" +msgstr "Само тривиално превъртащо сливане" + +msgid "Reset" +msgstr "Отначало" + +msgid "Checkout After Creation" +msgstr "Преминаване към клона след създаването му" + +msgid "Please select a tracking branch." +msgstr "Изберете клон за следени." -#: lib/transport.tcl:7 #, tcl-format -msgid "Fetching new changes from %s" -msgstr "Доставяне на промените от „%s“" +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "Следящият клон — „%s“, не съществува в отдалеченото хранилище." + +msgid "Please supply a branch name." +msgstr "Дайте име на клона." -#: lib/transport.tcl:18 #, tcl-format -msgid "remote prune %s" -msgstr "окастряне на следящите клони към „%s“" +msgid "'%s' is not an acceptable branch name." +msgstr "„%s“ не може да се използва за име на клон." -#: lib/transport.tcl:19 #, tcl-format -msgid "Pruning tracking branches deleted from %s" -msgstr "Окастряне на следящите клони на изтритите клони от „%s“" +msgid "%s (%s): Delete Branch" +msgstr "%s (%s): Изтриване на клон" -#: lib/transport.tcl:25 -msgid "fetch all remotes" -msgstr "доставяне от всички отдалечени" +msgid "Delete Local Branch" +msgstr "Изтриване на локален клон" -#: lib/transport.tcl:26 -msgid "Fetching new changes from all remotes" -msgstr "Доставяне на промените от всички отдалечени хранилища" +msgid "Local Branches" +msgstr "Локални клони" -#: lib/transport.tcl:40 -msgid "remote prune all remotes" -msgstr "окастряне на следящите изтрити" +msgid "Delete Only If Merged Into" +msgstr "Изтриване, само ако промените са слети и другаде" -#: lib/transport.tcl:41 -msgid "Pruning tracking branches deleted from all remotes" -msgstr "" -"Окастряне на следящите клони на изтритите клони от всички отдалечени " -"хранилища" +msgid "Always (Do not perform merge checks)" +msgstr "Винаги (без проверка за сливане)" -#: lib/transport.tcl:54 lib/transport.tcl:92 lib/transport.tcl:110 -#: lib/remote_add.tcl:162 #, tcl-format -msgid "push %s" -msgstr "изтласкване на „%s“" +msgid "The following branches are not completely merged into %s:" +msgstr "Не всички промени в клоните са слети в „%s“:" + +msgid "" +"Recovering deleted branches is difficult.\n" +"\n" +"Delete the selected branches?" +msgstr "" +"Възстановяването на изтрити клони може да е трудно.\n" +"\n" +"Сигурни ли сте, че искате да триете?" -#: lib/transport.tcl:55 #, tcl-format -msgid "Pushing changes to %s" -msgstr "Изтласкване на промените към „%s“" +msgid " - %s:" +msgstr " — „%s:“" -#: lib/transport.tcl:93 #, tcl-format -msgid "Mirroring to %s" -msgstr "Изтласкване на всичко към „%s“" +msgid "" +"Failed to delete branches:\n" +"%s" +msgstr "" +"Неуспешно триене на клони:\n" +"%s" -#: lib/transport.tcl:111 #, tcl-format -msgid "Pushing %s %s to %s" -msgstr "Изтласкване на %s „%s“ към „%s“" +msgid "%s (%s): Rename Branch" +msgstr "%s (%s): Преименуване на клон" -#: lib/transport.tcl:132 -msgid "Push Branches" -msgstr "Клони за изтласкване" +msgid "Rename Branch" +msgstr "Преименуване на клон" -#: lib/transport.tcl:141 lib/checkout_op.tcl:580 lib/remote_add.tcl:34 -#: lib/browser.tcl:292 lib/branch_checkout.tcl:30 lib/branch_rename.tcl:32 -#: lib/choose_font.tcl:45 lib/option.tcl:127 lib/tools_dlg.tcl:41 -#: lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 lib/remote_branch_delete.tcl:43 -#: lib/branch_create.tcl:37 lib/branch_delete.tcl:34 lib/merge.tcl:178 -msgid "Cancel" -msgstr "Отказване" +msgid "Rename" +msgstr "Преименуване" -#: lib/transport.tcl:147 -msgid "Source Branches" -msgstr "Клони-източници" +msgid "Branch:" +msgstr "Клон:" -#: lib/transport.tcl:162 -msgid "Destination Repository" -msgstr "Целево хранилище" +msgid "New Name:" +msgstr "Ново име:" -#: lib/transport.tcl:165 lib/remote_branch_delete.tcl:51 -msgid "Remote:" -msgstr "Отдалечено хранилище:" +msgid "Please select a branch to rename." +msgstr "Изберете клон за преименуване." -#: lib/transport.tcl:187 lib/remote_branch_delete.tcl:72 -msgid "Arbitrary Location:" -msgstr "Произволно местоположение:" +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "Клонът „%s“ вече съществува." -#: lib/transport.tcl:205 -msgid "Transfer Options" -msgstr "Настройки при пренасянето" +#, tcl-format +msgid "Failed to rename '%s'." +msgstr "Неуспешно преименуване на „%s“." -#: lib/transport.tcl:207 -msgid "Force overwrite existing branch (may discard changes)" -msgstr "" -"Изрично презаписване на съществуващ клон (някои промени може да се загубят)" +msgid "Starting..." +msgstr "Стартиране…" -#: lib/transport.tcl:211 -msgid "Use thin pack (for slow network connections)" -msgstr "Максимална компресия (за бавни мрежови връзки)" +#, tcl-format +msgid "%s (%s): File Browser" +msgstr "%s (%s): Файлов браузър" -#: lib/transport.tcl:215 -msgid "Include tags" -msgstr "Включване на етикетите" +#, tcl-format +msgid "Loading %s..." +msgstr "Зареждане на „%s“…" + +msgid "[Up To Parent]" +msgstr "[Към родителя]" -#: lib/transport.tcl:229 #, tcl-format -msgid "%s (%s): Push" -msgstr "%s (%s): Изтласкване" +msgid "%s (%s): Browse Branch Files" +msgstr "%s (%s): Разглеждане на файловете в клона" + +msgid "Browse Branch Files" +msgstr "Разглеждане на файловете в клона" + +msgid "Browse" +msgstr "Разглеждане" -#: lib/checkout_op.tcl:85 #, tcl-format msgid "Fetching %s from %s" msgstr "Доставяне на „%s“ от „%s“" -#: lib/checkout_op.tcl:133 #, tcl-format msgid "fatal: Cannot resolve %s" msgstr "фатална грешка: „%s“ не може да се открие" -#: lib/checkout_op.tcl:146 lib/sshkey.tcl:58 lib/console.tcl:81 -#: lib/database.tcl:30 msgid "Close" msgstr "Затваряне" -#: lib/checkout_op.tcl:175 #, tcl-format msgid "Branch '%s' does not exist." msgstr "Клонът „%s“ не съществува." -#: lib/checkout_op.tcl:194 #, tcl-format msgid "Failed to configure simplified git-pull for '%s'." msgstr "Неуспешно настройване на опростен git-pull за „%s“." -#: lib/checkout_op.tcl:202 lib/branch_rename.tcl:102 -#, tcl-format -msgid "Branch '%s' already exists." -msgstr "Клонът „%s“ вече съществува." - -#: lib/checkout_op.tcl:229 #, tcl-format msgid "" "Branch '%s' already exists.\n" @@ -810,21 +714,17 @@ msgstr "" "Той не може да се слее тривиално до „%s“.\n" "Необходимо е сливане." -#: lib/checkout_op.tcl:243 #, tcl-format msgid "Merge strategy '%s' not supported." msgstr "Стратегия за сливане „%s“ не се поддържа." -#: lib/checkout_op.tcl:262 #, tcl-format msgid "Failed to update '%s'." msgstr "Неуспешно обновяване на „%s“." -#: lib/checkout_op.tcl:274 msgid "Staging area (index) is already locked." msgstr "Индексът вече е заключен." -#: lib/checkout_op.tcl:289 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -841,31 +741,25 @@ msgstr "" "\n" "Автоматично ще започне нова проверка.\n" -#: lib/checkout_op.tcl:345 #, tcl-format msgid "Updating working directory to '%s'..." msgstr "Работната директория се привежда към „%s“…" -#: lib/checkout_op.tcl:346 msgid "files checked out" msgstr "файла са изтеглени" -#: lib/checkout_op.tcl:377 #, tcl-format msgid "Aborted checkout of '%s' (file level merging is required)." msgstr "" "Преустановяване на изтеглянето на „%s“ (необходимо е пофайлово сливане)." -#: lib/checkout_op.tcl:378 msgid "File level merge required." msgstr "Необходимо е пофайлово сливане." -#: lib/checkout_op.tcl:382 #, tcl-format msgid "Staying on branch '%s'." msgstr "Оставане върху клона „%s“." -#: lib/checkout_op.tcl:453 msgid "" "You are no longer on a local branch.\n" "\n" @@ -876,35 +770,25 @@ msgstr "" "\n" "Ако искате да сте на клон, създайте базиран на „Това несвързано изтегляне“." -#: lib/checkout_op.tcl:504 lib/checkout_op.tcl:508 #, tcl-format msgid "Checked out '%s'." msgstr "„%s“ е изтеглен." -#: lib/checkout_op.tcl:536 #, tcl-format msgid "Resetting '%s' to '%s' will lose the following commits:" msgstr "" "Зануляването на „%s“ към „%s“ ще доведе до загубването на следните подавания:" -#: lib/checkout_op.tcl:558 msgid "Recovering lost commits may not be easy." msgstr "Възстановяването на загубените подавания може да е трудно." -#: lib/checkout_op.tcl:563 #, tcl-format msgid "Reset '%s'?" msgstr "Зануляване на „%s“?" -#: lib/checkout_op.tcl:568 lib/tools_dlg.tcl:336 lib/merge.tcl:170 msgid "Visualize" msgstr "Визуализация" -#: lib/checkout_op.tcl:572 lib/branch_create.tcl:85 -msgid "Reset" -msgstr "Отначало" - -#: lib/checkout_op.tcl:636 #, tcl-format msgid "" "Failed to set current branch.\n" @@ -922,344 +806,18 @@ msgstr "" "Това състояние е аварийно и не трябва да се случва. Програмата „%s“ ще " "преустанови работа." -#: lib/remote_add.tcl:20 -#, tcl-format -msgid "%s (%s): Add Remote" -msgstr "%s (%s): Добавяне на отдалечено хранилище" - -#: lib/remote_add.tcl:25 -msgid "Add New Remote" -msgstr "Добавяне на отдалечено хранилище" - -#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 -msgid "Add" -msgstr "Добавяне" - -#: lib/remote_add.tcl:39 -msgid "Remote Details" -msgstr "Данни за отдалеченото хранилище" - -#: lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 lib/branch_create.tcl:44 -msgid "Name:" -msgstr "Име:" - -#: lib/remote_add.tcl:50 -msgid "Location:" -msgstr "Местоположение:" - -#: lib/remote_add.tcl:60 -msgid "Further Action" -msgstr "Следващо действие" - -#: lib/remote_add.tcl:63 -msgid "Fetch Immediately" -msgstr "Незабавно доставяне" - -#: lib/remote_add.tcl:69 -msgid "Initialize Remote Repository and Push" -msgstr "Инициализиране на отдалеченото хранилище и изтласкване на промените" - -#: lib/remote_add.tcl:75 -msgid "Do Nothing Else Now" -msgstr "Да не се прави нищо" - -#: lib/remote_add.tcl:100 -msgid "Please supply a remote name." -msgstr "Задайте име за отдалеченото хранилище." - -#: lib/remote_add.tcl:113 -#, tcl-format -msgid "'%s' is not an acceptable remote name." -msgstr "Отдалечено хранилище не може да се казва „%s“." - -#: lib/remote_add.tcl:124 -#, tcl-format -msgid "Failed to add remote '%s' of location '%s'." -msgstr "Неуспешно добавяне на отдалеченото хранилище „%s“ от адрес „%s“." - -#: lib/remote_add.tcl:133 -#, tcl-format -msgid "Fetching the %s" -msgstr "Доставяне на „%s“" - -#: lib/remote_add.tcl:156 -#, tcl-format -msgid "Do not know how to initialize repository at location '%s'." -msgstr "Хранилището с местоположение „%s“ не може да се инициализира." - -#: lib/remote_add.tcl:163 -#, tcl-format -msgid "Setting up the %s (at %s)" -msgstr "Добавяне на хранилище „%s“ (с адрес „%s“)" - -#: lib/browser.tcl:17 -msgid "Starting..." -msgstr "Стартиране…" - -#: lib/browser.tcl:27 -#, tcl-format -msgid "%s (%s): File Browser" -msgstr "%s (%s): Файлов браузър" - -#: lib/browser.tcl:132 lib/browser.tcl:149 -#, tcl-format -msgid "Loading %s..." -msgstr "Зареждане на „%s“…" - -#: lib/browser.tcl:193 -msgid "[Up To Parent]" -msgstr "[Към родителя]" - -#: lib/browser.tcl:275 -#, tcl-format -msgid "%s (%s): Browse Branch Files" -msgstr "%s (%s): Разглеждане на файловете в клона" - -#: lib/browser.tcl:282 -msgid "Browse Branch Files" -msgstr "Разглеждане на файловете в клона" - -#: lib/browser.tcl:288 lib/choose_repository.tcl:437 -#: lib/choose_repository.tcl:524 lib/choose_repository.tcl:533 -#: lib/choose_repository.tcl:1115 -msgid "Browse" -msgstr "Разглеждане" - -#: lib/browser.tcl:297 lib/branch_checkout.tcl:35 lib/tools_dlg.tcl:321 -msgid "Revision" -msgstr "Версия" - -#: lib/index.tcl:6 -msgid "Unable to unlock the index." -msgstr "Индексът не може да се отключи." - -#: lib/index.tcl:30 -msgid "Index Error" -msgstr "Грешка в индекса" - -#: lib/index.tcl:32 -msgid "" -"Updating the Git index failed. A rescan will be automatically started to " -"resynchronize git-gui." -msgstr "" -"Неуспешно обновяване на индекса на Git. Автоматично ще започне нова проверка " -"за синхронизирането на git-gui." - -#: lib/index.tcl:43 -msgid "Continue" -msgstr "Продължаване" - -#: lib/index.tcl:46 -msgid "Unlock Index" -msgstr "Отключване на индекса" - -#: lib/index.tcl:77 lib/index.tcl:146 lib/index.tcl:220 lib/index.tcl:587 -#: lib/choose_repository.tcl:999 -msgid "files" -msgstr "файлове" - -#: lib/index.tcl:326 -msgid "Unstaging selected files from commit" -msgstr "Изваждане на избраните файлове от подаването" - -#: lib/index.tcl:330 -#, tcl-format -msgid "Unstaging %s from commit" -msgstr "Изваждане на „%s“ от подаването" - -#: lib/index.tcl:369 -msgid "Ready to commit." -msgstr "Готовност за подаване." - -#: lib/index.tcl:378 -msgid "Adding selected files" -msgstr "Добавяне на избраните файлове" - -#: lib/index.tcl:382 -#, tcl-format -msgid "Adding %s" -msgstr "Добавяне на „%s“" - -#: lib/index.tcl:412 -#, tcl-format -msgid "Stage %d untracked files?" -msgstr "Да се добавят ли %d неследени файла към индекса?" - -#: lib/index.tcl:420 -msgid "Adding all changed files" -msgstr "Добавяне на всички променени файлове" - -#: lib/index.tcl:503 -#, tcl-format -msgid "Revert changes in file %s?" -msgstr "Да се махнат ли промените във файла „%s“?" - -#: lib/index.tcl:508 -#, tcl-format -msgid "Revert changes in these %i files?" -msgstr "Да се махнат ли промените в тези %i файла?" - -#: lib/index.tcl:517 -msgid "Any unstaged changes will be permanently lost by the revert." -msgstr "" -"Всички промени, които не са били добавени в индекса, ще се загубят " -"безвъзвратно." - -#: lib/index.tcl:520 lib/index.tcl:563 -msgid "Do Nothing" -msgstr "Нищо да не се прави" - -#: lib/index.tcl:545 -#, tcl-format -msgid "Delete untracked file %s?" -msgstr "Да се изтрие ли неследеният файл „%s“?" - -#: lib/index.tcl:550 -#, tcl-format -msgid "Delete these %i untracked files?" -msgstr "Да се изтрият ли тези %d неследени файла?" - -#: lib/index.tcl:560 -msgid "Files will be permanently deleted." -msgstr "Файловете ще се изтрият окончателно." - -#: lib/index.tcl:564 -msgid "Delete Files" -msgstr "Изтриване на файлове" - -#: lib/index.tcl:586 -msgid "Deleting" -msgstr "Изтриване" - -#: lib/index.tcl:665 -msgid "Encountered errors deleting files:\n" -msgstr "Грешки при изтриване на файловете:\n" - -#: lib/index.tcl:674 -#, tcl-format -msgid "None of the %d selected files could be deleted." -msgstr "Никой от избраните %d файла не бе изтрит." - -#: lib/index.tcl:679 -#, tcl-format -msgid "%d of the %d selected files could not be deleted." -msgstr "%d от избраните %d файла не бяха изтрити." - -#: lib/index.tcl:726 -msgid "Reverting selected files" -msgstr "Махане на промените в избраните файлове" - -#: lib/index.tcl:730 -#, tcl-format -msgid "Reverting %s" -msgstr "Махане на промените в „%s“" - -#: lib/branch_checkout.tcl:16 -#, tcl-format -msgid "%s (%s): Checkout Branch" -msgstr "%s (%s): Клон за изтегляне" - -#: lib/branch_checkout.tcl:21 -msgid "Checkout Branch" -msgstr "Клон за изтегляне" - -#: lib/branch_checkout.tcl:26 -msgid "Checkout" -msgstr "Изтегляне" - -#: lib/branch_checkout.tcl:39 lib/option.tcl:310 lib/branch_create.tcl:69 -msgid "Options" -msgstr "Опции" - -#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 -msgid "Fetch Tracking Branch" -msgstr "Изтегляне на промените от следения клон" - -#: lib/branch_checkout.tcl:47 -msgid "Detach From Local Branch" -msgstr "Изтриване от локалния клон" - -#: lib/status_bar.tcl:263 -#, tcl-format -msgid "%s ... %*i of %*i %s (%3i%%)" -msgstr "%s… %*i от общо %*i %s (%3i%%)" - -#: lib/remote.tcl:200 -msgid "Push to" -msgstr "Изтласкване към" - -#: lib/remote.tcl:218 -msgid "Remove Remote" -msgstr "Премахване на отдалечено хранилище" - -#: lib/remote.tcl:223 -msgid "Prune from" -msgstr "Окастряне от" - -#: lib/remote.tcl:228 -msgid "Fetch from" -msgstr "Доставяне от" - -#: lib/remote.tcl:249 lib/remote.tcl:253 lib/remote.tcl:258 lib/remote.tcl:264 -msgid "All" -msgstr "Всички" - -#: lib/branch_rename.tcl:15 -#, tcl-format -msgid "%s (%s): Rename Branch" -msgstr "%s (%s): Преименуване на клон" - -#: lib/branch_rename.tcl:23 -msgid "Rename Branch" -msgstr "Преименуване на клон" - -#: lib/branch_rename.tcl:28 -msgid "Rename" -msgstr "Преименуване" - -#: lib/branch_rename.tcl:38 -msgid "Branch:" -msgstr "Клон:" - -#: lib/branch_rename.tcl:46 -msgid "New Name:" -msgstr "Ново име:" - -#: lib/branch_rename.tcl:81 -msgid "Please select a branch to rename." -msgstr "Изберете клон за преименуване." - -#: lib/branch_rename.tcl:92 lib/branch_create.tcl:154 -msgid "Please supply a branch name." -msgstr "Дайте име на клона." - -#: lib/branch_rename.tcl:112 lib/branch_create.tcl:165 -#, tcl-format -msgid "'%s' is not an acceptable branch name." -msgstr "„%s“ не може да се използва за име на клон." - -#: lib/branch_rename.tcl:123 -#, tcl-format -msgid "Failed to rename '%s'." -msgstr "Неуспешно преименуване на „%s“." - -#: lib/choose_font.tcl:41 msgid "Select" msgstr "Избор" -#: lib/choose_font.tcl:55 msgid "Font Family" msgstr "Шрифт" -#: lib/choose_font.tcl:76 msgid "Font Size" msgstr "Размер" -#: lib/choose_font.tcl:93 msgid "Font Example" msgstr "Мостра" -#: lib/choose_font.tcl:105 msgid "" "This is example text.\n" "If you like this text, it can be your font." @@ -1267,1141 +825,137 @@ msgstr "" "Това е примерен текст.\n" "Ако ви харесва как изглежда, изберете шрифта." -#: lib/option.tcl:11 -#, tcl-format -msgid "Invalid global encoding '%s'" -msgstr "Неправилно глобално кодиране „%s“" - -#: lib/option.tcl:19 -#, tcl-format -msgid "Invalid repo encoding '%s'" -msgstr "Неправилно кодиране „%s“ на хранилището" - -#: lib/option.tcl:119 -msgid "Restore Defaults" -msgstr "Стандартни настройки" - -#: lib/option.tcl:123 -msgid "Save" -msgstr "Запазване" - -#: lib/option.tcl:133 -#, tcl-format -msgid "%s Repository" -msgstr "Хранилище „%s“" - -#: lib/option.tcl:134 -msgid "Global (All Repositories)" -msgstr "Глобално (за всички хранилища)" - -#: lib/option.tcl:140 -msgid "User Name" -msgstr "Потребителско име" - -#: lib/option.tcl:141 -msgid "Email Address" -msgstr "Адрес на е-поща" - -#: lib/option.tcl:143 -msgid "Summarize Merge Commits" -msgstr "Обобщаване на подаванията при сливане" - -#: lib/option.tcl:144 -msgid "Merge Verbosity" -msgstr "Подробности при сливанията" - -#: lib/option.tcl:145 -msgid "Show Diffstat After Merge" -msgstr "Извеждане на статистика след сливанията" - -#: lib/option.tcl:146 -msgid "Use Merge Tool" -msgstr "Използване на програма за сливане" - -#: lib/option.tcl:148 -msgid "Trust File Modification Timestamps" -msgstr "Доверие във времето на промяна на файловете" - -#: lib/option.tcl:149 -msgid "Prune Tracking Branches During Fetch" -msgstr "Окастряне на следящите клонове при доставяне" - -#: lib/option.tcl:150 -msgid "Match Tracking Branches" -msgstr "Напасване на следящите клонове" - -#: lib/option.tcl:151 -msgid "Use Textconv For Diffs and Blames" -msgstr "Използване на „textconv“ за разликите и анотирането" - -#: lib/option.tcl:152 -msgid "Blame Copy Only On Changed Files" -msgstr "Анотиране на копието само по променените файлове" - -#: lib/option.tcl:153 -msgid "Maximum Length of Recent Repositories List" -msgstr "Максимален брой на списъка „Скоро ползвани“ хранилища" - -#: lib/option.tcl:154 -msgid "Minimum Letters To Blame Copy On" -msgstr "Минимален брой знаци за анотиране на копието" - -#: lib/option.tcl:155 -msgid "Blame History Context Radius (days)" -msgstr "Исторически обхват за анотиране в дни" - -#: lib/option.tcl:156 -msgid "Number of Diff Context Lines" -msgstr "Брой редове за контекста на разликите" - -#: lib/option.tcl:157 -msgid "Additional Diff Parameters" -msgstr "Аргументи към командата за разликите" - -#: lib/option.tcl:158 -msgid "Commit Message Text Width" -msgstr "Широчина на текста на съобщението при подаване" - -#: lib/option.tcl:159 -msgid "New Branch Name Template" -msgstr "Шаблон за името на новите клони" - -#: lib/option.tcl:160 -msgid "Default File Contents Encoding" -msgstr "Кодиране на файловете" - -#: lib/option.tcl:161 -msgid "Warn before committing to a detached head" -msgstr "Предупреждаване при подаване към несвързан указател" - -#: lib/option.tcl:162 -msgid "Staging of untracked files" -msgstr "Добавяне на неследените файлове към индекса" - -#: lib/option.tcl:163 -msgid "Show untracked files" -msgstr "Показване на неследените файлове" - -#: lib/option.tcl:164 -msgid "Tab spacing" -msgstr "Ширина на табулацията" - -#: lib/option.tcl:182 lib/option.tcl:197 lib/option.tcl:220 lib/option.tcl:282 -#: lib/database.tcl:57 -#, tcl-format -msgid "%s:" -msgstr "%s:" - -#: lib/option.tcl:210 -msgid "Change" -msgstr "Смяна" - -#: lib/option.tcl:254 -msgid "Spelling Dictionary:" -msgstr "Правописен речник:" - -#: lib/option.tcl:284 -msgid "Change Font" -msgstr "Смяна на шрифта" - -#: lib/option.tcl:288 -#, tcl-format -msgid "Choose %s" -msgstr "Избор на „%s“" - -#: lib/option.tcl:294 -msgid "pt." -msgstr "тчк." - -#: lib/option.tcl:308 -msgid "Preferences" -msgstr "Настройки" - -#: lib/option.tcl:345 -msgid "Failed to completely save options:" -msgstr "Неуспешно запазване на настройките:" - -#: lib/encoding.tcl:443 -msgid "Default" -msgstr "Стандартното" - -#: lib/encoding.tcl:448 -#, tcl-format -msgid "System (%s)" -msgstr "Системното (%s)" - -#: lib/encoding.tcl:459 lib/encoding.tcl:465 -msgid "Other" -msgstr "Друго" - -#: lib/tools.tcl:76 -#, tcl-format -msgid "Running %s requires a selected file." -msgstr "За изпълнението на „%s“ трябва да изберете файл." - -#: lib/tools.tcl:92 -#, tcl-format -msgid "Are you sure you want to run %1$s on file \"%2$s\"?" -msgstr "Сигурни ли сте, че искате да изпълните „%1$s“ върху файла „%2$s“?" - -#: lib/tools.tcl:96 -#, tcl-format -msgid "Are you sure you want to run %s?" -msgstr "Сигурни ли сте, че искате да изпълните „%s“?" - -#: lib/tools.tcl:118 -#, tcl-format -msgid "Tool: %s" -msgstr "Команда: %s" - -#: lib/tools.tcl:119 -#, tcl-format -msgid "Running: %s" -msgstr "Изпълнение: %s" - -#: lib/tools.tcl:158 -#, tcl-format -msgid "Tool completed successfully: %s" -msgstr "Командата завърши успешно: %s" - -#: lib/tools.tcl:160 -#, tcl-format -msgid "Tool failed: %s" -msgstr "Командата върна грешка: %s" - -#: lib/mergetool.tcl:8 -msgid "Force resolution to the base version?" -msgstr "Да се използва базовата версия" - -#: lib/mergetool.tcl:9 -msgid "Force resolution to this branch?" -msgstr "Да се използва версията от този клон" - -#: lib/mergetool.tcl:10 -msgid "Force resolution to the other branch?" -msgstr "Да се използва версията от другия клон" - -#: lib/mergetool.tcl:14 -#, tcl-format -msgid "" -"Note that the diff shows only conflicting changes.\n" -"\n" -"%s will be overwritten.\n" -"\n" -"This operation can be undone only by restarting the merge." -msgstr "" -"Разликата показва само разликите с конфликт.\n" -"\n" -"Файлът „%s“ ще се презапише.\n" -"\n" -"Тази операция може да се отмени само чрез започване на сливането наново." - -#: lib/mergetool.tcl:45 -#, tcl-format -msgid "File %s seems to have unresolved conflicts, still stage?" -msgstr "" -"Изглежда, че все още има некоригирани конфликти във файла „%s“. Да се добави " -"ли файлът към индекса?" - -#: lib/mergetool.tcl:60 -#, tcl-format -msgid "Adding resolution for %s" -msgstr "Добавяне на корекция на конфликтите в „%s“" - -#: lib/mergetool.tcl:141 -msgid "Cannot resolve deletion or link conflicts using a tool" -msgstr "" -"Конфликтите при символни връзки или изтриване не може да се коригират с " -"външна програма." - -#: lib/mergetool.tcl:146 -msgid "Conflict file does not exist" -msgstr "Файлът, в който е конфликтът, не съществува" - -#: lib/mergetool.tcl:246 -#, tcl-format -msgid "Not a GUI merge tool: '%s'" -msgstr "Това не е графична програма за сливане: „%s“" - -#: lib/mergetool.tcl:275 -#, tcl-format -msgid "Unsupported merge tool '%s'" -msgstr "Неподдържана програма за сливане: „%s“" - -#: lib/mergetool.tcl:310 -msgid "Merge tool is already running, terminate it?" -msgstr "Програмата за сливане вече е стартирана. Да се изключи ли?" - -#: lib/mergetool.tcl:330 -#, tcl-format -msgid "" -"Error retrieving versions:\n" -"%s" -msgstr "" -"Грешка при изтеглянето на версии:\n" -"%s" - -#: lib/mergetool.tcl:350 -#, tcl-format -msgid "" -"Could not start the merge tool:\n" -"\n" -"%s" -msgstr "" -"Програмата за сливане не може да се стартира:\n" -"\n" -"%s" - -#: lib/mergetool.tcl:354 -msgid "Running merge tool..." -msgstr "Стартиране на програмата за сливане…" - -#: lib/mergetool.tcl:382 lib/mergetool.tcl:390 -msgid "Merge tool failed." -msgstr "Грешка в програмата за сливане." - -#: lib/tools_dlg.tcl:22 -#, tcl-format -msgid "%s (%s): Add Tool" -msgstr "%s (%s): Добавяне на команда" - -#: lib/tools_dlg.tcl:28 -msgid "Add New Tool Command" -msgstr "Добавяне на команда" - -#: lib/tools_dlg.tcl:34 -msgid "Add globally" -msgstr "Глобално добавяне" - -#: lib/tools_dlg.tcl:46 -msgid "Tool Details" -msgstr "Подробности за командата" - -#: lib/tools_dlg.tcl:49 -msgid "Use '/' separators to create a submenu tree:" -msgstr "За създаване на подменюта използвайте знака „/“ за разделител:" - -#: lib/tools_dlg.tcl:60 -msgid "Command:" -msgstr "Команда:" - -#: lib/tools_dlg.tcl:71 -msgid "Show a dialog before running" -msgstr "Преди изпълнение да се извежда диалогов прозорец" - -#: lib/tools_dlg.tcl:77 -msgid "Ask the user to select a revision (sets $REVISION)" -msgstr "Потребителят да укаже версия (задаване на променливата $REVISION)" - -#: lib/tools_dlg.tcl:82 -msgid "Ask the user for additional arguments (sets $ARGS)" -msgstr "" -"Потребителят да укаже допълнителни аргументи (задаване на променливата $ARGS)" - -#: lib/tools_dlg.tcl:89 -msgid "Don't show the command output window" -msgstr "Без показване на прозорец с изхода от командата" - -#: lib/tools_dlg.tcl:94 -msgid "Run only if a diff is selected ($FILENAME not empty)" -msgstr "" -"Стартиране само след избор на разлика (променливата $FILENAME не е празна)" - -#: lib/tools_dlg.tcl:118 -msgid "Please supply a name for the tool." -msgstr "Задайте име за командата." - -#: lib/tools_dlg.tcl:126 -#, tcl-format -msgid "Tool '%s' already exists." -msgstr "Командата „%s“ вече съществува." - -#: lib/tools_dlg.tcl:148 -#, tcl-format -msgid "" -"Could not add tool:\n" -"%s" -msgstr "" -"Командата не може да се добави:\n" -"%s" - -#: lib/tools_dlg.tcl:187 -#, tcl-format -msgid "%s (%s): Remove Tool" -msgstr "%s (%s): Премахване на команда" - -#: lib/tools_dlg.tcl:193 -msgid "Remove Tool Commands" -msgstr "Премахване на команди" - -#: lib/tools_dlg.tcl:198 -msgid "Remove" -msgstr "Премахване" - -#: lib/tools_dlg.tcl:231 -msgid "(Blue denotes repository-local tools)" -msgstr "(командите към локалното хранилище са обозначени в синьо)" - -#: lib/tools_dlg.tcl:283 -#, tcl-format -msgid "%s (%s):" -msgstr "%s (%s):" - -#: lib/tools_dlg.tcl:292 -#, tcl-format -msgid "Run Command: %s" -msgstr "Изпълнение на командата „%s“" - -#: lib/tools_dlg.tcl:306 -msgid "Arguments" -msgstr "Аргументи" - -#: lib/tools_dlg.tcl:341 -msgid "OK" -msgstr "Добре" - -#: lib/search.tcl:48 -msgid "Find:" -msgstr "Търсене:" - -#: lib/search.tcl:50 -msgid "Next" -msgstr "Следваща поява" - -#: lib/search.tcl:51 -msgid "Prev" -msgstr "Предишна поява" - -#: lib/search.tcl:52 -msgid "RegExp" -msgstr "РегИзр" - -#: lib/search.tcl:54 -msgid "Case" -msgstr "Главни/Малки" - -#: lib/shortcut.tcl:8 lib/shortcut.tcl:43 lib/shortcut.tcl:75 -#, tcl-format -msgid "%s (%s): Create Desktop Icon" -msgstr "%s (%s): Добавяне на икона на работния плот" - -#: lib/shortcut.tcl:24 lib/shortcut.tcl:65 -msgid "Cannot write shortcut:" -msgstr "Клавишната комбинация не може да се запази:" - -#: lib/shortcut.tcl:140 -msgid "Cannot write icon:" -msgstr "Иконата не може да се запази:" - -#: lib/remote_branch_delete.tcl:29 -#, tcl-format -msgid "%s (%s): Delete Branch Remotely" -msgstr "%s (%s): Изтриване на отдалечения клон" - -#: lib/remote_branch_delete.tcl:34 -msgid "Delete Branch Remotely" -msgstr "Изтриване на отдалечения клон" - -#: lib/remote_branch_delete.tcl:48 -msgid "From Repository" -msgstr "От хранилище" - -#: lib/remote_branch_delete.tcl:88 -msgid "Branches" -msgstr "Клони" - -#: lib/remote_branch_delete.tcl:110 -msgid "Delete Only If" -msgstr "Изтриване, само ако" - -#: lib/remote_branch_delete.tcl:112 -msgid "Merged Into:" -msgstr "Слят в:" - -#: lib/remote_branch_delete.tcl:120 lib/branch_delete.tcl:53 -msgid "Always (Do not perform merge checks)" -msgstr "Винаги (без проверка за сливане)" - -#: lib/remote_branch_delete.tcl:153 -msgid "A branch is required for 'Merged Into'." -msgstr "За данните „Слят в“ е необходимо да зададете клон." - -#: lib/remote_branch_delete.tcl:185 -#, tcl-format -msgid "" -"The following branches are not completely merged into %s:\n" -"\n" -" - %s" -msgstr "" -"Следните клони не са слети напълно в „%s“:\n" -"\n" -" ● %s" - -#: lib/remote_branch_delete.tcl:190 -#, tcl-format -msgid "" -"One or more of the merge tests failed because you have not fetched the " -"necessary commits. Try fetching from %s first." -msgstr "" -"Поне една от пробите за сливане е неуспешна, защото не сте доставили всички " -"необходими подавания. Пробвайте първо да доставите подаванията от „%s“." - -#: lib/remote_branch_delete.tcl:208 -msgid "Please select one or more branches to delete." -msgstr "Изберете поне един клон за изтриване." - -#: lib/remote_branch_delete.tcl:218 lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult.\n" -"\n" -"Delete the selected branches?" -msgstr "" -"Възстановяването на изтрити клони може да е трудно.\n" -"\n" -"Сигурни ли сте, че искате да триете?" - -#: lib/remote_branch_delete.tcl:227 -#, tcl-format -msgid "Deleting branches from %s" -msgstr "Изтриване на клони от „%s“" - -#: lib/remote_branch_delete.tcl:300 -msgid "No repository selected." -msgstr "Не е избрано хранилище." - -#: lib/remote_branch_delete.tcl:305 -#, tcl-format -msgid "Scanning %s..." -msgstr "Претърсване на „%s“…" - -#: lib/choose_repository.tcl:45 msgid "Git Gui" msgstr "ГПИ на Git" -#: lib/choose_repository.tcl:104 lib/choose_repository.tcl:427 msgid "Create New Repository" msgstr "Създаване на ново хранилище" -#: lib/choose_repository.tcl:110 msgid "New..." msgstr "Ново…" -#: lib/choose_repository.tcl:117 lib/choose_repository.tcl:511 msgid "Clone Existing Repository" msgstr "Клониране на съществуващо хранилище" -#: lib/choose_repository.tcl:128 msgid "Clone..." msgstr "Клониране…" -#: lib/choose_repository.tcl:135 lib/choose_repository.tcl:1105 msgid "Open Existing Repository" msgstr "Отваряне на съществуващо хранилище" -#: lib/choose_repository.tcl:141 msgid "Open..." msgstr "Отваряне…" -#: lib/choose_repository.tcl:154 msgid "Recent Repositories" msgstr "Скоро ползвани" -#: lib/choose_repository.tcl:164 msgid "Open Recent Repository:" msgstr "Отваряне на хранилище ползвано наскоро:" -#: lib/choose_repository.tcl:331 lib/choose_repository.tcl:338 -#: lib/choose_repository.tcl:345 #, tcl-format msgid "Failed to create repository %s:" msgstr "Неуспешно създаване на хранилището „%s“:" -#: lib/choose_repository.tcl:422 lib/branch_create.tcl:33 -msgid "Create" -msgstr "Създаване" - -#: lib/choose_repository.tcl:432 msgid "Directory:" msgstr "Директория:" -#: lib/choose_repository.tcl:462 lib/choose_repository.tcl:588 -#: lib/choose_repository.tcl:1139 msgid "Git Repository" msgstr "Хранилище на Git" -#: lib/choose_repository.tcl:487 #, tcl-format msgid "Directory %s already exists." msgstr "Вече съществува директория „%s“." -#: lib/choose_repository.tcl:491 #, tcl-format msgid "File %s already exists." msgstr "Вече съществува файл „%s“." -#: lib/choose_repository.tcl:506 msgid "Clone" msgstr "Клониране" -#: lib/choose_repository.tcl:519 msgid "Source Location:" msgstr "Адрес на източника:" -#: lib/choose_repository.tcl:528 msgid "Target Directory:" msgstr "Целева директория:" -#: lib/choose_repository.tcl:538 msgid "Clone Type:" msgstr "Вид клониране:" -#: lib/choose_repository.tcl:543 msgid "Standard (Fast, Semi-Redundant, Hardlinks)" msgstr "Стандартно (бързо, частично споделяне на файлове, твърди връзки)" -#: lib/choose_repository.tcl:548 msgid "Full Copy (Slower, Redundant Backup)" msgstr "Пълно (бавно, пълноценно резервно копие)" -#: lib/choose_repository.tcl:553 msgid "Shared (Fastest, Not Recommended, No Backup)" msgstr "Споделено (най-бързо, не се препоръчва, не прави резервно копие)" -#: lib/choose_repository.tcl:560 msgid "Recursively clone submodules too" msgstr "Рекурсивно клониране и на подмодулите" -#: lib/choose_repository.tcl:594 lib/choose_repository.tcl:641 -#: lib/choose_repository.tcl:790 lib/choose_repository.tcl:864 -#: lib/choose_repository.tcl:1145 lib/choose_repository.tcl:1153 #, tcl-format msgid "Not a Git repository: %s" msgstr "Това не е хранилище на Git: %s" -#: lib/choose_repository.tcl:630 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "Не се поддържат твърди връзки. Преминава се към копиране." + msgid "Standard only available for local repository." msgstr "Само локални хранилища може да се клонират стандартно" -#: lib/choose_repository.tcl:634 msgid "Shared only available for local repository." msgstr "Само локални хранилища може да се клонират споделено" -#: lib/choose_repository.tcl:655 #, tcl-format msgid "Location %s already exists." msgstr "Местоположението „%s“ вече съществува." -#: lib/choose_repository.tcl:666 -msgid "Failed to configure origin" -msgstr "Неуспешно настройване на хранилището-източник" - -#: lib/choose_repository.tcl:678 -msgid "Counting objects" -msgstr "Преброяване на обекти" - -#: lib/choose_repository.tcl:679 -msgid "buckets" -msgstr "клетки" - -#: lib/choose_repository.tcl:703 -#, tcl-format -msgid "Unable to copy objects/info/alternates: %s" -msgstr "Обектите/Информацията/Синонимите не може да се копират: %s" - -#: lib/choose_repository.tcl:740 -#, tcl-format -msgid "Nothing to clone from %s." -msgstr "Няма какво да се клонира от „%s“." - -#: lib/choose_repository.tcl:742 lib/choose_repository.tcl:962 -#: lib/choose_repository.tcl:974 -msgid "The 'master' branch has not been initialized." -msgstr "Основният клон — „master“ не е инициализиран." - -#: lib/choose_repository.tcl:755 -msgid "Hardlinks are unavailable. Falling back to copying." -msgstr "Не се поддържат твърди връзки. Преминава се към копиране." - -#: lib/choose_repository.tcl:769 #, tcl-format msgid "Cloning from %s" msgstr "Клониране на „%s“" -#: lib/choose_repository.tcl:800 -msgid "Copying objects" -msgstr "Копиране на обекти" - -#: lib/choose_repository.tcl:801 -msgid "KiB" -msgstr "KiB" - -#: lib/choose_repository.tcl:825 -#, tcl-format -msgid "Unable to copy object: %s" -msgstr "Неуспешно копиране на обект: %s" - -#: lib/choose_repository.tcl:837 -msgid "Linking objects" -msgstr "Създаване на връзки към обектите" - -#: lib/choose_repository.tcl:838 -msgid "objects" -msgstr "обекти" - -#: lib/choose_repository.tcl:846 -#, tcl-format -msgid "Unable to hardlink object: %s" -msgstr "Неуспешно създаване на твърда връзка към обект: %s" - -#: lib/choose_repository.tcl:903 -msgid "Cannot fetch branches and objects. See console output for details." -msgstr "" -"Клоните и обектите не може да се изтеглят. За повече информация погледнете " -"изхода на конзолата." - -#: lib/choose_repository.tcl:914 -msgid "Cannot fetch tags. See console output for details." -msgstr "" -"Етикетите не може да се изтеглят. За повече информация погледнете изхода на " -"конзолата." - -#: lib/choose_repository.tcl:938 -msgid "Cannot determine HEAD. See console output for details." -msgstr "" -"Върхът „HEAD“ не може да се определи. За повече информация погледнете изхода " -"на конзолата." - -#: lib/choose_repository.tcl:947 -#, tcl-format -msgid "Unable to cleanup %s" -msgstr "„%s“ не може да се изчисти" - -#: lib/choose_repository.tcl:953 msgid "Clone failed." msgstr "Неуспешно клониране." -#: lib/choose_repository.tcl:960 -msgid "No default branch obtained." -msgstr "Не е получен клон по подразбиране." - -#: lib/choose_repository.tcl:971 -#, tcl-format -msgid "Cannot resolve %s as a commit." -msgstr "Няма подаване отговарящо на „%s“." - -#: lib/choose_repository.tcl:998 -msgid "Creating working directory" -msgstr "Създаване на работната директория" - -#: lib/choose_repository.tcl:1028 -msgid "Initial file checkout failed." -msgstr "Неуспешно първоначално изтегляне." - -#: lib/choose_repository.tcl:1072 -msgid "Cloning submodules" -msgstr "Клониране на подмодули" - -#: lib/choose_repository.tcl:1087 -msgid "Cannot clone submodules." -msgstr "Подмодулите не може да се клонират." - -#: lib/choose_repository.tcl:1110 msgid "Repository:" msgstr "Хранилище:" -#: lib/choose_repository.tcl:1159 #, tcl-format msgid "Failed to open repository %s:" msgstr "Неуспешно отваряне на хранилището „%s“:" -#: lib/about.tcl:26 -msgid "git-gui - a graphical user interface for Git." -msgstr "git-gui — графичен интерфейс за Git." - -#: lib/blame.tcl:74 -#, tcl-format -msgid "%s (%s): File Viewer" -msgstr "%s (%s): Преглед на файлове" - -#: lib/blame.tcl:80 -msgid "Commit:" -msgstr "Подаване:" - -#: lib/blame.tcl:282 -msgid "Copy Commit" -msgstr "Копиране на подаване" - -#: lib/blame.tcl:286 -msgid "Find Text..." -msgstr "Търсене на текст…" - -#: lib/blame.tcl:290 -msgid "Goto Line..." -msgstr "Към ред…" - -#: lib/blame.tcl:299 -msgid "Do Full Copy Detection" -msgstr "Пълно търсене на копиране" - -#: lib/blame.tcl:303 -msgid "Show History Context" -msgstr "Показване на контекста от историята" - -#: lib/blame.tcl:306 -msgid "Blame Parent Commit" -msgstr "Анотиране на родителското подаване" - -#: lib/blame.tcl:468 -#, tcl-format -msgid "Reading %s..." -msgstr "Чете се „%s“…" - -#: lib/blame.tcl:596 -msgid "Loading copy/move tracking annotations..." -msgstr "Зареждане на анотациите за проследяване на копирането/преместването…" - -#: lib/blame.tcl:613 -msgid "lines annotated" -msgstr "реда анотирани" - -#: lib/blame.tcl:815 -msgid "Loading original location annotations..." -msgstr "Зареждане на анотациите за първоначалното местоположение…" - -#: lib/blame.tcl:818 -msgid "Annotation complete." -msgstr "Анотирането завърши." - -#: lib/blame.tcl:849 -msgid "Busy" -msgstr "Операцията не е завършила" - -#: lib/blame.tcl:850 -msgid "Annotation process is already running." -msgstr "В момента тече процес на анотиране." - -#: lib/blame.tcl:889 -msgid "Running thorough copy detection..." -msgstr "Изпълнява се цялостен процес на откриване на копиране…" - -#: lib/blame.tcl:957 -msgid "Loading annotation..." -msgstr "Зареждане на анотации…" - -#: lib/blame.tcl:1010 -msgid "Author:" -msgstr "Автор:" - -#: lib/blame.tcl:1014 -msgid "Committer:" -msgstr "Подал:" - -#: lib/blame.tcl:1019 -msgid "Original File:" -msgstr "Първоначален файл:" - -#: lib/blame.tcl:1067 -msgid "Cannot find HEAD commit:" -msgstr "Подаването за връх „HEAD“ не може да се открие:" - -#: lib/blame.tcl:1122 -msgid "Cannot find parent commit:" -msgstr "Родителското подаване не може да се открие" - -#: lib/blame.tcl:1137 -msgid "Unable to display parent" -msgstr "Родителят не може да се покаже" - -#: lib/blame.tcl:1138 lib/diff.tcl:345 -msgid "Error loading diff:" -msgstr "Грешка при зареждане на разлика:" - -#: lib/blame.tcl:1279 -msgid "Originally By:" -msgstr "Първоначално от:" - -#: lib/blame.tcl:1285 -msgid "In File:" -msgstr "Във файл:" - -#: lib/blame.tcl:1290 -msgid "Copied Or Moved Here By:" -msgstr "Копирано или преместено тук от:" - -#: lib/diff.tcl:77 -#, tcl-format -msgid "" -"No differences detected.\n" -"\n" -"%s has no changes.\n" -"\n" -"The modification date of this file was updated by another application, but " -"the content within the file was not changed.\n" -"\n" -"A rescan will be automatically started to find other files which may have " -"the same state." -msgstr "" -"Не са открити разлики.\n" -"\n" -"Няма промени в „%s“.\n" -"\n" -"Времето на промяна на файла е бил зададен от друга програма, но съдържанието " -"му не е променено.\n" -"\n" -"Автоматично ще започне нова проверка дали няма други файлове в това " -"състояние." - -#: lib/diff.tcl:117 -#, tcl-format -msgid "Loading diff of %s..." -msgstr "Зареждане на разликите в „%s“…" - -#: lib/diff.tcl:143 -msgid "" -"LOCAL: deleted\n" -"REMOTE:\n" -msgstr "" -"ЛОКАЛНО: изтрит\n" -"ОТДАЛЕЧЕНО:\n" - -#: lib/diff.tcl:148 -msgid "" -"REMOTE: deleted\n" -"LOCAL:\n" -msgstr "" -"ОТДАЛЕЧЕНО: изтрит\n" -"ЛОКАЛНО:\n" - -#: lib/diff.tcl:155 -msgid "LOCAL:\n" -msgstr "ЛОКАЛНО:\n" - -#: lib/diff.tcl:158 -msgid "REMOTE:\n" -msgstr "ОТДАЛЕЧЕНО:\n" - -#: lib/diff.tcl:220 lib/diff.tcl:344 -#, tcl-format -msgid "Unable to display %s" -msgstr "Файлът „%s“ не може да се покаже" - -#: lib/diff.tcl:221 -msgid "Error loading file:" -msgstr "Грешка при зареждане на файл:" - -#: lib/diff.tcl:227 -msgid "Git Repository (subproject)" -msgstr "Хранилище на Git (подмодул)" - -#: lib/diff.tcl:239 -msgid "* Binary file (not showing content)." -msgstr "● Двоичен файл (съдържанието не се показва)." - -#: lib/diff.tcl:244 -#, tcl-format -msgid "" -"* Untracked file is %d bytes.\n" -"* Showing only first %d bytes.\n" -msgstr "" -"● Неследеният файл е %d байта.\n" -"● Показват се само първите %d байта.\n" - -#: lib/diff.tcl:250 -#, tcl-format -msgid "" -"\n" -"* Untracked file clipped here by %s.\n" -"* To see the entire file, use an external editor.\n" -msgstr "" -"\n" -"● Неследеният файл е отрязан дотук от програмата „%s“.\n" -"● Използвайте външен редактор, за да видите целия файл.\n" - -#: lib/diff.tcl:583 -msgid "Failed to unstage selected hunk." -msgstr "Избраното парче не може да се извади от индекса." - -#: lib/diff.tcl:591 -msgid "Failed to revert selected hunk." -msgstr "Избраното парче не може да се върне." - -#: lib/diff.tcl:594 -msgid "Failed to stage selected hunk." -msgstr "Избраното парче не може да се добави към индекса." - -#: lib/diff.tcl:687 -msgid "Failed to unstage selected line." -msgstr "Избраният ред не може да се извади от индекса." - -#: lib/diff.tcl:696 -msgid "Failed to revert selected line." -msgstr "Избраният ред не може да се върне." - -#: lib/diff.tcl:700 -msgid "Failed to stage selected line." -msgstr "Избраният ред не може да се добави към индекса." - -#: lib/diff.tcl:889 -msgid "Failed to undo last revert." -msgstr "Неуспешна отмяна на последното връщане." - -#: lib/sshkey.tcl:34 -msgid "No keys found." -msgstr "Не са открити ключове." - -#: lib/sshkey.tcl:37 -#, tcl-format -msgid "Found a public key in: %s" -msgstr "Открит е публичен ключ в „%s“" - -#: lib/sshkey.tcl:43 -msgid "Generate Key" -msgstr "Генериране на ключ" - -#: lib/sshkey.tcl:61 -msgid "Copy To Clipboard" -msgstr "Копиране към системния буфер" - -#: lib/sshkey.tcl:75 -msgid "Your OpenSSH Public Key" -msgstr "Публичният ви ключ за OpenSSH" - -#: lib/sshkey.tcl:83 -msgid "Generating..." -msgstr "Генериране…" - -#: lib/sshkey.tcl:89 -#, tcl-format -msgid "" -"Could not start ssh-keygen:\n" -"\n" -"%s" -msgstr "" -"Програмата „ssh-keygen“ не може да се стартира:\n" -"\n" -"%s" - -#: lib/sshkey.tcl:116 -msgid "Generation failed." -msgstr "Неуспешно генериране." - -#: lib/sshkey.tcl:123 -msgid "Generation succeeded, but no keys found." -msgstr "Генерирането завърши успешно, а не са намерени ключове." - -#: lib/sshkey.tcl:126 -#, tcl-format -msgid "Your key is in: %s" -msgstr "Ключът ви е в „%s“" - -#: lib/branch_create.tcl:23 -#, tcl-format -msgid "%s (%s): Create Branch" -msgstr "%s (%s): Създаване на клон" - -#: lib/branch_create.tcl:28 -msgid "Create New Branch" -msgstr "Създаване на нов клон" - -#: lib/branch_create.tcl:42 -msgid "Branch Name" -msgstr "Име на клона" - -#: lib/branch_create.tcl:57 -msgid "Match Tracking Branch Name" -msgstr "Съвпадане по името на следения клон" - -#: lib/branch_create.tcl:66 -msgid "Starting Revision" -msgstr "Начална версия" - -#: lib/branch_create.tcl:72 -msgid "Update Existing Branch:" -msgstr "Обновяване на съществуващ клон:" - -#: lib/branch_create.tcl:75 -msgid "No" -msgstr "Не" - -#: lib/branch_create.tcl:80 -msgid "Fast Forward Only" -msgstr "Само тривиално превъртащо сливане" - -#: lib/branch_create.tcl:97 -msgid "Checkout After Creation" -msgstr "Преминаване към клона след създаването му" - -#: lib/branch_create.tcl:132 -msgid "Please select a tracking branch." -msgstr "Изберете клон за следени." - -#: lib/branch_create.tcl:141 -#, tcl-format -msgid "Tracking branch %s is not a branch in the remote repository." -msgstr "Следящият клон — „%s“, не съществува в отдалеченото хранилище." - -#: lib/console.tcl:59 -msgid "Working... please wait..." -msgstr "В момента се извършва действие, изчакайте…" - -#: lib/console.tcl:186 -msgid "Success" -msgstr "Успех" - -#: lib/console.tcl:200 -msgid "Error: Command Failed" -msgstr "Грешка: неуспешно изпълнение на команда" - -#: lib/line.tcl:17 -msgid "Goto Line:" -msgstr "Към ред:" - -#: lib/line.tcl:23 -msgid "Go" -msgstr "Към" - -#: lib/choose_rev.tcl:52 msgid "This Detached Checkout" msgstr "Това несвързано изтегляне" -#: lib/choose_rev.tcl:60 msgid "Revision Expression:" msgstr "Израз за версия:" -#: lib/choose_rev.tcl:72 msgid "Local Branch" msgstr "Локален клон" -#: lib/choose_rev.tcl:77 msgid "Tracking Branch" msgstr "Следящ клон" -#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544 msgid "Tag" msgstr "Етикет" -#: lib/choose_rev.tcl:321 #, tcl-format msgid "Invalid revision: %s" msgstr "Неправилна версия: %s" -#: lib/choose_rev.tcl:342 msgid "No revision selected." msgstr "Не е избрана версия." -#: lib/choose_rev.tcl:350 msgid "Revision expression is empty." msgstr "Изразът за версия е празен." -#: lib/choose_rev.tcl:537 msgid "Updated" msgstr "Обновен" -#: lib/choose_rev.tcl:565 msgid "URL" msgstr "Адрес" -#: lib/commit.tcl:9 msgid "" "There is nothing to amend.\n" "\n" @@ -2413,7 +967,6 @@ msgstr "" "Ще създадете първоначалното подаване. Преди него няма други подавания, които " "да поправите.\n" -#: lib/commit.tcl:18 msgid "" "Cannot amend while merging.\n" "\n" @@ -2426,24 +979,19 @@ msgstr "" "В момента все още не сте завършили операция по сливане. Не може да поправите " "предишното подаване, освен ако първо не преустановите текущото сливане.\n" -#: lib/commit.tcl:56 msgid "Error loading commit data for amend:" msgstr "Грешка при зареждане на данните от подаване, които да се поправят:" -#: lib/commit.tcl:83 msgid "Unable to obtain your identity:" msgstr "Идентификацията ви не може да се определи:" -#: lib/commit.tcl:88 msgid "Invalid GIT_COMMITTER_IDENT:" msgstr "Неправилно поле „GIT_COMMITTER_IDENT“:" -#: lib/commit.tcl:138 #, tcl-format msgid "warning: Tcl does not support encoding '%s'." msgstr "предупреждение: Tcl не поддържа кодирането „%s“." -#: lib/commit.tcl:158 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -2460,7 +1008,6 @@ msgstr "" "\n" "Автоматично ще започне нова проверка.\n" -#: lib/commit.tcl:182 #, tcl-format msgid "" "Unmerged files cannot be committed.\n" @@ -2473,7 +1020,6 @@ msgstr "" "Във файла „%s“ има конфликти при сливане. За да го подадете, трябва първо да " "коригирате конфликтите и да добавите файла към индекса за подаване.\n" -#: lib/commit.tcl:190 #, tcl-format msgid "" "Unknown file state %s detected.\n" @@ -2484,7 +1030,6 @@ msgstr "" "\n" "Файлът „%s“ не може да се подаде чрез текущата програма.\n" -#: lib/commit.tcl:198 msgid "" "No changes to commit.\n" "\n" @@ -2494,7 +1039,6 @@ msgstr "" "\n" "Трябва да добавите поне един файл към индекса, за да подадете.\n" -#: lib/commit.tcl:213 msgid "" "Please supply a commit message.\n" "\n" @@ -2512,15 +1056,12 @@ msgstr "" "● Втори ред: празен.\n" "● Останалите редове: опишете защо се налага тази промяна.\n" -#: lib/commit.tcl:244 msgid "Calling pre-commit hook..." msgstr "Изпълняване на куката преди подаване…" -#: lib/commit.tcl:259 msgid "Commit declined by pre-commit hook." msgstr "Подаването е отхвърлено от куката преди подаване." -#: lib/commit.tcl:278 msgid "" "You are about to commit on a detached head. This is a potentially dangerous " "thing to do because if you switch to another branch you will lose your " @@ -2536,32 +1077,25 @@ msgstr "" " \n" "Сигурни ли сте, че искате да извършите текущото подаване?" -#: lib/commit.tcl:299 msgid "Calling commit-msg hook..." msgstr "Изпълняване на куката за съобщението при подаване…" -#: lib/commit.tcl:314 msgid "Commit declined by commit-msg hook." msgstr "Подаването е отхвърлено от куката за съобщението при подаване." -#: lib/commit.tcl:327 msgid "Committing changes..." msgstr "Подаване на промените…" -#: lib/commit.tcl:344 msgid "write-tree failed:" msgstr "неуспешно запазване на дървото (write-tree):" -#: lib/commit.tcl:345 lib/commit.tcl:395 lib/commit.tcl:422 msgid "Commit failed." msgstr "Неуспешно подаване." -#: lib/commit.tcl:362 #, tcl-format msgid "Commit %s appears to be corrupt" msgstr "Подаването „%s“ изглежда повредено" -#: lib/commit.tcl:367 msgid "" "No changes to commit.\n" "\n" @@ -2576,106 +1110,63 @@ msgstr "" "\n" "Автоматично ще започне нова проверка.\n" -#: lib/commit.tcl:374 msgid "No changes to commit." msgstr "Няма промени за подаване." -#: lib/commit.tcl:394 msgid "commit-tree failed:" msgstr "неуспешно подаване на дървото (commit-tree):" -#: lib/commit.tcl:421 msgid "update-ref failed:" msgstr "неуспешно обновяване на указателите (update-ref):" -#: lib/commit.tcl:514 #, tcl-format msgid "Created commit %s: %s" msgstr "Успешно подаване %s: %s" -#: lib/branch_delete.tcl:16 -#, tcl-format -msgid "%s (%s): Delete Branch" -msgstr "%s (%s): Изтриване на клон" - -#: lib/branch_delete.tcl:21 -msgid "Delete Local Branch" -msgstr "Изтриване на локален клон" - -#: lib/branch_delete.tcl:39 -msgid "Local Branches" -msgstr "Локални клони" - -#: lib/branch_delete.tcl:51 -msgid "Delete Only If Merged Into" -msgstr "Изтриване, само ако промените са слети и другаде" - -#: lib/branch_delete.tcl:103 -#, tcl-format -msgid "The following branches are not completely merged into %s:" -msgstr "Не всички промени в клоните са слети в „%s“:" - -#: lib/branch_delete.tcl:131 -#, tcl-format -msgid " - %s:" -msgstr " — „%s:“" +msgid "Working... please wait..." +msgstr "В момента се извършва действие, изчакайте…" -#: lib/branch_delete.tcl:141 -#, tcl-format -msgid "" -"Failed to delete branches:\n" -"%s" -msgstr "" -"Неуспешно триене на клони:\n" -"%s" +msgid "Success" +msgstr "Успех" -#: lib/date.tcl:25 -#, tcl-format -msgid "Invalid date from Git: %s" -msgstr "Неправилни данни от Git: %s" +msgid "Error: Command Failed" +msgstr "Грешка: неуспешно изпълнение на команда" -#: lib/database.tcl:42 msgid "Number of loose objects" msgstr "Брой непакетирани обекти" -#: lib/database.tcl:43 msgid "Disk space used by loose objects" msgstr "Дисково пространство заето от непакетирани обекти" -#: lib/database.tcl:44 msgid "Number of packed objects" msgstr "Брой пакетирани обекти" -#: lib/database.tcl:45 msgid "Number of packs" msgstr "Брой пакети" -#: lib/database.tcl:46 msgid "Disk space used by packed objects" msgstr "Дисково пространство заето от пакетирани обекти" -#: lib/database.tcl:47 msgid "Packed objects waiting for pruning" msgstr "Пакетирани обекти за окастряне" -#: lib/database.tcl:48 msgid "Garbage files" msgstr "Файлове за боклука" -#: lib/database.tcl:66 +#, tcl-format +msgid "%s:" +msgstr "%s:" + #, tcl-format msgid "%s (%s): Database Statistics" msgstr "%s (%s): Статистика на базата от данни" -#: lib/database.tcl:72 msgid "Compressing the object database" msgstr "Компресиране на базата с данни за обектите" -#: lib/database.tcl:83 msgid "Verifying the object database with fsck-objects" msgstr "Проверка на базата с данни за обектите с програмата „fsck-objects“" -#: lib/database.tcl:107 #, tcl-format msgid "" "This repository currently has approximately %i loose objects.\n" @@ -2692,31 +1183,228 @@ msgstr "" "\n" "Да се започне ли компресирането?" -#: lib/error.tcl:20 +#, tcl-format +msgid "Invalid date from Git: %s" +msgstr "Неправилни данни от Git: %s" + +msgid "" +"* No differences detected; stage the file to de-list it from Unstaged " +"Changes.\n" +msgstr "" +"● Няма разлики. Добавете файла към индекса, за да се извади от промените " +"извън индекса.\n" + +msgid "* Click to find other files that may have the same state.\n" +msgstr "● Натиснете, за да потърсите други файлове в това състояние.\n" + +#, tcl-format +msgid "Loading diff of %s..." +msgstr "Зареждане на разликите в „%s“…" + +msgid "" +"LOCAL: deleted\n" +"REMOTE:\n" +msgstr "" +"ЛОКАЛНО: изтрит\n" +"ОТДАЛЕЧЕНО:\n" + +msgid "" +"REMOTE: deleted\n" +"LOCAL:\n" +msgstr "" +"ОТДАЛЕЧЕНО: изтрит\n" +"ЛОКАЛНО:\n" + +msgid "LOCAL:\n" +msgstr "ЛОКАЛНО:\n" + +msgid "REMOTE:\n" +msgstr "ОТДАЛЕЧЕНО:\n" + +#, tcl-format +msgid "Unable to display %s" +msgstr "Файлът „%s“ не може да се покаже" + +msgid "Error loading file:" +msgstr "Грешка при зареждане на файл:" + +msgid "Git Repository (subproject)" +msgstr "Хранилище на Git (подмодул)" + +msgid "* Binary file (not showing content)." +msgstr "● Двоичен файл (съдържанието не се показва)." + +#, tcl-format +msgid "" +"* Untracked file is %d bytes.\n" +"* Showing only first %d bytes.\n" +msgstr "" +"● Неследеният файл е %d байта.\n" +"● Показват се само първите %d байта.\n" + +#, tcl-format +msgid "" +"\n" +"* Untracked file clipped here by %s.\n" +"* To see the entire file, use an external editor.\n" +msgstr "" +"\n" +"● Неследеният файл е отрязан дотук от програмата „%s“.\n" +"● Използвайте външен редактор, за да видите целия файл.\n" + +msgid "Failed to unstage selected hunk." +msgstr "Избраното парче не може да се извади от индекса." + +msgid "Failed to revert selected hunk." +msgstr "Избраното парче не може да се върне." + +msgid "Failed to stage selected hunk." +msgstr "Избраното парче не може да се добави към индекса." + +msgid "Failed to unstage selected line." +msgstr "Избраният ред не може да се извади от индекса." + +msgid "Failed to revert selected line." +msgstr "Избраният ред не може да се върне." + +msgid "Failed to stage selected line." +msgstr "Избраният ред не може да се добави към индекса." + +msgid "Failed to undo last revert." +msgstr "Неуспешна отмяна на последното връщане." + +msgid "Default" +msgstr "Стандартното" + +#, tcl-format +msgid "System (%s)" +msgstr "Системното (%s)" + +msgid "Other" +msgstr "Друго" + #, tcl-format msgid "%s: error" msgstr "%s: грешка" -#: lib/error.tcl:36 #, tcl-format msgid "%s: warning" msgstr "%s: предупреждение" -#: lib/error.tcl:80 #, tcl-format msgid "%s hook failed:" msgstr "%s: грешка от куката" -#: lib/error.tcl:96 msgid "You must correct the above errors before committing." msgstr "Преди да можете да подадете, коригирайте горните грешки." -#: lib/error.tcl:116 #, tcl-format msgid "%s (%s): error" msgstr "%s (%s): грешка" -#: lib/merge.tcl:13 +msgid "Unable to unlock the index." +msgstr "Индексът не може да се отключи." + +msgid "Index Error" +msgstr "Грешка в индекса" + +msgid "" +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." +msgstr "" +"Неуспешно обновяване на индекса на Git. Автоматично ще започне нова проверка " +"за синхронизирането на git-gui." + +msgid "Continue" +msgstr "Продължаване" + +msgid "Unlock Index" +msgstr "Отключване на индекса" + +msgid "files" +msgstr "файлове" + +msgid "Unstaging selected files from commit" +msgstr "Изваждане на избраните файлове от подаването" + +#, tcl-format +msgid "Unstaging %s from commit" +msgstr "Изваждане на „%s“ от подаването" + +msgid "Ready to commit." +msgstr "Готовност за подаване." + +msgid "Adding selected files" +msgstr "Добавяне на избраните файлове" + +#, tcl-format +msgid "Adding %s" +msgstr "Добавяне на „%s“" + +#, tcl-format +msgid "Stage %d untracked files?" +msgstr "Да се добавят ли %d неследени файла към индекса?" + +msgid "Adding all changed files" +msgstr "Добавяне на всички променени файлове" + +#, tcl-format +msgid "Revert changes in file %s?" +msgstr "Да се махнат ли промените във файла „%s“?" + +#, tcl-format +msgid "Revert changes in these %i files?" +msgstr "Да се махнат ли промените в тези %i файла?" + +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" +"Всички промени, които не са били добавени в индекса, ще се загубят " +"безвъзвратно." + +msgid "Do Nothing" +msgstr "Нищо да не се прави" + +#, tcl-format +msgid "Delete untracked file %s?" +msgstr "Да се изтрие ли неследеният файл „%s“?" + +#, tcl-format +msgid "Delete these %i untracked files?" +msgstr "Да се изтрият ли тези %d неследени файла?" + +msgid "Files will be permanently deleted." +msgstr "Файловете ще се изтрият окончателно." + +msgid "Delete Files" +msgstr "Изтриване на файлове" + +msgid "Deleting" +msgstr "Изтриване" + +msgid "Encountered errors deleting files:\n" +msgstr "Грешки при изтриване на файловете:\n" + +#, tcl-format +msgid "None of the %d selected files could be deleted." +msgstr "Никой от избраните %d файла не бе изтрит." + +#, tcl-format +msgid "%d of the %d selected files could not be deleted." +msgstr "%d от избраните %d файла не бяха изтрити." + +msgid "Reverting selected files" +msgstr "Махане на промените в избраните файлове" + +#, tcl-format +msgid "Reverting %s" +msgstr "Махане на промените в „%s“" + +msgid "Goto Line:" +msgstr "Към ред:" + +msgid "Go" +msgstr "Към" + msgid "" "Cannot merge while amending.\n" "\n" @@ -2727,7 +1415,6 @@ msgstr "" "Трябва да завършите поправянето на текущото подаване, преди да започнете " "сливане.\n" -#: lib/merge.tcl:27 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -2744,7 +1431,6 @@ msgstr "" "Автоматично ще започне нова проверка.\n" "\n" -#: lib/merge.tcl:45 #, tcl-format msgid "" "You are in the middle of a conflicted merge.\n" @@ -2762,7 +1448,6 @@ msgstr "" "завършите текущото сливане чрез подаване. Чак тогава може да започнете ново " "сливане.\n" -#: lib/merge.tcl:55 #, tcl-format msgid "" "You are in the middle of a change.\n" @@ -2779,39 +1464,31 @@ msgstr "" "Трябва да завършите текущото подаване, преди да започнете сливане. Така ще " "можете лесно да преустановите сливането, ако възникне нужда.\n" -#: lib/merge.tcl:108 #, tcl-format msgid "%s of %s" msgstr "%s от общо %s" -#: lib/merge.tcl:126 #, tcl-format msgid "Merging %s and %s..." msgstr "Сливане на „%s“ и „%s“…" -#: lib/merge.tcl:137 msgid "Merge completed successfully." msgstr "Сливането завърши успешно." -#: lib/merge.tcl:139 msgid "Merge failed. Conflict resolution is required." msgstr "Неуспешно сливане — има конфликти за коригиране." -#: lib/merge.tcl:156 #, tcl-format msgid "%s (%s): Merge" msgstr "%s (%s): Сливане" -#: lib/merge.tcl:164 #, tcl-format msgid "Merge Into %s" msgstr "Сливане в „%s“" -#: lib/merge.tcl:183 msgid "Revision To Merge" msgstr "Версия за сливане" -#: lib/merge.tcl:218 msgid "" "Cannot abort while amending.\n" "\n" @@ -2821,7 +1498,6 @@ msgstr "" "\n" "Трябва да завършите поправката на това подаване.\n" -#: lib/merge.tcl:228 msgid "" "Abort merge?\n" "\n" @@ -2835,7 +1511,6 @@ msgstr "" "\n" "Наистина ли да се преустанови сливането?" -#: lib/merge.tcl:234 msgid "" "Reset changes?\n" "\n" @@ -2849,18 +1524,621 @@ msgstr "" "\n" "Наистина ли да се занулят промените?" -#: lib/merge.tcl:246 msgid "Aborting" msgstr "Преустановяване" -#: lib/merge.tcl:247 msgid "files reset" msgstr "файла със занулени промени" -#: lib/merge.tcl:277 msgid "Abort failed." msgstr "Неуспешно преустановяване." -#: lib/merge.tcl:279 msgid "Abort completed. Ready." msgstr "Успешно преустановяване. Готовност за следващо действие." + +msgid "Force resolution to the base version?" +msgstr "Да се използва базовата версия" + +msgid "Force resolution to this branch?" +msgstr "Да се използва версията от този клон" + +msgid "Force resolution to the other branch?" +msgstr "Да се използва версията от другия клон" + +#, tcl-format +msgid "" +"Note that the diff shows only conflicting changes.\n" +"\n" +"%s will be overwritten.\n" +"\n" +"This operation can be undone only by restarting the merge." +msgstr "" +"Разликата показва само разликите с конфликт.\n" +"\n" +"Файлът „%s“ ще се презапише.\n" +"\n" +"Тази операция може да се отмени само чрез започване на сливането наново." + +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" +msgstr "" +"Изглежда, че все още има некоригирани конфликти във файла „%s“. Да се добави " +"ли файлът към индекса?" + +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Добавяне на корекция на конфликтите в „%s“" + +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "" +"Конфликтите при символни връзки или изтриване не може да се коригират с " +"външна програма." + +msgid "Conflict file does not exist" +msgstr "Файлът, в който е конфликтът, не съществува" + +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "Това не е графична програма за сливане: „%s“" + +#, tcl-format +msgid "" +"Unable to process square brackets in \"mergetool.%s.cmd\" configuration " +"option.\n" +"\n" +"Please remove the square brackets." +msgstr "" +"Квадратните скоби в настройката „mergetool.%s.cmd“ не може да се обработят.\n" +"\n" +"Махнете ги." + +#, tcl-format +msgid "" +"Unsupported merge tool '%s'.\n" +"\n" +"To use this tool, configure \"mergetool.%s.cmd\" as shown in the git-config " +"manual page." +msgstr "" +"Неподдържана програма за сливане: „%s“.\n" +"\n" +"За да я използвате, настройте „mergetool.%s.cmd“ както както е обяснено в " +"страницата на ръководството за „git-config“." + +msgid "Merge tool is already running, terminate it?" +msgstr "Програмата за сливане вече е стартирана. Да се изключи ли?" + +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Грешка при изтеглянето на версии:\n" +"%s" + +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Програмата за сливане не може да се стартира:\n" +"\n" +"%s" + +msgid "Running merge tool..." +msgstr "Стартиране на програмата за сливане…" + +msgid "Merge tool failed." +msgstr "Грешка в програмата за сливане." + +#, tcl-format +msgid "Invalid global encoding '%s'" +msgstr "Неправилно глобално кодиране „%s“" + +#, tcl-format +msgid "Invalid repo encoding '%s'" +msgstr "Неправилно кодиране „%s“ на хранилището" + +msgid "Restore Defaults" +msgstr "Стандартни настройки" + +msgid "Save" +msgstr "Запазване" + +#, tcl-format +msgid "%s Repository" +msgstr "Хранилище „%s“" + +msgid "Global (All Repositories)" +msgstr "Глобално (за всички хранилища)" + +msgid "User Name" +msgstr "Потребителско име" + +msgid "Email Address" +msgstr "Адрес на е-поща" + +msgid "Summarize Merge Commits" +msgstr "Обобщаване на подаванията при сливане" + +msgid "Merge Verbosity" +msgstr "Подробности при сливанията" + +msgid "Show Diffstat After Merge" +msgstr "Извеждане на статистика след сливанията" + +msgid "Use Merge Tool" +msgstr "Използване на програма за сливане" + +msgid "Trust File Modification Timestamps" +msgstr "Доверие във времето на промяна на файловете" + +msgid "Prune Tracking Branches During Fetch" +msgstr "Окастряне на следящите клонове при доставяне" + +msgid "Match Tracking Branches" +msgstr "Напасване на следящите клонове" + +msgid "Use Textconv For Diffs and Blames" +msgstr "Използване на „textconv“ за разликите и анотирането" + +msgid "Blame Copy Only On Changed Files" +msgstr "Анотиране на копието само по променените файлове" + +msgid "Maximum Length of Recent Repositories List" +msgstr "Максимален брой на списъка „Скоро ползвани“ хранилища" + +msgid "Minimum Letters To Blame Copy On" +msgstr "Минимален брой знаци за анотиране на копието" + +msgid "Blame History Context Radius (days)" +msgstr "Исторически обхват за анотиране в дни" + +msgid "Number of Diff Context Lines" +msgstr "Брой редове за контекста на разликите" + +msgid "Additional Diff Parameters" +msgstr "Аргументи към командата за разликите" + +msgid "Commit Message Text Width" +msgstr "Широчина на текста на съобщението при подаване" + +msgid "New Branch Name Template" +msgstr "Шаблон за името на новите клони" + +msgid "Default File Contents Encoding" +msgstr "Кодиране на файловете" + +msgid "Warn before committing to a detached head" +msgstr "Предупреждаване при подаване към несвързан указател" + +msgid "Staging of untracked files" +msgstr "Добавяне на неследените файлове към индекса" + +msgid "Show untracked files" +msgstr "Показване на неследените файлове" + +msgid "Tab spacing" +msgstr "Ширина на табулацията" + +msgid "Change" +msgstr "Смяна" + +msgid "Spelling Dictionary:" +msgstr "Правописен речник:" + +msgid "Change Font" +msgstr "Смяна на шрифта" + +#, tcl-format +msgid "Choose %s" +msgstr "Избор на „%s“" + +msgid "pt." +msgstr "тчк." + +msgid "Preferences" +msgstr "Настройки" + +msgid "Failed to completely save options:" +msgstr "Неуспешно запазване на настройките:" + +#, tcl-format +msgid "%s (%s): Add Remote" +msgstr "%s (%s): Добавяне на отдалечено хранилище" + +msgid "Add New Remote" +msgstr "Добавяне на отдалечено хранилище" + +msgid "Add" +msgstr "Добавяне" + +msgid "Remote Details" +msgstr "Данни за отдалеченото хранилище" + +msgid "Location:" +msgstr "Местоположение:" + +msgid "Further Action" +msgstr "Следващо действие" + +msgid "Fetch Immediately" +msgstr "Незабавно доставяне" + +msgid "Initialize Remote Repository and Push" +msgstr "Инициализиране на отдалеченото хранилище и изтласкване на промените" + +msgid "Do Nothing Else Now" +msgstr "Да не се прави нищо" + +msgid "Please supply a remote name." +msgstr "Задайте име за отдалеченото хранилище." + +#, tcl-format +msgid "'%s' is not an acceptable remote name." +msgstr "Отдалечено хранилище не може да се казва „%s“." + +#, tcl-format +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Неуспешно добавяне на отдалеченото хранилище „%s“ от адрес „%s“." + +#, tcl-format +msgid "fetch %s" +msgstr "доставяне на „%s“" + +#, tcl-format +msgid "Fetching the %s" +msgstr "Доставяне на „%s“" + +#, tcl-format +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Хранилището с местоположение „%s“ не може да се инициализира." + +#, tcl-format +msgid "push %s" +msgstr "изтласкване на „%s“" + +#, tcl-format +msgid "Setting up the %s (at %s)" +msgstr "Добавяне на хранилище „%s“ (с адрес „%s“)" + +#, tcl-format +msgid "%s (%s): Delete Branch Remotely" +msgstr "%s (%s): Изтриване на отдалечения клон" + +msgid "Delete Branch Remotely" +msgstr "Изтриване на отдалечения клон" + +msgid "From Repository" +msgstr "От хранилище" + +msgid "Remote:" +msgstr "Отдалечено хранилище:" + +msgid "Arbitrary Location:" +msgstr "Произволно местоположение:" + +msgid "Branches" +msgstr "Клони" + +msgid "Delete Only If" +msgstr "Изтриване, само ако" + +msgid "Merged Into:" +msgstr "Слят в:" + +msgid "A branch is required for 'Merged Into'." +msgstr "За данните „Слят в“ е необходимо да зададете клон." + +#, tcl-format +msgid "" +"The following branches are not completely merged into %s:\n" +"\n" +" - %s" +msgstr "" +"Следните клони не са слети напълно в „%s“:\n" +"\n" +" ● %s" + +#, tcl-format +msgid "" +"One or more of the merge tests failed because you have not fetched the " +"necessary commits. Try fetching from %s first." +msgstr "" +"Поне една от пробите за сливане е неуспешна, защото не сте доставили всички " +"необходими подавания. Пробвайте първо да доставите подаванията от „%s“." + +msgid "Please select one or more branches to delete." +msgstr "Изберете поне един клон за изтриване." + +#, tcl-format +msgid "Deleting branches from %s" +msgstr "Изтриване на клони от „%s“" + +msgid "No repository selected." +msgstr "Не е избрано хранилище." + +#, tcl-format +msgid "Scanning %s..." +msgstr "Претърсване на „%s“…" + +msgid "Push to" +msgstr "Изтласкване към" + +msgid "Remove Remote" +msgstr "Премахване на отдалечено хранилище" + +msgid "Prune from" +msgstr "Окастряне от" + +msgid "Fetch from" +msgstr "Доставяне от" + +msgid "All" +msgstr "Всички" + +msgid "Find:" +msgstr "Търсене:" + +msgid "Next" +msgstr "Следваща поява" + +msgid "Prev" +msgstr "Предишна поява" + +msgid "RegExp" +msgstr "РегИзр" + +msgid "Case" +msgstr "Главни/Малки" + +#, tcl-format +msgid "%s (%s): Create Desktop Icon" +msgstr "%s (%s): Добавяне на икона на работния плот" + +msgid "Cannot write shortcut:" +msgstr "Клавишната комбинация не може да се запази:" + +msgid "Cannot write icon:" +msgstr "Иконата не може да се запази:" + +msgid "Unsupported spell checker" +msgstr "Тази програма за проверка на правописа не се поддържа" + +msgid "Spell checking is unavailable" +msgstr "Липсва програма за проверка на правописа" + +msgid "Invalid spell checking configuration" +msgstr "Неправилни настройки на проверката на правописа" + +#, tcl-format +msgid "Reverting dictionary to %s." +msgstr "Ползване на речник за език „%s“." + +msgid "Spell checker silently failed on startup" +msgstr "Програмата за правопис даже не стартира успешно." + +msgid "Unrecognized spell checker" +msgstr "Непозната програма за проверка на правописа" + +msgid "No Suggestions" +msgstr "Няма предложения" + +msgid "Unexpected EOF from spell checker" +msgstr "Неочакван край на файл от програмата за проверка на правописа" + +msgid "Spell Checker Failed" +msgstr "Грешка в програмата за проверка на правописа" + +msgid "No keys found." +msgstr "Не са открити ключове." + +#, tcl-format +msgid "Found a public key in: %s" +msgstr "Открит е публичен ключ в „%s“" + +msgid "Generate Key" +msgstr "Генериране на ключ" + +msgid "Copy To Clipboard" +msgstr "Копиране към системния буфер" + +msgid "Your OpenSSH Public Key" +msgstr "Публичният ви ключ за OpenSSH" + +msgid "Generating..." +msgstr "Генериране…" + +#, tcl-format +msgid "" +"Could not start ssh-keygen:\n" +"\n" +"%s" +msgstr "" +"Програмата „ssh-keygen“ не може да се стартира:\n" +"\n" +"%s" + +msgid "Generation failed." +msgstr "Неуспешно генериране." + +msgid "Generation succeeded, but no keys found." +msgstr "Генерирането завърши успешно, а не са намерени ключове." + +#, tcl-format +msgid "Your key is in: %s" +msgstr "Ключът ви е в „%s“" + +#, tcl-format +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "%s… %*i от общо %*i %s (%3i%%)" + +#, tcl-format +msgid "%s (%s): Add Tool" +msgstr "%s (%s): Добавяне на команда" + +msgid "Add New Tool Command" +msgstr "Добавяне на команда" + +msgid "Add globally" +msgstr "Глобално добавяне" + +msgid "Tool Details" +msgstr "Подробности за командата" + +msgid "Use '/' separators to create a submenu tree:" +msgstr "За създаване на подменюта използвайте знака „/“ за разделител:" + +msgid "Command:" +msgstr "Команда:" + +msgid "Show a dialog before running" +msgstr "Преди изпълнение да се извежда диалогов прозорец" + +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Потребителят да укаже версия (задаване на променливата $REVISION)" + +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "" +"Потребителят да укаже допълнителни аргументи (задаване на променливата $ARGS)" + +msgid "Don't show the command output window" +msgstr "Без показване на прозорец с изхода от командата" + +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "" +"Стартиране само след избор на разлика (променливата $FILENAME не е празна)" + +msgid "Please supply a name for the tool." +msgstr "Задайте име за командата." + +#, tcl-format +msgid "Tool '%s' already exists." +msgstr "Командата „%s“ вече съществува." + +#, tcl-format +msgid "" +"Could not add tool:\n" +"%s" +msgstr "" +"Командата не може да се добави:\n" +"%s" + +#, tcl-format +msgid "%s (%s): Remove Tool" +msgstr "%s (%s): Премахване на команда" + +msgid "Remove Tool Commands" +msgstr "Премахване на команди" + +msgid "Remove" +msgstr "Премахване" + +msgid "(Blue denotes repository-local tools)" +msgstr "(командите към локалното хранилище са обозначени в синьо)" + +#, tcl-format +msgid "%s (%s):" +msgstr "%s (%s):" + +#, tcl-format +msgid "Run Command: %s" +msgstr "Изпълнение на командата „%s“" + +msgid "Arguments" +msgstr "Аргументи" + +msgid "OK" +msgstr "Добре" + +#, tcl-format +msgid "Running %s requires a selected file." +msgstr "За изпълнението на „%s“ трябва да изберете файл." + +#, tcl-format +msgid "Are you sure you want to run %1$s on file \"%2$s\"?" +msgstr "Сигурни ли сте, че искате да изпълните „%1$s“ върху файла „%2$s“?" + +#, tcl-format +msgid "Are you sure you want to run %s?" +msgstr "Сигурни ли сте, че искате да изпълните „%s“?" + +#, tcl-format +msgid "Tool: %s" +msgstr "Команда: %s" + +#, tcl-format +msgid "Running: %s" +msgstr "Изпълнение: %s" + +#, tcl-format +msgid "Tool completed successfully: %s" +msgstr "Командата завърши успешно: %s" + +#, tcl-format +msgid "Tool failed: %s" +msgstr "Командата върна грешка: %s" + +#, tcl-format +msgid "Fetching new changes from %s" +msgstr "Доставяне на промените от „%s“" + +#, tcl-format +msgid "remote prune %s" +msgstr "окастряне на следящите клони към „%s“" + +#, tcl-format +msgid "Pruning tracking branches deleted from %s" +msgstr "Окастряне на следящите клони на изтритите клони от „%s“" + +msgid "fetch all remotes" +msgstr "доставяне от всички отдалечени" + +msgid "Fetching new changes from all remotes" +msgstr "Доставяне на промените от всички отдалечени хранилища" + +msgid "remote prune all remotes" +msgstr "окастряне на следящите изтрити" + +msgid "Pruning tracking branches deleted from all remotes" +msgstr "" +"Окастряне на следящите клони на изтритите клони от всички отдалечени " +"хранилища" + +#, tcl-format +msgid "Pushing changes to %s" +msgstr "Изтласкване на промените към „%s“" + +#, tcl-format +msgid "Mirroring to %s" +msgstr "Изтласкване на всичко към „%s“" + +#, tcl-format +msgid "Pushing %s %s to %s" +msgstr "Изтласкване на %s „%s“ към „%s“" + +msgid "Push Branches" +msgstr "Клони за изтласкване" + +msgid "Source Branches" +msgstr "Клони-източници" + +msgid "Destination Repository" +msgstr "Целево хранилище" + +msgid "Transfer Options" +msgstr "Настройки при пренасянето" + +msgid "Force overwrite existing branch (may discard changes)" +msgstr "" +"Изрично презаписване на съществуващ клон (някои промени може да се загубят)" + +msgid "Use thin pack (for slow network connections)" +msgstr "Максимална компресия (за бавни мрежови връзки)" + +msgid "Include tags" +msgstr "Включване на етикетите" + +#, tcl-format +msgid "%s (%s): Push" +msgstr "%s (%s): Изтласкване" diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index b1845c5055..38debe376c 100755 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,13 +13,5 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set basedir [file dirname \ - [file dirname \ - [file dirname [info script]]]] -set bindir [file join $basedir bin] -set bindir "$bindir;[file join $basedir mingw bin]" -regsub -all ";" $bindir "\\;" bindir -set env(PATH) "$bindir;$env(PATH)" -unset bindir - -source [file join [file dirname [info script]] git-gui.tcl] +set thisdir [file normalize [file dirname [info script]]] +source [file join $thisdir git-gui.tcl] diff --git a/git-send-email.perl b/git-send-email.perl index cb6dca2500..437f8ac46a 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -2112,6 +2112,17 @@ if ($validate) { } } + # Validate the SMTP server port, if provided. + if (defined $smtp_server_port) { + my $port = Git::port_num($smtp_server_port); + if ($port) { + $smtp_server_port = $port; + } else { + die sprintf(__("error: invalid SMTP port '%s'\n"), + $smtp_server_port); + } + } + # Run the loop once again to avoid gaps in the counter due to FIFO # arguments provided by the user. my $num = 1; diff --git a/gitk-git/gitk b/gitk-git/gitk index 5be8b2aeb0..3b6acfc592 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -7,7 +7,51 @@ exec wish "$0" -- "$@" # and distributed under the terms of the GNU General Public Licence, # either version 2, or (at your option) any later version. -package require Tk +if {[catch {package require Tcl 8.6-} err]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title "gitk: fatal error" \ + -message $err + exit 1 +} + +set MIN_GIT_VERSION 2.20 +regexp {^git version ([\d.]*\d)} [exec git version] _ git_version +if {[package vcompare $git_version $MIN_GIT_VERSION] < 0} { + set message "The git executable found is too old. +The minimum required version is $MIN_GIT_VERSION.0. +The version of git found is $git_version." + + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title "gitk: fatal error" \ + -message $message + exit 1 +} + +###################################################################### +## Enable Tcl8 profile in Tcl9, allowing consumption of data that has +## bytes not conforming to the assumed encoding profile. + +if {[package vcompare $::tcl_version 9.0] >= 0} { + rename open _strict_open + proc open args { + set f [_strict_open {*}$args] + chan configure $f -profile tcl8 + return $f + } + proc convertfrom args { + return [encoding convertfrom -profile tcl8 {*}$args] + } +} else { + proc convertfrom args { + return [encoding convertfrom {*}$args] + } +} ###################################################################### ## @@ -345,7 +389,7 @@ proc unmerged_files {files} { proc parseviewargs {n arglist} { global vdatemode vmergeonly vflags vdflags vrevs vfiltered vorigargs env global vinlinediff - global worddiff git_version + global worddiff set vdatemode($n) 0 set vmergeonly($n) 0 @@ -396,14 +440,10 @@ proc parseviewargs {n arglist} { "--color-words*" - "--word-diff=color" { # These trigger a word diff in the console interface, # so help the user by enabling our own support - if {[package vcompare $git_version "1.7.2"] >= 0} { - set worddiff [mc "Color words"] - } + set worddiff [mc "Color words"] } "--word-diff*" { - if {[package vcompare $git_version "1.7.2"] >= 0} { - set worddiff [mc "Markup words"] - } + set worddiff [mc "Markup words"] } "--stat=*" - "--numstat" - "--shortstat" - "--summary" - "--check" - "--exit-code" - "--quiet" - "--topo-order" - @@ -479,6 +519,7 @@ proc parseviewargs {n arglist} { proc parseviewrevs {view revs} { global vposids vnegids + global hashlength if {$revs eq {}} { set revs HEAD @@ -492,7 +533,7 @@ proc parseviewrevs {view revs} { set badrev {} for {set l 0} {$l < [llength $errlines]} {incr l} { set line [lindex $errlines $l] - if {!([string length $line] == 40 && [string is xdigit $line])} { + if {!([string length $line] == $hashlength && [string is xdigit $line])} { if {[string match "fatal:*" $line]} { if {[string match "fatal: ambiguous argument*" $line] && $badrev ne {}} { @@ -551,7 +592,6 @@ proc start_rev_list {view} { global viewactive viewinstances vmergeonly global mainheadid viewmainheadid viewmainheadid_orig global vcanopt vflags vrevs vorigargs - global show_notes set startmsecs [clock clicks -milliseconds] set commitidx($view) 0 @@ -601,7 +641,7 @@ proc start_rev_list {view} { } if {[catch { - set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw $show_notes \ + set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw --show-notes \ --parents --boundary $args --stdin] \ [list "<<[join [concat $revs "--" $files] "\n"]"]] } err]} { @@ -697,7 +737,7 @@ proc updatecommits {} { global mainheadid viewmainheadid viewmainheadid_orig pending_select global hasworktree global varcid vposids vnegids vflags vrevs - global show_notes + global hashlength set hasworktree [hasworktree] rereadrefs @@ -731,7 +771,7 @@ proc updatecommits {} { # take out positive refs that we asked for before or # that we have already seen foreach rev $revs { - if {[string length $rev] == 40} { + if {[string length $rev] == $hashlength} { if {[lsearch -exact $oldpos $rev] < 0 && ![info exists varcid($view,$rev)]} { lappend newrevs $rev @@ -754,7 +794,7 @@ proc updatecommits {} { set args $vorigargs($view) } if {[catch { - set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw $show_notes \ + set fd [safe_open_command_redirect [concat git log --no-color -z --pretty=raw --show-notes \ --parents --boundary $args --stdin] \ [list "<<[join [concat $revs "--" $vfilelimit($view)] "\n"]"]] } err]} { @@ -1614,6 +1654,7 @@ proc getcommitlines {fd inst view updating} { global parents children curview hlview global idpending ordertok global varccommits varcid varctok vtokmod vfilelimit vshortids + global hashlength set stuff [read $fd 500000] # git log doesn't terminate the last commit with a null... @@ -1696,7 +1737,7 @@ proc getcommitlines {fd inst view updating} { } set ok 1 foreach id $ids { - if {[string length $id] != 40} { + if {[string length $id] != $hashlength} { set ok 0 break } @@ -1942,8 +1983,8 @@ proc getcommit {id} { return 1 } -# Expand an abbreviated commit ID to a list of full 40-char IDs that match -# and are present in the current view. +# Expand an abbreviated commit ID to a list of full 40-char (or 64-char +# for SHA256 repo) IDs that match and are present in the current view. # This is fairly slow... proc longid {prefix} { global varcid curview vshortids @@ -1971,13 +2012,14 @@ proc longid {prefix} { } proc readrefs {} { - global tagids idtags headids idheads tagobjid + global tagids idtags headids idheads tagobjid upstreamofref global otherrefids idotherrefs mainhead mainheadid global selecthead selectheadid global hideremotes global tclencoding + global hashlength - foreach v {tagids idtags headids idheads otherrefids idotherrefs} { + foreach v {tagids idtags headids idheads otherrefids idotherrefs upstreamofref} { unset -nocomplain $v } set refd [safe_open_command [list git show-ref -d]] @@ -1985,9 +2027,9 @@ proc readrefs {} { fconfigure $refd -encoding $tclencoding } while {[gets $refd line] >= 0} { - if {[string index $line 40] ne " "} continue - set id [string range $line 0 39] - set ref [string range $line 41 end] + if {[string index $line $hashlength] ne " "} continue + set id [string range $line 0 [expr {$hashlength - 1}]] + set ref [string range $line [expr {$hashlength + 1}] end] if {![string match "refs/*" $ref]} continue set name [string range $ref 5 end] if {[string match "remotes/*" $name]} { @@ -2011,8 +2053,10 @@ proc readrefs {} { set tagids($name) $id lappend idtags($id) $name } else { - set otherrefids($name) $id - lappend idotherrefs($id) $name + if [is_other_ref_visible $name] { + set otherrefids($name) $id + lappend idotherrefs($id) $name + } } } catch {close $refd} @@ -2031,6 +2075,17 @@ proc readrefs {} { set selectheadid [safe_exec [list git rev-parse --verify $selecthead]] } } + #load the local_branch->upstream mapping + # the result of the for-each-ref command produces: local_branch NUL upstream + set refd [safe_open_command [list git for-each-ref {--format=%(refname:short)%00%(upstream)} refs/heads/]] + while {[gets $refd local_tracking] >= 0} { + set line [split $local_tracking \0] + if {[lindex $line 1] ne {}} { + set upstream_ref [string map {"refs/" ""} [lindex $line 1]] + set upstreamofref([lindex $line 0]) $upstream_ref + } + } + catch {close $refd} } # skip over fake commits @@ -2071,23 +2126,12 @@ proc removehead {id name} { } proc ttk_toplevel {w args} { - global use_ttk eval [linsert $args 0 ::toplevel $w] - if {$use_ttk} { - place [ttk::frame $w._toplevel_background] -x 0 -y 0 -relwidth 1 -relheight 1 - } + place [ttk::frame $w._toplevel_background] -x 0 -y 0 -relwidth 1 -relheight 1 return $w } proc make_transient {window origin} { - global have_tk85 - - # In MacOS Tk 8.4 transient appears to work by setting - # overrideredirect, which is utterly useless, since the - # windows get no border, and are not even kept above - # the parent. - if {!$have_tk85 && [tk windowingsystem] eq {aqua}} return - wm transient $window $origin # Windows fails to place transient windows normally, so @@ -2098,12 +2142,10 @@ proc make_transient {window origin} { } proc show_error {w top msg} { - global NS - if {![info exists NS]} {set NS ""} if {[wm state $top] eq "withdrawn"} { wm deiconify $top } message $w.m -text $msg -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 - ${NS}::button $w.ok -default active -text [mc OK] -command "destroy $top" + ttk::button $w.ok -default active -text [mc OK] -command "destroy $top" pack $w.ok -side bottom -fill x bind $top <Visibility> "grab $top; focus $top" bind $top <Key-Return> "destroy $top" @@ -2125,16 +2167,16 @@ proc error_popup {msg {owner .}} { } proc confirm_popup {msg {owner .}} { - global confirm_ok NS + global confirm_ok set confirm_ok 0 set w .confirm ttk_toplevel $w make_transient $w $owner message $w.m -text $msg -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 - ${NS}::button $w.ok -text [mc OK] -command "set confirm_ok 1; destroy $w" + ttk::button $w.ok -text [mc OK] -command "set confirm_ok 1; destroy $w" pack $w.ok -side left -fill x - ${NS}::button $w.cancel -text [mc Cancel] -command "destroy $w" + ttk::button $w.cancel -text [mc Cancel] -command "destroy $w" pack $w.cancel -side right -fill x bind $w <Visibility> "grab $w; focus $w" bind $w <Key-Return> "set confirm_ok 1; destroy $w" @@ -2150,8 +2192,6 @@ proc haveselectionclipboard {} { } proc setoptions {} { - global use_ttk - if {[tk windowingsystem] ne "win32"} { option add *Panedwindow.showHandle 1 startupFile option add *Panedwindow.sashRelief raised startupFile @@ -2244,23 +2284,62 @@ proc cleardropsel {w} { $w selection clear } proc makedroplist {w varname args} { - global use_ttk - if {$use_ttk} { - set width 0 - foreach label $args { - set cx [string length $label] - if {$cx > $width} {set width $cx} - } - set gm [ttk::combobox $w -width $width -state readonly\ - -textvariable $varname -values $args \ - -exportselection false] - bind $gm <<ComboboxSelected>> [list $gm selection clear] - } else { - set gm [eval [linsert $args 0 tk_optionMenu $w $varname]] - } + set width 0 + foreach label $args { + set cx [string length $label] + if {$cx > $width} {set width $cx} + } + set gm [ttk::combobox $w -width $width -state readonly\ + -textvariable $varname -values $args \ + -exportselection false] + bind $gm <<ComboboxSelected>> [list $gm selection clear] return $gm } +proc scrollval {D {koff 0}} { + global kscroll scroll_D0 + return [expr int(-($D / $scroll_D0) * max(1, $kscroll-$koff))] +} + +proc bind_mousewheel {} { + global canv cflist ctext + bindall <MouseWheel> {allcanvs yview scroll [scrollval %D] units} + bindall <Shift-MouseWheel> break + bind $ctext <MouseWheel> {$ctext yview scroll [scrollval %D 2] units} + bind $ctext <Shift-MouseWheel> {$ctext xview scroll [scrollval %D 2] units} + bind $cflist <MouseWheel> {$cflist yview scroll [scrollval %D 2] units} + bind $cflist <Shift-MouseWheel> break + bind $canv <Shift-MouseWheel> {$canv xview scroll [scrollval %D] units} + + if {[package vcompare $::tcl_version 8.7] >= 0} { + bindall <Alt-MouseWheel> {allcanvs yview scroll [scrollval 5*%D] units} + bindall <Alt-Shift-MouseWheel> break + bind $ctext <Alt-MouseWheel> {$ctext yview scroll [scrollval 5*%D 2] units} + bind $ctext <Alt-Shift-MouseWheel> {$ctext xview scroll [scrollval 5*%D 2] units} + 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} + } +} + +proc bind_mousewheel_buttons {} { + global canv cflist ctext + bindall <ButtonRelease-4> {allcanvs yview scroll [scrollval 1] units} + bindall <ButtonRelease-5> {allcanvs yview scroll [scrollval -1] units} + bindall <Shift-ButtonRelease-4> break + bindall <Shift-ButtonRelease-5> break + bind $ctext <ButtonRelease-4> {$ctext yview scroll [scrollval 1 2] units} + bind $ctext <ButtonRelease-5> {$ctext yview scroll [scrollval -1 2] units} + bind $ctext <Shift-ButtonRelease-4> {$ctext xview scroll [scrollval 1 2] units} + bind $ctext <Shift-ButtonRelease-5> {$ctext xview scroll [scrollval -1 2] units} + bind $cflist <ButtonRelease-4> {$cflist yview scroll [scrollval 1 2] units} + bind $cflist <ButtonRelease-5> {$cflist yview scroll [scrollval -1 2] units} + bind $cflist <Shift-ButtonRelease-4> break + bind $cflist <Shift-ButtonRelease-5> break + bind $canv <Shift-ButtonRelease-4> {$canv xview scroll [scrollval 1] units} + bind $canv <Shift-ButtonRelease-5> {$canv xview scroll [scrollval -1] units} +} + proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist cscroll global tabstop @@ -2279,9 +2358,8 @@ proc makewindow {} { global headctxmenu progresscanv progressitem progresscoords statusw global fprogitem fprogcoord lastprogupdate progupdatepending global rprogitem rprogcoord rownumsel numcommits - global have_tk85 have_tk86 use_ttk NS - global git_version global worddiff + global hashlength scroll_D0 # The "mc" arguments here are purely so that xgettext # sees the following string as needing to be translated @@ -2333,13 +2411,11 @@ proc makewindow {} { makemenu .bar $bar . configure -menu .bar - if {$use_ttk} { - # cover the non-themed toplevel with a themed frame. - place [ttk::frame ._main_background] -x 0 -y 0 -relwidth 1 -relheight 1 - } + # cover the non-themed toplevel with a themed frame. + place [ttk::frame ._main_background] -x 0 -y 0 -relwidth 1 -relheight 1 # the gui has upper and lower half, parts of a paned window. - ${NS}::panedwindow .ctop -orient vertical + ttk::panedwindow .ctop -orient vertical # possibly use assumed geometry if {![info exists geometry(pwsash0)]} { @@ -2352,12 +2428,9 @@ proc makewindow {} { } # the upper half will have a paned window, a scroll bar to the right, and some stuff below - ${NS}::frame .tf -height $geometry(topheight) -width $geometry(topwidth) - ${NS}::frame .tf.histframe - ${NS}::panedwindow .tf.histframe.pwclist -orient horizontal - if {!$use_ttk} { - .tf.histframe.pwclist configure -sashpad 0 -handlesize 4 - } + ttk::frame .tf -height $geometry(topheight) -width $geometry(topwidth) + ttk::frame .tf.histframe + ttk::panedwindow .tf.histframe.pwclist -orient horizontal # create three canvases set cscroll .tf.histframe.csb @@ -2365,6 +2438,7 @@ proc makewindow {} { canvas $canv \ -selectbackground $selectbgcolor \ -background $bgcolor -bd 0 \ + -xscrollincr $linespc \ -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll" .tf.histframe.pwclist add $canv set canv2 .tf.histframe.pwclist.canv2 @@ -2377,28 +2451,22 @@ proc makewindow {} { -selectbackground $selectbgcolor \ -background $bgcolor -bd 0 -yscrollincr $linespc .tf.histframe.pwclist add $canv3 - if {$use_ttk} { - bind .tf.histframe.pwclist <Map> { - bind %W <Map> {} - .tf.histframe.pwclist sashpos 1 [lindex $::geometry(pwsash1) 0] - .tf.histframe.pwclist sashpos 0 [lindex $::geometry(pwsash0) 0] - } - } else { - eval .tf.histframe.pwclist sash place 0 $geometry(pwsash0) - eval .tf.histframe.pwclist sash place 1 $geometry(pwsash1) + bind .tf.histframe.pwclist <Map> { + bind %W <Map> {} + .tf.histframe.pwclist sashpos 1 [lindex $::geometry(pwsash1) 0] + .tf.histframe.pwclist sashpos 0 [lindex $::geometry(pwsash0) 0] } # a scroll bar to rule them - ${NS}::scrollbar $cscroll -command {allcanvs yview} - if {!$use_ttk} {$cscroll configure -highlightthickness 0} + ttk::scrollbar $cscroll -command {allcanvs yview} pack $cscroll -side right -fill y bind .tf.histframe.pwclist <Configure> {resizeclistpanes %W %w} lappend bglist $canv $canv2 $canv3 pack .tf.histframe.pwclist -fill both -expand 1 -side left # we have two button bars at bottom of top frame. Bar 1 - ${NS}::frame .tf.bar - ${NS}::frame .tf.lbar -height 15 + ttk::frame .tf.bar + ttk::frame .tf.lbar -height 15 set sha1entry .tf.bar.sha1 set entries $sha1entry @@ -2407,7 +2475,7 @@ proc makewindow {} { -command gotocommit -width 8 $sha1but conf -disabledforeground [$sha1but cget -foreground] pack .tf.bar.sha1label -side left - ${NS}::entry $sha1entry -width 40 -font textfont -textvariable sha1string + ttk::entry $sha1entry -width $hashlength -font textfont -textvariable sha1string trace add variable sha1string write sha1change pack $sha1entry -side left -pady 2 @@ -2432,50 +2500,30 @@ proc makewindow {} { image create bitmap bm-right -data $bm_right_data -foreground $uifgcolor image create bitmap bm-right-gray -data $bm_right_data -foreground $uifgdisabledcolor - ${NS}::button .tf.bar.leftbut -command goback -state disabled -width 26 - if {$use_ttk} { - .tf.bar.leftbut configure -image [list bm-left disabled bm-left-gray] - } else { - .tf.bar.leftbut configure -image bm-left - } + ttk::button .tf.bar.leftbut -command goback -state disabled -width 26 + .tf.bar.leftbut configure -image [list bm-left disabled bm-left-gray] pack .tf.bar.leftbut -side left -fill y - ${NS}::button .tf.bar.rightbut -command goforw -state disabled -width 26 - if {$use_ttk} { - .tf.bar.rightbut configure -image [list bm-right disabled bm-right-gray] - } else { - .tf.bar.rightbut configure -image bm-right - } + ttk::button .tf.bar.rightbut -command goforw -state disabled -width 26 + .tf.bar.rightbut configure -image [list bm-right disabled bm-right-gray] pack .tf.bar.rightbut -side left -fill y - ${NS}::label .tf.bar.rowlabel -text [mc "Row"] + ttk::label .tf.bar.rowlabel -text [mc "Row"] set rownumsel {} - ${NS}::label .tf.bar.rownum -width 7 -textvariable rownumsel \ + ttk::label .tf.bar.rownum -width 7 -textvariable rownumsel \ -relief sunken -anchor e - ${NS}::label .tf.bar.rowlabel2 -text "/" - ${NS}::label .tf.bar.numcommits -width 7 -textvariable numcommits \ + ttk::label .tf.bar.rowlabel2 -text "/" + ttk::label .tf.bar.numcommits -width 7 -textvariable numcommits \ -relief sunken -anchor e pack .tf.bar.rowlabel .tf.bar.rownum .tf.bar.rowlabel2 .tf.bar.numcommits \ -side left - if {!$use_ttk} { - foreach w {rownum numcommits} {.tf.bar.$w configure -font textfont} - } global selectedline trace add variable selectedline write selectedline_change # Status label and progress bar set statusw .tf.bar.status - ${NS}::label $statusw -width 15 -relief sunken + ttk::label $statusw -width 15 -relief sunken pack $statusw -side left -padx 5 - if {$use_ttk} { - set progresscanv [ttk::progressbar .tf.bar.progress] - } else { - set h [expr {[font metrics uifont -linespace] + 2}] - set progresscanv .tf.bar.progress - canvas $progresscanv -relief sunken -height $h -borderwidth 2 - set progressitem [$progresscanv create rect -1 0 0 $h -fill "#00ff00"] - set fprogitem [$progresscanv create rect -1 0 0 $h -fill yellow] - set rprogitem [$progresscanv create rect -1 0 0 $h -fill red] - } + set progresscanv [ttk::progressbar .tf.bar.progress] pack $progresscanv -side right -expand 1 -fill x -padx {0 2} set progresscoords {0 0} set fprogcoord 0 @@ -2485,7 +2533,7 @@ proc makewindow {} { set progupdatepending 0 # build up the bottom bar of upper window - ${NS}::label .tf.lbar.flabel -text "[mc "Find"] " + ttk::label .tf.lbar.flabel -text "[mc "Find"] " set bm_down_data { #define down_width 16 @@ -2497,7 +2545,7 @@ proc makewindow {} { 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01}; } image create bitmap bm-down -data $bm_down_data -foreground $uifgcolor - ${NS}::button .tf.lbar.fnext -width 26 -command {dofind 1 1} + ttk::button .tf.lbar.fnext -width 26 -command {dofind 1 1} .tf.lbar.fnext configure -image bm-down set bm_up_data { @@ -2510,10 +2558,10 @@ proc makewindow {} { 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01}; } image create bitmap bm-up -data $bm_up_data -foreground $uifgcolor - ${NS}::button .tf.lbar.fprev -width 26 -command {dofind -1 1} + ttk::button .tf.lbar.fprev -width 26 -command {dofind -1 1} .tf.lbar.fprev configure -image bm-up - ${NS}::label .tf.lbar.flab2 -text " [mc "commit"] " + ttk::label .tf.lbar.flab2 -text " [mc "commit"] " pack .tf.lbar.flabel .tf.lbar.fnext .tf.lbar.fprev .tf.lbar.flab2 \ -side left -fill y @@ -2529,7 +2577,7 @@ proc makewindow {} { set findstring {} set fstring .tf.lbar.findstring lappend entries $fstring - ${NS}::entry $fstring -width 30 -textvariable findstring + ttk::entry $fstring -width 30 -textvariable findstring trace add variable findstring write find_change set findtype [mc "Exact"] set findtypemenu [makedroplist .tf.lbar.findtype \ @@ -2548,45 +2596,41 @@ proc makewindow {} { pack .tf.bar -in .tf -side bottom -fill x pack .tf.histframe -fill both -side top -expand 1 .ctop add .tf - if {!$use_ttk} { - .ctop paneconfigure .tf -height $geometry(topheight) - .ctop paneconfigure .tf -width $geometry(topwidth) - } # now build up the bottom - ${NS}::panedwindow .pwbottom -orient horizontal + ttk::panedwindow .pwbottom -orient horizontal # lower left, a text box over search bar, scroll bar to the right # if we know window height, then that will set the lower text height, otherwise # we set lower text height which will drive window height if {[info exists geometry(main)]} { - ${NS}::frame .bleft -width $geometry(botwidth) + ttk::frame .bleft -width $geometry(botwidth) } else { - ${NS}::frame .bleft -width $geometry(botwidth) -height $geometry(botheight) + ttk::frame .bleft -width $geometry(botwidth) -height $geometry(botheight) } - ${NS}::frame .bleft.top - ${NS}::frame .bleft.mid - ${NS}::frame .bleft.bottom + ttk::frame .bleft.top + ttk::frame .bleft.mid + ttk::frame .bleft.bottom # gap between sub-widgets set wgap [font measure uifont "i"] - ${NS}::button .bleft.top.search -text [mc "Search"] -command dosearch + ttk::button .bleft.top.search -text [mc "Search"] -command dosearch pack .bleft.top.search -side left -padx 5 set sstring .bleft.top.sstring set searchstring "" - ${NS}::entry $sstring -width 20 -textvariable searchstring + ttk::entry $sstring -width 20 -textvariable searchstring lappend entries $sstring trace add variable searchstring write incrsearch pack $sstring -side left -expand 1 -fill x - ${NS}::radiobutton .bleft.mid.diff -text [mc "Diff"] \ + ttk::radiobutton .bleft.mid.diff -text [mc "Diff"] \ -command changediffdisp -variable diffelide -value {0 0} - ${NS}::radiobutton .bleft.mid.old -text [mc "Old version"] \ + ttk::radiobutton .bleft.mid.old -text [mc "Old version"] \ -command changediffdisp -variable diffelide -value {0 1} - ${NS}::radiobutton .bleft.mid.new -text [mc "New version"] \ + ttk::radiobutton .bleft.mid.new -text [mc "New version"] \ -command changediffdisp -variable diffelide -value {1 0} - ${NS}::label .bleft.mid.labeldiffcontext -text " [mc "Lines of context"]: " + ttk::label .bleft.mid.labeldiffcontext -text " [mc "Lines of context"]: " pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left -ipadx $wgap spinbox .bleft.mid.diffcontext -width 5 \ -from 0 -increment 1 -to 10000000 \ @@ -2596,28 +2640,24 @@ proc makewindow {} { trace add variable diffcontextstring write diffcontextchange lappend entries .bleft.mid.diffcontext pack .bleft.mid.labeldiffcontext .bleft.mid.diffcontext -side left -ipadx $wgap - ${NS}::checkbutton .bleft.mid.ignspace -text [mc "Ignore space change"] \ + ttk::checkbutton .bleft.mid.ignspace -text [mc "Ignore space change"] \ -command changeignorespace -variable ignorespace pack .bleft.mid.ignspace -side left -padx 5 set worddiff [mc "Line diff"] - if {[package vcompare $git_version "1.7.2"] >= 0} { - makedroplist .bleft.mid.worddiff worddiff [mc "Line diff"] \ - [mc "Markup words"] [mc "Color words"] - trace add variable worddiff write changeworddiff - pack .bleft.mid.worddiff -side left -padx 5 - } + makedroplist .bleft.mid.worddiff worddiff [mc "Line diff"] \ + [mc "Markup words"] [mc "Color words"] + trace add variable worddiff write changeworddiff + pack .bleft.mid.worddiff -side left -padx 5 set ctext .bleft.bottom.ctext text $ctext -background $bgcolor -foreground $fgcolor \ -state disabled -undo 0 -font textfont \ -yscrollcommand scrolltext -wrap $wrapdefault \ -xscrollcommand ".bleft.bottom.sbhorizontal set" - if {$have_tk85} { - $ctext conf -tabstyle wordprocessor - } - ${NS}::scrollbar .bleft.bottom.sb -command "$ctext yview" - ${NS}::scrollbar .bleft.bottom.sbhorizontal -command "$ctext xview" -orient h + $ctext conf -tabstyle wordprocessor + ttk::scrollbar .bleft.bottom.sb -command "$ctext yview" + ttk::scrollbar .bleft.bottom.sbhorizontal -command "$ctext xview" -orient h pack .bleft.top -side top -fill x pack .bleft.mid -side top -fill x grid $ctext .bleft.bottom.sb -sticky nsew @@ -2668,16 +2708,13 @@ proc makewindow {} { $ctext tag lower d0 .pwbottom add .bleft - if {!$use_ttk} { - .pwbottom paneconfigure .bleft -width $geometry(botwidth) - } # lower right - ${NS}::frame .bright - ${NS}::frame .bright.mode - ${NS}::radiobutton .bright.mode.patch -text [mc "Patch"] \ + ttk::frame .bright + ttk::frame .bright.mode + ttk::radiobutton .bright.mode.patch -text [mc "Patch"] \ -command reselectline -variable cmitmode -value "patch" - ${NS}::radiobutton .bright.mode.tree -text [mc "Tree"] \ + ttk::radiobutton .bright.mode.tree -text [mc "Tree"] \ -command reselectline -variable cmitmode -value "tree" grid .bright.mode.patch .bright.mode.tree -sticky ew pack .bright.mode -side top -fill x @@ -2693,7 +2730,7 @@ proc makewindow {} { -spacing1 1 -spacing3 1 lappend bglist $cflist lappend fglist $cflist - ${NS}::scrollbar .bright.sb -command "$cflist yview" + ttk::scrollbar .bright.sb -command "$cflist yview" pack .bright.sb -side right -fill y pack $cflist -side left -fill both -expand 1 $cflist tag configure highlight \ @@ -2728,44 +2765,31 @@ proc makewindow {} { set ::BM "2" } - if {$use_ttk} { - bind .ctop <Map> { - bind %W <Map> {} - %W sashpos 0 $::geometry(topheight) - } - bind .pwbottom <Map> { - bind %W <Map> {} - %W sashpos 0 $::geometry(botwidth) - } - bind .pwbottom <Configure> {resizecdetpanes %W %w} + bind .ctop <Map> { + bind %W <Map> {} + %W sashpos 0 $::geometry(topheight) + } + bind .pwbottom <Map> { + bind %W <Map> {} + %W sashpos 0 $::geometry(botwidth) } + bind .pwbottom <Configure> {resizecdetpanes %W %w} pack .ctop -fill both -expand 1 bindall <1> {selcanvline %W %x %y} - #bindall <B1-Motion> {selcanvline %W %x %y} - if {[tk windowingsystem] == "win32"} { - bind . <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D } - bind $ctext <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D ; break } + + #Mouse / touchpad scrolling + if {[tk windowingsystem] == "win32" || [package vcompare $::tcl_version 8.7] >= 0} { + set scroll_D0 120 + bind_mousewheel + } elseif {[tk windowingsystem] == "x11"} { + set scroll_D0 1 + bind_mousewheel_buttons + } elseif {[tk windowingsystem] == "aqua"} { + set scroll_D0 1 + bind_mousewheel } else { - bindall <ButtonRelease-4> "allcanvs yview scroll -5 units" - bindall <ButtonRelease-5> "allcanvs yview scroll 5 units" - bind $ctext <Button> { - if {"%b" eq 6} { - $ctext xview scroll -5 units - } elseif {"%b" eq 7} { - $ctext xview scroll 5 units - } - } - if {[tk windowingsystem] eq "aqua"} { - bindall <MouseWheel> { - set delta [expr {- (%D)}] - allcanvs yview scroll $delta units - } - bindall <Shift-MouseWheel> { - set delta [expr {- (%D)}] - $canv xview scroll $delta units - } - } + puts stderr [mc "Unknown windowing system, cannot bind mouse"] } bindall <$::BM> "canvscan mark %W %x %y" bindall <B$::BM-Motion> "canvscan dragto %W %x %y" @@ -2777,13 +2801,8 @@ proc makewindow {} { bind . <Key-Down> "selnextline 1" bind . <Shift-Key-Up> "dofind -1 0" bind . <Shift-Key-Down> "dofind 1 0" - if {$have_tk86} { - bindkey <<NextChar>> "goforw" - bindkey <<PrevChar>> "goback" - } else { - bindkey <Key-Right> "goforw" - bindkey <Key-Left> "goback" - } + bindkey <<NextChar>> "goforw" + bindkey <<PrevChar>> "goback" bind . <Key-Prior> "selnextpage -1" bind . <Key-Next> "selnextpage 1" bind . <$M1B-Home> "allcanvs yview moveto 0.0" @@ -2910,24 +2929,6 @@ proc makewindow {} { $diff_menu configure -tearoff 0 } -# Windows sends all mouse wheel events to the current focused window, not -# the one where the mouse hovers, so bind those events here and redirect -# to the correct window -proc windows_mousewheel_redirector {W X Y D} { - global canv canv2 canv3 - set w [winfo containing -displayof $W $X $Y] - if {$w ne ""} { - set u [expr {$D < 0 ? 5 : -5}] - if {$w == $canv || $w == $canv2 || $w == $canv3} { - allcanvs yview scroll $u units - } else { - catch { - $w yview scroll $u units - } - } - } -} - # Update row number label when selectedline changes proc selectedline_change {n1 n2 op} { global selectedline rownumsel @@ -2990,30 +2991,10 @@ proc click {w} { # Adjust the progress bar for a change in requested extent or canvas size proc adjustprogress {} { - global progresscanv progressitem progresscoords - global fprogitem fprogcoord lastprogupdate progupdatepending - global rprogitem rprogcoord use_ttk + global progresscanv + global fprogcoord - if {$use_ttk} { - $progresscanv configure -value [expr {int($fprogcoord * 100)}] - return - } - - set w [expr {[winfo width $progresscanv] - 4}] - set x0 [expr {$w * [lindex $progresscoords 0]}] - set x1 [expr {$w * [lindex $progresscoords 1]}] - set h [winfo height $progresscanv] - $progresscanv coords $progressitem $x0 0 $x1 $h - $progresscanv coords $fprogitem 0 0 [expr {$w * $fprogcoord}] $h - $progresscanv coords $rprogitem 0 0 [expr {$w * $rprogcoord}] $h - set now [clock clicks -milliseconds] - if {$now >= $lastprogupdate + 100} { - set progupdatepending 0 - update - } elseif {!$progupdatepending} { - set progupdatepending 1 - after [expr {$lastprogupdate + 100 - $now}] doprogupdate - } + $progresscanv configure -value [expr {int($fprogcoord * 100)}] } proc doprogupdate {} { @@ -3072,7 +3053,6 @@ proc savestuff {w} { upvar #0 viewargscmd current_viewargscmd upvar #0 viewperm current_viewperm upvar #0 nextviewnum current_nextviewnum - upvar #0 use_ttk current_use_ttk if {$stuffsaved} return if {![winfo viewable .]} return @@ -3106,13 +3086,8 @@ proc savestuff {w} { puts $f "set geometry(state) [wm state .]" puts $f "set geometry(topwidth) [winfo width .tf]" puts $f "set geometry(topheight) [winfo height .tf]" - if {$current_use_ttk} { - puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sashpos 0] 1\"" - puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sashpos 1] 1\"" - } else { - puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sash coord 0]\"" - puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sash coord 1]\"" - } + puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sashpos 0] 1\"" + puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sashpos 1] 1\"" puts $f "set geometry(botwidth) [winfo width .bleft]" puts $f "set geometry(botheight) [winfo height .bleft]" @@ -3158,17 +3133,14 @@ proc savestuff {w} { } proc resizeclistpanes {win w} { - global oldwidth oldsash use_ttk + global oldwidth oldsash if {[info exists oldwidth($win)]} { if {[info exists oldsash($win)]} { set s0 [lindex $oldsash($win) 0] set s1 [lindex $oldsash($win) 1] - } elseif {$use_ttk} { + } else { set s0 [$win sashpos 0] set s1 [$win sashpos 1] - } else { - set s0 [$win sash coord 0] - set s1 [$win sash coord 1] } if {$w < 60} { set sash0 [expr {int($w/2 - 2)}] @@ -3190,29 +3162,20 @@ proc resizeclistpanes {win w} { } } } - if {$use_ttk} { - $win sashpos 0 $sash0 - $win sashpos 1 $sash1 - } else { - $win sash place 0 $sash0 [lindex $s0 1] - $win sash place 1 $sash1 [lindex $s1 1] - set sash0 [list $sash0 [lindex $s0 1]] - set sash1 [list $sash1 [lindex $s1 1]] - } + $win sashpos 0 $sash0 + $win sashpos 1 $sash1 set oldsash($win) [list $sash0 $sash1] } set oldwidth($win) $w } proc resizecdetpanes {win w} { - global oldwidth oldsash use_ttk + global oldwidth oldsash if {[info exists oldwidth($win)]} { if {[info exists oldsash($win)]} { set s0 $oldsash($win) - } elseif {$use_ttk} { - set s0 [$win sashpos 0] } else { - set s0 [$win sash coord 0] + set s0 [$win sashpos 0] } if {$w < 60} { set sash0 [expr {int($w*3/4 - 2)}] @@ -3226,12 +3189,7 @@ proc resizecdetpanes {win w} { set sash0 [expr {$w - 15}] } } - if {$use_ttk} { - $win sashpos 0 $sash0 - } else { - $win sash place 0 $sash0 [lindex $s0 1] - set sash0 [list $sash0 [lindex $s0 1]] - } + $win sashpos 0 $sash0 set oldsash($win) $sash0 } set oldwidth($win) $w @@ -3252,7 +3210,7 @@ proc bindall {event action} { } proc about {} { - global bgcolor NS + global bgcolor set w .about if {[winfo exists $w]} { raise $w @@ -3269,7 +3227,7 @@ Copyright \u00a9 2005-2016 Paul Mackerras Use and redistribute under the terms of the GNU General Public License"] \ -justify center -aspect 400 -border 2 -bg $bgcolor -relief groove pack $w.m -side top -fill x -padx 2 -pady 2 - ${NS}::button $w.ok -text [mc "Close"] -command "destroy $w" -default active + ttk::button $w.ok -text [mc "Close"] -command "destroy $w" -default active pack $w.ok -side bottom bind $w <Visibility> "focus $w.ok" bind $w <Key-Escape> "destroy $w" @@ -3278,7 +3236,7 @@ Use and redistribute under the terms of the GNU General Public License"] \ } proc keys {} { - global bgcolor NS + global bgcolor set w .keys if {[winfo exists $w]} { raise $w @@ -3336,7 +3294,7 @@ proc keys {} { " \ -justify left -bg $bgcolor -border 2 -relief groove pack $w.m -side top -fill both -padx 2 -pady 2 - ${NS}::button $w.ok -text [mc "Close"] -command "destroy $w" -default active + ttk::button $w.ok -text [mc "Close"] -command "destroy $w" -default active bind $w <Key-Escape> [list destroy $w] pack $w.ok -side bottom bind $w <Visibility> "focus $w.ok" @@ -4132,6 +4090,7 @@ proc stopblaming {} { proc read_line_source {fd inst} { global blamestuff curview commfd blameinst nullid nullid2 + global hashlength while {[gets $fd line] >= 0} { lappend blamestuff($inst) $line @@ -4152,7 +4111,7 @@ proc read_line_source {fd inst} { set line [split [lindex $blamestuff($inst) 0] " "] set id [lindex $line 0] set lnum [lindex $line 1] - if {[string length $id] == 40 && [string is xdigit $id] && + if {[string length $id] == $hashlength && [string is xdigit $id] && [string is digit -strict $lnum]} { # look for "filename" line foreach l $blamestuff($inst) { @@ -4480,16 +4439,16 @@ proc editview {} { proc vieweditor {top n title} { global newviewname newviewopts viewfiles bgcolor - global known_view_options NS + global known_view_options ttk_toplevel $top wm title $top [concat $title [mc "-- criteria for selecting revisions"]] make_transient $top . # View name - ${NS}::frame $top.nfr - ${NS}::label $top.nl -text [mc "View Name"] - ${NS}::entry $top.name -width 20 -textvariable newviewname($n) + ttk::frame $top.nfr + ttk::label $top.nl -text [mc "View Name"] + ttk::entry $top.name -width 20 -textvariable newviewname($n) pack $top.nfr -in $top -fill x -pady 5 -padx 3 pack $top.nl -in $top.nfr -side left -padx {0 5} pack $top.name -in $top.nfr -side left -padx {0 25} @@ -4508,13 +4467,13 @@ proc vieweditor {top n title} { if {$flags eq "+" || $flags eq "*"} { set cframe $top.fr$cnt incr cnt - ${NS}::frame $cframe + ttk::frame $cframe pack $cframe -in $top -fill x -pady 3 -padx 3 set cexpand [expr {$flags eq "*"}] } elseif {$flags eq ".." || $flags eq "*."} { set cframe $top.fr$cnt incr cnt - ${NS}::frame $cframe + ttk::frame $cframe pack $cframe -in $top -fill x -pady 3 -padx [list 15 3] set cexpand [expr {$flags eq "*."}] } else { @@ -4522,31 +4481,31 @@ proc vieweditor {top n title} { } if {$type eq "l"} { - ${NS}::label $cframe.l_$id -text $title + ttk::label $cframe.l_$id -text $title pack $cframe.l_$id -in $cframe -side left -pady [list 3 0] -anchor w } elseif {$type eq "b"} { - ${NS}::checkbutton $cframe.c_$id -text $title -variable newviewopts($n,$id) + ttk::checkbutton $cframe.c_$id -text $title -variable newviewopts($n,$id) pack $cframe.c_$id -in $cframe -side left \ -padx [list $lxpad 0] -expand $cexpand -anchor w } elseif {[regexp {^r(\d+)$} $type type sz]} { regexp {^(.*_)} $id uselessvar button_id - ${NS}::radiobutton $cframe.c_$id -text $title -variable newviewopts($n,$button_id) -value $sz + ttk::radiobutton $cframe.c_$id -text $title -variable newviewopts($n,$button_id) -value $sz pack $cframe.c_$id -in $cframe -side left \ -padx [list $lxpad 0] -expand $cexpand -anchor w } elseif {[regexp {^t(\d+)$} $type type sz]} { - ${NS}::label $cframe.l_$id -text $title - ${NS}::entry $cframe.e_$id -width $sz -background $bgcolor \ + ttk::label $cframe.l_$id -text $title + ttk::entry $cframe.e_$id -width $sz -background $bgcolor \ -textvariable newviewopts($n,$id) pack $cframe.l_$id -in $cframe -side left -padx [list $lxpad 0] pack $cframe.e_$id -in $cframe -side left -expand 1 -fill x } elseif {[regexp {^t(\d+)=$} $type type sz]} { - ${NS}::label $cframe.l_$id -text $title - ${NS}::entry $cframe.e_$id -width $sz -background $bgcolor \ + ttk::label $cframe.l_$id -text $title + ttk::entry $cframe.e_$id -width $sz -background $bgcolor \ -textvariable newviewopts($n,$id) pack $cframe.l_$id -in $cframe -side top -pady [list 3 0] -anchor w pack $cframe.e_$id -in $cframe -side top -fill x } elseif {$type eq "path"} { - ${NS}::label $top.l -text $title + ttk::label $top.l -text $title pack $top.l -in $top -side top -pady [list 3 0] -anchor w -padx 3 text $top.t -width 40 -height 5 -background $bgcolor if {[info exists viewfiles($n)]} { @@ -4561,10 +4520,10 @@ proc vieweditor {top n title} { } } - ${NS}::frame $top.buts - ${NS}::button $top.buts.ok -text [mc "OK"] -command [list newviewok $top $n] - ${NS}::button $top.buts.apply -text [mc "Apply (F5)"] -command [list newviewok $top $n 1] - ${NS}::button $top.buts.can -text [mc "Cancel"] -command [list destroy $top] + ttk::frame $top.buts + ttk::button $top.buts.ok -text [mc "OK"] -command [list newviewok $top $n] + ttk::button $top.buts.apply -text [mc "Apply (F5)"] -command [list newviewok $top $n 1] + ttk::button $top.buts.can -text [mc "Cancel"] -command [list destroy $top] bind $top <Control-Return> [list newviewok $top $n] bind $top <F5> [list newviewok $top $n 1] bind $top <Escape> [list destroy $top] @@ -5296,11 +5255,13 @@ proc askrelhighlight {row id} { # Graph layout functions proc shortids {ids} { + global hashlength + set res {} foreach id $ids { if {[llength $id] > 1} { lappend res [shortids $id] - } elseif {[regexp {^[0-9a-f]{40}$} $id]} { + } elseif {[regexp [string map "@@ $hashlength" {^[0-9a-f]{@@}$}] $id]} { lappend res [string range $id 0 7] } else { lappend res $id @@ -5475,13 +5436,14 @@ proc get_viewmainhead {view} { # git rev-list should give us just 1 line to use as viewmainheadid($view) proc getviewhead {fd inst view} { global viewmainheadid commfd curview viewinstances showlocalchanges + global hashlength set id {} if {[gets $fd line] < 0} { if {![eof $fd]} { return 1 } - } elseif {[string length $line] == 40 && [string is xdigit $line]} { + } elseif {[string length $line] == $hashlength && [string is xdigit $line]} { set id $line } set viewmainheadid($view) $id @@ -5523,15 +5485,11 @@ proc dohidelocalchanges {} { # spawn off a process to do git diff-index --cached HEAD proc dodiffindex {} { global lserial showlocalchanges vfilelimit curview - global hasworktree git_version + global hasworktree if {!$showlocalchanges || !$hasworktree} return incr lserial - if {[package vcompare $git_version "1.7.2"] >= 0} { - set cmd "git diff-index --cached --ignore-submodules=dirty HEAD" - } else { - set cmd "git diff-index --cached HEAD" - } + set cmd "git diff-index --cached --ignore-submodules=dirty HEAD" if {$vfilelimit($curview) ne {}} { set cmd [concat $cmd -- $vfilelimit($curview)] } @@ -6759,13 +6717,7 @@ proc bindline {t id} { } proc graph_pane_width {} { - global use_ttk - - if {$use_ttk} { - set g [.tf.histframe.pwclist sashpos 0] - } else { - set g [.tf.histframe.pwclist sash coord 0] - } + set g [.tf.histframe.pwclist sashpos 0] return [lindex $g 0] } @@ -7245,10 +7197,11 @@ proc commit_descriptor {p} { # Also look for URLs of the form "http[s]://..." and make them web links. proc appendwithlinks {text tags} { global ctext linknum curview + global hashlength set start [$ctext index "end - 1c"] $ctext insert end $text $tags - set links [regexp -indices -all -inline {(?:\m|-g)[0-9a-f]{6,40}\M} $text] + set links [regexp -indices -all -inline [string map "@@ $hashlength" {(?:\m|-g)[0-9a-f]{6,@@}\M}] $text] foreach l $links { set s [lindex $l 0] set e [lindex $l 1] @@ -7276,13 +7229,14 @@ proc appendwithlinks {text tags} { proc setlink {id lk} { global curview ctext pendinglinks global linkfgcolor + global hashlength if {[string range $id 0 1] eq "-g"} { set id [string range $id 2 end] } set known 0 - if {[string length $id] < 40} { + if {[string length $id] < $hashlength} { set matches [longid $id] if {[llength $matches] > 0} { if {[llength $matches] > 1} return @@ -7872,7 +7826,7 @@ proc gettree {id} { set treepending $id set treefilelist($id) {} set treeidlist($id) {} - fconfigure $gtf -blocking 0 -encoding binary + fconfigure $gtf -blocking 0 -translation binary filerun $gtf [list gettreeline $gtf $id] } } else { @@ -7899,7 +7853,7 @@ proc gettreeline {gtf id} { if {[string index $fname 0] eq "\""} { set fname [lindex $fname 0] } - set fname [encoding convertfrom utf-8 $fname] + set fname [convertfrom utf-8 $fname] lappend treefilelist($id) $fname } if {![eof $gtf]} { @@ -8079,7 +8033,7 @@ proc addtocflist {ids} { } proc diffcmd {ids flags} { - global log_showroot nullid nullid2 git_version + global log_showroot nullid nullid2 set i [lsearch -exact $ids $nullid] set j [lsearch -exact $ids $nullid2] @@ -8100,9 +8054,7 @@ proc diffcmd {ids flags} { } } } elseif {$j >= 0} { - if {[package vcompare $git_version "1.7.2"] >= 0} { - set flags "$flags --ignore-submodules=dirty" - } + set flags "$flags --ignore-submodules=dirty" set cmd [concat git diff-index --cached $flags] if {[llength $ids] > 1} { # comparing index with specific revision @@ -8135,7 +8087,7 @@ proc gettreediffs {ids} { set treepending $ids set treediff {} - fconfigure $gdtf -blocking 0 -encoding binary + fconfigure $gdtf -blocking 0 -translation binary filerun $gdtf [list gettreediffline $gdtf $ids] } @@ -8161,7 +8113,7 @@ proc gettreediffline {gdtf ids} { if {[string index $file 0] eq "\""} { set file [lindex $file 0] } - set file [encoding convertfrom utf-8 $file] + set file [convertfrom utf-8 $file] if {$file ne [lindex $treediff end]} { lappend treediff $file lappend sublist $file @@ -8231,17 +8183,8 @@ proc getblobdiffs {ids} { global ignorespace global worddiff global limitdiffs vfilelimit curview - global git_version - set textconv {} - if {[package vcompare $git_version "1.6.1"] >= 0} { - set textconv "--textconv" - } - set submodule {} - if {[package vcompare $git_version "1.6.6"] >= 0} { - set submodule "--submodule" - } - set cmd [diffcmd $ids "-p $textconv $submodule -C --cc --no-commit-id -U$diffcontext"] + set cmd [diffcmd $ids "-p --textconv --submodule -C --cc --no-commit-id -U$diffcontext"] if {$ignorespace} { append cmd " -w" } @@ -8255,7 +8198,7 @@ proc getblobdiffs {ids} { error_popup [mc "Error getting diffs: %s" $err] return } - fconfigure $bdf -blocking 0 -encoding binary -eofchar {} + fconfigure $bdf -blocking 0 -translation binary set blobdifffd($ids) $bdf initblobdiffvars filerun $bdf [list getblobdiffline $bdf $diffids] @@ -8306,7 +8249,7 @@ proc makediffhdr {fname ids} { global ctext curdiffstart treediffs diffencoding global ctext_file_names jump_to_here targetline diffline - set fname [encoding convertfrom utf-8 $fname] + set fname [convertfrom utf-8 $fname] set diffencoding [get_path_encoding $fname] set i [lsearch -exact $treediffs($ids) $fname] if {$i >= 0} { @@ -8368,7 +8311,7 @@ proc parseblobdiffline {ids line} { if {![string compare -length 5 "diff " $line]} { if {![regexp {^diff (--cc|--git) } $line m type]} { - set line [encoding convertfrom utf-8 $line] + set line [convertfrom utf-8 $line] $ctext insert end "$line\n" hunksep continue } @@ -8417,7 +8360,7 @@ proc parseblobdiffline {ids line} { makediffhdr $fname $ids } elseif {![string compare -length 16 "* Unmerged path " $line]} { - set fname [encoding convertfrom utf-8 [string range $line 16 end]] + set fname [convertfrom utf-8 [string range $line 16 end]] $ctext insert end "\n" set curdiffstart [$ctext index "end - 1c"] lappend ctext_file_names $fname @@ -8430,7 +8373,7 @@ proc parseblobdiffline {ids line} { } elseif {![string compare -length 2 "@@" $line]} { regexp {^@@+} $line ats - set line [encoding convertfrom $diffencoding $line] + set line [convertfrom $diffencoding $line] $ctext insert end "$line\n" hunksep if {[regexp { \+(\d+),\d+ @@} $line m nl]} { set diffline $nl @@ -8459,10 +8402,10 @@ proc parseblobdiffline {ids line} { $ctext insert end "$line\n" filesep } } elseif {$currdiffsubmod != "" && ![string compare -length 3 " >" $line]} { - set line [encoding convertfrom $diffencoding $line] + set line [convertfrom $diffencoding $line] $ctext insert end "$line\n" dresult } elseif {$currdiffsubmod != "" && ![string compare -length 3 " <" $line]} { - set line [encoding convertfrom $diffencoding $line] + set line [convertfrom $diffencoding $line] $ctext insert end "$line\n" d0 } elseif {$diffinhdr} { if {![string compare -length 12 "rename from " $line]} { @@ -8470,7 +8413,7 @@ proc parseblobdiffline {ids line} { if {[string index $fname 0] eq "\""} { set fname [lindex $fname 0] } - set fname [encoding convertfrom utf-8 $fname] + set fname [convertfrom utf-8 $fname] set i [lsearch -exact $treediffs($ids) $fname] if {$i >= 0} { setinlist difffilestart $i $curdiffstart @@ -8489,12 +8432,12 @@ proc parseblobdiffline {ids line} { set diffinhdr 0 return } - set line [encoding convertfrom utf-8 $line] + set line [convertfrom utf-8 $line] $ctext insert end "$line\n" filesep } else { set line [string map {\x1A ^Z} \ - [encoding convertfrom $diffencoding $line]] + [convertfrom $diffencoding $line]] # parse the prefix - one ' ', '-' or '+' for each parent set prefix [string range $line 0 [expr {$diffnparents - 1}]] set tag [expr {$diffnparents > 1? "m": "d"}] @@ -8646,19 +8589,17 @@ proc clear_ctext {{first 1.0}} { } proc settabs {{firstab {}}} { - global firsttabstop tabstop ctext have_tk85 + global firsttabstop tabstop ctext - if {$firstab ne {} && $have_tk85} { + if {$firstab ne {}} { set firsttabstop $firstab } set w [font measure textfont "0"] if {$firsttabstop != 0} { $ctext conf -tabs [list [expr {($firsttabstop + $tabstop) * $w}] \ [expr {($firsttabstop + 2 * $tabstop) * $w}]] - } elseif {$have_tk85 || $tabstop != 8} { - $ctext conf -tabs [expr {$tabstop * $w}] } else { - $ctext conf -tabs {} + $ctext conf -tabs [expr {$tabstop * $w}] } } @@ -8927,13 +8868,16 @@ proc incrfont {inc} { proc clearsha1 {} { global sha1entry sha1string - if {[string length $sha1string] == 40} { + global hashlength + + if {[string length $sha1string] == $hashlength} { $sha1entry delete 0 end } } proc sha1change {n1 n2 op} { global sha1string currentid sha1but + if {$sha1string == {} || ([info exists currentid] && $sha1string == $currentid)} { set state disabled @@ -8950,6 +8894,7 @@ proc sha1change {n1 n2 op} { proc gotocommit {} { global sha1string tagids headids curview varcid + global hashlength if {$sha1string == {} || ([info exists currentid] && $sha1string == $currentid)} return @@ -8959,7 +8904,7 @@ proc gotocommit {} { set id $headids($sha1string) } else { set id [string tolower $sha1string] - if {[regexp {^[0-9a-f]{4,39}$} $id]} { + if {[regexp {^[0-9a-f]{4,63}$} $id]} { set matches [longid $id] if {$matches ne {}} { if {[llength $matches] > 1} { @@ -9445,7 +9390,8 @@ proc doseldiff {oldid newid} { } proc mkpatch {} { - global rowmenuid currentid commitinfo patchtop patchnum NS + global rowmenuid currentid commitinfo patchtop patchnum + global hashlength if {![info exists currentid]} return set oldid $currentid @@ -9457,36 +9403,36 @@ proc mkpatch {} { catch {destroy $top} ttk_toplevel $top make_transient $top . - ${NS}::label $top.title -text [mc "Generate patch"] + ttk::label $top.title -text [mc "Generate patch"] grid $top.title - -pady 10 - ${NS}::label $top.from -text [mc "From:"] - ${NS}::entry $top.fromsha1 -width 40 + ttk::label $top.from -text [mc "From:"] + ttk::entry $top.fromsha1 -width $hashlength $top.fromsha1 insert 0 $oldid $top.fromsha1 conf -state readonly grid $top.from $top.fromsha1 -sticky w - ${NS}::entry $top.fromhead -width 60 + ttk::entry $top.fromhead -width 60 $top.fromhead insert 0 $oldhead $top.fromhead conf -state readonly grid x $top.fromhead -sticky w - ${NS}::label $top.to -text [mc "To:"] - ${NS}::entry $top.tosha1 -width 40 + ttk::label $top.to -text [mc "To:"] + ttk::entry $top.tosha1 -width $hashlength $top.tosha1 insert 0 $newid $top.tosha1 conf -state readonly grid $top.to $top.tosha1 -sticky w - ${NS}::entry $top.tohead -width 60 + ttk::entry $top.tohead -width 60 $top.tohead insert 0 $newhead $top.tohead conf -state readonly grid x $top.tohead -sticky w - ${NS}::button $top.rev -text [mc "Reverse"] -command mkpatchrev + ttk::button $top.rev -text [mc "Reverse"] -command mkpatchrev grid $top.rev x -pady 10 -padx 5 - ${NS}::label $top.flab -text [mc "Output file:"] - ${NS}::entry $top.fname -width 60 + ttk::label $top.flab -text [mc "Output file:"] + ttk::entry $top.fname -width 60 $top.fname insert 0 [file normalize "patch$patchnum.patch"] incr patchnum grid $top.flab $top.fname -sticky w - ${NS}::frame $top.buts - ${NS}::button $top.buts.gen -text [mc "Generate"] -command mkpatchgo - ${NS}::button $top.buts.can -text [mc "Cancel"] -command mkpatchcan + ttk::frame $top.buts + ttk::button $top.buts.gen -text [mc "Generate"] -command mkpatchgo + ttk::button $top.buts.can -text [mc "Cancel"] -command mkpatchcan bind $top <Key-Return> mkpatchgo bind $top <Key-Escape> mkpatchcan grid $top.buts.gen $top.buts.can @@ -9534,35 +9480,36 @@ proc mkpatchcan {} { } proc mktag {} { - global rowmenuid mktagtop commitinfo NS + global rowmenuid mktagtop commitinfo + global hashlength set top .maketag set mktagtop $top catch {destroy $top} ttk_toplevel $top make_transient $top . - ${NS}::label $top.title -text [mc "Create tag"] + ttk::label $top.title -text [mc "Create tag"] grid $top.title - -pady 10 - ${NS}::label $top.id -text [mc "ID:"] - ${NS}::entry $top.sha1 -width 40 + ttk::label $top.id -text [mc "ID:"] + ttk::entry $top.sha1 -width $hashlength $top.sha1 insert 0 $rowmenuid $top.sha1 conf -state readonly grid $top.id $top.sha1 -sticky w - ${NS}::entry $top.head -width 60 + ttk::entry $top.head -width 60 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0] $top.head conf -state readonly grid x $top.head -sticky w - ${NS}::label $top.tlab -text [mc "Tag name:"] - ${NS}::entry $top.tag -width 60 + ttk::label $top.tlab -text [mc "Tag name:"] + ttk::entry $top.tag -width 60 grid $top.tlab $top.tag -sticky w - ${NS}::label $top.op -text [mc "Tag message is optional"] + ttk::label $top.op -text [mc "Tag message is optional"] grid $top.op -columnspan 2 -sticky we - ${NS}::label $top.mlab -text [mc "Tag message:"] - ${NS}::entry $top.msg -width 60 + ttk::label $top.mlab -text [mc "Tag message:"] + ttk::entry $top.msg -width 60 grid $top.mlab $top.msg -sticky w - ${NS}::frame $top.buts - ${NS}::button $top.buts.gen -text [mc "Create"] -command mktaggo - ${NS}::button $top.buts.can -text [mc "Cancel"] -command mktagcan + ttk::frame $top.buts + ttk::button $top.buts.gen -text [mc "Create"] -command mktaggo + ttk::button $top.buts.can -text [mc "Cancel"] -command mktagcan bind $top <Key-Return> mktaggo bind $top <Key-Escape> mktagcan grid $top.buts.gen $top.buts.can @@ -9652,10 +9599,11 @@ proc mktaggo {} { proc copyreference {} { global rowmenuid autosellen + global hashlength set format "%h (\"%s\", %ad)" set cmd [list git show -s --pretty=format:$format --date=short] - if {$autosellen < 40} { + if {$autosellen < $hashlength} { lappend cmd --abbrev=$autosellen } set reference [safe_exec [concat $cmd $rowmenuid]] @@ -9665,34 +9613,35 @@ proc copyreference {} { } proc writecommit {} { - global rowmenuid wrcomtop commitinfo wrcomcmd NS + global rowmenuid wrcomtop commitinfo wrcomcmd + global hashlength set top .writecommit set wrcomtop $top catch {destroy $top} ttk_toplevel $top make_transient $top . - ${NS}::label $top.title -text [mc "Write commit to file"] + ttk::label $top.title -text [mc "Write commit to file"] grid $top.title - -pady 10 - ${NS}::label $top.id -text [mc "ID:"] - ${NS}::entry $top.sha1 -width 40 + ttk::label $top.id -text [mc "ID:"] + ttk::entry $top.sha1 -width $hashlength $top.sha1 insert 0 $rowmenuid $top.sha1 conf -state readonly grid $top.id $top.sha1 -sticky w - ${NS}::entry $top.head -width 60 + ttk::entry $top.head -width 60 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0] $top.head conf -state readonly grid x $top.head -sticky w - ${NS}::label $top.clab -text [mc "Command:"] - ${NS}::entry $top.cmd -width 60 -textvariable wrcomcmd + ttk::label $top.clab -text [mc "Command:"] + ttk::entry $top.cmd -width 60 -textvariable wrcomcmd grid $top.clab $top.cmd -sticky w -pady 10 - ${NS}::label $top.flab -text [mc "Output file:"] - ${NS}::entry $top.fname -width 60 + ttk::label $top.flab -text [mc "Output file:"] + ttk::entry $top.fname -width 60 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"] grid $top.flab $top.fname -sticky w - ${NS}::frame $top.buts - ${NS}::button $top.buts.gen -text [mc "Write"] -command wrcomgo - ${NS}::button $top.buts.can -text [mc "Cancel"] -command wrcomcan + ttk::frame $top.buts + ttk::button $top.buts.gen -text [mc "Write"] -command wrcomgo + ttk::button $top.buts.can -text [mc "Cancel"] -command wrcomcan bind $top <Key-Return> wrcomgo bind $top <Key-Escape> wrcomcan grid $top.buts.gen $top.buts.can @@ -9723,7 +9672,7 @@ proc wrcomcan {} { } proc mkbranch {} { - global NS rowmenuid + global rowmenuid set top .branchdialog @@ -9738,7 +9687,6 @@ proc mkbranch {} { } proc mvbranch {} { - global NS global headmenuid headmenuhead set top .branchdialog @@ -9754,31 +9702,32 @@ proc mvbranch {} { } proc branchdia {top valvar uivar} { - global NS commitinfo + global commitinfo + global hashlength upvar $valvar val $uivar ui catch {destroy $top} ttk_toplevel $top make_transient $top . - ${NS}::label $top.title -text $ui(title) + ttk::label $top.title -text $ui(title) grid $top.title - -pady 10 - ${NS}::label $top.id -text [mc "ID:"] - ${NS}::entry $top.sha1 -width 40 + ttk::label $top.id -text [mc "ID:"] + ttk::entry $top.sha1 -width $hashlength $top.sha1 insert 0 $val(id) $top.sha1 conf -state readonly grid $top.id $top.sha1 -sticky w - ${NS}::entry $top.head -width 60 + ttk::entry $top.head -width 60 $top.head insert 0 [lindex $commitinfo($val(id)) 0] $top.head conf -state readonly grid x $top.head -sticky ew grid columnconfigure $top 1 -weight 1 - ${NS}::label $top.nlab -text [mc "Name:"] - ${NS}::entry $top.name -width 40 + ttk::label $top.nlab -text [mc "Name:"] + ttk::entry $top.name -width $hashlength $top.name insert 0 $val(name) grid $top.nlab $top.name -sticky w - ${NS}::frame $top.buts - ${NS}::button $top.buts.go -text $ui(accept) -command $val(command) - ${NS}::button $top.buts.can -text [mc "Cancel"] -command "catch {destroy $top}" + ttk::frame $top.buts + ttk::button $top.buts.go -text $ui(accept) -command $val(command) + ttk::button $top.buts.can -text [mc "Cancel"] -command "catch {destroy $top}" bind $top <Key-Return> $val(command) bind $top <Key-Escape> "catch {destroy $top}" grid $top.buts.go $top.buts.can @@ -10025,31 +9974,31 @@ proc revert {} { } proc resethead {} { - global mainhead rowmenuid confirm_ok resettype NS + global mainhead rowmenuid confirm_ok resettype set confirm_ok 0 set w ".confirmreset" ttk_toplevel $w make_transient $w . wm title $w [mc "Confirm reset"] - ${NS}::label $w.m -text \ + ttk::label $w.m -text \ [mc "Reset branch %s to %s?" $mainhead [string range $rowmenuid 0 7]] pack $w.m -side top -fill x -padx 20 -pady 20 - ${NS}::labelframe $w.f -text [mc "Reset type:"] + ttk::labelframe $w.f -text [mc "Reset type:"] set resettype mixed - ${NS}::radiobutton $w.f.soft -value soft -variable resettype \ + ttk::radiobutton $w.f.soft -value soft -variable resettype \ -text [mc "Soft: Leave working tree and index untouched"] grid $w.f.soft -sticky w - ${NS}::radiobutton $w.f.mixed -value mixed -variable resettype \ + ttk::radiobutton $w.f.mixed -value mixed -variable resettype \ -text [mc "Mixed: Leave working tree untouched, reset index"] grid $w.f.mixed -sticky w - ${NS}::radiobutton $w.f.hard -value hard -variable resettype \ + ttk::radiobutton $w.f.hard -value hard -variable resettype \ -text [mc "Hard: Reset working tree and index\n(discard ALL local changes)"] grid $w.f.hard -sticky w pack $w.f -side top -fill x -padx 4 - ${NS}::button $w.ok -text [mc OK] -command "set confirm_ok 1; destroy $w" + ttk::button $w.ok -text [mc OK] -command "set confirm_ok 1; destroy $w" pack $w.ok -side left -fill x -padx 20 -pady 20 - ${NS}::button $w.cancel -text [mc Cancel] -command "destroy $w" + ttk::button $w.cancel -text [mc Cancel] -command "destroy $w" bind $w <Key-Escape> [list destroy $w] pack $w.cancel -side right -fill x -padx 20 -pady 20 bind $w <Visibility> "grab $w; focus $w" @@ -10226,7 +10175,7 @@ proc rmbranch {} { # Display a list of tags and heads proc showrefs {} { - global showrefstop bgcolor fgcolor selectbgcolor NS + global showrefstop bgcolor fgcolor selectbgcolor global bglist fglist reflistfilter reflist maincursor set top .showrefs @@ -10249,19 +10198,22 @@ proc showrefs {} { lappend bglist $top.list lappend fglist $top.list } - ${NS}::scrollbar $top.ysb -command "$top.list yview" -orient vertical - ${NS}::scrollbar $top.xsb -command "$top.list xview" -orient horizontal + ttk::scrollbar $top.ysb -command "$top.list yview" -orient vertical + ttk::scrollbar $top.xsb -command "$top.list xview" -orient horizontal grid $top.list $top.ysb -sticky nsew grid $top.xsb x -sticky ew - ${NS}::frame $top.f - ${NS}::label $top.f.l -text "[mc "Filter"]: " - ${NS}::entry $top.f.e -width 20 -textvariable reflistfilter + ttk::frame $top.f + ttk::label $top.f.l -text "[mc "Filter"]: " + ttk::entry $top.f.e -width 20 -textvariable reflistfilter set reflistfilter "*" trace add variable reflistfilter write reflistfilter_change pack $top.f.e -side right -fill x -expand 1 pack $top.f.l -side left grid $top.f - -sticky ew -pady 2 - ${NS}::button $top.close -command [list destroy $top] -text [mc "Close"] + ttk::checkbutton $top.sort -text [mc "Sort refs by type"] \ + -variable sortrefsbytype -command {refill_reflist} + grid $top.sort - -sticky w -pady 2 + ttk::button $top.close -command [list destroy $top] -text [mc "Close"] bind $top <Key-Escape> [list destroy $top] grid $top.close - grid columnconfigure $top 0 -weight 1 @@ -10304,43 +10256,71 @@ proc reflistfilter_change {n1 n2 op} { } proc refill_reflist {} { - global reflist reflistfilter showrefstop headids tagids otherrefids - global curview + global reflist reflistfilter showrefstop headids tagids otherrefids sortrefsbytype + global curview upstreamofref if {![info exists showrefstop] || ![winfo exists $showrefstop]} return - set refs {} + set localrefs {} + set remoterefs {} + set trackedremoterefs {} + set tagrefs {} + set otherrefs {} + foreach n [array names headids] { - if {[string match $reflistfilter $n]} { + if {![string match "remotes/*" $n] && [string match $reflistfilter $n]} { if {[commitinview $headids($n) $curview]} { - if {[string match "remotes/*" $n]} { - lappend refs [list $n R] - } else { - lappend refs [list $n H] + lappend localrefs [list $n H] + if {[info exists upstreamofref($n)] && [commitinview $headids($upstreamofref($n)) $curview]} { + lappend trackedremoterefs [list $upstreamofref($n) R] + } + } else { + interestedin $headids($n) {run refill_reflist} + } + } + } + set trackedremoterefs [lsort -index 0 -unique $trackedremoterefs] + set localrefs [lsort -index 0 $localrefs] + + foreach n [array names headids] { + if {[string match "remotes/*" $n] && [string match $reflistfilter $n]} { + if {[commitinview $headids($n) $curview]} { + if {[lsearch -exact $trackedremoterefs [list $n R]] < 0} { + lappend remoterefs [list $n R] } } else { interestedin $headids($n) {run refill_reflist} } } } + set remoterefs [lsort -index 0 $remoterefs] + foreach n [array names tagids] { if {[string match $reflistfilter $n]} { if {[commitinview $tagids($n) $curview]} { - lappend refs [list $n T] + lappend tagrefs [list $n T] } else { interestedin $tagids($n) {run refill_reflist} } } } + set tagrefs [lsort -index 0 $tagrefs] + foreach n [array names otherrefids] { if {[string match $reflistfilter $n]} { if {[commitinview $otherrefids($n) $curview]} { - lappend refs [list $n o] + lappend otherrefs [list "$n" o] } else { interestedin $otherrefids($n) {run refill_reflist} } } } - set refs [lsort -index 0 $refs] + set otherrefs [lsort -index 0 $otherrefs] + + set refs [concat $localrefs $trackedremoterefs $remoterefs $tagrefs $otherrefs] + if {!$sortrefsbytype} { + set refs [lsort -index 0 $refs] + } + if {$refs eq $reflist} return # Update the contents of $showrefstop.list according to the @@ -11599,84 +11579,16 @@ proc doquit {} { } proc mkfontdisp {font top which} { - global fontattr fontpref $font NS use_ttk + global fontattr fontpref $font set fontpref($font) [set $font] - ${NS}::button $top.${font}but -text $which \ + ttk::button $top.${font}but -text $which \ -command [list choosefont $font $which] - ${NS}::label $top.$font -relief flat -font $font \ + ttk::label $top.$font -relief flat -font $font \ -text $fontattr($font,family) -justify left grid x $top.${font}but $top.$font -sticky w } -proc choosefont {font which} { - global fontparam fontlist fonttop fontattr - global prefstop NS - - set fontparam(which) $which - set fontparam(font) $font - set fontparam(family) [font actual $font -family] - set fontparam(size) $fontattr($font,size) - set fontparam(weight) $fontattr($font,weight) - set fontparam(slant) $fontattr($font,slant) - set top .gitkfont - set fonttop $top - if {![winfo exists $top]} { - font create sample - eval font config sample [font actual $font] - ttk_toplevel $top - make_transient $top $prefstop - wm title $top [mc "Gitk font chooser"] - ${NS}::label $top.l -textvariable fontparam(which) - pack $top.l -side top - set fontlist [lsort [font families]] - ${NS}::frame $top.f - listbox $top.f.fam -listvariable fontlist \ - -yscrollcommand [list $top.f.sb set] - bind $top.f.fam <<ListboxSelect>> selfontfam - ${NS}::scrollbar $top.f.sb -command [list $top.f.fam yview] - pack $top.f.sb -side right -fill y - pack $top.f.fam -side left -fill both -expand 1 - pack $top.f -side top -fill both -expand 1 - ${NS}::frame $top.g - spinbox $top.g.size -from 4 -to 40 -width 4 \ - -textvariable fontparam(size) \ - -validatecommand {string is integer -strict %s} - checkbutton $top.g.bold -padx 5 \ - -font {{Times New Roman} 12 bold} -text [mc "B"] -indicatoron 0 \ - -variable fontparam(weight) -onvalue bold -offvalue normal - checkbutton $top.g.ital -padx 5 \ - -font {{Times New Roman} 12 italic} -text [mc "I"] -indicatoron 0 \ - -variable fontparam(slant) -onvalue italic -offvalue roman - pack $top.g.size $top.g.bold $top.g.ital -side left - pack $top.g -side top - canvas $top.c -width 150 -height 50 -border 2 -relief sunk \ - -background white - $top.c create text 100 25 -anchor center -text $which -font sample \ - -fill black -tags text - bind $top.c <Configure> [list centertext $top.c] - pack $top.c -side top -fill x - ${NS}::frame $top.buts - ${NS}::button $top.buts.ok -text [mc "OK"] -command fontok -default active - ${NS}::button $top.buts.can -text [mc "Cancel"] -command fontcan -default normal - bind $top <Key-Return> fontok - bind $top <Key-Escape> fontcan - grid $top.buts.ok $top.buts.can - grid columnconfigure $top.buts 0 -weight 1 -uniform a - grid columnconfigure $top.buts 1 -weight 1 -uniform a - pack $top.buts -side bottom -fill x - trace add variable fontparam write chg_fontparam - } else { - raise $top - $top.c itemconf text -text $which - } - set i [lsearch -exact $fontlist $fontparam(family)] - if {$i >= 0} { - $top.f.fam selection set $i - $top.f.fam see $i - } -} - proc centertext {w} { $w coords text [expr {[winfo width $w] / 2}] [expr {[winfo height $w] / 2}] } @@ -11709,26 +11621,21 @@ proc fontcan {} { } } -if {[package vsatisfies [package provide Tk] 8.6]} { - # In Tk 8.6 we have a native font chooser dialog. Overwrite the above - # function to make use of it. - proc choosefont {font which} { - tk fontchooser configure -title $which -font $font \ - -command [list on_choosefont $font $which] - tk fontchooser show - } - proc on_choosefont {font which newfont} { - global fontparam - puts stderr "$font $newfont" - array set f [font actual $newfont] - set fontparam(which) $which - set fontparam(font) $font - set fontparam(family) $f(-family) - set fontparam(size) $f(-size) - set fontparam(weight) $f(-weight) - set fontparam(slant) $f(-slant) - fontok - } +proc choosefont {font which} { + tk fontchooser configure -title $which -font $font \ + -command [list on_choosefont $font $which] + tk fontchooser show +} +proc on_choosefont {font which newfont} { + global fontparam + array set f [font actual $newfont] + set fontparam(which) $which + set fontparam(font) $font + set fontparam(family) $f(-family) + set fontparam(size) $f(-size) + set fontparam(weight) $f(-weight) + set fontparam(slant) $f(-slant) + fontok } proc selfontfam {} { @@ -11748,172 +11655,170 @@ proc chg_fontparam {v sub op} { # Create a property sheet tab page proc create_prefs_page {w} { - global NS - set parent [join [lrange [split $w .] 0 end-1] .] - if {[winfo class $parent] eq "TNotebook"} { - ${NS}::frame $w - } else { - ${NS}::labelframe $w - } + ttk::frame $w } proc prefspage_general {notebook} { - global NS maxwidth maxgraphpct showneartags showlocalchanges - global tabstop wrapcomment wrapdefault limitdiffs - global autocopy autoselect autosellen extdifftool perfile_attrs - global hideremotes want_ttk have_ttk maxrefs web_browser + global {*}$::config_variables + global hashlength set page [create_prefs_page $notebook.general] - ${NS}::label $page.ldisp -text [mc "Commit list display options"] -font mainfontbold + ttk::label $page.ldisp -text [mc "Commit list display options"] -font mainfontbold grid $page.ldisp - -sticky w -pady 10 - ${NS}::label $page.spacer -text " " - ${NS}::label $page.maxwidthl -text [mc "Maximum graph width (lines)"] + ttk::label $page.spacer -text " " + ttk::label $page.maxwidthl -text [mc "Maximum graph width (lines)"] spinbox $page.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth grid $page.spacer $page.maxwidthl $page.maxwidth -sticky w #xgettext:no-tcl-format - ${NS}::label $page.maxpctl -text [mc "Maximum graph width (% of pane)"] + ttk::label $page.maxpctl -text [mc "Maximum graph width (% of pane)"] spinbox $page.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct grid x $page.maxpctl $page.maxpct -sticky w - ${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \ + ttk::checkbutton $page.showlocal -text [mc "Show local changes"] \ -variable showlocalchanges grid x $page.showlocal -sticky w - ${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \ + ttk::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \ -variable hideremotes grid x $page.hideremotes -sticky w - ${NS}::checkbutton $page.autocopy -text [mc "Copy commit ID to clipboard"] \ + ttk::entry $page.refstohide -textvariable refstohide + ttk::frame $page.refstohidef + ttk::label $page.refstohidef.l -text [mc "Refs to hide (space-separated globs)" ] + pack $page.refstohidef.l -side left + pack configure $page.refstohidef.l -padx 10 + grid x $page.refstohidef $page.refstohide -sticky ew + + ttk::checkbutton $page.autocopy -text [mc "Copy commit ID to clipboard"] \ -variable autocopy grid x $page.autocopy -sticky w if {[haveselectionclipboard]} { - ${NS}::checkbutton $page.autoselect -text [mc "Copy commit ID to X11 selection"] \ + ttk::checkbutton $page.autoselect -text [mc "Copy commit ID to X11 selection"] \ -variable autoselect grid x $page.autoselect -sticky w } - spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen - ${NS}::label $page.autosellenl -text [mc "Length of commit ID to copy"] + + spinbox $page.autosellen -from 1 -to $hashlength -width 4 -textvariable autosellen + ttk::label $page.autosellenl -text [mc "Length of commit ID to copy"] grid x $page.autosellenl $page.autosellen -sticky w + ttk::label $page.kscroll1 -text [mc "Wheel scrolling multiplier"] + spinbox $page.kscroll -from 1 -to 20 -width 4 -textvariable kscroll + grid x $page.kscroll1 $page.kscroll -sticky w - ${NS}::label $page.ddisp -text [mc "Diff display options"] -font mainfontbold + ttk::label $page.ddisp -text [mc "Diff display options"] -font mainfontbold grid $page.ddisp - -sticky w -pady 10 - ${NS}::label $page.tabstopl -text [mc "Tab spacing"] + ttk::label $page.tabstopl -text [mc "Tab spacing"] spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop grid x $page.tabstopl $page.tabstop -sticky w - ${NS}::label $page.wrapcommentl -text [mc "Wrap comment text"] + ttk::label $page.wrapcommentl -text [mc "Wrap comment text"] makedroplist $page.wrapcomment wrapcomment none char word grid x $page.wrapcommentl $page.wrapcomment -sticky w - ${NS}::label $page.wrapdefaultl -text [mc "Wrap other text"] + ttk::label $page.wrapdefaultl -text [mc "Wrap other text"] makedroplist $page.wrapdefault wrapdefault none char word grid x $page.wrapdefaultl $page.wrapdefault -sticky w - ${NS}::checkbutton $page.ntag -text [mc "Display nearby tags/heads"] \ + ttk::checkbutton $page.ntag -text [mc "Display nearby tags/heads"] \ -variable showneartags grid x $page.ntag -sticky w - ${NS}::label $page.maxrefsl -text [mc "Maximum # tags/heads to show"] + ttk::label $page.maxrefsl -text [mc "Maximum # tags/heads to show"] spinbox $page.maxrefs -from 1 -to 1000 -width 4 -textvariable maxrefs grid x $page.maxrefsl $page.maxrefs -sticky w - ${NS}::checkbutton $page.ldiff -text [mc "Limit diffs to listed paths"] \ + ttk::checkbutton $page.ldiff -text [mc "Limit diffs to listed paths"] \ -variable limitdiffs grid x $page.ldiff -sticky w - ${NS}::checkbutton $page.lattr -text [mc "Support per-file encodings"] \ + ttk::checkbutton $page.lattr -text [mc "Support per-file encodings"] \ -variable perfile_attrs grid x $page.lattr -sticky w - ${NS}::entry $page.extdifft -textvariable extdifftool - ${NS}::frame $page.extdifff - ${NS}::label $page.extdifff.l -text [mc "External diff tool" ] - ${NS}::button $page.extdifff.b -text [mc "Choose..."] -command choose_extdiff + ttk::entry $page.extdifft -textvariable extdifftool + ttk::frame $page.extdifff + ttk::label $page.extdifff.l -text [mc "External diff tool" ] + ttk::button $page.extdifff.b -text [mc "Choose..."] -command choose_extdiff pack $page.extdifff.l $page.extdifff.b -side left pack configure $page.extdifff.l -padx 10 grid x $page.extdifff $page.extdifft -sticky ew - ${NS}::entry $page.webbrowser -textvariable web_browser - ${NS}::frame $page.webbrowserf - ${NS}::label $page.webbrowserf.l -text [mc "Web browser" ] + ttk::entry $page.webbrowser -textvariable web_browser + ttk::frame $page.webbrowserf + ttk::label $page.webbrowserf.l -text [mc "Web browser" ] pack $page.webbrowserf.l -side left pack configure $page.webbrowserf.l -padx 10 grid x $page.webbrowserf $page.webbrowser -sticky ew - ${NS}::label $page.lgen -text [mc "General options"] -font mainfontbold - grid $page.lgen - -sticky w -pady 10 - ${NS}::checkbutton $page.want_ttk -variable want_ttk \ - -text [mc "Use themed widgets"] - if {$have_ttk} { - ${NS}::label $page.ttk_note -text [mc "(change requires restart)"] - } else { - ${NS}::label $page.ttk_note -text [mc "(currently unavailable)"] - } - grid x $page.want_ttk $page.ttk_note -sticky w return $page } proc prefspage_colors {notebook} { - global NS uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor + global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor global diffbgcolors set page [create_prefs_page $notebook.colors] - ${NS}::label $page.cdisp -text [mc "Colors: press to choose"] -font mainfontbold + ttk::label $page.cdisp -text [mc "Colors: press to choose"] -font mainfontbold grid $page.cdisp - -sticky w -pady 10 label $page.ui -padx 40 -relief sunk -background $uicolor - ${NS}::button $page.uibut -text [mc "Interface"] \ - -command [list choosecolor uicolor {} $page.ui [mc "interface"] setui] + ttk::button $page.uibut -text [mc "Interface"] \ + -command [list choosecolor uicolor {} $page [mc "interface"]] grid x $page.uibut $page.ui -sticky w label $page.bg -padx 40 -relief sunk -background $bgcolor - ${NS}::button $page.bgbut -text [mc "Background"] \ - -command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg] + ttk::button $page.bgbut -text [mc "Background"] \ + -command [list choosecolor bgcolor {} $page [mc "background"]] grid x $page.bgbut $page.bg -sticky w label $page.fg -padx 40 -relief sunk -background $fgcolor - ${NS}::button $page.fgbut -text [mc "Foreground"] \ - -command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg] + ttk::button $page.fgbut -text [mc "Foreground"] \ + -command [list choosecolor fgcolor {} $page [mc "foreground"]] grid x $page.fgbut $page.fg -sticky w label $page.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0] - ${NS}::button $page.diffoldbut -text [mc "Diff: old lines"] \ - -command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \ - [list $ctext tag conf d0 -foreground]] + ttk::button $page.diffoldbut -text [mc "Diff: old lines"] \ + -command [list choosecolor diffcolors 0 $page [mc "diff old lines"]] grid x $page.diffoldbut $page.diffold -sticky w label $page.diffoldbg -padx 40 -relief sunk -background [lindex $diffbgcolors 0] - ${NS}::button $page.diffoldbgbut -text [mc "Diff: old lines bg"] \ - -command [list choosecolor diffbgcolors 0 $page.diffoldbg \ - [mc "diff old lines bg"] \ - [list $ctext tag conf d0 -background]] + ttk::button $page.diffoldbgbut -text [mc "Diff: old lines bg"] \ + -command [list choosecolor diffbgcolors 0 $page [mc "diff old lines bg"]] grid x $page.diffoldbgbut $page.diffoldbg -sticky w label $page.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1] - ${NS}::button $page.diffnewbut -text [mc "Diff: new lines"] \ - -command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \ - [list $ctext tag conf dresult -foreground]] + ttk::button $page.diffnewbut -text [mc "Diff: new lines"] \ + -command [list choosecolor diffcolors 1 $page [mc "diff new lines"]] grid x $page.diffnewbut $page.diffnew -sticky w label $page.diffnewbg -padx 40 -relief sunk -background [lindex $diffbgcolors 1] - ${NS}::button $page.diffnewbgbut -text [mc "Diff: new lines bg"] \ - -command [list choosecolor diffbgcolors 1 $page.diffnewbg \ - [mc "diff new lines bg"] \ - [list $ctext tag conf dresult -background]] + ttk::button $page.diffnewbgbut -text [mc "Diff: new lines bg"] \ + -command [list choosecolor diffbgcolors 1 $page [mc "diff new lines bg"]] grid x $page.diffnewbgbut $page.diffnewbg -sticky w label $page.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2] - ${NS}::button $page.hunksepbut -text [mc "Diff: hunk header"] \ - -command [list choosecolor diffcolors 2 $page.hunksep \ - [mc "diff hunk header"] \ - [list $ctext tag conf hunksep -foreground]] + ttk::button $page.hunksepbut -text [mc "Diff: hunk header"] \ + -command [list choosecolor diffcolors 2 $page [mc "diff hunk header"]] grid x $page.hunksepbut $page.hunksep -sticky w label $page.markbgsep -padx 40 -relief sunk -background $markbgcolor - ${NS}::button $page.markbgbut -text [mc "Marked line bg"] \ - -command [list choosecolor markbgcolor {} $page.markbgsep \ - [mc "marked line background"] \ - [list $ctext tag conf omark -background]] + ttk::button $page.markbgbut -text [mc "Marked line bg"] \ + -command [list choosecolor markbgcolor {} $page [mc "marked line background"]] grid x $page.markbgbut $page.markbgsep -sticky w label $page.selbgsep -padx 40 -relief sunk -background $selectbgcolor - ${NS}::button $page.selbgbut -text [mc "Select bg"] \ - -command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg] + ttk::button $page.selbgbut -text [mc "Select bg"] \ + -command [list choosecolor selectbgcolor {} $page [mc "background"]] grid x $page.selbgbut $page.selbgsep -sticky w return $page } +proc prefspage_set_colorswatches {page} { + global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor + global diffbgcolors + + $page.ui configure -background $uicolor + $page.bg configure -background $bgcolor + $page.fg configure -background $fgcolor + $page.diffold configure -background [lindex $diffcolors 0] + $page.diffoldbg configure -background [lindex $diffbgcolors 0] + $page.diffnew configure -background [lindex $diffcolors 1] + $page.diffnewbg configure -background [lindex $diffbgcolors 1] + $page.hunksep configure -background [lindex $diffcolors 2] + $page.markbgsep configure -background $markbgcolor + $page.selbgsep configure -background $selectbgcolor +} + proc prefspage_fonts {notebook} { - global NS set page [create_prefs_page $notebook.fonts] - ${NS}::label $page.cfont -text [mc "Fonts: press to choose"] -font mainfontbold + ttk::label $page.cfont -text [mc "Fonts: press to choose"] -font mainfontbold grid $page.cfont - -sticky w -pady 10 mkfontdisp mainfont $page [mc "Main font"] mkfontdisp textfont $page [mc "Diff display font"] @@ -11922,11 +11827,8 @@ proc prefspage_fonts {notebook} { } proc doprefs {} { - global maxwidth maxgraphpct use_ttk NS - global oldprefs prefstop showneartags showlocalchanges - global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor - global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs - global hideremotes want_ttk have_ttk wrapcomment wrapdefault + global oldprefs prefstop + global {*}$::config_variables set top .gitkprefs set prefstop $top @@ -11934,49 +11836,34 @@ proc doprefs {} { raise $top return } - foreach v {maxwidth maxgraphpct showneartags showlocalchanges \ - limitdiffs tabstop perfile_attrs hideremotes want_ttk wrapcomment wrapdefault} { + foreach v $::config_variables { set oldprefs($v) [set $v] } ttk_toplevel $top wm title $top [mc "Gitk preferences"] make_transient $top . - if {[set use_notebook [expr {$use_ttk && [info command ::ttk::notebook] ne ""}]]} { - set notebook [ttk::notebook $top.notebook] - } else { - set notebook [${NS}::frame $top.notebook -borderwidth 0 -relief flat] - } + set notebook [ttk::notebook $top.notebook] lappend pages [prefspage_general $notebook] [mc "General"] lappend pages [prefspage_colors $notebook] [mc "Colors"] lappend pages [prefspage_fonts $notebook] [mc "Fonts"] set col 0 foreach {page title} $pages { - if {$use_notebook} { - $notebook add $page -text $title - } else { - set btn [${NS}::button $notebook.b_[string map {. X} $page] \ - -text $title -command [list raise $page]] - $page configure -text $title - grid $btn -row 0 -column [incr col] -sticky w - grid $page -row 1 -column 0 -sticky news -columnspan 100 - } + $notebook add $page -text $title } - if {!$use_notebook} { - grid columnconfigure $notebook 0 -weight 1 - grid rowconfigure $notebook 1 -weight 1 - raise [lindex $pages 0] - } + grid columnconfigure $notebook 0 -weight 1 + grid rowconfigure $notebook 1 -weight 1 + raise [lindex $pages 0] grid $notebook -sticky news -padx 2 -pady 2 grid rowconfigure $top 0 -weight 1 grid columnconfigure $top 0 -weight 1 - ${NS}::frame $top.buts - ${NS}::button $top.buts.ok -text [mc "OK"] -command prefsok -default active - ${NS}::button $top.buts.can -text [mc "Cancel"] -command prefscan -default normal + ttk::frame $top.buts + ttk::button $top.buts.ok -text [mc "OK"] -command prefsok -default active + ttk::button $top.buts.can -text [mc "Cancel"] -command prefscan -default normal bind $top <Key-Return> prefsok bind $top <Key-Escape> prefscan grid $top.buts.ok $top.buts.can @@ -11996,15 +11883,15 @@ proc choose_extdiff {} { } } -proc choosecolor {v vi w x cmd} { +proc choosecolor {v vi prefspage x} { global $v set c [tk_chooseColor -initialcolor [lindex [set $v] $vi] \ -title [mc "Gitk: choose color for %s" $x]] if {$c eq {}} return - $w conf -background $c lset $v $vi $c - eval $cmd $c + set_gui_colors + prefspage_set_colorswatches $prefspage } proc setselbg {c} { @@ -12057,25 +11944,38 @@ proc setfg {c} { $canv itemconf markid -outline $c } +proc set_gui_colors {} { + global uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor + global diffbgcolors + + setui $uicolor + setbg $bgcolor + setfg $fgcolor + $ctext tag conf d0 -foreground [lindex $diffcolors 0] + $ctext tag conf d0 -background [lindex $diffbgcolors 0] + $ctext tag conf dresult -foreground [lindex $diffcolors 1] + $ctext tag conf dresult -background [lindex $diffbgcolors 1] + $ctext tag conf hunksep -foreground [lindex $diffcolors 2] + $ctext tag conf omark -background $markbgcolor + setselbg $selectbgcolor +} + proc prefscan {} { global oldprefs prefstop + global {*}$::config_variables - foreach v {maxwidth maxgraphpct showneartags showlocalchanges \ - limitdiffs tabstop perfile_attrs hideremotes want_ttk wrapcomment wrapdefault} { - global $v + foreach v $::config_variables { set $v $oldprefs($v) } catch {destroy $prefstop} unset prefstop fontcan + set_gui_colors } proc prefsok {} { - global maxwidth maxgraphpct - global oldprefs prefstop showneartags showlocalchanges - global fontpref mainfont textfont uifont - global limitdiffs treediffs perfile_attrs - global hideremotes wrapcomment wrapdefault + global oldprefs prefstop fontpref treediffs + global {*}$::config_variables global ctext catch {destroy $prefstop} @@ -12122,7 +12022,7 @@ proc prefsok {} { $limitdiffs != $oldprefs(limitdiffs)} { reselectline } - if {$hideremotes != $oldprefs(hideremotes)} { + if {$hideremotes != $oldprefs(hideremotes) || $refstohide != $oldprefs(refstohide)} { rereadrefs } if {$wrapcomment != $oldprefs(wrapcomment)} { @@ -12478,7 +12378,7 @@ proc cache_gitattr {attr pathlist} { foreach row [split $rlist "\n"] { if {[regexp "(.*): $attr: (.*)" $row m path value]} { if {[string index $path 0] eq "\""} { - set path [encoding convertfrom utf-8 [lindex $path 0]] + set path [convertfrom utf-8 [lindex $path 0]] } set path_attr_cache($attr,$path) $value } @@ -12499,6 +12399,23 @@ proc get_path_encoding {path} { return $tcl_enc } +proc is_other_ref_visible {ref} { + global refstohide + + if {$refstohide eq {}} { + return 1 + } + + foreach pat [split $refstohide " "] { + if {$pat eq {}} continue + if {[string match $pat $ref]} { + return 0 + } + } + + return 1 +} + ## For msgcat loading, first locate the installation location. if { [info exists ::env(GITK_MSGSDIR)] } { ## Msgsdir was manually set in the environment. @@ -12517,13 +12434,6 @@ namespace import ::msgcat::mc ## And eventually load the actual message catalog ::msgcat::mcload $gitk_msgsdir -# First check that Tcl/Tk is recent enough -if {[catch {package require Tk 8.4} err]} { - show_error {} . [mc "Sorry, gitk cannot run with this version of Tcl/Tk.\n\ - Gitk requires at least Tcl/Tk 8.4."] - exit 1 -} - # on OSX bring the current Wish process window to front if {[tk windowingsystem] eq "aqua"} { safe_exec [list osascript -e [format { @@ -12569,6 +12479,17 @@ catch { } } +# Use object format as hash algorightm (either "sha1" or "sha256") +set hashalgorithm [exec git rev-parse --show-object-format] +if {$hashalgorithm eq "sha1"} { + set hashlength 40 +} elseif {$hashalgorithm eq "sha256"} { + set hashlength 64 +} else { + puts stderr "Unknown hash algorithm: $hashalgorithm" + exit 1 +} + set log_showroot true catch { set log_showroot [exec git config --bool --get log.showroot] @@ -12602,17 +12523,19 @@ set wrapcomment "none" set wrapdefault "none" set showneartags 1 set hideremotes 0 +set refstohide "" +set sortrefsbytype 1 set maxrefs 20 set visiblerefs {"master"} set maxlinelen 200 set showlocalchanges 1 set limitdiffs 1 +set kscroll 3 set datetimeformat "%Y-%m-%d %H:%M:%S" set autocopy 0 set autoselect 1 -set autosellen 40 +set autosellen $hashlength set perfile_attrs 0 -set want_ttk 1 if {[tk windowingsystem] eq "aqua"} { set extdifftool "opendiff" @@ -12688,14 +12611,14 @@ catch { set config_file_tmp [file join $env(XDG_CONFIG_HOME) git gitk-tmp] } else { # default XDG_CONFIG_HOME - set config_file "~/.config/git/gitk" - set config_file_tmp "~/.config/git/gitk-tmp" + set config_file "$env(HOME)/.config/git/gitk" + set config_file_tmp "$env(HOME)/.config/git/gitk-tmp" } if {![file exists $config_file]} { # for backward compatibility use the old config file if it exists - if {[file exists "~/.gitk"]} { - set config_file "~/.gitk" - set config_file_tmp "~/.gitk-tmp" + if {[file exists "$env(HOME)/.gitk"]} { + set config_file "$env(HOME)/.gitk" + set config_file_tmp "$env(HOME)/.gitk-tmp" } elseif {![file exists [file dirname $config_file]]} { file mkdir [file dirname $config_file] } @@ -12705,19 +12628,67 @@ catch { config_check_tmp_exists 50 set config_variables { - mainfont textfont uifont tabstop findmergefiles maxgraphpct maxwidth - cmitmode wrapcomment wrapdefault autocopy autoselect autosellen - showneartags maxrefs visiblerefs - hideremotes showlocalchanges datetimeformat limitdiffs uicolor want_ttk - bgcolor fgcolor uifgcolor uifgdisabledcolor colors diffcolors mergecolors - markbgcolor diffcontext selectbgcolor foundbgcolor currentsearchhitbgcolor - extdifftool perfile_attrs headbgcolor headfgcolor headoutlinecolor - remotebgcolor tagbgcolor tagfgcolor tagoutlinecolor reflinecolor - filesepbgcolor filesepfgcolor linehoverbgcolor linehoverfgcolor - linehoveroutlinecolor mainheadcirclecolor workingfilescirclecolor - indexcirclecolor circlecolors linkfgcolor circleoutlinecolor diffbgcolors + autocopy + autoselect + autosellen + bgcolor + circlecolors + circleoutlinecolor + cmitmode + colors + currentsearchhitbgcolor + datetimeformat + diffbgcolors + diffcolors + diffcontext + extdifftool + fgcolor + filesepbgcolor + filesepfgcolor + findmergefiles + foundbgcolor + headbgcolor + headfgcolor + headoutlinecolor + hideremotes + indexcirclecolor + kscroll + limitdiffs + linehoverbgcolor + linehoverfgcolor + linehoveroutlinecolor + linkfgcolor + mainfont + mainheadcirclecolor + markbgcolor + maxgraphpct + maxrefs + maxwidth + mergecolors + perfile_attrs + reflinecolor + refstohide + remotebgcolor + selectbgcolor + showlocalchanges + showneartags + sortrefsbytype + tabstop + tagbgcolor + tagfgcolor + tagoutlinecolor + textfont + uicolor + uifgcolor + uifgdisabledcolor + uifont + visiblerefs web_browser + workingfilescirclecolor + wrapcomment + wrapdefault } + foreach var $config_variables { config_init_trace $var trace add variable $var write config_variable_change_cb @@ -12734,8 +12705,6 @@ eval font create textfontbold [fontflags textfont 1] parsefont uifont $uifont eval font create uifont [fontflags uifont] -setui $uicolor - setoptions # check that we can find a .git directory somewhere... @@ -12808,25 +12777,7 @@ set nullid "0000000000000000000000000000000000000000" set nullid2 "0000000000000000000000000000000000000001" set nullfile "/dev/null" -set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] -set have_tk86 [expr {[package vcompare $tk_version "8.6"] >= 0}] -if {![info exists have_ttk]} { - set have_ttk [llength [info commands ::ttk::style]] -} -set use_ttk [expr {$have_ttk && $want_ttk}] -set NS [expr {$use_ttk ? "ttk" : ""}] - -if {$use_ttk} { - setttkstyle -} - -regexp {^git version ([\d.]*\d)} [exec git version] _ git_version - -set show_notes {} -if {[package vcompare $git_version "1.6.6.2"] >= 0} { - set show_notes "--show-notes" -} - +setttkstyle set appname "gitk" set runq {} @@ -12942,6 +12893,8 @@ if {[tk windowingsystem] eq "win32"} { focus -force . } +set_gui_colors + getcommits {} # Local variables: diff --git a/gitk-git/po/bg.po b/gitk-git/po/bg.po index 773a049831..d1e7d92425 100644 --- a/gitk-git/po/bg.po +++ b/gitk-git/po/bg.po @@ -1,15 +1,15 @@ # Bulgarian translation of gitk po-file. -# Copyright (C) 2014, 2015, 2019, 2020, 2024 Alexander Shopov <ash@kambanaria.org>. +# Copyright (C) 2014, 2015, 2019, 2020, 2024, 2025 Alexander Shopov <ash@kambanaria.org>. # This file is distributed under the same license as the git package. -# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2019, 2020, 2024. +# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2019, 2020, 2024, 2025. # # msgid "" msgstr "" "Project-Id-Version: gitk master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-12-24 11:01+0100\n" -"PO-Revision-Date: 2024-12-24 11:05+0100\n" +"POT-Creation-Date: 2025-07-22 18:34+0200\n" +"PO-Revision-Date: 2025-07-28 13:38+0200\n" "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n" "Language-Team: Bulgarian <dict@fsa-bg.org>\n" "Language: bg\n" @@ -18,32 +18,25 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: gitk:139 msgid "Couldn't get list of unmerged files:" msgstr "Списъкът с неслети файлове не може да се получи:" -#: gitk:211 gitk:2430 msgid "Color words" msgstr "Оцветяване на думите" -#: gitk:216 gitk:2430 gitk:8335 gitk:8368 msgid "Markup words" msgstr "Отбелязване на думите" -#: gitk:323 msgid "Error parsing revisions:" msgstr "Грешка при анализ на версиите:" -#: gitk:389 msgid "Error executing --argscmd command:" msgstr "Грешка при изпълнение на командата с „--argscmd“." -#: gitk:402 msgid "No files selected: --merge specified but no files are unmerged." msgstr "" "Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове." -#: gitk:405 msgid "" "No files selected: --merge specified but no unmerged files are within file " "limit." @@ -51,326 +44,246 @@ msgstr "" "Не са избрани файлове — указана е опцията „--merge“, но няма неслети файлове " "в ограниченията." -#: gitk:430 gitk:585 msgid "Error executing git log:" msgstr "Грешка при изпълнение на „git log“:" -#: gitk:448 gitk:601 msgid "Reading" msgstr "Прочитане" -#: gitk:508 gitk:4596 msgid "Reading commits..." msgstr "Прочитане на подаванията…" -#: gitk:511 gitk:1660 gitk:4599 msgid "No commits selected" msgstr "Не са избрани подавания" -#: gitk:1468 gitk:4116 gitk:12738 msgid "Command line" msgstr "Команден ред" -#: gitk:1534 msgid "Can't parse git log output:" msgstr "Изходът от „git log“ не може да се анализира:" -#: gitk:1763 msgid "No commit information available" msgstr "Липсва информация за подавания" -#: gitk:1930 gitk:1959 gitk:4386 gitk:9875 gitk:11485 gitk:11805 msgid "OK" msgstr "Добре" -#: gitk:1961 gitk:4388 gitk:9311 gitk:9390 gitk:9520 gitk:9606 gitk:9877 -#: gitk:11486 gitk:11806 msgid "Cancel" msgstr "Отказ" -#: gitk:2114 msgid "&Update" msgstr "&Обновяване" -#: gitk:2115 msgid "&Reload" msgstr "&Презареждане" -#: gitk:2116 msgid "Reread re&ferences" msgstr "Прочитане &наново" -#: gitk:2117 msgid "&List references" msgstr "&Изброяване на указателите" -#: gitk:2119 msgid "Start git &gui" msgstr "&Стартиране на „git gui“" -#: gitk:2121 msgid "&Quit" msgstr "&Спиране на програмата" -#: gitk:2113 msgid "&File" msgstr "&Файл" -#: gitk:2125 msgid "&Preferences" msgstr "&Настройки" -#: gitk:2124 msgid "&Edit" msgstr "&Редактиране" -#: gitk:2129 msgid "&New view..." msgstr "&Нов изглед…" -#: gitk:2130 msgid "&Edit view..." msgstr "&Редактиране на изгледа…" -#: gitk:2131 msgid "&Delete view" msgstr "&Изтриване на изгледа" -#: gitk:2133 msgid "&All files" msgstr "&Всички файлове" -#: gitk:2128 msgid "&View" msgstr "&Изглед" -#: gitk:2138 gitk:2148 msgid "&About gitk" msgstr "&Относно gitk" -#: gitk:2139 gitk:2153 msgid "&Key bindings" msgstr "&Клавишни комбинации" -#: gitk:2137 gitk:2152 msgid "&Help" msgstr "Помо&щ" -#: gitk:2230 gitk:8767 msgid "Commit ID:" msgstr "Подаване:" -#: gitk:2274 msgid "Row" msgstr "Ред" -#: gitk:2312 msgid "Find" msgstr "Търсене" -#: gitk:2340 msgid "commit" msgstr "подаване" -#: gitk:2344 gitk:2346 gitk:4758 gitk:4781 gitk:4805 gitk:6826 gitk:6898 -#: gitk:6983 msgid "containing:" msgstr "съдържащо:" -#: gitk:2347 gitk:3597 gitk:3602 gitk:4834 msgid "touching paths:" msgstr "в пътищата:" -#: gitk:2348 gitk:4848 msgid "adding/removing string:" msgstr "добавящо/премахващо низ" -#: gitk:2349 gitk:4850 msgid "changing lines matching:" msgstr "променящо редове напасващи:" -#: gitk:2358 gitk:2360 gitk:4837 msgid "Exact" msgstr "Точно" -#: gitk:2360 gitk:4925 gitk:6794 msgid "IgnCase" msgstr "Без регистър" -#: gitk:2360 gitk:4807 gitk:4923 gitk:6790 msgid "Regexp" msgstr "Рег. израз" -#: gitk:2362 gitk:2363 gitk:4945 gitk:4975 gitk:4982 gitk:6919 gitk:6987 msgid "All fields" msgstr "Всички полета" -#: gitk:2363 gitk:4942 gitk:4975 gitk:6857 msgid "Headline" msgstr "Първи ред" -#: gitk:2364 gitk:4942 gitk:6857 gitk:6987 gitk:7499 msgid "Comments" msgstr "Коментари" -#: gitk:2364 gitk:4942 gitk:4947 gitk:4982 gitk:6857 gitk:7434 gitk:8945 -#: gitk:8960 msgid "Author" msgstr "Автор" -#: gitk:2364 gitk:4942 gitk:6857 gitk:7436 msgid "Committer" msgstr "Подаващ" -#: gitk:2398 msgid "Search" msgstr "Търсене" -#: gitk:2406 msgid "Diff" msgstr "Разлики" -#: gitk:2408 msgid "Old version" msgstr "Стара версия" -#: gitk:2410 msgid "New version" msgstr "Нова версия" -#: gitk:2413 msgid "Lines of context" msgstr "Контекст в редове" -#: gitk:2423 msgid "Ignore space change" msgstr "Празните знаци без значение" -#: gitk:2427 gitk:2429 gitk:8069 gitk:8321 msgid "Line diff" msgstr "Поредови разлики" -#: gitk:2502 msgid "Patch" msgstr "Кръпка" -#: gitk:2504 msgid "Tree" msgstr "Дърво" -#: gitk:2674 gitk:2695 +msgid "Unknown windowing system, cannot bind mouse" +msgstr "Непозната графична система, не може да се установи връзка с мишка" + msgid "Diff this -> selected" msgstr "Разлики между това и избраното" -#: gitk:2675 gitk:2696 msgid "Diff selected -> this" msgstr "Разлики между избраното и това" -#: gitk:2676 gitk:2697 msgid "Make patch" msgstr "Създаване на кръпка" -#: gitk:2677 gitk:9369 msgid "Create tag" msgstr "Създаване на етикет" -#: gitk:2678 msgid "Copy commit reference" msgstr "Копиране на указателя на подаване" -#: gitk:2679 gitk:9500 msgid "Write commit to file" msgstr "Запазване на подаването във файл" -#: gitk:2680 msgid "Create new branch" msgstr "Създаване на нов клон" -#: gitk:2681 msgid "Cherry-pick this commit" msgstr "Отбиране на това подаване" -#: gitk:2682 msgid "Reset HEAD branch to here" msgstr "Привеждане на върха на клона към текущото подаване" -#: gitk:2683 msgid "Mark this commit" msgstr "Отбелязване на това подаване" -#: gitk:2684 msgid "Return to mark" msgstr "Връщане към отбелязаното подаване" -#: gitk:2685 msgid "Find descendant of this and mark" msgstr "Откриване и отбелязване на наследниците" -#: gitk:2686 msgid "Compare with marked commit" msgstr "Сравнение с отбелязаното подаване" -#: gitk:2687 gitk:2698 msgid "Diff this -> marked commit" msgstr "Разлики между това и отбелязаното" -#: gitk:2688 gitk:2699 msgid "Diff marked commit -> this" msgstr "Разлики между отбелязаното и това" -#: gitk:2689 msgid "Revert this commit" msgstr "Отмяна на това подаване" -#: gitk:2705 msgid "Check out this branch" msgstr "Изтегляне на този клон" -#: gitk:2706 msgid "Rename this branch" msgstr "Преименуване на този клон" -#: gitk:2707 msgid "Remove this branch" msgstr "Изтриване на този клон" -#: gitk:2708 msgid "Copy branch name" msgstr "Копиране на името на клона" -#: gitk:2715 msgid "Highlight this too" msgstr "Отбелязване и на това" -#: gitk:2716 msgid "Highlight this only" msgstr "Отбелязване само на това" -#: gitk:2717 msgid "External diff" msgstr "Външна програма за разлики" -#: gitk:2718 msgid "Blame parent commit" msgstr "Анотиране на родителското подаване" -#: gitk:2719 msgid "Copy path" msgstr "Копиране на пътя" -#: gitk:2726 msgid "Show origin of this line" msgstr "Показване на произхода на този ред" -#: gitk:2727 msgid "Run git gui blame on this line" msgstr "Изпълнение на „git gui blame“ върху този ред" -#: gitk:3081 msgid "About gitk" msgstr "Относно gitk" -#: gitk:3083 msgid "" "\n" "Gitk - a commit viewer for git\n" @@ -386,324 +299,250 @@ msgstr "" "\n" "Използвайте и разпространявайте при условията на ОПЛ на ГНУ" -#: gitk:3091 gitk:3158 gitk:10090 msgid "Close" msgstr "Затваряне" -#: gitk:3112 msgid "Gitk key bindings" msgstr "Клавишни комбинации" -#: gitk:3115 msgid "Gitk key bindings:" msgstr "Клавишни комбинации:" -#: gitk:3117 #, tcl-format msgid "<%s-Q>\t\tQuit" msgstr "<%s-Q>\t\tСпиране на програмата" -#: gitk:3118 #, tcl-format msgid "<%s-W>\t\tClose window" msgstr "<%s-W>\t\tЗатваряне на прозореца" -#: gitk:3119 msgid "<Home>\t\tMove to first commit" msgstr "<Home>\t\tКъм първото подаване" -#: gitk:3120 msgid "<End>\t\tMove to last commit" msgstr "<End>\t\tКъм последното подаване" -#: gitk:3121 msgid "<Up>, p, k\tMove up one commit" msgstr "<Up>, p, k\tЕдно подаване нагоре" -#: gitk:3122 msgid "<Down>, n, j\tMove down one commit" msgstr "<Down>, n, j\tЕдно подаване надолу" -#: gitk:3123 msgid "<Left>, z, h\tGo back in history list" msgstr "<Left>, z, h\tНазад в историята" -#: gitk:3124 msgid "<Right>, x, l\tGo forward in history list" msgstr "<Right>, x, l\tНапред в историята" -#: gitk:3125 #, tcl-format msgid "<%s-n>\tGo to n-th parent of current commit in history list" msgstr "<%s-n>\tКъм n-тия родител на текущото подаване в историята" -#: gitk:3126 msgid "<PageUp>\tMove up one page in commit list" msgstr "<PageUp>\tСтраница нагоре в списъка с подаванията" -#: gitk:3127 msgid "<PageDown>\tMove down one page in commit list" msgstr "<PageDown>\tСтраница надолу в списъка с подаванията" -#: gitk:3128 #, tcl-format msgid "<%s-Home>\tScroll to top of commit list" msgstr "<%s-Home>\tКъм началото на списъка с подаванията" -#: gitk:3129 #, tcl-format msgid "<%s-End>\tScroll to bottom of commit list" msgstr "<%s-End>\tКъм края на списъка с подаванията" -#: gitk:3130 #, tcl-format msgid "<%s-Up>\tScroll commit list up one line" msgstr "<%s-Up>\tРед нагоре в списъка с подавания" -#: gitk:3131 #, tcl-format msgid "<%s-Down>\tScroll commit list down one line" msgstr "<%s-Down>\tРед надолу в списъка с подавания" -#: gitk:3132 #, tcl-format msgid "<%s-PageUp>\tScroll commit list up one page" msgstr "<%s-PageUp>\tСтраница нагоре в списъка с подавания" -#: gitk:3133 #, tcl-format msgid "<%s-PageDown>\tScroll commit list down one page" msgstr "<%s-PageDown>\tСтраница надолу в списъка с подавания" -#: gitk:3134 msgid "<Shift-Up>\tFind backwards (upwards, later commits)" msgstr "<Shift-Up>\tТърсене назад (визуално нагоре, исторически — последващи)" -#: gitk:3135 msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)" msgstr "" "<Shift-Down>\tТърсене напред (визуално надолу, исторически — предхождащи)" -#: gitk:3136 msgid "<Delete>, b\tScroll diff view up one page" msgstr "<Delete>, b\tСтраница нагоре в изгледа за разлики" -#: gitk:3137 msgid "<Backspace>\tScroll diff view up one page" msgstr "<Backspace>\tСтраница надолу в изгледа за разлики" -#: gitk:3138 msgid "<Space>\t\tScroll diff view down one page" msgstr "<Space>\t\tСтраница надолу в изгледа за разлики" -#: gitk:3139 msgid "u\t\tScroll diff view up 18 lines" msgstr "u\t\t18 реда нагоре в изгледа за разлики" -#: gitk:3140 msgid "d\t\tScroll diff view down 18 lines" msgstr "d\t\t18 реда надолу в изгледа за разлики" -#: gitk:3141 #, tcl-format msgid "<%s-F>\t\tFind" msgstr "<%s-F>\t\tТърсене" -#: gitk:3142 #, tcl-format msgid "<%s-G>\t\tMove to next find hit" msgstr "<%s-G>\t\tКъм следващата поява" -#: gitk:3143 msgid "<Return>\tMove to next find hit" msgstr "<Return>\tКъм следващата поява" -#: gitk:3144 msgid "g\t\tGo to commit" msgstr "g\t\tКъм последното подаване" -#: gitk:3145 msgid "/\t\tFocus the search box" msgstr "/\t\tФокус върху полето за търсене" -#: gitk:3146 msgid "?\t\tMove to previous find hit" msgstr "?\t\tКъм предишната поява" -#: gitk:3147 msgid "f\t\tScroll diff view to next file" msgstr "f\t\tСледващ файл в изгледа за разлики" -#: gitk:3148 #, tcl-format msgid "<%s-S>\t\tSearch for next hit in diff view" msgstr "<%s-S>\t\tТърсене на следващата поява в изгледа за разлики" -#: gitk:3149 #, tcl-format msgid "<%s-R>\t\tSearch for previous hit in diff view" msgstr "<%s-R>\t\tТърсене на предишната поява в изгледа за разлики" -#: gitk:3150 #, tcl-format msgid "<%s-KP+>\tIncrease font size" msgstr "<%s-KP+>\tПо-голям размер на шрифта" -#: gitk:3151 #, tcl-format msgid "<%s-plus>\tIncrease font size" msgstr "<%s-plus>\tПо-голям размер на шрифта" -#: gitk:3152 #, tcl-format msgid "<%s-KP->\tDecrease font size" msgstr "<%s-KP->\tПо-малък размер на шрифта" -#: gitk:3153 #, tcl-format msgid "<%s-minus>\tDecrease font size" msgstr "<%s-minus>\tПо-малък размер на шрифта" -#: gitk:3154 msgid "<F5>\t\tUpdate" msgstr "<F5>\t\tОбновяване" -#: gitk:3621 gitk:3630 #, tcl-format msgid "Error creating temporary directory %s:" msgstr "Грешка при създаването на временната директория „%s“:" -#: gitk:3643 #, tcl-format msgid "Error getting \"%s\" from %s:" msgstr "Грешка при получаването на „%s“ от %s:" -#: gitk:3706 msgid "command failed:" msgstr "неуспешно изпълнение на команда:" -#: gitk:3855 msgid "No such commit" msgstr "Такова подаване няма" -#: gitk:3869 msgid "git gui blame: command failed:" msgstr "„git gui blame“: неуспешно изпълнение на команда:" -#: gitk:3900 #, tcl-format msgid "Couldn't read merge head: %s" msgstr "Върхът за сливане не може да се прочете: %s" -#: gitk:3908 #, tcl-format msgid "Error reading index: %s" msgstr "Грешка при прочитане на индекса: %s" -#: gitk:3933 #, tcl-format msgid "Couldn't start git blame: %s" msgstr "Командата „git blame“ не може да се стартира: %s" -#: gitk:3936 gitk:6825 msgid "Searching" msgstr "Търсене" -#: gitk:3968 #, tcl-format msgid "Error running git blame: %s" msgstr "Грешка при изпълнението на „git blame“: %s" -#: gitk:3996 #, tcl-format msgid "That line comes from commit %s, which is not in this view" msgstr "Този ред идва от подаването %s, което не е в изгледа" -#: gitk:4010 msgid "External diff viewer failed:" msgstr "Неуспешно изпълнение на външната програма за разлики:" -#: gitk:4114 msgid "All files" msgstr "Всички файлове" -#: gitk:4138 msgid "View" msgstr "Изглед" -#: gitk:4141 msgid "Gitk view definition" msgstr "Дефиниция на изглед в Gitk" -#: gitk:4145 msgid "Remember this view" msgstr "Запазване на този изглед" -#: gitk:4146 msgid "References (space separated list):" msgstr "Указатели (списък с разделител интервал):" -#: gitk:4147 msgid "Branches & tags:" msgstr "Клони и етикети:" -#: gitk:4148 msgid "All refs" msgstr "Всички указатели" -#: gitk:4149 msgid "All (local) branches" msgstr "Всички (локални) клони" -#: gitk:4150 msgid "All tags" msgstr "Всички етикети" -#: gitk:4151 msgid "All remote-tracking branches" msgstr "Всички следящи клони" -#: gitk:4152 msgid "Commit Info (regular expressions):" msgstr "Информация за подаване (рег. изр.):" -#: gitk:4153 msgid "Author:" msgstr "Автор:" -#: gitk:4154 msgid "Committer:" msgstr "Подал:" -#: gitk:4155 msgid "Commit Message:" msgstr "Съобщение при подаване:" -#: gitk:4156 msgid "Matches all Commit Info criteria" msgstr "Съвпадение по всички характеристики на подаването" -#: gitk:4157 msgid "Matches no Commit Info criteria" msgstr "Не съвпада по никоя от характеристиките на подаването" -#: gitk:4158 msgid "Changes to Files:" msgstr "Промени по файловете:" -#: gitk:4159 msgid "Fixed String" msgstr "Дословен низ" -#: gitk:4160 msgid "Regular Expression" msgstr "Регулярен израз" -#: gitk:4161 msgid "Search string:" msgstr "Низ за търсене:" -#: gitk:4162 msgid "" "Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " "15:27:38\"):" @@ -711,208 +550,159 @@ msgstr "" "Дата на подаване („2 weeks ago“ (преди 2 седмици), „2009-03-17 15:27:38“, " "„March 17, 2009 15:27:38“):" -#: gitk:4163 msgid "Since:" msgstr "От:" -#: gitk:4164 msgid "Until:" msgstr "До:" -#: gitk:4165 msgid "Limit and/or skip a number of revisions (positive integer):" msgstr "" "Ограничаване и/или прескачане на определен брой версии (неотрицателно цяло " "число):" -#: gitk:4166 msgid "Number to show:" msgstr "Брой показани:" -#: gitk:4167 msgid "Number to skip:" msgstr "Брой прескочени:" -#: gitk:4168 msgid "Miscellaneous options:" msgstr "Разни:" -#: gitk:4169 msgid "Strictly sort by date" msgstr "Подреждане по дата" -#: gitk:4170 msgid "Mark branch sides" msgstr "Отбелязване на страните по клона" -#: gitk:4171 msgid "Limit to first parent" msgstr "Само първия родител" -#: gitk:4172 msgid "Simple history" msgstr "Опростена история" -#: gitk:4173 msgid "Additional arguments to git log:" msgstr "Допълнителни аргументи към „git log“:" -#: gitk:4174 msgid "Enter files and directories to include, one per line:" msgstr "Въведете файловете и директориите за включване, по елемент на ред" -#: gitk:4175 msgid "Command to generate more commits to include:" msgstr "" "Команда за генерирането на допълнителни подавания, които да се включат:" -#: gitk:4299 msgid "Gitk: edit view" msgstr "Gitk: редактиране на изглед" -#: gitk:4307 msgid "-- criteria for selecting revisions" msgstr "— критерии за избор на версии" -#: gitk:4312 msgid "View Name" msgstr "Име на изглед" -#: gitk:4387 msgid "Apply (F5)" msgstr "Прилагане (F5)" -#: gitk:4425 msgid "Error in commit selection arguments:" msgstr "Грешка в аргументите за избор на подавания:" -#: gitk:4480 gitk:4533 gitk:4995 gitk:5009 gitk:6279 gitk:12679 gitk:12680 msgid "None" msgstr "Няма" -#: gitk:5092 gitk:5097 msgid "Descendant" msgstr "Наследник" -#: gitk:5093 msgid "Not descendant" msgstr "Не е наследник" -#: gitk:5100 gitk:5105 msgid "Ancestor" msgstr "Предшественик" -#: gitk:5101 msgid "Not ancestor" msgstr "Не е предшественик" -#: gitk:5395 msgid "Local changes checked in to index but not committed" msgstr "Локални промени добавени към индекса, но неподадени" -#: gitk:5431 msgid "Local uncommitted changes, not checked in to index" msgstr "Локални промени извън индекса" -#: gitk:7179 msgid "Error starting web browser:" msgstr "Грешка при стартирането на уеб браузър:" -#: gitk:7240 msgid "and many more" msgstr "и още много" -#: gitk:7243 msgid "many" msgstr "много" -#: gitk:7438 msgid "Tags:" msgstr "Етикети:" -#: gitk:7455 gitk:7461 gitk:8940 msgid "Parent" msgstr "Родител" -#: gitk:7466 msgid "Child" msgstr "Дете" -#: gitk:7475 msgid "Branch" msgstr "Клон" -#: gitk:7478 msgid "Follows" msgstr "Следва" -#: gitk:7481 msgid "Precedes" msgstr "Предшества" -#: gitk:8076 #, tcl-format msgid "Error getting diffs: %s" msgstr "Грешка при получаването на разликите: %s" -#: gitk:8765 msgid "Goto:" msgstr "Към ред:" -#: gitk:8786 #, tcl-format msgid "Short commit ID %s is ambiguous" msgstr "Съкратената контролна сума %s не е еднозначна" -#: gitk:8793 #, tcl-format msgid "Revision %s is not known" msgstr "Непозната версия %s" -#: gitk:8803 #, tcl-format msgid "Commit ID %s is not known" msgstr "Непозната контролна сума %s" -#: gitk:8805 #, tcl-format msgid "Revision %s is not in the current view" msgstr "Версия %s не е в текущия изглед" -#: gitk:8947 gitk:8962 msgid "Date" msgstr "Дата" -#: gitk:8950 msgid "Children" msgstr "Деца" -#: gitk:9013 #, tcl-format msgid "Reset %s branch to here" msgstr "Зануляване на клона „%s“ към текущото подаване" -#: gitk:9015 msgid "Detached head: can't reset" msgstr "Несвързан връх: невъзможно зануляване" -#: gitk:9120 gitk:9126 msgid "Skipping merge commit " msgstr "Пропускане на подаването на сливането" -#: gitk:9135 gitk:9140 msgid "Error getting patch ID for " msgstr "Грешка при получаването на идентификатора на " -#: gitk:9136 gitk:9141 msgid " - stopping\n" msgstr " — спиране\n" -#: gitk:9146 gitk:9149 gitk:9157 gitk:9171 gitk:9180 msgid "Commit " msgstr "Подаване" -#: gitk:9150 msgid "" " is the same patch as\n" " " @@ -920,7 +710,6 @@ msgstr "" " е същата кръпка като\n" " " -#: gitk:9158 msgid "" " differs from\n" " " @@ -928,7 +717,6 @@ msgstr "" " се различава от\n" " " -#: gitk:9160 msgid "" "Diff of commits:\n" "\n" @@ -936,147 +724,113 @@ msgstr "" "Разлика между подаванията:\n" "\n" -#: gitk:9172 gitk:9181 #, tcl-format msgid " has %s children - stopping\n" msgstr " има %s деца — спиране\n" -#: gitk:9200 #, tcl-format msgid "Error writing commit to file: %s" msgstr "Грешка при запазването на подаването във файл: %s" -#: gitk:9206 #, tcl-format msgid "Error diffing commits: %s" msgstr "Грешка при изчисляването на разликите между подаванията: %s" -#: gitk:9252 msgid "Top" msgstr "Най-горе" -#: gitk:9253 msgid "From" msgstr "От" -#: gitk:9258 msgid "To" msgstr "До" -#: gitk:9282 msgid "Generate patch" msgstr "Генериране на кръпка" -#: gitk:9284 msgid "From:" msgstr "От:" -#: gitk:9293 msgid "To:" msgstr "До:" -#: gitk:9302 msgid "Reverse" msgstr "Обръщане" -#: gitk:9304 gitk:9514 msgid "Output file:" msgstr "Запазване във файла:" -#: gitk:9310 msgid "Generate" msgstr "Генериране" -#: gitk:9348 msgid "Error creating patch:" msgstr "Грешка при създаването на кръпка:" -#: gitk:9371 gitk:9502 gitk:9590 msgid "ID:" msgstr "Идентификатор:" -#: gitk:9380 msgid "Tag name:" msgstr "Име на етикет:" -#: gitk:9383 msgid "Tag message is optional" msgstr "Съобщението за етикет е незадължително" -#: gitk:9385 msgid "Tag message:" msgstr "Съобщение за етикет:" -#: gitk:9389 gitk:9560 msgid "Create" msgstr "Създаване" -#: gitk:9407 msgid "No tag name specified" msgstr "Липсва име на етикет" -#: gitk:9411 #, tcl-format msgid "Tag \"%s\" already exists" msgstr "Етикетът „%s“ вече съществува" -#: gitk:9421 msgid "Error creating tag:" msgstr "Грешка при създаването на етикет:" -#: gitk:9511 msgid "Command:" msgstr "Команда:" -#: gitk:9519 msgid "Write" msgstr "Запазване" -#: gitk:9537 msgid "Error writing commit:" msgstr "Грешка при запазването на подаването:" -#: gitk:9559 msgid "Create branch" msgstr "Създаване на клон" -#: gitk:9575 #, tcl-format msgid "Rename branch %s" msgstr "Преименуване на клона „%s“" -#: gitk:9576 msgid "Rename" msgstr "Преименуване" -#: gitk:9600 msgid "Name:" msgstr "Име:" -#: gitk:9624 msgid "Please specify a name for the new branch" msgstr "Укажете име за новия клон" -#: gitk:9629 #, tcl-format msgid "Branch '%s' already exists. Overwrite?" msgstr "Клонът „%s“ вече съществува. Да се презапише ли?" -#: gitk:9673 msgid "Please specify a new name for the branch" msgstr "Укажете ново име за клона" -#: gitk:9736 #, tcl-format msgid "Commit %s is already included in branch %s -- really re-apply it?" msgstr "" "Подаването „%s“ вече е включено в клона „%s“ — да се приложи ли отново?" -#: gitk:9741 msgid "Cherry-picking" msgstr "Отбиране" -#: gitk:9750 #, tcl-format msgid "" "Cherry-pick failed because of local changes to file '%s'.\n" @@ -1085,7 +839,6 @@ msgstr "" "Неуспешно отбиране, защото във файла „%s“ има локални промени.\n" "Подайте, занулете или ги скатайте и пробвайте отново." -#: gitk:9756 msgid "" "Cherry-pick failed because of merge conflict.\n" "Do you wish to run git citool to resolve it?" @@ -1093,20 +846,16 @@ msgstr "" "Неуспешно отбиране поради конфликти при сливане.\n" "Искате ли да ги коригирате чрез „git citool“?" -#: gitk:9772 gitk:9830 msgid "No changes committed" msgstr "Не са подадени промени" -#: gitk:9799 #, tcl-format msgid "Commit %s is not included in branch %s -- really revert it?" msgstr "Подаването „%s“ не е включено в клона „%s“. Да се отменени ли?" -#: gitk:9804 msgid "Reverting" msgstr "Отмяна" -#: gitk:9812 #, tcl-format msgid "" "Revert failed because of local changes to the following files:%s Please " @@ -1115,7 +864,6 @@ msgstr "" "Неуспешна отмяна, защото във файла „%s“ има локални промени.\n" "Подайте, занулете или ги скатайте и пробвайте отново." -#: gitk:9816 msgid "" "Revert failed because of merge conflict.\n" " Do you wish to run git citool to resolve it?" @@ -1123,28 +871,22 @@ msgstr "" "Неуспешно отмяна поради конфликти при сливане.\n" "Искате ли да ги коригирате чрез „git citool“?" -#: gitk:9859 msgid "Confirm reset" msgstr "Потвърждаване на зануляването" -#: gitk:9861 #, tcl-format msgid "Reset branch %s to %s?" msgstr "Да се занули ли клонът „%s“ към „%s“?" -#: gitk:9863 msgid "Reset type:" msgstr "Вид зануляване:" -#: gitk:9866 msgid "Soft: Leave working tree and index untouched" msgstr "Слабо: работното дърво и индекса остават същите" -#: gitk:9869 msgid "Mixed: Leave working tree untouched, reset index" msgstr "Смесено: работното дърво остава същото, индексът се занулява" -#: gitk:9872 msgid "" "Hard: Reset working tree and index\n" "(discard ALL local changes)" @@ -1152,24 +894,19 @@ msgstr "" "Силно: зануляване и на работното дърво, и на индекса\n" "(ВСИЧКИ локални промени ще се загубят безвъзвратно)" -#: gitk:9889 msgid "Resetting" msgstr "Зануляване" -#: gitk:9962 #, tcl-format msgid "A local branch named %s exists already" msgstr "Вече съществува локален клон „%s“." -#: gitk:9970 msgid "Checking out" msgstr "Изтегляне" -#: gitk:10029 msgid "Cannot delete the currently checked-out branch" msgstr "Текущо изтегленият клон не може да се изтрие" -#: gitk:10035 #, tcl-format msgid "" "The commits on branch %s aren't on any other branch.\n" @@ -1178,16 +915,16 @@ msgstr "" "Подаванията на клона „%s“ не са на никой друг клон.\n" "Наистина ли искате да изтриете клона „%s“?" -#: gitk:10066 #, tcl-format msgid "Tags and heads: %s" msgstr "Етикети и върхове: %s" -#: gitk:10083 msgid "Filter" msgstr "Филтриране" -#: gitk:10390 +msgid "Sort refs by type" +msgstr "Подредба на указателите по вид" + msgid "" "Error reading commit topology information; branch and preceding/following " "tag information will be incomplete." @@ -1195,253 +932,167 @@ msgstr "" "Грешка при прочитането на топологията на подаванията. Информацията за клона " "и предшестващите/следващите етикети ще е непълна." -#: gitk:11367 msgid "Tag" msgstr "Етикет" -#: gitk:11371 msgid "Id" msgstr "Идентификатор" -#: gitk:11454 -msgid "Gitk font chooser" -msgstr "Избор на шрифт за Gitk" - -#: gitk:11471 -msgid "B" -msgstr "Ч" - -#: gitk:11474 -msgid "I" -msgstr "К" - -#: gitk:11593 msgid "Commit list display options" msgstr "Настройки на списъка с подавания" -#: gitk:11596 msgid "Maximum graph width (lines)" msgstr "Максимална широчина на графа (в редове)" -#: gitk:11600 #, no-tcl-format msgid "Maximum graph width (% of pane)" msgstr "Максимална широчина на графа (% от панела)" -#: gitk:11603 msgid "Show local changes" msgstr "Показване на локалните промени" -#: gitk:11606 msgid "Hide remote refs" msgstr "Скриване на отдалечените указатели" -#: gitk:11610 msgid "Copy commit ID to clipboard" msgstr "Копиране на контролната сума към буфера за обмен" -#: gitk:11614 msgid "Copy commit ID to X11 selection" msgstr "Копиране на контролната сума в селекцията на X11" -#: gitk:11619 msgid "Length of commit ID to copy" msgstr "Дължина на контролната сума, която се копира" -#: gitk:11622 +msgid "Wheel scrolling multiplier" +msgstr "Множител за колелцето на мишката" + msgid "Diff display options" msgstr "Настройки на показването на разликите" -#: gitk:11624 msgid "Tab spacing" msgstr "Широчина на табулатора" -#: gitk:11628 msgid "Wrap comment text" msgstr "Пренасяне на думите в коментарите" -#: gitk:11633 msgid "Wrap other text" msgstr "Пренасяне на другия текст" -#: gitk:11638 msgid "Display nearby tags/heads" msgstr "Извеждане на близките етикети и върхове" -#: gitk:11641 msgid "Maximum # tags/heads to show" msgstr "Максимален брой етикети/върхове за показване" -#: gitk:11644 msgid "Limit diffs to listed paths" msgstr "Разлика само в избраните пътища" -#: gitk:11647 msgid "Support per-file encodings" msgstr "Поддръжка на различни кодирания за всеки файл" -#: gitk:11653 gitk:11820 msgid "External diff tool" msgstr "Външен инструмент за разлики" -#: gitk:11654 msgid "Choose..." msgstr "Избор…" -#: gitk:11661 msgid "Web browser" msgstr "Уеб браузър" -#: gitk:11666 -msgid "General options" -msgstr "Общи настройки" - -#: gitk:11669 -msgid "Use themed widgets" -msgstr "Използване на тема за графичните обекти" - -#: gitk:11671 -msgid "(change requires restart)" -msgstr "(промяната изисква рестартиране на Gitk)" - -#: gitk:11673 -msgid "(currently unavailable)" -msgstr "(в момента недостъпно)" - -#: gitk:11685 msgid "Colors: press to choose" msgstr "Цветове: избира се с натискане" -#: gitk:11688 msgid "Interface" msgstr "Интерфейс" -#: gitk:11689 msgid "interface" msgstr "интерфейс" -#: gitk:11692 msgid "Background" msgstr "Фон" -#: gitk:11693 gitk:11735 msgid "background" msgstr "фон" -#: gitk:11696 msgid "Foreground" msgstr "Знаци" -#: gitk:11697 msgid "foreground" msgstr "знаци" -#: gitk:11700 msgid "Diff: old lines" msgstr "Разлика: стари редове" -#: gitk:11701 msgid "diff old lines" msgstr "разлика, стари редове" -#: gitk:11705 msgid "Diff: old lines bg" msgstr "Разлика: фон на стари редове" -#: gitk:11707 msgid "diff old lines bg" msgstr "разлика, фон на стари редове" -#: gitk:11711 msgid "Diff: new lines" msgstr "Разлика: нови редове" -#: gitk:11712 msgid "diff new lines" msgstr "разлика, нови редове" -#: gitk:11716 msgid "Diff: new lines bg" msgstr "Разлика: фон на нови редове" -#: gitk:11718 msgid "diff new lines bg" msgstr "разлика, фон на нови редове" -#: gitk:11722 msgid "Diff: hunk header" msgstr "Разлика: начало на парче" -#: gitk:11724 msgid "diff hunk header" msgstr "разлика, начало на парче" -#: gitk:11728 msgid "Marked line bg" msgstr "Фон на отбелязан ред" -#: gitk:11730 msgid "marked line background" msgstr "фон на отбелязан ред" -#: gitk:11734 msgid "Select bg" msgstr "Избор на фон" -#: gitk:11743 msgid "Fonts: press to choose" msgstr "Шрифтове: избира се с натискане" -#: gitk:11745 msgid "Main font" msgstr "Основен шрифт" -#: gitk:11746 msgid "Diff display font" msgstr "Шрифт за разликите" -#: gitk:11747 msgid "User interface font" msgstr "Шрифт на интерфейса" -#: gitk:11769 msgid "Gitk preferences" msgstr "Настройки на Gitk" -#: gitk:11778 msgid "General" msgstr "Общи" -#: gitk:11779 msgid "Colors" msgstr "Цветове" -#: gitk:11780 msgid "Fonts" msgstr "Шрифтове" -#: gitk:11830 #, tcl-format msgid "Gitk: choose color for %s" msgstr "Gitk: избор на цвят на „%s“" -#: gitk:12350 -msgid "" -"Sorry, gitk cannot run with this version of Tcl/Tk.\n" -" Gitk requires at least Tcl/Tk 8.4." -msgstr "" -"Тази версия на Tcl/Tk не се поддържа от Gitk.\n" -" Необходима ви е поне Tcl/Tk 8.4." - -#: gitk:12571 msgid "Cannot find a git repository here." msgstr "Тук липсва хранилище на Git." -#: gitk:12618 #, tcl-format msgid "Ambiguous argument '%s': both revision and filename" msgstr "Нееднозначен аргумент „%s“: има и такава версия, и такъв файл" -#: gitk:12630 msgid "Bad arguments to gitk:" msgstr "Неправилни аргументи на gitk:" diff --git a/gpg-interface.c b/gpg-interface.c index 0896458de5..06e7fb5060 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -25,7 +25,7 @@ static void gpg_interface_lazy_init(void) if (done) return; done = 1; - git_config(git_gpg_config, NULL); + repo_config(the_repository, git_gpg_config, NULL); } static char *configured_signing_key; @@ -144,6 +144,18 @@ static struct gpg_format *get_format_by_sig(const char *sig) return NULL; } +const char *get_signature_format(const char *buf) +{ + struct gpg_format *format = get_format_by_sig(buf); + return format ? format->name : "unknown"; +} + +int valid_signature_format(const char *format) +{ + return (!!get_format_by_name(format) || + !strcmp(format, "unknown")); +} + void signature_check_clear(struct signature_check *sigc) { FREE_AND_NULL(sigc->payload); @@ -783,7 +795,7 @@ static int git_gpg_config(const char *var, const char *value, if (fmtname) { fmt = get_format_by_name(fmtname); - return git_config_string((char **) &fmt->program, var, value); + return git_config_pathname((char **) &fmt->program, var, value); } return 0; @@ -1048,7 +1060,7 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature, key_file->filename.buf); goto out; } - ssh_signing_key_file = strbuf_detach(&key_file->filename, NULL); + ssh_signing_key_file = xstrdup(key_file->filename.buf); } else { /* We assume a file */ ssh_signing_key_file = interpolate_path(signing_key, 1); diff --git a/gpg-interface.h b/gpg-interface.h index e09f12e8d0..60ddf8bbfa 100644 --- a/gpg-interface.h +++ b/gpg-interface.h @@ -48,6 +48,18 @@ struct signature_check { void signature_check_clear(struct signature_check *sigc); /* + * Return the format of the signature (like "openpgp", "x509", "ssh" + * or "unknown"). + */ +const char *get_signature_format(const char *buf); + +/* + * Is the signature format valid (like "openpgp", "x509", "ssh" or + * "unknown") + */ +int valid_signature_format(const char *format); + +/* * Look at a GPG signed tag object. If such a signature exists, store it in * signature and the signed content in payload. Return 1 if a signature was * found, and 0 otherwise. @@ -175,6 +175,16 @@ static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *s /* Number of algorithms supported (including unknown). */ #define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1) +/* Default hash algorithm if unspecified. */ +#ifdef WITH_BREAKING_CHANGES +# define GIT_HASH_DEFAULT GIT_HASH_SHA256 +#else +# define GIT_HASH_DEFAULT GIT_HASH_SHA1 +#endif + +/* Legacy hash algorithm. Implied for older data formats which don't specify. */ +#define GIT_HASH_SHA1_LEGACY GIT_HASH_SHA1 + /* "sha1", big-endian */ #define GIT_SHA1_FORMAT_ID 0x73686131 @@ -332,7 +332,7 @@ static int get_colopts(const char *var, const char *value, void list_commands(struct cmdnames *main_cmds, struct cmdnames *other_cmds) { unsigned int colopts = 0; - git_config(get_colopts, &colopts); + repo_config(the_repository, get_colopts, &colopts); if (main_cmds->cnt) { const char *exec_path = git_exec_path(); @@ -417,7 +417,7 @@ void list_cmds_by_config(struct string_list *list) { const char *cmd_list; - if (git_config_get_string_tmp("completion.commands", &cmd_list)) + if (repo_config_get_string_tmp(the_repository, "completion.commands", &cmd_list)) return; string_list_sort(list); @@ -502,7 +502,7 @@ static void list_all_cmds_help_aliases(int longest) struct cmdname_help *aliases; int i; - git_config(get_alias, &alias_list); + repo_config(the_repository, get_alias, &alias_list); string_list_sort(&alias_list); for (i = 0; i < alias_list.nr; i++) { @@ -810,6 +810,9 @@ void get_version_info(struct strbuf *buf, int show_build_options) SHA1_UNSAFE_BACKEND); #endif strbuf_addf(buf, "SHA-256: %s\n", SHA256_BACKEND); + strbuf_addf(buf, "default-ref-format: %s\n", + ref_storage_format_to_name(REF_STORAGE_FORMAT_DEFAULT)); + strbuf_addf(buf, "default-hash: %s\n", hash_algos[GIT_HASH_DEFAULT].name); } } diff --git a/http-backend.c b/http-backend.c index ad8c403749..d5dfe762bb 100644 --- a/http-backend.c +++ b/http-backend.c @@ -246,13 +246,13 @@ static void http_config(void) int i, value = 0; struct strbuf var = STRBUF_INIT; - git_config_get_bool("http.getanyfile", &getanyfile); - git_config_get_ulong("http.maxrequestbuffer", &max_request_buffer); + repo_config_get_bool(the_repository, "http.getanyfile", &getanyfile); + repo_config_get_ulong(the_repository, "http.maxrequestbuffer", &max_request_buffer); for (i = 0; i < ARRAY_SIZE(rpc_service); i++) { struct rpc_service *svc = &rpc_service[i]; strbuf_addf(&var, "http.%s", svc->config_name); - if (!git_config_get_bool(var.buf, &value)) + if (!repo_config_get_bool(the_repository, var.buf, &value)) svc->enabled = value; strbuf_reset(&var); } diff --git a/http-fetch.c b/http-fetch.c index 02ab80533f..1922e23fcd 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -2,6 +2,7 @@ #include "git-compat-util.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "http.h" @@ -150,7 +151,7 @@ int cmd_main(int argc, const char **argv) trace2_cmd_name("http-fetch"); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); if (packfile) { if (!index_pack_args.nr) @@ -3,6 +3,7 @@ #include "git-compat-util.h" #include "git-curl-compat.h" +#include "environment.h" #include "hex.h" #include "http.h" #include "config.h" @@ -1315,7 +1316,7 @@ void http_init(struct remote *remote, const char *url, int proactive_auth) http_is_verbose = 0; normalized_url = url_normalize(url, &config.url); - git_config(urlmatch_config_entry, &config); + repo_config(the_repository, urlmatch_config_entry, &config); free(normalized_url); string_list_clear(&config.vars, 1); diff --git a/imap-send.c b/imap-send.c index f5a656ac71..254ec83ab7 100644 --- a/imap-send.c +++ b/imap-send.c @@ -28,6 +28,7 @@ #include "advice.h" #include "config.h" #include "credential.h" +#include "environment.h" #include "gettext.h" #include "run-command.h" #include "parse-options.h" @@ -1776,7 +1777,7 @@ int cmd_main(int argc, const char **argv) int ret; setup_git_directory_gently(&nongit_ok); - git_config(git_imap_config, &server); + repo_config(the_repository, git_imap_config, &server); argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0); diff --git a/line-log.c b/line-log.c index 628e3fe3ae..07f2154e84 100644 --- a/line-log.c +++ b/line-log.c @@ -1172,12 +1172,13 @@ static int bloom_filter_check(struct rev_info *rev, return 0; while (!result && range) { - fill_bloom_key(range->path, strlen(range->path), &key, rev->bloom_filter_settings); + bloom_key_fill(&key, range->path, strlen(range->path), + rev->bloom_filter_settings); if (bloom_filter_contains(filter, &key, rev->bloom_filter_settings)) result = 1; - clear_bloom_key(&key); + bloom_key_clear(&key); range = range->next; } diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c index 948376d42d..7420bf81fe 100644 --- a/list-objects-filter-options.c +++ b/list-objects-filter-options.c @@ -350,7 +350,7 @@ void partial_clone_register( /* Add promisor config for the remote */ cfg_name = xstrfmt("remote.%s.promisor", remote); - git_config_set(cfg_name, "true"); + repo_config_set(the_repository, cfg_name, "true"); free(cfg_name); } @@ -360,8 +360,8 @@ void partial_clone_register( */ filter_name = xstrfmt("remote.%s.partialclonefilter", remote); /* NEEDSWORK: 'expand' result leaking??? */ - git_config_set(filter_name, - expand_list_objects_filter_spec(filter_options)); + repo_config_set(the_repository, filter_name, + expand_list_objects_filter_spec(filter_options)); free(filter_name); /* Make sure the config info are reset */ @@ -159,7 +159,7 @@ int ls_refs(struct repository *r, struct packet_reader *request) strbuf_init(&data.buf, 0); strvec_init(&data.hidden_refs); - git_config(ls_refs_config, &data); + repo_config(the_repository, ls_refs_config, &data); while (packet_reader_read(request) == PACKET_READ_NORMAL) { const char *arg = request->line; diff --git a/mailinfo.c b/mailinfo.c index b4e815b2d8..99ac596e09 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -2,6 +2,7 @@ #include "git-compat-util.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "hex-ll.h" #include "utf8.h" diff --git a/merge-ll.c b/merge-ll.c index b2dc26da4f..fafe2c9197 100644 --- a/merge-ll.c +++ b/merge-ll.c @@ -357,7 +357,7 @@ static void initialize_ll_merge(void) if (ll_user_merge_tail) return; ll_user_merge_tail = &ll_user_merge; - git_config(read_merge_config, NULL); + repo_config(the_repository, read_merge_config, NULL); } static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr) diff --git a/merge-ort.c b/merge-ort.c index 535ef3efc6..cd0cb4d1f0 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -5354,20 +5354,20 @@ static void merge_recursive_config(struct merge_options *opt, int ui) { char *value = NULL; int renormalize = 0; - git_config_get_int("merge.verbosity", &opt->verbosity); - git_config_get_int("diff.renamelimit", &opt->rename_limit); - git_config_get_int("merge.renamelimit", &opt->rename_limit); - git_config_get_bool("merge.renormalize", &renormalize); + repo_config_get_int(the_repository, "merge.verbosity", &opt->verbosity); + repo_config_get_int(the_repository, "diff.renamelimit", &opt->rename_limit); + repo_config_get_int(the_repository, "merge.renamelimit", &opt->rename_limit); + repo_config_get_bool(the_repository, "merge.renormalize", &renormalize); opt->renormalize = renormalize; - if (!git_config_get_string("diff.renames", &value)) { + if (!repo_config_get_string(the_repository, "diff.renames", &value)) { opt->detect_renames = git_config_rename("diff.renames", value); free(value); } - if (!git_config_get_string("merge.renames", &value)) { + if (!repo_config_get_string(the_repository, "merge.renames", &value)) { opt->detect_renames = git_config_rename("merge.renames", value); free(value); } - if (!git_config_get_string("merge.directoryrenames", &value)) { + if (!repo_config_get_string(the_repository, "merge.directoryrenames", &value)) { int boolval = git_parse_maybe_bool(value); if (0 <= boolval) { opt->detect_directory_renames = boolval ? @@ -5380,7 +5380,7 @@ static void merge_recursive_config(struct merge_options *opt, int ui) free(value); } if (ui) { - if (!git_config_get_string("diff.algorithm", &value)) { + if (!repo_config_get_string(the_repository, "diff.algorithm", &value)) { long diff_algorithm = parse_algorithm_value(value); if (diff_algorithm < 0) die(_("unknown value for config '%s': %s"), "diff.algorithm", value); @@ -5388,7 +5388,7 @@ static void merge_recursive_config(struct merge_options *opt, int ui) free(value); } } - git_config(git_xmerge_config, NULL); + repo_config(the_repository, git_xmerge_config, NULL); } static void init_merge_options(struct merge_options *opt, diff --git a/meson.build b/meson.build index 738e89feec..5dd299b496 100644 --- a/meson.build +++ b/meson.build @@ -245,7 +245,7 @@ time = find_program('time', dirs: program_path, required: get_option('benchmarks # "/bin/sh" over a PATH-based lookup, which provides a working shell on most # supported systems. This path is also the default shell path used by our # Makefile. This lookup can be overridden via `program_path`. -target_shell = find_program('sh', dirs: program_path + [ '/bin' ], native: false) +target_shell = find_program('/bin/sh', 'sh', dirs: program_path, native: false) # Sanity-check that programs required for the build exist. foreach tool : ['cat', 'cut', 'grep', 'sort', 'tr', 'uname'] @@ -694,9 +694,14 @@ third_party_excludes = [ headers_to_check = [] if git.found() and fs.exists(meson.project_source_root() / '.git') - foreach header : run_command(git, '-C', meson.project_source_root(), 'ls-files', '--deduplicate', '*.h', third_party_excludes, check: true).stdout().split() - headers_to_check += header - endforeach + ls_headers = run_command(git, '-C', meson.project_source_root(), 'ls-files', '--deduplicate', '*.h', third_party_excludes, check: false) + if ls_headers.returncode() == 0 + foreach header : ls_headers.stdout().split() + headers_to_check += header + endforeach + else + warning('could not list headers, disabling static analysis targets') + endif endif if not get_option('breaking_changes') @@ -866,9 +871,11 @@ if host_machine.system() == 'cygwin' or host_machine.system() == 'windows' endif build_options_config.set_quoted('X', executable_suffix) -python = import('python').find_installation('python3', required: get_option('python')) -target_python = find_program('python3', native: false, required: python.found()) -if python.found() +# Python is not used for our build system, but exclusively for git-p4. +# Consequently we only need to determine whether Python is available for the +# build target. +target_python = find_program('python3', native: false, required: get_option('python')) +if target_python.found() build_options_config.set('NO_PYTHON', '') else libgit_c_args += '-DNO_PYTHON' @@ -1055,7 +1062,33 @@ else build_options_config.set('NO_ICONV', '1') endif -pcre2 = dependency('libpcre2-8', required: get_option('pcre2'), default_options: ['default_library=static', 'test=false']) +# can't use enable_auto_if() because it is only available in meson 1.1 +if host_machine.system() == 'windows' and get_option('pcre2').allowed() + pcre2_feature = true +else + pcre2_feature = get_option('pcre2') +endif +pcre2 = dependency('libpcre2-8', required: pcre2_feature, default_options: ['default_library=static', 'test=false']) +if pcre2.found() and pcre2.type_name() != 'internal' and host_machine.system() == 'darwin' + # macOS installs a broken system package, double check + if not compiler.has_header('pcre2.h', dependencies: pcre2) + if pcre2_feature.enabled() + pcre2_fallback = ['pcre2', 'libpcre2_8'] + else + pcre2_fallback = [] + endif + # Attempt to fallback or replace with not-found-dependency + pcre2 = dependency('', required: false, fallback: pcre2_fallback, default_options: ['default_library=static', 'test=false']) + if not pcre2.found() + if pcre2_feature.enabled() + error('only a broken pcre2 install found and pcre2 is required') + else + warning('broken pcre2 install found, disabling pcre2 feature') + endif + endif + endif +endif + if pcre2.found() libgit_dependencies += pcre2 libgit_c_args += '-DUSE_LIBPCRE2' @@ -1331,10 +1364,6 @@ if host_machine.system() != 'windows' endif endif -if compiler.has_member('struct sysinfo', 'totalram', prefix: '#include <sys/sysinfo.h>') - libgit_c_args += '-DHAVE_SYSINFO' -endif - if compiler.has_member('struct stat', 'st_mtimespec.tv_nsec', prefix: '#include <sys/stat.h>') libgit_c_args += '-DUSE_ST_TIMESPEC' elif not compiler.has_member('struct stat', 'st_mtim.tv_nsec', prefix: '#include <sys/stat.h>') @@ -1420,17 +1449,6 @@ if compiler.compiles(''' libgit_c_args += '-DHAVE_CLOCK_MONOTONIC' endif -if not compiler.compiles(''' - #include <inttypes.h> - - void func(void) - { - uintmax_t x = 0; - } -''', name: 'uintmax_t') - libgit_c_args += '-DNO_UINTMAX_T' -endif - has_bsd_sysctl = false if compiler.has_header('sys/sysctl.h') if compiler.compiles(''' @@ -1449,6 +1467,12 @@ if compiler.has_header('sys/sysctl.h') endif endif +if not has_bsd_sysctl + if compiler.has_member('struct sysinfo', 'totalram', prefix: '#include <sys/sysinfo.h>') + libgit_c_args += '-DHAVE_SYSINFO' + endif +endif + if not meson.is_cross_build() and compiler.run(''' #include <stdio.h> @@ -1744,7 +1768,7 @@ git_builtin = executable('git', sources: builtin_sources + 'git.c', dependencies: [libgit_commonmain], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) bin_wrappers += git_builtin @@ -1752,35 +1776,35 @@ test_dependencies += executable('git-daemon', sources: 'daemon.c', dependencies: [libgit_commonmain], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) test_dependencies += executable('git-sh-i18n--envsubst', sources: 'sh-i18n--envsubst.c', dependencies: [libgit_commonmain], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) bin_wrappers += executable('git-shell', sources: 'shell.c', dependencies: [libgit_commonmain], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) test_dependencies += executable('git-http-backend', sources: 'http-backend.c', dependencies: [libgit_commonmain], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) bin_wrappers += executable('scalar', sources: 'scalar.c', dependencies: [libgit_commonmain], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) if curl.found() @@ -1796,14 +1820,14 @@ if curl.found() sources: 'remote-curl.c', dependencies: [libgit_curl], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) test_dependencies += executable('git-http-fetch', sources: 'http-fetch.c', dependencies: [libgit_curl], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) if expat.found() @@ -1811,7 +1835,7 @@ if curl.found() sources: 'http-push.c', dependencies: [libgit_curl], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) endif @@ -1822,7 +1846,7 @@ if curl.found() ) install_symlink(alias + executable_suffix, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, pointing_to: 'git-remote-http', ) endforeach @@ -1832,7 +1856,7 @@ test_dependencies += executable('git-imap-send', sources: 'imap-send.c', dependencies: [ use_curl_for_imap_send ? libgit_curl : libgit_commonmain ], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) foreach alias : [ 'git-receive-pack', 'git-upload-archive', 'git-upload-pack' ] @@ -1842,7 +1866,7 @@ foreach alias : [ 'git-receive-pack', 'git-upload-archive', 'git-upload-pack' ] ) install_symlink(alias + executable_suffix, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, pointing_to: 'git', ) endforeach @@ -1856,9 +1880,9 @@ foreach symlink : [ 'scalar', ] if meson.version().version_compare('>=1.3.0') - pointing_to = fs.relative_to(get_option('libexecdir') / 'git-core' / symlink, get_option('bindir')) + pointing_to = fs.relative_to(git_exec_path / symlink, get_option('bindir')) else - pointing_to = '../libexec/git-core' / symlink + pointing_to = '..' / git_exec_path / symlink endif install_symlink(symlink, @@ -1898,7 +1922,7 @@ foreach script : scripts_sh meson.project_build_root() / 'GIT-BUILD-OPTIONS', ], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) endforeach @@ -1931,7 +1955,7 @@ if perl_features_enabled input: perl_header_template, output: 'GIT-PERL-HEADER', configuration: { - 'GITEXECDIR_REL': get_option('libexecdir') / 'git-core', + 'GITEXECDIR_REL': git_exec_path, 'PERLLIBDIR_REL': perllibdir, 'LOCALEDIR_REL': get_option('datadir') / 'locale', 'INSTLIBDIR': perllibdir, @@ -1955,7 +1979,7 @@ if perl_features_enabled output: fs.stem(script), command: generate_perl_command, install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, depends: [git_version_file], ) test_dependencies += generated_script @@ -1964,9 +1988,9 @@ if perl_features_enabled bin_wrappers += generated_script if meson.version().version_compare('>=1.3.0') - pointing_to = fs.relative_to(get_option('libexecdir') / 'git-core' / fs.stem(script), get_option('bindir')) + pointing_to = fs.relative_to(git_exec_path / fs.stem(script), get_option('bindir')) else - pointing_to = '../libexec/git-core' / fs.stem(script) + pointing_to = '..' / git_exec_path / fs.stem(script) endif install_symlink(fs.stem(script), @@ -1979,7 +2003,7 @@ if perl_features_enabled subdir('perl') endif -if python.found() +if target_python.found() scripts_python = [ 'git-p4.py' ] @@ -1996,7 +2020,7 @@ if python.found() '@OUTPUT@', ], install: true, - install_dir: get_option('libexecdir') / 'git-core', + install_dir: git_exec_path, ) test_dependencies += generated_python endforeach @@ -2030,7 +2054,7 @@ mergetools = [ ] foreach mergetool : mergetools - install_data(mergetool, install_dir: get_option('libexecdir') / 'git-core' / 'mergetools') + install_data(mergetool, install_dir: git_exec_path / 'mergetools') endforeach if intl.found() @@ -2144,6 +2168,18 @@ if headers_to_check.length() != 0 and compiler.get_argument_syntax() == 'gcc' alias_target('check-headers', hdr_check) endif +git_clang_format = find_program('git-clang-format', required: false, native: true) +if git_clang_format.found() + run_target('style', + command: [ + git_clang_format, + '--style', 'file', + '--diff', + '--extensions', 'c,h' + ] + ) +endif + foreach key, value : { 'DIFF': diff.full_path(), 'GIT_SOURCE_DIR': meson.project_source_root(), @@ -2194,16 +2230,15 @@ meson.add_dist_script( summary({ 'benchmarks': get_option('tests') and perl.found() and time.found(), - 'curl': curl.found(), - 'expat': expat.found(), - 'gettext': intl.found(), + 'curl': curl, + 'expat': expat, + 'gettext': intl, 'gitweb': gitweb_option.allowed(), - 'https': https_backend, - 'iconv': iconv.found(), - 'pcre2': pcre2.found(), + 'iconv': iconv, + 'pcre2': pcre2, 'perl': perl_features_enabled, - 'python': python.found(), -}, section: 'Auto-detected features') + 'python': target_python.found(), +}, section: 'Auto-detected features', bool_yn: true) summary({ 'csprng': csprng_backend, diff --git a/meson_options.txt b/meson_options.txt index e7f768df24..1668f260a1 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -45,7 +45,7 @@ option('gitweb', type: 'feature', value: 'auto', description: 'Build Git web interface. Requires Perl.') option('iconv', type: 'feature', value: 'auto', description: 'Support reencoding strings with different encodings.') -option('pcre2', type: 'feature', value: 'enabled', +option('pcre2', type: 'feature', value: 'auto', description: 'Support Perl-compatible regular expressions in e.g. git-grep(1).') option('perl', type: 'feature', value: 'auto', description: 'Build tools written in Perl.') diff --git a/midx-write.c b/midx-write.c index effacade2d..a0aceab5e0 100644 --- a/midx-write.c +++ b/midx-write.c @@ -916,26 +916,8 @@ cleanup: static struct multi_pack_index *lookup_multi_pack_index(struct repository *r, const char *object_dir) { - struct multi_pack_index *result = NULL; - struct multi_pack_index *cur; - char *obj_dir_real = real_pathdup(object_dir, 1); - struct strbuf cur_path_real = STRBUF_INIT; - - /* Ensure the given object_dir is local, or a known alternate. */ - odb_find_source(r->objects, obj_dir_real); - - for (cur = get_multi_pack_index(r); cur; cur = cur->next) { - strbuf_realpath(&cur_path_real, cur->object_dir, 1); - if (!strcmp(obj_dir_real, cur_path_real.buf)) { - result = cur; - goto cleanup; - } - } - -cleanup: - free(obj_dir_real); - strbuf_release(&cur_path_real); - return result; + 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, @@ -401,7 +401,6 @@ void close_midx(struct multi_pack_index *m) if (!m) return; - close_midx(m->next); close_midx(m->base_midx); munmap((unsigned char *)m->data, m->data_len); @@ -724,32 +723,20 @@ int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id) return 0; } -int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, int local) +int prepare_multi_pack_index_one(struct odb_source *source, int local) { - struct multi_pack_index *m; - struct multi_pack_index *m_search; + struct repository *r = source->odb->repo; prepare_repo_settings(r); if (!r->settings.core_multi_pack_index) return 0; - for (m_search = r->objects->multi_pack_index; m_search; m_search = m_search->next) - if (!strcmp(object_dir, m_search->object_dir)) - return 1; - - m = load_multi_pack_index(r, object_dir, local); - - if (m) { - struct multi_pack_index *mp = r->objects->multi_pack_index; - if (mp) { - m->next = mp->next; - mp->next = m; - } else - r->objects->multi_pack_index = m; + if (source->midx) return 1; - } - return 0; + source->midx = load_multi_pack_index(r, source->path, local); + + return !!source->midx; } int midx_checksum_valid(struct multi_pack_index *m) @@ -834,9 +821,14 @@ void clear_midx_file(struct repository *r) get_midx_filename(r->hash_algo, &midx, r->objects->sources->path); - if (r->objects && r->objects->multi_pack_index) { - close_midx(r->objects->multi_pack_index); - r->objects->multi_pack_index = NULL; + if (r->objects) { + struct odb_source *source; + + for (source = r->objects->sources; source; source = source->next) { + if (source->midx) + close_midx(source->midx); + source->midx = NULL; + } } if (remove_path(midx.buf)) @@ -8,6 +8,7 @@ struct pack_entry; struct repository; struct bitmapped_pack; struct git_hash_algo; +struct odb_source; #define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */ #define MIDX_VERSION 1 @@ -34,8 +35,6 @@ struct git_hash_algo; "GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL" struct multi_pack_index { - struct multi_pack_index *next; - const unsigned char *data; size_t data_len; @@ -123,7 +122,7 @@ int fill_midx_entry(struct repository *r, const struct object_id *oid, struct pa 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 repository *r, const char *object_dir, int local); +int prepare_multi_pack_index_one(struct odb_source *source, int local); /* * Variant of write_midx_file which writes a MIDX containing only the packs diff --git a/notes-utils.c b/notes-utils.c index ac66b82dd3..6a50c6d564 100644 --- a/notes-utils.c +++ b/notes-utils.c @@ -162,7 +162,7 @@ struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd) c->refs_from_env = 1; string_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env); } - git_config(notes_rewrite_config, c); + repo_config(the_repository, notes_rewrite_config, c); if (!c->enabled || !c->refs->nr) { string_list_clear(c->refs, 0); free(c->refs); @@ -1126,7 +1126,7 @@ void load_display_notes(struct display_notes_opt *opt) load_config_refs = 1; } - git_config(notes_display_config, &load_config_refs); + repo_config(the_repository, notes_display_config, &load_config_refs); if (opt) { struct string_list_item *item; diff --git a/object-name.c b/object-name.c index ddafe7f9b1..11aa0e6afc 100644 --- a/object-name.c +++ b/object-name.c @@ -28,6 +28,7 @@ #include "commit-reach.h" #include "date.h" #include "object-file-convert.h" +#include "prio-queue.h" static int get_oid_oneline(struct repository *r, const char *, struct object_id *, const struct commit_list *); @@ -198,16 +199,20 @@ static void unique_in_pack(struct packed_git *p, static void find_short_packed_object(struct disambiguate_state *ds) { - struct multi_pack_index *m; + struct odb_source *source; struct packed_git *p; /* Skip, unless oids from the storage hash algorithm are wanted */ if (ds->bin_pfx.algo && (&hash_algos[ds->bin_pfx.algo] != ds->repo->hash_algo)) return; - for (m = get_multi_pack_index(ds->repo); m && !ds->ambiguous; - m = m->next) - unique_in_midx(m, ds); + odb_prepare_alternates(ds->repo->objects); + for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next) { + struct multi_pack_index *m = get_multi_pack_index(source); + if (m) + unique_in_midx(m, ds); + } + for (p = get_packed_git(ds->repo); p && !ds->ambiguous; p = p->next) unique_in_pack(p, ds); @@ -792,11 +797,15 @@ static void find_abbrev_len_for_pack(struct packed_git *p, static void find_abbrev_len_packed(struct min_abbrev_data *mad) { - struct multi_pack_index *m; struct packed_git *p; - for (m = get_multi_pack_index(mad->repo); m; m = m->next) - find_abbrev_len_for_midx(m, mad); + odb_prepare_alternates(mad->repo->objects); + for (struct odb_source *source = mad->repo->objects->sources; source; source = source->next) { + struct multi_pack_index *m = get_multi_pack_index(source); + if (m) + find_abbrev_len_for_midx(m, mad); + } + for (p = get_packed_git(mad->repo); p; p = p->next) find_abbrev_len_for_pack(p, mad); } @@ -1461,7 +1470,7 @@ static int get_oid_oneline(struct repository *r, const char *prefix, struct object_id *oid, const struct commit_list *list) { - struct commit_list *copy = NULL, **copy_tail = © + struct prio_queue copy = { compare_commits_by_commit_date }; const struct commit_list *l; int found = 0; int negative = 0; @@ -1483,9 +1492,9 @@ static int get_oid_oneline(struct repository *r, for (l = list; l; l = l->next) { l->item->object.flags |= ONELINE_SEEN; - copy_tail = &commit_list_insert(l->item, copy_tail)->next; + prio_queue_put(©, l->item); } - while (copy) { + while (copy.nr) { const char *p, *buf; struct commit *commit; int matches; @@ -1507,7 +1516,7 @@ static int get_oid_oneline(struct repository *r, regfree(®ex); for (l = list; l; l = l->next) clear_commit_marks(l->item, ONELINE_SEEN); - free_commit_list(copy); + clear_prio_queue(©); return found ? 0 : -1; } @@ -2061,7 +2070,6 @@ static enum get_oid_result get_oid_with_context_1(struct repository *repo, cb.list = &list; refs_for_each_ref(get_main_ref_store(repo), handle_one_ref, &cb); refs_head_ref(get_main_ref_store(repo), handle_one_ref, &cb); - commit_list_sort_by_date(&list); ret = get_oid_oneline(repo, name + 2, oid, list); free_commit_list(list); @@ -13,6 +13,7 @@ struct oidmap; struct oidtree; struct strbuf; struct repository; +struct multi_pack_index; /* * Compute the exact path an alternate is at and returns it. In case of @@ -56,6 +57,13 @@ struct odb_source { struct loose_object_map *loose_map; /* + * private data + * + * should only be accessed directly by packfile.c and midx.c + */ + struct multi_pack_index *midx; + + /* * 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. @@ -75,7 +83,6 @@ struct odb_source { }; struct packed_git; -struct multi_pack_index; struct cached_object_entry; /* @@ -119,13 +126,6 @@ struct object_database { /* * private data * - * should only be accessed directly by packfile.c and midx.c - */ - struct multi_pack_index *multi_pack_index; - - /* - * private data - * * should only be accessed directly by packfile.c */ diff --git a/pack-bitmap.c b/pack-bitmap.c index 0a4af199c0..d14421ee20 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -31,6 +31,7 @@ struct stored_bitmap { struct object_id oid; struct ewah_bitmap *root; struct stored_bitmap *xor; + size_t map_pos; int flags; }; @@ -314,13 +315,14 @@ static struct stored_bitmap *store_bitmap(struct bitmap_index *index, struct ewah_bitmap *root, const struct object_id *oid, struct stored_bitmap *xor_with, - int flags) + int flags, size_t map_pos) { struct stored_bitmap *stored; khiter_t hash_pos; int ret; stored = xmalloc(sizeof(struct stored_bitmap)); + stored->map_pos = map_pos; stored->root = root; stored->xor = xor_with; stored->flags = flags; @@ -376,10 +378,12 @@ static int load_bitmap_entries_v1(struct bitmap_index *index) struct stored_bitmap *xor_bitmap = NULL; uint32_t commit_idx_pos; struct object_id oid; + size_t entry_map_pos; if (index->map_size - index->map_pos < 6) return error(_("corrupt ewah bitmap: truncated header for entry %d"), i); + entry_map_pos = index->map_pos; commit_idx_pos = read_be32(index->map, &index->map_pos); xor_offset = read_u8(index->map, &index->map_pos); flags = read_u8(index->map, &index->map_pos); @@ -402,8 +406,9 @@ static int load_bitmap_entries_v1(struct bitmap_index *index) if (!bitmap) return -1; - recent_bitmaps[i % MAX_XOR_OFFSET] = store_bitmap( - index, bitmap, &oid, xor_bitmap, flags); + recent_bitmaps[i % MAX_XOR_OFFSET] = + store_bitmap(index, bitmap, &oid, xor_bitmap, flags, + entry_map_pos); } return 0; @@ -630,41 +635,28 @@ static int load_bitmap(struct repository *r, struct bitmap_index *bitmap_git, bitmap_git->ext_index.positions = kh_init_oid_pos(); if (load_reverse_index(r, bitmap_git)) - goto failed; + return -1; if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) || !(bitmap_git->trees = read_bitmap_1(bitmap_git)) || !(bitmap_git->blobs = read_bitmap_1(bitmap_git)) || !(bitmap_git->tags = read_bitmap_1(bitmap_git))) - goto failed; + return -1; if (!bitmap_git->table_lookup && load_bitmap_entries_v1(bitmap_git) < 0) - goto failed; + return -1; if (bitmap_git->base) { if (!bitmap_is_midx(bitmap_git)) BUG("non-MIDX bitmap has non-NULL base bitmap index"); if (load_bitmap(r, bitmap_git->base, 1) < 0) - goto failed; + return -1; } if (!recursing) load_all_type_bitmaps(bitmap_git); return 0; - -failed: - munmap(bitmap_git->map, bitmap_git->map_size); - bitmap_git->map = NULL; - bitmap_git->map_size = 0; - - kh_destroy_oid_map(bitmap_git->bitmaps); - bitmap_git->bitmaps = NULL; - - kh_destroy_oid_pos(bitmap_git->ext_index.positions); - bitmap_git->ext_index.positions = NULL; - - return -1; } static int open_pack_bitmap(struct repository *r, @@ -691,13 +683,15 @@ static int open_pack_bitmap(struct repository *r, static int open_midx_bitmap(struct repository *r, struct bitmap_index *bitmap_git) { + struct odb_source *source; int ret = -1; - struct multi_pack_index *midx; assert(!bitmap_git->map); - for (midx = get_multi_pack_index(r); midx; midx = midx->next) { - if (!open_midx_bitmap_1(bitmap_git, midx)) + odb_prepare_alternates(r->objects); + for (source = r->objects->sources; source; source = source->next) { + struct multi_pack_index *midx = get_multi_pack_index(source); + if (midx && !open_midx_bitmap_1(bitmap_git, midx)) ret = 0; } return ret; @@ -882,6 +876,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ int xor_flags; khiter_t hash_pos; struct bitmap_lookup_table_xor_item *xor_item; + size_t entry_map_pos; if (is_corrupt) return NULL; @@ -941,6 +936,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ goto corrupt; } + entry_map_pos = bitmap_git->map_pos; bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t); xor_flags = read_u8(bitmap_git->map, &bitmap_git->map_pos); bitmap = read_bitmap_1(bitmap_git); @@ -948,7 +944,8 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ if (!bitmap) goto corrupt; - xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, xor_bitmap, xor_flags); + xor_bitmap = store_bitmap(bitmap_git, bitmap, &xor_item->oid, + xor_bitmap, xor_flags, entry_map_pos); xor_items_nr--; } @@ -982,6 +979,7 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ * Instead, we can skip ahead and immediately read the flags and * ewah bitmap. */ + entry_map_pos = bitmap_git->map_pos; bitmap_git->map_pos += sizeof(uint32_t) + sizeof(uint8_t); flags = read_u8(bitmap_git->map, &bitmap_git->map_pos); bitmap = read_bitmap_1(bitmap_git); @@ -989,7 +987,8 @@ static struct stored_bitmap *lazy_bitmap_for_commit(struct bitmap_index *bitmap_ if (!bitmap) goto corrupt; - return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags); + return store_bitmap(bitmap_git, bitmap, oid, xor_bitmap, flags, + entry_map_pos); corrupt: free(xor_items); @@ -2852,8 +2851,9 @@ int test_bitmap_commits(struct repository *r) die(_("failed to load bitmap indexes")); /* - * As this function is only used to print bitmap selected - * commits, we don't have to read the commit table. + * Since this function needs to print the bitmapped + * commits, bypass the commit lookup table (if one exists) + * by forcing the bitmap to eagerly load its entries. */ if (bitmap_git->table_lookup) { if (load_bitmap_entries_v1(bitmap_git) < 0) @@ -2869,6 +2869,48 @@ int test_bitmap_commits(struct repository *r) return 0; } +int test_bitmap_commits_with_offset(struct repository *r) +{ + struct object_id oid; + struct stored_bitmap *stored; + struct bitmap_index *bitmap_git; + size_t commit_idx_pos_map_pos, xor_offset_map_pos, flag_map_pos, + ewah_bitmap_map_pos; + + bitmap_git = prepare_bitmap_git(r); + if (!bitmap_git) + die(_("failed to load bitmap indexes")); + + /* + * Since this function needs to know the position of each individual + * bitmap, bypass the commit lookup table (if one exists) by forcing + * the bitmap to eagerly load its entries. + */ + if (bitmap_git->table_lookup) { + if (load_bitmap_entries_v1(bitmap_git) < 0) + die(_("failed to load bitmap indexes")); + } + + kh_foreach (bitmap_git->bitmaps, oid, stored, { + commit_idx_pos_map_pos = stored->map_pos; + xor_offset_map_pos = stored->map_pos + sizeof(uint32_t); + flag_map_pos = xor_offset_map_pos + sizeof(uint8_t); + ewah_bitmap_map_pos = flag_map_pos + sizeof(uint8_t); + + printf_ln("%s %"PRIuMAX" %"PRIuMAX" %"PRIuMAX" %"PRIuMAX, + oid_to_hex(&oid), + (uintmax_t)commit_idx_pos_map_pos, + (uintmax_t)xor_offset_map_pos, + (uintmax_t)flag_map_pos, + (uintmax_t)ewah_bitmap_map_pos); + }) + ; + + free_bitmap_index(bitmap_git); + + return 0; +} + int test_bitmap_hashes(struct repository *r) { struct bitmap_index *bitmap_git = prepare_bitmap_git(r); @@ -3305,11 +3347,18 @@ static int verify_bitmap_file(const struct git_hash_algo *algop, int verify_bitmap_files(struct repository *r) { + struct odb_source *source; int res = 0; - for (struct multi_pack_index *m = get_multi_pack_index(r); - m; m = m->next) { - char *midx_bitmap_name = midx_bitmap_filename(m); + odb_prepare_alternates(r->objects); + for (source = r->objects->sources; source; source = source->next) { + struct multi_pack_index *m = get_multi_pack_index(source); + char *midx_bitmap_name; + + if (!m) + continue; + + midx_bitmap_name = midx_bitmap_filename(m); res |= verify_bitmap_file(r->hash_algo, midx_bitmap_name); free(midx_bitmap_name); } diff --git a/pack-bitmap.h b/pack-bitmap.h index 382d39499a..1bd7a791e2 100644 --- a/pack-bitmap.h +++ b/pack-bitmap.h @@ -81,6 +81,7 @@ void traverse_bitmap_commit_list(struct bitmap_index *, show_reachable_fn show_reachable); void test_bitmap_walk(struct rev_info *revs); int test_bitmap_commits(struct repository *r); +int test_bitmap_commits_with_offset(struct repository *r); int test_bitmap_hashes(struct repository *r); int test_bitmap_pseudo_merges(struct repository *r); int test_bitmap_pseudo_merge_commits(struct repository *r, uint32_t n); diff --git a/packfile.c b/packfile.c index af9ccfdba6..5d73932f50 100644 --- a/packfile.c +++ b/packfile.c @@ -361,6 +361,7 @@ void close_pack(struct packed_git *p) void close_object_store(struct object_database *o) { + struct odb_source *source; struct packed_git *p; for (p = o->packed_git; p; p = p->next) @@ -369,9 +370,10 @@ void close_object_store(struct object_database *o) else close_pack(p); - if (o->multi_pack_index) { - close_midx(o->multi_pack_index); - o->multi_pack_index = NULL; + for (source = o->sources; source; source = source->next) { + if (source->midx) + close_midx(source->midx); + source->midx = NULL; } close_commit_graph(o); @@ -933,22 +935,17 @@ 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 repository *r, char *objdir, int local) +static void prepare_packed_git_one(struct odb_source *source, int local) { - struct prepare_pack_data data; struct string_list garbage = STRING_LIST_INIT_DUP; + struct prepare_pack_data data = { + .m = source->midx, + .r = source->odb->repo, + .garbage = &garbage, + .local = local, + }; - data.m = r->objects->multi_pack_index; - - /* look for the multi-pack-index for this object directory */ - while (data.m && strcmp(data.m->object_dir, objdir)) - data.m = data.m->next; - - data.r = r; - data.garbage = &garbage; - data.local = local; - - for_each_file_in_pack_dir(objdir, prepare_pack, &data); + for_each_file_in_pack_dir(source->path, prepare_pack, &data); report_pack_garbage(data.garbage); string_list_clear(data.garbage, 0); @@ -965,14 +962,18 @@ static void prepare_packed_git(struct repository *r); unsigned long repo_approximate_object_count(struct repository *r) { if (!r->objects->approximate_object_count_valid) { - unsigned long count; - struct multi_pack_index *m; + struct odb_source *source; + unsigned long count = 0; struct packed_git *p; prepare_packed_git(r); - count = 0; - for (m = get_multi_pack_index(r); m; m = m->next) - count += m->num_objects; + + for (source = r->objects->sources; source; source = source->next) { + struct multi_pack_index *m = get_multi_pack_index(source); + if (m) + count += m->num_objects; + } + for (p = r->objects->packed_git; p; p = p->next) { if (open_pack_index(p)) continue; @@ -1037,8 +1038,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(r, source->path, local); - prepare_packed_git_one(r, source->path, local); + prepare_multi_pack_index_one(source, local); + prepare_packed_git_one(source, local); } rearrange_packed_git(r); @@ -1076,31 +1077,21 @@ struct packed_git *get_packed_git(struct repository *r) return r->objects->packed_git; } -struct multi_pack_index *get_multi_pack_index(struct repository *r) +struct multi_pack_index *get_multi_pack_index(struct odb_source *source) { - prepare_packed_git(r); - return r->objects->multi_pack_index; -} - -struct multi_pack_index *get_local_multi_pack_index(struct repository *r) -{ - struct multi_pack_index *m = get_multi_pack_index(r); - - /* no need to iterate; we always put the local one first (if any) */ - if (m && m->local) - return m; - - return NULL; + prepare_packed_git(source->odb->repo); + return source->midx; } struct packed_git *get_all_packs(struct repository *r) { - struct multi_pack_index *m; - prepare_packed_git(r); - for (m = r->objects->multi_pack_index; m; m = m->next) { - uint32_t i; - for (i = 0; i < m->num_packs + m->num_packs_in_base; i++) + + for (struct odb_source *source = r->objects->sources; source; source = source->next) { + struct multi_pack_index *m = source->midx; + if (!m) + continue; + for (uint32_t i = 0; i < m->num_packs + m->num_packs_in_base; i++) prepare_midx_pack(r, m, i); } @@ -2083,16 +2074,15 @@ static int fill_pack_entry(const struct object_id *oid, int find_pack_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e) { struct list_head *pos; - struct multi_pack_index *m; prepare_packed_git(r); - if (!r->objects->packed_git && !r->objects->multi_pack_index) - return 0; - for (m = r->objects->multi_pack_index; m; m = m->next) { - if (fill_midx_entry(r, oid, e, m)) + for (struct odb_source *source = r->objects->sources; source; source = source->next) + if (source->midx && fill_midx_entry(r, oid, e, source->midx)) return 1; - } + + if (!r->objects->packed_git) + return 0; list_for_each(pos, &r->objects->packed_git_mru) { struct packed_git *p = list_entry(pos, struct packed_git, mru); diff --git a/packfile.h b/packfile.h index 53c3b7d3b4..f16753f2a9 100644 --- a/packfile.h +++ b/packfile.h @@ -147,8 +147,7 @@ void install_packed_git(struct repository *r, struct packed_git *pack); struct packed_git *get_packed_git(struct repository *r); struct list_head *get_packed_git_mru(struct repository *r); -struct multi_pack_index *get_multi_pack_index(struct repository *r); -struct multi_pack_index *get_local_multi_pack_index(struct repository *r); +struct multi_pack_index *get_multi_pack_index(struct odb_source *source); struct packed_git *get_all_packs(struct repository *r); /* diff --git a/parallel-checkout.c b/parallel-checkout.c index 57c2dcaa8f..fba6aa65a6 100644 --- a/parallel-checkout.c +++ b/parallel-checkout.c @@ -57,12 +57,12 @@ void get_parallel_checkout_configs(int *num_workers, int *threshold) return; } - if (git_config_get_int("checkout.workers", num_workers)) + if (repo_config_get_int(the_repository, "checkout.workers", num_workers)) *num_workers = DEFAULT_NUM_WORKERS; else if (*num_workers < 1) *num_workers = online_cpus(); - if (git_config_get_int("checkout.thresholdForParallelism", threshold)) + if (repo_config_get_int(the_repository, "checkout.thresholdForParallelism", threshold)) *threshold = DEFAULT_THRESHOLD_FOR_PARALLELISM; } diff --git a/parse-options.c b/parse-options.c index a9a39ecaef..5224203ffe 100644 --- a/parse-options.c +++ b/parse-options.c @@ -68,6 +68,64 @@ static char *fix_filename(const char *prefix, const char *file) return prefix_filename_except_for_dash(prefix, file); } +static int do_get_int_value(const void *value, size_t precision, intmax_t *ret) +{ + switch (precision) { + case sizeof(int8_t): + *ret = *(int8_t *)value; + return 0; + case sizeof(int16_t): + *ret = *(int16_t *)value; + return 0; + case sizeof(int32_t): + *ret = *(int32_t *)value; + return 0; + case sizeof(int64_t): + *ret = *(int64_t *)value; + return 0; + default: + return -1; + } +} + +static intmax_t get_int_value(const struct option *opt, enum opt_parsed flags) +{ + intmax_t ret; + if (do_get_int_value(opt->value, opt->precision, &ret)) + BUG("invalid precision for option %s", optname(opt, flags)); + return ret; +} + +static enum parse_opt_result set_int_value(const struct option *opt, + enum opt_parsed flags, + intmax_t value) +{ + switch (opt->precision) { + case sizeof(int8_t): + *(int8_t *)opt->value = value; + return 0; + case sizeof(int16_t): + *(int16_t *)opt->value = value; + return 0; + case sizeof(int32_t): + *(int32_t *)opt->value = value; + return 0; + case sizeof(int64_t): + *(int64_t *)opt->value = value; + return 0; + default: + BUG("invalid precision for option %s", optname(opt, flags)); + } +} + +static int signed_int_fits(intmax_t value, size_t precision) +{ + size_t bits = precision * CHAR_BIT; + intmax_t upper_bound = INTMAX_MAX >> (bitsizeof(intmax_t) - bits); + intmax_t lower_bound = -upper_bound - 1; + return lower_bound <= value && value <= upper_bound; +} + static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, const struct option *opt, enum opt_parsed flags, @@ -89,35 +147,55 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, return opt->ll_callback(p, opt, NULL, unset); case OPTION_BIT: + { + intmax_t value = get_int_value(opt, flags); if (unset) - *(int *)opt->value &= ~opt->defval; + value &= ~opt->defval; else - *(int *)opt->value |= opt->defval; - return 0; + value |= opt->defval; + return set_int_value(opt, flags, value); + } case OPTION_NEGBIT: + { + intmax_t value = get_int_value(opt, flags); if (unset) - *(int *)opt->value |= opt->defval; + value |= opt->defval; else - *(int *)opt->value &= ~opt->defval; - return 0; + value &= ~opt->defval; + return set_int_value(opt, flags, value); + } case OPTION_BITOP: + { + intmax_t value = get_int_value(opt, flags); if (unset) BUG("BITOP can't have unset form"); - *(int *)opt->value &= ~opt->extra; - *(int *)opt->value |= opt->defval; - return 0; + value &= ~opt->extra; + value |= opt->defval; + return set_int_value(opt, flags, value); + } case OPTION_COUNTUP: - if (*(int *)opt->value < 0) - *(int *)opt->value = 0; - *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; - return 0; + { + size_t bits = CHAR_BIT * opt->precision; + intmax_t upper_bound = INTMAX_MAX >> (bitsizeof(intmax_t) - bits); + intmax_t value = get_int_value(opt, flags); + + if (value < 0) + value = 0; + if (unset) + value = 0; + else if (value < upper_bound) + value++; + else + return error(_("value for %s exceeds %"PRIdMAX), + optname(opt, flags), upper_bound); + return set_int_value(opt, flags, value); + } case OPTION_SET_INT: - *(int *)opt->value = unset ? 0 : opt->defval; - return 0; + return set_int_value(opt, flags, unset ? 0 : opt->defval); case OPTION_STRING: if (unset) @@ -199,23 +277,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"), arg, optname(opt, flags), (intmax_t)lower_bound, (intmax_t)upper_bound); - switch (opt->precision) { - case 1: - *(int8_t *)opt->value = value; - return 0; - case 2: - *(int16_t *)opt->value = value; - return 0; - case 4: - *(int32_t *)opt->value = value; - return 0; - case 8: - *(int64_t *)opt->value = value; - return 0; - default: - BUG("invalid precision for option %s", - optname(opt, flags)); - } + return set_int_value(opt, flags, value); } case OPTION_UNSIGNED: { @@ -266,7 +328,9 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, } struct parse_opt_cmdmode_list { - int value, *value_ptr; + intmax_t value; + void *value_ptr; + size_t precision; const struct option *opt; const char *arg; enum opt_parsed flags; @@ -280,7 +344,7 @@ static void build_cmdmode_list(struct parse_opt_ctx_t *ctx, for (; opts->type != OPTION_END; opts++) { struct parse_opt_cmdmode_list *elem = ctx->cmdmode_list; - int *value_ptr = opts->value; + void *value_ptr = opts->value; if (!(opts->flags & PARSE_OPT_CMDMODE) || !value_ptr) continue; @@ -292,10 +356,13 @@ static void build_cmdmode_list(struct parse_opt_ctx_t *ctx, CALLOC_ARRAY(elem, 1); elem->value_ptr = value_ptr; - elem->value = *value_ptr; + elem->precision = opts->precision; + if (do_get_int_value(value_ptr, opts->precision, &elem->value)) + optbug(opts, "has invalid precision"); elem->next = ctx->cmdmode_list; ctx->cmdmode_list = elem; } + BUG_if_bug("invalid 'struct option'"); } static char *optnamearg(const struct option *opt, const char *arg, @@ -317,7 +384,13 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p, char *opt_name, *other_opt_name; for (; elem; elem = elem->next) { - if (*elem->value_ptr == elem->value) + intmax_t new_value; + + if (do_get_int_value(elem->value_ptr, elem->precision, + &new_value)) + BUG("impossible: invalid precision"); + + if (new_value == elem->value) continue; if (elem->opt && @@ -327,7 +400,7 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p, elem->opt = opt; elem->arg = arg; elem->flags = flags; - elem->value = *elem->value_ptr; + elem->value = new_value; } if (result || !elem) @@ -586,10 +659,14 @@ static void parse_options_check(const struct option *opts) opts->long_name && !(opts->flags & PARSE_OPT_NONEG)) optbug(opts, "OPTION_SET_INT 0 should not be negatable"); switch (opts->type) { - case OPTION_COUNTUP: + case OPTION_SET_INT: case OPTION_BIT: case OPTION_NEGBIT: - case OPTION_SET_INT: + case OPTION_BITOP: + case OPTION_COUNTUP: + if (!signed_int_fits(opts->defval, opts->precision)) + optbug(opts, "has invalid defval"); + /* fallthru */ case OPTION_NUMBER: if ((opts->flags & PARSE_OPT_OPTARG) || !(opts->flags & PARSE_OPT_NOARG)) diff --git a/parse-options.h b/parse-options.h index 91c3e3c29b..706de9729f 100644 --- a/parse-options.h +++ b/parse-options.h @@ -172,6 +172,7 @@ struct option { .short_name = (s), \ .long_name = (l), \ .value = (v), \ + .precision = sizeof(*v), \ .help = (h), \ .flags = PARSE_OPT_NOARG|(f), \ .callback = NULL, \ @@ -182,6 +183,7 @@ struct option { .short_name = (s), \ .long_name = (l), \ .value = (v), \ + .precision = sizeof(*v), \ .help = (h), \ .flags = PARSE_OPT_NOARG|(f), \ } @@ -190,6 +192,7 @@ struct option { .short_name = (s), \ .long_name = (l), \ .value = (v), \ + .precision = sizeof(*v), \ .help = (h), \ .flags = PARSE_OPT_NOARG | (f), \ .defval = (i), \ @@ -238,6 +241,7 @@ struct option { .short_name = (s), \ .long_name = (l), \ .value = (v), \ + .precision = sizeof(*v), \ .help = (h), \ .flags = PARSE_OPT_NOARG|PARSE_OPT_NONEG, \ .defval = (set), \ @@ -248,6 +252,7 @@ struct option { .short_name = (s), \ .long_name = (l), \ .value = (v), \ + .precision = sizeof(*v), \ .help = (h), \ .flags = PARSE_OPT_NOARG, \ .defval = (b), \ @@ -260,6 +265,7 @@ struct option { .short_name = (s), \ .long_name = (l), \ .value = (v), \ + .precision = sizeof(*v), \ .help = (h), \ .flags = PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, \ .defval = 1, \ @@ -269,6 +275,7 @@ struct option { .short_name = (s), \ .long_name = (l), \ .value = (v), \ + .precision = sizeof(*v), \ .help = (h), \ .flags = PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG | (f), \ .defval = (i), \ @@ -616,6 +623,8 @@ int parse_opt_tracking_mode(const struct option *, const char *, int); #define OPT_PATHSPEC_FROM_FILE(v) OPT_FILENAME(0, "pathspec-from-file", v, N_("read pathspec from file")) #define OPT_PATHSPEC_FILE_NUL(v) OPT_BOOL(0, "pathspec-file-nul", v, N_("with --pathspec-from-file, pathspec elements are separated with NUL character")) #define OPT_AUTOSTASH(v) OPT_BOOL(0, "autostash", v, N_("automatically stash/stash pop before and after")) +#define OPT_DIFF_UNIFIED(v) OPT_INTEGER_F('U', "unified", v, N_("generate diffs with <n> lines context"), PARSE_OPT_NONEG) +#define OPT_DIFF_INTERHUNK_CONTEXT(v) OPT_INTEGER_F(0, "inter-hunk-context", v, N_("show context between diff hunks up to the specified number of lines"), PARSE_OPT_NONEG) #define OPT_IPVERSION(v) \ OPT_SET_INT_F('4', "ipv4", (v), N_("use IPv4 addresses only"), \ diff --git a/perl/Git.pm b/perl/Git.pm index 6f47d653ab..090cf77dab 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -1061,6 +1061,19 @@ sub _close_cat_blob { delete @$self{@vars}; } +# Given PORT, a port number or service name, return its numerical +# value else undef. +sub port_num { + my ($port) = @_; + + # Port can be either a positive integer within the 16-bit range... + if ($port =~ /^\d+$/ && $port > 0 && $port <= (2**16 - 1)) { + return $port; + } + + # ... or a symbolic port (service name). + return scalar getservbyname($port, ''); +} =item credential_read( FILEHANDLE ) diff --git a/pkt-line.c b/pkt-line.c index a5bcbc96fb..fc583feb26 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -617,7 +617,7 @@ void packet_reader_init(struct packet_reader *reader, int fd, reader->buffer_size = sizeof(packet_buffer); reader->options = options; reader->me = "git"; - reader->hash_algo = &hash_algos[GIT_HASH_SHA1]; + reader->hash_algo = &hash_algos[GIT_HASH_SHA1_LEGACY]; strbuf_init(&reader->scratch, 0); } diff --git a/po/meson.build b/po/meson.build index d7154b6395..de3b4e2c38 100644 --- a/po/meson.build +++ b/po/meson.build @@ -8,6 +8,7 @@ translations = i18n.gettext('git', 'el', 'es', 'fr', + 'ga', 'id', 'is', 'it', @@ -141,7 +141,7 @@ static void setup_commit_formats(void) COPY_ARRAY(commit_formats, builtin_formats, ARRAY_SIZE(builtin_formats)); - git_config(git_pretty_formats_config, NULL); + repo_config(the_repository, git_pretty_formats_config, NULL); } static struct cmt_fmt_map *find_commit_format_recursive(const char *sought, diff --git a/prio-queue.c b/prio-queue.c index ec33ac27db..9748528ce6 100644 --- a/prio-queue.c +++ b/prio-queue.c @@ -58,22 +58,10 @@ void prio_queue_put(struct prio_queue *queue, void *thing) } } -void *prio_queue_get(struct prio_queue *queue) +static void sift_down_root(struct prio_queue *queue) { - void *result; size_t ix, child; - if (!queue->nr) - return NULL; - if (!queue->compare) - return queue->array[--queue->nr].data; /* LIFO */ - - result = queue->array[0].data; - if (!--queue->nr) - return result; - - queue->array[0] = queue->array[queue->nr]; - /* Push down the one at the root */ for (ix = 0; ix * 2 + 1 < queue->nr; ix = child) { child = ix * 2 + 1; /* left */ @@ -86,6 +74,23 @@ void *prio_queue_get(struct prio_queue *queue) swap(queue, child, ix); } +} + +void *prio_queue_get(struct prio_queue *queue) +{ + void *result; + + if (!queue->nr) + return NULL; + if (!queue->compare) + return queue->array[--queue->nr].data; /* LIFO */ + + result = queue->array[0].data; + if (!--queue->nr) + return result; + + queue->array[0] = queue->array[queue->nr]; + sift_down_root(queue); return result; } @@ -97,3 +102,17 @@ void *prio_queue_peek(struct prio_queue *queue) return queue->array[queue->nr - 1].data; return queue->array[0].data; } + +void prio_queue_replace(struct prio_queue *queue, void *thing) +{ + if (!queue->nr) { + prio_queue_put(queue, thing); + } else if (!queue->compare) { + queue->array[queue->nr - 1].ctr = queue->insertion_ctr++; + queue->array[queue->nr - 1].data = thing; + } else { + queue->array[0].ctr = queue->insertion_ctr++; + queue->array[0].data = thing; + sift_down_root(queue); + } +} diff --git a/prio-queue.h b/prio-queue.h index 38d032636d..da7fad2f1f 100644 --- a/prio-queue.h +++ b/prio-queue.h @@ -52,6 +52,14 @@ void *prio_queue_get(struct prio_queue *); */ void *prio_queue_peek(struct prio_queue *); +/* + * Replace the "thing" that compares the smallest with a new "thing", + * like prio_queue_get()+prio_queue_put() would do, but in a more + * efficient way. Does the same as prio_queue_put() if the queue is + * empty. + */ +void prio_queue_replace(struct prio_queue *queue, void *thing); + void clear_prio_queue(struct prio_queue *); /* Reverse the LIFO elements */ diff --git a/promisor-remote.c b/promisor-remote.c index be6f82d12f..08b0da8962 100644 --- a/promisor-remote.c +++ b/promisor-remote.c @@ -46,7 +46,7 @@ static int fetch_objects(struct repository *repo, "fetch", remote_name, "--no-tags", "--no-write-fetch-head", "--recurse-submodules=no", "--filter=blob:none", "--stdin", NULL); - if (!git_config_get_bool("promisor.quiet", &quiet) && quiet) + if (!repo_config_get_bool(the_repository, "promisor.quiet", &quiet) && quiet) strvec_push(&child.args, "--quiet"); if (start_command(&child)) die(_("promisor-remote: unable to fork off fetch subprocess")); @@ -327,7 +327,7 @@ static void promisor_info_vecs(struct repository *repo, char *url_key = xstrfmt("remote.%s.url", r->name); /* Only add remotes with a non empty URL */ - if (!git_config_get_string_tmp(url_key, &url) && *url) { + if (!repo_config_get_string_tmp(the_repository, url_key, &url) && *url) { strvec_push(names, r->name); strvec_push(urls, url); } @@ -343,7 +343,7 @@ char *promisor_remote_info(struct repository *repo) struct strvec names = STRVEC_INIT; struct strvec urls = STRVEC_INIT; - git_config_get_bool("promisor.advertise", &advertise_promisors); + repo_config_get_bool(the_repository, "promisor.advertise", &advertise_promisors); if (!advertise_promisors) return NULL; @@ -433,7 +433,7 @@ static void filter_promisor_remote(struct repository *repo, struct strvec names = STRVEC_INIT; struct strvec urls = STRVEC_INIT; - if (!git_config_get_string_tmp("promisor.acceptfromserver", &accept_str)) { + if (!repo_config_get_string_tmp(the_repository, "promisor.acceptfromserver", &accept_str)) { if (!*accept_str || !strcasecmp("None", accept_str)) accept = ACCEPT_NONE; else if (!strcasecmp("KnownUrl", accept_str)) @@ -77,12 +77,6 @@ char *git_prompt(const char *prompt, int flags) int git_read_line_interactively(struct strbuf *line) { - int ret; - fflush(stdout); - ret = strbuf_getline_lf(line, stdin); - if (ret != EOF) - strbuf_trim_trailing_newline(line); - - return ret; + return strbuf_getline(line, stdin); } diff --git a/protocol.c b/protocol.c index bae7226ff4..65f6621702 100644 --- a/protocol.c +++ b/protocol.c @@ -24,7 +24,7 @@ enum protocol_version get_protocol_version_config(void) const char *git_test_k = "GIT_TEST_PROTOCOL_VERSION"; const char *git_test_v; - if (!git_config_get_string_tmp("protocol.version", &value)) { + if (!repo_config_get_string_tmp(the_repository, "protocol.version", &value)) { enum protocol_version version = parse_protocol_version(value); if (version == protocol_unknown_version) diff --git a/reachable.c b/reachable.c index 5706ccaede..22266db523 100644 --- a/reachable.c +++ b/reachable.c @@ -170,7 +170,7 @@ static void load_gc_recent_objects(struct recent_data *data) data->extra_recent_oids_loaded = 1; - if (git_config_get_string_multi("gc.recentobjectshook", &programs)) + if (repo_config_get_string_multi(the_repository, "gc.recentobjectshook", &programs)) return; for (i = 0; i < programs->nr; i++) { diff --git a/read-cache.c b/read-cache.c index be17ca7f58..06ad74db22 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1456,7 +1456,8 @@ int repo_refresh_and_write_index(struct repository *repo, struct lock_file lock_file = LOCK_INIT; int fd, ret = 0; - fd = repo_hold_locked_index(repo, &lock_file, 0); + fd = repo_hold_locked_index(repo, &lock_file, + gentle ? 0 : LOCK_REPORT_ON_ERROR); if (!gentle && fd < 0) return -1; if (refresh_index(repo->index, refresh_flags, pathspec, seen, header_msg)) @@ -2754,7 +2755,7 @@ static int record_eoie(void) { int val; - if (!git_config_get_bool("index.recordendofindexentries", &val)) + if (!repo_config_get_bool(the_repository, "index.recordendofindexentries", &val)) return val; /* @@ -2769,7 +2770,7 @@ static int record_ieot(void) { int val; - if (!git_config_get_bool("index.recordoffsettable", &val)) + if (!repo_config_get_bool(the_repository, "index.recordoffsettable", &val)) return val; /* diff --git a/rebase-interactive.c b/rebase-interactive.c index cbeb864147..809f76a87b 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -30,7 +30,7 @@ static enum missing_commit_check_level get_missing_commit_check_level(void) { const char *value; - if (git_config_get_value("rebase.missingcommitscheck", &value) || + if (repo_config_get_value(the_repository, "rebase.missingcommitscheck", &value) || !strcasecmp("ignore", value)) return MISSING_COMMIT_CHECK_IGNORE; if (!strcasecmp("warn", value)) diff --git a/ref-filter.c b/ref-filter.c index f9f2c512a8..4edf0df4cc 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -2684,6 +2684,41 @@ static int filter_exclude_match(struct ref_filter *filter, const char *refname) } /* + * We need to seek to the reference right after a given marker but excluding any + * matching references. So we seek to the lexicographically next reference. + */ +static int start_ref_iterator_after(struct ref_iterator *iter, const char *marker) +{ + struct strbuf sb = STRBUF_INIT; + int ret; + + strbuf_addstr(&sb, marker); + strbuf_addch(&sb, 1); + + ret = ref_iterator_seek(iter, sb.buf, 0); + + strbuf_release(&sb); + return ret; +} + +static int for_each_fullref_with_seek(struct ref_filter *filter, each_ref_fn cb, + void *cb_data, unsigned int flags) +{ + struct ref_iterator *iter; + int ret = 0; + + iter = refs_ref_iterator_begin(get_main_ref_store(the_repository), "", + NULL, 0, flags); + if (filter->start_after) + ret = start_ref_iterator_after(iter, filter->start_after); + + if (ret) + return ret; + + return do_for_each_ref_iterator(iter, cb, cb_data); +} + +/* * This is the same as for_each_fullref_in(), but it tries to iterate * only over the patterns we'll care about. Note that it _doesn't_ do a full * pattern match, so the callback still has to match each ref individually. @@ -2694,8 +2729,8 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter, { if (filter->kind & FILTER_REFS_ROOT_REFS) { /* In this case, we want to print all refs including root refs. */ - return refs_for_each_include_root_refs(get_main_ref_store(the_repository), - cb, cb_data); + return for_each_fullref_with_seek(filter, cb, cb_data, + DO_FOR_EACH_INCLUDE_ROOT_REFS); } if (!filter->match_as_path) { @@ -2704,8 +2739,7 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter, * prefixes like "refs/heads/" etc. are stripped off, * so we have to look at everything: */ - return refs_for_each_fullref_in(get_main_ref_store(the_repository), - "", NULL, cb, cb_data); + return for_each_fullref_with_seek(filter, cb, cb_data, 0); } if (filter->ignore_case) { @@ -2714,14 +2748,12 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter, * so just return everything and let the caller * sort it out. */ - return refs_for_each_fullref_in(get_main_ref_store(the_repository), - "", NULL, cb, cb_data); + return for_each_fullref_with_seek(filter, cb, cb_data, 0); } if (!filter->name_patterns[0]) { /* no patterns; we have to look at everything */ - return refs_for_each_fullref_in(get_main_ref_store(the_repository), - "", filter->exclude.v, cb, cb_data); + return for_each_fullref_with_seek(filter, cb, cb_data, 0); } return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository), @@ -3189,6 +3221,7 @@ void filter_is_base(struct repository *r, static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref_fn fn, void *cb_data) { + const char *prefix = NULL; int ret = 0; filter->kind = type & FILTER_REFS_KIND_MASK; @@ -3199,38 +3232,48 @@ static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref /* Simple per-ref filtering */ if (!filter->kind) die("filter_refs: invalid type"); - else { - /* - * For common cases where we need only branches or remotes or tags, - * we only iterate through those refs. If a mix of refs is needed, - * we iterate over all refs and filter out required refs with the help - * of filter_ref_kind(). - */ - if (filter->kind == FILTER_REFS_BRANCHES) - ret = refs_for_each_fullref_in(get_main_ref_store(the_repository), - "refs/heads/", NULL, - fn, cb_data); - else if (filter->kind == FILTER_REFS_REMOTES) - ret = refs_for_each_fullref_in(get_main_ref_store(the_repository), - "refs/remotes/", NULL, - fn, cb_data); - else if (filter->kind == FILTER_REFS_TAGS) - ret = refs_for_each_fullref_in(get_main_ref_store(the_repository), - "refs/tags/", NULL, fn, - cb_data); - else if (filter->kind & FILTER_REFS_REGULAR) - ret = for_each_fullref_in_pattern(filter, fn, cb_data); - /* - * When printing all ref types, HEAD is already included, - * so we don't want to print HEAD again. - */ - if (!ret && !(filter->kind & FILTER_REFS_ROOT_REFS) && - (filter->kind & FILTER_REFS_DETACHED_HEAD)) - refs_head_ref(get_main_ref_store(the_repository), fn, - cb_data); + /* + * For common cases where we need only branches or remotes or tags, + * we only iterate through those refs. If a mix of refs is needed, + * we iterate over all refs and filter out required refs with the help + * of filter_ref_kind(). + */ + if (filter->kind == FILTER_REFS_BRANCHES) + prefix = "refs/heads/"; + else if (filter->kind == FILTER_REFS_REMOTES) + prefix = "refs/remotes/"; + else if (filter->kind == FILTER_REFS_TAGS) + prefix = "refs/tags/"; + + if (prefix) { + struct ref_iterator *iter; + + iter = refs_ref_iterator_begin(get_main_ref_store(the_repository), + "", NULL, 0, 0); + + if (filter->start_after) + ret = start_ref_iterator_after(iter, filter->start_after); + else + ret = ref_iterator_seek(iter, prefix, + REF_ITERATOR_SEEK_SET_PREFIX); + + if (!ret) + ret = do_for_each_ref_iterator(iter, fn, cb_data); + } else if (filter->kind & FILTER_REFS_REGULAR) { + ret = for_each_fullref_in_pattern(filter, fn, cb_data); } + /* + * When printing all ref types, HEAD is already included, + * so we don't want to print HEAD again. + */ + if (!ret && !(filter->kind & FILTER_REFS_ROOT_REFS) && + (filter->kind & FILTER_REFS_DETACHED_HEAD)) + refs_head_ref(get_main_ref_store(the_repository), fn, + cb_data); + + clear_contains_cache(&filter->internal.contains_cache); clear_contains_cache(&filter->internal.no_contains_cache); diff --git a/ref-filter.h b/ref-filter.h index c98c4fbd4c..f22ca94b49 100644 --- a/ref-filter.h +++ b/ref-filter.h @@ -64,6 +64,7 @@ struct ref_array { struct ref_filter { const char **name_patterns; + const char *start_after; struct strvec exclude; struct oid_array points_at; struct commit_list *with_commit; @@ -3,6 +3,7 @@ #include "git-compat-util.h" #include "config.h" +#include "environment.h" #include "gettext.h" #include "parse-options.h" #include "odb.h" @@ -81,6 +82,20 @@ int reflog_expire_config(const char *var, const char *value, return 0; } +void reflog_clear_expire_config(struct reflog_expire_options *opts) +{ + struct reflog_expire_entry_option *ent = opts->entries, *tmp; + + while (ent) { + tmp = ent; + ent = ent->next; + free(tmp); + } + + opts->entries = NULL; + opts->entries_tail = NULL; +} + void reflog_expire_options_set_refname(struct reflog_expire_options *cb, const char *ref) { @@ -34,6 +34,8 @@ struct reflog_expire_options { int reflog_expire_config(const char *var, const char *value, const struct config_context *ctx, void *cb); +void reflog_clear_expire_config(struct reflog_expire_options *opts); + /* * Adapt the options so that they apply to the given refname. This applies any * per-reference reflog expiry configuration that may exist to the options. @@ -439,9 +439,9 @@ static int for_each_filter_refs(const char *refname, const char *referent, struct warn_if_dangling_data { struct ref_store *refs; FILE *fp; - const char *refname; const struct string_list *refnames; - const char *msg_fmt; + const char *indent; + int dry_run; }; static int warn_if_dangling_symref(const char *refname, const char *referent UNUSED, @@ -449,44 +449,34 @@ static int warn_if_dangling_symref(const char *refname, const char *referent UNU int flags, void *cb_data) { struct warn_if_dangling_data *d = cb_data; - const char *resolves_to; + const char *resolves_to, *msg; if (!(flags & REF_ISSYMREF)) return 0; resolves_to = refs_resolve_ref_unsafe(d->refs, refname, 0, NULL, NULL); if (!resolves_to - || (d->refname - ? strcmp(resolves_to, d->refname) - : !string_list_has_string(d->refnames, resolves_to))) { + || !string_list_has_string(d->refnames, resolves_to)) { return 0; } - fprintf(d->fp, d->msg_fmt, refname); - fputc('\n', d->fp); + msg = d->dry_run + ? _("%s%s will become dangling after %s is deleted\n") + : _("%s%s has become dangling after %s was deleted\n"); + fprintf(d->fp, msg, d->indent, refname, resolves_to); return 0; } -void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp, - const char *msg_fmt, const char *refname) -{ - struct warn_if_dangling_data data = { - .refs = refs, - .fp = fp, - .refname = refname, - .msg_fmt = msg_fmt, - }; - refs_for_each_rawref(refs, warn_if_dangling_symref, &data); -} - void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp, - const char *msg_fmt, const struct string_list *refnames) + const char *indent, int dry_run, + const struct string_list *refnames) { struct warn_if_dangling_data data = { .refs = refs, .fp = fp, .refnames = refnames, - .msg_fmt = msg_fmt, + .indent = indent, + .dry_run = dry_run, }; refs_for_each_rawref(refs, warn_if_dangling_symref, &data); } @@ -955,7 +945,7 @@ long get_files_ref_lock_timeout_ms(void) static int timeout_ms = 100; if (!configured) { - git_config_get_int("core.filesreflocktimeout", &timeout_ms); + repo_config_get_int(the_repository, "core.filesreflocktimeout", &timeout_ms); configured = 1; } @@ -2667,12 +2657,12 @@ enum ref_transaction_error refs_verify_refnames_available(struct ref_store *refs if (!initial_transaction) { int ok; - if (!iter) { + if (!iter) iter = refs_ref_iterator_begin(refs, dirname.buf, NULL, 0, DO_FOR_EACH_INCLUDE_BROKEN); - } else if (ref_iterator_seek(iter, dirname.buf) < 0) { + else if (ref_iterator_seek(iter, dirname.buf, + REF_ITERATOR_SEEK_SET_PREFIX) < 0) goto cleanup; - } while ((ok = ref_iterator_advance(iter)) == ITER_OK) { if (skip && @@ -452,10 +452,9 @@ static inline const char *has_glob_specials(const char *pattern) return strpbrk(pattern, "?*["); } -void refs_warn_dangling_symref(struct ref_store *refs, FILE *fp, - const char *msg_fmt, const char *refname); void refs_warn_dangling_symrefs(struct ref_store *refs, FILE *fp, - const char *msg_fmt, const struct string_list *refnames); + const char *indent, int dry_run, + const struct string_list *refnames); /* * Flags for controlling behaviour of pack_refs() @@ -1195,4 +1194,159 @@ int repo_migrate_ref_storage_format(struct repository *repo, unsigned int flags, struct strbuf *err); +/* + * Reference iterators + * + * A reference iterator encapsulates the state of an in-progress + * iteration over references. Create an instance of `struct + * ref_iterator` via one of the functions in this module. + * + * A freshly-created ref_iterator doesn't yet point at a reference. To + * advance the iterator, call ref_iterator_advance(). If successful, + * this sets the iterator's refname, oid, and flags fields to describe + * the next reference and returns ITER_OK. The data pointed at by + * refname and oid belong to the iterator; if you want to retain them + * after calling ref_iterator_advance() again or calling + * ref_iterator_free(), you must make a copy. When the iteration has + * been exhausted, ref_iterator_advance() releases any resources + * associated with the iteration, frees the ref_iterator object, and + * returns ITER_DONE. If you want to abort the iteration early, call + * ref_iterator_free(), which also frees the ref_iterator object and + * any associated resources. If there was an internal error advancing + * to the next entry, ref_iterator_advance() aborts the iteration, + * frees the ref_iterator, and returns ITER_ERROR. + * + * The reference currently being looked at can be peeled by calling + * ref_iterator_peel(). This function is often faster than peel_ref(), + * so it should be preferred when iterating over references. + * + * Putting it all together, a typical iteration looks like this: + * + * int ok; + * struct ref_iterator *iter = ...; + * + * while ((ok = ref_iterator_advance(iter)) == ITER_OK) { + * if (want_to_stop_iteration()) { + * ok = ITER_DONE; + * break; + * } + * + * // Access information about the current reference: + * if (!(iter->flags & REF_ISSYMREF)) + * printf("%s is %s\n", iter->refname, oid_to_hex(iter->oid)); + * + * // If you need to peel the reference: + * ref_iterator_peel(iter, &oid); + * } + * + * if (ok != ITER_DONE) + * handle_error(); + * ref_iterator_free(iter); + */ +struct ref_iterator; + +/* + * These flags are passed to refs_ref_iterator_begin() (and do_for_each_ref(), + * which feeds it). + */ +enum do_for_each_ref_flags { + /* + * Include broken references in a do_for_each_ref*() iteration, which + * would normally be omitted. This includes both refs that point to + * missing objects (a true repository corruption), ones with illegal + * names (which we prefer not to expose to callers), as well as + * dangling symbolic refs (i.e., those that point to a non-existent + * ref; this is not a corruption, but as they have no valid oid, we + * omit them from normal iteration results). + */ + DO_FOR_EACH_INCLUDE_BROKEN = (1 << 0), + + /* + * Only include per-worktree refs in a do_for_each_ref*() iteration. + * Normally this will be used with a files ref_store, since that's + * where all reference backends will presumably store their + * per-worktree refs. + */ + DO_FOR_EACH_PER_WORKTREE_ONLY = (1 << 1), + + /* + * Omit dangling symrefs from output; this only has an effect with + * INCLUDE_BROKEN, since they are otherwise not included at all. + */ + DO_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2), + + /* + * Include root refs i.e. HEAD and pseudorefs along with the regular + * refs. + */ + DO_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3), +}; + +/* + * Return an iterator that goes over each reference in `refs` for + * which the refname begins with prefix. If trim is non-zero, then + * trim that many characters off the beginning of each refname. + * The output is ordered by refname. + */ +struct ref_iterator *refs_ref_iterator_begin( + struct ref_store *refs, + const char *prefix, const char **exclude_patterns, + int trim, enum do_for_each_ref_flags flags); + +/* + * Advance the iterator to the first or next item and return ITER_OK. + * If the iteration is exhausted, free the resources associated with + * the ref_iterator and return ITER_DONE. On errors, free the iterator + * resources and return ITER_ERROR. It is a bug to use ref_iterator or + * call this function again after it has returned ITER_DONE or + * ITER_ERROR. + */ +int ref_iterator_advance(struct ref_iterator *ref_iterator); + +enum ref_iterator_seek_flag { + /* + * When the REF_ITERATOR_SEEK_SET_PREFIX flag is set, the iterator's prefix is + * updated to match the provided string, affecting all subsequent iterations. If + * not, the iterator seeks to the specified reference and clears any previously + * set prefix. + */ + REF_ITERATOR_SEEK_SET_PREFIX = (1 << 0), +}; + +/* + * Seek the iterator to the first reference matching the given seek string. + * The seek string is matched as a literal string, without regard for path + * separators. If seek is NULL or the empty string, seek the iterator to the + * first reference again. + * + * This function is expected to behave as if a new ref iterator has been + * created, but allows reuse of existing iterators for optimization. + * + * Returns 0 on success, a negative error code otherwise. + */ +int ref_iterator_seek(struct ref_iterator *ref_iterator, const char *refname, + unsigned int flags); + +/* + * If possible, peel the reference currently being viewed by the + * iterator. Return 0 on success. + */ +int ref_iterator_peel(struct ref_iterator *ref_iterator, + struct object_id *peeled); + +/* Free the reference iterator and any associated resources. */ +void ref_iterator_free(struct ref_iterator *ref_iterator); + +/* + * The common backend for the for_each_*ref* functions. Call fn for + * each reference in iter. If the iterator itself ever returns + * ITER_ERROR, return -1. If fn ever returns a non-zero value, stop + * the iteration and return that value. Otherwise, return 0. In any + * case, free the iterator when done. This function is basically an + * adapter between the callback style of reference iteration and the + * iterator style. + */ +int do_for_each_ref_iterator(struct ref_iterator *iter, + each_ref_fn fn, void *cb_data); + #endif /* REFS_H */ diff --git a/refs/debug.c b/refs/debug.c index 485e3079d7..da300efaf3 100644 --- a/refs/debug.c +++ b/refs/debug.c @@ -170,12 +170,13 @@ static int debug_ref_iterator_advance(struct ref_iterator *ref_iterator) } static int debug_ref_iterator_seek(struct ref_iterator *ref_iterator, - const char *prefix) + const char *refname, unsigned int flags) { struct debug_ref_iterator *diter = (struct debug_ref_iterator *)ref_iterator; - int res = diter->iter->vtable->seek(diter->iter, prefix); - trace_printf_key(&trace_refs, "iterator_seek: %s: %d\n", prefix ? prefix : "", res); + int res = diter->iter->vtable->seek(diter->iter, refname, flags); + trace_printf_key(&trace_refs, "iterator_seek: %s flags: %d: %d\n", + refname ? refname : "", flags, res); return res; } diff --git a/refs/files-backend.c b/refs/files-backend.c index 92c3d2c318..088b52c740 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -929,11 +929,11 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator) } static int files_ref_iterator_seek(struct ref_iterator *ref_iterator, - const char *prefix) + const char *refname, unsigned int flags) { struct files_ref_iterator *iter = (struct files_ref_iterator *)ref_iterator; - return ref_iterator_seek(iter->iter0, prefix); + return ref_iterator_seek(iter->iter0, refname, flags); } static int files_ref_iterator_peel(struct ref_iterator *ref_iterator, @@ -2316,7 +2316,8 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator) } static int files_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED, - const char *prefix UNUSED) + const char *refname UNUSED, + unsigned int flags UNUSED) { BUG("ref_iterator_seek() called for reflog_iterator"); } @@ -2760,6 +2761,8 @@ static void files_transaction_cleanup(struct files_ref_store *refs, if (lock) { unlock_ref(lock); + try_remove_empty_parents(refs, update->refname, + REMOVE_EMPTY_PARENTS_REF); update->backend_data = NULL; } } diff --git a/refs/iterator.c b/refs/iterator.c index 766d96e795..17ef841d8a 100644 --- a/refs/iterator.c +++ b/refs/iterator.c @@ -15,10 +15,10 @@ int ref_iterator_advance(struct ref_iterator *ref_iterator) return ref_iterator->vtable->advance(ref_iterator); } -int ref_iterator_seek(struct ref_iterator *ref_iterator, - const char *prefix) +int ref_iterator_seek(struct ref_iterator *ref_iterator, const char *refname, + unsigned int flags) { - return ref_iterator->vtable->seek(ref_iterator, prefix); + return ref_iterator->vtable->seek(ref_iterator, refname, flags); } int ref_iterator_peel(struct ref_iterator *ref_iterator, @@ -57,7 +57,8 @@ static int empty_ref_iterator_advance(struct ref_iterator *ref_iterator UNUSED) } static int empty_ref_iterator_seek(struct ref_iterator *ref_iterator UNUSED, - const char *prefix UNUSED) + const char *refname UNUSED, + unsigned int flags UNUSED) { return 0; } @@ -224,7 +225,7 @@ error: } static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator, - const char *prefix) + const char *refname, unsigned int flags) { struct merge_ref_iterator *iter = (struct merge_ref_iterator *)ref_iterator; @@ -234,11 +235,11 @@ static int merge_ref_iterator_seek(struct ref_iterator *ref_iterator, iter->iter0 = iter->iter0_owned; iter->iter1 = iter->iter1_owned; - ret = ref_iterator_seek(iter->iter0, prefix); + ret = ref_iterator_seek(iter->iter0, refname, flags); if (ret < 0) return ret; - ret = ref_iterator_seek(iter->iter1, prefix); + ret = ref_iterator_seek(iter->iter1, refname, flags); if (ret < 0) return ret; @@ -407,13 +408,16 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator) } static int prefix_ref_iterator_seek(struct ref_iterator *ref_iterator, - const char *prefix) + const char *refname, unsigned int flags) { struct prefix_ref_iterator *iter = (struct prefix_ref_iterator *)ref_iterator; - free(iter->prefix); - iter->prefix = xstrdup_or_null(prefix); - return ref_iterator_seek(iter->iter0, prefix); + + if (flags & REF_ITERATOR_SEEK_SET_PREFIX) { + free(iter->prefix); + iter->prefix = xstrdup_or_null(refname); + } + return ref_iterator_seek(iter->iter0, refname, flags); } static int prefix_ref_iterator_peel(struct ref_iterator *ref_iterator, diff --git a/refs/packed-backend.c b/refs/packed-backend.c index 7fd73a0e6d..a8c22a0a7f 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -1004,19 +1004,23 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator) } static int packed_ref_iterator_seek(struct ref_iterator *ref_iterator, - const char *prefix) + const char *refname, unsigned int flags) { struct packed_ref_iterator *iter = (struct packed_ref_iterator *)ref_iterator; const char *start; - if (prefix && *prefix) - start = find_reference_location(iter->snapshot, prefix, 0); + if (refname && *refname) + start = find_reference_location(iter->snapshot, refname, 0); else start = iter->snapshot->start; - free(iter->prefix); - iter->prefix = xstrdup_or_null(prefix); + /* Unset any previously set prefix */ + FREE_AND_NULL(iter->prefix); + + if (flags & REF_ITERATOR_SEEK_SET_PREFIX) + iter->prefix = xstrdup_or_null(refname); + iter->pos = start; iter->eof = iter->snapshot->eof; @@ -1194,7 +1198,8 @@ static struct ref_iterator *packed_ref_iterator_begin( iter->repo = ref_store->repo; iter->flags = flags; - if (packed_ref_iterator_seek(&iter->base, prefix) < 0) { + if (packed_ref_iterator_seek(&iter->base, prefix, + REF_ITERATOR_SEEK_SET_PREFIX) < 0) { ref_iterator_free(&iter->base); return NULL; } @@ -1228,7 +1233,7 @@ int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err) static int timeout_value = 1000; if (!timeout_configured) { - git_config_get_int("core.packedrefstimeout", &timeout_value); + repo_config_get_int(the_repository, "core.packedrefstimeout", &timeout_value); timeout_configured = 1; } diff --git a/refs/ref-cache.c b/refs/ref-cache.c index c1f1bab1d5..c180e0aad7 100644 --- a/refs/ref-cache.c +++ b/refs/ref-cache.c @@ -194,20 +194,6 @@ static struct ref_dir *find_containing_dir(struct ref_dir *dir, return dir; } -struct ref_entry *find_ref_entry(struct ref_dir *dir, const char *refname) -{ - int entry_index; - struct ref_entry *entry; - dir = find_containing_dir(dir, refname); - if (!dir) - return NULL; - entry_index = search_ref_dir(dir, refname, strlen(refname)); - if (entry_index == -1) - return NULL; - entry = dir->entries[entry_index]; - return (entry->flag & REF_DIR) ? NULL : entry; -} - /* * Emit a warning and return true iff ref1 and ref2 have the same name * and the same oid. Die if they have the same name but different @@ -448,11 +434,9 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator) } } -static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator, - const char *prefix) +static int cache_ref_iterator_set_prefix(struct cache_ref_iterator *iter, + const char *prefix) { - struct cache_ref_iterator *iter = - (struct cache_ref_iterator *)ref_iterator; struct cache_ref_iterator_level *level; struct ref_dir *dir; @@ -483,6 +467,84 @@ static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator, return 0; } +static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator, + const char *refname, unsigned int flags) +{ + struct cache_ref_iterator *iter = + (struct cache_ref_iterator *)ref_iterator; + + if (flags & REF_ITERATOR_SEEK_SET_PREFIX) { + return cache_ref_iterator_set_prefix(iter, refname); + } else if (refname && *refname) { + struct cache_ref_iterator_level *level; + const char *slash = refname; + struct ref_dir *dir; + + dir = get_ref_dir(iter->cache->root); + + if (iter->prime_dir) + prime_ref_dir(dir, refname); + + iter->levels_nr = 1; + level = &iter->levels[0]; + level->index = -1; + level->dir = dir; + + /* Unset any previously set prefix */ + FREE_AND_NULL(iter->prefix); + + /* + * Breakdown the provided seek path and assign the correct + * indexing to each level as needed. + */ + do { + int idx; + size_t len; + int cmp = 0; + + sort_ref_dir(dir); + + slash = strchr(slash, '/'); + len = slash ? (size_t)(slash - refname) : strlen(refname); + + for (idx = 0; idx < dir->nr; idx++) { + cmp = strncmp(refname, dir->entries[idx]->name, len); + if (cmp <= 0) + break; + } + /* don't overflow the index */ + idx = idx >= dir->nr ? dir->nr - 1 : idx; + + if (slash) + slash = slash + 1; + + level->index = idx; + if (dir->entries[idx]->flag & REF_DIR) { + /* push down a level */ + dir = get_ref_dir(dir->entries[idx]); + + ALLOC_GROW(iter->levels, iter->levels_nr + 1, + iter->levels_alloc); + level = &iter->levels[iter->levels_nr++]; + level->dir = dir; + level->index = -1; + level->prefix_state = PREFIX_CONTAINS_DIR; + } else { + /* reduce the index so the leaf node is iterated over */ + if (cmp <= 0 && !slash) + level->index = idx - 1; + /* + * while the seek path may not be exhausted, our + * match is exhausted at a leaf node. + */ + break; + } + } while (slash); + } + + return 0; +} + static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator, struct object_id *peeled) { @@ -523,7 +585,8 @@ struct ref_iterator *cache_ref_iterator_begin(struct ref_cache *cache, iter->cache = cache; iter->prime_dir = prime_dir; - if (cache_ref_iterator_seek(&iter->base, prefix) < 0) { + if (cache_ref_iterator_seek(&iter->base, prefix, + REF_ITERATOR_SEEK_SET_PREFIX) < 0) { ref_iterator_free(&iter->base); return NULL; } diff --git a/refs/ref-cache.h b/refs/ref-cache.h index 5f04e518c3..f635d2d824 100644 --- a/refs/ref-cache.h +++ b/refs/ref-cache.h @@ -202,13 +202,6 @@ void free_ref_cache(struct ref_cache *cache); void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry); /* - * Find the value entry with the given name in dir, sorting ref_dirs - * and recursing into subdirectories as necessary. If the name is not - * found or it corresponds to a directory entry, return NULL. - */ -struct ref_entry *find_ref_entry(struct ref_dir *dir, const char *refname); - -/* * Start iterating over references in `cache`. If `prefix` is * specified, only include references whose names start with that * prefix. If `prime_dir` is true, then fill any incomplete diff --git a/refs/refs-internal.h b/refs/refs-internal.h index f868870851..40c1c0f93d 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -244,90 +244,8 @@ const char *find_descendant_ref(const char *dirname, #define SYMREF_MAXDEPTH 5 /* - * These flags are passed to refs_ref_iterator_begin() (and do_for_each_ref(), - * which feeds it). - */ -enum do_for_each_ref_flags { - /* - * Include broken references in a do_for_each_ref*() iteration, which - * would normally be omitted. This includes both refs that point to - * missing objects (a true repository corruption), ones with illegal - * names (which we prefer not to expose to callers), as well as - * dangling symbolic refs (i.e., those that point to a non-existent - * ref; this is not a corruption, but as they have no valid oid, we - * omit them from normal iteration results). - */ - DO_FOR_EACH_INCLUDE_BROKEN = (1 << 0), - - /* - * Only include per-worktree refs in a do_for_each_ref*() iteration. - * Normally this will be used with a files ref_store, since that's - * where all reference backends will presumably store their - * per-worktree refs. - */ - DO_FOR_EACH_PER_WORKTREE_ONLY = (1 << 1), - - /* - * Omit dangling symrefs from output; this only has an effect with - * INCLUDE_BROKEN, since they are otherwise not included at all. - */ - DO_FOR_EACH_OMIT_DANGLING_SYMREFS = (1 << 2), - - /* - * Include root refs i.e. HEAD and pseudorefs along with the regular - * refs. - */ - DO_FOR_EACH_INCLUDE_ROOT_REFS = (1 << 3), -}; - -/* - * Reference iterators - * - * A reference iterator encapsulates the state of an in-progress - * iteration over references. Create an instance of `struct - * ref_iterator` via one of the functions in this module. - * - * A freshly-created ref_iterator doesn't yet point at a reference. To - * advance the iterator, call ref_iterator_advance(). If successful, - * this sets the iterator's refname, oid, and flags fields to describe - * the next reference and returns ITER_OK. The data pointed at by - * refname and oid belong to the iterator; if you want to retain them - * after calling ref_iterator_advance() again or calling - * ref_iterator_free(), you must make a copy. When the iteration has - * been exhausted, ref_iterator_advance() releases any resources - * associated with the iteration, frees the ref_iterator object, and - * returns ITER_DONE. If you want to abort the iteration early, call - * ref_iterator_free(), which also frees the ref_iterator object and - * any associated resources. If there was an internal error advancing - * to the next entry, ref_iterator_advance() aborts the iteration, - * frees the ref_iterator, and returns ITER_ERROR. - * - * The reference currently being looked at can be peeled by calling - * ref_iterator_peel(). This function is often faster than peel_ref(), - * so it should be preferred when iterating over references. - * - * Putting it all together, a typical iteration looks like this: - * - * int ok; - * struct ref_iterator *iter = ...; - * - * while ((ok = ref_iterator_advance(iter)) == ITER_OK) { - * if (want_to_stop_iteration()) { - * ok = ITER_DONE; - * break; - * } - * - * // Access information about the current reference: - * if (!(iter->flags & REF_ISSYMREF)) - * printf("%s is %s\n", iter->refname, oid_to_hex(iter->oid)); - * - * // If you need to peel the reference: - * ref_iterator_peel(iter, &oid); - * } - * - * if (ok != ITER_DONE) - * handle_error(); - * ref_iterator_free(iter); + * Data structure for holding a reference iterator. See refs.h for + * more details and usage instructions. */ struct ref_iterator { struct ref_iterator_vtable *vtable; @@ -338,42 +256,6 @@ struct ref_iterator { }; /* - * Advance the iterator to the first or next item and return ITER_OK. - * If the iteration is exhausted, free the resources associated with - * the ref_iterator and return ITER_DONE. On errors, free the iterator - * resources and return ITER_ERROR. It is a bug to use ref_iterator or - * call this function again after it has returned ITER_DONE or - * ITER_ERROR. - */ -int ref_iterator_advance(struct ref_iterator *ref_iterator); - -/* - * Seek the iterator to the first reference with the given prefix. - * The prefix is matched as a literal string, without regard for path - * separators. If prefix is NULL or the empty string, seek the iterator to the - * first reference again. - * - * This function is expected to behave as if a new ref iterator with the same - * prefix had been created, but allows reuse of iterators and thus may allow - * the backend to optimize. Parameters other than the prefix that have been - * passed when creating the iterator will remain unchanged. - * - * Returns 0 on success, a negative error code otherwise. - */ -int ref_iterator_seek(struct ref_iterator *ref_iterator, - const char *prefix); - -/* - * If possible, peel the reference currently being viewed by the - * iterator. Return 0 on success. - */ -int ref_iterator_peel(struct ref_iterator *ref_iterator, - struct object_id *peeled); - -/* Free the reference iterator and any associated resources. */ -void ref_iterator_free(struct ref_iterator *ref_iterator); - -/* * An iterator over nothing (its first ref_iterator_advance() call * returns ITER_DONE). */ @@ -385,17 +267,6 @@ struct ref_iterator *empty_ref_iterator_begin(void); int is_empty_ref_iterator(struct ref_iterator *ref_iterator); /* - * Return an iterator that goes over each reference in `refs` for - * which the refname begins with prefix. If trim is non-zero, then - * trim that many characters off the beginning of each refname. - * The output is ordered by refname. - */ -struct ref_iterator *refs_ref_iterator_begin( - struct ref_store *refs, - const char *prefix, const char **exclude_patterns, - int trim, enum do_for_each_ref_flags flags); - -/* * A callback function used to instruct merge_ref_iterator how to * interleave the entries from iter0 and iter1. The function should * return one of the constants defined in enum iterator_selection. It @@ -482,11 +353,12 @@ void base_ref_iterator_init(struct ref_iterator *iter, typedef int ref_iterator_advance_fn(struct ref_iterator *ref_iterator); /* - * Seek the iterator to the first reference matching the given prefix. Should - * behave the same as if a new iterator was created with the same prefix. + * Seek the iterator to the first matching reference. If the + * REF_ITERATOR_SEEK_SET_PREFIX flag is set, it would behave the same as if a + * new iterator was created with the provided refname as prefix. */ typedef int ref_iterator_seek_fn(struct ref_iterator *ref_iterator, - const char *prefix); + const char *refname, unsigned int flags); /* * Peels the current ref, returning 0 for success or -1 for failure. @@ -520,18 +392,6 @@ struct ref_iterator_vtable { */ extern struct ref_iterator *current_ref_iter; -/* - * The common backend for the for_each_*ref* functions. Call fn for - * each reference in iter. If the iterator itself ever returns - * ITER_ERROR, return -1. If fn ever returns a non-zero value, stop - * the iteration and return that value. Otherwise, return 0. In any - * case, free the iterator when done. This function is basically an - * adapter between the callback style of reference iteration and the - * iterator style. - */ -int do_for_each_ref_iterator(struct ref_iterator *iter, - each_ref_fn fn, void *cb_data); - struct ref_store; /* refs backends */ diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 4c3817f4ec..8dae1e1112 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -386,7 +386,7 @@ static struct ref_store *reftable_be_init(struct repository *repo, refs->write_options.lock_timeout_ms = 100; refs->write_options.fsync = reftable_be_fsync; - git_config(reftable_be_config, &refs->write_options); + repo_config(the_repository, reftable_be_config, &refs->write_options); /* * It is somewhat unfortunate that we have to mirror the default block @@ -719,15 +719,20 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator) } static int reftable_ref_iterator_seek(struct ref_iterator *ref_iterator, - const char *prefix) + const char *refname, unsigned int flags) { struct reftable_ref_iterator *iter = (struct reftable_ref_iterator *)ref_iterator; - free(iter->prefix); - iter->prefix = xstrdup_or_null(prefix); - iter->prefix_len = prefix ? strlen(prefix) : 0; - iter->err = reftable_iterator_seek_ref(&iter->iter, prefix); + /* Unset any previously set prefix */ + FREE_AND_NULL(iter->prefix); + iter->prefix_len = 0; + + if (flags & REF_ITERATOR_SEEK_SET_PREFIX) { + iter->prefix = xstrdup_or_null(refname); + iter->prefix_len = refname ? strlen(refname) : 0; + } + iter->err = reftable_iterator_seek_ref(&iter->iter, refname); return iter->err; } @@ -839,7 +844,8 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_ if (ret) goto done; - ret = reftable_ref_iterator_seek(&iter->base, prefix); + ret = reftable_ref_iterator_seek(&iter->base, prefix, + REF_ITERATOR_SEEK_SET_PREFIX); if (ret) goto done; @@ -2042,7 +2048,8 @@ static int reftable_reflog_iterator_advance(struct ref_iterator *ref_iterator) } static int reftable_reflog_iterator_seek(struct ref_iterator *ref_iterator UNUSED, - const char *prefix UNUSED) + const char *refname UNUSED, + unsigned int flags UNUSED) { BUG("reftable reflog iterator cannot be seeked"); return -1; diff --git a/remote-curl.c b/remote-curl.c index b8bc3a80cf..84f4694780 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -285,7 +285,7 @@ static const struct git_hash_algo *detect_hash_algo(struct discovery *heads) * back to SHA1, which may or may not be correct. */ if (!p) - return &hash_algos[GIT_HASH_SHA1]; + return &hash_algos[GIT_HASH_SHA1_LEGACY]; algo = hash_algo_by_length((p - heads->buf) / 2); if (algo == GIT_HASH_UNKNOWN) @@ -734,7 +734,7 @@ static void validate_remote_url(struct remote *remote) struct strbuf redacted = STRBUF_INIT; int warn_not_die; - if (git_config_get_string_tmp("transfer.credentialsinurl", &value)) + if (repo_config_get_string_tmp(the_repository, "transfer.credentialsinurl", &value)) return; if (!strcmp("warn", value)) diff --git a/repository.c b/repository.c index c606e1153c..ecd691181f 100644 --- a/repository.c +++ b/repository.c @@ -285,6 +285,7 @@ int repo_init(struct repository *repo, repo_set_ref_storage_format(repo, format.ref_storage_format); repo->repository_format_worktree_config = format.worktree_config; repo->repository_format_relative_worktrees = format.relative_worktrees; + repo->repository_format_precious_objects = format.precious_objects; /* take ownership of format.partial_clone */ repo->repository_format_partial_clone = format.partial_clone; diff --git a/repository.h b/repository.h index 3a5ef9c781..042dc93f0f 100644 --- a/repository.h +++ b/repository.h @@ -20,6 +20,12 @@ enum ref_storage_format { REF_STORAGE_FORMAT_REFTABLE, }; +#ifdef WITH_BREAKING_CHANGES /* Git 3.0 */ +# define REF_STORAGE_FORMAT_DEFAULT REF_STORAGE_FORMAT_REFTABLE +#else +# define REF_STORAGE_FORMAT_DEFAULT REF_STORAGE_FORMAT_FILES +#endif + struct repo_path_cache { char *squash_msg; char *merge_msg; @@ -151,6 +157,7 @@ struct repository { /* Configurations */ int repository_format_worktree_config; int repository_format_relative_worktrees; + int repository_format_precious_objects; /* Indicate if a repository has a different 'commondir' from 'gitdir' */ unsigned different_commondir:1; @@ -5,6 +5,7 @@ #include "abspath.h" #include "config.h" #include "copy.h" +#include "environment.h" #include "gettext.h" #include "hex.h" #include "lockfile.h" @@ -877,9 +878,9 @@ static int do_plain_rerere(struct repository *r, static void git_rerere_config(void) { - git_config_get_bool("rerere.enabled", &rerere_enabled); - git_config_get_bool("rerere.autoupdate", &rerere_autoupdate); - git_config(git_default_config, NULL); + repo_config_get_bool(the_repository, "rerere.enabled", &rerere_enabled); + repo_config_get_bool(the_repository, "rerere.autoupdate", &rerere_autoupdate); + repo_config(the_repository, git_default_config, NULL); } static GIT_PATH_FUNC(git_path_rr_cache, "rr-cache") @@ -1247,7 +1248,7 @@ void rerere_gc(struct repository *r, struct string_list *rr) &cutoff_resolve, now); repo_config_get_expiry_in_days(the_repository, "gc.rerereunresolved", &cutoff_noresolve, now); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); dir = opendir(repo_git_path_replace(the_repository, &buf, "rr-cache")); if (!dir) die_errno(_("unable to open rr-cache directory")); diff --git a/revision.c b/revision.c index 0cd9890297..18f300d455 100644 --- a/revision.c +++ b/revision.c @@ -50,8 +50,6 @@ #include "parse-options.h" #include "wildmatch.h" -volatile show_early_output_fn_t show_early_output; - static char *term_bad; static char *term_good; @@ -675,24 +673,48 @@ static int forbid_bloom_filters(struct pathspec *spec) { if (spec->has_wildcard) return 1; - if (spec->nr > 1) - return 1; if (spec->magic & ~PATHSPEC_LITERAL) return 1; - if (spec->nr && (spec->items[0].magic & ~PATHSPEC_LITERAL)) - return 1; + for (size_t nr = 0; nr < spec->nr; nr++) + if (spec->items[nr].magic & ~PATHSPEC_LITERAL) + return 1; return 0; } -static void prepare_to_use_bloom_filter(struct rev_info *revs) +static void release_revisions_bloom_keyvecs(struct rev_info *revs); + +static int convert_pathspec_to_bloom_keyvec(struct bloom_keyvec **out, + const struct pathspec_item *pi, + const struct bloom_filter_settings *settings) { - struct pathspec_item *pi; char *path_alloc = NULL; - const char *path, *p; + const char *path; size_t len; - int path_component_nr = 1; + int res = 0; + + /* remove single trailing slash from path, if needed */ + if (pi->len > 0 && pi->match[pi->len - 1] == '/') { + path_alloc = xmemdupz(pi->match, pi->len - 1); + path = path_alloc; + } else + path = pi->match; + len = strlen(path); + if (!len) { + res = -1; + goto cleanup; + } + + *out = bloom_keyvec_new(path, len, settings); + +cleanup: + free(path_alloc); + return res; +} + +static void prepare_to_use_bloom_filter(struct rev_info *revs) +{ if (!revs->commits) return; @@ -708,48 +730,14 @@ static void prepare_to_use_bloom_filter(struct rev_info *revs) if (!revs->pruning.pathspec.nr) return; - pi = &revs->pruning.pathspec.items[0]; - - /* remove single trailing slash from path, if needed */ - if (pi->len > 0 && pi->match[pi->len - 1] == '/') { - path_alloc = xmemdupz(pi->match, pi->len - 1); - path = path_alloc; - } else - path = pi->match; - - len = strlen(path); - if (!len) { - revs->bloom_filter_settings = NULL; - free(path_alloc); - return; - } - - p = path; - while (*p) { - /* - * At this point, the path is normalized to use Unix-style - * path separators. This is required due to how the - * changed-path Bloom filters store the paths. - */ - if (*p == '/') - path_component_nr++; - p++; - } - - revs->bloom_keys_nr = path_component_nr; - ALLOC_ARRAY(revs->bloom_keys, revs->bloom_keys_nr); - - fill_bloom_key(path, len, &revs->bloom_keys[0], - revs->bloom_filter_settings); - path_component_nr = 1; + revs->bloom_keyvecs_nr = revs->pruning.pathspec.nr; + CALLOC_ARRAY(revs->bloom_keyvecs, revs->bloom_keyvecs_nr); - p = path + len - 1; - while (p > path) { - if (*p == '/') - fill_bloom_key(path, p - path, - &revs->bloom_keys[path_component_nr++], - revs->bloom_filter_settings); - p--; + for (int i = 0; i < revs->pruning.pathspec.nr; i++) { + if (convert_pathspec_to_bloom_keyvec(&revs->bloom_keyvecs[i], + &revs->pruning.pathspec.items[i], + revs->bloom_filter_settings)) + goto fail; } if (trace2_is_enabled() && !bloom_filter_atexit_registered) { @@ -757,14 +745,18 @@ static void prepare_to_use_bloom_filter(struct rev_info *revs) bloom_filter_atexit_registered = 1; } - free(path_alloc); + return; + +fail: + revs->bloom_filter_settings = NULL; + release_revisions_bloom_keyvecs(revs); } static int check_maybe_different_in_bloom_filter(struct rev_info *revs, struct commit *commit) { struct bloom_filter *filter; - int result = 1, j; + int result = 0; if (!revs->repo->objects->commit_graph) return -1; @@ -779,10 +771,10 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs, return -1; } - for (j = 0; result && j < revs->bloom_keys_nr; j++) { - result = bloom_filter_contains(filter, - &revs->bloom_keys[j], - revs->bloom_filter_settings); + for (size_t nr = 0; !result && nr < revs->bloom_keyvecs_nr; nr++) { + result = bloom_filter_contains_vec(filter, + revs->bloom_keyvecs[nr], + revs->bloom_filter_settings); } if (result) @@ -823,7 +815,7 @@ static int rev_compare_tree(struct rev_info *revs, return REV_TREE_SAME; } - if (revs->bloom_keys_nr && !nth_parent) { + if (revs->bloom_keyvecs_nr && !nth_parent) { bloom_ret = check_maybe_different_in_bloom_filter(revs, commit); if (bloom_ret == 0) @@ -850,7 +842,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit, if (!t1) return 0; - if (!nth_parent && revs->bloom_keys_nr) { + if (!nth_parent && revs->bloom_keyvecs_nr) { bloom_ret = check_maybe_different_in_bloom_filter(revs, commit); if (!bloom_ret) return 1; @@ -1479,7 +1471,6 @@ static int limit_list(struct rev_info *revs) while (original_list) { struct commit *commit = pop_commit(&original_list); struct object *obj = &commit->object; - show_early_output_fn_t show; if (commit == interesting_cache) interesting_cache = NULL; @@ -1503,13 +1494,6 @@ static int limit_list(struct rev_info *revs) continue; date = commit->date; p = &commit_list_insert(commit, p)->next; - - show = show_early_output; - if (!show) - continue; - - show(revs, newlist); - show_early_output = NULL; } if (revs->cherry_pick || revs->cherry_mark) cherry_pick_list(newlist, revs); @@ -1636,7 +1620,7 @@ void exclude_hidden_refs(struct ref_exclusions *exclusions, const char *section) cb.exclusions = exclusions; cb.section = section; - git_config(hide_refs_config, &cb); + repo_config(the_repository, hide_refs_config, &cb); } struct all_refs_cb { @@ -2443,13 +2427,6 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--author-date-order")) { revs->sort_order = REV_SORT_BY_AUTHOR_DATE; revs->topo_order = 1; - } else if (!strcmp(arg, "--early-output")) { - revs->early_output = 100; - revs->topo_order = 1; - } else if (skip_prefix(arg, "--early-output=", &optarg)) { - if (strtoul_ui(optarg, 10, &revs->early_output) < 0) - die("'%s': not a non-negative integer", optarg); - revs->topo_order = 1; } else if (!strcmp(arg, "--parents")) { revs->rewrite_parents = 1; revs->print_parents = 1; @@ -3113,7 +3090,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s /* Pickaxe, diff-filter and rename following need diffs */ if ((revs->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) || - revs->diffopt.filter || + revs->diffopt.filter || revs->diffopt.filter_not || revs->diffopt.flags.follow_renames) revs->diff = 1; @@ -3202,6 +3179,14 @@ static void release_revisions_mailmap(struct string_list *mailmap) static void release_revisions_topo_walk_info(struct topo_walk_info *info); +static void release_revisions_bloom_keyvecs(struct rev_info *revs) +{ + for (size_t nr = 0; nr < revs->bloom_keyvecs_nr; nr++) + bloom_keyvec_free(revs->bloom_keyvecs[nr]); + FREE_AND_NULL(revs->bloom_keyvecs); + revs->bloom_keyvecs_nr = 0; +} + static void free_void_commit_list(void *list) { free_commit_list(list); @@ -3230,11 +3215,7 @@ void release_revisions(struct rev_info *revs) clear_decoration(&revs->treesame, free); line_log_free(revs); oidset_clear(&revs->missing_commits); - - for (int i = 0; i < revs->bloom_keys_nr; i++) - clear_bloom_key(&revs->bloom_keys[i]); - FREE_AND_NULL(revs->bloom_keys); - revs->bloom_keys_nr = 0; + release_revisions_bloom_keyvecs(revs); } static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child) diff --git a/revision.h b/revision.h index 6d369cdad6..21e288c5ba 100644 --- a/revision.h +++ b/revision.h @@ -62,7 +62,7 @@ struct repository; struct rev_info; struct string_list; struct saved_parents; -struct bloom_key; +struct bloom_keyvec; struct bloom_filter_settings; struct option; struct parse_opt_ctx_t; @@ -160,8 +160,6 @@ struct rev_info { /* topo-sort */ enum rev_sort_order sort_order; - unsigned int early_output; - unsigned int ignore_missing:1, ignore_missing_links:1; @@ -360,8 +358,8 @@ struct rev_info { /* Commit graph bloom filter fields */ /* The bloom filter key(s) for the pathspec */ - struct bloom_key *bloom_keys; - int bloom_keys_nr; + struct bloom_keyvec **bloom_keyvecs; + int bloom_keyvecs_nr; /* * The bloom filter settings used to generate the key. @@ -553,10 +551,4 @@ int rewrite_parents(struct rev_info *revs, */ struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit); -/** - * Global for the (undocumented) "--early-output" flag for "git log". - */ -typedef void (*show_early_output_fn_t)(struct rev_info *, struct commit_list *); -extern volatile show_early_output_fn_t show_early_output; - #endif diff --git a/run-command.c b/run-command.c index 8833b23367..ed9575bd6a 100644 --- a/run-command.c +++ b/run-command.c @@ -1817,7 +1817,7 @@ int prepare_auto_maintenance(int quiet, struct child_process *maint) { int enabled, auto_detach; - if (!git_config_get_bool("maintenance.auto", &enabled) && + if (!repo_config_get_bool(the_repository, "maintenance.auto", &enabled) && !enabled) return 0; @@ -1826,8 +1826,8 @@ int prepare_auto_maintenance(int quiet, struct child_process *maint) * honoring `gc.autoDetach`. This is somewhat weird, but required to * retain behaviour from when we used to run git-gc(1) here. */ - if (git_config_get_bool("maintenance.autodetach", &auto_detach) && - git_config_get_bool("gc.autodetach", &auto_detach)) + if (repo_config_get_bool(the_repository, "maintenance.autodetach", &auto_detach) && + repo_config_get_bool(the_repository, "gc.autodetach", &auto_detach)) auto_detach = 1; maint->git_cmd = 1; diff --git a/sane-ctype.h b/sane-ctype.h index cbea1b299b..4f476c4381 100644 --- a/sane-ctype.h +++ b/sane-ctype.h @@ -1,6 +1,15 @@ #ifndef SANE_CTYPE_H #define SANE_CTYPE_H +/* + * Explicitly include <ctype.h> so that its header guards kick in from here on. + * This ensures that the file won't get included after "sane-ctype.h", as that + * would otherwise lead to a compiler error because the function declarations + * for `int isascii(int c)` et al would be mangled by our macros with the same + * name. + */ +#include <ctype.h> + /* Sane ctype - no locale, and works with signed chars */ #undef isascii #undef isspace @@ -101,9 +101,9 @@ static int set_scalar_config(const struct scalar_config *config, int reconfigure int res; if ((reconfigure && config->overwrite_on_reconfigure) || - git_config_get_string(config->key, &value)) { + repo_config_get_string(the_repository, config->key, &value)) { trace2_data_string("scalar", the_repository, config->key, "created"); - res = git_config_set_gently(config->key, config->value); + res = repo_config_set_gently(the_repository, config->key, config->value); } else { trace2_data_string("scalar", the_repository, config->key, "exists"); res = 0; @@ -193,12 +193,12 @@ static int set_recommended_config(int reconfigure) * The `log.excludeDecoration` setting is special because it allows * for multiple values. */ - if (git_config_get_string("log.excludeDecoration", &value)) { + if (repo_config_get_string(the_repository, "log.excludeDecoration", &value)) { trace2_data_string("scalar", the_repository, "log.excludeDecoration", "created"); - if (git_config_set_multivar_gently("log.excludeDecoration", - "refs/prefetch/*", - CONFIG_REGEX_NONE, 0)) + if (repo_config_set_multivar_gently(the_repository, "log.excludeDecoration", + "refs/prefetch/*", + CONFIG_REGEX_NONE, 0)) return error(_("could not configure " "log.excludeDecoration")); } else { @@ -322,7 +322,7 @@ static int set_config(const char *fmt, ...) value = strchr(buf.buf, '='); if (value) *(value++) = '\0'; - res = git_config_set_gently(buf.buf, value); + res = repo_config_set_gently(the_repository, buf.buf, value); strbuf_release(&buf); return res; @@ -713,7 +713,7 @@ static int cmd_reconfigure(int argc, const char **argv) maintenance_str); } - git_config(get_scalar_repos, &scalar_repos); + repo_config(the_repository, get_scalar_repos, &scalar_repos); for (size_t i = 0; i < scalar_repos.nr; i++) { int succeeded = 0; @@ -763,7 +763,7 @@ static int cmd_reconfigure(int argc, const char **argv) break; } - git_config_clear(); + repo_config_clear(the_repository); if (repo_init(&r, gitdir.buf, commondir.buf)) goto loop_end; diff --git a/sequencer.c b/sequencer.c index 67e4310edc..aaf2e4df64 100644 --- a/sequencer.c +++ b/sequencer.c @@ -327,7 +327,7 @@ static int git_sequencer_config(const char *k, const char *v, void sequencer_init_config(struct replay_opts *opts) { opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE; - git_config(git_sequencer_config, opts); + repo_config(the_repository, git_sequencer_config, opts); } static inline int is_rebase_i(const struct replay_opts *opts) @@ -3650,57 +3650,57 @@ static int save_opts(struct replay_opts *opts) int res = 0; if (opts->no_commit) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.no-commit", NULL, "true"); if (opts->edit >= 0) - res |= git_config_set_in_file_gently(opts_file, "options.edit", NULL, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.edit", NULL, opts->edit ? "true" : "false"); if (opts->allow_empty) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.allow-empty", NULL, "true"); if (opts->allow_empty_message) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.allow-empty-message", NULL, "true"); if (opts->drop_redundant_commits) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.drop-redundant-commits", NULL, "true"); if (opts->keep_redundant_commits) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.keep-redundant-commits", NULL, "true"); if (opts->signoff) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.signoff", NULL, "true"); if (opts->record_origin) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.record-origin", NULL, "true"); if (opts->allow_ff) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.allow-ff", NULL, "true"); if (opts->mainline) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%d", opts->mainline); - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.mainline", NULL, buf.buf); strbuf_release(&buf); } if (opts->strategy) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.strategy", NULL, opts->strategy); if (opts->gpg_sign) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.gpg-sign", NULL, opts->gpg_sign); for (size_t i = 0; i < opts->xopts.nr; i++) - res |= git_config_set_multivar_in_file_gently(opts_file, + res |= repo_config_set_multivar_in_file_gently(the_repository, opts_file, "options.strategy-option", opts->xopts.v[i], "^$", NULL, 0); if (opts->allow_rerere_auto) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.allow-rerere-auto", NULL, opts->allow_rerere_auto == RERERE_AUTOUPDATE ? "true" : "false"); if (opts->explicit_cleanup) - res |= git_config_set_in_file_gently(opts_file, + res |= repo_config_set_in_file_gently(the_repository, opts_file, "options.default-msg-cleanup", NULL, describe_cleanup_mode(opts->default_msg_cleanup)); return res; @@ -5834,7 +5834,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, *cmd_reset = abbr ? "t" : "reset", *cmd_merge = abbr ? "m" : "merge"; - git_config_get_int("rebase.maxlabellength", &state.max_label_length); + repo_config_get_int(the_repository, "rebase.maxlabellength", &state.max_label_length); oidmap_init(&commit2todo, 0); oidmap_init(&state.commit2label, 0); @@ -6089,7 +6089,7 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc, revs.topo_order = 1; revs.pretty_given = 1; - git_config_get_string("rebase.instructionFormat", &format); + repo_config_get_string(the_repository, "rebase.instructionFormat", &format); if (!format || !*format) { free(format); format = xstrdup("# %s"); @@ -14,7 +14,7 @@ static int advertise_sid = -1; static int advertise_object_info = -1; -static int client_hash_algo = GIT_HASH_SHA1; +static int client_hash_algo = GIT_HASH_SHA1_LEGACY; static int always_advertise(struct repository *r UNUSED, struct strbuf *value UNUSED) @@ -753,7 +753,8 @@ static int check_repository_format_gently(const char *gitdir, struct repository_ die("%s", err.buf); } - repository_format_precious_objects = candidate->precious_objects; + the_repository->repository_format_precious_objects = candidate->precious_objects; + string_list_clear(&candidate->unknown_extensions, 0); string_list_clear(&candidate->v1_only_extensions, 0); @@ -814,7 +815,7 @@ int upgrade_repository_format(int target_version) } strbuf_addf(&repo_version, "%d", target_version); - git_config_set("core.repositoryformatversion", repo_version.buf); + repo_config_set(the_repository, "core.repositoryformatversion", repo_version.buf); ret = 1; @@ -835,9 +836,12 @@ static void init_repository_format(struct repository_format *format) int read_repository_format(struct repository_format *format, const char *path) { clear_repository_format(format); + format->hash_algo = GIT_HASH_SHA1_LEGACY; git_config_from_file(check_repo_format, path, format); - if (format->version == -1) + if (format->version == -1) { clear_repository_format(format); + format->hash_algo = GIT_HASH_SHA1_LEGACY; + } return format->version; } @@ -1737,7 +1741,7 @@ const char *setup_git_directory_gently(int *nongit_ok) * configuration (including the per-repo config file that we * ignored previously). */ - git_config_clear(); + repo_config_clear(the_repository); /* * Let's assume that we are in a git repository. @@ -1864,6 +1868,8 @@ const char *setup_git_directory_gently(int *nongit_ok) the_repository->repository_format_partial_clone = repo_fmt.partial_clone; repo_fmt.partial_clone = NULL; + the_repository->repository_format_precious_objects = + repo_fmt.precious_objects; } } /* @@ -1871,7 +1877,7 @@ const char *setup_git_directory_gently(int *nongit_ok) * the core.precomposeunicode configuration, this * has to happen after the above block that finds * out where the repository is, i.e. a preparation - * for calling git_config_get_bool(). + * for calling repo_config_get_bool(). */ if (prefix) { prefix = precompose_string_if_needed(prefix); @@ -2222,21 +2228,21 @@ void initialize_repository_version(int hash_algo, * version will get adjusted by git-clone(1) once it has learned about * the remote repository's format. */ - if (hash_algo != GIT_HASH_SHA1 || + if (hash_algo != GIT_HASH_SHA1_LEGACY || ref_storage_format != REF_STORAGE_FORMAT_FILES) target_version = GIT_REPO_VERSION_READ; - if (hash_algo != GIT_HASH_SHA1 && hash_algo != GIT_HASH_UNKNOWN) - git_config_set("extensions.objectformat", - hash_algos[hash_algo].name); + if (hash_algo != GIT_HASH_SHA1_LEGACY && hash_algo != GIT_HASH_UNKNOWN) + repo_config_set(the_repository, "extensions.objectformat", + hash_algos[hash_algo].name); else if (reinit) - git_config_set_gently("extensions.objectformat", NULL); + repo_config_set_gently(the_repository, "extensions.objectformat", NULL); if (ref_storage_format != REF_STORAGE_FORMAT_FILES) - git_config_set("extensions.refstorage", - ref_storage_format_to_name(ref_storage_format)); + repo_config_set(the_repository, "extensions.refstorage", + ref_storage_format_to_name(ref_storage_format)); else if (reinit) - git_config_set_gently("extensions.refstorage", NULL); + repo_config_set_gently(the_repository, "extensions.refstorage", NULL); if (reinit) { struct strbuf config = STRBUF_INIT; @@ -2253,7 +2259,7 @@ void initialize_repository_version(int hash_algo, } strbuf_addf(&repo_version, "%d", target_version); - git_config_set("core.repositoryformatversion", repo_version.buf); + repo_config_set(the_repository, "core.repositoryformatversion", repo_version.buf); strbuf_release(&repo_version); } @@ -2331,9 +2337,9 @@ static int create_default_files(const char *template_path, * disk). */ copy_templates(template_path); - git_config_clear(); + repo_config_clear(the_repository); repo_settings_reset_shared_repository(the_repository); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); reinit = is_reinit(); @@ -2369,17 +2375,17 @@ static int create_default_files(const char *template_path, if (filemode && !reinit && (st1.st_mode & S_IXUSR)) filemode = 0; } - git_config_set("core.filemode", filemode ? "true" : "false"); + repo_config_set(the_repository, "core.filemode", filemode ? "true" : "false"); if (is_bare_repository()) - git_config_set("core.bare", "true"); + repo_config_set(the_repository, "core.bare", "true"); else { - git_config_set("core.bare", "false"); + repo_config_set(the_repository, "core.bare", "false"); /* allow template config file to override the default */ if (repo_settings_get_log_all_ref_updates(the_repository) == LOG_REFS_UNSET) - git_config_set("core.logallrefupdates", "true"); + repo_config_set(the_repository, "core.logallrefupdates", "true"); if (needs_work_tree_config(original_git_dir, work_tree)) - git_config_set("core.worktree", work_tree); + repo_config_set(the_repository, "core.worktree", work_tree); } if (!reinit) { @@ -2392,12 +2398,12 @@ static int create_default_files(const char *template_path, S_ISLNK(st1.st_mode)) unlink(path.buf); /* good */ else - git_config_set("core.symlinks", "false"); + repo_config_set(the_repository, "core.symlinks", "false"); /* Check if the filesystem is case-insensitive */ repo_git_path_replace(the_repository, &path, "CoNfIg"); if (!access(path.buf, F_OK)) - git_config_set("core.ignorecase", "true"); + repo_config_set(the_repository, "core.ignorecase", "true"); probe_utf8_pathname_composition(); } @@ -2481,6 +2487,18 @@ static int read_default_format_config(const char *key, const char *value, goto out; } + /* + * Enable the reftable format when "features.experimental" is enabled. + * "init.defaultRefFormat" takes precedence over this setting. + */ + if (!strcmp(key, "feature.experimental") && + cfg->ref_format == REF_STORAGE_FORMAT_UNKNOWN && + git_config_bool(key, value)) { + cfg->ref_format = REF_STORAGE_FORMAT_REFTABLE; + ret = 0; + goto out; + } + ret = 0; out: free(str); @@ -2541,6 +2559,8 @@ static void repository_format_configure(struct repository_format *repo_fmt, repo_fmt->ref_storage_format = ref_format; } else if (cfg.ref_format != REF_STORAGE_FORMAT_UNKNOWN) { repo_fmt->ref_storage_format = cfg.ref_format; + } else { + repo_fmt->ref_storage_format = REF_STORAGE_FORMAT_DEFAULT; } repo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format); } @@ -2590,7 +2610,7 @@ int init_db(const char *git_dir, const char *real_git_dir, * have set up the repository format such that we can evaluate * includeIf conditions correctly in the case of re-initialization. */ - git_config(platform_core_config, NULL); + repo_config(the_repository, platform_core_config, NULL); safe_create_dir(the_repository, git_dir, 0); @@ -2619,8 +2639,8 @@ int init_db(const char *git_dir, const char *real_git_dir, xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY); else BUG("invalid value for shared_repository"); - git_config_set("core.sharedrepository", buf); - git_config_set("receive.denyNonFastforwards", "true"); + repo_config_set(the_repository, "core.sharedrepository", buf); + repo_config_set(the_repository, "receive.denyNonFastforwards", "true"); } if (!(flags & INIT_DB_QUIET)) { @@ -149,7 +149,7 @@ struct repository_format { { \ .version = -1, \ .is_bare = -1, \ - .hash_algo = GIT_HASH_SHA1, \ + .hash_algo = GIT_HASH_DEFAULT, \ .ref_storage_format = REF_STORAGE_FORMAT_FILES, \ .unknown_extensions = STRING_LIST_INIT_DUP, \ .v1_only_extensions = STRING_LIST_INIT_DUP, \ diff --git a/sideband.c b/sideband.c index 251e9615ed..8f15b98a65 100644 --- a/sideband.c +++ b/sideband.c @@ -39,9 +39,9 @@ static int use_sideband_colors(void) if (use_sideband_colors_cached >= 0) return use_sideband_colors_cached; - if (!git_config_get_string_tmp(key, &value)) + if (!repo_config_get_string_tmp(the_repository, key, &value)) use_sideband_colors_cached = git_config_colorbool(key, value); - else if (!git_config_get_string_tmp("color.ui", &value)) + else if (!repo_config_get_string_tmp(the_repository, "color.ui", &value)) use_sideband_colors_cached = git_config_colorbool("color.ui", value); else use_sideband_colors_cached = GIT_COLOR_AUTO; @@ -49,7 +49,7 @@ static int use_sideband_colors(void) for (i = 0; i < ARRAY_SIZE(keywords); i++) { strbuf_reset(&sb); strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword); - if (git_config_get_string_tmp(sb.buf, &value)) + if (repo_config_get_string_tmp(the_repository, sb.buf, &value)) continue; color_parse(value, keywords[i].color); } @@ -8,55 +8,55 @@ #include "utf8.h" #include "date.h" -int starts_with(const char *str, const char *prefix) +bool starts_with(const char *str, const char *prefix) { for (; ; str++, prefix++) if (!*prefix) - return 1; + return true; else if (*str != *prefix) - return 0; + return false; } -int istarts_with(const char *str, const char *prefix) +bool istarts_with(const char *str, const char *prefix) { for (; ; str++, prefix++) if (!*prefix) - return 1; + return true; else if (tolower(*str) != tolower(*prefix)) - return 0; + return false; } -int starts_with_mem(const char *str, size_t len, const char *prefix) +bool starts_with_mem(const char *str, size_t len, const char *prefix) { const char *end = str + len; for (; ; str++, prefix++) { if (!*prefix) - return 1; + return true; else if (str == end || *str != *prefix) - return 0; + return false; } } -int skip_to_optional_arg_default(const char *str, const char *prefix, +bool skip_to_optional_arg_default(const char *str, const char *prefix, const char **arg, const char *def) { const char *p; if (!skip_prefix(str, prefix, &p)) - return 0; + return false; if (!*p) { if (arg) *arg = def; - return 1; + return true; } if (*p != '=') - return 0; + return false; if (arg) *arg = p + 1; - return 1; + return true; } /* @@ -660,9 +660,9 @@ char *xstrvfmt(const char *fmt, va_list ap); __attribute__((format (printf, 1, 2))) char *xstrfmt(const char *fmt, ...); -int starts_with(const char *str, const char *prefix); -int istarts_with(const char *str, const char *prefix); -int starts_with_mem(const char *str, size_t len, const char *prefix); +bool starts_with(const char *str, const char *prefix); +bool istarts_with(const char *str, const char *prefix); +bool starts_with_mem(const char *str, size_t len, const char *prefix); /* * If the string "str" is the same as the string in "prefix", then the "arg" @@ -678,16 +678,16 @@ int starts_with_mem(const char *str, size_t len, const char *prefix); * can be used instead of !strcmp(arg, "--key") and then * skip_prefix(arg, "--key=", &arg) to parse such an option. */ -int skip_to_optional_arg_default(const char *str, const char *prefix, +bool skip_to_optional_arg_default(const char *str, const char *prefix, const char **arg, const char *def); -static inline int skip_to_optional_arg(const char *str, const char *prefix, +static inline bool skip_to_optional_arg(const char *str, const char *prefix, const char **arg) { return skip_to_optional_arg_default(str, prefix, arg, ""); } -static inline int ends_with(const char *str, const char *suffix) +static inline bool ends_with(const char *str, const char *suffix) { size_t len; return strip_suffix(str, suffix, &len); diff --git a/string-list.c b/string-list.c index bf061fec56..53faaa8420 100644 --- a/string-list.c +++ b/string-list.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "string-list.h" @@ -17,19 +15,19 @@ void string_list_init_dup(struct string_list *list) /* if there is no exact match, point to the index where the entry could be * inserted */ -static int get_entry_index(const struct string_list *list, const char *string, - int *exact_match) +static size_t get_entry_index(const struct string_list *list, const char *string, + int *exact_match) { - int left = -1, right = list->nr; + size_t left = 0, right = list->nr; compare_strings_fn cmp = list->cmp ? list->cmp : strcmp; - while (left + 1 < right) { - int middle = left + (right - left) / 2; + while (left < right) { + size_t middle = left + (right - left) / 2; int compare = cmp(string, list->items[middle].string); if (compare < 0) right = middle; else if (compare > 0) - left = middle; + left = middle + 1; else { *exact_match = 1; return middle; @@ -40,14 +38,13 @@ static int get_entry_index(const struct string_list *list, const char *string, return right; } -/* returns -1-index if already exists */ -static int add_entry(int insert_at, struct string_list *list, const char *string) +static size_t add_entry(struct string_list *list, const char *string) { int exact_match = 0; - int index = insert_at != -1 ? insert_at : get_entry_index(list, string, &exact_match); + size_t index = get_entry_index(list, string, &exact_match); if (exact_match) - return -1 - index; + return index; ALLOC_GROW(list->items, list->nr+1, list->alloc); if (index < list->nr) @@ -63,10 +60,7 @@ static int add_entry(int insert_at, struct string_list *list, const char *string struct string_list_item *string_list_insert(struct string_list *list, const char *string) { - int index = add_entry(-1, list, string); - - if (index < 0) - index = -1 - index; + size_t index = add_entry(list, string); return list->items + index; } @@ -116,9 +110,9 @@ struct string_list_item *string_list_lookup(struct string_list *list, const char void string_list_remove_duplicates(struct string_list *list, int free_util) { if (list->nr > 1) { - int src, dst; + size_t dst = 1; compare_strings_fn cmp = list->cmp ? list->cmp : strcmp; - for (src = dst = 1; src < list->nr; src++) { + for (size_t src = 1; src < list->nr; src++) { if (!cmp(list->items[dst - 1].string, list->items[src].string)) { if (list->strdup_strings) free(list->items[src].string); @@ -134,8 +128,8 @@ void string_list_remove_duplicates(struct string_list *list, int free_util) int for_each_string_list(struct string_list *list, string_list_each_func_t fn, void *cb_data) { - int i, ret = 0; - for (i = 0; i < list->nr; i++) + int ret = 0; + for (size_t i = 0; i < list->nr; i++) if ((ret = fn(&list->items[i], cb_data))) break; return ret; @@ -144,8 +138,8 @@ int for_each_string_list(struct string_list *list, void filter_string_list(struct string_list *list, int free_util, string_list_each_func_t want, void *cb_data) { - int src, dst = 0; - for (src = 0; src < list->nr; src++) { + size_t dst = 0; + for (size_t src = 0; src < list->nr; src++) { if (want(&list->items[src], cb_data)) { list->items[dst++] = list->items[src]; } else { @@ -171,13 +165,12 @@ void string_list_remove_empty_items(struct string_list *list, int free_util) void string_list_clear(struct string_list *list, int free_util) { if (list->items) { - int i; if (list->strdup_strings) { - for (i = 0; i < list->nr; i++) + for (size_t i = 0; i < list->nr; i++) free(list->items[i].string); } if (free_util) { - for (i = 0; i < list->nr; i++) + for (size_t i = 0; i < list->nr; i++) free(list->items[i].util); } free(list->items); @@ -189,13 +182,12 @@ void string_list_clear(struct string_list *list, int free_util) void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc) { if (list->items) { - int i; if (clearfunc) { - for (i = 0; i < list->nr; i++) + for (size_t i = 0; i < list->nr; i++) clearfunc(list->items[i].util, list->items[i].string); } if (list->strdup_strings) { - for (i = 0; i < list->nr; i++) + for (size_t i = 0; i < list->nr; i++) free(list->items[i].string); } free(list->items); diff --git a/submodule-config.c b/submodule-config.c index 70324da383..1f19fe2077 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -983,7 +983,7 @@ int config_set_in_gitmodules_file_gently(const char *key, const char *value) { int ret; - ret = git_config_set_in_file_gently(GITMODULES_FILE, key, NULL, value); + ret = repo_config_set_in_file_gently(the_repository, GITMODULES_FILE, key, NULL, value); if (ret < 0) /* Maybe the user already did that, don't error out here */ warning(_("Could not update .gitmodules entry %s"), key); diff --git a/submodule.c b/submodule.c index f8373a9ea7..fff3c75570 100644 --- a/submodule.c +++ b/submodule.c @@ -2058,7 +2058,7 @@ void submodule_unset_core_worktree(const struct submodule *sub) submodule_name_to_gitdir(&config_path, the_repository, sub->name); strbuf_addstr(&config_path, "/config"); - if (git_config_set_in_file_gently(config_path.buf, "core.worktree", NULL, NULL)) + if (repo_config_set_in_file_gently(the_repository, config_path.buf, "core.worktree", NULL, NULL)) warning(_("Could not unset core.worktree setting in submodule '%s'"), sub->path); diff --git a/subprojects/expat.wrap b/subprojects/expat.wrap index 2e0427dcfd..0e9292f97b 100644 --- a/subprojects/expat.wrap +++ b/subprojects/expat.wrap @@ -1,13 +1,13 @@ [wrap-file] -directory = expat-2.6.3 -source_url = https://github.com/libexpat/libexpat/releases/download/R_2_6_3/expat-2.6.3.tar.xz -source_filename = expat-2.6.3.tar.bz2 -source_hash = 274db254a6979bde5aad404763a704956940e465843f2a9bd9ed7af22e2c0efc -patch_filename = expat_2.6.3-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/expat_2.6.3-1/get_patch -patch_hash = cf017fbe105e31428b2768360bd9be39094df4e948a1e8d1c54b6f7c76460cb1 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/expat_2.6.3-1/expat-2.6.3.tar.bz2 -wrapdb_version = 2.6.3-1 +directory = expat-2.7.1 +source_url = https://github.com/libexpat/libexpat/releases/download/R_2_7_1/expat-2.7.1.tar.xz +source_filename = expat-2.7.1.tar.bz2 +source_hash = 354552544b8f99012e5062f7d570ec77f14b412a3ff5c7d8d0dae62c0d217c30 +patch_filename = expat_2.7.1-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/expat_2.7.1-1/get_patch +patch_hash = fe28cbbc427a7c9787d08b969ad54d19f59d8dd18294b4a18651cecfc789d4ef +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/expat_2.7.1-1/expat-2.7.1.tar.bz2 +wrapdb_version = 2.7.1-1 [provide] expat = expat_dep diff --git a/subprojects/pcre2.wrap b/subprojects/pcre2.wrap index 7e18447254..f45c968e2f 100644 --- a/subprojects/pcre2.wrap +++ b/subprojects/pcre2.wrap @@ -1,13 +1,13 @@ [wrap-file] -directory = pcre2-10.44 -source_url = https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.44/pcre2-10.44.tar.bz2 -source_filename = pcre2-10.44.tar.bz2 -source_hash = d34f02e113cf7193a1ebf2770d3ac527088d485d4e047ed10e5d217c6ef5de96 -patch_filename = pcre2_10.44-2_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/pcre2_10.44-2/get_patch -patch_hash = 4336d422ee9043847e5e10dbbbd01940d4c9e5027f31ccdc33a7898a1ca94009 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/pcre2_10.44-2/pcre2-10.44.tar.bz2 -wrapdb_version = 10.44-2 +directory = pcre2-10.45 +source_url = https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.45/pcre2-10.45.tar.bz2 +source_filename = pcre2-10.45.tar.bz2 +source_hash = 21547f3516120c75597e5b30a992e27a592a31950b5140e7b8bfde3f192033c4 +patch_filename = pcre2_10.45-2_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/pcre2_10.45-2/get_patch +patch_hash = 7c6f34b703708652a404f9dc2769c67658c437b6043573295fa3428a9b7a6807 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/pcre2_10.45-2/pcre2-10.45.tar.bz2 +wrapdb_version = 10.45-2 [provide] libpcre2-8 = libpcre2_8 diff --git a/t/Makefile b/t/Makefile index 791e0a0978..757674e727 100644 --- a/t/Makefile +++ b/t/Makefile @@ -125,7 +125,6 @@ check-meson: @mkdir -p mesontmp && \ printf "%s\n" \ "integration_tests t[0-9][0-9][0-9][0-9]-*.sh" \ - "unit_test_programs unit-tests/t-*.c" \ "clar_test_suites unit-tests/u-*.c" | \ while read -r variable pattern; do \ awk "/^$$variable = \[\$$/ {flag=1 ; next } /^]$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047,\$$/, \"\"); print }" meson.build >mesontmp/meson.txt && \ diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c index 6967c8e25c..81ed93a05c 100644 --- a/t/helper/test-advise.c +++ b/t/helper/test-advise.c @@ -3,6 +3,7 @@ #include "test-tool.h" #include "advice.h" #include "config.h" +#include "environment.h" #include "setup.h" int cmd__advise_if_enabled(int argc, const char **argv) @@ -11,7 +12,7 @@ int cmd__advise_if_enabled(int argc, const char **argv) die("usage: %s <advice>", argv[0]); setup_git_directory(); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); /* * Any advice type can be used for testing, but NESTED_TAG was diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c index 3f23f21072..16a01669e4 100644 --- a/t/helper/test-bitmap.c +++ b/t/helper/test-bitmap.c @@ -10,6 +10,11 @@ static int bitmap_list_commits(void) return test_bitmap_commits(the_repository); } +static int bitmap_list_commits_with_offset(void) +{ + return test_bitmap_commits_with_offset(the_repository); +} + static int bitmap_dump_hashes(void) { return test_bitmap_hashes(the_repository); @@ -36,6 +41,8 @@ int cmd__bitmap(int argc, const char **argv) if (argc == 2 && !strcmp(argv[1], "list-commits")) return bitmap_list_commits(); + if (argc == 2 && !strcmp(argv[1], "list-commits-with-offset")) + return bitmap_list_commits_with_offset(); if (argc == 2 && !strcmp(argv[1], "dump-hashes")) return bitmap_dump_hashes(); if (argc == 2 && !strcmp(argv[1], "dump-pseudo-merges")) @@ -46,6 +53,7 @@ int cmd__bitmap(int argc, const char **argv) return bitmap_dump_pseudo_merge_objects(atoi(argv[2])); usage("\ttest-tool bitmap list-commits\n" + "\ttest-tool bitmap list-commits-with-offset\n" "\ttest-tool bitmap dump-hashes\n" "\ttest-tool bitmap dump-pseudo-merges\n" "\ttest-tool bitmap dump-pseudo-merge-commits <n>\n" diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c index 9aa2c5a592..3283544bd3 100644 --- a/t/helper/test-bloom.c +++ b/t/helper/test-bloom.c @@ -12,13 +12,13 @@ static struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS; static void add_string_to_filter(const char *data, struct bloom_filter *filter) { struct bloom_key key; - fill_bloom_key(data, strlen(data), &key, &settings); + bloom_key_fill(&key, data, strlen(data), &settings); printf("Hashes:"); for (size_t i = 0; i < settings.num_hashes; i++) printf("0x%08x|", key.hashes[i]); printf("\n"); add_key_to_filter(&key, filter, &settings); - clear_bloom_key(&key); + bloom_key_clear(&key); } static void print_bloom_filter(struct bloom_filter *filter) { @@ -61,13 +61,13 @@ int cmd__bloom(int argc, const char **argv) uint32_t hashed; if (argc < 3) usage(bloom_usage); - hashed = murmur3_seeded_v2(0, argv[2], strlen(argv[2])); + hashed = test_bloom_murmur3_seeded(0, argv[2], strlen(argv[2]), 2); printf("Murmur3 Hash with seed=0:0x%08x\n", hashed); } if (!strcmp(argv[1], "get_murmur3_seven_highbit")) { uint32_t hashed; - hashed = murmur3_seeded_v2(0, "\x99\xaa\xbb\xcc\xdd\xee\xff", 7); + hashed = test_bloom_murmur3_seeded(0, "\x99\xaa\xbb\xcc\xdd\xee\xff", 7, 2); printf("Murmur3 Hash with seed=0:0x%08x\n", hashed); } diff --git a/t/helper/test-config.c b/t/helper/test-config.c index 75e028ab2a..9f8cca7c48 100644 --- a/t/helper/test-config.c +++ b/t/helper/test-config.c @@ -32,10 +32,10 @@ * ascending order of priority from a config_set * constructed from files entered as arguments. * - * iterate -> iterate over all values using git_config(), and print some + * iterate -> iterate over all values using repo_config(), and print some * data for each * - * git_config_int -> iterate over all values using git_config() and print the + * git_config_int -> iterate over all values using repo_config() and print the * integer value for the entered key or die * * Examples: @@ -110,7 +110,7 @@ int cmd__config(int argc, const char **argv) fprintf(stderr, "Please, provide a command name on the command-line\n"); goto exit1; } else if (argc == 3 && !strcmp(argv[1], "get_value")) { - if (!git_config_get_value(argv[2], &v)) { + if (!repo_config_get_value(the_repository, argv[2], &v)) { if (!v) printf("(NULL)\n"); else @@ -121,7 +121,7 @@ int cmd__config(int argc, const char **argv) goto exit1; } } else if (argc == 3 && !strcmp(argv[1], "get_value_multi")) { - if (!git_config_get_value_multi(argv[2], &strptr)) { + if (!repo_config_get_value_multi(the_repository, argv[2], &strptr)) { for (i = 0; i < strptr->nr; i++) { v = strptr->items[i].string; if (!v) @@ -137,7 +137,7 @@ int cmd__config(int argc, const char **argv) } else if (argc == 3 && !strcmp(argv[1], "get")) { int ret; - if (!(ret = git_config_get(argv[2]))) + if (!(ret = repo_config_get(the_repository, argv[2]))) goto exit0; else if (ret == 1) printf("Value not found for \"%s\"\n", argv[2]); @@ -155,7 +155,7 @@ int cmd__config(int argc, const char **argv) BUG("Key \"%s\" has unknown return %d", argv[2], ret); goto exit1; } else if (argc == 3 && !strcmp(argv[1], "get_int")) { - if (!git_config_get_int(argv[2], &val)) { + if (!repo_config_get_int(the_repository, argv[2], &val)) { printf("%d\n", val); goto exit0; } else { @@ -163,7 +163,7 @@ int cmd__config(int argc, const char **argv) goto exit1; } } else if (argc == 3 && !strcmp(argv[1], "get_bool")) { - if (!git_config_get_bool(argv[2], &val)) { + if (!repo_config_get_bool(the_repository, argv[2], &val)) { printf("%d\n", val); goto exit0; } else { @@ -171,7 +171,7 @@ int cmd__config(int argc, const char **argv) goto exit1; } } else if (argc == 3 && !strcmp(argv[1], "get_string")) { - if (!git_config_get_string_tmp(argv[2], &v)) { + if (!repo_config_get_string_tmp(the_repository, argv[2], &v)) { printf("%s\n", v); goto exit0; } else { @@ -218,10 +218,10 @@ int cmd__config(int argc, const char **argv) goto exit1; } } else if (!strcmp(argv[1], "iterate")) { - git_config(iterate_cb, NULL); + repo_config(the_repository, iterate_cb, NULL); goto exit0; } else if (argc == 3 && !strcmp(argv[1], "git_config_int")) { - git_config(parse_int_cb, (void *) argv[2]); + repo_config(the_repository, parse_int_cb, (void *) argv[2]); goto exit0; } diff --git a/t/helper/test-delta.c b/t/helper/test-delta.c index 6bc787a474..52ea00c937 100644 --- a/t/helper/test-delta.c +++ b/t/helper/test-delta.c @@ -11,6 +11,7 @@ #include "test-tool.h" #include "git-compat-util.h" #include "delta.h" +#include "strbuf.h" static const char usage_str[] = "test-tool delta (-d|-p) <from_file> <data_file> <out_file>"; @@ -18,68 +19,38 @@ static const char usage_str[] = int cmd__delta(int argc, const char **argv) { int fd; - struct stat st; - void *from_buf = NULL, *data_buf = NULL, *out_buf = NULL; - unsigned long from_size, data_size, out_size; - int ret = 1; + struct strbuf from = STRBUF_INIT, data = STRBUF_INIT; + char *out_buf; + unsigned long out_size; - if (argc != 5 || (strcmp(argv[1], "-d") && strcmp(argv[1], "-p"))) { - fprintf(stderr, "usage: %s\n", usage_str); - return 1; - } + if (argc != 5 || (strcmp(argv[1], "-d") && strcmp(argv[1], "-p"))) + usage(usage_str); - fd = open(argv[2], O_RDONLY); - if (fd < 0 || fstat(fd, &st)) { - perror(argv[2]); - return 1; - } - from_size = st.st_size; - from_buf = xmalloc(from_size); - if (read_in_full(fd, from_buf, from_size) < 0) { - perror(argv[2]); - close(fd); - goto cleanup; - } - close(fd); - - fd = open(argv[3], O_RDONLY); - if (fd < 0 || fstat(fd, &st)) { - perror(argv[3]); - goto cleanup; - } - data_size = st.st_size; - data_buf = xmalloc(data_size); - if (read_in_full(fd, data_buf, data_size) < 0) { - perror(argv[3]); - close(fd); - goto cleanup; - } - close(fd); + if (strbuf_read_file(&from, argv[2], 0) < 0) + die_errno("unable to read '%s'", argv[2]); + if (strbuf_read_file(&data, argv[3], 0) < 0) + die_errno("unable to read '%s'", argv[3]); if (argv[1][1] == 'd') - out_buf = diff_delta(from_buf, from_size, - data_buf, data_size, + out_buf = diff_delta(from.buf, from.len, + data.buf, data.len, &out_size, 0); else - out_buf = patch_delta(from_buf, from_size, - data_buf, data_size, + out_buf = patch_delta(from.buf, from.len, + data.buf, data.len, &out_size); - if (!out_buf) { - fprintf(stderr, "delta operation failed (returned NULL)\n"); - goto cleanup; - } + if (!out_buf) + die("delta operation failed (returned NULL)"); - fd = open (argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666); - if (fd < 0 || write_in_full(fd, out_buf, out_size) < 0) { - perror(argv[4]); - goto cleanup; - } + fd = xopen(argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (write_in_full(fd, out_buf, out_size) < 0) + die_errno("write(%s)", argv[4]); + if (close(fd) < 0) + die_errno("close(%s)", argv[4]); - ret = 0; -cleanup: - free(from_buf); - free(data_buf); + strbuf_release(&from); + strbuf_release(&data); free(out_buf); - return ret; + return 0; } diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index 7782ae585e..16a3145c3a 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -137,6 +137,11 @@ static void perf_hashmap(unsigned int method, unsigned int rounds) * Read stdin line by line and print result of commands to stdout: * * perfhashmap method rounds -> test hashmap.[ch] performance + * + * NOTE: this is not used by any of our mechanized build & test + * procedure, after 3469a236 (t: port helper/test-hashmap.c to + * unit-tests/t-hashmap.c, 2024-08-03). See the log message of that + * commit for the reason why this is still here. */ int cmd__hashmap(int argc UNUSED, const char **argv UNUSED) { diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index f2663dd0c0..68579d83f3 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -131,6 +131,7 @@ int cmd__parse_options(int argc, const char **argv) .short_name = 'B', .long_name = "no-fear", .value = &boolean, + .precision = sizeof(boolean), .help = "be brave", .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, .defval = 1, @@ -148,9 +149,16 @@ int cmd__parse_options(int argc, const char **argv) OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1), OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2), - OPT_CALLBACK_F(0, "mode34", &integer, "(3|4)", - "set integer to 3 or 4 (cmdmode option)", - PARSE_OPT_CMDMODE, mode34_callback), + { + .type = OPTION_CALLBACK, + .long_name = "mode34", + .value = &integer, + .precision = sizeof(integer), + .argh = "(3|4)", + .help = "set integer to 3 or 4 (cmdmode option)", + .flags = PARSE_OPT_CMDMODE, + .callback = mode34_callback, + }, OPT_CALLBACK('L', "length", &integer, "str", "get length of <str>", length_callback), OPT_FILENAME('F', "file", &file, "set file to <file>"), @@ -170,6 +178,7 @@ int cmd__parse_options(int argc, const char **argv) .type = OPTION_COUNTUP, .short_name = '+', .value = &boolean, + .precision = sizeof(boolean), .help = "same as -b", .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, }, @@ -177,6 +186,7 @@ int cmd__parse_options(int argc, const char **argv) .type = OPTION_COUNTUP, .long_name = "ambiguous", .value = &ambiguous, + .precision = sizeof(ambiguous), .help = "positive ambiguity", .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, }, @@ -184,6 +194,7 @@ int cmd__parse_options(int argc, const char **argv) .type = OPTION_COUNTUP, .long_name = "no-ambiguous", .value = &ambiguous, + .precision = sizeof(ambiguous), .help = "negative ambiguity", .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, }, diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c index e277dde8e7..9ae71cefb3 100644 --- a/t/helper/test-read-cache.c +++ b/t/helper/test-read-cache.c @@ -2,6 +2,7 @@ #include "test-tool.h" #include "config.h" +#include "environment.h" #include "read-cache-ll.h" #include "repository.h" #include "setup.h" @@ -19,7 +20,7 @@ int cmd__read_cache(int argc, const char **argv) if (argc == 2) cnt = strtol(argv[1], NULL, 0); setup_git_directory(); - git_config(git_default_config, NULL); + repo_config(the_repository, git_default_config, NULL); for (i = 0; i < cnt; i++) { repo_read_index(the_repository); diff --git a/t/helper/test-string-list.c b/t/helper/test-string-list.c index 6f10c5a435..6be0cdb8e2 100644 --- a/t/helper/test-string-list.c +++ b/t/helper/test-string-list.c @@ -1,105 +1,9 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "test-tool.h" #include "strbuf.h" #include "string-list.h" -/* - * Parse an argument into a string list. arg should either be a - * ':'-separated list of strings, or "-" to indicate an empty string - * list (as opposed to "", which indicates a string list containing a - * single empty string). list->strdup_strings must be set. - */ -static void parse_string_list(struct string_list *list, const char *arg) -{ - if (!strcmp(arg, "-")) - return; - - (void)string_list_split(list, arg, ':', -1); -} - -static void write_list(const struct string_list *list) -{ - int i; - for (i = 0; i < list->nr; i++) - printf("[%d]: \"%s\"\n", i, list->items[i].string); -} - -static void write_list_compact(const struct string_list *list) -{ - int i; - if (!list->nr) - printf("-\n"); - else { - printf("%s", list->items[0].string); - for (i = 1; i < list->nr; i++) - printf(":%s", list->items[i].string); - printf("\n"); - } -} - -static int prefix_cb(struct string_list_item *item, void *cb_data) -{ - const char *prefix = (const char *)cb_data; - return starts_with(item->string, prefix); -} - int cmd__string_list(int argc, const char **argv) { - if (argc == 5 && !strcmp(argv[1], "split")) { - struct string_list list = STRING_LIST_INIT_DUP; - int i; - const char *s = argv[2]; - int delim = *argv[3]; - int maxsplit = atoi(argv[4]); - - i = string_list_split(&list, s, delim, maxsplit); - printf("%d\n", i); - write_list(&list); - string_list_clear(&list, 0); - return 0; - } - - if (argc == 5 && !strcmp(argv[1], "split_in_place")) { - struct string_list list = STRING_LIST_INIT_NODUP; - int i; - char *s = xstrdup(argv[2]); - const char *delim = argv[3]; - int maxsplit = atoi(argv[4]); - - i = string_list_split_in_place(&list, s, delim, maxsplit); - printf("%d\n", i); - write_list(&list); - string_list_clear(&list, 0); - free(s); - return 0; - } - - if (argc == 4 && !strcmp(argv[1], "filter")) { - /* - * Retain only the items that have the specified prefix. - * Arguments: list|- prefix - */ - struct string_list list = STRING_LIST_INIT_DUP; - const char *prefix = argv[3]; - - parse_string_list(&list, argv[2]); - filter_string_list(&list, 0, prefix_cb, (void *)prefix); - write_list_compact(&list); - string_list_clear(&list, 0); - return 0; - } - - if (argc == 3 && !strcmp(argv[1], "remove_duplicates")) { - struct string_list list = STRING_LIST_INIT_DUP; - - parse_string_list(&list, argv[2]); - string_list_remove_duplicates(&list, 0); - write_list_compact(&list); - string_list_clear(&list, 0); - return 0; - } - if (argc == 2 && !strcmp(argv[1], "sort")) { struct string_list list = STRING_LIST_INIT_NODUP; struct strbuf sb = STRBUF_INIT; diff --git a/t/helper/test-truncate.c b/t/helper/test-truncate.c index 3931deaec7..2820cc7ed7 100644 --- a/t/helper/test-truncate.c +++ b/t/helper/test-truncate.c @@ -21,5 +21,8 @@ int cmd__truncate(int argc, const char **argv) if (ftruncate(fd, (off_t) sz) < 0) die_errno("failed to truncate file"); + + close(fd); + return 0; } diff --git a/t/helper/test-userdiff.c b/t/helper/test-userdiff.c index 94c48ababb..aa3a9894d2 100644 --- a/t/helper/test-userdiff.c +++ b/t/helper/test-userdiff.c @@ -41,7 +41,7 @@ int cmd__userdiff(int argc, const char **argv) if (want & USERDIFF_DRIVER_TYPE_CUSTOM) { setup_git_directory(); - git_config(cmd__userdiff_config, NULL); + repo_config(the_repository, cmd__userdiff_config, NULL); } for_each_userdiff_driver(driver_cb, &want); diff --git a/t/meson.build b/t/meson.build index 6d7fe6b117..bbeba1a8d5 100644 --- a/t/meson.build +++ b/t/meson.build @@ -8,9 +8,18 @@ clar_test_suites = [ 'unit-tests/u-oidmap.c', 'unit-tests/u-oidtree.c', 'unit-tests/u-prio-queue.c', + 'unit-tests/u-reftable-basics.c', + 'unit-tests/u-reftable-block.c', + 'unit-tests/u-reftable-merged.c', + 'unit-tests/u-reftable-pq.c', + 'unit-tests/u-reftable-readwrite.c', + 'unit-tests/u-reftable-record.c', + 'unit-tests/u-reftable-stack.c', + 'unit-tests/u-reftable-table.c', 'unit-tests/u-reftable-tree.c', 'unit-tests/u-strbuf.c', 'unit-tests/u-strcmp-offset.c', + 'unit-tests/u-string-list.c', 'unit-tests/u-strvec.c', 'unit-tests/u-trailer.c', 'unit-tests/u-urlmatch-normalization.c', @@ -19,7 +28,8 @@ clar_test_suites = [ clar_sources = [ 'unit-tests/clar/clar.c', 'unit-tests/unit-test.c', - 'unit-tests/lib-oid.c' + 'unit-tests/lib-oid.c', + 'unit-tests/lib-reftable.c' ] clar_decls_h = custom_target( @@ -49,37 +59,13 @@ clar_sources += custom_target( clar_unit_tests = executable('unit-tests', sources: clar_sources + clar_test_suites, + c_args: [ + '-DGIT_CLAR_DECLS_H="' + clar_decls_h.full_path() + '"', + ], dependencies: [libgit_commonmain], ) test('unit-tests', clar_unit_tests, kwargs: test_kwargs) -unit_test_programs = [ - 'unit-tests/t-reftable-basics.c', - 'unit-tests/t-reftable-block.c', - 'unit-tests/t-reftable-merged.c', - 'unit-tests/t-reftable-pq.c', - 'unit-tests/t-reftable-readwrite.c', - 'unit-tests/t-reftable-record.c', - 'unit-tests/t-reftable-stack.c', - 'unit-tests/t-reftable-table.c', -] - -foreach unit_test_program : unit_test_programs - unit_test_name = fs.stem(unit_test_program) - unit_test = executable(unit_test_name, - sources: [ - 'unit-tests/test-lib.c', - 'unit-tests/lib-reftable.c', - unit_test_program, - ], - dependencies: [libgit_commonmain], - ) - test(unit_test_name, unit_test, - workdir: meson.current_source_dir(), - kwargs: test_kwargs, - ) -endforeach - subdir('helper') integration_tests = [ @@ -123,7 +109,6 @@ integration_tests = [ 't0060-path-utils.sh', 't0061-run-command.sh', 't0062-revision-walking.sh', - 't0063-string-list.sh', 't0066-dir-iterator.sh', 't0067-parse_pathspec_file.sh', 't0068-for-each-repo.sh', @@ -1116,6 +1101,7 @@ benchmarks = [ 'perf/p1450-fsck.sh', 'perf/p1451-fsck-skip-list.sh', 'perf/p1500-graph-walks.sh', + 'perf/p1501-rev-parse-oneline.sh', 'perf/p2000-sparse-operations.sh', 'perf/p3400-rebase.sh', 'perf/p3404-rebase-interactive.sh', @@ -1162,8 +1148,6 @@ benchmarks = [ # sufficient to catch missing test suites in our CI though. foreach glob, tests : { 't[0-9][0-9][0-9][0-9]-*.sh': integration_tests, - 'perf/p[0-9][0-9][0-9][0-9]-*.sh': benchmarks, - 'unit-tests/t-*.c': unit_test_programs, 'unit-tests/u-*.c': clar_test_suites, } actual_tests = run_command(shell, '-c', 'ls ' + glob, @@ -1230,4 +1214,4 @@ if perl.found() and time.found() timeout: 0, ) endforeach -endif +endif
\ No newline at end of file diff --git a/t/perf/p1501-rev-parse-oneline.sh b/t/perf/p1501-rev-parse-oneline.sh new file mode 100755 index 0000000000..538fa9c404 --- /dev/null +++ b/t/perf/p1501-rev-parse-oneline.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +test_description='Test :/ object name notation' + +. ./perf-lib.sh + +test_perf_fresh_repo + +# +# Creates lots of merges to make history traversal costly. In +# particular it creates 2^($max_level-1)-1 2-way merges on top of +# 2^($max_level-1) root commits. E.g., the commit history looks like +# this for a $max_level of 3: +# +# _1_ +# / \ +# 2 3 +# / \ / \ +# 4 5 6 7 +# +# The numbers are the fast-import marks, which also are the commit +# messages. 1 is the HEAD commit and a merge, 2 and 3 are also merges, +# 4-7 are the root commits. +# +build_history () { + local max_level="$1" && + local level="${2:-1}" && + local mark="${3:-1}" && + if test $level -eq $max_level + then + echo "reset refs/heads/master" && + echo "from $ZERO_OID" && + echo "commit refs/heads/master" && + echo "mark :$mark" && + echo "committer C <c@example.com> 1234567890 +0000" && + echo "data <<EOF" && + echo "$mark" && + echo "EOF" + else + local level1=$((level+1)) && + local mark1=$((2*mark)) && + local mark2=$((2*mark+1)) && + build_history $max_level $level1 $mark1 && + build_history $max_level $level1 $mark2 && + echo "commit refs/heads/master" && + echo "mark :$mark" && + echo "committer C <c@example.com> 1234567890 +0000" && + echo "data <<EOF" && + echo "$mark" && + echo "EOF" && + echo "from :$mark1" && + echo "merge :$mark2" + fi +} + +test_expect_success 'setup' ' + build_history 16 | git fast-import && + git log --format="%H %s" --reverse >commits && + sed -n -e "s/ .*$//p" -e "q" <commits >expect && + sed -n -e "s/^.* //p" -e "q" <commits >needle +' + +test_perf "rev-parse :/$(cat needle)" ' + git rev-parse :/$(cat needle) >actual +' + +test_expect_success 'verify result' ' + test_cmp expect actual +' + +test_done diff --git a/t/t0001-init.sh b/t/t0001-init.sh index f11a40811f..f593c53687 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -658,6 +658,17 @@ test_expect_success 'init warns about invalid init.defaultRefFormat' ' test_cmp expected actual ' +test_expect_success 'default ref format' ' + test_when_finished "rm -rf refformat" && + ( + sane_unset GIT_DEFAULT_REF_FORMAT && + git init refformat + ) && + git version --build-options | sed -ne "s/^default-ref-format: //p" >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual +' + backends="files reftable" for format in $backends do @@ -738,6 +749,40 @@ test_expect_success "GIT_DEFAULT_REF_FORMAT= overrides init.defaultRefFormat" ' test_cmp expect actual ' +test_expect_success "init with feature.experimental=true" ' + test_when_finished "rm -rf refformat" && + test_config_global feature.experimental true && + ( + sane_unset GIT_DEFAULT_REF_FORMAT && + git init refformat + ) && + echo reftable >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success "init.defaultRefFormat overrides feature.experimental=true" ' + test_when_finished "rm -rf refformat" && + test_config_global feature.experimental true && + test_config_global init.defaultRefFormat files && + ( + sane_unset GIT_DEFAULT_REF_FORMAT && + git init refformat + ) && + echo files >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual +' + +test_expect_success "GIT_DEFAULT_REF_FORMAT= overrides feature.experimental=true" ' + test_when_finished "rm -rf refformat" && + test_config_global feature.experimental true && + GIT_DEFAULT_REF_FORMAT=files git init refformat && + echo files >expect && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual +' + for from_format in $backends do test_expect_success "re-init with same format ($from_format)" ' diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh deleted file mode 100755 index aac63ba506..0000000000 --- a/t/t0063-string-list.sh +++ /dev/null @@ -1,142 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2012 Michael Haggerty -# - -test_description='Test string list functionality' - -. ./test-lib.sh - -test_split () { - cat >expected && - test_expect_success "split $1 at $2, max $3" " - test-tool string-list split '$1' '$2' '$3' >actual && - test_cmp expected actual && - test-tool string-list split_in_place '$1' '$2' '$3' >actual && - test_cmp expected actual - " -} - -test_split_in_place() { - cat >expected && - test_expect_success "split (in place) $1 at $2, max $3" " - test-tool string-list split_in_place '$1' '$2' '$3' >actual && - test_cmp expected actual - " -} - -test_split "foo:bar:baz" ":" "-1" <<EOF -3 -[0]: "foo" -[1]: "bar" -[2]: "baz" -EOF - -test_split "foo:bar:baz" ":" "0" <<EOF -1 -[0]: "foo:bar:baz" -EOF - -test_split "foo:bar:baz" ":" "1" <<EOF -2 -[0]: "foo" -[1]: "bar:baz" -EOF - -test_split "foo:bar:baz" ":" "2" <<EOF -3 -[0]: "foo" -[1]: "bar" -[2]: "baz" -EOF - -test_split "foo:bar:" ":" "-1" <<EOF -3 -[0]: "foo" -[1]: "bar" -[2]: "" -EOF - -test_split "" ":" "-1" <<EOF -1 -[0]: "" -EOF - -test_split ":" ":" "-1" <<EOF -2 -[0]: "" -[1]: "" -EOF - -test_split_in_place "foo:;:bar:;:baz:;:" ":;" "-1" <<EOF -10 -[0]: "foo" -[1]: "" -[2]: "" -[3]: "bar" -[4]: "" -[5]: "" -[6]: "baz" -[7]: "" -[8]: "" -[9]: "" -EOF - -test_split_in_place "foo:;:bar:;:baz" ":;" "0" <<EOF -1 -[0]: "foo:;:bar:;:baz" -EOF - -test_split_in_place "foo:;:bar:;:baz" ":;" "1" <<EOF -2 -[0]: "foo" -[1]: ";:bar:;:baz" -EOF - -test_split_in_place "foo:;:bar:;:baz" ":;" "2" <<EOF -3 -[0]: "foo" -[1]: "" -[2]: ":bar:;:baz" -EOF - -test_split_in_place "foo:;:bar:;:" ":;" "-1" <<EOF -7 -[0]: "foo" -[1]: "" -[2]: "" -[3]: "bar" -[4]: "" -[5]: "" -[6]: "" -EOF - -test_expect_success "test filter_string_list" ' - test "x-" = "x$(test-tool string-list filter - y)" && - test "x-" = "x$(test-tool string-list filter no y)" && - test yes = "$(test-tool string-list filter yes y)" && - test yes = "$(test-tool string-list filter no:yes y)" && - test yes = "$(test-tool string-list filter yes:no y)" && - test y1:y2 = "$(test-tool string-list filter y1:y2 y)" && - test y2:y1 = "$(test-tool string-list filter y2:y1 y)" && - test "x-" = "x$(test-tool string-list filter x1:x2 y)" -' - -test_expect_success "test remove_duplicates" ' - test "x-" = "x$(test-tool string-list remove_duplicates -)" && - test "x" = "x$(test-tool string-list remove_duplicates "")" && - test a = "$(test-tool string-list remove_duplicates a)" && - test a = "$(test-tool string-list remove_duplicates a:a)" && - test a = "$(test-tool string-list remove_duplicates a:a:a:a:a)" && - test a:b = "$(test-tool string-list remove_duplicates a:b)" && - test a:b = "$(test-tool string-list remove_duplicates a:a:b)" && - test a:b = "$(test-tool string-list remove_duplicates a:b:b)" && - test a:b:c = "$(test-tool string-list remove_duplicates a:b:c)" && - test a:b:c = "$(test-tool string-list remove_duplicates a:a:b:c)" && - test a:b:c = "$(test-tool string-list remove_duplicates a:b:b:c)" && - test a:b:c = "$(test-tool string-list remove_duplicates a:b:c:c)" && - test a:b:c = "$(test-tool string-list remove_duplicates a:a:b:b:c:c)" && - test a:b:c = "$(test-tool string-list remove_duplicates a:a:a:b:b:b:c:c:c)" -' - -test_done diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index f123ef1e36..1f61b666a7 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -197,7 +197,7 @@ $content" # FIXME: %(rest) is incompatible with object names that include whitespace, # e.g. HEAD:path/to/a/file with spaces. Use the resolved OID as input to # test this instead of the raw object name. - if echo "$object_name" | grep " "; then + if echo "$object_name" | grep -q " "; then test_rest=test_expect_failure else test_rest=test_expect_success diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index 64658b3ba5..de076293b6 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -252,9 +252,9 @@ test_expect_success '--literally complains about non-standard types' ' test_must_fail git hash-object -t bogus --literally --stdin ' -test_expect_success '--stdin outside of repository (uses SHA-1)' ' +test_expect_success '--stdin outside of repository (uses default hash)' ' nongit git hash-object --stdin <hello >actual && - echo "$(test_oid --hash=sha1 hello)" >expect && + echo "$(test_oid --hash=builtin hello)" >expect && test_cmp expect actual ' diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index 7359af02a2..96648a6e5d 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -2349,4 +2349,23 @@ test_expect_success 'update-ref should also create reflog for HEAD' ' test_cmp expect actual ' +test_expect_success REFFILES 'empty directories are pruned when aborting a transaction' ' + test_path_is_missing .git/refs/heads/nested && + git update-ref --stdin <<-EOF && + create refs/heads/nested/something HEAD + prepare + abort + EOF + test_path_is_missing .git/refs/heads/nested +' + +test_expect_success REFFILES 'empty directories are pruned when not committing' ' + test_path_is_missing .git/refs/heads/nested && + git update-ref --stdin <<-EOF && + create refs/heads/nested/something HEAD + prepare + EOF + test_path_is_missing .git/refs/heads/nested +' + test_done diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 42b501f163..e30f87a358 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -673,4 +673,32 @@ test_expect_success 'reflog drop --all with reference' ' ) ' +test_expect_success 'expire with pattern config' ' + # Split refs/heads/ into two roots so we can apply config to each. Make + # two branches per root to verify that config is applied correctly + # multiple times. + git branch root1/branch1 && + git branch root1/branch2 && + git branch root2/branch1 && + git branch root2/branch2 && + + test_config "gc.reflogexpire" "never" && + test_config "gc.refs/heads/root2/*.reflogExpire" "now" && + git reflog expire \ + root1/branch1 root1/branch2 \ + root2/branch1 root2/branch2 && + + cat >expect <<-\EOF && + root1/branch1@{0} + root1/branch2@{0} + EOF + git log -g --branches="root*" --format=%gD >actual.raw && + # The sole reflog entry of each branch points to the same commit, so + # the order in which they are shown is nondeterministic. We just care + # about the what was expired (and what was not), so sort to get a known + # order. + sort <actual.raw >actual.sorted && + test_cmp expect actual.sorted +' + test_done diff --git a/t/t1517-outside-repo.sh b/t/t1517-outside-repo.sh index 6824581317..8f59b867f2 100755 --- a/t/t1517-outside-repo.sh +++ b/t/t1517-outside-repo.sh @@ -114,4 +114,11 @@ test_expect_success 'update-server-info does not crash with -h' ' test_grep "[Uu]sage: git update-server-info " usage ' +test_expect_success 'prune does not crash with -h' ' + test_expect_code 129 git prune -h >usage && + test_grep "[Uu]sage: git prune " usage && + test_expect_code 129 nongit git prune -h >usage && + test_grep "[Uu]sage: git prune " usage +' + test_done diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh index 26b42a526a..5d093e3a7a 100755 --- a/t/t3415-rebase-autosquash.sh +++ b/t/t3415-rebase-autosquash.sh @@ -394,6 +394,16 @@ test_expect_success 'autosquash with empty custom instructionFormat' ' ) ' +test_expect_success 'autosquash with invalid custom instructionFormat' ' + git reset --hard base && + test_commit invalid-instructionFormat-test && + ( + test_must_fail git -c rebase.instructionFormat=blah \ + rebase --autosquash --force-rebase -i HEAD^ && + test_path_is_missing .git/rebase-merge + ) +' + set_backup_editor () { write_script backup-editor.sh <<-\EOF cp "$1" .git/backup-"$(basename "$1")" diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 127216f722..b8a8dd77e7 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -328,6 +328,19 @@ 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' ' + git checkout -b branch-a && + test_commit A F1 && + git checkout -b branch-b HEAD^ && + test_commit B F1 && + test_must_fail git rebase branch-a && + printf "B\nA\n" >F1 && + git add F1 && + GIT_EDITOR="cat >actual" git -c core.commentChar=auto rebase --continue && + # Check that "#" is still the comment character. + test_grep "^# Changes to be committed" actual +' + test_orig_head_helper () { test_when_finished 'git rebase --abort && git checkout topic && diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index b8a05d95f3..04d2a19835 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -63,7 +63,7 @@ test_expect_success 'setup (initial)' ' ' test_expect_success 'status works (initial)' ' git add -i </dev/null >output && - grep "+1/-0 *+2/-0 file" output + test_grep "+1/-0 *+2/-0 file" output ' test_expect_success 'setup expected' ' @@ -86,7 +86,7 @@ test_expect_success 'revert works (initial)' ' git add file && test_write_lines r 1 | git add -i && git ls-files >output && - ! grep . output + test_grep ! . output ' test_expect_success 'add untracked (multiple)' ' @@ -109,7 +109,7 @@ test_expect_success 'setup (commit)' ' ' test_expect_success 'status works (commit)' ' git add -i </dev/null >output && - grep "+1/-0 *+2/-0 file" output + test_grep "+1/-0 *+2/-0 file" output ' test_expect_success 'update can stage deletions' ' @@ -141,7 +141,7 @@ test_expect_success 'revert works (commit)' ' git add file && test_write_lines r 1 | git add -i && git add -i </dev/null >output && - grep "unchanged *+3/-0 file" output + test_grep "unchanged *+3/-0 file" output ' test_expect_success 'reject multi-key input' ' @@ -185,7 +185,7 @@ test_expect_success 'setup fake editor' ' test_expect_success 'bad edit rejected' ' git reset && test_write_lines e n d | git add -p >output && - grep "hunk does not apply" output + test_grep "hunk does not apply" output ' test_expect_success 'setup patch' ' @@ -198,7 +198,7 @@ test_expect_success 'setup patch' ' test_expect_success 'garbage edit rejected' ' git reset && test_write_lines e n d | git add -p >output && - grep "hunk does not apply" output + test_grep "hunk does not apply" output ' test_expect_success 'setup patch' ' @@ -313,8 +313,8 @@ test_expect_success FILEMODE 'stage mode and hunk' ' chmod +x file && printf "y\\ny\\n" | git add -p && git diff --cached file >out && - grep "new mode" out && - grep "+content" out && + test_grep "new mode" out && + test_grep "+content" out && git diff file >out && test_must_be_empty out ' @@ -636,7 +636,7 @@ test_expect_success 'split hunk "add -p (edit)"' ' printf "%s\n" s e q n q q | EDITOR=: git add -p && git diff >actual && - ! grep "^+15" actual + test_grep ! "^+15" actual ' test_expect_success 'split hunk "add -p (no, yes, edit)"' ' @@ -648,7 +648,7 @@ test_expect_success 'split hunk "add -p (no, yes, edit)"' ' EDITOR=: git add -p 2>error && test_must_be_empty error && git diff >actual && - ! grep "^+31" actual + test_grep ! "^+31" actual ' test_expect_success 'split hunk with incomplete line at end' ' @@ -682,7 +682,7 @@ test_expect_success 'edit, adding lines to the first hunk' ' EDITOR=./fake_editor.sh git add -p 2>error && test_must_be_empty error && git diff --cached >actual && - grep "^+22" actual + test_grep "^+22" actual ' test_expect_success 'patch mode ignores unmerged entries' ' @@ -696,7 +696,7 @@ test_expect_success 'patch mode ignores unmerged entries' ' test_must_fail git merge side && echo changed >non-conflict.t && echo y | git add -p >output && - ! grep a/conflict.t output && + test_grep ! a/conflict.t output && cat >expected <<-\EOF && * Unmerged path conflict.t diff --git a/non-conflict.t b/non-conflict.t @@ -728,7 +728,7 @@ test_expect_success 'diffs can be colorized' ' # We do not want to depend on the exact coloring scheme # git uses for diffs, so just check that we saw some kind of color. - grep "$(printf "\\033")" output + test_grep "$(printf "\\033")" output ' test_expect_success 'colors can be overridden' ' @@ -743,7 +743,7 @@ test_expect_success 'colors can be overridden' ' -c color.interactive.error=blue \ add -i 2>err.raw <input && test_decode_color <err.raw >err && - grep "<BLUE>Huh (trigger)?<RESET>" err && + test_grep "<BLUE>Huh (trigger)?<RESET>" err && test_write_lines help quit >input && force_color git \ @@ -863,7 +863,7 @@ test_expect_success 'colorized diffs respect diff.wsErrorHighlight' ' printf y >y && force_color git -c diff.wsErrorHighlight=all add -p >output.raw 2>&1 <y && test_decode_color <output.raw >output && - grep "old<" output + test_grep "old<" output ' test_expect_success 'diffFilter filters diff' ' @@ -876,7 +876,7 @@ test_expect_success 'diffFilter filters diff' ' # avoid depending on the exact coloring or content of the prompts, # and just make sure we saw our diff prefixed - grep foo:.*content output + test_grep foo:.*content output ' test_expect_success 'detect bogus diffFilter output' ' @@ -886,7 +886,7 @@ test_expect_success 'detect bogus diffFilter output' ' test_config interactive.diffFilter "sed 6d" && printf y >y && force_color test_must_fail git add -p <y >output 2>&1 && - grep "mismatched output" output + test_grep "mismatched output" output ' test_expect_success 'handle iffy colored hunk headers' ' @@ -896,7 +896,7 @@ test_expect_success 'handle iffy colored hunk headers' ' printf n >n && force_color git -c interactive.diffFilter="sed s/.*@@.*/XX/" \ add -p >output 2>&1 <n && - grep "^XX$" output + test_grep "^XX$" output ' test_expect_success 'handle very large filtered diff' ' @@ -1002,7 +1002,7 @@ test_expect_success 'add -p does not expand argument lists' ' # update it, but we want to be sure that our "." pathspec # was not expanded into the argument list of any command. # So look only for "not-changed". - ! grep -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out + test_grep ! -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out ' test_expect_success 'hunk-editing handles custom comment char' ' @@ -1072,21 +1072,21 @@ test_expect_success 'setup different kinds of dirty submodules' ' test_expect_success 'status ignores dirty submodules (except HEAD)' ' git -C for-submodules add -i </dev/null >output && - grep dirty-head output && - grep dirty-both-ways output && - ! grep dirty-otherwise output + test_grep dirty-head output && + test_grep dirty-both-ways output && + test_grep ! dirty-otherwise output ' test_expect_success 'handle submodules' ' echo 123 >>for-submodules/dirty-otherwise/initial.t && force_color git -C for-submodules add -p dirty-otherwise >output 2>&1 && - grep "No changes" output && + test_grep "No changes" output && force_color git -C for-submodules add -p dirty-head >output 2>&1 <y && git -C for-submodules ls-files --stage dirty-head >actual && rev="$(git -C for-submodules/dirty-head rev-parse HEAD)" && - grep "$rev" actual + test_grep "$rev" actual ' test_expect_success 'set up pathological context' ' @@ -1230,4 +1230,75 @@ test_expect_success 'hunk splitting works with diff.suppressBlankEmpty' ' test_cmp expect actual ' +test_expect_success 'add -p respects diff.context' ' + test_write_lines a b c d e f g h i j k l m >file && + git add file && + test_write_lines a b c d e f G h i j k l m >file && + echo y | git -c diff.context=5 add -p >actual && + test_grep "@@ -2,11 +2,11 @@" actual +' + +test_expect_success 'add -p respects diff.interHunkContext' ' + test_write_lines a b c d e f g h i j k l m n o p q r s >file && + git add file && + test_write_lines a b c d E f g i i j k l m N o p q r s >file && + echo y | git -c diff.interhunkcontext=2 add -p >actual && + test_grep "@@ -2,16 +2,16 @@" actual +' + +test_expect_success 'add -p rejects negative diff.context' ' + test_config diff.context -1 && + test_must_fail git add -p 2>output && + test_grep "diff.context cannot be negative" output +' + +for cmd in add checkout restore 'commit -m file' +do + test_expect_success "${cmd%% *} accepts -U and --inter-hunk-context" ' + test_write_lines a b c d e f g h i j k l m n o p q r s t u v >file && + git add file && + test_write_lines a b c d e F g h i j k l m n o p Q r s t u v >file && + echo y | git -c diff.context=5 -c diff.interhunkcontext=1 \ + $cmd -p -U 4 --inter-hunk-context 2 >actual && + test_grep "@@ -2,20 +2,20 @@" actual + ' +done + +test_expect_success 'reset accepts -U and --inter-hunk-context' ' + test_write_lines a b c d e f g h i j k l m n o p q r s t u v >file && + git commit -m file file && + test_write_lines a b c d e F g h i j k l m n o p Q r s t u v >file && + git add file && + echo y | git -c diff.context=5 -c diff.interhunkcontext=1 \ + reset -p -U 4 --inter-hunk-context 2 >actual && + test_grep "@@ -2,20 +2,20 @@" actual +' + +test_expect_success 'stash accepts -U and --inter-hunk-context' ' + test_write_lines a b c d e F g h i j k l m n o p Q r s t u v >file && + git commit -m file file && + test_write_lines a b c d e f g h i j k l m n o p q r s t u v >file && + echo y | git -c diff.context=5 -c diff.interhunkcontext=1 \ + stash -p -U 4 --inter-hunk-context 2 >actual && + test_grep "@@ -2,20 +2,20 @@" actual +' + +for cmd in add checkout commit reset restore "stash save" "stash push" +do + test_expect_success "$cmd rejects invalid context options" ' + test_must_fail git $cmd -p -U -3 2>actual && + cat actual | echo && + test_grep -e ".--unified. cannot be negative" actual && + + test_must_fail git $cmd -p --inter-hunk-context -3 2>actual && + test_grep -e ".--inter-hunk-context. cannot be negative" actual && + + test_must_fail git $cmd -U 7 2>actual && + test_grep -E ".--unified. requires .(--interactive/)?--patch." actual && + + test_must_fail git $cmd --inter-hunk-context 2 2>actual && + test_grep -E ".--inter-hunk-context. requires .(--interactive/)?--patch." actual + ' +done + test_done diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index c58ccb136c..0bb4648e36 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -1672,11 +1672,9 @@ test_expect_success 'stash create reports a locked index' ' echo change >A.file && touch .git/index.lock && - cat >expect <<-EOF && - error: could not write index - EOF test_must_fail git stash create 2>err && - test_cmp expect err + test_grep "error: could not write index" err && + test_grep "error: Unable to create '.*index.lock'" err ) ' @@ -1689,11 +1687,9 @@ test_expect_success 'stash push reports a locked index' ' echo change >A.file && touch .git/index.lock && - cat >expect <<-EOF && - error: could not write index - EOF test_must_fail git stash push 2>err && - test_cmp expect err + test_grep "error: could not write index" err && + test_grep "error: Unable to create '.*index.lock'" err ) ' @@ -1707,11 +1703,9 @@ test_expect_success 'stash apply reports a locked index' ' git stash push && touch .git/index.lock && - cat >expect <<-EOF && - error: could not write index - EOF test_must_fail git stash apply 2>err && - test_cmp expect err + test_grep "error: could not write index" err && + test_grep "error: Unable to create '.*index.lock'" err ) ' diff --git a/t/t4042-diff-textconv-caching.sh b/t/t4042-diff-textconv-caching.sh index ff0e73531b..31018ceba2 100755 --- a/t/t4042-diff-textconv-caching.sh +++ b/t/t4042-diff-textconv-caching.sh @@ -120,6 +120,14 @@ test_expect_success 'log notes cache and still use cache for -p' ' ' test_expect_success 'caching is silently ignored outside repo' ' + test_oid_cache <<-\EOM && + oid1 sha1:5626abf + oid1 sha256:a4ed1f3 + oid2 sha1:f719efd + oid2 sha256:aa9e7dc + EOM + oid1=$(test_oid --hash=builtin oid1) && + oid2=$(test_oid --hash=builtin oid2) && mkdir -p non-repo && echo one >non-repo/one && echo two >non-repo/two && @@ -129,9 +137,9 @@ test_expect_success 'caching is silently ignored outside repo' ' -c diff.test.textconv="tr a-z A-Z <" \ -c diff.test.cachetextconv=true \ diff --no-index one two >actual && - cat >expect <<-\EOF && + cat >expect <<-EOF && diff --git a/one b/two - index 5626abf..f719efd 100644 + index $oid1..$oid2 100644 --- a/one +++ b/two @@ -1 +1 @@ diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh index ec2804eea6..1384a81957 100755 --- a/t/t4055-diff-context.sh +++ b/t/t4055-diff-context.sh @@ -38,55 +38,55 @@ test_expect_success 'setup' ' test_expect_success 'the default number of context lines is 3' ' git diff >output && - ! grep "^ d" output && - grep "^ e" output && - grep "^ j" output && - ! grep "^ k" output + test_grep ! "^ d" output && + test_grep "^ e" output && + test_grep "^ j" output && + test_grep ! "^ k" output ' test_expect_success 'diff.context honored by "log"' ' git log -1 -p >output && - ! grep firstline output && - git config diff.context 8 && + test_grep ! firstline output && + test_config diff.context 8 && git log -1 -p >output && - grep "^ firstline" output + test_grep "^ firstline" output ' test_expect_success 'The -U option overrides diff.context' ' - git config diff.context 8 && + test_config diff.context 8 && git log -U4 -1 >output && - ! grep "^ firstline" output + test_grep ! "^ firstline" output ' test_expect_success 'diff.context honored by "diff"' ' - git config diff.context 8 && + test_config diff.context 8 && git diff >output && - grep "^ firstline" output + test_grep "^ firstline" output ' test_expect_success 'plumbing not affected' ' - git config diff.context 8 && + test_config diff.context 8 && git diff-files -p >output && - ! grep "^ firstline" output + test_grep ! "^ firstline" output ' test_expect_success 'non-integer config parsing' ' - git config diff.context no && + test_config diff.context no && test_must_fail git diff 2>output && test_grep "bad numeric config value" output ' test_expect_success 'negative integer config parsing' ' - git config diff.context -1 && + test_config diff.context -1 && test_must_fail git diff 2>output && test_grep "bad config variable" output ' test_expect_success '-U0 is valid, so is diff.context=0' ' - git config diff.context 0 && + test_config diff.context 0 && git diff >output && - grep "^-ADDED" output && - grep "^+MODIFIED" output + test_grep "^-ADDED" output && + test_grep "^+MODIFIED" output ' test_expect_success '-U2147483647 works' ' @@ -94,9 +94,9 @@ test_expect_success '-U2147483647 works' ' test_line_count = 16 x && git diff -U2147483647 >output && test_line_count = 22 output && - grep "^-ADDED" output && - grep "^+MODIFIED" output && - grep "^+APPENDED" output + test_grep "^-ADDED" output && + test_grep "^+MODIFIED" output && + test_grep "^+APPENDED" output ' test_done diff --git a/t/t4140-apply-ita.sh b/t/t4140-apply-ita.sh index c614eaf04c..0b11a8aef4 100755 --- a/t/t4140-apply-ita.sh +++ b/t/t4140-apply-ita.sh @@ -7,6 +7,10 @@ test_description='git apply of i-t-a file' test_expect_success setup ' test_write_lines 1 2 3 4 5 >blueprint && + cat blueprint >committed-file && + git add committed-file && + git commit -m "commit" && + cat blueprint >test-file && git add -N test-file && git diff >creation-patch && @@ -14,7 +18,14 @@ test_expect_success setup ' rm -f test-file && git diff >deletion-patch && - grep "deleted file mode 100644" deletion-patch + grep "deleted file mode 100644" deletion-patch && + + git rm -f test-file && + test_write_lines 6 >>committed-file && + cat blueprint >test-file && + git add -N test-file && + git diff >complex-patch && + git restore committed-file ' test_expect_success 'apply creation patch to ita path (--cached)' ' @@ -53,4 +64,22 @@ test_expect_success 'apply deletion patch to ita path (--index)' ' git ls-files --stage --error-unmatch test-file ' +test_expect_success 'apply creation patch to existing index with -N' ' + git rm -f test-file && + cat blueprint >index-file && + git add index-file && + git apply -N creation-patch && + + git ls-files --stage --error-unmatch index-file && + git ls-files --stage --error-unmatch test-file +' + +test_expect_success 'apply complex patch with -N' ' + git rm -f test-file index-file && + git apply -N complex-patch && + + git ls-files --stage --error-unmatch test-file && + git diff | grep "a/committed-file" +' + test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 2ae93d3c96..699a81ab5c 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -1086,7 +1086,7 @@ test_expect_success 'am works with multi-line in-body headers' ' # bump from, date, and subject down to in-body header awk " /^From:/{ - print \"From: x <x\@example.com>\"; + print \"From: x <x@example.com>\"; print \"Date: Sat, 1 Jan 2000 00:00:00 +0000\"; print \"Subject: x\n\"; }; 1 diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 4a6c4dfbf4..05cee9e41b 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -134,6 +134,12 @@ test_expect_success 'diff-filter=D' ' ' +test_expect_success 'all-negative filter' ' + git log --no-renames --format=%s --diff-filter=d HEAD >actual && + printf "%s\n" fifth fourth third second initial >expect && + test_cmp expect actual +' + test_expect_success 'diff-filter=R' ' git log -M --pretty="format:%s" --diff-filter=R HEAD >actual && diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh index 8910d53cac..639868ac56 100755 --- a/t/t4216-log-bloom.sh +++ b/t/t4216-log-bloom.sh @@ -66,8 +66,9 @@ sane_unset GIT_TRACE2_CONFIG_PARAMS setup () { rm -f "$TRASH_DIRECTORY/trace.perf" && - git -c core.commitGraph=false log --pretty="format:%s" $1 >log_wo_bloom && - GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.perf" git -c core.commitGraph=true log --pretty="format:%s" $1 >log_w_bloom + eval git -c core.commitGraph=false log --pretty="format:%s" "$1" >log_wo_bloom && + eval "GIT_TRACE2_PERF=\"$TRASH_DIRECTORY/trace.perf\"" \ + git -c core.commitGraph=true log --pretty="format:%s" "$1" >log_w_bloom } test_bloom_filters_used () { @@ -138,10 +139,6 @@ test_expect_success 'git log with --walk-reflogs does not use Bloom filters' ' test_bloom_filters_not_used "--walk-reflogs -- A" ' -test_expect_success 'git log -- multiple path specs does not use Bloom filters' ' - test_bloom_filters_not_used "-- file4 A/file1" -' - test_expect_success 'git log -- "." pathspec at root does not use Bloom filters' ' test_bloom_filters_not_used "-- ." ' @@ -151,9 +148,17 @@ test_expect_success 'git log with wildcard that resolves to a single path uses B test_bloom_filters_used "-- *renamed" ' -test_expect_success 'git log with wildcard that resolves to a multiple paths does not uses Bloom filters' ' - test_bloom_filters_not_used "-- *" && - test_bloom_filters_not_used "-- file*" +test_expect_success 'git log with multiple literal paths uses Bloom filter' ' + test_bloom_filters_used "-- file4 A/file1" && + test_bloom_filters_used "-- *" && + test_bloom_filters_used "-- file*" +' + +test_expect_success 'git log with path contains a wildcard does not use Bloom filter' ' + test_bloom_filters_not_used "-- file\*" && + test_bloom_filters_not_used "-- A/\* file4" && + test_bloom_filters_not_used "-- file4 A/\*" && + test_bloom_filters_not_used "-- * A/\*" ' test_expect_success 'setup - add commit-graph to the chain without Bloom filters' ' diff --git a/t/t4256/1/mailinfo.c b/t/t4256/1/mailinfo.c index b395adbdf2..39caeba865 100644 --- a/t/t4256/1/mailinfo.c +++ b/t/t4256/1/mailinfo.c @@ -1214,7 +1214,7 @@ void setup_mailinfo(struct mailinfo *mi) mi->header_stage = 1; mi->use_inbody_headers = 1; mi->content_top = mi->content; - git_config(git_mailinfo_config, mi); + repo_config(the_repository, git_mailinfo_config, mi); } void clear_mailinfo(struct mailinfo *mi) diff --git a/t/t4256/1/mailinfo.c.orig b/t/t4256/1/mailinfo.c.orig index 3281a37d51..b76eb866aa 100644 --- a/t/t4256/1/mailinfo.c.orig +++ b/t/t4256/1/mailinfo.c.orig @@ -1154,7 +1154,7 @@ void setup_mailinfo(struct mailinfo *mi) mi->header_stage = 1; mi->use_inbody_headers = 1; mi->content_top = mi->content; - git_config(git_mailinfo_config, mi); + repo_config(the_repository, git_mailinfo_config, mi); } void clear_mailinfo(struct mailinfo *mi) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index ae72158b94..73445782e7 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -525,7 +525,7 @@ test_expect_success 'index-pack --strict <pack> works in non-repo' ' test_path_is_file foo.idx ' -test_expect_success SHA1 'show-index works OK outside a repository' ' +test_expect_success DEFAULT_HASH_ALGORITHM 'show-index works OK outside a repository' ' nongit git show-index <foo.idx ' @@ -658,7 +658,7 @@ do test_commit -C repo initial && git -C repo repack -ad && git -C repo verify-pack "$(pwd)"/repo/.git/objects/pack/*.idx && - if test $hash = sha1 + if test $hash = $GIT_TEST_BUILTIN_HASH then nongit git verify-pack "$(pwd)"/repo/.git/objects/pack/*.idx else @@ -676,7 +676,7 @@ do test_commit -C repo initial && git -C repo repack -ad && git -C repo index-pack --verify "$(pwd)"/repo/.git/objects/pack/*.pack && - if test $hash = sha1 + if test $hash = $GIT_TEST_BUILTIN_HASH then nongit git index-pack --verify "$(pwd)"/repo/.git/objects/pack/*.pack else diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index b6926f1027..6718fb98c0 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -495,6 +495,36 @@ test_bitmap_cases () { grep "ignoring extra bitmap" trace2.txt ) ' + + test_expect_success 'load corrupt bitmap' ' + rm -fr repo && + git init repo && + test_when_finished "rm -fr repo" && + ( + cd repo && + git config pack.writeBitmapLookupTable '"$writeLookupTable"' && + + test_commit base && + + git repack -adb && + bitmap="$(ls .git/objects/pack/pack-*.bitmap)" && + chmod +w $bitmap && + + test-tool bitmap list-commits-with-offset >offsets && + xor_off=$(head -n1 offsets | awk "{print \$3}") && + printf '\161' | + dd of=$bitmap count=1 bs=1 conv=notrunc seek=$xor_off && + + git rev-list --objects --no-object-names HEAD >expect.raw && + git rev-list --objects --use-bitmap-index --no-object-names HEAD \ + >actual.raw && + + sort expect.raw >expect && + sort actual.raw >actual && + + test_cmp expect actual + ) + ' } test_bitmap_cases diff --git a/t/t5331-pack-objects-stdin.sh b/t/t5331-pack-objects-stdin.sh index b48c0cbe8f..4a8df5a389 100755 --- a/t/t5331-pack-objects-stdin.sh +++ b/t/t5331-pack-objects-stdin.sh @@ -64,7 +64,7 @@ test_expect_success '--stdin-packs is incompatible with --filter' ' cd stdin-packs && test_must_fail git pack-objects --stdin-packs --stdout \ --filter=blob:none </dev/null 2>err && - test_grep "cannot use --filter with --stdin-packs" err + test_grep "options .--stdin-packs. and .--filter. cannot be used together" err ) ' @@ -236,4 +236,124 @@ test_expect_success 'pack-objects --stdin with packfiles from main and alternate test_cmp expected-objects actual-objects ' +objdir=.git/objects +packdir=$objdir/pack + +objects_in_packs () { + for p in "$@" + do + git show-index <"$packdir/pack-$p.idx" || return 1 + done >objects.raw && + + cut -d' ' -f2 objects.raw | sort && + rm -f objects.raw +} + +test_expect_success '--stdin-packs=follow walks into unknown packs' ' + test_when_finished "rm -fr repo" && + + git init repo && + ( + cd repo && + + for c in A B C D + do + test_commit "$c" || return 1 + done && + + A="$(echo A | git pack-objects --revs $packdir/pack)" && + B="$(echo A..B | git pack-objects --revs $packdir/pack)" && + C="$(echo B..C | git pack-objects --revs $packdir/pack)" && + D="$(echo C..D | git pack-objects --revs $packdir/pack)" && + test_commit E && + + git prune-packed && + + cat >in <<-EOF && + pack-$B.pack + ^pack-$C.pack + pack-$D.pack + EOF + + # With just --stdin-packs, pack "A" is unknown to us, so + # only objects from packs "B" and "D" are included in + # the output pack. + P=$(git pack-objects --stdin-packs $packdir/pack <in) && + objects_in_packs $B $D >expect && + objects_in_packs $P >actual && + test_cmp expect actual && + + # But with --stdin-packs=follow, objects from both + # included packs reach objects from the unknown pack, so + # objects from pack "A" is included in the output pack + # in addition to the above. + P=$(git pack-objects --stdin-packs=follow $packdir/pack <in) && + objects_in_packs $A $B $D >expect && + objects_in_packs $P >actual && + test_cmp expect actual && + + # And with --unpacked, we will pick up objects from unknown + # packs that are reachable from loose objects. Loose object E + # reaches objects in pack A, but there are three excluded packs + # in between. + # + # The resulting pack should include objects reachable from E + # that are not present in packs B, C, or D, along with those + # present in pack A. + cat >in <<-EOF && + ^pack-$B.pack + ^pack-$C.pack + ^pack-$D.pack + EOF + + P=$(git pack-objects --stdin-packs=follow --unpacked \ + $packdir/pack <in) && + + { + objects_in_packs $A && + git rev-list --objects --no-object-names D..E + }>expect.raw && + sort expect.raw >expect && + objects_in_packs $P >actual && + test_cmp expect actual + ) +' + +stdin_packs__follow_with_only () { + rm -fr stdin_packs__follow_with_only && + git init stdin_packs__follow_with_only && + ( + cd stdin_packs__follow_with_only && + + test_commit A && + test_commit B && + + git rev-parse "$@" >B.objects && + + echo A | git pack-objects --revs $packdir/pack && + B="$(git pack-objects $packdir/pack <B.objects)" && + + git cat-file --batch-check="%(objectname)" --batch-all-objects >objs && + for obj in $(cat objs) + do + rm -f $objdir/$(test_oid_to_path $obj) || return 1 + done && + + ( cd $packdir && ls pack-*.pack ) >in && + git pack-objects --stdin-packs=follow --stdout >/dev/null <in + ) +} + +test_expect_success '--stdin-packs=follow tolerates missing blobs' ' + stdin_packs__follow_with_only HEAD HEAD^{tree} +' + +test_expect_success '--stdin-packs=follow tolerates missing trees' ' + stdin_packs__follow_with_only HEAD HEAD:B.t +' + +test_expect_success '--stdin-packs=follow tolerates missing commits' ' + stdin_packs__follow_with_only HEAD HEAD^{tree} +' + test_done diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh index ba5ae6a00c..1f7a5d82ee 100755 --- a/t/t5333-pseudo-merge-bitmaps.sh +++ b/t/t5333-pseudo-merge-bitmaps.sh @@ -234,8 +234,8 @@ test_expect_success 'pseudo-merge pattern with capture groups' ' test_commit_bulk 16 && git rev-list HEAD~16.. >in && - sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1" in | - git update-ref --stdin || return 1 + sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1|" in >refs && + git update-ref --stdin <refs || return 1 done && git \ diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index bef0250e89..2701eef85e 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -1644,4 +1644,18 @@ test_expect_success 'empty config clears remote.*.pushurl list' ' test_cmp expect actual ' +test_expect_success 'forbid adding subset of existing remote' ' + test_when_finished "git remote rm outer" && + git remote add outer url && + test_must_fail git remote add outer/inner url 2>err && + test_grep ".outer/inner. is a subset of existing remote .outer." err +' + +test_expect_success 'forbid adding superset of existing remote' ' + test_when_finished "git remote rm outer/inner" && + git remote add outer/inner url && + test_must_fail git remote add outer url 2>err && + test_grep ".outer. is a superset of existing remote .outer/inner." err +' + test_done diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 63c9a8f04b..0e0019347e 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -472,6 +472,66 @@ test_expect_success 'pull --no-autostash & merge.autostash unset' ' test_pull_autostash_fail --no-autostash --no-rebase ' +test_expect_success 'pull succeeds with dirty working directory and pull.autostash=true' ' + test_config pull.autostash true && + test_pull_autostash 1 --rebase && + test_pull_autostash 2 --no-rebase && + test_pull_autostash 1 --autostash --rebase && + test_pull_autostash 2 --autostash --no-rebase +' + +test_expect_success 'pull fails with dirty working directory and pull.autostash=false' ' + test_config pull.autostash false && + test_pull_autostash_fail --rebase && + test_pull_autostash_fail --no-rebase && + test_pull_autostash_fail --no-autostash --rebase && + test_pull_autostash_fail --no-autostash --no-rebase +' + +test_expect_success 'pull --autostash overrides pull.autostash=false' ' + test_config pull.autostash false && + test_pull_autostash 1 --autostash --rebase && + test_pull_autostash 2 --autostash --no-rebase +' + +test_expect_success 'pull --no-autostash overrides pull.autostash=true' ' + test_config pull.autostash true && + test_pull_autostash_fail --no-autostash --rebase && + test_pull_autostash_fail --no-autostash --no-rebase +' + +test_expect_success 'pull.autostash=true overrides rebase.autostash' ' + test_config pull.autostash true && + test_config rebase.autostash true && + test_pull_autostash 1 --rebase && + test_config rebase.autostash false && + test_pull_autostash 1 --rebase +' + +test_expect_success 'pull.autostash=false overrides rebase.autostash' ' + test_config pull.autostash false && + test_config rebase.autostash true && + test_pull_autostash_fail --rebase && + test_config rebase.autostash false && + test_pull_autostash_fail --rebase +' + +test_expect_success 'pull.autostash=true overrides merge.autostash' ' + test_config pull.autostash true && + test_config merge.autostash true && + test_pull_autostash 2 --no-rebase && + test_config merge.autostash false && + test_pull_autostash 2 --no-rebase +' + +test_expect_success 'pull.autostash=false overrides merge.autostash' ' + test_config pull.autostash false && + test_config merge.autostash true && + test_pull_autostash_fail --no-rebase && + test_config merge.autostash false && + test_pull_autostash_fail --no-rebase +' + test_expect_success 'pull.rebase' ' git reset --hard before-rebase && test_config pull.rebase true && diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh index bb02b86c16..9b80ea1e3b 100755 --- a/t/t6302-for-each-ref-filter.sh +++ b/t/t6302-for-each-ref-filter.sh @@ -541,4 +541,217 @@ test_expect_success 'validate worktree atom' ' test_cmp expect actual ' +test_expect_success 'start after with empty value' ' + cat >expect <<-\EOF && + refs/heads/main + refs/heads/main_worktree + refs/heads/side + refs/odd/spot + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after="" >actual && + test_cmp expect actual +' + +test_expect_success 'start after a specific reference' ' + cat >expect <<-\EOF && + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after=refs/odd/spot >actual && + test_cmp expect actual +' + +test_expect_success 'start after a specific reference with partial match' ' + cat >expect <<-\EOF && + refs/odd/spot + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after=refs/odd/sp >actual && + test_cmp expect actual +' + +test_expect_success 'start after, just behind a specific reference' ' + cat >expect <<-\EOF && + refs/odd/spot + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after=refs/odd/parrot >actual && + test_cmp expect actual +' + +test_expect_success 'start after with specific directory match' ' + cat >expect <<-\EOF && + refs/odd/spot + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after=refs/odd >actual && + test_cmp expect actual +' + +test_expect_success 'start after with specific directory and trailing slash' ' + cat >expect <<-\EOF && + refs/odd/spot + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after=refs/odd/ >actual && + test_cmp expect actual +' + +test_expect_success 'start after, just behind a specific directory' ' + cat >expect <<-\EOF && + refs/odd/spot + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after=refs/lost >actual && + test_cmp expect actual +' + +test_expect_success 'start after, overflow specific reference length' ' + cat >expect <<-\EOF && + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after=refs/odd/spotnew >actual && + test_cmp expect actual +' + +test_expect_success 'start after, overflow specific reference path' ' + cat >expect <<-\EOF && + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after=refs/odd/spot/new >actual && + test_cmp expect actual +' + +test_expect_success 'start after, with exclude pattern' ' + cat >expect <<-\EOF && + refs/tags/annotated-tag + refs/tags/doubly-annotated-tag + refs/tags/doubly-signed-tag + refs/tags/foo1.10 + refs/tags/foo1.3 + refs/tags/foo1.6 + refs/tags/four + refs/tags/one + refs/tags/signed-tag + refs/tags/three + refs/tags/two + EOF + git for-each-ref --format="%(refname)" --start-after=refs/odd/spot \ + --exclude=refs/tags/foo >actual && + test_cmp expect actual +' + +test_expect_success 'start after, last reference' ' + cat >expect <<-\EOF && + EOF + git for-each-ref --format="%(refname)" --start-after=refs/tags/two >actual && + test_cmp expect actual +' + +test_expect_success 'start after used with a pattern' ' + cat >expect <<-\EOF && + fatal: cannot use --start-after with patterns + EOF + test_must_fail git for-each-ref --format="%(refname)" --start-after=refs/odd/spot refs/tags 2>actual && + test_cmp expect actual +' + +test_expect_success 'start after used with custom sort order' ' + cat >expect <<-\EOF && + fatal: cannot use --start-after with custom sort options + EOF + test_must_fail git for-each-ref --format="%(refname)" --start-after=refs/odd/spot --sort=author 2>actual && + test_cmp expect actual +' + test_done diff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh index 14b5743b96..f512eed278 100755 --- a/t/t7450-bad-git-dotfiles.sh +++ b/t/t7450-bad-git-dotfiles.sh @@ -401,7 +401,7 @@ test_expect_success SYMLINKS,!WINDOWS,!MINGW 'submodule must not checkout into d git -C repo commit -m submodule && git -c protocol.file.allow=always clone --recurse-submodules repo bad-clone && - ! test -f "$PWD/foo" && + ! test -f "$PWD/bad-clone/sub/foo" && test -f $(printf "bad-clone/sub\r/post-checkout") ' diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh index 39677e859a..1201c85ba6 100755 --- a/t/t7510-signed-commit.sh +++ b/t/t7510-signed-commit.sh @@ -449,7 +449,17 @@ test_expect_success 'custom `gpg.program`' ' test_must_fail env LET_GPG_PROGRAM_FAIL=1 \ git commit -S --allow-empty -m must-fail 2>err && - grep zOMG err + grep zOMG err && + + # `gpg.program` starts with `~`, the path should be interpreted to be relative to `$HOME` + test_config gpg.program "~/fake-gpg" && + env HOME="$(pwd)" \ + git commit -S --allow-empty -m signed-commit && + + # `gpg.program` does not specify an absolute path, it should find a program in `$PATH` + test_config gpg.program "fake-gpg" && + env PATH="$PWD:$PATH" \ + git commit -S --allow-empty -m signed-commit ' test_done diff --git a/t/t7528-signed-commit-ssh.sh b/t/t7528-signed-commit-ssh.sh index 065f780636..0f887a3ebe 100755 --- a/t/t7528-signed-commit-ssh.sh +++ b/t/t7528-signed-commit-ssh.sh @@ -84,18 +84,26 @@ test_expect_success GPGSSH 'sign commits using literal public keys with ssh-agen test_config gpg.format ssh && eval $(ssh-agent) && test_when_finished "kill ${SSH_AGENT_PID}" && - ssh-add "${GPGSSH_KEY_PRIMARY}" && - echo 1 >file && git add file && - git commit -a -m rsa-inline -S"$(cat "${GPGSSH_KEY_PRIMARY}.pub")" && - echo 2 >file && - test_config user.signingkey "$(cat "${GPGSSH_KEY_PRIMARY}.pub")" && - git commit -a -m rsa-config -S && - ssh-add "${GPGSSH_KEY_ECDSA}" && - echo 3 >file && - git commit -a -m ecdsa-inline -S"key::$(cat "${GPGSSH_KEY_ECDSA}.pub")" && - echo 4 >file && - test_config user.signingkey "key::$(cat "${GPGSSH_KEY_ECDSA}.pub")" && - git commit -a -m ecdsa-config -S + test_when_finished "test_unconfig user.signingkey" && + mkdir tmpdir && + TMPDIR="$(pwd)/tmpdir" && + ( + export TMPDIR && + ssh-add "${GPGSSH_KEY_PRIMARY}" && + echo 1 >file && git add file && + git commit -a -m rsa-inline -S"$(cat "${GPGSSH_KEY_PRIMARY}.pub")" && + echo 2 >file && + git config user.signingkey "$(cat "${GPGSSH_KEY_PRIMARY}.pub")" && + git commit -a -m rsa-config -S && + ssh-add "${GPGSSH_KEY_ECDSA}" && + echo 3 >file && + git commit -a -m ecdsa-inline -S"key::$(cat "${GPGSSH_KEY_ECDSA}.pub")" && + echo 4 >file && + git config user.signingkey "key::$(cat "${GPGSSH_KEY_ECDSA}.pub")" && + git commit -a -m ecdsa-config -S + ) && + find tmpdir -type f >tmpfiles && + test_must_be_empty tmpfiles ' test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'create signed commits with keys having defined lifetimes' ' diff --git a/t/t7704-repack-cruft.sh b/t/t7704-repack-cruft.sh index 8aebfb45f5..aa2e2e6ad8 100755 --- a/t/t7704-repack-cruft.sh +++ b/t/t7704-repack-cruft.sh @@ -724,4 +724,149 @@ test_expect_success 'cruft repack respects --quiet' ' ) ' +setup_cruft_exclude_tests() { + git init "$1" && + ( + cd "$1" && + + git config repack.midxMustContainCruft false && + + test_commit one && + + test_commit --no-tag two && + two="$(git rev-parse HEAD)" && + test_commit --no-tag three && + three="$(git rev-parse HEAD)" && + git reset --hard one && + git reflog expire --all --expire=all && + + GIT_TEST_MULTI_PACK_INDEX=0 git repack --cruft -d && + + git merge $two && + test_commit four + ) +} + +test_expect_success 'repack --write-midx excludes cruft where possible' ' + setup_cruft_exclude_tests exclude-cruft-when-possible && + ( + cd exclude-cruft-when-possible && + + GIT_TEST_MULTI_PACK_INDEX=0 \ + git repack -d --geometric=2 --write-midx --write-bitmap-index && + + test-tool read-midx --show-objects $objdir >midx && + cruft="$(ls $packdir/*.mtimes)" && + test_grep ! "$(basename "$cruft" .mtimes).idx" midx && + + git rev-list --all --objects --no-object-names >reachable.raw && + sort reachable.raw >reachable.objects && + awk "/\.pack$/ { print \$1 }" <midx | sort >midx.objects && + + test_cmp reachable.objects midx.objects + ) +' + +test_expect_success 'repack --write-midx includes cruft when instructed' ' + setup_cruft_exclude_tests exclude-cruft-when-instructed && + ( + cd exclude-cruft-when-instructed && + + GIT_TEST_MULTI_PACK_INDEX=0 \ + git -c repack.midxMustContainCruft=true repack \ + -d --geometric=2 --write-midx --write-bitmap-index && + + test-tool read-midx --show-objects $objdir >midx && + cruft="$(ls $packdir/*.mtimes)" && + test_grep "$(basename "$cruft" .mtimes).idx" midx && + + git cat-file --batch-check="%(objectname)" --batch-all-objects \ + >all.objects && + awk "/\.pack$/ { print \$1 }" <midx | sort >midx.objects && + + test_cmp all.objects midx.objects + ) +' + +test_expect_success 'repack --write-midx includes cruft when necessary' ' + setup_cruft_exclude_tests exclude-cruft-when-necessary && + ( + cd exclude-cruft-when-necessary && + + test_path_is_file $(ls $packdir/pack-*.mtimes) && + ( cd $packdir && ls pack-*.idx ) | sort >packs.all && + git multi-pack-index write --stdin-packs --bitmap <packs.all && + + test_commit five && + GIT_TEST_MULTI_PACK_INDEX=0 \ + git repack -d --geometric=2 --write-midx --write-bitmap-index && + + test-tool read-midx --show-objects $objdir >midx && + awk "/\.pack$/ { print \$1 }" <midx | sort >midx.objects && + git cat-file --batch-all-objects --batch-check="%(objectname)" \ + >expect.objects && + test_cmp expect.objects midx.objects && + + grep "^pack-" midx >midx.packs && + test_line_count = "$(($(wc -l <packs.all) + 1))" midx.packs + ) +' + +test_expect_success 'repack --write-midx includes cruft when already geometric' ' + git init repack--write-midx-geometric-noop && + ( + cd repack--write-midx-geometric-noop && + + git branch -M main && + test_commit A && + test_commit B && + + git checkout -B side && + test_commit --no-tag C && + C="$(git rev-parse HEAD)" && + + git checkout main && + git branch -D side && + git reflog expire --all --expire=all && + + # At this point we have two packs: one containing the + # objects belonging to commits A and B, and another + # (cruft) pack containing the objects belonging to + # commit C. + git repack --cruft -d && + + # Create a third pack which contains a merge commit + # making commit C reachable again. + # + # --no-ff is important here, as it ensures that we + # actually write a new object and subsequently a new + # pack to contain it. + git merge --no-ff $C && + git repack -d && + + ls $packdir/pack-*.idx | sort >packs.all && + cruft="$(ls $packdir/pack-*.mtimes)" && + cruft="${cruft%.mtimes}.idx" && + + for idx in $(grep -v $cruft <packs.all) + do + git show-index <$idx >out && + wc -l <out || return 1 + done >sizes.raw && + + # Make sure that there are two non-cruft packs, and + # that one of them contains at least twice as many + # objects as the other, ensuring that they are already + # in a geometric progression. + sort -n sizes.raw >sizes && + test_line_count = 2 sizes && + s1=$(head -n 1 sizes) && + s2=$(tail -n 1 sizes) && + test "$s2" -gt "$((2 * $s1))" && + + git -c repack.midxMustContainCruft=false repack --geometric=2 \ + --write-midx --write-bitmap-index + ) +' + test_done diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 0c1af43f6f..e56e0c8d77 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -201,6 +201,13 @@ test_expect_success $PREREQ 'cc trailer with get_maintainer.pl output' ' test_cmp expected-cc commandline1 ' +test_expect_failure $PREREQ 'invalid smtp server port value' ' + clean_fake_sendmail && + git send-email -1 --to=recipient@example.com \ + --smtp-server-port=bogus-symbolic-name \ + --smtp-server="$(pwd)/fake.sendmail" +' + test_expect_success $PREREQ 'setup expect' " cat >expected-show-all-headers <<\EOF 0001-Second.patch diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index 76619765fc..8f85c69d62 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -48,12 +48,11 @@ test_expect_success 'fast-export | fast-import' ' mkdir new && git --git-dir=new/.git init && git fast-export --all >actual && - (cd new && - git fast-import && - test $MAIN = $(git rev-parse --verify refs/heads/main) && - test $REIN = $(git rev-parse --verify refs/tags/rein) && - test $WER = $(git rev-parse --verify refs/heads/wer) && - test $MUSS = $(git rev-parse --verify refs/tags/muss)) <actual + git -C new fast-import <actual && + test $MAIN = $(git -C new rev-parse --verify refs/heads/main) && + test $REIN = $(git -C new rev-parse --verify refs/tags/rein) && + test $WER = $(git -C new rev-parse --verify refs/heads/wer) && + test $MUSS = $(git -C new rev-parse --verify refs/tags/muss) ' @@ -87,13 +86,11 @@ test_expect_success 'fast-export --mark-tags ^muss^{commit} muss' ' test_expect_success 'fast-export main~2..main' ' git fast-export main~2..main >actual && - sed "s/main/partial/" actual | - (cd new && - git fast-import && - test $MAIN != $(git rev-parse --verify refs/heads/partial) && - git diff --exit-code main partial && - git diff --exit-code main^ partial^ && - test_must_fail git rev-parse partial~2) + sed "s/main/partial/" actual | git -C new fast-import && + test $MAIN != $(git -C new rev-parse --verify refs/heads/partial) && + git -C new diff --exit-code main partial && + git -C new diff --exit-code main^ partial^ && + test_must_fail git -C new rev-parse partial~2 ' @@ -102,10 +99,8 @@ test_expect_success 'fast-export --reference-excluded-parents main~2..main' ' git fast-export --reference-excluded-parents main~2..main >actual && grep commit.refs/heads/main actual >commit-count && test_line_count = 2 commit-count && - sed "s/main/rewrite/" actual | - (cd new && - git fast-import && - test $MAIN = $(git rev-parse --verify refs/heads/rewrite)) + sed "s/main/rewrite/" actual | git -C new fast-import && + test $MAIN = $(git -C new rev-parse --verify refs/heads/rewrite) ' test_expect_success 'fast-export --show-original-ids' ' @@ -133,20 +128,19 @@ test_expect_success ICONV 'reencoding iso-8859-7' ' echo rosten >file && git commit -s -F "$TEST_DIRECTORY/t9350/simple-iso-8859-7-commit-message.txt" file && git fast-export --reencode=yes wer^..wer >iso-8859-7.fi && - sed "s/wer/i18n/" iso-8859-7.fi | - (cd new && - git fast-import && - # The commit object, if not re-encoded, would be 200 bytes plus hash. - # Removing the "encoding iso-8859-7\n" header drops 20 bytes. - # Re-encoding the Pi character from \xF0 (\360) in iso-8859-7 - # to \xCF\x80 (\317\200) in UTF-8 adds a byte. Check for - # the expected size. - test $(($(test_oid hexsz) + 181)) -eq "$(git cat-file -s i18n)" && - # ...and for the expected translation of bytes. - git cat-file commit i18n >actual && - grep $(printf "\317\200") actual && - # Also make sure the commit does not have the "encoding" header - ! grep ^encoding actual) + sed "s/wer/i18n/" iso-8859-7.fi | git -C new fast-import && + + # The commit object, if not re-encoded, would be 200 bytes plus hash. + # Removing the "encoding iso-8859-7\n" header drops 20 bytes. + # Re-encoding the Pi character from \xF0 (\360) in iso-8859-7 + # to \xCF\x80 (\317\200) in UTF-8 adds a byte. Check for + # the expected size. + test $(($(test_oid hexsz) + 181)) -eq "$(git -C new cat-file -s i18n)" && + # ...and for the expected translation of bytes. + git -C new cat-file commit i18n >actual && + grep $(printf "\317\200") actual && + # Also make sure the commit does not have the "encoding" header + ! grep ^encoding actual ' test_expect_success 'aborting on iso-8859-7' ' @@ -165,20 +159,19 @@ test_expect_success 'preserving iso-8859-7' ' echo rosten >file && git commit -s -F "$TEST_DIRECTORY/t9350/simple-iso-8859-7-commit-message.txt" file && git fast-export --reencode=no wer^..wer >iso-8859-7.fi && - sed "s/wer/i18n-no-recoding/" iso-8859-7.fi | - (cd new && - git fast-import && - # The commit object, if not re-encoded, is 200 bytes plus hash. - # Removing the "encoding iso-8859-7\n" header would drops 20 - # bytes. Re-encoding the Pi character from \xF0 (\360) in - # iso-8859-7 to \xCF\x80 (\317\200) in UTF-8 adds a byte. - # Check for the expected size... - test $(($(test_oid hexsz) + 200)) -eq "$(git cat-file -s i18n-no-recoding)" && - # ...as well as the expected byte. - git cat-file commit i18n-no-recoding >actual && - grep $(printf "\360") actual && - # Also make sure the commit has the "encoding" header - grep ^encoding actual) + sed "s/wer/i18n-no-recoding/" iso-8859-7.fi | git -C new fast-import && + + # The commit object, if not re-encoded, is 200 bytes plus hash. + # Removing the "encoding iso-8859-7\n" header would drops 20 + # bytes. Re-encoding the Pi character from \xF0 (\360) in + # iso-8859-7 to \xCF\x80 (\317\200) in UTF-8 adds a byte. + # Check for the expected size... + test $(($(test_oid hexsz) + 200)) -eq "$(git -C new cat-file -s i18n-no-recoding)" && + # ...as well as the expected byte. + git -C new cat-file commit i18n-no-recoding >actual && + grep $(printf "\360") actual && + # Also make sure the commit has the "encoding" header + grep ^encoding actual ' test_expect_success 'encoding preserved if reencoding fails' ' @@ -188,18 +181,17 @@ test_expect_success 'encoding preserved if reencoding fails' ' echo rosten >file && git commit -s -F "$TEST_DIRECTORY/t9350/broken-iso-8859-7-commit-message.txt" file && git fast-export --reencode=yes wer^..wer >iso-8859-7.fi && - sed "s/wer/i18n-invalid/" iso-8859-7.fi | - (cd new && - git fast-import && - git cat-file commit i18n-invalid >actual && - # Make sure the commit still has the encoding header - grep ^encoding actual && - # Verify that the commit has the expected size; i.e. - # that no bytes were re-encoded to a different encoding. - test $(($(test_oid hexsz) + 212)) -eq "$(git cat-file -s i18n-invalid)" && - # ...and check for the original special bytes - grep $(printf "\360") actual && - grep $(printf "\377") actual) + sed "s/wer/i18n-invalid/" iso-8859-7.fi | git -C new fast-import && + git -C new cat-file commit i18n-invalid >actual && + + # Make sure the commit still has the encoding header + grep ^encoding actual && + # Verify that the commit has the expected size; i.e. + # that no bytes were re-encoded to a different encoding. + test $(($(test_oid hexsz) + 212)) -eq "$(git -C new cat-file -s i18n-invalid)" && + # ...and check for the original special bytes + grep $(printf "\360") actual && + grep $(printf "\377") actual ' test_expect_success 'import/export-marks' ' @@ -314,29 +306,23 @@ test_expect_success GPG 'signed-commits=abort' ' test_expect_success GPG 'signed-commits=verbatim' ' git fast-export --signed-commits=verbatim --reencode=no commit-signing >output && - grep "^gpgsig sha" output && + test_grep -E "^gpgsig $GIT_DEFAULT_HASH openpgp" output && grep "encoding ISO-8859-1" output && - ( - cd new && - git fast-import && - STRIPPED=$(git rev-parse --verify refs/heads/commit-signing) && - test $COMMIT_SIGNING = $STRIPPED - ) <output + git -C new fast-import <output && + STRIPPED=$(git -C new rev-parse --verify refs/heads/commit-signing) && + test $COMMIT_SIGNING = $STRIPPED ' test_expect_success GPG 'signed-commits=warn-verbatim' ' git fast-export --signed-commits=warn-verbatim --reencode=no commit-signing >output 2>err && - grep "^gpgsig sha" output && + test_grep -E "^gpgsig $GIT_DEFAULT_HASH openpgp" output && grep "encoding ISO-8859-1" output && test -s err && - ( - cd new && - git fast-import && - STRIPPED=$(git rev-parse --verify refs/heads/commit-signing) && - test $COMMIT_SIGNING = $STRIPPED - ) <output + git -C new fast-import <output && + STRIPPED=$(git -C new rev-parse --verify refs/heads/commit-signing) && + test $COMMIT_SIGNING = $STRIPPED ' @@ -345,12 +331,9 @@ test_expect_success GPG 'signed-commits=strip' ' git fast-export --signed-commits=strip --reencode=no commit-signing >output && ! grep ^gpgsig output && grep "^encoding ISO-8859-1" output && - sed "s/commit-signing/commit-strip-signing/" output | ( - cd new && - git fast-import && - STRIPPED=$(git rev-parse --verify refs/heads/commit-strip-signing) && - test $COMMIT_SIGNING != $STRIPPED - ) + sed "s/commit-signing/commit-strip-signing/" output | git -C new fast-import && + STRIPPED=$(git -C new rev-parse --verify refs/heads/commit-strip-signing) && + test $COMMIT_SIGNING != $STRIPPED ' @@ -360,12 +343,59 @@ test_expect_success GPG 'signed-commits=warn-strip' ' ! grep ^gpgsig output && grep "^encoding ISO-8859-1" output && test -s err && - sed "s/commit-signing/commit-strip-signing/" output | ( - cd new && - git fast-import && - STRIPPED=$(git rev-parse --verify refs/heads/commit-strip-signing) && - test $COMMIT_SIGNING != $STRIPPED - ) + sed "s/commit-signing/commit-strip-signing/" output | git -C new fast-import && + STRIPPED=$(git -C new rev-parse --verify refs/heads/commit-strip-signing) && + test $COMMIT_SIGNING != $STRIPPED + +' + +test_expect_success GPGSM 'setup X.509 signed commit' ' + + git checkout -b x509-signing main && + test_config gpg.format x509 && + test_config user.signingkey $GIT_COMMITTER_EMAIL && + echo "X.509 content" >file && + git add file && + git commit -S -m "X.509 signed commit" && + X509_COMMIT=$(git rev-parse HEAD) && + git checkout main + +' + +test_expect_success GPGSM 'round-trip X.509 signed commit' ' + + git fast-export --signed-commits=verbatim x509-signing >output && + test_grep -E "^gpgsig $GIT_DEFAULT_HASH x509" output && + git -C new fast-import <output && + git -C new cat-file commit refs/heads/x509-signing >actual && + grep "^gpgsig" actual && + IMPORTED=$(git -C new rev-parse refs/heads/x509-signing) && + test $X509_COMMIT = $IMPORTED + +' + +test_expect_success GPGSSH 'setup SSH signed commit' ' + + git checkout -b ssh-signing main && + test_config gpg.format ssh && + test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && + echo "SSH content" >file && + git add file && + git commit -S -m "SSH signed commit" && + SSH_COMMIT=$(git rev-parse HEAD) && + git checkout main + +' + +test_expect_success GPGSSH 'round-trip SSH signed commit' ' + + git fast-export --signed-commits=verbatim ssh-signing >output && + test_grep -E "^gpgsig $GIT_DEFAULT_HASH ssh" output && + git -C new fast-import <output && + git -C new cat-file commit refs/heads/ssh-signing >actual && + grep "^gpgsig" actual && + IMPORTED=$(git -C new rev-parse refs/heads/ssh-signing) && + test $SSH_COMMIT = $IMPORTED ' @@ -405,14 +435,13 @@ test_expect_success 'submodule fast-export | fast-import' ' mkdir new && git --git-dir=new/.git init && git fast-export --signed-tags=strip --all >actual && - (cd new && - git fast-import && - test "$SUBENT1" = "$(git ls-tree refs/heads/main^ sub)" && - test "$SUBENT2" = "$(git ls-tree refs/heads/main sub)" && - git checkout main && - git submodule init && - git submodule update && - cmp sub/file ../sub/file) <actual + git -C new fast-import <actual && + test "$SUBENT1" = "$(git -C new ls-tree refs/heads/main^ sub)" && + test "$SUBENT2" = "$(git -C new ls-tree refs/heads/main sub)" && + git -C new checkout main && + git -C new submodule init && + git -C new submodule update && + cmp new/sub/file sub/file ' @@ -454,10 +483,8 @@ test_expect_success 'fast-export -C -C | fast-import' ' git --git-dir=new/.git init && git fast-export -C -C --signed-tags=strip --all > output && grep "^C file2 file4\$" output && - cat output | - (cd new && - git fast-import && - test $ENTRY = $(git rev-parse --verify refs/heads/copy)) + git -C new fast-import <output && + test $ENTRY = $(git -C new rev-parse --verify refs/heads/copy) ' @@ -905,4 +932,42 @@ test_expect_success 'fast-export handles --end-of-options' ' test_cmp expect actual ' +test_expect_success GPG 'setup a commit with dual signatures on its SHA-1 and SHA-256 formats' ' + # Create a signed SHA-256 commit + git init --object-format=sha256 explicit-sha256 && + git -C explicit-sha256 config extensions.compatObjectFormat sha1 && + git -C explicit-sha256 checkout -b dual-signed && + test_commit -C explicit-sha256 A && + echo B >explicit-sha256/B && + git -C explicit-sha256 add B && + test_tick && + git -C explicit-sha256 commit -S -m "signed" B && + SHA256_B=$(git -C explicit-sha256 rev-parse dual-signed) && + + # Create the corresponding SHA-1 commit + SHA1_B=$(git -C explicit-sha256 rev-parse --output-object-format=sha1 dual-signed) && + + # Check that the resulting SHA-1 commit has both signatures + echo $SHA1_B | git -C explicit-sha256 cat-file --batch >out && + test_grep -E "^gpgsig " out && + test_grep -E "^gpgsig-sha256 " out +' + +test_expect_success GPG 'export and import of doubly signed commit' ' + git -C explicit-sha256 fast-export --signed-commits=verbatim dual-signed >output && + test_grep -E "^gpgsig sha1 openpgp" output && + test_grep -E "^gpgsig sha256 openpgp" output && + git -C new fast-import <output && + git -C new cat-file commit refs/heads/dual-signed >actual && + test_grep -E "^gpgsig " actual && + test_grep -E "^gpgsig-sha256 " actual && + IMPORTED=$(git -C new rev-parse refs/heads/dual-signed) && + if test "$GIT_DEFAULT_HASH" = "sha1" + then + test $SHA1_B = $IMPORTED + else + test $SHA256_B = $IMPORTED + fi +' + test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 343b8cd191..6650d33fba 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -2596,6 +2596,8 @@ test_expect_success 'double dash "git checkout"' ' --merge Z --conflict=Z --patch Z + --unified=Z + --inter-hunk-context=Z --ignore-skip-worktree-bits Z --ignore-other-worktrees Z --recurse-submodules Z diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 6230746cc4..a28de7b19b 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -1707,7 +1707,7 @@ test_set_hash () { # Detect the hash algorithm in use. test_detect_hash () { - case "$GIT_TEST_DEFAULT_HASH" in + case "${GIT_TEST_DEFAULT_HASH:-$GIT_TEST_BUILTIN_HASH}" in "sha256") test_hash_algo=sha256 test_compat_hash_algo=sha1 @@ -1779,6 +1779,9 @@ test_oid () { --hash=compat) algo="$test_compat_hash_algo" && shift;; + --hash=builtin) + algo="$GIT_TEST_BUILTIN_HASH" && + shift;; --hash=*) algo="${1#--hash=}" && shift;; diff --git a/t/test-lib.sh b/t/test-lib.sh index 51370a201c..621cd31ae1 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -134,7 +134,8 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME ################################################################ # It appears that people try to run tests without building... -"${GIT_TEST_INSTALLED:-$GIT_BUILD_DIR}/git$X" >/dev/null +GIT_BINARY="${GIT_TEST_INSTALLED:-$GIT_BUILD_DIR}/git$X" +"$GIT_BINARY" >/dev/null if test $? != 1 then if test -n "$GIT_TEST_INSTALLED" @@ -536,7 +537,8 @@ export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME export GIT_COMMITTER_DATE GIT_AUTHOR_DATE export EDITOR -GIT_DEFAULT_HASH="${GIT_TEST_DEFAULT_HASH:-sha1}" +GIT_TEST_BUILTIN_HASH=$("$GIT_BINARY" version --build-options | sed -ne 's/^default-hash: //p') +GIT_DEFAULT_HASH="${GIT_TEST_DEFAULT_HASH:-$GIT_TEST_BUILTIN_HASH}" export GIT_DEFAULT_HASH GIT_DEFAULT_REF_FORMAT="${GIT_TEST_DEFAULT_REF_FORMAT:-files}" export GIT_DEFAULT_REF_FORMAT @@ -1908,6 +1910,10 @@ test_lazy_prereq SHA1 ' esac ' +test_lazy_prereq DEFAULT_HASH_ALGORITHM ' + test "$GIT_TEST_BUILTIN_HASH" = "$GIT_DEFAULT_HASH" +' + test_lazy_prereq DEFAULT_REPO_FORMAT ' test_have_prereq SHA1,REFFILES ' diff --git a/t/unit-tests/lib-reftable.c b/t/unit-tests/lib-reftable.c index 8a69612266..fdb5b11a20 100644 --- a/t/unit-tests/lib-reftable.c +++ b/t/unit-tests/lib-reftable.c @@ -1,12 +1,14 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - +#include "unit-test.h" #include "lib-reftable.h" -#include "test-lib.h" +#include "hex.h" +#include "parse-options.h" #include "reftable/constants.h" #include "reftable/writer.h" #include "strbuf.h" +#include "string-list.h" +#include "strvec.h" -void t_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id) +void cl_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id) { memset(p, (uint8_t)i, hash_size(id)); } @@ -22,17 +24,17 @@ static int strbuf_writer_flush(void *arg UNUSED) return 0; } -struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf, +struct reftable_writer *cl_reftable_strbuf_writer(struct reftable_buf *buf, struct reftable_write_options *opts) { struct reftable_writer *writer; int ret = reftable_writer_new(&writer, &strbuf_writer_write, &strbuf_writer_flush, buf, opts); - check(!ret); + cl_assert(!ret); return writer; } -void t_reftable_write_to_buf(struct reftable_buf *buf, +void cl_reftable_write_to_buf(struct reftable_buf *buf, struct reftable_ref_record *refs, size_t nrefs, struct reftable_log_record *logs, @@ -64,35 +66,36 @@ void t_reftable_write_to_buf(struct reftable_buf *buf, min = ui; } - writer = t_reftable_strbuf_writer(buf, &opts); - reftable_writer_set_limits(writer, min, max); + writer = cl_reftable_strbuf_writer(buf, &opts); + ret = reftable_writer_set_limits(writer, min, max); + cl_assert(!ret); if (nrefs) { ret = reftable_writer_add_refs(writer, refs, nrefs); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); } if (nlogs) { ret = reftable_writer_add_logs(writer, logs, nlogs); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); } ret = reftable_writer_close(writer); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); stats = reftable_writer_stats(writer); - for (size_t i = 0; i < stats->ref_stats.blocks; i++) { + for (size_t i = 0; i < (size_t)stats->ref_stats.blocks; i++) { size_t off = i * (opts.block_size ? opts.block_size : DEFAULT_BLOCK_SIZE); if (!off) off = header_size(opts.hash_id == REFTABLE_HASH_SHA256 ? 2 : 1); - check_char(buf->buf[off], ==, 'r'); + cl_assert(buf->buf[off] == 'r'); } if (nrefs) - check_int(stats->ref_stats.blocks, >, 0); + cl_assert(stats->ref_stats.blocks > 0); if (nlogs) - check_int(stats->log_stats.blocks, >, 0); + cl_assert(stats->log_stats.blocks > 0); reftable_writer_free(writer); } diff --git a/t/unit-tests/lib-reftable.h b/t/unit-tests/lib-reftable.h index e4c360fa7e..d7e6d3136f 100644 --- a/t/unit-tests/lib-reftable.h +++ b/t/unit-tests/lib-reftable.h @@ -1,21 +1,20 @@ -#ifndef LIB_REFTABLE_H -#define LIB_REFTABLE_H - +#include "git-compat-util.h" +#include "clar/clar.h" +#include "clar-decls.h" #include "git-compat-util.h" #include "reftable/reftable-writer.h" +#include "strbuf.h" struct reftable_buf; -void t_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id); +void cl_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id); -struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf, +struct reftable_writer *cl_reftable_strbuf_writer(struct reftable_buf *buf, struct reftable_write_options *opts); -void t_reftable_write_to_buf(struct reftable_buf *buf, +void cl_reftable_write_to_buf(struct reftable_buf *buf, struct reftable_ref_record *refs, size_t nrecords, struct reftable_log_record *logs, size_t nlogs, struct reftable_write_options *opts); - -#endif diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c deleted file mode 100644 index c9e751e49e..0000000000 --- a/t/unit-tests/t-reftable-basics.c +++ /dev/null @@ -1,219 +0,0 @@ -/* -Copyright 2020 Google LLC - -Use of this source code is governed by a BSD-style -license that can be found in the LICENSE file or at -https://developers.google.com/open-source/licenses/bsd -*/ - -#include "test-lib.h" -#include "reftable/basics.h" - -struct integer_needle_lesseq_args { - int needle; - int *haystack; -}; - -static int integer_needle_lesseq(size_t i, void *_args) -{ - struct integer_needle_lesseq_args *args = _args; - return args->needle <= args->haystack[i]; -} - -static void *realloc_stub(void *p UNUSED, size_t size UNUSED) -{ - return NULL; -} - -int cmd_main(int argc UNUSED, const char *argv[] UNUSED) -{ - if_test ("binary search with binsearch works") { - int haystack[] = { 2, 4, 6, 8, 10 }; - struct { - int needle; - size_t expected_idx; - } testcases[] = { - {-9000, 0}, - {-1, 0}, - {0, 0}, - {2, 0}, - {3, 1}, - {4, 1}, - {7, 3}, - {9, 4}, - {10, 4}, - {11, 5}, - {9000, 5}, - }; - - for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) { - struct integer_needle_lesseq_args args = { - .haystack = haystack, - .needle = testcases[i].needle, - }; - size_t idx; - - idx = binsearch(ARRAY_SIZE(haystack), - &integer_needle_lesseq, &args); - check_int(idx, ==, testcases[i].expected_idx); - } - } - - if_test ("names_length returns size of a NULL-terminated string array") { - const char *a[] = { "a", "b", NULL }; - check_int(names_length(a), ==, 2); - } - - if_test ("names_equal compares NULL-terminated string arrays") { - const char *a[] = { "a", "b", "c", NULL }; - const char *b[] = { "a", "b", "d", NULL }; - const char *c[] = { "a", "b", NULL }; - - check(names_equal(a, a)); - check(!names_equal(a, b)); - check(!names_equal(a, c)); - } - - if_test ("parse_names works for basic input") { - char in1[] = "line\n"; - char in2[] = "a\nb\nc"; - char **out = parse_names(in1, strlen(in1)); - check(out != NULL); - check_str(out[0], "line"); - check(!out[1]); - free_names(out); - - out = parse_names(in2, strlen(in2)); - check(out != NULL); - check_str(out[0], "a"); - check_str(out[1], "b"); - check_str(out[2], "c"); - check(!out[3]); - free_names(out); - } - - if_test ("parse_names drops empty string") { - char in[] = "a\n\nb\n"; - char **out = parse_names(in, strlen(in)); - check(out != NULL); - check_str(out[0], "a"); - /* simply '\n' should be dropped as empty string */ - check_str(out[1], "b"); - check(!out[2]); - free_names(out); - } - - if_test ("common_prefix_size works") { - struct reftable_buf a = REFTABLE_BUF_INIT; - struct reftable_buf b = REFTABLE_BUF_INIT; - struct { - const char *a, *b; - int want; - } cases[] = { - {"abcdef", "abc", 3}, - { "abc", "ab", 2 }, - { "", "abc", 0 }, - { "abc", "abd", 2 }, - { "abc", "pqr", 0 }, - }; - - for (size_t i = 0; i < ARRAY_SIZE(cases); i++) { - check(!reftable_buf_addstr(&a, cases[i].a)); - check(!reftable_buf_addstr(&b, cases[i].b)); - check_uint(common_prefix_size(&a, &b), ==, cases[i].want); - reftable_buf_reset(&a); - reftable_buf_reset(&b); - } - reftable_buf_release(&a); - reftable_buf_release(&b); - } - - if_test ("reftable_put_be64 and reftable_get_be64 work") { - uint64_t in = 0x1122334455667788; - uint8_t dest[8]; - uint64_t out; - reftable_put_be64(dest, in); - out = reftable_get_be64(dest); - check_int(in, ==, out); - } - - if_test ("reftable_put_be32 and reftable_get_be32 work") { - uint32_t in = 0x11223344; - uint8_t dest[4]; - uint32_t out; - reftable_put_be32(dest, in); - out = reftable_get_be32(dest); - check_int(in, ==, out); - } - - if_test ("reftable_put_be24 and reftable_get_be24 work") { - uint32_t in = 0x112233; - uint8_t dest[3]; - uint32_t out; - reftable_put_be24(dest, in); - out = reftable_get_be24(dest); - check_int(in, ==, out); - } - - if_test ("put_be16 and get_be16 work") { - uint32_t in = 0xfef1; - uint8_t dest[3]; - uint32_t out; - reftable_put_be16(dest, in); - out = reftable_get_be16(dest); - check_int(in, ==, out); - } - - if_test ("REFTABLE_ALLOC_GROW works") { - int *arr = NULL, *old_arr; - size_t alloc = 0, old_alloc; - - check(!REFTABLE_ALLOC_GROW(arr, 1, alloc)); - check(arr != NULL); - check_uint(alloc, >=, 1); - arr[0] = 42; - - old_alloc = alloc; - old_arr = arr; - reftable_set_alloc(NULL, realloc_stub, NULL); - check(REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc)); - check(arr == old_arr); - check_uint(alloc, ==, old_alloc); - - old_alloc = alloc; - reftable_set_alloc(NULL, NULL, NULL); - check(!REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc)); - check(arr != NULL); - check_uint(alloc, >, old_alloc); - arr[alloc - 1] = 42; - - reftable_free(arr); - } - - if_test ("REFTABLE_ALLOC_GROW_OR_NULL works") { - int *arr = NULL; - size_t alloc = 0, old_alloc; - - REFTABLE_ALLOC_GROW_OR_NULL(arr, 1, alloc); - check(arr != NULL); - check_uint(alloc, >=, 1); - arr[0] = 42; - - old_alloc = alloc; - REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc); - check(arr != NULL); - check_uint(alloc, >, old_alloc); - arr[alloc - 1] = 42; - - old_alloc = alloc; - reftable_set_alloc(NULL, realloc_stub, NULL); - REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc); - check(arr == NULL); - check_uint(alloc, ==, 0); - reftable_set_alloc(NULL, NULL, NULL); - - reftable_free(arr); - } - - return test_done(); -} diff --git a/t/unit-tests/u-prio-queue.c b/t/unit-tests/u-prio-queue.c index 145e689c9c..63e58114ae 100644 --- a/t/unit-tests/u-prio-queue.c +++ b/t/unit-tests/u-prio-queue.c @@ -13,6 +13,7 @@ static int intcmp(const void *va, const void *vb, void *data UNUSED) #define STACK -3 #define GET -4 #define REVERSE -5 +#define REPLACE -6 static int show(int *v) { @@ -51,6 +52,15 @@ static void test_prio_queue(int *input, size_t input_size, case REVERSE: prio_queue_reverse(&pq); break; + case REPLACE: + peek = prio_queue_peek(&pq); + cl_assert(i + 1 < input_size); + cl_assert(input[i + 1] >= 0); + cl_assert(j < result_size); + cl_assert_equal_i(result[j], show(peek)); + j++; + prio_queue_replace(&pq, &input[++i]); + break; default: prio_queue_put(&pq, &input[i]); break; @@ -81,6 +91,13 @@ void test_prio_queue__empty(void) ((int []){ 1, 2, MISSING, 1, 2, MISSING })); } +void test_prio_queue__replace(void) +{ + TEST_INPUT(((int []){ REPLACE, 6, 2, 4, REPLACE, 5, 7, GET, + REPLACE, 1, DUMP }), + ((int []){ MISSING, 2, 4, 5, 1, 6, 7 })); +} + void test_prio_queue__stack(void) { TEST_INPUT(((int []){ STACK, 8, 1, 5, 4, 6, 2, 3, DUMP }), @@ -92,3 +109,9 @@ void test_prio_queue__reverse_stack(void) TEST_INPUT(((int []){ STACK, 1, 2, 3, 4, 5, 6, REVERSE, DUMP }), ((int []){ 1, 2, 3, 4, 5, 6 })); } + +void test_prio_queue__replace_stack(void) +{ + TEST_INPUT(((int []){ STACK, 8, 1, 5, REPLACE, 4, 6, 2, 3, DUMP }), + ((int []){ 5, 3, 2, 6, 4, 1, 8 })); +} diff --git a/t/unit-tests/u-reftable-basics.c b/t/unit-tests/u-reftable-basics.c new file mode 100644 index 0000000000..a0471083e7 --- /dev/null +++ b/t/unit-tests/u-reftable-basics.c @@ -0,0 +1,227 @@ +/* +Copyright 2020 Google LLC + +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file or at +https://developers.google.com/open-source/licenses/bsd +*/ + +#include "unit-test.h" +#include "lib-reftable.h" +#include "reftable/basics.h" + +struct integer_needle_lesseq_args { + int needle; + int *haystack; +}; + +static int integer_needle_lesseq(size_t i, void *_args) +{ + struct integer_needle_lesseq_args *args = _args; + return args->needle <= args->haystack[i]; +} + +static void *realloc_stub(void *p UNUSED, size_t size UNUSED) +{ + return NULL; +} + +void test_reftable_basics__binsearch(void) +{ + int haystack[] = { 2, 4, 6, 8, 10 }; + struct { + int needle; + size_t expected_idx; + } testcases[] = { + {-9000, 0}, + {-1, 0}, + {0, 0}, + {2, 0}, + {3, 1}, + {4, 1}, + {7, 3}, + {9, 4}, + {10, 4}, + {11, 5}, + {9000, 5}, + }; + + for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) { + struct integer_needle_lesseq_args args = { + .haystack = haystack, + .needle = testcases[i].needle, + }; + size_t idx; + + idx = binsearch(ARRAY_SIZE(haystack), + &integer_needle_lesseq, &args); + cl_assert_equal_i(idx, testcases[i].expected_idx); + } +} + +void test_reftable_basics__names_length(void) +{ + const char *a[] = { "a", "b", NULL }; + cl_assert_equal_i(names_length(a), 2); +} + +void test_reftable_basics__names_equal(void) +{ + const char *a[] = { "a", "b", "c", NULL }; + const char *b[] = { "a", "b", "d", NULL }; + const char *c[] = { "a", "b", NULL }; + + cl_assert(names_equal(a, a)); + cl_assert(!names_equal(a, b)); + cl_assert(!names_equal(a, c)); +} + +void test_reftable_basics__parse_names(void) +{ + char in1[] = "line\n"; + char in2[] = "a\nb\nc"; + char **out = parse_names(in1, strlen(in1)); + cl_assert(out != NULL); + cl_assert_equal_s(out[0], "line"); + cl_assert(!out[1]); + free_names(out); + + out = parse_names(in2, strlen(in2)); + cl_assert(out != NULL); + cl_assert_equal_s(out[0], "a"); + cl_assert_equal_s(out[1], "b"); + cl_assert_equal_s(out[2], "c"); + cl_assert(!out[3]); + free_names(out); +} + +void test_reftable_basics__parse_names_drop_empty_string(void) +{ + char in[] = "a\n\nb\n"; + char **out = parse_names(in, strlen(in)); + cl_assert(out != NULL); + cl_assert_equal_s(out[0], "a"); + /* simply '\n' should be dropped as empty string */ + cl_assert_equal_s(out[1], "b"); + cl_assert(out[2] == NULL); + free_names(out); +} + +void test_reftable_basics__common_prefix_size(void) +{ + struct reftable_buf a = REFTABLE_BUF_INIT; + struct reftable_buf b = REFTABLE_BUF_INIT; + struct { + const char *a, *b; + int want; + } cases[] = { + {"abcdef", "abc", 3}, + { "abc", "ab", 2 }, + { "", "abc", 0 }, + { "abc", "abd", 2 }, + { "abc", "pqr", 0 }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(cases); i++) { + cl_assert_equal_i(reftable_buf_addstr(&a, cases[i].a), 0); + cl_assert_equal_i(reftable_buf_addstr(&b, cases[i].b), 0); + cl_assert_equal_i(common_prefix_size(&a, &b), cases[i].want); + reftable_buf_reset(&a); + reftable_buf_reset(&b); + } + reftable_buf_release(&a); + reftable_buf_release(&b); +} + +void test_reftable_basics__put_get_be64(void) +{ + uint64_t in = 0x1122334455667788; + uint8_t dest[8]; + uint64_t out; + reftable_put_be64(dest, in); + out = reftable_get_be64(dest); + cl_assert(in == out); +} + +void test_reftable_basics__put_get_be32(void) +{ + uint32_t in = 0x11223344; + uint8_t dest[4]; + uint32_t out; + reftable_put_be32(dest, in); + out = reftable_get_be32(dest); + cl_assert_equal_i(in, out); +} + +void test_reftable_basics__put_get_be24(void) +{ + uint32_t in = 0x112233; + uint8_t dest[3]; + uint32_t out; + reftable_put_be24(dest, in); + out = reftable_get_be24(dest); + cl_assert_equal_i(in, out); +} + +void test_reftable_basics__put_get_be16(void) +{ + uint32_t in = 0xfef1; + uint8_t dest[3]; + uint32_t out; + reftable_put_be16(dest, in); + out = reftable_get_be16(dest); + cl_assert_equal_i(in, out); +} + +void test_reftable_basics__alloc_grow(void) +{ + int *arr = NULL, *old_arr; + size_t alloc = 0, old_alloc; + + cl_assert_equal_i(REFTABLE_ALLOC_GROW(arr, 1, alloc), 0); + cl_assert(arr != NULL); + cl_assert(alloc >= 1); + arr[0] = 42; + + old_alloc = alloc; + old_arr = arr; + reftable_set_alloc(NULL, realloc_stub, NULL); + cl_assert(REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc)); + cl_assert(arr == old_arr); + cl_assert_equal_i(alloc, old_alloc); + + old_alloc = alloc; + reftable_set_alloc(NULL, NULL, NULL); + cl_assert_equal_i(REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc), 0); + cl_assert(arr != NULL); + cl_assert(alloc > old_alloc); + arr[alloc - 1] = 42; + + reftable_free(arr); +} + +void test_reftable_basics__alloc_grow_or_null(void) +{ + int *arr = NULL; + size_t alloc = 0, old_alloc; + + REFTABLE_ALLOC_GROW_OR_NULL(arr, 1, alloc); + cl_assert(arr != NULL); + cl_assert(alloc >= 1); + arr[0] = 42; + + old_alloc = alloc; + REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc); + cl_assert(arr != NULL); + cl_assert(alloc > old_alloc); + arr[alloc - 1] = 42; + + old_alloc = alloc; + reftable_set_alloc(NULL, realloc_stub, NULL); + REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc); + cl_assert(arr == NULL); + cl_assert_equal_i(alloc, 0); + reftable_set_alloc(NULL, NULL, NULL); + + reftable_free(arr); +} diff --git a/t/unit-tests/t-reftable-block.c b/t/unit-tests/u-reftable-block.c index 52f1dae1c9..f4bded7d26 100644 --- a/t/unit-tests/t-reftable-block.c +++ b/t/unit-tests/u-reftable-block.c @@ -6,14 +6,15 @@ license that can be found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd */ -#include "test-lib.h" +#include "unit-test.h" +#include "lib-reftable.h" #include "reftable/block.h" #include "reftable/blocksource.h" #include "reftable/constants.h" #include "reftable/reftable-error.h" #include "strbuf.h" -static void t_ref_block_read_write(void) +void test_reftable_block__read_write(void) { const int header_off = 21; /* random */ struct reftable_record recs[30]; @@ -34,17 +35,18 @@ static void t_ref_block_read_write(void) struct reftable_buf block_data = REFTABLE_BUF_INIT; REFTABLE_CALLOC_ARRAY(block_data.buf, block_size); - check(block_data.buf != NULL); + cl_assert(block_data.buf != NULL); block_data.len = block_size; - ret = block_writer_init(&bw, REFTABLE_BLOCK_TYPE_REF, (uint8_t *) block_data.buf, block_size, + ret = block_writer_init(&bw, REFTABLE_BLOCK_TYPE_REF, + (uint8_t *) block_data.buf, block_size, header_off, hash_size(REFTABLE_HASH_SHA1)); - check(!ret); + cl_assert(!ret); rec.u.ref.refname = (char *) ""; rec.u.ref.value_type = REFTABLE_REF_DELETION; ret = block_writer_add(&bw, &rec); - check_int(ret, ==, REFTABLE_API_ERROR); + cl_assert_equal_i(ret, REFTABLE_API_ERROR); for (i = 0; i < N; i++) { rec.u.ref.refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i); @@ -55,11 +57,11 @@ static void t_ref_block_read_write(void) ret = block_writer_add(&bw, &rec); rec.u.ref.refname = NULL; rec.u.ref.value_type = REFTABLE_REF_DELETION; - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); } ret = block_writer_finish(&bw); - check_int(ret, >, 0); + cl_assert(ret > 0); block_writer_release(&bw); @@ -71,32 +73,32 @@ static void t_ref_block_read_write(void) for (i = 0; ; i++) { ret = block_iter_next(&it, &rec); - check_int(ret, >=, 0); + cl_assert(ret >= 0); if (ret > 0) { - check_int(i, ==, N); + cl_assert_equal_i(i, N); break; } - check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1), 1); } for (i = 0; i < N; i++) { reftable_record_key(&recs[i], &want); ret = block_iter_seek_key(&it, &want); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); ret = block_iter_next(&it, &rec); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); - check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1), 1); want.len--; ret = block_iter_seek_key(&it, &want); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); ret = block_iter_next(&it, &rec); - check_int(ret, ==, 0); - check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(ret, 0); + cl_assert_equal_i(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1), 1); } reftable_block_release(&block); @@ -108,7 +110,7 @@ static void t_ref_block_read_write(void) reftable_record_release(&recs[i]); } -static void t_log_block_read_write(void) +void test_reftable_block__log_read_write(void) { const int header_off = 21; struct reftable_record recs[30]; @@ -129,12 +131,12 @@ static void t_log_block_read_write(void) struct reftable_buf block_data = REFTABLE_BUF_INIT; REFTABLE_CALLOC_ARRAY(block_data.buf, block_size); - check(block_data.buf != NULL); + cl_assert(block_data.buf != NULL); block_data.len = block_size; ret = block_writer_init(&bw, REFTABLE_BLOCK_TYPE_LOG, (uint8_t *) block_data.buf, block_size, header_off, hash_size(REFTABLE_HASH_SHA1)); - check(!ret); + cl_assert(!ret); for (i = 0; i < N; i++) { rec.u.log.refname = xstrfmt("branch%02"PRIuMAX , (uintmax_t)i); @@ -145,11 +147,11 @@ static void t_log_block_read_write(void) ret = block_writer_add(&bw, &rec); rec.u.log.refname = NULL; rec.u.log.value_type = REFTABLE_LOG_DELETION; - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); } ret = block_writer_finish(&bw); - check_int(ret, >, 0); + cl_assert(ret > 0); block_writer_release(&bw); @@ -161,33 +163,33 @@ static void t_log_block_read_write(void) for (i = 0; ; i++) { ret = block_iter_next(&it, &rec); - check_int(ret, >=, 0); + cl_assert(ret >= 0); if (ret > 0) { - check_int(i, ==, N); + cl_assert_equal_i(i, N); break; } - check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1), 1); } for (i = 0; i < N; i++) { reftable_buf_reset(&want); - check(!reftable_buf_addstr(&want, recs[i].u.log.refname)); + cl_assert(reftable_buf_addstr(&want, recs[i].u.log.refname) == 0); ret = block_iter_seek_key(&it, &want); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); ret = block_iter_next(&it, &rec); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); - check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1), 1); want.len--; ret = block_iter_seek_key(&it, &want); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); ret = block_iter_next(&it, &rec); - check_int(ret, ==, 0); - check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(ret, 0); + cl_assert_equal_i(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1), 1); } reftable_block_release(&block); @@ -199,7 +201,7 @@ static void t_log_block_read_write(void) reftable_record_release(&recs[i]); } -static void t_obj_block_read_write(void) +void test_reftable_block__obj_read_write(void) { const int header_off = 21; struct reftable_record recs[30]; @@ -220,12 +222,12 @@ static void t_obj_block_read_write(void) struct reftable_buf block_data = REFTABLE_BUF_INIT; REFTABLE_CALLOC_ARRAY(block_data.buf, block_size); - check(block_data.buf != NULL); + cl_assert(block_data.buf != NULL); block_data.len = block_size; ret = block_writer_init(&bw, REFTABLE_BLOCK_TYPE_OBJ, (uint8_t *) block_data.buf, block_size, header_off, hash_size(REFTABLE_HASH_SHA1)); - check(!ret); + cl_assert(!ret); for (i = 0; i < N; i++) { uint8_t bytes[] = { i, i + 1, i + 2, i + 3, i + 5 }, *allocated; @@ -238,11 +240,11 @@ static void t_obj_block_read_write(void) ret = block_writer_add(&bw, &rec); rec.u.obj.hash_prefix = NULL; rec.u.obj.hash_prefix_len = 0; - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); } ret = block_writer_finish(&bw); - check_int(ret, >, 0); + cl_assert(ret > 0); block_writer_release(&bw); @@ -254,24 +256,24 @@ static void t_obj_block_read_write(void) for (i = 0; ; i++) { ret = block_iter_next(&it, &rec); - check_int(ret, >=, 0); + cl_assert(ret >= 0); if (ret > 0) { - check_int(i, ==, N); + cl_assert_equal_i(i, N); break; } - check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1), 1); } for (i = 0; i < N; i++) { reftable_record_key(&recs[i], &want); ret = block_iter_seek_key(&it, &want); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); ret = block_iter_next(&it, &rec); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); - check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1), 1); } reftable_block_release(&block); @@ -283,7 +285,7 @@ static void t_obj_block_read_write(void) reftable_record_release(&recs[i]); } -static void t_index_block_read_write(void) +void test_reftable_block__ref_read_write(void) { const int header_off = 21; struct reftable_record recs[30]; @@ -305,12 +307,12 @@ static void t_index_block_read_write(void) struct reftable_buf block_data = REFTABLE_BUF_INIT; REFTABLE_CALLOC_ARRAY(block_data.buf, block_size); - check(block_data.buf != NULL); + cl_assert(block_data.buf != NULL); block_data.len = block_size; ret = block_writer_init(&bw, REFTABLE_BLOCK_TYPE_INDEX, (uint8_t *) block_data.buf, block_size, header_off, hash_size(REFTABLE_HASH_SHA1)); - check(!ret); + cl_assert(!ret); for (i = 0; i < N; i++) { char buf[128]; @@ -319,15 +321,15 @@ static void t_index_block_read_write(void) reftable_buf_init(&recs[i].u.idx.last_key); recs[i].type = REFTABLE_BLOCK_TYPE_INDEX; - check(!reftable_buf_addstr(&recs[i].u.idx.last_key, buf)); + cl_assert(!reftable_buf_addstr(&recs[i].u.idx.last_key, buf)); recs[i].u.idx.offset = i; ret = block_writer_add(&bw, &recs[i]); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); } ret = block_writer_finish(&bw); - check_int(ret, >, 0); + cl_assert(ret > 0); block_writer_release(&bw); @@ -339,32 +341,32 @@ static void t_index_block_read_write(void) for (i = 0; ; i++) { ret = block_iter_next(&it, &rec); - check_int(ret, >=, 0); + cl_assert(ret >= 0); if (ret > 0) { - check_int(i, ==, N); + cl_assert_equal_i(i, N); break; } - check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1), 1); } for (i = 0; i < N; i++) { reftable_record_key(&recs[i], &want); ret = block_iter_seek_key(&it, &want); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); ret = block_iter_next(&it, &rec); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); - check(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_record_equal(&recs[i], &rec, REFTABLE_HASH_SIZE_SHA1), 1); want.len--; ret = block_iter_seek_key(&it, &want); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); ret = block_iter_next(&it, &rec); - check_int(ret, ==, 0); - check(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(ret, 0); + cl_assert_equal_i(reftable_record_equal(&recs[10 * (i / 10)], &rec, REFTABLE_HASH_SIZE_SHA1), 1); } reftable_block_release(&block); @@ -376,7 +378,7 @@ static void t_index_block_read_write(void) reftable_record_release(&recs[i]); } -static void t_block_iterator(void) +void test_reftable_block__iterator(void) { struct reftable_block_source source = { 0 }; struct block_writer writer = { @@ -391,11 +393,12 @@ static void t_block_iterator(void) data.len = 1024; REFTABLE_CALLOC_ARRAY(data.buf, data.len); - check(data.buf != NULL); + cl_assert(data.buf != NULL); - err = block_writer_init(&writer, REFTABLE_BLOCK_TYPE_REF, (uint8_t *) data.buf, data.len, + err = block_writer_init(&writer, REFTABLE_BLOCK_TYPE_REF, + (uint8_t *) data.buf, data.len, 0, hash_size(REFTABLE_HASH_SHA1)); - check(!err); + cl_assert(!err); for (size_t i = 0; i < ARRAY_SIZE(expected_refs); i++) { expected_refs[i] = (struct reftable_record) { @@ -408,42 +411,42 @@ static void t_block_iterator(void) memset(expected_refs[i].u.ref.value.val1, i, REFTABLE_HASH_SIZE_SHA1); err = block_writer_add(&writer, &expected_refs[i]); - check_int(err, ==, 0); + cl_assert_equal_i(err, 0); } err = block_writer_finish(&writer); - check_int(err, >, 0); + cl_assert(err > 0); block_source_from_buf(&source, &data); reftable_block_init(&block, &source, 0, 0, data.len, REFTABLE_HASH_SIZE_SHA1, REFTABLE_BLOCK_TYPE_REF); err = reftable_block_init_iterator(&block, &it); - check_int(err, ==, 0); + cl_assert_equal_i(err, 0); for (size_t i = 0; ; i++) { err = reftable_iterator_next_ref(&it, &ref); if (err > 0) { - check_int(i, ==, ARRAY_SIZE(expected_refs)); + cl_assert_equal_i(i, ARRAY_SIZE(expected_refs)); break; } - check_int(err, ==, 0); + cl_assert_equal_i(err, 0); - check(reftable_ref_record_equal(&ref, &expected_refs[i].u.ref, - REFTABLE_HASH_SIZE_SHA1)); + cl_assert(reftable_ref_record_equal(&ref, + &expected_refs[i].u.ref, REFTABLE_HASH_SIZE_SHA1)); } err = reftable_iterator_seek_ref(&it, "refs/heads/does-not-exist"); - check_int(err, ==, 0); + cl_assert_equal_i(err, 0); err = reftable_iterator_next_ref(&it, &ref); - check_int(err, ==, 1); + cl_assert_equal_i(err, 1); err = reftable_iterator_seek_ref(&it, "refs/heads/branch-13"); - check_int(err, ==, 0); + cl_assert_equal_i(err, 0); err = reftable_iterator_next_ref(&it, &ref); - check_int(err, ==, 0); - check(reftable_ref_record_equal(&ref, &expected_refs[13].u.ref, - REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(err, 0); + cl_assert(reftable_ref_record_equal(&ref, + &expected_refs[13].u.ref,REFTABLE_HASH_SIZE_SHA1)); for (size_t i = 0; i < ARRAY_SIZE(expected_refs); i++) reftable_free(expected_refs[i].u.ref.refname); @@ -453,14 +456,3 @@ static void t_block_iterator(void) block_writer_release(&writer); reftable_buf_release(&data); } - -int cmd_main(int argc UNUSED, const char *argv[] UNUSED) -{ - TEST(t_index_block_read_write(), "read-write operations on index blocks work"); - TEST(t_log_block_read_write(), "read-write operations on log blocks work"); - TEST(t_obj_block_read_write(), "read-write operations on obj blocks work"); - TEST(t_ref_block_read_write(), "read-write operations on ref blocks work"); - TEST(t_block_iterator(), "block iterator works"); - - return test_done(); -} diff --git a/t/unit-tests/t-reftable-merged.c b/t/unit-tests/u-reftable-merged.c index 18c3251a56..54cb7fc2a7 100644 --- a/t/unit-tests/t-reftable-merged.c +++ b/t/unit-tests/u-reftable-merged.c @@ -6,7 +6,7 @@ license that can be found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd */ -#include "test-lib.h" +#include "unit-test.h" #include "lib-reftable.h" #include "reftable/blocksource.h" #include "reftable/constants.h" @@ -29,21 +29,21 @@ merged_table_from_records(struct reftable_ref_record **refs, int err; REFTABLE_CALLOC_ARRAY(*tables, n); - check(*tables != NULL); + cl_assert(*tables != NULL); REFTABLE_CALLOC_ARRAY(*source, n); - check(*source != NULL); + cl_assert(*source != NULL); for (size_t i = 0; i < n; i++) { - t_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts); + cl_reftable_write_to_buf(&buf[i], refs[i], sizes[i], NULL, 0, &opts); block_source_from_buf(&(*source)[i], &buf[i]); err = reftable_table_new(&(*tables)[i], &(*source)[i], "name"); - check(!err); + cl_assert(!err); } err = reftable_merged_table_new(&mt, *tables, n, REFTABLE_HASH_SHA1); - check(!err); + cl_assert(!err); return mt; } @@ -54,7 +54,7 @@ static void tables_destroy(struct reftable_table **tables, const size_t n) reftable_free(tables); } -static void t_merged_single_record(void) +void test_reftable_merged__single_record(void) { struct reftable_ref_record r1[] = { { .refname = (char *) "b", @@ -85,13 +85,14 @@ static void t_merged_single_record(void) int err; err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, "a"); - check(!err); + cl_assert(!err); err = reftable_iterator_next_ref(&it, &ref); - check(!err); - check(reftable_ref_record_equal(&r2[0], &ref, REFTABLE_HASH_SIZE_SHA1)); + cl_assert(!err); + cl_assert(reftable_ref_record_equal(&r2[0], &ref, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_ref_record_release(&ref); reftable_iterator_destroy(&it); tables_destroy(tables, 3); @@ -101,7 +102,7 @@ static void t_merged_single_record(void) reftable_free(bs); } -static void t_merged_refs(void) +void test_reftable_merged__refs(void) { struct reftable_ref_record r1[] = { { @@ -165,12 +166,12 @@ static void t_merged_refs(void) size_t i; err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, "a"); - check(!err); - check_int(reftable_merged_table_hash_id(mt), ==, REFTABLE_HASH_SHA1); - check_int(reftable_merged_table_min_update_index(mt), ==, 1); - check_int(reftable_merged_table_max_update_index(mt), ==, 3); + cl_assert(err == 0); + cl_assert_equal_i(reftable_merged_table_hash_id(mt), REFTABLE_HASH_SHA1); + cl_assert_equal_i(reftable_merged_table_min_update_index(mt), 1); + cl_assert_equal_i(reftable_merged_table_max_update_index(mt), 3); while (len < 100) { /* cap loops/recursion. */ struct reftable_ref_record ref = { 0 }; @@ -178,15 +179,15 @@ static void t_merged_refs(void) if (err > 0) break; - check(!REFTABLE_ALLOC_GROW(out, len + 1, cap)); + cl_assert(REFTABLE_ALLOC_GROW(out, len + 1, cap) == 0); out[len++] = ref; } reftable_iterator_destroy(&it); - check_int(ARRAY_SIZE(want), ==, len); + cl_assert_equal_i(ARRAY_SIZE(want), len); for (i = 0; i < len; i++) - check(reftable_ref_record_equal(want[i], &out[i], - REFTABLE_HASH_SIZE_SHA1)); + cl_assert(reftable_ref_record_equal(want[i], &out[i], + REFTABLE_HASH_SIZE_SHA1) != 0); for (i = 0; i < len; i++) reftable_ref_record_release(&out[i]); reftable_free(out); @@ -198,7 +199,7 @@ static void t_merged_refs(void) reftable_free(bs); } -static void t_merged_seek_multiple_times(void) +void test_reftable_merged__seek_multiple_times(void) { struct reftable_ref_record r1[] = { { @@ -248,20 +249,17 @@ static void t_merged_seek_multiple_times(void) for (size_t i = 0; i < 5; i++) { int err = reftable_iterator_seek_ref(&it, "c"); - check(!err); + cl_assert(!err); - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - err = reftable_ref_record_equal(&rec, &r1[1], REFTABLE_HASH_SIZE_SHA1); - check(err == 1); + cl_assert(reftable_iterator_next_ref(&it, &rec) == 0); + cl_assert_equal_i(reftable_ref_record_equal(&rec, &r1[1], + REFTABLE_HASH_SIZE_SHA1), 1); - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - err = reftable_ref_record_equal(&rec, &r2[1], REFTABLE_HASH_SIZE_SHA1); - check(err == 1); + cl_assert(reftable_iterator_next_ref(&it, &rec) == 0); + cl_assert_equal_i(reftable_ref_record_equal(&rec, &r2[1], + REFTABLE_HASH_SIZE_SHA1), 1); - err = reftable_iterator_next_ref(&it, &rec); - check(err > 0); + cl_assert(reftable_iterator_next_ref(&it, &rec) > 0); } for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) @@ -273,7 +271,7 @@ static void t_merged_seek_multiple_times(void) reftable_free(sources); } -static void t_merged_seek_multiple_times_without_draining(void) +void test_reftable_merged__seek_multiple_times_no_drain(void) { struct reftable_ref_record r1[] = { { @@ -317,24 +315,19 @@ static void t_merged_seek_multiple_times_without_draining(void) struct reftable_ref_record rec = { 0 }; struct reftable_iterator it = { 0 }; struct reftable_merged_table *mt; - int err; mt = merged_table_from_records(refs, &sources, &tables, sizes, bufs, 2); merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_REF); - err = reftable_iterator_seek_ref(&it, "b"); - check(!err); - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - err = reftable_ref_record_equal(&rec, &r2[0], REFTABLE_HASH_SIZE_SHA1); - check(err == 1); + cl_assert(reftable_iterator_seek_ref(&it, "b") == 0); + cl_assert(reftable_iterator_next_ref(&it, &rec) == 0); + cl_assert_equal_i(reftable_ref_record_equal(&rec, &r2[0], + REFTABLE_HASH_SIZE_SHA1), 1); - err = reftable_iterator_seek_ref(&it, "a"); - check(!err); - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - err = reftable_ref_record_equal(&rec, &r1[0], REFTABLE_HASH_SIZE_SHA1); - check(err == 1); + cl_assert(reftable_iterator_seek_ref(&it, "a") == 0); + cl_assert(reftable_iterator_next_ref(&it, &rec) == 0); + cl_assert_equal_i(reftable_ref_record_equal(&rec, &r1[0], + REFTABLE_HASH_SIZE_SHA1), 1); for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) reftable_buf_release(&bufs[i]); @@ -359,25 +352,25 @@ merged_table_from_log_records(struct reftable_log_record **logs, int err; REFTABLE_CALLOC_ARRAY(*tables, n); - check(*tables != NULL); + cl_assert(*tables != NULL); REFTABLE_CALLOC_ARRAY(*source, n); - check(*source != NULL); + cl_assert(*source != NULL); for (size_t i = 0; i < n; i++) { - t_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts); + cl_reftable_write_to_buf(&buf[i], NULL, 0, logs[i], sizes[i], &opts); block_source_from_buf(&(*source)[i], &buf[i]); err = reftable_table_new(&(*tables)[i], &(*source)[i], "name"); - check(!err); + cl_assert(!err); } err = reftable_merged_table_new(&mt, *tables, n, REFTABLE_HASH_SHA1); - check(!err); + cl_assert(!err); return mt; } -static void t_merged_logs(void) +void test_reftable_merged__logs(void) { struct reftable_log_record r1[] = { { @@ -439,19 +432,19 @@ static void t_merged_logs(void) struct reftable_merged_table *mt = merged_table_from_log_records( logs, &bs, &tables, sizes, bufs, 3); struct reftable_iterator it = { 0 }; - int err; struct reftable_log_record *out = NULL; size_t len = 0; size_t cap = 0; size_t i; + int err; err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_LOG); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_log(&it, "a"); - check(!err); - check_int(reftable_merged_table_hash_id(mt), ==, REFTABLE_HASH_SHA1); - check_int(reftable_merged_table_min_update_index(mt), ==, 1); - check_int(reftable_merged_table_max_update_index(mt), ==, 3); + cl_assert(!err); + cl_assert_equal_i(reftable_merged_table_hash_id(mt), REFTABLE_HASH_SHA1); + cl_assert_equal_i(reftable_merged_table_min_update_index(mt), 1); + cl_assert_equal_i(reftable_merged_table_max_update_index(mt), 3); while (len < 100) { /* cap loops/recursion. */ struct reftable_log_record log = { 0 }; @@ -459,24 +452,24 @@ static void t_merged_logs(void) if (err > 0) break; - check(!REFTABLE_ALLOC_GROW(out, len + 1, cap)); + cl_assert(REFTABLE_ALLOC_GROW(out, len + 1, cap) == 0); out[len++] = log; } reftable_iterator_destroy(&it); - check_int(ARRAY_SIZE(want), ==, len); + cl_assert_equal_i(ARRAY_SIZE(want), len); for (i = 0; i < len; i++) - check(reftable_log_record_equal(want[i], &out[i], - REFTABLE_HASH_SIZE_SHA1)); + cl_assert(reftable_log_record_equal(want[i], &out[i], + REFTABLE_HASH_SIZE_SHA1) != 0); err = merged_table_init_iter(mt, &it, REFTABLE_BLOCK_TYPE_LOG); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_log_at(&it, "a", 2); - check(!err); + cl_assert(!err); reftable_log_record_release(&out[0]); - err = reftable_iterator_next_log(&it, &out[0]); - check(!err); - check(reftable_log_record_equal(&out[0], &r3[0], REFTABLE_HASH_SIZE_SHA1)); + cl_assert(reftable_iterator_next_log(&it, &out[0]) == 0); + cl_assert(reftable_log_record_equal(&out[0], &r3[0], + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_iterator_destroy(&it); for (i = 0; i < len; i++) @@ -490,11 +483,11 @@ static void t_merged_logs(void) reftable_free(bs); } -static void t_default_write_opts(void) +void test_reftable_merged__default_write_opts(void) { struct reftable_write_options opts = { 0 }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record rec = { .refname = (char *) "master", .update_index = 1, @@ -507,40 +500,25 @@ static void t_default_write_opts(void) reftable_writer_set_limits(w, 1, 1); - err = reftable_writer_add_ref(w, &rec); - check(!err); + cl_assert_equal_i(reftable_writer_add_ref(w, &rec), 0); - err = reftable_writer_close(w); - check(!err); + cl_assert_equal_i(reftable_writer_close(w), 0); reftable_writer_free(w); block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "filename"); - check(!err); + cl_assert(!err); hash_id = reftable_table_hash_id(table); - check_int(hash_id, ==, REFTABLE_HASH_SHA1); + cl_assert_equal_i(hash_id, REFTABLE_HASH_SHA1); err = reftable_merged_table_new(&merged, &table, 1, REFTABLE_HASH_SHA256); - check_int(err, ==, REFTABLE_FORMAT_ERROR); + cl_assert_equal_i(err, REFTABLE_FORMAT_ERROR); err = reftable_merged_table_new(&merged, &table, 1, REFTABLE_HASH_SHA1); - check(!err); + cl_assert(!err); reftable_table_decref(table); reftable_merged_table_free(merged); reftable_buf_release(&buf); } - - -int cmd_main(int argc UNUSED, const char *argv[] UNUSED) -{ - TEST(t_default_write_opts(), "merged table with default write opts"); - TEST(t_merged_logs(), "merged table with multiple log updates for same ref"); - TEST(t_merged_refs(), "merged table with multiple updates to same ref"); - TEST(t_merged_seek_multiple_times(), "merged table can seek multiple times"); - TEST(t_merged_seek_multiple_times_without_draining(), "merged table can seek multiple times without draining"); - TEST(t_merged_single_record(), "ref occurring in only one record can be fetched"); - - return test_done(); -} diff --git a/t/unit-tests/t-reftable-pq.c b/t/unit-tests/u-reftable-pq.c index fb5a4eb187..f8a28f6e07 100644 --- a/t/unit-tests/t-reftable-pq.c +++ b/t/unit-tests/u-reftable-pq.c @@ -6,7 +6,8 @@ license that can be found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd */ -#include "test-lib.h" +#include "unit-test.h" +#include "lib-reftable.h" #include "reftable/constants.h" #include "reftable/pq.h" #include "strbuf.h" @@ -15,18 +16,18 @@ static void merged_iter_pqueue_check(const struct merged_iter_pqueue *pq) { for (size_t i = 1; i < pq->len; i++) { size_t parent = (i - 1) / 2; - check(pq_less(&pq->heap[parent], &pq->heap[i])); + cl_assert(pq_less(&pq->heap[parent], &pq->heap[i]) != 0); } } static int pq_entry_equal(struct pq_entry *a, struct pq_entry *b) { int cmp; - check(!reftable_record_cmp(a->rec, b->rec, &cmp)); + cl_assert_equal_i(reftable_record_cmp(a->rec, b->rec, &cmp), 0); return !cmp && (a->index == b->index); } -static void t_pq_record(void) +void test_reftable_pq__record(void) { struct merged_iter_pqueue pq = { 0 }; struct reftable_record recs[54]; @@ -34,7 +35,8 @@ static void t_pq_record(void) char *last = NULL; for (i = 0; i < N; i++) { - check(!reftable_record_init(&recs[i], REFTABLE_BLOCK_TYPE_REF)); + cl_assert(!reftable_record_init(&recs[i], + REFTABLE_BLOCK_TYPE_REF)); recs[i].u.ref.refname = xstrfmt("%02"PRIuMAX, (uintmax_t)i); } @@ -53,13 +55,13 @@ static void t_pq_record(void) struct pq_entry top = merged_iter_pqueue_top(pq); struct pq_entry e; - check(!merged_iter_pqueue_remove(&pq, &e)); + cl_assert_equal_i(merged_iter_pqueue_remove(&pq, &e), 0); merged_iter_pqueue_check(&pq); - check(pq_entry_equal(&top, &e)); - check(reftable_record_type(e.rec) == REFTABLE_BLOCK_TYPE_REF); + cl_assert(pq_entry_equal(&top, &e)); + cl_assert(reftable_record_type(e.rec) == REFTABLE_BLOCK_TYPE_REF); if (last) - check_int(strcmp(last, e.rec->u.ref.refname), <, 0); + cl_assert(strcmp(last, e.rec->u.ref.refname) < 0); last = e.rec->u.ref.refname; } @@ -68,7 +70,7 @@ static void t_pq_record(void) merged_iter_pqueue_release(&pq); } -static void t_pq_index(void) +void test_reftable_pq__index(void) { struct merged_iter_pqueue pq = { 0 }; struct reftable_record recs[13]; @@ -76,7 +78,8 @@ static void t_pq_index(void) size_t N = ARRAY_SIZE(recs), i; for (i = 0; i < N; i++) { - check(!reftable_record_init(&recs[i], REFTABLE_BLOCK_TYPE_REF)); + cl_assert(!reftable_record_init(&recs[i], + REFTABLE_BLOCK_TYPE_REF)); recs[i].u.ref.refname = (char *) "refs/heads/master"; } @@ -96,28 +99,29 @@ static void t_pq_index(void) struct pq_entry top = merged_iter_pqueue_top(pq); struct pq_entry e; - check(!merged_iter_pqueue_remove(&pq, &e)); + cl_assert_equal_i(merged_iter_pqueue_remove(&pq, &e), 0); merged_iter_pqueue_check(&pq); - check(pq_entry_equal(&top, &e)); - check(reftable_record_type(e.rec) == REFTABLE_BLOCK_TYPE_REF); - check_int(e.index, ==, i); + cl_assert(pq_entry_equal(&top, &e)); + cl_assert(reftable_record_type(e.rec) == REFTABLE_BLOCK_TYPE_REF); + cl_assert_equal_i(e.index, i); if (last) - check_str(last, e.rec->u.ref.refname); + cl_assert_equal_s(last, e.rec->u.ref.refname); last = e.rec->u.ref.refname; } merged_iter_pqueue_release(&pq); } -static void t_merged_iter_pqueue_top(void) +void test_reftable_pq__merged_iter_pqueue_top(void) { struct merged_iter_pqueue pq = { 0 }; struct reftable_record recs[13]; size_t N = ARRAY_SIZE(recs), i; for (i = 0; i < N; i++) { - check(!reftable_record_init(&recs[i], REFTABLE_BLOCK_TYPE_REF)); + cl_assert(!reftable_record_init(&recs[i], + REFTABLE_BLOCK_TYPE_REF)); recs[i].u.ref.refname = (char *) "refs/heads/master"; } @@ -137,25 +141,16 @@ static void t_merged_iter_pqueue_top(void) struct pq_entry top = merged_iter_pqueue_top(pq); struct pq_entry e; - check(!merged_iter_pqueue_remove(&pq, &e)); + cl_assert_equal_i(merged_iter_pqueue_remove(&pq, &e), 0); merged_iter_pqueue_check(&pq); - check(pq_entry_equal(&top, &e)); - check(reftable_record_equal(top.rec, &recs[i], REFTABLE_HASH_SIZE_SHA1)); + cl_assert(pq_entry_equal(&top, &e) != 0); + cl_assert(reftable_record_equal(top.rec, &recs[i], REFTABLE_HASH_SIZE_SHA1) != 0); for (size_t j = 0; i < pq.len; j++) { - check(pq_less(&top, &pq.heap[j])); - check_int(top.index, >, j); + cl_assert(pq_less(&top, &pq.heap[j]) != 0); + cl_assert(top.index > j); } } merged_iter_pqueue_release(&pq); } - -int cmd_main(int argc UNUSED, const char *argv[] UNUSED) -{ - TEST(t_pq_record(), "pq works with record-based comparison"); - TEST(t_pq_index(), "pq works with index-based comparison"); - TEST(t_merged_iter_pqueue_top(), "merged_iter_pqueue_top works"); - - return test_done(); -} diff --git a/t/unit-tests/t-reftable-readwrite.c b/t/unit-tests/u-reftable-readwrite.c index 4c49129439..4d8c4be5f1 100644 --- a/t/unit-tests/t-reftable-readwrite.c +++ b/t/unit-tests/u-reftable-readwrite.c @@ -8,7 +8,7 @@ https://developers.google.com/open-source/licenses/bsd #define DISABLE_SIGN_COMPARE_WARNINGS -#include "test-lib.h" +#include "unit-test.h" #include "lib-reftable.h" #include "reftable/basics.h" #include "reftable/blocksource.h" @@ -19,24 +19,24 @@ https://developers.google.com/open-source/licenses/bsd static const int update_index = 5; -static void t_buffer(void) +void test_reftable_readwrite__buffer(void) { struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_block_source source = { 0 }; struct reftable_block_data out = { 0 }; int n; uint8_t in[] = "hello"; - check(!reftable_buf_add(&buf, in, sizeof(in))); + cl_assert_equal_i(reftable_buf_add(&buf, in, sizeof(in)), 0); block_source_from_buf(&source, &buf); - check_int(block_source_size(&source), ==, 6); + cl_assert_equal_i(block_source_size(&source), 6); n = block_source_read_data(&source, &out, 0, sizeof(in)); - check_int(n, ==, sizeof(in)); - check(!memcmp(in, out.data, n)); + cl_assert_equal_i(n, sizeof(in)); + cl_assert(!memcmp(in, out.data, n)); block_source_release_data(&out); n = block_source_read_data(&source, &out, 1, 2); - check_int(n, ==, 2); - check(!memcmp(out.data, "el", 2)); + cl_assert_equal_i(n, 2); + cl_assert(!memcmp(out.data, "el", 2)); block_source_release_data(&out); block_source_close(&source); @@ -55,41 +55,41 @@ static void write_table(char ***names, struct reftable_buf *buf, int N, int i; REFTABLE_CALLOC_ARRAY(*names, N + 1); - check(*names != NULL); + cl_assert(*names != NULL); REFTABLE_CALLOC_ARRAY(refs, N); - check(refs != NULL); + cl_assert(refs != NULL); REFTABLE_CALLOC_ARRAY(logs, N); - check(logs != NULL); + cl_assert(logs != NULL); for (i = 0; i < N; i++) { refs[i].refname = (*names)[i] = xstrfmt("refs/heads/branch%02d", i); refs[i].update_index = update_index; refs[i].value_type = REFTABLE_REF_VAL1; - t_reftable_set_hash(refs[i].value.val1, i, REFTABLE_HASH_SHA1); + cl_reftable_set_hash(refs[i].value.val1, i, + REFTABLE_HASH_SHA1); } for (i = 0; i < N; i++) { logs[i].refname = (*names)[i]; logs[i].update_index = update_index; logs[i].value_type = REFTABLE_LOG_UPDATE; - t_reftable_set_hash(logs[i].value.update.new_hash, i, - REFTABLE_HASH_SHA1); + cl_reftable_set_hash(logs[i].value.update.new_hash, i, + REFTABLE_HASH_SHA1); logs[i].value.update.message = (char *) "message"; } - t_reftable_write_to_buf(buf, refs, N, logs, N, &opts); + cl_reftable_write_to_buf(buf, refs, N, logs, N, &opts); reftable_free(refs); reftable_free(logs); } -static void t_log_buffer_size(void) +void test_reftable_readwrite__log_buffer_size(void) { struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_write_options opts = { .block_size = 4096, }; - int err; int i; struct reftable_log_record log = { .refname = (char *) "refs/heads/master", @@ -102,7 +102,8 @@ static void t_log_buffer_size(void) .time = 0x5e430672, .message = (char *) "commit: 9\n", } } }; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); /* This tests buffer extension for log compression. Must use a random hash, to ensure that the compressed part is larger than the original. @@ -112,22 +113,19 @@ static void t_log_buffer_size(void) log.value.update.new_hash[i] = (uint8_t)(git_rand(0) % 256); } reftable_writer_set_limits(w, update_index, update_index); - err = reftable_writer_add_log(w, &log); - check(!err); - err = reftable_writer_close(w); - check(!err); + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); + cl_assert_equal_i(reftable_writer_close(w), 0); reftable_writer_free(w); reftable_buf_release(&buf); } -static void t_log_overflow(void) +void test_reftable_readwrite__log_overflow(void) { struct reftable_buf buf = REFTABLE_BUF_INIT; char msg[256] = { 0 }; struct reftable_write_options opts = { .block_size = ARRAY_SIZE(msg), }; - int err; struct reftable_log_record log = { .refname = (char *) "refs/heads/master", .update_index = update_index, @@ -144,21 +142,22 @@ static void t_log_overflow(void) }, }, }; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); memset(msg, 'x', sizeof(msg) - 1); reftable_writer_set_limits(w, update_index, update_index); - err = reftable_writer_add_log(w, &log); - check_int(err, ==, REFTABLE_ENTRY_TOO_BIG_ERROR); + cl_assert_equal_i(reftable_writer_add_log(w, &log), REFTABLE_ENTRY_TOO_BIG_ERROR); reftable_writer_free(w); reftable_buf_release(&buf); } -static void t_log_write_limits(void) +void test_reftable_readwrite__log_write_limits(void) { struct reftable_write_options opts = { 0 }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); struct reftable_log_record log = { .refname = (char *)"refs/head/master", .update_index = 0, @@ -174,29 +173,25 @@ static void t_log_write_limits(void) }, }, }; - int err; reftable_writer_set_limits(w, 1, 1); /* write with update_index (0) below set limits (1, 1) */ - err = reftable_writer_add_log(w, &log); - check_int(err, ==, 0); + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); /* write with update_index (1) in the set limits (1, 1) */ log.update_index = 1; - err = reftable_writer_add_log(w, &log); - check_int(err, ==, 0); + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); /* write with update_index (3) above set limits (1, 1) */ log.update_index = 3; - err = reftable_writer_add_log(w, &log); - check_int(err, ==, REFTABLE_API_ERROR); + cl_assert_equal_i(reftable_writer_add_log(w, &log), REFTABLE_API_ERROR); reftable_writer_free(w); reftable_buf_release(&buf); } -static void t_log_write_read(void) +void test_reftable_readwrite__log_write_read(void) { struct reftable_write_options opts = { .block_size = 256, @@ -207,13 +202,14 @@ static void t_log_write_read(void) struct reftable_table *table; struct reftable_block_source source = { 0 }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); const struct reftable_stats *stats = NULL; - int N = 2, err, i, n; + int N = 2, i; char **names; + int err; names = reftable_calloc(N + 1, sizeof(*names)); - check(names != NULL); + cl_assert(names != NULL); reftable_writer_set_limits(w, 0, N); @@ -225,8 +221,7 @@ static void t_log_write_read(void) ref.refname = name; ref.update_index = i; - err = reftable_writer_add_ref(w, &ref); - check(!err); + cl_assert_equal_i(reftable_writer_add_ref(w, &ref), 0); } for (i = 0; i < N; i++) { @@ -235,60 +230,57 @@ static void t_log_write_read(void) log.refname = names[i]; log.update_index = i; log.value_type = REFTABLE_LOG_UPDATE; - t_reftable_set_hash(log.value.update.old_hash, i, - REFTABLE_HASH_SHA1); - t_reftable_set_hash(log.value.update.new_hash, i + 1, - REFTABLE_HASH_SHA1); + cl_reftable_set_hash(log.value.update.old_hash, i, + REFTABLE_HASH_SHA1); + cl_reftable_set_hash(log.value.update.new_hash, i + 1, + REFTABLE_HASH_SHA1); - err = reftable_writer_add_log(w, &log); - check(!err); + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); } - n = reftable_writer_close(w); - check_int(n, ==, 0); + cl_assert_equal_i(reftable_writer_close(w), 0); stats = reftable_writer_stats(w); - check_int(stats->log_stats.blocks, >, 0); + cl_assert(stats->log_stats.blocks > 0); reftable_writer_free(w); w = NULL; block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "file.log"); - check(!err); + cl_assert(!err); err = reftable_table_init_ref_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, names[N - 1]); - check(!err); + cl_assert(!err); err = reftable_iterator_next_ref(&it, &ref); - check(!err); + cl_assert(!err); /* end of iteration. */ - err = reftable_iterator_next_ref(&it, &ref); - check_int(err, >, 0); + cl_assert(reftable_iterator_next_ref(&it, &ref) > 0); reftable_iterator_destroy(&it); reftable_ref_record_release(&ref); err = reftable_table_init_log_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_log(&it, ""); - check(!err); + cl_assert(!err); for (i = 0; ; i++) { int err = reftable_iterator_next_log(&it, &log); if (err > 0) break; - check(!err); - check_str(names[i], log.refname); - check_int(i, ==, log.update_index); + cl_assert(!err); + cl_assert_equal_s(names[i], log.refname); + cl_assert_equal_i(i, log.update_index); reftable_log_record_release(&log); } - check_int(i, ==, N); + cl_assert_equal_i(i, N); reftable_iterator_destroy(&it); /* cleanup. */ @@ -297,7 +289,7 @@ static void t_log_write_read(void) reftable_table_decref(table); } -static void t_log_zlib_corruption(void) +void test_reftable_readwrite__log_zlib_corruption(void) { struct reftable_write_options opts = { .block_size = 256, @@ -306,10 +298,12 @@ static void t_log_zlib_corruption(void) struct reftable_table *table; struct reftable_block_source source = { 0 }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); const struct reftable_stats *stats = NULL; char message[100] = { 0 }; - int err, i, n; + int i; + int err; struct reftable_log_record log = { .refname = (char *) "refname", .value_type = REFTABLE_LOG_UPDATE, @@ -329,14 +323,11 @@ static void t_log_zlib_corruption(void) reftable_writer_set_limits(w, 1, 1); - err = reftable_writer_add_log(w, &log); - check(!err); - - n = reftable_writer_close(w); - check_int(n, ==, 0); + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); + cl_assert_equal_i(reftable_writer_close(w), 0); stats = reftable_writer_stats(w); - check_int(stats->log_stats.blocks, >, 0); + cl_assert(stats->log_stats.blocks > 0); reftable_writer_free(w); w = NULL; @@ -346,12 +337,12 @@ static void t_log_zlib_corruption(void) block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "file.log"); - check(!err); + cl_assert(!err); err = reftable_table_init_log_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_log(&it, "refname"); - check_int(err, ==, REFTABLE_ZLIB_ERROR); + cl_assert_equal_i(err, REFTABLE_ZLIB_ERROR); reftable_iterator_destroy(&it); @@ -360,7 +351,7 @@ static void t_log_zlib_corruption(void) reftable_buf_release(&buf); } -static void t_table_read_write_sequential(void) +void test_reftable_readwrite__table_read_write_sequential(void) { char **names; struct reftable_buf buf = REFTABLE_BUF_INIT; @@ -376,24 +367,24 @@ static void t_table_read_write_sequential(void) block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "file.ref"); - check(!err); + cl_assert(!err); err = reftable_table_init_ref_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, ""); - check(!err); + cl_assert(!err); for (j = 0; ; j++) { struct reftable_ref_record ref = { 0 }; int r = reftable_iterator_next_ref(&it, &ref); - check_int(r, >=, 0); + cl_assert(r >= 0); if (r > 0) break; - check_str(names[j], ref.refname); - check_int(update_index, ==, ref.update_index); + cl_assert_equal_s(names[j], ref.refname); + cl_assert_equal_i(update_index, ref.update_index); reftable_ref_record_release(&ref); } - check_int(j, ==, N); + cl_assert_equal_i(j, N); reftable_iterator_destroy(&it); reftable_table_decref(table); @@ -401,42 +392,42 @@ static void t_table_read_write_sequential(void) free_names(names); } -static void t_table_write_small_table(void) +void test_reftable_readwrite__table_write_small_table(void) { char **names; struct reftable_buf buf = REFTABLE_BUF_INIT; int N = 1; write_table(&names, &buf, N, 4096, REFTABLE_HASH_SHA1); - check_int(buf.len, <, 200); + cl_assert(buf.len < 200); reftable_buf_release(&buf); free_names(names); } -static void t_table_read_api(void) +void test_reftable_readwrite__table_read_api(void) { char **names; struct reftable_buf buf = REFTABLE_BUF_INIT; int N = 50; struct reftable_table *table; struct reftable_block_source source = { 0 }; - int err; struct reftable_log_record log = { 0 }; struct reftable_iterator it = { 0 }; + int err; write_table(&names, &buf, N, 256, REFTABLE_HASH_SHA1); block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "file.ref"); - check(!err); + cl_assert(!err); err = reftable_table_init_ref_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, names[0]); - check(!err); + cl_assert(!err); err = reftable_iterator_next_log(&it, &log); - check_int(err, ==, REFTABLE_API_ERROR); + cl_assert_equal_i(err, REFTABLE_API_ERROR); reftable_buf_release(&buf); free_names(names); @@ -464,42 +455,43 @@ static void t_table_read_write_seek(int index, enum reftable_hash hash_id) block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "file.ref"); - check(!err); - check_int(hash_id, ==, reftable_table_hash_id(table)); + cl_assert(!err); + cl_assert_equal_i(hash_id, reftable_table_hash_id(table)); if (!index) { table->ref_offsets.index_offset = 0; } else { - check_int(table->ref_offsets.index_offset, >, 0); + cl_assert(table->ref_offsets.index_offset > 0); } for (i = 1; i < N; i++) { err = reftable_table_init_ref_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, names[i]); - check(!err); + cl_assert(!err); err = reftable_iterator_next_ref(&it, &ref); - check(!err); - check_str(names[i], ref.refname); - check_int(REFTABLE_REF_VAL1, ==, ref.value_type); - check_int(i, ==, ref.value.val1[0]); + cl_assert(!err); + cl_assert_equal_s(names[i], ref.refname); + cl_assert_equal_i(REFTABLE_REF_VAL1, ref.value_type); + cl_assert_equal_i(i, ref.value.val1[0]); reftable_ref_record_release(&ref); reftable_iterator_destroy(&it); } - check(!reftable_buf_addstr(&pastLast, names[N - 1])); - check(!reftable_buf_addstr(&pastLast, "/")); + cl_assert_equal_i(reftable_buf_addstr(&pastLast, names[N - 1]), + 0); + cl_assert_equal_i(reftable_buf_addstr(&pastLast, "/"), 0); err = reftable_table_init_ref_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, pastLast.buf); if (err == 0) { struct reftable_ref_record ref = { 0 }; int err = reftable_iterator_next_ref(&it, &ref); - check_int(err, >, 0); + cl_assert(err > 0); } else { - check_int(err, >, 0); + cl_assert(err > 0); } reftable_buf_release(&pastLast); @@ -510,17 +502,17 @@ static void t_table_read_write_seek(int index, enum reftable_hash hash_id) reftable_table_decref(table); } -static void t_table_read_write_seek_linear(void) +void test_reftable_readwrite__table_read_write_seek_linear(void) { t_table_read_write_seek(0, REFTABLE_HASH_SHA1); } -static void t_table_read_write_seek_linear_sha256(void) +void test_reftable_readwrite__table_read_write_seek_linear_sha256(void) { t_table_read_write_seek(0, REFTABLE_HASH_SHA256); } -static void t_table_read_write_seek_index(void) +void test_reftable_readwrite__table_read_write_seek_index(void) { t_table_read_write_seek(1, REFTABLE_HASH_SHA1); } @@ -538,14 +530,16 @@ static void t_table_refs_for(int indexed) struct reftable_table *table; struct reftable_block_source source = { 0 }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); struct reftable_iterator it = { 0 }; - int N = 50, n, j, err, i; + int N = 50, j, i; + int err; want_names = reftable_calloc(N + 1, sizeof(*want_names)); - check(want_names != NULL); + cl_assert(want_names != NULL); - t_reftable_set_hash(want_hash, 4, REFTABLE_HASH_SHA1); + cl_reftable_set_hash(want_hash, 4, REFTABLE_HASH_SHA1); for (i = 0; i < N; i++) { uint8_t hash[REFTABLE_HASH_SIZE_SHA1]; @@ -561,24 +555,22 @@ static void t_table_refs_for(int indexed) ref.refname = name; ref.value_type = REFTABLE_REF_VAL2; - t_reftable_set_hash(ref.value.val2.value, i / 4, - REFTABLE_HASH_SHA1); - t_reftable_set_hash(ref.value.val2.target_value, 3 + i / 4, - REFTABLE_HASH_SHA1); + cl_reftable_set_hash(ref.value.val2.value, i / 4, + REFTABLE_HASH_SHA1); + cl_reftable_set_hash(ref.value.val2.target_value, + 3 + i / 4, REFTABLE_HASH_SHA1); /* 80 bytes / entry, so 3 entries per block. Yields 17 */ /* blocks. */ - n = reftable_writer_add_ref(w, &ref); - check_int(n, ==, 0); + cl_assert_equal_i(reftable_writer_add_ref(w, &ref), 0); if (!memcmp(ref.value.val2.value, want_hash, REFTABLE_HASH_SIZE_SHA1) || !memcmp(ref.value.val2.target_value, want_hash, REFTABLE_HASH_SIZE_SHA1)) want_names[want_names_len++] = xstrdup(name); } - n = reftable_writer_close(w); - check_int(n, ==, 0); + cl_assert_equal_i(reftable_writer_close(w), 0); reftable_writer_free(w); w = NULL; @@ -586,29 +578,29 @@ static void t_table_refs_for(int indexed) block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "file.ref"); - check(!err); + cl_assert(!err); if (!indexed) table->obj_offsets.is_present = 0; err = reftable_table_init_ref_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, ""); - check(!err); + cl_assert(!err); reftable_iterator_destroy(&it); err = reftable_table_refs_for(table, &it, want_hash); - check(!err); + cl_assert(!err); for (j = 0; ; j++) { int err = reftable_iterator_next_ref(&it, &ref); - check_int(err, >=, 0); + cl_assert(err >= 0); if (err > 0) break; - check_int(j, <, want_names_len); - check_str(ref.refname, want_names[j]); + cl_assert(j < want_names_len); + cl_assert_equal_s(ref.refname, want_names[j]); reftable_ref_record_release(&ref); } - check_int(j, ==, want_names_len); + cl_assert_equal_i(j, want_names_len); reftable_buf_release(&buf); free_names(want_names); @@ -616,21 +608,21 @@ static void t_table_refs_for(int indexed) reftable_table_decref(table); } -static void t_table_refs_for_no_index(void) +void test_reftable_readwrite__table_refs_for_no_index(void) { t_table_refs_for(0); } -static void t_table_refs_for_obj_index(void) +void test_reftable_readwrite__table_refs_for_obj_index(void) { t_table_refs_for(1); } -static void t_write_empty_table(void) +void test_reftable_readwrite__write_empty_table(void) { struct reftable_write_options opts = { 0 }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); struct reftable_block_source source = { 0 }; struct reftable_table *table = NULL; struct reftable_ref_record rec = { 0 }; @@ -639,43 +631,41 @@ static void t_write_empty_table(void) reftable_writer_set_limits(w, 1, 1); - err = reftable_writer_close(w); - check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR); + cl_assert_equal_i(reftable_writer_close(w), REFTABLE_EMPTY_TABLE_ERROR); reftable_writer_free(w); - check_uint(buf.len, ==, header_size(1) + footer_size(1)); + cl_assert_equal_i(buf.len, header_size(1) + footer_size(1)); block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "filename"); - check(!err); + cl_assert(!err); err = reftable_table_init_ref_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, ""); - check(!err); + cl_assert(!err); err = reftable_iterator_next_ref(&it, &rec); - check_int(err, >, 0); + cl_assert(err > 0); reftable_iterator_destroy(&it); reftable_table_decref(table); reftable_buf_release(&buf); } -static void t_write_object_id_min_length(void) +void test_reftable_readwrite__write_object_id_min_length(void) { struct reftable_write_options opts = { .block_size = 75, }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record ref = { .update_index = 1, .value_type = REFTABLE_REF_VAL1, .value.val1 = {42}, }; - int err; int i; reftable_writer_set_limits(w, 1, 1); @@ -686,30 +676,27 @@ static void t_write_object_id_min_length(void) char name[256]; snprintf(name, sizeof(name), "ref%05d", i); ref.refname = name; - err = reftable_writer_add_ref(w, &ref); - check(!err); + cl_assert_equal_i(reftable_writer_add_ref(w, &ref), 0); } - err = reftable_writer_close(w); - check(!err); - check_int(reftable_writer_stats(w)->object_id_len, ==, 2); + cl_assert_equal_i(reftable_writer_close(w), 0); + cl_assert_equal_i(reftable_writer_stats(w)->object_id_len, 2); reftable_writer_free(w); reftable_buf_release(&buf); } -static void t_write_object_id_length(void) +void test_reftable_readwrite__write_object_id_length(void) { struct reftable_write_options opts = { .block_size = 75, }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record ref = { .update_index = 1, .value_type = REFTABLE_REF_VAL1, .value.val1 = {42}, }; - int err; int i; reftable_writer_set_limits(w, 1, 1); @@ -721,44 +708,39 @@ static void t_write_object_id_length(void) snprintf(name, sizeof(name), "ref%05d", i); ref.refname = name; ref.value.val1[15] = i; - err = reftable_writer_add_ref(w, &ref); - check(!err); + cl_assert(reftable_writer_add_ref(w, &ref) == 0); } - err = reftable_writer_close(w); - check(!err); - check_int(reftable_writer_stats(w)->object_id_len, ==, 16); + cl_assert_equal_i(reftable_writer_close(w), 0); + cl_assert_equal_i(reftable_writer_stats(w)->object_id_len, 16); reftable_writer_free(w); reftable_buf_release(&buf); } -static void t_write_empty_key(void) +void test_reftable_readwrite__write_empty_key(void) { struct reftable_write_options opts = { 0 }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record ref = { .refname = (char *) "", .update_index = 1, .value_type = REFTABLE_REF_DELETION, }; - int err; reftable_writer_set_limits(w, 1, 1); - err = reftable_writer_add_ref(w, &ref); - check_int(err, ==, REFTABLE_API_ERROR); - - err = reftable_writer_close(w); - check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR); + cl_assert_equal_i(reftable_writer_add_ref(w, &ref), REFTABLE_API_ERROR); + cl_assert_equal_i(reftable_writer_close(w), + REFTABLE_EMPTY_TABLE_ERROR); reftable_writer_free(w); reftable_buf_release(&buf); } -static void t_write_key_order(void) +void test_reftable_readwrite__write_key_order(void) { struct reftable_write_options opts = { 0 }; struct reftable_buf buf = REFTABLE_BUF_INIT; - struct reftable_writer *w = t_reftable_strbuf_writer(&buf, &opts); + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); struct reftable_ref_record refs[2] = { { .refname = (char *) "b", @@ -776,24 +758,21 @@ static void t_write_key_order(void) }, } }; - int err; reftable_writer_set_limits(w, 1, 1); - err = reftable_writer_add_ref(w, &refs[0]); - check(!err); - err = reftable_writer_add_ref(w, &refs[1]); - check_int(err, ==, REFTABLE_API_ERROR); + cl_assert_equal_i(reftable_writer_add_ref(w, &refs[0]), 0); + cl_assert_equal_i(reftable_writer_add_ref(w, &refs[1]), + REFTABLE_API_ERROR); refs[0].update_index = 2; - err = reftable_writer_add_ref(w, &refs[0]); - check_int(err, ==, REFTABLE_API_ERROR); + cl_assert_equal_i(reftable_writer_add_ref(w, &refs[0]), REFTABLE_API_ERROR); reftable_writer_close(w); reftable_writer_free(w); reftable_buf_release(&buf); } -static void t_write_multiple_indices(void) +void test_reftable_readwrite__write_multiple_indices(void) { struct reftable_write_options opts = { .block_size = 100, @@ -805,9 +784,10 @@ static void t_write_multiple_indices(void) struct reftable_writer *writer; struct reftable_table *table; char buf[128]; - int err, i; + int i; + int err; - writer = t_reftable_strbuf_writer(&writer_buf, &opts); + writer = cl_reftable_strbuf_writer(&writer_buf, &opts); reftable_writer_set_limits(writer, 1, 1); for (i = 0; i < 100; i++) { struct reftable_ref_record ref = { @@ -819,8 +799,7 @@ static void t_write_multiple_indices(void) snprintf(buf, sizeof(buf), "refs/heads/%04d", i); ref.refname = buf; - err = reftable_writer_add_ref(writer, &ref); - check(!err); + cl_assert_equal_i(reftable_writer_add_ref(writer, &ref), 0); } for (i = 0; i < 100; i++) { @@ -836,8 +815,7 @@ static void t_write_multiple_indices(void) snprintf(buf, sizeof(buf), "refs/heads/%04d", i); log.refname = buf; - err = reftable_writer_add_log(writer, &log); - check(!err); + cl_assert_equal_i(reftable_writer_add_log(writer, &log), 0); } reftable_writer_close(writer); @@ -847,22 +825,22 @@ static void t_write_multiple_indices(void) * for each of the block types. */ stats = reftable_writer_stats(writer); - check_int(stats->ref_stats.index_offset, >, 0); - check_int(stats->obj_stats.index_offset, >, 0); - check_int(stats->log_stats.index_offset, >, 0); + cl_assert(stats->ref_stats.index_offset > 0); + cl_assert(stats->obj_stats.index_offset > 0); + cl_assert(stats->log_stats.index_offset > 0); block_source_from_buf(&source, &writer_buf); err = reftable_table_new(&table, &source, "filename"); - check(!err); + cl_assert(!err); /* * Seeking the log uses the log index now. In case there is any * confusion regarding indices we would notice here. */ err = reftable_table_init_log_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_log(&it, ""); - check(!err); + cl_assert(!err); reftable_iterator_destroy(&it); reftable_writer_free(writer); @@ -870,7 +848,7 @@ static void t_write_multiple_indices(void) reftable_buf_release(&writer_buf); } -static void t_write_multi_level_index(void) +void test_reftable_readwrite__write_multi_level_index(void) { struct reftable_write_options opts = { .block_size = 100, @@ -883,7 +861,7 @@ static void t_write_multi_level_index(void) struct reftable_table *table; int err; - writer = t_reftable_strbuf_writer(&writer_buf, &opts); + writer = cl_reftable_strbuf_writer(&writer_buf, &opts); reftable_writer_set_limits(writer, 1, 1); for (size_t i = 0; i < 200; i++) { struct reftable_ref_record ref = { @@ -896,8 +874,7 @@ static void t_write_multi_level_index(void) snprintf(buf, sizeof(buf), "refs/heads/%03" PRIuMAX, (uintmax_t)i); ref.refname = buf; - err = reftable_writer_add_ref(writer, &ref); - check(!err); + cl_assert_equal_i(reftable_writer_add_ref(writer, &ref), 0); } reftable_writer_close(writer); @@ -906,19 +883,19 @@ static void t_write_multi_level_index(void) * multi-level index. */ stats = reftable_writer_stats(writer); - check_int(stats->ref_stats.max_index_level, ==, 2); + cl_assert_equal_i(stats->ref_stats.max_index_level, 2); block_source_from_buf(&source, &writer_buf); err = reftable_table_new(&table, &source, "filename"); - check(!err); + cl_assert(!err); /* * Seeking the last ref should work as expected. */ err = reftable_table_init_ref_iterator(table, &it); - check(!err); + cl_assert(!err); err = reftable_iterator_seek_ref(&it, "refs/heads/199"); - check(!err); + cl_assert(!err); reftable_iterator_destroy(&it); reftable_writer_free(writer); @@ -927,7 +904,7 @@ static void t_write_multi_level_index(void) reftable_buf_release(&buf); } -static void t_corrupt_table_empty(void) +void test_reftable_readwrite__corrupt_table_empty(void) { struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_block_source source = { 0 }; @@ -936,50 +913,22 @@ static void t_corrupt_table_empty(void) block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "file.log"); - check_int(err, ==, REFTABLE_FORMAT_ERROR); + cl_assert_equal_i(err, REFTABLE_FORMAT_ERROR); } -static void t_corrupt_table(void) +void test_reftable_readwrite__corrupt_table(void) { uint8_t zeros[1024] = { 0 }; struct reftable_buf buf = REFTABLE_BUF_INIT; struct reftable_block_source source = { 0 }; struct reftable_table *table; int err; - check(!reftable_buf_add(&buf, zeros, sizeof(zeros))); + + cl_assert(!reftable_buf_add(&buf, zeros, sizeof(zeros))); block_source_from_buf(&source, &buf); err = reftable_table_new(&table, &source, "file.log"); - check_int(err, ==, REFTABLE_FORMAT_ERROR); + cl_assert_equal_i(err, REFTABLE_FORMAT_ERROR); reftable_buf_release(&buf); } - -int cmd_main(int argc UNUSED, const char *argv[] UNUSED) -{ - TEST(t_buffer(), "strbuf works as blocksource"); - TEST(t_corrupt_table(), "read-write on corrupted table"); - TEST(t_corrupt_table_empty(), "read-write on an empty table"); - TEST(t_log_buffer_size(), "buffer extension for log compression"); - TEST(t_log_overflow(), "log overflow returns expected error"); - TEST(t_log_write_limits(), "writer limits for writing log records"); - TEST(t_log_write_read(), "read-write on log records"); - TEST(t_log_zlib_corruption(), "reading corrupted log record returns expected error"); - TEST(t_table_read_api(), "read on a table"); - TEST(t_table_read_write_seek_index(), "read-write on a table with index"); - TEST(t_table_read_write_seek_linear(), "read-write on a table without index (SHA1)"); - TEST(t_table_read_write_seek_linear_sha256(), "read-write on a table without index (SHA256)"); - TEST(t_table_read_write_sequential(), "sequential read-write on a table"); - TEST(t_table_refs_for_no_index(), "refs-only table with no index"); - TEST(t_table_refs_for_obj_index(), "refs-only table with index"); - TEST(t_table_write_small_table(), "write_table works"); - TEST(t_write_empty_key(), "write on refs with empty keys"); - TEST(t_write_empty_table(), "read-write on empty tables"); - TEST(t_write_key_order(), "refs must be written in increasing order"); - TEST(t_write_multi_level_index(), "table with multi-level index"); - TEST(t_write_multiple_indices(), "table with indices for multiple block types"); - TEST(t_write_object_id_length(), "prefix compression on writing refs"); - TEST(t_write_object_id_min_length(), "prefix compression on writing refs"); - - return test_done(); -} diff --git a/t/unit-tests/t-reftable-record.c b/t/unit-tests/u-reftable-record.c index 553a007664..6c8c0d5374 100644 --- a/t/unit-tests/t-reftable-record.c +++ b/t/unit-tests/u-reftable-record.c @@ -6,7 +6,8 @@ https://developers.google.com/open-source/licenses/bsd */ -#include "test-lib.h" +#include "unit-test.h" +#include "lib-reftable.h" #include "reftable/basics.h" #include "reftable/constants.h" #include "reftable/record.h" @@ -17,16 +18,17 @@ static void t_copy(struct reftable_record *rec) uint8_t typ; typ = reftable_record_type(rec); - check(!reftable_record_init(©, typ)); + cl_assert_equal_i(reftable_record_init(©, typ), 0); reftable_record_copy_from(©, rec, REFTABLE_HASH_SIZE_SHA1); /* do it twice to catch memory leaks */ reftable_record_copy_from(©, rec, REFTABLE_HASH_SIZE_SHA1); - check(reftable_record_equal(rec, ©, REFTABLE_HASH_SIZE_SHA1)); + cl_assert(reftable_record_equal(rec, ©, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_record_release(©); } -static void t_varint_roundtrip(void) +void test_reftable_record__varint_roundtrip(void) { uint64_t inputs[] = { 0, 1, @@ -49,16 +51,16 @@ static void t_varint_roundtrip(void) int n = put_var_int(&out, in); uint64_t got = 0; - check_int(n, >, 0); + cl_assert(n > 0); out.len = n; n = get_var_int(&got, &out); - check_int(n, >, 0); + cl_assert(n > 0); - check_int(got, ==, in); + cl_assert_equal_i(got, in); } } -static void t_varint_overflow(void) +void test_reftable_record__varint_overflow(void) { unsigned char buf[] = { 0xFF, 0xFF, 0xFF, 0xFF, @@ -70,8 +72,7 @@ static void t_varint_overflow(void) .len = sizeof(buf), }; uint64_t value; - int err = get_var_int(&value, &view); - check_int(err, ==, -1); + cl_assert_equal_i(get_var_int(&value, &view), -1); } static void set_hash(uint8_t *h, int j) @@ -80,7 +81,7 @@ static void set_hash(uint8_t *h, int j) h[i] = (j >> i) & 0xff; } -static void t_reftable_ref_record_comparison(void) +void test_reftable_record__ref_record_comparison(void) { struct reftable_record in[3] = { { @@ -102,21 +103,23 @@ static void t_reftable_ref_record_comparison(void) }; int cmp; - check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[0], &in[1], &cmp)); - check(!cmp); + cl_assert(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1) == 0); + cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0); + cl_assert(!cmp); - check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[1], &in[2], &cmp)); - check_int(cmp, >, 0); + cl_assert(reftable_record_equal(&in[1], &in[2], + REFTABLE_HASH_SIZE_SHA1) == 0); + cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0); + cl_assert(cmp > 0); in[1].u.ref.value_type = in[0].u.ref.value_type; - check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[0], &in[1], &cmp)); - check(!cmp); + cl_assert(reftable_record_equal(&in[0], &in[1], + REFTABLE_HASH_SIZE_SHA1) != 0); + cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0); + cl_assert(!cmp); } -static void t_reftable_ref_record_compare_name(void) +void test_reftable_record__ref_record_compare_name(void) { struct reftable_ref_record recs[3] = { { @@ -130,12 +133,15 @@ static void t_reftable_ref_record_compare_name(void) }, }; - check_int(reftable_ref_record_compare_name(&recs[0], &recs[1]), <, 0); - check_int(reftable_ref_record_compare_name(&recs[1], &recs[0]), >, 0); - check_int(reftable_ref_record_compare_name(&recs[0], &recs[2]), ==, 0); + cl_assert(reftable_ref_record_compare_name(&recs[0], + &recs[1]) < 0); + cl_assert(reftable_ref_record_compare_name(&recs[1], + &recs[0]) > 0); + cl_assert_equal_i(reftable_ref_record_compare_name(&recs[0], + &recs[2]), 0); } -static void t_reftable_ref_record_roundtrip(void) +void test_reftable_record__ref_record_roundtrip(void) { struct reftable_buf scratch = REFTABLE_BUF_INIT; @@ -172,19 +178,21 @@ static void t_reftable_ref_record_roundtrip(void) t_copy(&in); - check_int(reftable_record_val_type(&in), ==, i); - check_int(reftable_record_is_deletion(&in), ==, i == REFTABLE_REF_DELETION); + cl_assert_equal_i(reftable_record_val_type(&in), i); + cl_assert_equal_i(reftable_record_is_deletion(&in), + i == REFTABLE_REF_DELETION); reftable_record_key(&in, &key); n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1); - check_int(n, >, 0); + cl_assert(n > 0); /* decode into a non-zero reftable_record to test for leaks. */ m = reftable_record_decode(&out, key, i, dest, REFTABLE_HASH_SIZE_SHA1, &scratch); - check_int(n, ==, m); + cl_assert_equal_i(n, m); - check(reftable_ref_record_equal(&in.u.ref, &out.u.ref, - REFTABLE_HASH_SIZE_SHA1)); + cl_assert(reftable_ref_record_equal(&in.u.ref, + &out.u.ref, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_record_release(&in); reftable_buf_release(&key); @@ -194,7 +202,7 @@ static void t_reftable_ref_record_roundtrip(void) reftable_buf_release(&scratch); } -static void t_reftable_log_record_comparison(void) +void test_reftable_record__log_record_comparison(void) { struct reftable_record in[3] = { { @@ -215,21 +223,24 @@ static void t_reftable_log_record_comparison(void) }; int cmp; - check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[1], &in[2], &cmp)); - check_int(cmp, >, 0); + cl_assert_equal_i(reftable_record_equal(&in[0], &in[1], + REFTABLE_HASH_SIZE_SHA1), 0); + cl_assert_equal_i(reftable_record_equal(&in[1], &in[2], + REFTABLE_HASH_SIZE_SHA1), 0); + cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0); + cl_assert(cmp > 0); /* comparison should be reversed for equal keys, because * comparison is now performed on the basis of update indices */ - check(!reftable_record_cmp(&in[0], &in[1], &cmp)); - check_int(cmp, <, 0); + cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0); + cl_assert(cmp < 0); in[1].u.log.update_index = in[0].u.log.update_index; - check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[0], &in[1], &cmp)); + cl_assert(reftable_record_equal(&in[0], &in[1], + REFTABLE_HASH_SIZE_SHA1) != 0); + cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0); } -static void t_reftable_log_record_compare_key(void) +void test_reftable_record__log_record_compare_key(void) { struct reftable_log_record logs[3] = { { @@ -246,19 +257,24 @@ static void t_reftable_log_record_compare_key(void) }, }; - check_int(reftable_log_record_compare_key(&logs[0], &logs[1]), <, 0); - check_int(reftable_log_record_compare_key(&logs[1], &logs[0]), >, 0); + cl_assert(reftable_log_record_compare_key(&logs[0], + &logs[1]) < 0); + cl_assert(reftable_log_record_compare_key(&logs[1], + &logs[0]) > 0); logs[1].update_index = logs[0].update_index; - check_int(reftable_log_record_compare_key(&logs[0], &logs[1]), <, 0); + cl_assert(reftable_log_record_compare_key(&logs[0], + &logs[1]) < 0); - check_int(reftable_log_record_compare_key(&logs[0], &logs[2]), >, 0); - check_int(reftable_log_record_compare_key(&logs[2], &logs[0]), <, 0); + cl_assert(reftable_log_record_compare_key(&logs[0], + &logs[2]) > 0); + cl_assert(reftable_log_record_compare_key(&logs[2], + &logs[0]) < 0); logs[2].update_index = logs[0].update_index; - check_int(reftable_log_record_compare_key(&logs[0], &logs[2]), ==, 0); + cl_assert_equal_i(reftable_log_record_compare_key(&logs[0], &logs[2]), 0); } -static void t_reftable_log_record_roundtrip(void) +void test_reftable_record__log_record_roundtrip(void) { struct reftable_log_record in[] = { { @@ -292,9 +308,9 @@ static void t_reftable_log_record_roundtrip(void) set_hash(in[2].value.update.new_hash, 3); set_hash(in[2].value.update.old_hash, 4); - check(!reftable_log_record_is_deletion(&in[0])); - check(reftable_log_record_is_deletion(&in[1])); - check(!reftable_log_record_is_deletion(&in[2])); + cl_assert_equal_i(reftable_log_record_is_deletion(&in[0]), 0); + cl_assert(reftable_log_record_is_deletion(&in[1]) != 0); + cl_assert_equal_i(reftable_log_record_is_deletion(&in[2]), 0); for (size_t i = 0; i < ARRAY_SIZE(in); i++) { struct reftable_record rec = { .type = REFTABLE_BLOCK_TYPE_LOG }; @@ -328,14 +344,14 @@ static void t_reftable_log_record_roundtrip(void) reftable_record_key(&rec, &key); n = reftable_record_encode(&rec, dest, REFTABLE_HASH_SIZE_SHA1); - check_int(n, >=, 0); + cl_assert(n >= 0); valtype = reftable_record_val_type(&rec); m = reftable_record_decode(&out, key, valtype, dest, REFTABLE_HASH_SIZE_SHA1, &scratch); - check_int(n, ==, m); + cl_assert_equal_i(n, m); - check(reftable_log_record_equal(&in[i], &out.u.log, - REFTABLE_HASH_SIZE_SHA1)); + cl_assert(reftable_log_record_equal(&in[i], &out.u.log, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_log_record_release(&in[i]); reftable_buf_release(&key); reftable_record_release(&out); @@ -344,7 +360,7 @@ static void t_reftable_log_record_roundtrip(void) reftable_buf_release(&scratch); } -static void t_key_roundtrip(void) +void test_reftable_record__key_roundtrip(void) { uint8_t buffer[1024] = { 0 }; struct string_view dest = { @@ -359,25 +375,28 @@ static void t_key_roundtrip(void) int n, m; uint8_t rt_extra; - check(!reftable_buf_addstr(&last_key, "refs/heads/master")); - check(!reftable_buf_addstr(&key, "refs/tags/bla")); + cl_assert_equal_i(reftable_buf_addstr(&last_key, + "refs/heads/master"), 0); + cl_assert_equal_i(reftable_buf_addstr(&key, + "refs/tags/bla"), 0); extra = 6; n = reftable_encode_key(&restart, dest, last_key, key, extra); - check(!restart); - check_int(n, >, 0); + cl_assert(!restart); + cl_assert(n > 0); - check(!reftable_buf_addstr(&roundtrip, "refs/heads/master")); + cl_assert_equal_i(reftable_buf_addstr(&roundtrip, + "refs/heads/master"), 0); m = reftable_decode_key(&roundtrip, &rt_extra, dest); - check_int(n, ==, m); - check(!reftable_buf_cmp(&key, &roundtrip)); - check_int(rt_extra, ==, extra); + cl_assert_equal_i(n, m); + cl_assert_equal_i(reftable_buf_cmp(&key, &roundtrip), 0); + cl_assert_equal_i(rt_extra, extra); reftable_buf_release(&last_key); reftable_buf_release(&key); reftable_buf_release(&roundtrip); } -static void t_reftable_obj_record_comparison(void) +void test_reftable_record__obj_record_comparison(void) { uint8_t id_bytes[] = { 0, 1, 2, 3, 4, 5, 6 }; @@ -405,21 +424,23 @@ static void t_reftable_obj_record_comparison(void) }; int cmp; - check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[0], &in[1], &cmp)); - check(!cmp); + cl_assert_equal_i(reftable_record_equal(&in[0], &in[1], + REFTABLE_HASH_SIZE_SHA1), 0); + cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0); + cl_assert(!cmp); - check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[1], &in[2], &cmp)); - check_int(cmp, >, 0); + cl_assert_equal_i(reftable_record_equal(&in[1], &in[2], + REFTABLE_HASH_SIZE_SHA1), 0); + cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0); + cl_assert(cmp > 0); in[1].u.obj.offset_len = in[0].u.obj.offset_len; - check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[0], &in[1], &cmp)); - check(!cmp); + cl_assert(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1) != 0); + cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0); + cl_assert(!cmp); } -static void t_reftable_obj_record_roundtrip(void) +void test_reftable_record__obj_record_roundtrip(void) { uint8_t testHash1[REFTABLE_HASH_SIZE_SHA1] = { 1, 2, 3, 4, 0 }; uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 }; @@ -460,17 +481,18 @@ static void t_reftable_obj_record_roundtrip(void) int n, m; uint8_t extra; - check(!reftable_record_is_deletion(&in)); + cl_assert_equal_i(reftable_record_is_deletion(&in), 0); t_copy(&in); reftable_record_key(&in, &key); n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1); - check_int(n, >, 0); + cl_assert(n > 0); extra = reftable_record_val_type(&in); m = reftable_record_decode(&out, key, extra, dest, REFTABLE_HASH_SIZE_SHA1, &scratch); - check_int(n, ==, m); + cl_assert_equal_i(n, m); - check(reftable_record_equal(&in, &out, REFTABLE_HASH_SIZE_SHA1)); + cl_assert(reftable_record_equal(&in, &out, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_buf_release(&key); reftable_record_release(&out); } @@ -478,7 +500,7 @@ static void t_reftable_obj_record_roundtrip(void) reftable_buf_release(&scratch); } -static void t_reftable_index_record_comparison(void) +void test_reftable_record__index_record_comparison(void) { struct reftable_record in[3] = { { @@ -499,28 +521,33 @@ static void t_reftable_index_record_comparison(void) }; int cmp; - check(!reftable_buf_addstr(&in[0].u.idx.last_key, "refs/heads/master")); - check(!reftable_buf_addstr(&in[1].u.idx.last_key, "refs/heads/master")); - check(!reftable_buf_addstr(&in[2].u.idx.last_key, "refs/heads/branch")); + cl_assert_equal_i(reftable_buf_addstr(&in[0].u.idx.last_key, + "refs/heads/master"), 0); + cl_assert_equal_i(reftable_buf_addstr(&in[1].u.idx.last_key, "refs/heads/master"), 0); + cl_assert(reftable_buf_addstr(&in[2].u.idx.last_key, + "refs/heads/branch") == 0); - check(!reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[0], &in[1], &cmp)); - check(!cmp); + cl_assert_equal_i(reftable_record_equal(&in[0], &in[1], + REFTABLE_HASH_SIZE_SHA1), 0); + cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0); + cl_assert(!cmp); - check(!reftable_record_equal(&in[1], &in[2], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[1], &in[2], &cmp)); - check_int(cmp, >, 0); + cl_assert_equal_i(reftable_record_equal(&in[1], &in[2], + REFTABLE_HASH_SIZE_SHA1), 0); + cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0); + cl_assert(cmp > 0); in[1].u.idx.offset = in[0].u.idx.offset; - check(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1)); - check(!reftable_record_cmp(&in[0], &in[1], &cmp)); - check(!cmp); + cl_assert(reftable_record_equal(&in[0], &in[1], + REFTABLE_HASH_SIZE_SHA1) != 0); + cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0); + cl_assert(!cmp); for (size_t i = 0; i < ARRAY_SIZE(in); i++) reftable_record_release(&in[i]); } -static void t_reftable_index_record_roundtrip(void) +void test_reftable_record__index_record_roundtrip(void) { struct reftable_record in = { .type = REFTABLE_BLOCK_TYPE_INDEX, @@ -543,43 +570,26 @@ static void t_reftable_index_record_roundtrip(void) int n, m; uint8_t extra; - check(!reftable_buf_addstr(&in.u.idx.last_key, "refs/heads/master")); + cl_assert_equal_i(reftable_buf_addstr(&in.u.idx.last_key, + "refs/heads/master"), 0); reftable_record_key(&in, &key); t_copy(&in); - check(!reftable_record_is_deletion(&in)); - check(!reftable_buf_cmp(&key, &in.u.idx.last_key)); + cl_assert_equal_i(reftable_record_is_deletion(&in), 0); + cl_assert_equal_i(reftable_buf_cmp(&key, &in.u.idx.last_key), 0); n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1); - check_int(n, >, 0); + cl_assert(n > 0); extra = reftable_record_val_type(&in); - m = reftable_record_decode(&out, key, extra, dest, REFTABLE_HASH_SIZE_SHA1, - &scratch); - check_int(m, ==, n); + m = reftable_record_decode(&out, key, extra, dest, + REFTABLE_HASH_SIZE_SHA1, &scratch); + cl_assert_equal_i(m, n); - check(reftable_record_equal(&in, &out, REFTABLE_HASH_SIZE_SHA1)); + cl_assert(reftable_record_equal(&in, &out, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_record_release(&out); reftable_buf_release(&key); reftable_buf_release(&scratch); reftable_buf_release(&in.u.idx.last_key); } - -int cmd_main(int argc UNUSED, const char *argv[] UNUSED) -{ - TEST(t_reftable_ref_record_comparison(), "comparison operations work on ref record"); - TEST(t_reftable_log_record_comparison(), "comparison operations work on log record"); - TEST(t_reftable_index_record_comparison(), "comparison operations work on index record"); - TEST(t_reftable_obj_record_comparison(), "comparison operations work on obj record"); - TEST(t_reftable_ref_record_compare_name(), "reftable_ref_record_compare_name works"); - TEST(t_reftable_log_record_compare_key(), "reftable_log_record_compare_key works"); - TEST(t_reftable_log_record_roundtrip(), "record operations work on log record"); - TEST(t_reftable_ref_record_roundtrip(), "record operations work on ref record"); - TEST(t_varint_roundtrip(), "put_var_int and get_var_int work"); - TEST(t_varint_overflow(), "get_var_int notices an integer overflow"); - TEST(t_key_roundtrip(), "reftable_encode_key and reftable_decode_key work"); - TEST(t_reftable_obj_record_roundtrip(), "record operations work on obj record"); - TEST(t_reftable_index_record_roundtrip(), "record operations work on index record"); - - return test_done(); -} diff --git a/t/unit-tests/t-reftable-stack.c b/t/unit-tests/u-reftable-stack.c index 2f49c97519..e4ea57138e 100644 --- a/t/unit-tests/t-reftable-stack.c +++ b/t/unit-tests/u-reftable-stack.c @@ -8,9 +8,9 @@ https://developers.google.com/open-source/licenses/bsd #define DISABLE_SIGN_COMPARE_WARNINGS -#include "test-lib.h" -#include "lib-reftable.h" +#include "unit-test.h" #include "dir.h" +#include "lib-reftable.h" #include "reftable/merged.h" #include "reftable/reftable-error.h" #include "reftable/stack.h" @@ -70,11 +70,11 @@ static char *get_tmp_template(int linenumber) static char *get_tmp_dir(int linenumber) { char *dir = get_tmp_template(linenumber); - check(mkdtemp(dir) != NULL); + cl_assert(mkdtemp(dir) != NULL); return dir; } -static void t_read_file(void) +void test_reftable_stack__read_file(void) { char *fn = get_tmp_template(__LINE__); struct tempfile *tmp = mks_tempfile(fn); @@ -84,17 +84,17 @@ static void t_read_file(void) char **names = NULL; const char *want[] = { "line1", "line2", "line3" }; - check_int(fd, >, 0); + cl_assert(fd > 0); n = write_in_full(fd, out, strlen(out)); - check_int(n, ==, strlen(out)); + cl_assert_equal_i(n, strlen(out)); err = close(fd); - check_int(err, >=, 0); + cl_assert(err >= 0); err = read_lines(fn, &names); - check(!err); + cl_assert(!err); for (size_t i = 0; names[i]; i++) - check_str(want[i], names[i]); + cl_assert_equal_s(want[i], names[i]); free_names(names); (void) remove(fn); delete_tempfile(&tmp); @@ -103,8 +103,8 @@ static void t_read_file(void) static int write_test_ref(struct reftable_writer *wr, void *arg) { struct reftable_ref_record *ref = arg; - check(!reftable_writer_set_limits(wr, ref->update_index, - ref->update_index)); + cl_assert_equal_i(reftable_writer_set_limits(wr, + ref->update_index, ref->update_index), 0); return reftable_writer_add_ref(wr, ref); } @@ -112,7 +112,6 @@ static void write_n_ref_tables(struct reftable_stack *st, size_t n) { int disable_auto_compact; - int err; disable_auto_compact = st->opts.disable_auto_compact; st->opts.disable_auto_compact = 1; @@ -126,10 +125,10 @@ static void write_n_ref_tables(struct reftable_stack *st, snprintf(buf, sizeof(buf), "refs/heads/branch-%04"PRIuMAX, (uintmax_t)i); ref.refname = buf; - t_reftable_set_hash(ref.value.val1, i, REFTABLE_HASH_SHA1); + cl_reftable_set_hash(ref.value.val1, i, REFTABLE_HASH_SHA1); - err = reftable_stack_add(st, &write_test_ref, &ref); - check(!err); + cl_assert_equal_i(reftable_stack_add(st, + &write_test_ref, &ref), 0); } st->opts.disable_auto_compact = disable_auto_compact; @@ -144,12 +143,13 @@ static int write_test_log(struct reftable_writer *wr, void *arg) { struct write_log_arg *wla = arg; - check(!reftable_writer_set_limits(wr, wla->update_index, - wla->update_index)); + cl_assert_equal_i(reftable_writer_set_limits(wr, + wla->update_index, + wla->update_index), 0); return reftable_writer_add_log(wr, wla->log); } -static void t_reftable_stack_add_one(void) +void test_reftable_stack__add_one(void) { char *dir = get_tmp_dir(__LINE__); struct reftable_buf scratch = REFTABLE_BUF_INIT; @@ -158,7 +158,6 @@ static void t_reftable_stack_add_one(void) .default_permissions = 0660, }; struct reftable_stack *st = NULL; - int err; struct reftable_ref_record ref = { .refname = (char *) "HEAD", .update_index = 1, @@ -167,32 +166,37 @@ static void t_reftable_stack_add_one(void) }; struct reftable_ref_record dest = { 0 }; struct stat stat_result = { 0 }; + int err; + err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert(!err); err = reftable_stack_add(st, write_test_ref, &ref); - check(!err); + cl_assert(!err); err = reftable_stack_read_ref(st, ref.refname, &dest); - check(!err); - check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1)); - check_int(st->tables_len, >, 0); + cl_assert(!err); + cl_assert(reftable_ref_record_equal(&ref, &dest, + REFTABLE_HASH_SIZE_SHA1)); + cl_assert(st->tables_len > 0); #ifndef GIT_WINDOWS_NATIVE - check(!reftable_buf_addstr(&scratch, dir)); - check(!reftable_buf_addstr(&scratch, "/tables.list")); - err = stat(scratch.buf, &stat_result); - check(!err); - check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); + cl_assert_equal_i(reftable_buf_addstr(&scratch, dir), 0); + cl_assert_equal_i(reftable_buf_addstr(&scratch, + "/tables.list"), 0); + cl_assert_equal_i(stat(scratch.buf, &stat_result), 0); + cl_assert_equal_i((stat_result.st_mode & 0777), + opts.default_permissions); reftable_buf_reset(&scratch); - check(!reftable_buf_addstr(&scratch, dir)); - check(!reftable_buf_addstr(&scratch, "/")); + cl_assert_equal_i(reftable_buf_addstr(&scratch, dir), 0); + cl_assert_equal_i(reftable_buf_addstr(&scratch, "/"), 0); /* do not try at home; not an external API for reftable. */ - check(!reftable_buf_addstr(&scratch, st->tables[0]->name)); + cl_assert(!reftable_buf_addstr(&scratch, st->tables[0]->name)); err = stat(scratch.buf, &stat_result); - check(!err); - check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); + cl_assert(!err); + cl_assert_equal_i((stat_result.st_mode & 0777), + opts.default_permissions); #else (void) stat_result; #endif @@ -204,14 +208,13 @@ static void t_reftable_stack_add_one(void) umask(mask); } -static void t_reftable_stack_uptodate(void) +void test_reftable_stack__uptodate(void) { struct reftable_write_options opts = { 0 }; struct reftable_stack *st1 = NULL; struct reftable_stack *st2 = NULL; char *dir = get_tmp_dir(__LINE__); - int err; struct reftable_ref_record ref1 = { .refname = (char *) "HEAD", .update_index = 1, @@ -229,34 +232,25 @@ static void t_reftable_stack_uptodate(void) /* simulate multi-process access to the same stack by creating two stacks for the same directory. */ - err = reftable_new_stack(&st1, dir, &opts); - check(!err); - - err = reftable_new_stack(&st2, dir, &opts); - check(!err); - - err = reftable_stack_add(st1, write_test_ref, &ref1); - check(!err); - - err = reftable_stack_add(st2, write_test_ref, &ref2); - check_int(err, ==, REFTABLE_OUTDATED_ERROR); - - err = reftable_stack_reload(st2); - check(!err); - - err = reftable_stack_add(st2, write_test_ref, &ref2); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st1, dir, &opts), 0); + cl_assert_equal_i(reftable_new_stack(&st2, dir, &opts), 0); + cl_assert_equal_i(reftable_stack_add(st1, write_test_ref, + &ref1), 0); + cl_assert_equal_i(reftable_stack_add(st2, write_test_ref, + &ref2), REFTABLE_OUTDATED_ERROR); + cl_assert_equal_i(reftable_stack_reload(st2), 0); + cl_assert_equal_i(reftable_stack_add(st2, write_test_ref, + &ref2), 0); reftable_stack_destroy(st1); reftable_stack_destroy(st2); clear_dir(dir); } -static void t_reftable_stack_transaction_api(void) +void test_reftable_stack__transaction_api(void) { char *dir = get_tmp_dir(__LINE__); struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; - int err; struct reftable_addition *add = NULL; struct reftable_ref_record ref = { @@ -267,37 +261,32 @@ static void t_reftable_stack_transaction_api(void) }; struct reftable_ref_record dest = { 0 }; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); reftable_addition_destroy(add); - err = reftable_stack_new_addition(&add, st, 0); - check(!err); - - err = reftable_addition_add(add, write_test_ref, &ref); - check(!err); - - err = reftable_addition_commit(add); - check(!err); + cl_assert_equal_i(reftable_stack_new_addition(&add, st, 0), 0); + cl_assert_equal_i(reftable_addition_add(add, write_test_ref, + &ref), 0); + cl_assert_equal_i(reftable_addition_commit(add), 0); reftable_addition_destroy(add); - err = reftable_stack_read_ref(st, ref.refname, &dest); - check(!err); - check_int(REFTABLE_REF_SYMREF, ==, dest.value_type); - check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_stack_read_ref(st, ref.refname, + &dest), 0); + cl_assert_equal_i(REFTABLE_REF_SYMREF, dest.value_type); + cl_assert(reftable_ref_record_equal(&ref, &dest, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_ref_record_release(&dest); reftable_stack_destroy(st); clear_dir(dir); } -static void t_reftable_stack_transaction_with_reload(void) +void test_reftable_stack__transaction_with_reload(void) { char *dir = get_tmp_dir(__LINE__); struct reftable_stack *st1 = NULL, *st2 = NULL; - int err; struct reftable_addition *add = NULL; struct reftable_ref_record refs[2] = { { @@ -315,17 +304,12 @@ static void t_reftable_stack_transaction_with_reload(void) }; struct reftable_ref_record ref = { 0 }; - err = reftable_new_stack(&st1, dir, NULL); - check(!err); - err = reftable_new_stack(&st2, dir, NULL); - check(!err); - - err = reftable_stack_new_addition(&add, st1, 0); - check(!err); - err = reftable_addition_add(add, write_test_ref, &refs[0]); - check(!err); - err = reftable_addition_commit(add); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st1, dir, NULL), 0); + cl_assert_equal_i(reftable_new_stack(&st2, dir, NULL), 0); + cl_assert_equal_i(reftable_stack_new_addition(&add, st1, 0), 0); + cl_assert_equal_i(reftable_addition_add(add, write_test_ref, + &refs[0]), 0); + cl_assert_equal_i(reftable_addition_commit(add), 0); reftable_addition_destroy(add); /* @@ -333,20 +317,20 @@ static void t_reftable_stack_transaction_with_reload(void) * create the addition and lock the stack by default, but allow the * reload to happen when REFTABLE_STACK_NEW_ADDITION_RELOAD is set. */ - err = reftable_stack_new_addition(&add, st2, 0); - check_int(err, ==, REFTABLE_OUTDATED_ERROR); - err = reftable_stack_new_addition(&add, st2, REFTABLE_STACK_NEW_ADDITION_RELOAD); - check(!err); - err = reftable_addition_add(add, write_test_ref, &refs[1]); - check(!err); - err = reftable_addition_commit(add); - check(!err); + cl_assert_equal_i(reftable_stack_new_addition(&add, st2, 0), + REFTABLE_OUTDATED_ERROR); + cl_assert_equal_i(reftable_stack_new_addition(&add, st2, + REFTABLE_STACK_NEW_ADDITION_RELOAD), 0); + cl_assert_equal_i(reftable_addition_add(add, write_test_ref, + &refs[1]), 0); + cl_assert_equal_i(reftable_addition_commit(add), 0); reftable_addition_destroy(add); for (size_t i = 0; i < ARRAY_SIZE(refs); i++) { - err = reftable_stack_read_ref(st2, refs[i].refname, &ref); - check(!err); - check(reftable_ref_record_equal(&refs[i], &ref, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_stack_read_ref(st2, + refs[i].refname, &ref) , 0); + cl_assert(reftable_ref_record_equal(&refs[i], &ref, + REFTABLE_HASH_SIZE_SHA1) != 0); } reftable_ref_record_release(&ref); @@ -355,17 +339,15 @@ static void t_reftable_stack_transaction_with_reload(void) clear_dir(dir); } -static void t_reftable_stack_transaction_api_performs_auto_compaction(void) +void test_reftable_stack__transaction_api_performs_auto_compaction(void) { char *dir = get_tmp_dir(__LINE__); struct reftable_write_options opts = {0}; struct reftable_addition *add = NULL; struct reftable_stack *st = NULL; size_t n = 20; - int err; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); for (size_t i = 0; i <= n; i++) { struct reftable_ref_record ref = { @@ -385,14 +367,11 @@ static void t_reftable_stack_transaction_api_performs_auto_compaction(void) */ st->opts.disable_auto_compact = i != n; - err = reftable_stack_new_addition(&add, st, 0); - check(!err); - - err = reftable_addition_add(add, write_test_ref, &ref); - check(!err); - - err = reftable_addition_commit(add); - check(!err); + cl_assert_equal_i(reftable_stack_new_addition(&add, + st, 0), 0); + cl_assert_equal_i(reftable_addition_add(add, + write_test_ref, &ref), 0); + cl_assert_equal_i(reftable_addition_commit(add), 0); reftable_addition_destroy(add); @@ -402,16 +381,16 @@ static void t_reftable_stack_transaction_api_performs_auto_compaction(void) * all tables in the stack. */ if (i != n) - check_int(st->merged->tables_len, ==, i + 1); + cl_assert_equal_i(st->merged->tables_len, i + 1); else - check_int(st->merged->tables_len, ==, 1); + cl_assert_equal_i(st->merged->tables_len, 1); } reftable_stack_destroy(st); clear_dir(dir); } -static void t_reftable_stack_auto_compaction_fails_gracefully(void) +void test_reftable_stack__auto_compaction_fails_gracefully(void) { struct reftable_ref_record ref = { .refname = (char *) "refs/heads/master", @@ -425,32 +404,31 @@ static void t_reftable_stack_auto_compaction_fails_gracefully(void) char *dir = get_tmp_dir(__LINE__); int err; - err = reftable_new_stack(&st, dir, &opts); - check(!err); - - err = reftable_stack_add(st, write_test_ref, &ref); - check(!err); - check_int(st->merged->tables_len, ==, 1); - check_int(st->stats.attempts, ==, 0); - check_int(st->stats.failures, ==, 0); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); + cl_assert_equal_i(reftable_stack_add(st, write_test_ref, + &ref), 0); + cl_assert_equal_i(st->merged->tables_len, 1); + cl_assert_equal_i(st->stats.attempts, 0); + cl_assert_equal_i(st->stats.failures, 0); /* * Lock the newly written table such that it cannot be compacted. * Adding a new table to the stack should not be impacted by this, even * though auto-compaction will now fail. */ - check(!reftable_buf_addstr(&table_path, dir)); - check(!reftable_buf_addstr(&table_path, "/")); - check(!reftable_buf_addstr(&table_path, st->tables[0]->name)); - check(!reftable_buf_addstr(&table_path, ".lock")); + cl_assert(!reftable_buf_addstr(&table_path, dir)); + cl_assert(!reftable_buf_addstr(&table_path, "/")); + cl_assert(!reftable_buf_addstr(&table_path, + st->tables[0]->name)); + cl_assert(!reftable_buf_addstr(&table_path, ".lock")); write_file_buf(table_path.buf, "", 0); ref.update_index = 2; err = reftable_stack_add(st, write_test_ref, &ref); - check(!err); - check_int(st->merged->tables_len, ==, 2); - check_int(st->stats.attempts, ==, 1); - check_int(st->stats.failures, ==, 1); + cl_assert(!err); + cl_assert_equal_i(st->merged->tables_len, 2); + cl_assert_equal_i(st->stats.attempts, 1); + cl_assert_equal_i(st->stats.failures, 1); reftable_stack_destroy(st); reftable_buf_release(&table_path); @@ -462,12 +440,11 @@ static int write_error(struct reftable_writer *wr UNUSED, void *arg) return *((int *)arg); } -static void t_reftable_stack_update_index_check(void) +void test_reftable_stack__update_index_check(void) { char *dir = get_tmp_dir(__LINE__); struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; - int err; struct reftable_ref_record ref1 = { .refname = (char *) "name1", .update_index = 1, @@ -481,39 +458,33 @@ static void t_reftable_stack_update_index_check(void) .value.symref = (char *) "master", }; - err = reftable_new_stack(&st, dir, &opts); - check(!err); - - err = reftable_stack_add(st, write_test_ref, &ref1); - check(!err); - - err = reftable_stack_add(st, write_test_ref, &ref2); - check_int(err, ==, REFTABLE_API_ERROR); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); + cl_assert_equal_i(reftable_stack_add(st, write_test_ref, + &ref1), 0); + cl_assert_equal_i(reftable_stack_add(st, write_test_ref, + &ref2), REFTABLE_API_ERROR); reftable_stack_destroy(st); clear_dir(dir); } -static void t_reftable_stack_lock_failure(void) +void test_reftable_stack__lock_failure(void) { char *dir = get_tmp_dir(__LINE__); struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; - int err, i; + int i; - err = reftable_new_stack(&st, dir, &opts); - check(!err); - for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--) { - err = reftable_stack_add(st, write_error, &i); - check_int(err, ==, i); - } + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); + for (i = -1; i != REFTABLE_EMPTY_TABLE_ERROR; i--) + cl_assert_equal_i(reftable_stack_add(st, write_error, + &i), i); reftable_stack_destroy(st); clear_dir(dir); } -static void t_reftable_stack_add(void) +void test_reftable_stack__add(void) { - int err = 0; struct reftable_write_options opts = { .exact_log_message = 1, .default_permissions = 0660, @@ -526,9 +497,10 @@ static void t_reftable_stack_add(void) struct reftable_buf path = REFTABLE_BUF_INIT; struct stat stat_result; size_t i, N = ARRAY_SIZE(refs); + int err = 0; err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert(!err); for (i = 0; i < N; i++) { char buf[256]; @@ -536,66 +508,66 @@ static void t_reftable_stack_add(void) refs[i].refname = xstrdup(buf); refs[i].update_index = i + 1; refs[i].value_type = REFTABLE_REF_VAL1; - t_reftable_set_hash(refs[i].value.val1, i, REFTABLE_HASH_SHA1); + cl_reftable_set_hash(refs[i].value.val1, i, + REFTABLE_HASH_SHA1); logs[i].refname = xstrdup(buf); logs[i].update_index = N + i + 1; logs[i].value_type = REFTABLE_LOG_UPDATE; logs[i].value.update.email = xstrdup("identity@invalid"); - t_reftable_set_hash(logs[i].value.update.new_hash, i, REFTABLE_HASH_SHA1); + cl_reftable_set_hash(logs[i].value.update.new_hash, i, + REFTABLE_HASH_SHA1); } - for (i = 0; i < N; i++) { - int err = reftable_stack_add(st, write_test_ref, &refs[i]); - check(!err); - } + for (i = 0; i < N; i++) + cl_assert_equal_i(reftable_stack_add(st, write_test_ref, + &refs[i]), 0); for (i = 0; i < N; i++) { struct write_log_arg arg = { .log = &logs[i], .update_index = reftable_stack_next_update_index(st), }; - int err = reftable_stack_add(st, write_test_log, &arg); - check(!err); + cl_assert_equal_i(reftable_stack_add(st, write_test_log, + &arg), 0); } - err = reftable_stack_compact_all(st, NULL); - check(!err); + cl_assert_equal_i(reftable_stack_compact_all(st, NULL), 0); for (i = 0; i < N; i++) { struct reftable_ref_record dest = { 0 }; - int err = reftable_stack_read_ref(st, refs[i].refname, &dest); - check(!err); - check(reftable_ref_record_equal(&dest, refs + i, - REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_stack_read_ref(st, + refs[i].refname, &dest), 0); + cl_assert(reftable_ref_record_equal(&dest, refs + i, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_ref_record_release(&dest); } for (i = 0; i < N; i++) { struct reftable_log_record dest = { 0 }; - int err = reftable_stack_read_log(st, refs[i].refname, &dest); - check(!err); - check(reftable_log_record_equal(&dest, logs + i, - REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_stack_read_log(st, + refs[i].refname, &dest), 0); + cl_assert(reftable_log_record_equal(&dest, logs + i, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_log_record_release(&dest); } #ifndef GIT_WINDOWS_NATIVE - check(!reftable_buf_addstr(&path, dir)); - check(!reftable_buf_addstr(&path, "/tables.list")); - err = stat(path.buf, &stat_result); - check(!err); - check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); + cl_assert_equal_i(reftable_buf_addstr(&path, dir), 0); + cl_assert_equal_i(reftable_buf_addstr(&path, "/tables.list"), 0); + cl_assert_equal_i(stat(path.buf, &stat_result), 0); + cl_assert_equal_i((stat_result.st_mode & 0777), opts.default_permissions); reftable_buf_reset(&path); - check(!reftable_buf_addstr(&path, dir)); - check(!reftable_buf_addstr(&path, "/")); + cl_assert_equal_i(reftable_buf_addstr(&path, dir), 0); + cl_assert_equal_i(reftable_buf_addstr(&path, "/"), 0); /* do not try at home; not an external API for reftable. */ - check(!reftable_buf_addstr(&path, st->tables[0]->name)); + cl_assert(!reftable_buf_addstr(&path, st->tables[0]->name)); err = stat(path.buf, &stat_result); - check(!err); - check_int((stat_result.st_mode & 0777), ==, opts.default_permissions); + cl_assert(!err); + cl_assert_equal_i((stat_result.st_mode & 0777), + opts.default_permissions); #else (void) stat_result; #endif @@ -610,7 +582,7 @@ static void t_reftable_stack_add(void) clear_dir(dir); } -static void t_reftable_stack_iterator(void) +void test_reftable_stack__iterator(void) { struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; @@ -621,27 +593,27 @@ static void t_reftable_stack_iterator(void) size_t N = ARRAY_SIZE(refs), i; int err; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); for (i = 0; i < N; i++) { refs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i); refs[i].update_index = i + 1; refs[i].value_type = REFTABLE_REF_VAL1; - t_reftable_set_hash(refs[i].value.val1, i, REFTABLE_HASH_SHA1); + cl_reftable_set_hash(refs[i].value.val1, i, + REFTABLE_HASH_SHA1); logs[i].refname = xstrfmt("branch%02"PRIuMAX, (uintmax_t)i); logs[i].update_index = i + 1; logs[i].value_type = REFTABLE_LOG_UPDATE; logs[i].value.update.email = xstrdup("johndoe@invalid"); logs[i].value.update.message = xstrdup("commit\n"); - t_reftable_set_hash(logs[i].value.update.new_hash, i, REFTABLE_HASH_SHA1); + cl_reftable_set_hash(logs[i].value.update.new_hash, i, + REFTABLE_HASH_SHA1); } - for (i = 0; i < N; i++) { - err = reftable_stack_add(st, write_test_ref, &refs[i]); - check(!err); - } + for (i = 0; i < N; i++) + cl_assert_equal_i(reftable_stack_add(st, + write_test_ref, &refs[i]), 0); for (i = 0; i < N; i++) { struct write_log_arg arg = { @@ -649,8 +621,8 @@ static void t_reftable_stack_iterator(void) .update_index = reftable_stack_next_update_index(st), }; - err = reftable_stack_add(st, write_test_log, &arg); - check(!err); + cl_assert_equal_i(reftable_stack_add(st, + write_test_log, &arg), 0); } reftable_stack_init_ref_iterator(st, &it); @@ -661,16 +633,16 @@ static void t_reftable_stack_iterator(void) err = reftable_iterator_next_ref(&it, &ref); if (err > 0) break; - check(!err); - check(reftable_ref_record_equal(&ref, &refs[i], REFTABLE_HASH_SIZE_SHA1)); + cl_assert(!err); + cl_assert(reftable_ref_record_equal(&ref, &refs[i], + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_ref_record_release(&ref); } - check_int(i, ==, N); + cl_assert_equal_i(i, N); reftable_iterator_destroy(&it); - err = reftable_stack_init_log_iterator(st, &it); - check(!err); + cl_assert_equal_i(reftable_stack_init_log_iterator(st, &it), 0); reftable_iterator_seek_log(&it, logs[0].refname); for (i = 0; ; i++) { @@ -679,11 +651,12 @@ static void t_reftable_stack_iterator(void) err = reftable_iterator_next_log(&it, &log); if (err > 0) break; - check(!err); - check(reftable_log_record_equal(&log, &logs[i], REFTABLE_HASH_SIZE_SHA1)); + cl_assert(!err); + cl_assert(reftable_log_record_equal(&log, &logs[i], + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_log_record_release(&log); } - check_int(i, ==, N); + cl_assert_equal_i(i, N); reftable_stack_destroy(st); reftable_iterator_destroy(&it); @@ -694,9 +667,8 @@ static void t_reftable_stack_iterator(void) clear_dir(dir); } -static void t_reftable_stack_log_normalize(void) +void test_reftable_stack__log_normalize(void) { - int err = 0; struct reftable_write_options opts = { 0, }; @@ -721,28 +693,26 @@ static void t_reftable_stack_log_normalize(void) .update_index = 1, }; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); input.value.update.message = (char *) "one\ntwo"; - err = reftable_stack_add(st, write_test_log, &arg); - check_int(err, ==, REFTABLE_API_ERROR); + cl_assert_equal_i(reftable_stack_add(st, write_test_log, + &arg), REFTABLE_API_ERROR); input.value.update.message = (char *) "one"; - err = reftable_stack_add(st, write_test_log, &arg); - check(!err); - - err = reftable_stack_read_log(st, input.refname, &dest); - check(!err); - check_str(dest.value.update.message, "one\n"); + cl_assert_equal_i(reftable_stack_add(st, write_test_log, + &arg), 0); + cl_assert_equal_i(reftable_stack_read_log(st, input.refname, + &dest), 0); + cl_assert_equal_s(dest.value.update.message, "one\n"); input.value.update.message = (char *) "two\n"; arg.update_index = 2; - err = reftable_stack_add(st, write_test_log, &arg); - check(!err); - err = reftable_stack_read_log(st, input.refname, &dest); - check(!err); - check_str(dest.value.update.message, "two\n"); + cl_assert_equal_i(reftable_stack_add(st, write_test_log, + &arg), 0); + cl_assert_equal_i(reftable_stack_read_log(st, input.refname, + &dest), 0); + cl_assert_equal_s(dest.value.update.message, "two\n"); /* cleanup */ reftable_stack_destroy(st); @@ -750,20 +720,18 @@ static void t_reftable_stack_log_normalize(void) clear_dir(dir); } -static void t_reftable_stack_tombstone(void) +void test_reftable_stack__tombstone(void) { char *dir = get_tmp_dir(__LINE__); struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; - int err; struct reftable_ref_record refs[2] = { 0 }; struct reftable_log_record logs[2] = { 0 }; size_t i, N = ARRAY_SIZE(refs); struct reftable_ref_record dest = { 0 }; struct reftable_log_record log_dest = { 0 }; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); /* even entries add the refs, odd entries delete them. */ for (i = 0; i < N; i++) { @@ -772,8 +740,8 @@ static void t_reftable_stack_tombstone(void) refs[i].update_index = i + 1; if (i % 2 == 0) { refs[i].value_type = REFTABLE_REF_VAL1; - t_reftable_set_hash(refs[i].value.val1, i, - REFTABLE_HASH_SHA1); + cl_reftable_set_hash(refs[i].value.val1, i, + REFTABLE_HASH_SHA1); } logs[i].refname = xstrdup(buf); @@ -785,42 +753,36 @@ static void t_reftable_stack_tombstone(void) logs[i].update_index = 1; if (i % 2 == 0) { logs[i].value_type = REFTABLE_LOG_UPDATE; - t_reftable_set_hash(logs[i].value.update.new_hash, i, - REFTABLE_HASH_SHA1); + cl_reftable_set_hash(logs[i].value.update.new_hash, i, REFTABLE_HASH_SHA1); logs[i].value.update.email = xstrdup("identity@invalid"); } } - for (i = 0; i < N; i++) { - int err = reftable_stack_add(st, write_test_ref, &refs[i]); - check(!err); - } + for (i = 0; i < N; i++) + cl_assert_equal_i(reftable_stack_add(st, write_test_ref, &refs[i]), 0); for (i = 0; i < N; i++) { struct write_log_arg arg = { .log = &logs[i], .update_index = reftable_stack_next_update_index(st), }; - int err = reftable_stack_add(st, write_test_log, &arg); - check(!err); + cl_assert_equal_i(reftable_stack_add(st, + write_test_log, &arg), 0); } - err = reftable_stack_read_ref(st, "branch", &dest); - check_int(err, ==, 1); + cl_assert_equal_i(reftable_stack_read_ref(st, "branch", + &dest), 1); reftable_ref_record_release(&dest); - err = reftable_stack_read_log(st, "branch", &log_dest); - check_int(err, ==, 1); + cl_assert_equal_i(reftable_stack_read_log(st, "branch", + &log_dest), 1); reftable_log_record_release(&log_dest); - err = reftable_stack_compact_all(st, NULL); - check(!err); - - err = reftable_stack_read_ref(st, "branch", &dest); - check_int(err, ==, 1); - - err = reftable_stack_read_log(st, "branch", &log_dest); - check_int(err, ==, 1); + cl_assert_equal_i(reftable_stack_compact_all(st, NULL), 0); + cl_assert_equal_i(reftable_stack_read_ref(st, "branch", + &dest), 1); + cl_assert_equal_i(reftable_stack_read_log(st, "branch", + &log_dest), 1); reftable_ref_record_release(&dest); reftable_log_record_release(&log_dest); @@ -833,12 +795,11 @@ static void t_reftable_stack_tombstone(void) clear_dir(dir); } -static void t_reftable_stack_hash_id(void) +void test_reftable_stack__hash_id(void) { char *dir = get_tmp_dir(__LINE__); struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; - int err; struct reftable_ref_record ref = { .refname = (char *) "master", @@ -852,62 +813,57 @@ static void t_reftable_stack_hash_id(void) struct reftable_stack *st_default = NULL; struct reftable_ref_record dest = { 0 }; - err = reftable_new_stack(&st, dir, &opts); - check(!err); - - err = reftable_stack_add(st, write_test_ref, &ref); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); + cl_assert_equal_i(reftable_stack_add(st, write_test_ref, + &ref), 0); /* can't read it with the wrong hash ID. */ - err = reftable_new_stack(&st32, dir, &opts32); - check_int(err, ==, REFTABLE_FORMAT_ERROR); + cl_assert_equal_i(reftable_new_stack(&st32, dir, + &opts32), REFTABLE_FORMAT_ERROR); /* check that we can read it back with default opts too. */ - err = reftable_new_stack(&st_default, dir, &opts_default); - check(!err); - - err = reftable_stack_read_ref(st_default, "master", &dest); - check(!err); - - check(reftable_ref_record_equal(&ref, &dest, REFTABLE_HASH_SIZE_SHA1)); + cl_assert_equal_i(reftable_new_stack(&st_default, dir, + &opts_default), 0); + cl_assert_equal_i(reftable_stack_read_ref(st_default, "master", + &dest), 0); + cl_assert(reftable_ref_record_equal(&ref, &dest, + REFTABLE_HASH_SIZE_SHA1) != 0); reftable_ref_record_release(&dest); reftable_stack_destroy(st); reftable_stack_destroy(st_default); clear_dir(dir); } -static void t_suggest_compaction_segment(void) +void test_reftable_stack__suggest_compaction_segment(void) { uint64_t sizes[] = { 512, 64, 17, 16, 9, 9, 9, 16, 2, 16 }; struct segment min = suggest_compaction_segment(sizes, ARRAY_SIZE(sizes), 2); - check_int(min.start, ==, 1); - check_int(min.end, ==, 10); + cl_assert_equal_i(min.start, 1); + cl_assert_equal_i(min.end, 10); } -static void t_suggest_compaction_segment_nothing(void) +void test_reftable_stack__suggest_compaction_segment_nothing(void) { uint64_t sizes[] = { 64, 32, 16, 8, 4, 2 }; struct segment result = suggest_compaction_segment(sizes, ARRAY_SIZE(sizes), 2); - check_int(result.start, ==, result.end); + cl_assert_equal_i(result.start, result.end); } -static void t_reflog_expire(void) +void test_reftable_stack__reflog_expire(void) { char *dir = get_tmp_dir(__LINE__); struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; struct reftable_log_record logs[20] = { 0 }; size_t i, N = ARRAY_SIZE(logs) - 1; - int err; struct reftable_log_expiry_config expiry = { .time = 10, }; struct reftable_log_record log = { 0 }; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); for (i = 1; i <= N; i++) { char buf[256]; @@ -918,8 +874,8 @@ static void t_reflog_expire(void) logs[i].value_type = REFTABLE_LOG_UPDATE; logs[i].value.update.time = i; logs[i].value.update.email = xstrdup("identity@invalid"); - t_reftable_set_hash(logs[i].value.update.new_hash, i, - REFTABLE_HASH_SHA1); + cl_reftable_set_hash(logs[i].value.update.new_hash, i, + REFTABLE_HASH_SHA1); } for (i = 1; i <= N; i++) { @@ -927,31 +883,23 @@ static void t_reflog_expire(void) .log = &logs[i], .update_index = reftable_stack_next_update_index(st), }; - int err = reftable_stack_add(st, write_test_log, &arg); - check(!err); + cl_assert_equal_i(reftable_stack_add(st, write_test_log, + &arg), 0); } - err = reftable_stack_compact_all(st, NULL); - check(!err); - - err = reftable_stack_compact_all(st, &expiry); - check(!err); - - err = reftable_stack_read_log(st, logs[9].refname, &log); - check_int(err, ==, 1); - - err = reftable_stack_read_log(st, logs[11].refname, &log); - check(!err); + cl_assert_equal_i(reftable_stack_compact_all(st, NULL), 0); + cl_assert_equal_i(reftable_stack_compact_all(st, &expiry), 0); + cl_assert_equal_i(reftable_stack_read_log(st, logs[9].refname, + &log), 1); + cl_assert_equal_i(reftable_stack_read_log(st, logs[11].refname, + &log), 0); expiry.min_update_index = 15; - err = reftable_stack_compact_all(st, &expiry); - check(!err); - - err = reftable_stack_read_log(st, logs[14].refname, &log); - check_int(err, ==, 1); - - err = reftable_stack_read_log(st, logs[16].refname, &log); - check(!err); + cl_assert_equal_i(reftable_stack_compact_all(st, &expiry), 0); + cl_assert_equal_i(reftable_stack_read_log(st, logs[14].refname, + &log), 1); + cl_assert_equal_i(reftable_stack_read_log(st, logs[16].refname, + &log), 0); /* cleanup */ reftable_stack_destroy(st); @@ -963,26 +911,21 @@ static void t_reflog_expire(void) static int write_nothing(struct reftable_writer *wr, void *arg UNUSED) { - check(!reftable_writer_set_limits(wr, 1, 1)); + cl_assert_equal_i(reftable_writer_set_limits(wr, 1, 1), 0); return 0; } -static void t_empty_add(void) +void test_reftable_stack__empty_add(void) { struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; - int err; char *dir = get_tmp_dir(__LINE__); struct reftable_stack *st2 = NULL; - err = reftable_new_stack(&st, dir, &opts); - check(!err); - - err = reftable_stack_add(st, write_nothing, NULL); - check(!err); - - err = reftable_new_stack(&st2, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); + cl_assert_equal_i(reftable_stack_add(st, write_nothing, + NULL), 0); + cl_assert_equal_i(reftable_new_stack(&st2, dir, &opts), 0); clear_dir(dir); reftable_stack_destroy(st); reftable_stack_destroy(st2); @@ -998,18 +941,17 @@ static int fastlogN(uint64_t sz, uint64_t N) return l - 1; } -static void t_reftable_stack_auto_compaction(void) +void test_reftable_stack__auto_compaction(void) { struct reftable_write_options opts = { .disable_auto_compact = 1, }; struct reftable_stack *st = NULL; char *dir = get_tmp_dir(__LINE__); - int err; size_t i, N = 100; + int err; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); for (i = 0; i < N; i++) { char name[100]; @@ -1022,32 +964,31 @@ static void t_reftable_stack_auto_compaction(void) snprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i); err = reftable_stack_add(st, write_test_ref, &ref); - check(!err); + cl_assert(!err); err = reftable_stack_auto_compact(st); - check(!err); - check(i < 2 || st->merged->tables_len < 2 * fastlogN(i, 2)); + cl_assert(!err); + cl_assert(i < 2 || st->merged->tables_len < 2 * fastlogN(i, 2)); } - check_int(reftable_stack_compaction_stats(st)->entries_written, <, - (uint64_t)(N * fastlogN(N, 2))); + cl_assert(reftable_stack_compaction_stats(st)->entries_written < + (uint64_t)(N * fastlogN(N, 2))); reftable_stack_destroy(st); clear_dir(dir); } -static void t_reftable_stack_auto_compaction_factor(void) +void test_reftable_stack__auto_compaction_factor(void) { struct reftable_write_options opts = { .auto_compaction_factor = 5, }; struct reftable_stack *st = NULL; char *dir = get_tmp_dir(__LINE__); - int err; size_t N = 100; + int err; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); for (size_t i = 0; i < N; i++) { char name[20]; @@ -1059,16 +1000,16 @@ static void t_reftable_stack_auto_compaction_factor(void) xsnprintf(name, sizeof(name), "branch%04"PRIuMAX, (uintmax_t)i); err = reftable_stack_add(st, &write_test_ref, &ref); - check(!err); + cl_assert(!err); - check(i < 5 || st->merged->tables_len < 5 * fastlogN(i, 5)); + cl_assert(i < 5 || st->merged->tables_len < 5 * fastlogN(i, 5)); } reftable_stack_destroy(st); clear_dir(dir); } -static void t_reftable_stack_auto_compaction_with_locked_tables(void) +void test_reftable_stack__auto_compaction_with_locked_tables(void) { struct reftable_write_options opts = { .disable_auto_compact = 1, @@ -1078,21 +1019,20 @@ static void t_reftable_stack_auto_compaction_with_locked_tables(void) char *dir = get_tmp_dir(__LINE__); int err; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); write_n_ref_tables(st, 5); - check_int(st->merged->tables_len, ==, 5); + cl_assert_equal_i(st->merged->tables_len, 5); /* * Given that all tables we have written should be roughly the same * size, we expect that auto-compaction will want to compact all of the * tables. Locking any of the tables will keep it from doing so. */ - check(!reftable_buf_addstr(&buf, dir)); - check(!reftable_buf_addstr(&buf, "/")); - check(!reftable_buf_addstr(&buf, st->tables[2]->name)); - check(!reftable_buf_addstr(&buf, ".lock")); + cl_assert(!reftable_buf_addstr(&buf, dir)); + cl_assert(!reftable_buf_addstr(&buf, "/")); + cl_assert(!reftable_buf_addstr(&buf, st->tables[2]->name)); + cl_assert(!reftable_buf_addstr(&buf, ".lock")); write_file_buf(buf.buf, "", 0); /* @@ -1102,25 +1042,23 @@ static void t_reftable_stack_auto_compaction_with_locked_tables(void) * only compact the newest two tables. */ err = reftable_stack_auto_compact(st); - check(!err); - check_int(st->stats.failures, ==, 0); - check_int(st->merged->tables_len, ==, 4); + cl_assert(!err); + cl_assert_equal_i(st->stats.failures, 0); + cl_assert_equal_i(st->merged->tables_len, 4); reftable_stack_destroy(st); reftable_buf_release(&buf); clear_dir(dir); } -static void t_reftable_stack_add_performs_auto_compaction(void) +void test_reftable_stack__add_performs_auto_compaction(void) { struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; char *dir = get_tmp_dir(__LINE__); - int err; size_t i, n = 20; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); for (i = 0; i <= n; i++) { struct reftable_ref_record ref = { @@ -1140,8 +1078,8 @@ static void t_reftable_stack_add_performs_auto_compaction(void) snprintf(buf, sizeof(buf), "branch-%04"PRIuMAX, (uintmax_t)i); ref.refname = buf; - err = reftable_stack_add(st, write_test_ref, &ref); - check(!err); + cl_assert_equal_i(reftable_stack_add(st, + write_test_ref, &ref), 0); /* * The stack length should grow continuously for all runs where @@ -1149,16 +1087,16 @@ static void t_reftable_stack_add_performs_auto_compaction(void) * all tables in the stack. */ if (i != n) - check_int(st->merged->tables_len, ==, i + 1); + cl_assert_equal_i(st->merged->tables_len, i + 1); else - check_int(st->merged->tables_len, ==, 1); + cl_assert_equal_i(st->merged->tables_len, 1); } reftable_stack_destroy(st); clear_dir(dir); } -static void t_reftable_stack_compaction_with_locked_tables(void) +void test_reftable_stack__compaction_with_locked_tables(void) { struct reftable_write_options opts = { .disable_auto_compact = 1, @@ -1168,17 +1106,16 @@ static void t_reftable_stack_compaction_with_locked_tables(void) char *dir = get_tmp_dir(__LINE__); int err; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); write_n_ref_tables(st, 3); - check_int(st->merged->tables_len, ==, 3); + cl_assert_equal_i(st->merged->tables_len, 3); /* Lock one of the tables that we're about to compact. */ - check(!reftable_buf_addstr(&buf, dir)); - check(!reftable_buf_addstr(&buf, "/")); - check(!reftable_buf_addstr(&buf, st->tables[1]->name)); - check(!reftable_buf_addstr(&buf, ".lock")); + cl_assert(!reftable_buf_addstr(&buf, dir)); + cl_assert(!reftable_buf_addstr(&buf, "/")); + cl_assert(!reftable_buf_addstr(&buf, st->tables[1]->name)); + cl_assert(!reftable_buf_addstr(&buf, ".lock")); write_file_buf(buf.buf, "", 0); /* @@ -1186,36 +1123,31 @@ static void t_reftable_stack_compaction_with_locked_tables(void) * compact all tables. */ err = reftable_stack_compact_all(st, NULL); - check_int(err, ==, REFTABLE_LOCK_ERROR); - check_int(st->stats.failures, ==, 1); - check_int(st->merged->tables_len, ==, 3); + cl_assert_equal_i(err, REFTABLE_LOCK_ERROR); + cl_assert_equal_i(st->stats.failures, 1); + cl_assert_equal_i(st->merged->tables_len, 3); reftable_stack_destroy(st); reftable_buf_release(&buf); clear_dir(dir); } -static void t_reftable_stack_compaction_concurrent(void) +void test_reftable_stack__compaction_concurrent(void) { struct reftable_write_options opts = { 0 }; struct reftable_stack *st1 = NULL, *st2 = NULL; char *dir = get_tmp_dir(__LINE__); - int err; - err = reftable_new_stack(&st1, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st1, dir, &opts), 0); write_n_ref_tables(st1, 3); - err = reftable_new_stack(&st2, dir, &opts); - check(!err); - - err = reftable_stack_compact_all(st1, NULL); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st2, dir, &opts), 0); + cl_assert_equal_i(reftable_stack_compact_all(st1, NULL), 0); reftable_stack_destroy(st1); reftable_stack_destroy(st2); - check_int(count_dir_entries(dir), ==, 2); + cl_assert_equal_i(count_dir_entries(dir), 2); clear_dir(dir); } @@ -1228,32 +1160,24 @@ static void unclean_stack_close(struct reftable_stack *st) REFTABLE_FREE_AND_NULL(st->tables); } -static void t_reftable_stack_compaction_concurrent_clean(void) +void test_reftable_stack__compaction_concurrent_clean(void) { struct reftable_write_options opts = { 0 }; struct reftable_stack *st1 = NULL, *st2 = NULL, *st3 = NULL; char *dir = get_tmp_dir(__LINE__); - int err; - err = reftable_new_stack(&st1, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st1, dir, &opts), 0); write_n_ref_tables(st1, 3); - err = reftable_new_stack(&st2, dir, &opts); - check(!err); - - err = reftable_stack_compact_all(st1, NULL); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st2, dir, &opts), 0); + cl_assert_equal_i(reftable_stack_compact_all(st1, NULL), 0); unclean_stack_close(st1); unclean_stack_close(st2); - err = reftable_new_stack(&st3, dir, &opts); - check(!err); - - err = reftable_stack_clean(st3); - check(!err); - check_int(count_dir_entries(dir), ==, 2); + cl_assert_equal_i(reftable_new_stack(&st3, dir, &opts), 0); + cl_assert_equal_i(reftable_stack_clean(st3), 0); + cl_assert_equal_i(count_dir_entries(dir), 2); reftable_stack_destroy(st1); reftable_stack_destroy(st2); @@ -1262,7 +1186,7 @@ static void t_reftable_stack_compaction_concurrent_clean(void) clear_dir(dir); } -static void t_reftable_stack_read_across_reload(void) +void test_reftable_stack__read_across_reload(void) { struct reftable_write_options opts = { 0 }; struct reftable_stack *st1 = NULL, *st2 = NULL; @@ -1272,37 +1196,35 @@ static void t_reftable_stack_read_across_reload(void) int err; /* Create a first stack and set up an iterator for it. */ - err = reftable_new_stack(&st1, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st1, dir, &opts), 0); write_n_ref_tables(st1, 2); - check_int(st1->merged->tables_len, ==, 2); + cl_assert_equal_i(st1->merged->tables_len, 2); reftable_stack_init_ref_iterator(st1, &it); - err = reftable_iterator_seek_ref(&it, ""); - check(!err); + cl_assert_equal_i(reftable_iterator_seek_ref(&it, ""), 0); /* Set up a second stack for the same directory and compact it. */ err = reftable_new_stack(&st2, dir, &opts); - check(!err); - check_int(st2->merged->tables_len, ==, 2); + cl_assert(!err); + cl_assert_equal_i(st2->merged->tables_len, 2); err = reftable_stack_compact_all(st2, NULL); - check(!err); - check_int(st2->merged->tables_len, ==, 1); + cl_assert(!err); + cl_assert_equal_i(st2->merged->tables_len, 1); /* * Verify that we can continue to use the old iterator even after we * have reloaded its stack. */ err = reftable_stack_reload(st1); - check(!err); - check_int(st1->merged->tables_len, ==, 1); + cl_assert(!err); + cl_assert_equal_i(st1->merged->tables_len, 1); err = reftable_iterator_next_ref(&it, &rec); - check(!err); - check_str(rec.refname, "refs/heads/branch-0000"); + cl_assert(!err); + cl_assert_equal_s(rec.refname, "refs/heads/branch-0000"); err = reftable_iterator_next_ref(&it, &rec); - check(!err); - check_str(rec.refname, "refs/heads/branch-0001"); + cl_assert(!err); + cl_assert_equal_s(rec.refname, "refs/heads/branch-0001"); err = reftable_iterator_next_ref(&it, &rec); - check_int(err, >, 0); + cl_assert(err > 0); reftable_ref_record_release(&rec); reftable_iterator_destroy(&it); @@ -1311,7 +1233,7 @@ static void t_reftable_stack_read_across_reload(void) clear_dir(dir); } -static void t_reftable_stack_reload_with_missing_table(void) +void test_reftable_stack__reload_with_missing_table(void) { struct reftable_write_options opts = { 0 }; struct reftable_stack *st = NULL; @@ -1322,46 +1244,40 @@ static void t_reftable_stack_reload_with_missing_table(void) int err; /* Create a first stack and set up an iterator for it. */ - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); write_n_ref_tables(st, 2); - check_int(st->merged->tables_len, ==, 2); + cl_assert_equal_i(st->merged->tables_len, 2); reftable_stack_init_ref_iterator(st, &it); - err = reftable_iterator_seek_ref(&it, ""); - check(!err); + cl_assert_equal_i(reftable_iterator_seek_ref(&it, ""), 0); /* * Update the tables.list file with some garbage data, while reusing * our old tables. This should trigger a partial reload of the stack, * where we try to reuse our old tables. */ - check(!reftable_buf_addstr(&content, st->tables[0]->name)); - check(!reftable_buf_addstr(&content, "\n")); - check(!reftable_buf_addstr(&content, st->tables[1]->name)); - check(!reftable_buf_addstr(&content, "\n")); - check(!reftable_buf_addstr(&content, "garbage\n")); - check(!reftable_buf_addstr(&table_path, st->list_file)); - check(!reftable_buf_addstr(&table_path, ".lock")); + cl_assert(!reftable_buf_addstr(&content, st->tables[0]->name)); + cl_assert(!reftable_buf_addstr(&content, "\n")); + cl_assert(!reftable_buf_addstr(&content, st->tables[1]->name)); + cl_assert(!reftable_buf_addstr(&content, "\n")); + cl_assert(!reftable_buf_addstr(&content, "garbage\n")); + cl_assert(!reftable_buf_addstr(&table_path, st->list_file)); + cl_assert(!reftable_buf_addstr(&table_path, ".lock")); write_file_buf(table_path.buf, content.buf, content.len); - err = rename(table_path.buf, st->list_file); - check(!err); + cl_assert_equal_i(rename(table_path.buf, st->list_file), 0); err = reftable_stack_reload(st); - check_int(err, ==, -4); - check_int(st->merged->tables_len, ==, 2); + cl_assert_equal_i(err, -4); + cl_assert_equal_i(st->merged->tables_len, 2); /* * Even though the reload has failed, we should be able to continue * using the iterator. */ - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - check_str(rec.refname, "refs/heads/branch-0000"); - err = reftable_iterator_next_ref(&it, &rec); - check(!err); - check_str(rec.refname, "refs/heads/branch-0001"); - err = reftable_iterator_next_ref(&it, &rec); - check_int(err, >, 0); + cl_assert_equal_i(reftable_iterator_next_ref(&it, &rec), 0); + cl_assert_equal_s(rec.refname, "refs/heads/branch-0000"); + cl_assert_equal_i(reftable_iterator_next_ref(&it, &rec), 0); + cl_assert_equal_s(rec.refname, "refs/heads/branch-0001"); + cl_assert(reftable_iterator_next_ref(&it, &rec) > 0); reftable_ref_record_release(&rec); reftable_iterator_destroy(&it); @@ -1374,12 +1290,13 @@ static void t_reftable_stack_reload_with_missing_table(void) static int write_limits_after_ref(struct reftable_writer *wr, void *arg) { struct reftable_ref_record *ref = arg; - check(!reftable_writer_set_limits(wr, ref->update_index, ref->update_index)); - check(!reftable_writer_add_ref(wr, ref)); + cl_assert_equal_i(reftable_writer_set_limits(wr, + ref->update_index, ref->update_index), 0); + cl_assert_equal_i(reftable_writer_add_ref(wr, ref), 0); return reftable_writer_set_limits(wr, ref->update_index, ref->update_index); } -static void t_reftable_invalid_limit_updates(void) +void test_reftable_stack__invalid_limit_updates(void) { struct reftable_ref_record ref = { .refname = (char *) "HEAD", @@ -1393,59 +1310,22 @@ static void t_reftable_invalid_limit_updates(void) struct reftable_addition *add = NULL; char *dir = get_tmp_dir(__LINE__); struct reftable_stack *st = NULL; - int err; - err = reftable_new_stack(&st, dir, &opts); - check(!err); + cl_assert_equal_i(reftable_new_stack(&st, dir, &opts), 0); reftable_addition_destroy(add); - err = reftable_stack_new_addition(&add, st, 0); - check(!err); + cl_assert_equal_i(reftable_stack_new_addition(&add, st, 0), 0); /* * write_limits_after_ref also updates the update indexes after adding * the record. This should cause an err to be returned, since the limits * must be set at the start. */ - err = reftable_addition_add(add, write_limits_after_ref, &ref); - check_int(err, ==, REFTABLE_API_ERROR); + cl_assert_equal_i(reftable_addition_add(add, + write_limits_after_ref, &ref), REFTABLE_API_ERROR); reftable_addition_destroy(add); reftable_stack_destroy(st); clear_dir(dir); } - -int cmd_main(int argc UNUSED, const char *argv[] UNUSED) -{ - TEST(t_empty_add(), "empty addition to stack"); - TEST(t_read_file(), "read_lines works"); - TEST(t_reflog_expire(), "expire reflog entries"); - TEST(t_reftable_invalid_limit_updates(), "prevent limit updates after adding records"); - TEST(t_reftable_stack_add(), "add multiple refs and logs to stack"); - TEST(t_reftable_stack_add_one(), "add a single ref record to stack"); - TEST(t_reftable_stack_add_performs_auto_compaction(), "addition to stack triggers auto-compaction"); - TEST(t_reftable_stack_auto_compaction(), "stack must form geometric sequence after compaction"); - TEST(t_reftable_stack_auto_compaction_factor(), "auto-compaction with non-default geometric factor"); - TEST(t_reftable_stack_auto_compaction_fails_gracefully(), "failure on auto-compaction"); - TEST(t_reftable_stack_auto_compaction_with_locked_tables(), "auto compaction with locked tables"); - TEST(t_reftable_stack_compaction_concurrent(), "compaction with concurrent stack"); - TEST(t_reftable_stack_compaction_concurrent_clean(), "compaction with unclean stack shutdown"); - TEST(t_reftable_stack_compaction_with_locked_tables(), "compaction with locked tables"); - TEST(t_reftable_stack_hash_id(), "read stack with wrong hash ID"); - TEST(t_reftable_stack_iterator(), "log and ref iterator for reftable stack"); - TEST(t_reftable_stack_lock_failure(), "stack addition with lockfile failure"); - TEST(t_reftable_stack_log_normalize(), "log messages should be normalized"); - TEST(t_reftable_stack_read_across_reload(), "stack iterators work across reloads"); - TEST(t_reftable_stack_reload_with_missing_table(), "stack iteration with garbage tables"); - TEST(t_reftable_stack_tombstone(), "'tombstone' refs in stack"); - TEST(t_reftable_stack_transaction_api(), "update transaction to stack"); - TEST(t_reftable_stack_transaction_with_reload(), "transaction with reload"); - TEST(t_reftable_stack_transaction_api_performs_auto_compaction(), "update transaction triggers auto-compaction"); - TEST(t_reftable_stack_update_index_check(), "update transactions with equal update indices"); - TEST(t_reftable_stack_uptodate(), "stack must be reloaded before ref update"); - TEST(t_suggest_compaction_segment(), "suggest_compaction_segment with basic input"); - TEST(t_suggest_compaction_segment_nothing(), "suggest_compaction_segment with pre-compacted input"); - - return test_done(); -} diff --git a/t/unit-tests/t-reftable-table.c b/t/unit-tests/u-reftable-table.c index 7e1eb533d0..14fae8b199 100644 --- a/t/unit-tests/t-reftable-table.c +++ b/t/unit-tests/u-reftable-table.c @@ -1,4 +1,4 @@ -#include "test-lib.h" +#include "unit-test.h" #include "lib-reftable.h" #include "reftable/blocksource.h" #include "reftable/constants.h" @@ -6,7 +6,7 @@ #include "reftable/table.h" #include "strbuf.h" -static int t_table_seek_once(void) +void test_reftable_table__seek_once(void) { struct reftable_ref_record records[] = { { @@ -22,32 +22,32 @@ static int t_table_seek_once(void) struct reftable_buf buf = REFTABLE_BUF_INIT; int ret; - t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL); + cl_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL); block_source_from_buf(&source, &buf); ret = reftable_table_new(&table, &source, "name"); - check(!ret); + cl_assert(!ret); reftable_table_init_ref_iterator(table, &it); ret = reftable_iterator_seek_ref(&it, ""); - check(!ret); + cl_assert(!ret); ret = reftable_iterator_next_ref(&it, &ref); - check(!ret); + cl_assert(!ret); - ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1); - check_int(ret, ==, 1); + ret = reftable_ref_record_equal(&ref, &records[0], + REFTABLE_HASH_SIZE_SHA1); + cl_assert_equal_i(ret, 1); ret = reftable_iterator_next_ref(&it, &ref); - check_int(ret, ==, 1); + cl_assert_equal_i(ret, 1); reftable_ref_record_release(&ref); reftable_iterator_destroy(&it); reftable_table_decref(table); reftable_buf_release(&buf); - return 0; } -static int t_table_reseek(void) +void test_reftable_table__reseek(void) { struct reftable_ref_record records[] = { { @@ -63,35 +63,35 @@ static int t_table_reseek(void) struct reftable_buf buf = REFTABLE_BUF_INIT; int ret; - t_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), NULL, 0, NULL); + cl_reftable_write_to_buf(&buf, records, ARRAY_SIZE(records), + NULL, 0, NULL); block_source_from_buf(&source, &buf); ret = reftable_table_new(&table, &source, "name"); - check(!ret); + cl_assert(!ret); reftable_table_init_ref_iterator(table, &it); for (size_t i = 0; i < 5; i++) { ret = reftable_iterator_seek_ref(&it, ""); - check(!ret); + cl_assert(!ret); ret = reftable_iterator_next_ref(&it, &ref); - check(!ret); + cl_assert(!ret); ret = reftable_ref_record_equal(&ref, &records[0], REFTABLE_HASH_SIZE_SHA1); - check_int(ret, ==, 1); + cl_assert_equal_i(ret, 1); ret = reftable_iterator_next_ref(&it, &ref); - check_int(ret, ==, 1); + cl_assert_equal_i(ret, 1); } reftable_ref_record_release(&ref); reftable_iterator_destroy(&it); reftable_table_decref(table); reftable_buf_release(&buf); - return 0; } -static int t_table_block_iterator(void) +void test_reftable_table__block_iterator(void) { struct reftable_block_source source = { 0 }; struct reftable_table_iterator it = { 0 }; @@ -147,14 +147,14 @@ static int t_table_block_iterator(void) (uintmax_t) i); } - t_reftable_write_to_buf(&buf, records, nrecords, NULL, 0, NULL); + cl_reftable_write_to_buf(&buf, records, nrecords, NULL, 0, NULL); block_source_from_buf(&source, &buf); ret = reftable_table_new(&table, &source, "name"); - check(!ret); + cl_assert(!ret); ret = reftable_table_iterator_init(&it, table); - check(!ret); + cl_assert(!ret); for (size_t i = 0; i < ARRAY_SIZE(expected_blocks); i++) { struct reftable_iterator record_it = { 0 }; @@ -163,22 +163,26 @@ static int t_table_block_iterator(void) }; ret = reftable_table_iterator_next(&it, &block); - check(!ret); + cl_assert(!ret); - check_int(block->block_type, ==, expected_blocks[i].block_type); - check_int(block->header_off, ==, expected_blocks[i].header_off); - check_int(block->restart_count, ==, expected_blocks[i].restart_count); + cl_assert_equal_i(block->block_type, + expected_blocks[i].block_type); + cl_assert_equal_i(block->header_off, + expected_blocks[i].header_off); + cl_assert_equal_i(block->restart_count, + expected_blocks[i].restart_count); ret = reftable_block_init_iterator(block, &record_it); - check(!ret); + cl_assert(!ret); for (size_t j = 0; ; j++) { ret = iterator_next(&record_it, &record); if (ret > 0) { - check_int(j, ==, expected_blocks[i].record_count); + cl_assert_equal_i(j, + expected_blocks[i].record_count); break; } - check(!ret); + cl_assert(!ret); } reftable_iterator_destroy(&record_it); @@ -186,7 +190,7 @@ static int t_table_block_iterator(void) } ret = reftable_table_iterator_next(&it, &block); - check_int(ret, ==, 1); + cl_assert_equal_i(ret, 1); for (size_t i = 0; i < nrecords; i++) reftable_free(records[i].refname); @@ -194,13 +198,4 @@ static int t_table_block_iterator(void) reftable_table_decref(table); reftable_buf_release(&buf); reftable_free(records); - return 0; -} - -int cmd_main(int argc UNUSED, const char *argv[] UNUSED) -{ - TEST(t_table_seek_once(), "table can seek once"); - TEST(t_table_reseek(), "table can reseek multiple times"); - TEST(t_table_block_iterator(), "table can iterate through blocks"); - return test_done(); } diff --git a/t/unit-tests/u-string-list.c b/t/unit-tests/u-string-list.c new file mode 100644 index 0000000000..d4ba5f9fa5 --- /dev/null +++ b/t/unit-tests/u-string-list.c @@ -0,0 +1,227 @@ +#include "unit-test.h" +#include "string-list.h" + +static void t_vcreate_string_list_dup(struct string_list *list, + int free_util, va_list ap) +{ + const char *arg; + + cl_assert(list->strdup_strings); + + string_list_clear(list, free_util); + while ((arg = va_arg(ap, const char *))) + string_list_append(list, arg); +} + +static void t_create_string_list_dup(struct string_list *list, int free_util, ...) +{ + va_list ap; + + cl_assert(list->strdup_strings); + + string_list_clear(list, free_util); + va_start(ap, free_util); + t_vcreate_string_list_dup(list, free_util, ap); + va_end(ap); +} + +static void t_string_list_clear(struct string_list *list, int free_util) +{ + string_list_clear(list, free_util); + cl_assert_equal_p(list->items, NULL); + cl_assert_equal_i(list->nr, 0); + cl_assert_equal_i(list->alloc, 0); +} + +static void t_string_list_equal(struct string_list *list, + struct string_list *expected_strings) +{ + cl_assert_equal_i(list->nr, expected_strings->nr); + cl_assert(list->nr <= list->alloc); + for (size_t i = 0; i < expected_strings->nr; i++) + cl_assert_equal_s(list->items[i].string, + expected_strings->items[i].string); +} + +static void t_string_list_split(const char *data, int delim, int maxsplit, ...) +{ + struct string_list expected_strings = STRING_LIST_INIT_DUP; + struct string_list list = STRING_LIST_INIT_DUP; + va_list ap; + int len; + + va_start(ap, maxsplit); + t_vcreate_string_list_dup(&expected_strings, 0, ap); + va_end(ap); + + string_list_clear(&list, 0); + len = string_list_split(&list, data, delim, maxsplit); + cl_assert_equal_i(len, expected_strings.nr); + t_string_list_equal(&list, &expected_strings); + + string_list_clear(&expected_strings, 0); + string_list_clear(&list, 0); +} + +void test_string_list__split(void) +{ + t_string_list_split("foo:bar:baz", ':', -1, "foo", "bar", "baz", NULL); + t_string_list_split("foo:bar:baz", ':', 0, "foo:bar:baz", NULL); + t_string_list_split("foo:bar:baz", ':', 1, "foo", "bar:baz", NULL); + t_string_list_split("foo:bar:baz", ':', 2, "foo", "bar", "baz", NULL); + t_string_list_split("foo:bar:", ':', -1, "foo", "bar", "", NULL); + t_string_list_split("", ':', -1, "", NULL); + t_string_list_split(":", ':', -1, "", "", NULL); +} + +static void t_string_list_split_in_place(const char *data, const char *delim, + int maxsplit, ...) +{ + struct string_list expected_strings = STRING_LIST_INIT_DUP; + struct string_list list = STRING_LIST_INIT_NODUP; + char *string = xstrdup(data); + va_list ap; + int len; + + va_start(ap, maxsplit); + t_vcreate_string_list_dup(&expected_strings, 0, ap); + va_end(ap); + + string_list_clear(&list, 0); + len = string_list_split_in_place(&list, string, delim, maxsplit); + cl_assert_equal_i(len, expected_strings.nr); + t_string_list_equal(&list, &expected_strings); + + free(string); + string_list_clear(&expected_strings, 0); + string_list_clear(&list, 0); +} + +void test_string_list__split_in_place(void) +{ + t_string_list_split_in_place("foo:;:bar:;:baz:;:", ":;", -1, + "foo", "", "", "bar", "", "", "baz", "", "", "", NULL); + t_string_list_split_in_place("foo:;:bar:;:baz", ":;", 0, + "foo:;:bar:;:baz", NULL); + t_string_list_split_in_place("foo:;:bar:;:baz", ":;", 1, + "foo", ";:bar:;:baz", NULL); + t_string_list_split_in_place("foo:;:bar:;:baz", ":;", 2, + "foo", "", ":bar:;:baz", NULL); + t_string_list_split_in_place("foo:;:bar:;:", ":;", -1, + "foo", "", "", "bar", "", "", "", NULL); +} + +static int prefix_cb(struct string_list_item *item, void *cb_data) +{ + const char *prefix = (const char *)cb_data; + return starts_with(item->string, prefix); +} + +static void t_string_list_filter(struct string_list *list, ...) +{ + struct string_list expected_strings = STRING_LIST_INIT_DUP; + const char *prefix = "y"; + va_list ap; + + va_start(ap, list); + t_vcreate_string_list_dup(&expected_strings, 0, ap); + va_end(ap); + + filter_string_list(list, 0, prefix_cb, (void *)prefix); + t_string_list_equal(list, &expected_strings); + + string_list_clear(&expected_strings, 0); +} + +void test_string_list__filter(void) +{ + struct string_list list = STRING_LIST_INIT_DUP; + + t_create_string_list_dup(&list, 0, NULL); + t_string_list_filter(&list, NULL); + + t_create_string_list_dup(&list, 0, "no", NULL); + t_string_list_filter(&list, NULL); + + t_create_string_list_dup(&list, 0, "yes", NULL); + t_string_list_filter(&list, "yes", NULL); + + t_create_string_list_dup(&list, 0, "no", "yes", NULL); + t_string_list_filter(&list, "yes", NULL); + + t_create_string_list_dup(&list, 0, "yes", "no", NULL); + t_string_list_filter(&list, "yes", NULL); + + t_create_string_list_dup(&list, 0, "y1", "y2", NULL); + t_string_list_filter(&list, "y1", "y2", NULL); + + t_create_string_list_dup(&list, 0, "y2", "y1", NULL); + t_string_list_filter(&list, "y2", "y1", NULL); + + t_create_string_list_dup(&list, 0, "x1", "x2", NULL); + t_string_list_filter(&list, NULL); + + t_string_list_clear(&list, 0); +} + +static void t_string_list_remove_duplicates(struct string_list *list, ...) +{ + struct string_list expected_strings = STRING_LIST_INIT_DUP; + va_list ap; + + va_start(ap, list); + t_vcreate_string_list_dup(&expected_strings, 0, ap); + va_end(ap); + + string_list_remove_duplicates(list, 0); + t_string_list_equal(list, &expected_strings); + + string_list_clear(&expected_strings, 0); +} + +void test_string_list__remove_duplicates(void) +{ + struct string_list list = STRING_LIST_INIT_DUP; + + t_create_string_list_dup(&list, 0, NULL); + t_string_list_remove_duplicates(&list, NULL); + + t_create_string_list_dup(&list, 0, "", NULL); + t_string_list_remove_duplicates(&list, "", NULL); + + t_create_string_list_dup(&list, 0, "a", NULL); + t_string_list_remove_duplicates(&list, "a", NULL); + + t_create_string_list_dup(&list, 0, "a", "a", NULL); + t_string_list_remove_duplicates(&list, "a", NULL); + + t_create_string_list_dup(&list, 0, "a", "a", "a", NULL); + t_string_list_remove_duplicates(&list, "a", NULL); + + t_create_string_list_dup(&list, 0, "a", "a", "b", NULL); + t_string_list_remove_duplicates(&list, "a", "b", NULL); + + t_create_string_list_dup(&list, 0, "a", "b", "b", NULL); + t_string_list_remove_duplicates(&list, "a", "b", NULL); + + t_create_string_list_dup(&list, 0, "a", "b", "c", NULL); + t_string_list_remove_duplicates(&list, "a", "b", "c", NULL); + + t_create_string_list_dup(&list, 0, "a", "a", "b", "c", NULL); + t_string_list_remove_duplicates(&list, "a", "b", "c", NULL); + + t_create_string_list_dup(&list, 0, "a", "b", "b", "c", NULL); + t_string_list_remove_duplicates(&list, "a", "b", "c", NULL); + + t_create_string_list_dup(&list, 0, "a", "b", "c", "c", NULL); + t_string_list_remove_duplicates(&list, "a", "b", "c", NULL); + + t_create_string_list_dup(&list, 0, "a", "a", "b", "b", "c", "c", NULL); + t_string_list_remove_duplicates(&list, "a", "b", "c", NULL); + + t_create_string_list_dup(&list, 0, "a", "a", "a", "b", "b", "b", + "c", "c", "c", NULL); + t_string_list_remove_duplicates(&list, "a", "b", "c", NULL); + + t_string_list_clear(&list, 0); +} diff --git a/t/unit-tests/unit-test.h b/t/unit-tests/unit-test.h index 85e5d6a948..39a0b72a05 100644 --- a/t/unit-tests/unit-test.h +++ b/t/unit-tests/unit-test.h @@ -1,8 +1,13 @@ #include "git-compat-util.h" #include "clar/clar.h" -#include "clar-decls.h" #include "strbuf.h" +#ifndef GIT_CLAR_DECLS_H +# include "clar-decls.h" +#else +# include GIT_CLAR_DECLS_H +#endif + #define cl_failf(fmt, ...) do { \ char desc[4096]; \ snprintf(desc, sizeof(desc), fmt, __VA_ARGS__); \ @@ -595,8 +595,8 @@ void trailer_config_init(void) default_conf_info.where = WHERE_END; default_conf_info.if_exists = EXISTS_ADD_IF_DIFFERENT_NEIGHBOR; default_conf_info.if_missing = MISSING_ADD; - git_config(git_trailer_default_config, NULL); - git_config(git_trailer_config, NULL); + repo_config(the_repository, git_trailer_default_config, NULL); + repo_config(the_repository, git_trailer_config, NULL); configured = 1; } diff --git a/transport.c b/transport.c index 6c2801bcbd..e305d6bd22 100644 --- a/transport.c +++ b/transport.c @@ -54,14 +54,14 @@ static int transport_color_config(void) return 0; initialized = 1; - if (!git_config_get_string(key, &value)) + if (!repo_config_get_string(the_repository, key, &value)) transport_use_color = git_config_colorbool(key, value); if (!want_color_stderr(transport_use_color)) return 0; for (size_t i = 0; i < ARRAY_SIZE(keys); i++) - if (!git_config_get_string(keys[i], &value)) { + if (!repo_config_get_string(the_repository, keys[i], &value)) { if (!value) return config_error_nonbool(keys[i]); if (color_parse(value, transport_colors[i]) < 0) @@ -202,7 +202,7 @@ static int fetch_refs_from_bundle(struct transport *transport, if (!data->get_refs_from_bundle_called) get_refs_from_bundle_inner(transport); - git_config(fetch_fsck_config_cb, &msg_types); + repo_config(the_repository, fetch_fsck_config_cb, &msg_types); opts.fsck_msg_types = msg_types.buf; ret = unbundle(the_repository, &data->header, data->fd, @@ -1078,7 +1078,7 @@ static enum protocol_allow_config get_protocol_config(const char *type) char *value; /* first check the per-protocol config */ - if (!git_config_get_string(key, &value)) { + if (!repo_config_get_string(the_repository, key, &value)) { enum protocol_allow_config ret = parse_protocol_config(key, value); free(key); @@ -1088,7 +1088,7 @@ static enum protocol_allow_config get_protocol_config(const char *type) free(key); /* if defined, fallback to user-defined default for unknown protocols */ - if (!git_config_get_string("protocol.allow", &value)) { + if (!repo_config_get_string(the_repository, "protocol.allow", &value)) { enum protocol_allow_config ret = parse_protocol_config("protocol.allow", value); free(value); @@ -1243,7 +1243,7 @@ struct transport *transport_get(struct remote *remote, const char *url) ret->smart_options->receivepack = remote->receivepack; } - ret->hash_algo = &hash_algos[GIT_HASH_SHA1]; + ret->hash_algo = &hash_algos[GIT_HASH_SHA1_LEGACY]; return ret; } @@ -1602,7 +1602,7 @@ int transport_get_remote_bundle_uri(struct transport *transport) * Don't request bundle-uri from the server unless configured to * do so by the transfer.bundleURI=true config option. */ - if (git_config_get_bool("transfer.bundleuri", &value) || !value) + if (repo_config_get_bool(the_repository, "transfer.bundleuri", &value) || !value) return 0; if (!transport->bundles->baseURI) diff --git a/versioncmp.c b/versioncmp.c index b6eebdb989..3a81b17bc1 100644 --- a/versioncmp.c +++ b/versioncmp.c @@ -167,8 +167,8 @@ int versioncmp(const char *s1, const char *s2) const char *const oldk = "versionsort.prereleasesuffix"; const struct string_list *newl; const struct string_list *oldl; - int new = git_config_get_string_multi(newk, &newl); - int old = git_config_get_string_multi(oldk, &oldl); + int new = repo_config_get_string_multi(the_repository, newk, &newl); + int old = repo_config_get_string_multi(the_repository, oldk, &oldl); if (!new && !old) warning("ignoring %s because %s is set", oldk, newk); @@ -14,6 +14,7 @@ #include "blob.h" #include "refs.h" #include "progress.h" +#include "prio-queue.h" static struct object_id current_commit_oid; @@ -78,7 +79,7 @@ static int process_tree(struct walker *walker, struct tree *tree) #define SEEN (1U << 1) #define TO_SCAN (1U << 2) -static struct commit_list *complete = NULL; +static struct prio_queue complete = { compare_commits_by_commit_date }; static int process_commit(struct walker *walker, struct commit *commit) { @@ -87,7 +88,10 @@ static int process_commit(struct walker *walker, struct commit *commit) if (repo_parse_commit(the_repository, commit)) return -1; - while (complete && complete->item->date >= commit->date) { + while (complete.nr) { + struct commit *item = prio_queue_peek(&complete); + if (item->date < commit->date) + break; pop_most_recent_commit(&complete, COMPLETE); } @@ -233,7 +237,7 @@ static int mark_complete(const char *path UNUSED, if (commit) { commit->object.flags |= COMPLETE; - commit_list_insert(commit, &complete); + prio_queue_put(&complete, commit); } return 0; } @@ -302,7 +306,6 @@ int walker_fetch(struct walker *walker, int targets, char **target, if (!walker->get_recover) { refs_for_each_ref(get_main_ref_store(the_repository), mark_complete, NULL); - commit_list_sort_by_date(&complete); } for (i = 0; i < targets; i++) { diff --git a/worktree.c b/worktree.c index c34b9eb74e..a2a5f51f29 100644 --- a/worktree.c +++ b/worktree.c @@ -991,9 +991,9 @@ done: static int move_config_setting(const char *key, const char *value, const char *from_file, const char *to_file) { - if (git_config_set_in_file_gently(to_file, key, NULL, value)) + if (repo_config_set_in_file_gently(the_repository, to_file, key, NULL, value)) return error(_("unable to set %s in '%s'"), key, to_file); - if (git_config_set_in_file_gently(from_file, key, NULL, NULL)) + if (repo_config_set_in_file_gently(the_repository, from_file, key, NULL, NULL)) return error(_("unable to unset %s in '%s'"), key, from_file); return 0; } @@ -1013,7 +1013,7 @@ int init_worktree_config(struct repository *r) */ if (r->repository_format_worktree_config) return 0; - if ((res = git_config_set_gently("extensions.worktreeConfig", "true"))) + if ((res = repo_config_set_gently(the_repository, "extensions.worktreeConfig", "true"))) return error(_("failed to set extensions.worktreeConfig setting")); common_config_file = xstrfmt("%s/config", r->commondir); @@ -1077,7 +1077,7 @@ void write_worktree_linking_files(struct strbuf dotgit, struct strbuf gitdir, if (use_relative_paths && !the_repository->repository_format_relative_worktrees) { if (upgrade_repository_format(1) < 0) die(_("unable to upgrade repository format to support relative worktrees")); - if (git_config_set_gently("extensions.relativeWorktrees", "true")) + if (repo_config_set_gently(the_repository, "extensions.relativeWorktrees", "true")) die(_("unable to set extensions.relativeWorktrees setting")); the_repository->repository_format_relative_worktrees = 1; } diff --git a/xdiff-interface.c b/xdiff-interface.c index 0e5d38c960..4971f722b3 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -2,6 +2,7 @@ #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" +#include "environment.h" #include "gettext.h" #include "config.h" #include "hex.h" |
