diff options
836 files changed, 23014 insertions, 9402 deletions
diff --git a/.clang-format b/.clang-format index 3ed4fac753..0b82f3c776 100644 --- a/.clang-format +++ b/.clang-format @@ -72,6 +72,10 @@ AlwaysBreakAfterReturnType: None BinPackArguments: true BinPackParameters: true +# Add no space around the bit field +# unsigned bf:2; +BitFieldColonSpacing: None + # Attach braces to surrounding context except break before braces on function # definitions. # void foo() @@ -96,6 +100,14 @@ BreakStringLiterals: false # Switch statement body is always indented one level more than case labels. IndentCaseLabels: false +# Indents directives before the hash. Each level uses a single space for +# indentation. +# #if FOO +# # include <foo> +# #endif +IndentPPDirectives: AfterHash +PPIndentWidth: 1 + # Don't indent a function definition or declaration if it is wrapped after the # type IndentWrappedFunctionNames: false @@ -108,11 +120,18 @@ PointerAlignment: Right # x = (int32)y; not x = (int32) y; SpaceAfterCStyleCast: false +# No space is inserted after the logical not operator +SpaceAfterLogicalNot: false + # Insert spaces before and after assignment operators # int a = 5; not int a=5; # a += 42; a+=42; SpaceBeforeAssignmentOperators: true +# Spaces will be removed before case colon. +# case 1: break; not case 1 : break; +SpaceBeforeCaseColon: false + # Put a space before opening parentheses only after control statement keywords. # void f() { # if (true) { @@ -124,6 +143,14 @@ SpaceBeforeParens: ControlStatements # Don't insert spaces inside empty '()' SpaceInEmptyParentheses: false +# No space before first '[' in arrays +# int a[5][5]; not int a [5][5]; +SpaceBeforeSquareBrackets: false + +# No space will be inserted into {} +# while (true) {} not while (true) { } +SpaceInEmptyBlock: false + # The number of spaces before trailing line comments (// - comments). # This does not affect trailing block comments (/* - comments). SpacesBeforeTrailingComments: 1 @@ -149,20 +176,25 @@ Cpp11BracedListStyle: false # A list of macros that should be interpreted as foreach loops instead of as # function calls. Taken from: -# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' \ -# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ -# | sort | uniq +# git grep -h '^#define [^[:space:]]*for_\?each[^[:space:]]*(' | +# sed "s/^#define / - '/; s/(.*$/'/" | sort | uniq ForEachMacros: - - 'for_each_abbrev' - 'for_each_builtin' - 'for_each_string_list_item' - 'for_each_ut' - 'for_each_wanted_builtin' + - 'hashmap_for_each_entry' + - 'hashmap_for_each_entry_from' + - 'kh_foreach' + - 'kh_foreach_value' - 'list_for_each' - 'list_for_each_dir' - 'list_for_each_prev' - 'list_for_each_prev_safe' - 'list_for_each_safe' + - 'strintmap_for_each_entry' + - 'strmap_for_each_entry' + - 'strset_for_each_entry' # The maximum number of consecutive empty lines to keep. MaxEmptyLinesToKeep: 1 diff --git a/.github/workflows/check-style.yml b/.github/workflows/check-style.yml new file mode 100644 index 0000000000..c052a5df23 --- /dev/null +++ b/.github/workflows/check-style.yml @@ -0,0 +1,34 @@ +name: check-style + +# Get the repository with all commits to ensure that we can analyze +# all of the commits contributed via the Pull Request. + +on: + pull_request: + types: [opened, synchronize] + +# Avoid unnecessary builds. Unlike the main CI jobs, these are not +# ci-configurable (but could be). +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + check-style: + env: + CC: clang + jobname: ClangFormat + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - run: ci/install-dependencies.sh + + - name: git clang-format + continue-on-error: true + id: check_out + run: | + ./ci/run-style-check.sh \ + "${{github.event.pull_request.base.sha}}" diff --git a/.gitignore b/.gitignore index 612c0f6a0f..8caf3700c2 100644 --- a/.gitignore +++ b/.gitignore @@ -126,6 +126,7 @@ /git-rebase /git-receive-pack /git-reflog +/git-refs /git-remote /git-remote-http /git-remote-https diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f676959ca0..2589098eff 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -118,7 +118,39 @@ check-whitespace: image: ubuntu:latest before_script: - ./ci/install-dependencies.sh + # Since $CI_MERGE_REQUEST_TARGET_BRANCH_SHA is only defined for merged + # pipelines, we fallback to $CI_MERGE_REQUEST_DIFF_BASE_SHA, which should + # be defined in all pipelines. script: - - ./ci/check-whitespace.sh "$CI_MERGE_REQUEST_TARGET_BRANCH_SHA" + - | + R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit + ./ci/check-whitespace.sh "$R" rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + +check-style: + image: ubuntu:latest + allow_failure: true + variables: + CC: clang + jobname: ClangFormat + before_script: + - ./ci/install-dependencies.sh + # Since $CI_MERGE_REQUEST_TARGET_BRANCH_SHA is only defined for merged + # pipelines, we fallback to $CI_MERGE_REQUEST_DIFF_BASE_SHA, which should + # be defined in all pipelines. + script: + - | + R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit + ./ci/run-style-check.sh "$R" + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + +documentation: + image: ubuntu:latest + variables: + jobname: Documentation + before_script: + - ./ci/install-dependencies.sh + script: + - ./ci/test-documentation.sh diff --git a/Documentation/BreakingChanges.txt b/Documentation/BreakingChanges.txt new file mode 100644 index 0000000000..0532bfcf7f --- /dev/null +++ b/Documentation/BreakingChanges.txt @@ -0,0 +1,135 @@ += Upcoming breaking changes + +The Git project aims to ensure backwards compatibility to the best extent +possible. Minor releases will not break backwards compatibility unless there is +a very strong reason to do so, like for example a security vulnerability. + +Regardless of that, due to the age of the Git project, it is only natural to +accumulate a backlog of backwards-incompatible changes that will eventually be +required to keep the project aligned with a changing world. These changes fall +into several categories: + +* Changes to long established defaults. +* Concepts that have been replaced with a superior design. +* Concepts, commands, configuration or options that have been lacking in major + ways and that cannot be fixed and which will thus be removed without any + replacement. + +Explicitly not included in this list are fixes to minor bugs that may cause a +change in user-visible behavior. + +The Git project irregularly releases breaking versions that deliberately break +backwards compatibility with older versions. This is done to ensure that Git +remains relevant, safe and maintainable going forward. The release cadence of +breaking versions is typically measured in multiple years. We had the following +major breaking releases in the past: + +* Git 1.6.0, released in August 2008. +* Git 2.0, released in May 2014. + +We use <major>.<minor> release numbers these days, starting from Git 2.0. For +future releases, our plan is to increment <major> in the release number when we +make the next breaking release. Before Git 2.0, the release numbers were +1.<major>.<minor> with the intention to increment <major> for "usual" breaking +releases, reserving the jump to Git 2.0 for really large backward-compatibility +breaking changes. + +The intent of this document is to track upcoming deprecations for future +breaking releases. Furthermore, this document also tracks what will _not_ be +deprecated. This is done such that the outcome of discussions document both +when the discussion favors deprecation, but also when it rejects a deprecation. + +Items should have a clear summary of the reasons why we do or do not want to +make the described change that can be easily understood without having to read +the mailing list discussions. If there are alternatives to the changed feature, +those alternatives should be pointed out to our users. + +All items should be accompanied by references to relevant mailing list threads +where the deprecation was discussed. These references use message-IDs, which +can visited via + + https://lore.kernel.org/git/$message_id/ + +to see the message and its surrounding discussion. Such a reference is there to +make it easier for you to find how the project reached consensus on the +described item back then. + +This is a living document as the environment surrounding the project changes +over time. If circumstances change, an earlier decision to deprecate or change +something may need to be revisited from time to time. So do not take items on +this list to mean "it is settled, do not waste our time bringing it up again". + +== Git 3.0 + +The following subsections document upcoming breaking changes for Git 3.0. There +is no planned release date for this breaking version yet. + +Proposed changes and removals only include items which are "ready" to be done. +In other words, this is not supposed to be a wishlist of features that should +be changed to or replaced in case the alternative was implemented already. + +=== Changes + +* The default hash function for new repositories will be changed from "sha1" + to "sha256". SHA-1 has been deprecated by NIST in 2011 and is nowadays + recommended against in FIPS 140-2 and similar certifications. Furthermore, + there are practical attacks on SHA-1 that weaken its cryptographic properties: ++ + ** The SHAppening (2015). The first demonstration of a practical attack + against SHA-1 with 2^57 operations. + ** SHAttered (2017). Generation of two valid PDF files with 2^63 operations. + ** Birthday-Near-Collision (2019). This attack allows for chosen prefix + attacks with 2^68 operations. + ** Shambles (2020). This attack allows for chosen prefix attacks with 2^63 + operations. ++ +While we have protections in place against known attacks, it is expected +that more attacks against SHA-1 will be found by future research. Paired +with the ever-growing capability of hardware, it is only a matter of time +before SHA-1 will be considered broken completely. We want to be prepared +and will thus change the default hash algorithm to "sha256" for newly +initialized repositories. ++ +An important requirement for this change is that the ecosystem is ready to +support the "sha256" object format. This includes popular Git libraries, +applications and forges. ++ +There is no plan to deprecate the "sha1" object format at this point in time. ++ +Cf. <2f5de416-04ba-c23d-1e0b-83bb655829a7@zombino.com>, +<20170223155046.e7nxivfwqqoprsqj@LykOS.localdomain>, +<CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@mail.gmail.com>. + +=== Removals + +* Support for grafting commits has long been superseded by git-replace(1). + Grafts are inferior to replacement refs: ++ + ** Grafts are a local-only mechanism and cannot be shared across + repositories. + ** Grafts can lead to hard-to-diagnose problems when transferring objects + between repositories. ++ +The grafting mechanism has been marked as outdated since e650d0643b (docs: mark +info/grafts as outdated, 2014-03-05) and will be removed. ++ +Cf. <20140304174806.GA11561@sigill.intra.peff.net>. + +== Superseded features that will not be deprecated + +Some features have gained newer replacements that aim to improve the design in +certain ways. The fact that there is a replacement does not automatically mean +that the old way of doing things will eventually be removed. This section tracks +those features with newer alternatives. + +* The features git-checkout(1) offers are covered by the pair of commands + git-restore(1) and git-switch(1). Because the use of git-checkout(1) is still + widespread, and it is not expected that this will change anytime soon, all + three commands will stay. ++ +This decision may get revisited in case we ever figure out that there are +almost no users of any of the commands anymore. ++ +Cf. <xmqqttjazwwa.fsf@gitster.g>, +<xmqqleeubork.fsf@gitster.g>, +<112b6568912a6de6672bf5592c3a718e@manjaro.org>. diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 1d92b2da03..2f35b6691f 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -204,6 +204,33 @@ For shell scripts specifically (not exhaustive): local variable="$value" local variable="$(command args)" + - The common construct + + VAR=VAL command args + + to temporarily set and export environment variable VAR only while + "command args" is running is handy, but this triggers an + unspecified behaviour according to POSIX when used for a command + that is not an external command (like shell functions). Indeed, + dash 0.5.10.2-6 on Ubuntu 20.04, /bin/sh on FreeBSD 13, and AT&T + ksh all make a temporary assignment without exporting the variable, + in such a case. As it does not work portably across shells, do not + use this syntax for shell functions. A common workaround is to do + an explicit export in a subshell, like so: + + (incorrect) + VAR=VAL func args + + (correct) + ( + VAR=VAL && + export VAR && + func args + ) + + but be careful that the effect "func" makes to the variables in the + current shell will be lost across the subshell boundary. + - Use octal escape sequences (e.g. "\302\242"), not hexadecimal (e.g. "\xc2\xa2") in printf format strings, since hexadecimal escape sequences are not portable. @@ -214,6 +241,16 @@ For C programs: - We use tabs to indent, and interpret tabs as taking up to 8 spaces. + - Nested C preprocessor directives are indented after the hash by one + space per nesting level. + + #if FOO + # include <foo.h> + # if BAR + # include <bar.h> + # endif + #endif + - We try to keep to at most 80 characters per line. - As a Git developer we assume you have a reasonably modern compiler @@ -234,7 +271,7 @@ For C programs: . since around 2007 with 2b6854c863a, we have been using initializer elements which are not computable at load time. E.g.: - const char *args[] = {"constant", variable, NULL}; + const char *args[] = { "constant", variable, NULL }; . since early 2012 with e1327023ea, we have been using an enum definition whose last element is followed by a comma. This, like @@ -531,6 +568,42 @@ For C programs: use your own debugger and arguments. Example: `GIT_DEBUGGER="ddd --gdb" ./bin-wrappers/git log` (See `wrap-for-bin.sh`.) + - The primary data structure that a subsystem 'S' deals with is called + `struct S`. Functions that operate on `struct S` are named + `S_<verb>()` and should generally receive a pointer to `struct S` as + first parameter. E.g. + + struct strbuf; + + void strbuf_add(struct strbuf *buf, ...); + + void strbuf_reset(struct strbuf *buf); + + is preferred over: + + struct strbuf; + + void add_string(struct strbuf *buf, ...); + + void reset_strbuf(struct strbuf *buf); + + - There are several common idiomatic names for functions performing + specific tasks on a structure `S`: + + - `S_init()` initializes a structure without allocating the + structure itself. + + - `S_release()` releases a structure's contents without freeing the + structure. + + - `S_clear()` is equivalent to `S_release()` followed by `S_init()` + such that the structure is directly usable after clearing it. When + `S_clear()` is provided, `S_init()` shall not allocate resources + that need to be released again. + + - `S_free()` releases a structure's contents and frees the + structure. + For Perl programs: - Most of the C guidelines above apply. diff --git a/Documentation/Makefile b/Documentation/Makefile index a04da672c6..1bd23fbeef 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -51,6 +51,7 @@ MAN7_TXT += gitdiffcore.txt MAN7_TXT += giteveryday.txt MAN7_TXT += gitfaq.txt MAN7_TXT += gitglossary.txt +MAN7_TXT += gitpacking.txt MAN7_TXT += gitnamespaces.txt MAN7_TXT += gitremote-helpers.txt MAN7_TXT += gitrevisions.txt @@ -203,12 +204,15 @@ ASCIIDOC_DOCBOOK = docbook5 ASCIIDOC_EXTRA += -acompat-mode -atabsize=8 ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions ASCIIDOC_EXTRA += -alitdd='&\#x2d;&\#x2d;' +ASCIIDOC_EXTRA += -adocinfo=shared ASCIIDOC_DEPS = asciidoctor-extensions.rb GIT-ASCIIDOCFLAGS DBLATEX_COMMON = XMLTO_EXTRA += --skip-validation XMLTO_EXTRA += -x manpage.xsl endif +ASCIIDOC_DEPS += docinfo.html + SHELL_PATH ?= $(SHELL) # Shell quote; SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) @@ -337,6 +341,9 @@ clean: $(RM) $(cmds_txt) $(mergetools_txt) *.made $(RM) GIT-ASCIIDOCFLAGS +docinfo.html: docinfo-html.in + $(QUIET_GEN)$(RM) $@ && cat $< >$@ + $(MAN_HTML): %.html : %.txt $(ASCIIDOC_DEPS) $(QUIET_ASCIIDOC)$(TXT_TO_HTML) -d manpage -o $@ $< @@ -485,12 +492,16 @@ $(LINT_DOCS_FSCK_MSGIDS): ../fsck.h fsck-msgids.txt lint-docs-fsck-msgids: $(LINT_DOCS_FSCK_MSGIDS) +lint-docs-manpages: + $(QUIET_GEN)./lint-manpages.sh + ## Lint: list of targets above .PHONY: lint-docs lint-docs: lint-docs-fsck-msgids lint-docs: lint-docs-gitlink lint-docs: lint-docs-man-end-blurb lint-docs: lint-docs-man-section-order +lint-docs: lint-docs-manpages ifeq ($(wildcard po/Makefile),po/Makefile) doc-l10n install-l10n:: diff --git a/Documentation/RelNotes/2.45.3.txt b/Documentation/RelNotes/2.45.3.txt new file mode 100644 index 0000000000..2a1e9aa608 --- /dev/null +++ b/Documentation/RelNotes/2.45.3.txt @@ -0,0 +1,107 @@ +Git v2.45.3 Release Notes +========================= + +This primarily is to backport various small fixes accumulated on the +'master' front during the development towards Git 2.46, the next +feature release. + + +Fixes since v2.45.2 +------------------- + + * Git-GUI has a new maintainer, Johannes Sixt. + + * Tests that try to corrupt in-repository files in chunked format did + not work well on macOS due to its broken "mv", which has been + worked around. + + * The maximum size of attribute files is enforced more consistently. + + * Unbreak CI jobs so that we do not attempt to use Python 2 that has + been removed from the platform. + + * Git 2.43 started using the tree of HEAD as the source of attributes + in a bare repository, which has severe performance implications. + For now, revert the change, without ripping out a more explicit + support for the attr.tree configuration variable. + + * Windows CI running in GitHub Actions started complaining about the + order of arguments given to calloc(); the imported regex code uses + the wrong order almost consistently, which has been corrected. + + * The SubmittingPatches document now refers folks to manpages + translation project. + + * "git rebase --signoff" used to forget that it needs to add a + sign-off to the resulting commit when told to continue after a + conflict stops its operation. + + * The procedure to build multi-pack-index got confused by the + replace-refs mechanism, which has been corrected by disabling the + latter. + + * "git stash -S" did not handle binary files correctly, which has + been corrected. + + * A scheduled "git maintenance" job is expected to work on all + repositories it knows about, but it stopped at the first one that + errored out. Now it keeps going. + + * zsh can pretend to be a normal shell pretty well except for some + glitches that we tickle in some of our scripts. Work them around + so that "vimdiff" and our test suite works well enough with it. + + * Command line completion support for zsh (in contrib/) has been + updated to stop exposing internal state to end-user shell + interaction. + + * The documentation for "git diff --name-only" has been clarified + that it is about showing the names in the post-image tree. + + * The chainlint script (invoked during "make test") did nothing when + it failed to detect the number of available CPUs. It now falls + back to 1 CPU to avoid the problem. + + * "git init" in an already created directory, when the user + configuration has includeif.onbranch, started to fail recently, + which has been corrected. + + * The safe.directory configuration knob has been updated to + optionally allow leading path matches. + + * An overly large ".gitignore" files are now rejected silently. + + * Fix for an embarrassing typo that prevented Python2 tests from running + anywhere. + + * Varargs functions that are unannotated as printf-like or execl-like + have been annotated as such. + + * The "-k" and "--rfc" options of "format-patch" will now error out + when used together, as one tells us not to add anything to the + title of the commit, and the other one tells us to add "RFC" in + addition to "PATCH". + + * When the user adds to "git rebase -i" instruction to "pick" a merge + commit, the error experience is not pleasant. Such an error is now + caught earlier in the process that parses the todo list. + + * We forgot to normalize the result of getcwd() to NFC on macOS where + all other paths are normalized, which has been corrected. This still + does not address the case where core.precomposeUnicode configuration + is not defined globally. + + * Earlier we stopped using the tree of HEAD as the default source of + attributes in a bare repository, but failed to document it. This + has been corrected. + + * An unused extern declaration for mingw has been removed to prevent + it from causing build failure. + + * A helper function shared between two tests had a copy-paste bug, + which has been corrected. + + * "git fetch-pack -k -k" without passing "--lock-pack" (which we + never do ourselves) did not work at all, which has been corrected. + +Also contains various documentation updates and code clean-ups. diff --git a/Documentation/RelNotes/2.46.0.txt b/Documentation/RelNotes/2.46.0.txt index d1e4d016a6..b25475918a 100644 --- a/Documentation/RelNotes/2.46.0.txt +++ b/Documentation/RelNotes/2.46.0.txt @@ -1,10 +1,6 @@ Git v2.46 Release Notes ======================= -Backward Compatibility Notes - - (None at this moment) - UI, Workflows & Features * The "--rfc" option of "git format-patch" learned to take an @@ -61,6 +57,43 @@ UI, Workflows & Features * The promisor.quiet configuration knob can be set to true to make lazy fetching from promisor remotes silent. + * The inter/range-diff output has been moved to the end of the patch + when format-patch adds it to a single patch, instead of writing it + before the patch text, to be consistent with what is done for a + cover letter for a multi-patch series. + + * A new command has been added to migrate a repository that uses the + files backend for its ref storage to use the reftable backend, with + limitations. + + * "git diff --exit-code --ext-diff" learned to take the exit status + of the external diff driver into account when deciding the exit + status of the overall "git diff" invocation when configured to do + so. + + * "git update-ref --stdin" learned to handle transactional updates of + symbolic-refs. + + * "git format-patch --interdiff" for multi-patch series learned to + turn on cover letters automatically (unless told never to enable + cover letter with "--no-cover-letter" and such). + + * The "--heads" option of "ls-remote" and "show-ref" has been been + deprecated; "--branches" replaces "--heads". + + * For over a year, setting add.interactive.useBuiltin configuration + variable did nothing but giving a "this does not do anything" + warning. The warning has been removed. + + * The http transport can now be told to send request with + authentication material without first getting a 401 response. + + * A handful of entries are added to the GitFAQ document. + + * "git var GIT_SHELL_PATH" should report the path to the shell used + to spawn external commands, but it didn't do so on Windows, which + has been corrected. + Performance, Internal Implementation, Development Support etc. @@ -119,6 +152,86 @@ Performance, Internal Implementation, Development Support etc. * The alias-expanded command lines are logged to the trace output. + * A new test was added to ensure git commands that are designed to + run outside repositories do work. + + * A few tests in reftable library have been rewritten using the + unit test framework. + + * A pair of test helpers that essentially are unit tests on hash + algorithms have been rewritten using the unit-tests framework. + + * A test helper that essentially is unit tests on the "decorate" + logic has been rewritten using the unit-tests framework. + + * Many memory leaks in the sparse-checkout code paths have been + plugged. + + * "make check-docs" noticed problems and reported to its output but + failed to signal its findings with its exit status, which has been + corrected. + + * Building with "-Werror -Wwrite-strings" is now supported. + + * To help developers, the build procedure now allows builders to use + CFLAGS_APPEND to specify additional CFLAGS. + + * "oidtree" tests were rewritten to use the unit test framework. + + * The structure of the document that records longer-term project + decisions to deprecate/remove/update various behaviour has been + outlined. + + * The pseudo-merge reachability bitmap to help more efficient storage + of the reachability bitmap in a repository with too many refs has + been added. + + * When "git merge" sees that the index cannot be refreshed (e.g. due + to another process doing the same in the background), it died but + after writing MERGE_HEAD etc. files, which was useless for the + purpose to recover from the failure. + + * The output from "git cat-file --batch-check" and "--batch-command + (info)" should not be unbuffered, for which some tests have been + added. + + * A CPP macro USE_THE_REPOSITORY_VARIABLE is introduced to help + transition the codebase to rely less on the availability of the + singleton the_repository instance. + + * "git version --build-options" reports the version information of + OpenSSL and other libraries (if used) in the build. + + * Memory ownership rules for the in-core representation of + remote.*.url configuration values have been straightened out, which + resulted in a few leak fixes and code clarification. + + * When bundleURI interface fetches multiple bundles, Git failed to + take full advantage of all bundles and ended up slurping duplicated + objects, which has been corrected. + + * The code to deal with modified paths that are out-of-cone in a + sparsely checked out working tree has been optimized. + + * An existing test of oidmap API has been rewritten with the + unit-test framework. + + * The "ort" merge backend saw one bugfix for a crash that happens + when inner merge gets killed, and assorted code clean-ups. + + * A new warning message is issued when a command has to expand a + sparse index to handle working tree cruft that are outside of the + sparse checkout. + + * The test framework learned to take the test body not as a single + string but as a here-document. + + * "git push '' HEAD:there" used to hit a BUG(); it has been corrected + to die with "fatal: bad repository ''". + + * What happens when http.cookieFile gets the special value "" has + been clarified in the documentation. + Fixes since v2.45 ----------------- @@ -126,44 +239,36 @@ Fixes since v2.45 * "git rebase --signoff" used to forget that it needs to add a sign-off to the resulting commit when told to continue after a conflict stops its operation. - (merge a6c2654f83 pw/rebase-m-signoff-fix later to maint). * The procedure to build multi-pack-index got confused by the replace-refs mechanism, which has been corrected by disabling the latter. - (merge 93e2ae1c95 xx/disable-replace-when-building-midx later to maint). * The "-k" and "--rfc" options of "format-patch" will now error out when used together, as one tells us not to add anything to the title of the commit, and the other one tells us to add "RFC" in addition to "PATCH". - (merge cadcf58085 ds/format-patch-rfc-and-k later to maint). * "git stash -S" did not handle binary files correctly, which has been corrected. - (merge 5fb7686409 aj/stash-staged-fix later to maint). * A scheduled "git maintenance" job is expected to work on all repositories it knows about, but it stopped at the first one that errored out. Now it keeps going. - (merge c75662bfc9 js/for-each-repo-keep-going later to maint). * zsh can pretend to be a normal shell pretty well except for some glitches that we tickle in some of our scripts. Work them around so that "vimdiff" and our test suite works well enough with it. - (merge fedd5c79ff bc/zsh-compatibility later to maint). * Command line completion support for zsh (in contrib/) has been updated to stop exposing internal state to end-user shell interaction. - (merge 3c20acdf46 dk/zsh-git-repo-path-fix later to maint). * Tests that try to corrupt in-repository files in chunked format did not work well on macOS due to its broken "mv", which has been worked around. * The maximum size of attribute files is enforced more consistently. - (merge c793f9cb08 tb/attr-limits later to maint). * Unbreak CI jobs so that we do not attempt to use Python 2 that has been removed from the platform. @@ -175,7 +280,6 @@ Fixes since v2.45 * The "--exit-code" option of "git diff" command learned to work with the "--ext-diff" option. - (merge 11be65cfa4 rs/external-diff-with-exit-code later to maint). * Windows CI running in GitHub Actions started complaining about the order of arguments given to calloc(); the imported regex code uses @@ -191,7 +295,6 @@ Fixes since v2.45 * The documentation for "git diff --name-only" has been clarified that it is about showing the names in the post-image tree. - (merge 4986662cbc jc/doc-diff-name-only later to maint). * The credential helper that talks with osx keychain learned to avoid storing back the authentication material it just got received from @@ -201,7 +304,6 @@ Fixes since v2.45 * The chainlint script (invoked during "make test") did nothing when it failed to detect the number of available CPUs. It now falls back to 1 CPU to avoid the problem. - (merge 2e7e9205be es/chainlint-ncores-fix later to maint). * Revert overly aggressive "layered defence" that went into 2.45.1 and friends, which broke "git-lfs", "git-annex", and other use @@ -210,17 +312,150 @@ Fixes since v2.45 * "git init" in an already created directory, when the user configuration has includeif.onbranch, started to fail recently, which has been corrected. - (merge 407997c1dd ps/fix-reinit-includeif-onbranch later to maint). * Memory leaks in "git mv" has been plugged. + * The safe.directory configuration knob has been updated to + optionally allow leading path matches. + + * An overly large ".gitignore" files are now rejected silently. + + * Upon expiration event, the credential subsystem forgot to clear + in-core authentication material other than password (whose support + was added recently), which has been corrected. + + * Fix for an embarrassing typo that prevented Python2 tests from running + anywhere. + + * Varargs functions that are unannotated as printf-like or execl-like + have been annotated as such. + + * "git am" has a safety feature to prevent it from starting a new + session when there already is a session going. It reliably + triggers when a mbox is given on the command line, but it has to + rely on the tty-ness of the standard input. Add an explicit way to + opt out of this safety with a command line option. + (merge 62c71ace44 jk/am-retry later to maint). + + * A leak in "git imap-send" that somehow escapes LSan has been + plugged. + + * Setting core.abbrev too early before the repository set-up + (typically in "git clone") caused segfault, which as been + corrected. + + * When the user adds to "git rebase -i" instruction to "pick" a merge + commit, the error experience is not pleasant. Such an error is now + caught earlier in the process that parses the todo list. + + * We forgot to normalize the result of getcwd() to NFC on macOS where + all other paths are normalized, which has been corrected. This still + does not address the case where core.precomposeUnicode configuration + is not defined globally. + + * Earlier we stopped using the tree of HEAD as the default source of + attributes in a bare repository, but failed to document it. This + has been corrected. + + * "git update-server-info" and "git commit-graph --write" have been + updated to use the tempfile API to avoid leaving cruft after + failing. + + * An unused extern declaration for mingw has been removed to prevent + it from causing build failure. + + * A helper function shared between two tests had a copy-paste bug, + which has been corrected. + + * "git fetch-pack -k -k" without passing "--lock-pack" (which we + never do ourselves) did not work at all, which has been corrected. + + * CI job to build minimum fuzzers learned to pass NO_CURL=NoThanks to + the build procedure, as its build environment does not offer, or + the rest of the build needs, anything cURL. + (merge 4e66b5a990 jc/fuzz-sans-curl later to maint). + + * "git diff --no-ext-diff" when diff.external is configured ignored + the "--color-moved" option. + (merge 0f4b0d4cf0 rs/diff-color-moved-w-no-ext-diff-fix later to maint). + + * "git archive --add-virtual-file=<path>:<contents>" never paid + attention to the --prefix=<prefix> option but the documentation + said it would. The documentation has been corrected. + (merge 72c282098d jc/archive-prefix-with-add-virtual-file later to maint). + + * When GIT_PAGER failed to spawn, depending on the code path taken, + we failed immediately (correct) or just spew the payload to the + standard output (incorrect). The code now always fail immediately + when GIT_PAGER fails. + (merge 78f0a5d187 rj/pager-die-upon-exec-failure later to maint). + + * date parser updates to be more careful about underflowing epoch + based timestamp. + (merge 9d69789770 db/date-underflow-fix later to maint). + + * The Bloom filter used for path limited history traversal was broken + on systems whose "char" is unsigned; update the implementation and + bump the format version to 2. + (merge 9c8a9ec787 tb/path-filter-fix later to maint). + + * Typofix. + (merge 231cf7370e as/pathspec-h-typofix later to maint). + + * Code clean-up. + (merge 4b837f821e rs/simplify-submodule-helper-super-prefix-invocation later to maint). + + * "git describe --dirty --broken" forgot to refresh the index before + seeing if there is any chang, ("git describe --dirty" correctly did + so), which has been corrected. + (merge b8ae42e292 as/describe-broken-refresh-index-fix later to maint). + + * Test suite has been taught not to unnecessarily rely on DNS failing + a bogus external name. + (merge 407cdbd271 jk/tests-without-dns later to maint). + + * GitWeb update to use committer date consistently in rss/atom feeds. + (merge cf6ead095b am/gitweb-feed-use-committer-date later to maint). + + * Custom control structures we invented more recently have been + taught to the clang-format file. + (merge 1457dff9be rs/clang-format-updates later to maint). + + * Developer build procedure fix. + (merge df32729866 tb/dev-build-pedantic-fix later to maint). + + * "git push" that pushes only deletion gave an unnecessary and + harmless error message when push negotiation is configured, which + has been corrected. + (merge 4d8ee0317f jc/disable-push-nego-for-deletion later to maint). + + * Address-looking strings found on the trailer are now placed on the + Cc: list after running through sanitize_address by "git send-email". + (merge c852531f45 cb/send-email-sanitize-trailer-addresses later to maint). + + * Tests that use GIT_TEST_SANITIZE_LEAK_LOG feature got their exit + status inverted, which has been corrected. + (merge 8c1d6691bc rj/test-sanitize-leak-log-fix later to maint). + + * The http.cookieFile and http.saveCookies configuration variables + have a few values that need to be avoided, which are now ignored + with warning messages. + (merge 4f5822076f jc/http-cookiefile later to maint). + + * Repacking a repository with multi-pack index started making stupid + pack selections in Git 2.45, which has been corrected. + (merge 8fb6d11fad ds/midx-write-repack-fix later to maint). + + * Fix documentation mark-up regression in 2.45. + (merge 6474da0aa4 ja/doc-markup-updates-fix later to maint). + + * Work around asciidoctor's css that renders `monospace` material + in the SYNOPSIS section of manual pages as block elements. + (merge d44ce6ddd5 js/doc-markup-updates-fix later to maint). + * Other code cleanup, docfix, build fix, etc. - (merge a5a4cb7b27 rs/diff-parseopts-cleanup later to maint). - (merge 55702c543e fa/p4-error later to maint). - (merge 2566a77774 vd/doc-merge-tree-x-option later to maint). - (merge b64b0df9da ds/scalar-reconfigure-all-fix later to maint). - (merge c81ffcff83 dm/update-index-doc-fix later to maint). - (merge fc0202b0e9 dg/fetch-pack-code-cleanup later to maint). - (merge 7150f140f9 mt/t0211-typofix later to maint). - (merge d424488901 jc/rev-parse-fatal-doc later to maint). - (merge 36d900d2b0 rs/difftool-env-simplify later to maint). + (merge 493fdae046 ew/object-convert-leakfix later to maint). + (merge 00f3661a0a ss/doc-eol-attr-fix later to maint). + (merge 428c40da61 ri/doc-show-branch-fix later to maint). + (merge 58696bfcaa jc/where-is-bash-for-ci later to maint). + (merge 616e94ca24 tb/doc-max-tree-depth-fix later to maint). diff --git a/Documentation/RelNotes/2.47.0.txt b/Documentation/RelNotes/2.47.0.txt new file mode 100644 index 0000000000..bdac4c306a --- /dev/null +++ b/Documentation/RelNotes/2.47.0.txt @@ -0,0 +1,77 @@ +Git v2.47 Release Notes +======================= + +UI, Workflows & Features +------------------------ + + * Many Porcelain commands that internally use the merge machinery + were taught to consistently honor the diff.algorithm configuration. + + * A few descriptions in "git show-ref -h" have been clarified. + + * A 'P' command to "git add -p" that passes the patch hunk to the + pager has been added. + + * "git grep -W" omits blank lines that follow the found function at + the end of the file, just like it omits blank lines before the next + function. + + +Performance, Internal Implementation, Development Support etc. +-------------------------------------------------------------- + + * A build tweak knob has been simplified by not setting the value + that is already the default; another unused one has been removed. + + * A CI job that use clang-format to check coding style issues in new + code has been added. + + * The reviewing guidelines document now explicitly encourages people + to give positive reviews and how. + + * Test script linter has been updated to catch an attempt to use + one-shot export construct "VAR=VAL func" for shell functions (which + does not work for some shells) better. + + * Some project conventions have been added to CodingGuidelines. + + +Fixes since v2.46 +----------------- + + * "git add -p" by users with diff.suppressBlankEmpty set to true + failed to parse the patch that represents an unmodified empty line + with an empty line (not a line with a single space on it), which + has been corrected. + (merge 60cf761ed1 pw/add-patch-with-suppress-blank-empty later to maint). + + * "git checkout --ours" (no other arguments) complained that the + option is incompatible with branch switching, which is technically + correct, but found confusing by some users. It now says that the + user needs to give pathspec to specify what paths to checkout. + (merge d1e6c61272 jc/checkout-no-op-switch-errors later to maint). + + * It has been documented that we avoid "VAR=VAL shell_func" and why. + (merge 728a1962cd jc/doc-one-shot-export-with-shell-func later to maint). + + * "git rebase --help" referred to "offset" (the difference between + the location a change was taken from and the change gets replaced) + incorrectly and called it "fuzz", which has been corrected. + (merge 70058db385 jc/doc-rebase-fuzz-vs-offset-fix later to maint). + + * "git notes add -m '' --allow-empty" and friends that take prepared + data to create notes should not invoke an editor, but it started + doing so since Git 2.42, which has been corrected. + (merge 8b426c84f3 dd/notes-empty-no-edit-by-default later to maint). + + * An expensive operation to prepare tracing was done in re-encoding + code path even when the tracing was not requested, which has been + corrected. + (merge 63ad8dbf16 dh/encoding-trace-optim later to maint). + + * Other code cleanup, docfix, build fix, etc. + (merge 8db8786fc2 jt/doc-post-receive-hook-update later to maint). + (merge 1c473dd6af tn/doc-commit-fix later to maint). + (merge bb0498b1bb jc/how-to-maintain-updates later to maint). + (merge 6e71d6ac7c ks/unit-test-comment-typofix later to maint). + (merge 63ee933383 ps/p4-tests-updates later to maint). diff --git a/Documentation/ReviewingGuidelines.txt b/Documentation/ReviewingGuidelines.txt index 515d470d23..6534643cff 100644 --- a/Documentation/ReviewingGuidelines.txt +++ b/Documentation/ReviewingGuidelines.txt @@ -72,12 +72,29 @@ guidance, and concrete tips for interacting with patches on the mailing list. could fix it. This not only helps the author to understand and fix the issue, it also deepens and improves your understanding of the topic. -- Reviews do not need to exclusively point out problems. Feel free to "think out +- Reviews do not need to exclusively point out problems. Positive + reviews indicate that it is not only the original author of the + patches who care about the issue the patches address, and are + highly encouraged. + +- Do not hesitate to give positive reviews on a series from your + work colleague. If your positive review is written well, it will + not make you look as if you two are representing corporate + interest on a series that is otherwise uninteresting to other + community members and shoving it down their throat. + +- Write a positive review in such a way that others can understand + why you support the goal, the approach, and the implementation the + patches took. Make sure to demonstrate that you did thoroughly read + the series and understood problem area well enough to be able to + say that the patches are written well. Feel free to "think out loud" in your review: describe how you read & understood a complex section of a patch, ask a question about something that confused you, point out something - you found exceptionally well-written, etc. In particular, uplifting feedback - goes a long way towards encouraging contributors to participate more actively - in the Git community. + you found exceptionally well-written, etc. + +- In particular, uplifting feedback goes a long way towards + encouraging contributors to participate more actively in the Git + community. ==== Performing your review - Provide your review comments per-patch in a plaintext "Reply-All" email to the diff --git a/Documentation/config.txt b/Documentation/config.txt index 2d2d06d7ee..8c0b3ed807 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -384,6 +384,8 @@ include::config/apply.txt[] include::config/attr.txt[] +include::config/bitmap-pseudo-merge.txt[] + include::config/blame.txt[] include::config/branch.txt[] diff --git a/Documentation/config/add.txt b/Documentation/config/add.txt index e0354ceaed..4d753f006e 100644 --- a/Documentation/config/add.txt +++ b/Documentation/config/add.txt @@ -5,9 +5,3 @@ add.ignore-errors (deprecated):: option of linkgit:git-add[1]. `add.ignore-errors` is deprecated, as it does not follow the usual naming convention for configuration variables. - -add.interactive.useBuiltin:: - Unused configuration variable. Used in Git versions v2.25.0 to - v2.36.0 to enable the built-in version of linkgit:git-add[1]'s - interactive mode, which then became the default in Git - versions v2.37.0 to v2.39.0. diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt index 0e35ae5240..0ba8989820 100644 --- a/Documentation/config/advice.txt +++ b/Documentation/config/advice.txt @@ -96,6 +96,8 @@ advice.*:: `pushNonFFCurrent`, `pushNonFFMatching`, `pushAlreadyExists`, `pushFetchFirst`, `pushNeedsForce`, and `pushRefNeedsUpdate` simultaneously. + rebaseTodoError:: + Shown when there is an error after editing the rebase todo list. refSyntax:: Shown when the user provides an illegal ref name, to tell the user about the ref syntax documentation. @@ -114,6 +116,10 @@ advice.*:: skippedCherryPicks:: Shown when linkgit:git-rebase[1] skips a commit that has already been cherry-picked onto the upstream branch. + sparseIndexExpanded:: + Shown when a sparse index is expanded to a full index, which is likely + due to an unexpected set of files existing outside of the + sparse-checkout. statusAheadBehind:: Shown when linkgit:git-status[1] computes the ahead/behind counts for a local ref compared to its remote tracking ref, diff --git a/Documentation/config/attr.txt b/Documentation/config/attr.txt index 1a482d6af2..c4a5857993 100644 --- a/Documentation/config/attr.txt +++ b/Documentation/config/attr.txt @@ -1,7 +1,6 @@ attr.tree:: A reference to a tree in the repository from which to read attributes, - instead of the `.gitattributes` file in the working tree. In a bare - repository, this defaults to `HEAD:.gitattributes`. If the value does - not resolve to a valid tree object, an empty tree is used instead. + instead of the `.gitattributes` file in the working tree. If the value + does not resolve to a valid tree object, an empty tree is used instead. When the `GIT_ATTR_SOURCE` environment variable or `--attr-source` command line option are used, this configuration variable has no effect. diff --git a/Documentation/config/bitmap-pseudo-merge.txt b/Documentation/config/bitmap-pseudo-merge.txt new file mode 100644 index 0000000000..1f264eca99 --- /dev/null +++ b/Documentation/config/bitmap-pseudo-merge.txt @@ -0,0 +1,91 @@ +NOTE: The configuration options in `bitmapPseudoMerge.*` are considered +EXPERIMENTAL and may be subject to change or be removed entirely in the +future. For more information about the pseudo-merge bitmap feature, see +the "Pseudo-merge bitmaps" section of linkgit:gitpacking[7]. + +bitmapPseudoMerge.<name>.pattern:: + Regular expression used to match reference names. Commits + pointed to by references matching this pattern (and meeting + the below criteria, like `bitmapPseudoMerge.<name>.sampleRate` + and `bitmapPseudoMerge.<name>.threshold`) will be considered + for inclusion in a pseudo-merge bitmap. ++ +Commits are grouped into pseudo-merge groups based on whether or not +any reference(s) that point at a given commit match the pattern, which +is an extended regular expression. ++ +Within a pseudo-merge group, commits may be further grouped into +sub-groups based on the capture groups in the pattern. These +sub-groupings are formed from the regular expressions by concatenating +any capture groups from the regular expression, with a '-' dash in +between. ++ +For example, if the pattern is `refs/tags/`, then all tags (provided +they meet the below criteria) will be considered candidates for the +same pseudo-merge group. However, if the pattern is instead +`refs/remotes/([0-9])+/tags/`, then tags from different remotes will +be grouped into separate pseudo-merge groups, based on the remote +number. + +bitmapPseudoMerge.<name>.decay:: + Determines the rate at which consecutive pseudo-merge bitmap + groups decrease in size. Must be non-negative. This parameter + can be thought of as `k` in the function `f(n) = C * n^-k`, + where `f(n)` is the size of the `n`th group. ++ +Setting the decay rate equal to `0` will cause all groups to be the +same size. Setting the decay rate equal to `1` will cause the `n`th +group to be `1/n` the size of the initial group. Higher values of the +decay rate cause consecutive groups to shrink at an increasing rate. +The default is `1`. ++ +If all groups are the same size, it is possible that groups containing +newer commits will be able to be used less often than earlier groups, +since it is more likely that the references pointing at newer commits +will be updated more often than a reference pointing at an old commit. + +bitmapPseudoMerge.<name>.sampleRate:: + Determines the proportion of non-bitmapped commits (among + reference tips) which are selected for inclusion in an + unstable pseudo-merge bitmap. Must be between `0` and `1` + (inclusive). The default is `1`. + +bitmapPseudoMerge.<name>.threshold:: + Determines the minimum age of non-bitmapped commits (among + reference tips, as above) which are candidates for inclusion + in an unstable pseudo-merge bitmap. The default is + `1.week.ago`. + +bitmapPseudoMerge.<name>.maxMerges:: + Determines the maximum number of pseudo-merge commits among + which commits may be distributed. ++ +For pseudo-merge groups whose pattern does not contain any capture +groups, this setting is applied for all commits matching the regular +expression. For patterns that have one or more capture groups, this +setting is applied for each distinct capture group. ++ +For example, if your capture group is `refs/tags/`, then this setting +will distribute all tags into a maximum of `maxMerges` pseudo-merge +commits. However, if your capture group is, say, +`refs/remotes/([0-9]+)/tags/`, then this setting will be applied to +each remote's set of tags individually. ++ +Must be non-negative. The default value is 64. + +bitmapPseudoMerge.<name>.stableThreshold:: + Determines the minimum age of commits (among reference tips, + as above, however stable commits are still considered + candidates even when they have been covered by a bitmap) which + are candidates for a stable a pseudo-merge bitmap. The default + is `1.month.ago`. ++ +Setting this threshold to a smaller value (e.g., 1.week.ago) will cause +more stable groups to be generated (which impose a one-time generation +cost) but those groups will likely become stale over time. Using a +larger value incurs the opposite penalty (fewer stable groups which are +more useful). + +bitmapPseudoMerge.<name>.stableSize:: + Determines the size (in number of commits) of a stable + psuedo-merge bitmap. The default is `512`. diff --git a/Documentation/config/commitgraph.txt b/Documentation/config/commitgraph.txt index 30604e4a4c..7f8c9d6638 100644 --- a/Documentation/config/commitgraph.txt +++ b/Documentation/config/commitgraph.txt @@ -9,6 +9,29 @@ commitGraph.maxNewFilters:: commit-graph write` (c.f., linkgit:git-commit-graph[1]). commitGraph.readChangedPaths:: - If true, then git will use the changed-path Bloom filters in the - commit-graph file (if it exists, and they are present). Defaults to - true. See linkgit:git-commit-graph[1] for more information. + Deprecated. Equivalent to commitGraph.changedPathsVersion=-1 if true, and + commitGraph.changedPathsVersion=0 if false. (If commitGraph.changedPathVersion + is also set, commitGraph.changedPathsVersion takes precedence.) + +commitGraph.changedPathsVersion:: + Specifies the version of the changed-path Bloom filters that Git will read and + write. May be -1, 0, 1, or 2. Note that values greater than 1 may be + incompatible with older versions of Git which do not yet understand + those versions. Use caution when operating in a mixed-version + environment. ++ +Defaults to -1. ++ +If -1, Git will use the version of the changed-path Bloom filters in the +repository, defaulting to 1 if there are none. ++ +If 0, Git will not read any Bloom filters, and will write version 1 Bloom +filters when instructed to write. ++ +If 1, Git will only read version 1 Bloom filters, and will write version 1 +Bloom filters. ++ +If 2, Git will only read version 2 Bloom filters, and will write version 2 +Bloom filters. ++ +See linkgit:git-commit-graph[1] for more information. diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt index 93d65e1dfd..60ca9f2b68 100644 --- a/Documentation/config/core.txt +++ b/Documentation/config/core.txt @@ -756,4 +756,5 @@ core.maxTreeDepth:: The maximum depth Git is willing to recurse while traversing a tree (e.g., "a/b/cde/f" has a depth of 4). This is a fail-safe to allow Git to abort cleanly, and should not generally need to - be adjusted. The default is 4096. + be adjusted. When Git is compiled with MSVC, the default is 512. + Otherwise, the default is 2048. diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.txt index 5ce7b91f1d..190bda17e5 100644 --- a/Documentation/config/diff.txt +++ b/Documentation/config/diff.txt @@ -79,6 +79,15 @@ diff.external:: you want to use an external diff program only on a subset of your files, you might want to use linkgit:gitattributes[5] instead. +diff.trustExitCode:: + If this boolean value is set to true then the + `diff.external` command is expected to return exit code + 0 if it considers the input files to be equal or 1 if it + considers them to be different, like `diff(1)`. + If it is set to false, which is the default, then the command + is expected to return exit code 0 regardless of equality. + Any other exit code causes Git to report a fatal error. + diff.ignoreSubmodules:: Sets the default value of --ignore-submodules. Note that this affects only 'git diff' Porcelain, and not lower level 'diff' @@ -164,6 +173,15 @@ diff.<driver>.command:: The custom diff driver command. See linkgit:gitattributes[5] for details. +diff.<driver>.trustExitCode:: + If this boolean value is set to true then the + `diff.<driver>.command` command is expected to return exit code + 0 if it considers the input files to be equal or 1 if it + considers them to be different, like `diff(1)`. + If it is set to false, which is the default, then the command + is expected to return exit code 0 regardless of equality. + Any other exit code causes Git to report a fatal error. + diff.<driver>.xfuncname:: The regular expression that the diff driver should use to recognize the hunk header. A built-in pattern may also be used. diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt index 2d4e0c9b86..a14371b5c9 100644 --- a/Documentation/config/http.txt +++ b/Documentation/config/http.txt @@ -5,8 +5,13 @@ http.proxy:: proxy string with a user name but no password, in which case git will attempt to acquire one in the same way it does for other credentials. See linkgit:gitcredentials[7] for more information. The syntax thus is - '[protocol://][user[:password]@]proxyhost[:port]'. This can be overridden - on a per-remote basis; see remote.<name>.proxy + '[protocol://][user[:password]@]proxyhost[:port][/path]'. This can be + overridden on a per-remote basis; see remote.<name>.proxy ++ +Any proxy, however configured, must be completely transparent and must not +modify, transform, or buffer the request or response in any way. Proxies which +are not completely transparent are known to cause various forms of breakage +with Git. http.proxyAuthMethod:: Set the method with which to authenticate against the HTTP proxy. This @@ -56,6 +61,26 @@ http.emptyAuth:: a username in the URL, as libcurl normally requires a username for authentication. +http.proactiveAuth:: + Attempt authentication without first making an unauthenticated attempt and + receiving a 401 response. This can be used to ensure that all requests are + authenticated. If `http.emptyAuth` is set to true, this value has no effect. ++ +If the credential helper used specifies an authentication scheme (i.e., via the +`authtype` field), that value will be used; if a username and password is +provided without a scheme, then Basic authentication is used. The value of the +option determines the scheme requested from the helper. Possible values are: ++ +-- +* `basic` - Request Basic authentication from the helper. +* `auto` - Allow the helper to pick an appropriate scheme. +* `none` - Disable proactive authentication. +-- ++ +Note that TLS should always be used with this configuration, since otherwise it +is easy to accidentally expose plaintext credentials if Basic authentication +is selected. + http.delegation:: Control GSSAPI credential delegation. The delegation is disabled by default in libcurl since version 7.21.7. Set parameter to tell @@ -82,12 +107,16 @@ http.cookieFile:: in the Git http session, if they match the server. The file format of the file to read cookies from should be plain HTTP headers or the Netscape/Mozilla cookie file format (see `curl(1)`). + Set it to an empty string, to accept only new cookies from + the server and send them back in successive requests within same + connection. NOTE that the file specified with http.cookieFile is used only as input unless http.saveCookies is set. http.saveCookies:: If set, store cookies received during requests to the file specified by - http.cookieFile. Has no effect if http.cookieFile is unset. + http.cookieFile. Has no effect if http.cookieFile is unset, or set to + an empty string. http.version:: Use the specified HTTP protocol version when communicating with a server. diff --git a/Documentation/config/interactive.txt b/Documentation/config/interactive.txt index 5cc26555f1..8b876cb4eb 100644 --- a/Documentation/config/interactive.txt +++ b/Documentation/config/interactive.txt @@ -1,8 +1,8 @@ interactive.singleKey:: - In interactive commands, allow the user to provide one-letter - input with a single key (i.e., without hitting enter). - Currently this is used by the `--patch` mode of - linkgit:git-add[1], linkgit:git-checkout[1], + When set to true, allow the user to provide one-letter input + with a single key (i.e., without hitting the Enter key) in + interactive commands. This is currently used by the `--patch` + mode of linkgit:git-add[1], linkgit:git-checkout[1], linkgit:git-restore[1], linkgit:git-commit[1], linkgit:git-reset[1], and linkgit:git-stash[1]. diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt index 0678b4bcfe..8efc53e836 100644 --- a/Documentation/config/remote.txt +++ b/Documentation/config/remote.txt @@ -5,10 +5,19 @@ remote.pushDefault:: remote.<name>.url:: The URL of a remote repository. See linkgit:git-fetch[1] or - linkgit:git-push[1]. + linkgit:git-push[1]. A configured remote can have multiple URLs; + in this case the first is used for fetching, and all are used + for pushing (assuming no `remote.<name>.pushurl` is defined). + Setting this key to the empty string clears the list of urls, + allowing you to override earlier config. remote.<name>.pushurl:: The push URL of a remote repository. See linkgit:git-push[1]. + If a `pushurl` option is present in a configured remote, it + is used for pushing instead of `remote.<name>.url`. A configured + remote can have multiple push URLs; in this case a push goes to + all of them. Setting this key to the empty string clears the + list of urls, allowing you to override earlier config. remote.<name>.proxy:: For remotes that require curl (http, https and ftp), the URL to diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt index 577df40223..2d45c98b12 100644 --- a/Documentation/config/safe.txt +++ b/Documentation/config/safe.txt @@ -44,7 +44,8 @@ string `*`. This will allow all repositories to be treated as if their directory was listed in the `safe.directory` list. If `safe.directory=*` is set in system config and you want to re-enable this protection, then initialize your list with an empty value before listing the repositories -that you deem safe. +that you deem safe. Giving a directory with `/*` appended to it will +allow access to all repositories under the named directory. + As explained, Git only allows you to access repositories owned by yourself, i.e. the user who is running Git, by default. When Git diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index c7df20e571..cd0b81adbb 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -820,6 +820,11 @@ ifndef::git-log[] --quiet:: Disable all output of the program. Implies `--exit-code`. + Disables execution of external diff helpers whose exit code + is not trusted, i.e. their respective configuration option + `diff.trustExitCode` or `diff.<driver>.trustExitCode` or + environment variable `GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE` is + false. endif::git-log[] endif::git-format-patch[] diff --git a/Documentation/docinfo-html.in b/Documentation/docinfo-html.in new file mode 100644 index 0000000000..fb3560eb92 --- /dev/null +++ b/Documentation/docinfo-html.in @@ -0,0 +1,5 @@ +<style> +pre>code { + display: inline; +} +</style> diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index 624a6e6fe4..69d5cc9f21 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -18,7 +18,7 @@ SYNOPSIS [--quoted-cr=<action>] [--empty=(stop|drop|keep)] [(<mbox> | <Maildir>)...] -'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)] | --allow-empty) +'git am' (--continue | --skip | --abort | --quit | --retry | --show-current-patch[=(diff|raw)] | --allow-empty) DESCRIPTION ----------- @@ -208,6 +208,12 @@ Valid <action> for the `--whitespace` option are: Abort the patching operation but keep HEAD and the index untouched. +--retry:: + Try to apply the last conflicting patch again. This is generally + only useful for passing extra options to the retry attempt + (e.g., `--3way`), since otherwise you'll just see the same + failure again. + --show-current-patch[=(diff|raw)]:: Show the message at which `git am` has stopped due to conflicts. If `raw` is specified, show the raw contents of diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt index 98526f2beb..a0e3fe7996 100644 --- a/Documentation/git-archive.txt +++ b/Documentation/git-archive.txt @@ -53,7 +53,7 @@ OPTIONS --prefix=<prefix>/:: Prepend <prefix>/ to paths in the archive. Can be repeated; its rightmost value is used for all tracked files. See below which - value gets used by `--add-file` and `--add-virtual-file`. + value gets used by `--add-file`. -o <file>:: --output=<file>:: @@ -67,9 +67,7 @@ OPTIONS --add-virtual-file=<path>:<content>:: Add the specified contents to the archive. Can be repeated to add - multiple files. The path of the file in the archive is built - by concatenating the value of the last `--prefix` option (if any) - before this `--add-virtual-file` and `<path>`. + multiple files. + The `<path>` argument can start and end with a literal double-quote character; the contained file name is interpreted as a C-style string, @@ -81,6 +79,10 @@ if the path begins or ends with a double-quote character. The file mode is limited to a regular file, and the option may be subject to platform-dependent command-line limits. For non-trivial cases, write an untracked file and use `--add-file` instead. ++ +Note that unlike `--add-file` the path created in the archive is not +affected by the `--prefix` option, as a full `<path>` can be given as +the value of the option. --worktree-attributes:: Look for attributes in .gitattributes files in the working tree diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 5de18de2ab..8e925db7e9 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -13,9 +13,9 @@ SYNOPSIS [`-l`] [`-s`] [`--no-hardlinks`] [`-q`] [`-n`] [`--bare`] [`--mirror`] [`-o` _<name>_] [`-b` _<name>_] [`-u` _<upload-pack>_] [`--reference` _<repository>_] [`--dissociate`] [`--separate-git-dir` _<git-dir>_] - [`--depth` _<depth>_] [`--`[`no-`]`single-branch`] [`--no-tags`] - [++--recurse-submodules++[++=++__<pathspec>__]] [`--`[`no-`]`shallow-submodules`] - [`--`[`no-`]`remote-submodules`] [`--jobs` _<n>_] [`--sparse`] [`--`[`no-`]`reject-shallow`] + [`--depth` _<depth>_] [`--`[`no-`]{empty}`single-branch`] [`--no-tags`] + [++--recurse-submodules++[++=++__<pathspec>__]] [++--++[++no-++]{empty}++shallow-submodules++] + [`--`[`no-`]{empty}`remote-submodules`] [`--jobs` _<n>_] [`--sparse`] [`--`[`no-`]{empty}`reject-shallow`] [++--filter=++__<filter-spec>__] [`--also-filter-submodules`]] [`--`] _<repository>_ [_<directory>_] diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 89ecfc63a8..c822113c11 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git commit' [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend] - [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)] + [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>] [-F <file> | -m <msg>] [--reset-author] [--allow-empty] [--allow-empty-message] [--no-verify] [-e] [--author=<author>] [--date=<date>] [--cleanup=<mode>] [--[no-]status] diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index d08c7da8f4..58c529afbe 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -219,9 +219,9 @@ followed by the ("attr/<eolattr>"). --format=<format>:: A string that interpolates `%(fieldname)` from the result being shown. - It also interpolates `%%` to `%`, and `%xx` where `xx` are hex digits - interpolates to character with hex code `xx`; for example `%00` - interpolates to `\0` (NUL), `%09` to `\t` (TAB) and %0a to `\n` (LF). + It also interpolates `%%` to `%`, and `%xXX` where `XX` are hex digits + interpolates to character with hex code `XX`; for example `%x00` + interpolates to `\0` (NUL), `%x09` to `\t` (TAB) and %x0a to `\n` (LF). --format cannot be combined with `-s`, `-o`, `-k`, `-t`, `--resolve-undo` and `--eol`. \--:: diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt index 1c4f696ab5..76c86c3ce4 100644 --- a/Documentation/git-ls-remote.txt +++ b/Documentation/git-ls-remote.txt @@ -9,7 +9,7 @@ git-ls-remote - List references in a remote repository SYNOPSIS -------- [verse] -'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>] +'git ls-remote' [--branches] [--tags] [--refs] [--upload-pack=<exec>] [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>] [--symref] [<repository> [<patterns>...]] @@ -21,14 +21,16 @@ commit IDs. OPTIONS ------- --h:: ---heads:: +-b:: +--branches:: -t:: --tags:: - Limit to only refs/heads and refs/tags, respectively. + Limit to only local branches and local tags, respectively. These options are _not_ mutually exclusive; when given both, references stored in refs/heads and refs/tags are - displayed. Note that `git ls-remote -h` used without + displayed. Note that `--heads` and `-h` are deprecated + synonyms for `--branches` and `-b` and may be removed in + the future. Also note that `git ls-remote -h` used without anything else on the command line gives help, consistent with other git subcommands. diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 74df345f9e..b18cdbc023 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -737,7 +737,7 @@ The 'apply' backend works by creating a sequence of patches (by calling `format-patch` internally), and then applying the patches in sequence (calling `am` internally). Patches are composed of multiple hunks, each with line numbers, a context region, and the actual changes. The -line numbers have to be taken with some fuzz, since the other side +line numbers have to be taken with some offset, since the other side will likely have inserted or deleted lines earlier in the file. The context region is meant to help find how to adjust the line numbers in order to apply the changes to the right lines. However, if multiple diff --git a/Documentation/git-refs.txt b/Documentation/git-refs.txt new file mode 100644 index 0000000000..5b99e04385 --- /dev/null +++ b/Documentation/git-refs.txt @@ -0,0 +1,61 @@ +git-refs(1) +=========== + +NAME +---- +git-refs - Low-level access to refs + + +SYNOPSIS +-------- +[verse] +'git refs migrate' --ref-format=<format> [--dry-run] + +DESCRIPTION +----------- + +This command provides low-level access to refs. + +COMMANDS +-------- + +migrate:: + Migrate ref store between different formats. + +OPTIONS +------- + +The following options are specific to 'git refs migrate': + +--ref-format=<format>:: + The ref format to migrate the ref store to. Can be one of: ++ +include::ref-storage-format.txt[] + +--dry-run:: + Perform the migration, but do not modify the repository. The migrated + refs will be written into a separate directory that can be inspected + separately. The name of the directory will be reported on stdout. This + can be used to double check that the migration works as expected before + performing the actual migration. + +KNOWN LIMITATIONS +----------------- + +The ref format migration has several known limitations in its current form: + +* It is not possible to migrate repositories that have reflogs. + +* It is not possible to migrate repositories that have worktrees. + +* There is no way to block concurrent writes to the repository during an + ongoing migration. Concurrent writes can lead to an inconsistent migrated + state. Users are expected to block writes on a higher level. If your + repository is registered for scheduled maintenance, it is recommended to + unregister it first with git-maintenance(1). + +These limitations may eventually be lifted. + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt index c771c89770..bc31d8b6d3 100644 --- a/Documentation/git-show-branch.txt +++ b/Documentation/git-show-branch.txt @@ -22,7 +22,7 @@ Shows the commit ancestry graph starting from the commits named with <rev>s or <glob>s (or all refs under refs/heads and/or refs/tags) semi-visually. -It cannot show more than 29 branches and commits at a time. +It cannot show more than 26 branches and commits at a time. It uses `showbranch.default` multi-valued configuration items if no <rev> or <glob> is given on the command line. diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt index ba75747005..616d919655 100644 --- a/Documentation/git-show-ref.txt +++ b/Documentation/git-show-ref.txt @@ -9,8 +9,8 @@ SYNOPSIS -------- [verse] 'git show-ref' [--head] [-d | --dereference] - [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags] - [--heads] [--] [<pattern>...] + [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags] + [--] [<pattern>...] 'git show-ref' --verify [-q | --quiet] [-d | --dereference] [-s | --hash[=<n>]] [--abbrev[=<n>]] [--] [<ref>...] @@ -45,12 +45,14 @@ OPTIONS Show the HEAD reference, even if it would normally be filtered out. ---heads:: +--branches:: --tags:: - Limit to "refs/heads" and "refs/tags", respectively. These options + Limit to local branches and local tags, respectively. These options are not mutually exclusive; when given both, references stored in - "refs/heads" and "refs/tags" are displayed. + "refs/heads" and "refs/tags" are displayed. Note that `--heads` + is a deprecated synonym for `--branches` and may be removed + in the future. -d:: --dereference:: @@ -139,7 +141,7 @@ When using `--hash` (and not `--dereference`), the output is in the format: For example, ----------------------------------------------------------------------------- -$ git show-ref --heads --hash +$ git show-ref --branches --hash 2e3ba0114a1f52b47df29743d6915d056be13278 185008ae97960c8d551adcd9e23565194651b5d1 03adf42c988195b50e1a1935ba5fcbc39b2b029b @@ -183,8 +185,8 @@ to check whether a particular branch exists or not (notice how we don't actually want to show any results, and we want to use the full refname for it in order to not trigger the problem with ambiguous partial matches). -To show only tags, or only proper branch heads, use `--tags` and/or `--heads` -respectively (using both means that it shows tags and heads, but not other +To show only tags, or only proper branch heads, use `--tags` and/or `--branches` +respectively (using both means that it shows tags and branches, but not other random references under the refs/ subdirectory). To do automatic tag object dereferencing, use the `-d` or `--dereference` diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt index 374a2ebd2b..afcf33cf60 100644 --- a/Documentation/git-update-ref.txt +++ b/Documentation/git-update-ref.txt @@ -65,6 +65,10 @@ performs all modifications together. Specify commands of the form: create SP <ref> SP <new-oid> LF delete SP <ref> [SP <old-oid>] LF verify SP <ref> [SP <old-oid>] LF + symref-update SP <ref> SP <new-target> [SP (ref SP <old-target> | oid SP <old-oid>)] LF + symref-create SP <ref> SP <new-target> LF + symref-delete SP <ref> [SP <old-target>] LF + symref-verify SP <ref> [SP <old-target>] LF option SP <opt> LF start LF prepare LF @@ -86,6 +90,10 @@ quoting: create SP <ref> NUL <new-oid> NUL delete SP <ref> NUL [<old-oid>] NUL verify SP <ref> NUL [<old-oid>] NUL + symref-update SP <ref> NUL <new-target> [NUL (ref NUL <old-target> | oid NUL <old-oid>)] NUL + symref-create SP <ref> NUL <new-target> NUL + symref-delete SP <ref> [NUL <old-target>] NUL + symref-verify SP <ref> [NUL <old-target>] NUL option SP <opt> NUL start NUL prepare NUL @@ -113,10 +121,27 @@ delete:: Delete <ref> after verifying it exists with <old-oid>, if given. If given, <old-oid> may not be zero. +symref-update:: + Set <ref> to <new-target> after verifying <old-target> or <old-oid>, + if given. Specify a zero <old-oid> to ensure that the ref does not + exist before the update. + verify:: Verify <ref> against <old-oid> but do not change it. If <old-oid> is zero or missing, the ref must not exist. +symref-create: + Create symbolic ref <ref> with <new-target> after verifying + it does not exist. + +symref-delete:: + Delete <ref> after verifying it exists with <old-target>, if given. + +symref-verify:: + Verify symbolic <ref> against <old-target> but do not change it. + If <old-target> is missing, the ref must not exist. Can only be + used in `no-deref` mode. + option:: Modify the behavior of the next command naming a <ref>. The only valid option is `no-deref` to avoid dereferencing diff --git a/Documentation/git.txt b/Documentation/git.txt index a31a70acca..4489e2297a 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -644,6 +644,16 @@ parameter, <path>. For each path `GIT_EXTERNAL_DIFF` is called, two environment variables, `GIT_DIFF_PATH_COUNTER` and `GIT_DIFF_PATH_TOTAL` are set. +`GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE`:: + If this Boolean environment variable is set to true then the + `GIT_EXTERNAL_DIFF` command is expected to return exit code + 0 if it considers the input files to be equal or 1 if it + considers them to be different, like `diff(1)`. + If it is set to false, which is the default, then the command + is expected to return exit code 0 regardless of equality. + Any other exit code causes Git to report a fatal error. + + `GIT_DIFF_PATH_COUNTER`:: A 1-based counter incremented by one for every path. diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 4338d023d9..e6150595af 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -374,7 +374,7 @@ explicitly define the line endings with `eol` if the `working-tree-encoding` attribute is used to avoid ambiguity. ------------------------ -*.ps1 text working-tree-encoding=UTF-16LE eol=CRLF +*.ps1 text working-tree-encoding=UTF-16LE eol=crlf ------------------------ You can get a list of all available encodings on your platform with the @@ -776,6 +776,11 @@ with the above configuration, i.e. `j-c-diff`, with 7 parameters, just like `GIT_EXTERNAL_DIFF` program is called. See linkgit:git[1] for details. +If the program is able to ignore certain changes (similar to +`git diff --ignore-space-change`), then also set the option +`trustExitCode` to true. It is then expected to return exit code 1 if +it finds significant changes and 0 if it doesn't. + Setting the internal diff algorithm ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt index 8c1f2d5675..f2917d142c 100644 --- a/Documentation/gitfaq.txt +++ b/Documentation/gitfaq.txt @@ -185,6 +185,58 @@ Then, you can adjust your push URL to use `git@example_author` or `git@example_committer` instead of `git@example.org` (e.g., `git remote set-url git@example_author:org1/project1.git`). +Transfers +--------- + +[[sync-working-tree]] +How do I sync a working tree across systems?:: + First, decide whether you want to do this at all. Git works best when you + push or pull your work using the typical `git push` and `git fetch` commands + and isn't designed to share a working tree across systems. This is + potentially risky and in some cases can cause repository corruption or data + loss. ++ +Usually, doing so will cause `git status` to need to re-read every file in the +working tree. Additionally, Git's security model does not permit sharing a +working tree across untrusted users, so it is only safe to sync a working tree +if it will only be used by a single user across all machines. ++ +It is important not to use a cloud syncing service to sync any portion of a Git +repository, since this can cause corruption, such as missing objects, changed +or added files, broken refs, and a wide variety of other problems. These +services tend to sync file by file on a continuous basis and don't understand +the structure of a Git repository. This is especially bad if they sync the +repository in the middle of it being updated, since that is very likely to +cause incomplete or partial updates and therefore data loss. ++ +An example of the kind of corruption that can occur is conflicts over the state +of refs, such that both sides end up with different commits on a branch that +the other doesn't have. This can result in important objects becoming +unreferenced and possibly pruned by `git gc`, causing data loss. ++ +Therefore, it's better to push your work to either the other system or a central +server using the normal push and pull mechanism. However, this doesn't always +preserve important data, like stashes, so some people prefer to share a working +tree across systems. ++ +If you do this, the recommended approach is to use `rsync -a --delete-after` +(ideally with an encrypted connection such as with `ssh`) on the root of +repository. You should ensure several things when you do this: ++ +* If you have additional worktrees or a separate Git directory, they must be + synced at the same time as the main working tree and repository. +* You are comfortable with the destination directory being an exact copy of the + source directory, _deleting any data that is already there_. +* The repository (including all worktrees and the Git directory) is in a + quiescent state for the duration of the transfer (that is, no operations of + any sort are taking place on it, including background operations like `git + gc` and operations invoked by your editor). ++ +Be aware that even with these recommendations, syncing in this way has some risk +since it bypasses Git's normal integrity checking for repositories, so having +backups is advised. You may also wish to do a `git fsck` to verify the +integrity of your data on the destination system after syncing. + Common Issues ------------- @@ -241,6 +293,42 @@ How do I know if I want to do a fetch or a pull?:: ignore the upstream changes. A pull consists of a fetch followed immediately by either a merge or rebase. See linkgit:git-pull[1]. +[[proxy]] +Can I use a proxy with Git?:: + Yes, Git supports the use of proxies. Git honors the standard `http_proxy`, + `https_proxy`, and `no_proxy` environment variables commonly used on Unix, and + it also can be configured with `http.proxy` and similar options for HTTPS (see + linkgit:git-config[1]). The `http.proxy` and related options can be + customized on a per-URL pattern basis. In addition, Git can in theory + function normally with transparent proxies that exist on the network. ++ +For SSH, Git can support a proxy using OpenSSH's `ProxyCommand`. Commonly used +tools include `netcat` and `socat`. However, they must be configured not to +exit when seeing EOF on standard input, which usually means that `netcat` will +require `-q` and `socat` will require a timeout with something like `-t 10`. +This is required because the way the Git SSH server knows that no more requests +will be made is an EOF on standard input, but when that happens, the server may +not have yet processed the final request, so dropping the connection at that +point would interrupt that request. ++ +An example configuration entry in `~/.ssh/config` with an HTTP proxy might look +like this: ++ +---- +Host git.example.org + User git + ProxyCommand socat -t 10 - PROXY:proxy.example.org:%h:%p,proxyport=8080 +---- ++ +Note that in all cases, for Git to work properly, the proxy must be completely +transparent. The proxy cannot modify, tamper with, or buffer the connection in +any way, or Git will almost certainly fail to work. Note that many proxies, +including many TLS middleboxes, Windows antivirus and firewall programs other +than Windows Defender and Windows Firewall, and filtering proxies fail to meet +this standard, and as a result end up breaking Git. Because of the many +reports of problems and their poor security history, we recommend against the +use of these classes of software and devices. + Merging and Rebasing -------------------- @@ -357,8 +445,9 @@ I'm on Windows and git diff shows my files as having a `^M` at the end.:: + You can store the files in the repository with Unix line endings and convert them automatically to your platform's line endings. To do that, set the -configuration option `core.eol` to `native` and see the following entry for -information about how to configure files as text or binary. +configuration option `core.eol` to `native` and see +<<recommended-storage-settings,the question on recommended storage settings>> +for information about how to configure files as text or binary. + You can also control this behavior with the `core.whitespace` setting if you don't wish to remove the carriage returns from your line endings. @@ -420,14 +509,26 @@ references, URLs, and hashes stored in the repository. + We also recommend setting a linkgit:gitattributes[5] file to explicitly mark which files are text and which are binary. If you want Git to guess, you can -set the attribute `text=auto`. For example, the following might be appropriate -in some projects: +set the attribute `text=auto`. ++ +With text files, Git will generally ensure that LF endings are used in the +repository. The `core.autocrlf` and `core.eol` configuration variables specify +what line-ending convention is followed when any text file is checked out. You +can also use the `eol` attribute (e.g., `eol=crlf`) to override which files get +what line-ending treatment. ++ +For example, generally shell files must have LF endings and batch files must +have CRLF endings, so the following might be appropriate in some projects: + ---- # By default, guess. * text=auto # Mark all C files as text. *.c text +# Ensure all shell files have LF endings and all batch files have CRLF +# endings in the working tree and both have LF in the repo. +*.sh text eol=lf +*.bat text eol=crlf # Mark all JPEG files as binary. *.jpg binary ---- diff --git a/Documentation/gitformat-commit-graph.txt b/Documentation/gitformat-commit-graph.txt index 31cad585e2..3e906e8030 100644 --- a/Documentation/gitformat-commit-graph.txt +++ b/Documentation/gitformat-commit-graph.txt @@ -142,13 +142,16 @@ All multi-byte numbers are in network byte order. ==== Bloom Filter Data (ID: {'B', 'D', 'A', 'T'}) [Optional] * It starts with header consisting of three unsigned 32-bit integers: - - Version of the hash algorithm being used. We currently only support - value 1 which corresponds to the 32-bit version of the murmur3 hash + - Version of the hash algorithm being used. We currently support + value 2 which corresponds to the 32-bit version of the murmur3 hash implemented exactly as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm and the double hashing technique using seed values 0x293ae76f and 0x7e646e2 as described in https://doi.org/10.1007/978-3-540-30494-4_26 "Bloom Filters - in Probabilistic Verification" + in Probabilistic Verification". Version 1 Bloom filters have a bug that appears + when char is signed and the repository has path names that have characters >= + 0x80; Git supports reading and writing them, but this ability will be removed + in a future version of Git. - The number of times a path is hashed and hence the number of bit positions that cumulatively determine whether a file is present in the commit. - The minimum number of bits 'b' per entry in the Bloom filter. If the filter diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index 06e997131b..0397dec64d 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -415,13 +415,13 @@ post-receive This hook is invoked by linkgit:git-receive-pack[1] when it reacts to `git push` and updates reference(s) in its repository. -It executes on the remote repository once after all the refs have -been updated. +The hook executes on the remote repository once after all the proposed +ref updates are processed and if at least one ref is updated as the +result. -This hook executes once for the receive operation. It takes no -arguments, but gets the same information as the -<<pre-receive,'pre-receive'>> -hook does on its standard input. +The hook takes no arguments. It receives one line on standard input for +each ref that is successfully updated following the same format as the +<<pre-receive,'pre-receive'>> hook. This hook does not affect the outcome of `git receive-pack`, as it is called after the real work is done. @@ -448,6 +448,9 @@ environment variables will not be set. If the client selects to use push options, but doesn't transmit any, the count variable will be set to zero, `GIT_PUSH_OPTION_COUNT=0`. +See the "post-receive" section in linkgit:git-receive-pack[1] for +additional details. + [[post-update]] post-update ~~~~~~~~~~~ diff --git a/Documentation/gitpacking.txt b/Documentation/gitpacking.txt new file mode 100644 index 0000000000..321154d4e6 --- /dev/null +++ b/Documentation/gitpacking.txt @@ -0,0 +1,195 @@ +gitpacking(7) +============= + +NAME +---- +gitpacking - Advanced concepts related to packing in Git + +SYNOPSIS +-------- +gitpacking + +DESCRIPTION +----------- + +This document aims to describe some advanced concepts related to packing +in Git. + +Many concepts are currently described scattered between manual pages of +various Git commands, including linkgit:git-pack-objects[1], +linkgit:git-repack[1], and others, as well as linkgit:gitformat-pack[5], +and parts of the `Documentation/technical` tree. + +There are many aspects of packing in Git that are not covered in this +document that instead live in the aforementioned areas. Over time, those +scattered bits may coalesce into this document. + +== Pseudo-merge bitmaps + +NOTE: Pseudo-merge bitmaps are considered an experimental feature, so +the configuration and many of the ideas are subject to change. + +=== Background + +Reachability bitmaps are most efficient when we have on-disk stored +bitmaps for one or more of the starting points of a traversal. For this +reason, Git prefers storing bitmaps for commits at the tips of refs, +because traversals tend to start with those points. + +But if you have a large number of refs, it's not feasible to store a +bitmap for _every_ ref tip. It takes up space, and just OR-ing all of +those bitmaps together is expensive. + +One way we can deal with that is to create bitmaps that represent +_groups_ of refs. When a traversal asks about the entire group, then we +can use this single bitmap instead of considering each ref individually. +Because these bitmaps represent the set of objects which would be +reachable in a hypothetical merge of all of the commits, we call them +pseudo-merge bitmaps. + +=== Overview + +A "pseudo-merge bitmap" is used to refer to a pair of bitmaps, as +follows: + +Commit bitmap:: + + A bitmap whose set bits describe the set of commits included in the + pseudo-merge's "merge" bitmap (as below). + +Merge bitmap:: + + A bitmap whose set bits describe the reachability closure over the set + of commits in the pseudo-merge's "commits" bitmap (as above). An + identical bitmap would be generated for an octopus merge with the same + set of parents as described in the commits bitmap. + +Pseudo-merge bitmaps can accelerate bitmap traversals when all commits +for a given pseudo-merge are listed on either side of the traversal, +either directly (by explicitly asking for them as part of the `HAVES` +or `WANTS`) or indirectly (by encountering them during a fill-in +traversal). + +=== Use-cases + +For example, suppose there exists a pseudo-merge bitmap with a large +number of commits, all of which are listed in the `WANTS` section of +some bitmap traversal query. When pseudo-merge bitmaps are enabled, the +bitmap machinery can quickly determine there is a pseudo-merge which +satisfies some subset of the wanted objects on either side of the query. +Then, we can inflate the EWAH-compressed bitmap, and `OR` it in to the +resulting bitmap. By contrast, without pseudo-merge bitmaps, we would +have to repeat the decompression and `OR`-ing step over a potentially +large number of individual bitmaps, which can take proportionally more +time. + +Another benefit of pseudo-merges arises when there is some combination +of (a) a large number of references, with (b) poor bitmap coverage, and +(c) deep, nested trees, making fill-in traversal relatively expensive. +For example, suppose that there are a large enough number of tags where +bitmapping each of the tags individually is infeasible. Without +pseudo-merge bitmaps, computing the result of, say, `git rev-list +--use-bitmap-index --count --objects --tags` would likely require a +large amount of fill-in traversal. But when a large quantity of those +tags are stored together in a pseudo-merge bitmap, the bitmap machinery +can take advantage of the fact that we only care about the union of +objects reachable from all of those tags, and answer the query much +faster. + +=== Configuration + +Reference tips are grouped into different pseudo-merge groups according +to two criteria. A reference name matches one or more of the defined +pseudo-merge patterns, and optionally one or more capture groups within +that pattern which further partition the group. + +Within a group, commits may be considered "stable", or "unstable" +depending on their age. These are adjusted by setting the +`bitmapPseudoMerge.<name>.stableThreshold` and +`bitmapPseudoMerge.<name>.threshold` configuration values, respectively. + +All stable commits are grouped into pseudo-merges of equal size +(`bitmapPseudoMerge.<name>.stableSize`). If the `stableSize` +configuration is set to, say, 100, then the first 100 commits (ordered +by committer date) which are older than the `stableThreshold` value will +form one group, the next 100 commits will form another group, and so on. + +Among unstable commits, the pseudo-merge machinery will attempt to +combine older commits into large groups as opposed to newer commits +which will appear in smaller groups. This is based on the heuristic that +references whose tip commit is older are less likely to be modified to +point at a different commit than a reference whose tip commit is newer. + +The size of groups is determined by a power-law decay function, and the +decay parameter roughly corresponds to "k" in `f(n) = C*n^(-k/100)`, +where `f(n)` describes the size of the `n`-th pseudo-merge group. The +sample rate controls what percentage of eligible commits are considered +as candidates. The threshold parameter indicates the minimum age (so as +to avoid including too-recent commits in a pseudo-merge group, making it +less likely to be valid). The "maxMerges" parameter sets an upper-bound +on the number of pseudo-merge commits an individual group + +The "stable"-related parameters control "stable" pseudo-merge groups, +comprised of a fixed number of commits which are older than the +configured "stable threshold" value and may be grouped together in +chunks of "stableSize" in order of age. + +The exact configuration for pseudo-merges is as follows: + +include::config/bitmap-pseudo-merge.txt[] + +=== Examples + +Suppose that you have a repository with a large number of references, +and you want a bare-bones configuration of pseudo-merge bitmaps that +will enhance bitmap coverage of the `refs/` namespace. You may start +with a configuration like so: + +---- +[bitmapPseudoMerge "all"] + pattern = "refs/" + threshold = now + stableThreshold = never + sampleRate = 100 + maxMerges = 64 +---- + +This will create pseudo-merge bitmaps for all references, regardless of +their age, and group them into 64 pseudo-merge commits. + +If you wanted to separate tags from branches when generating +pseudo-merge commits, you would instead define the pattern with a +capture group, like so: + +---- +[bitmapPseudoMerge "all"] + pattern = "refs/(heads/tags)/" +---- + +Suppose instead that you are working in a fork-network repository, with +each fork specified by some numeric ID, and whose refs reside in +`refs/virtual/NNN/` (where `NNN` is the numeric ID corresponding to some +fork) in the network. In this instance, you may instead write something +like: + +---- +[bitmapPseudoMerge "all"] + pattern = "refs/virtual/([0-9]+)/(heads|tags)/" + threshold = now + stableThreshold = never + sampleRate = 100 + maxMerges = 64 +---- + +Which would generate pseudo-merge group identifiers like "1234-heads", +and "5678-tags" (for branches in fork "1234", and tags in remote "5678", +respectively). + +SEE ALSO +-------- +linkgit:git-pack-objects[1] +linkgit:git-repack[1] + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index 30b394ab47..42afe04869 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -550,7 +550,7 @@ The following pseudorefs are known to Git: to the result. [[def_ref]]ref:: - A name that that points to an <<def_object_name,object name>> or + A name that points to an <<def_object_name,object name>> or another ref (the latter is called a <<def_symref,symbolic ref>>). For convenience, a ref can sometimes be abbreviated when used as an argument to a Git command; see linkgit:gitrevisions[7] diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt index 013014bbef..41f54050f8 100644 --- a/Documentation/howto/maintain-git.txt +++ b/Documentation/howto/maintain-git.txt @@ -37,22 +37,20 @@ The Policy The policy on Integration is informally mentioned in "A Note from the maintainer" message, which is periodically posted to -this mailing list after each feature release is made. +the mailing list after each feature release is made: - Feature releases are numbered as vX.Y.0 and are meant to contain bugfixes and enhancements in any area, including functionality, performance and usability, without regression. - - One release cycle for a feature release is expected to last for - eight to ten weeks. - - - Maintenance releases are numbered as vX.Y.Z and are meant + - Maintenance releases are numbered as vX.Y.Z (0 < Z) and are meant to contain only bugfixes for the corresponding vX.Y.0 feature release and earlier maintenance releases vX.Y.W (W < Z). - - 'master' branch is used to prepare for the next feature + - The 'master' branch is used to prepare for the next feature release. In other words, at some point, the tip of 'master' - branch is tagged with vX.Y.0. + branch is tagged as vX.(Y+1).0, when vX.Y.0 is the latest + feature release. - 'maint' branch is used to prepare for the next maintenance release. After the feature release vX.Y.0 is made, the tip @@ -63,11 +61,13 @@ this mailing list after each feature release is made. - 'next' branch is used to publish changes (both enhancements and fixes) that (1) have worthwhile goal, (2) are in a fairly good shape suitable for everyday use, (3) but have not yet - demonstrated to be regression free. New changes are tested - in 'next' before merged to 'master'. + demonstrated to be regression free. Reviews from contributors on + the mailing list help to make the determination. After a topic + is merged to 'next', it is tested for at least 7 calendar days + before getting merged to 'master'. - 'seen' branch is used to publish other proposed changes that do - not yet pass the criteria set for 'next'. + not yet pass the criteria set for 'next' (see above). - The tips of 'master' and 'maint' branches will not be rewound to allow people to build their own customization on top of them. @@ -86,6 +86,38 @@ this mailing list after each feature release is made. users are encouraged to test it so that regressions and bugs are found before new topics are merged to 'master'. + - When a problem is found in a topic in 'next', the topic is marked + not to be merged to 'master'. Follow-up patches are discussed on + the mailing list and applied to the topic after being reviewed and + then the topic is merged (again) to 'next'. After going through + the usual testing in 'next', the entire (fixed) topic is merged + to 'master'. + + - One release cycle for a feature release is expected to last for + eight to ten weeks. A few "release candidate" releases are + expected to be tagged about a week apart before the final + release, and a "preview" release is tagged about a week before + the first release candidate gets tagged. + + - After the preview release is tagged, topics that were well + reviewed may be merged to 'master' before spending the usual 7 + calendar days in 'next', with the expectation that any bugs in + them can be caught and fixed in the release candidates before + the final release. + + - After the first release candidate is tagged, the contributors are + strongly encouraged to focus on finding and fixing new regressions + introduced during the cycle, over addressing old bugs and any new + features. Topics stop getting merged down from 'next' to 'master', + and new topics stop getting merged to 'next'. Unless they are fixes + to new regressions in the cycle, that is. + + - Soon after a feature release is made, the tip of 'maint' gets + fast-forwarded to point at the release. Topics that have been + kept in 'next' are merged down to 'master' and a new development + cycle starts. + + Note that before v1.9.0 release, the version numbers used to be structured slightly differently. vX.Y.Z were feature releases while vX.Y.Z.W were maintenance releases for vX.Y.Z. @@ -179,12 +211,12 @@ by doing the following: The initial round is done with: $ git checkout ai/topic ;# or "git checkout -b ai/topic master" - $ git am -sc3 mailbox + $ git am -sc3 --whitespace=warn mailbox and replacing an existing topic with subsequent round is done with: $ git checkout master...ai/topic ;# try to reapply to the same base - $ git am -sc3 mailbox + $ git am -sc3 --whitespace=warn mailbox to prepare the new round on a detached HEAD, and then @@ -209,39 +241,59 @@ by doing the following: (trivial typofixes etc. are often squashed directly into the patches that need fixing, without being applied as a separate "SQUASH???" commit), so that they can be removed easily as needed. + The expectation is that the original author will make corrections + in a reroll. + - By now, new topic branches are created and existing topic + branches are updated. The integration branches 'next', 'jch', + and 'seen' need to be updated to contain them. - - Merge maint to master as needed: + - If there are topics that have been merged to 'master' and should + be merged to 'maint', merge them to 'maint', and update the + release notes to the next maintenance release. - $ git checkout master - $ git merge maint - $ make test + - Review the latest issue of "What's cooking" again. Are topics + that have been sufficiently long in 'next' ready to be merged to + 'master'? Are topics we saw earlier and are in 'seen' now got + positive reviews and are ready to be merged to 'next'? - - Merge master to next as needed: + - If there are topics that have been cooking in 'next' long enough + and should be merged to 'master', merge them to 'master', and + update the release notes to the next feature release. - $ git checkout next - $ git merge master - $ make test + - If there were patches directly made on 'maint', merge 'maint' to + 'master'; make sure that the result is what you want. - - Review the last issue of "What's cooking" again and see if topics - that are ready to be merged to 'next' are still in good shape - (e.g. has there any new issue identified on the list with the - series?) + $ git checkout master + $ git merge -m "Sync with 'maint'" --no-log maint + $ git log -p --first-parent ORIG_HEAD.. + $ make test - - Prepare 'jch' branch, which is used to represent somewhere - between 'master' and 'seen' and often is slightly ahead of 'next'. + - Prepare to update the 'jch' branch, which is used to represent + somewhere between 'master' and 'seen' and often is slightly ahead + of 'next', and the 'seen' branch, which is used to hold the rest. $ Meta/Reintegrate master..jch >Meta/redo-jch.sh The result is a script that lists topics to be merged in order to - rebuild 'seen' as the input to Meta/Reintegrate script. Remove - later topics that should not be in 'jch' yet. Add a line that - consists of '### match next' before the name of the first topic - in the output that should be in 'jch' but not in 'next' yet. + rebuild the current 'jch'. Do the same for 'seen'. + + - Review the Meta/redo-jch.sh and Meta/redo-seen.sh scripts. The + former should have a line '### match next'---the idea is that + merging the topics listed before the line on top of 'master' + should result in a tree identical to that of 'next'. - - Now we are ready to start merging topics to 'next'. For each - branch whose tip is not merged to 'next', one of three things can - happen: + - As newly created topics are usually merged near the tip of + 'seen', add them to the end of the Meta/redo-seen.sh script. + Among the topics that were in 'seen', there may be ones that + are not quite ready for 'next' but are getting there. Move + them from Meta/redo-seen.sh to the end of Meta/redo-jch.sh. + The expectation is that you'd use 'jch' as your daily driver + as the first guinea pig, so you should choose carefully. + + - Now we are ready to start rebuilding 'jch' and merging topics to + 'next'. For each branch whose tip is not merged to 'next', one + of three things can happen: - The commits are all next-worthy; merge the topic to next; - The new parts are of mixed quality, but earlier ones are @@ -252,10 +304,12 @@ by doing the following: If a topic that was already in 'next' gained a patch, the script would list it as "ai/topic~1". To include the new patch to the updated 'next', drop the "~1" part; to keep it excluded, do not - touch the line. If a topic that was not in 'next' should be - merged to 'next', add it at the end of the list. Then: + touch the line. + + If a topic that was not in 'next' should be merged to 'next', add + it before the '### match next' line. Then: - $ git checkout -B jch master + $ git checkout --detach master $ sh Meta/redo-jch.sh -c1 to rebuild the 'jch' branch from scratch. "-c1" tells the script @@ -267,26 +321,29 @@ by doing the following: reference to the variable under its old name), in which case prepare an appropriate merge-fix first (see appendix), and rebuild the 'jch' branch from scratch, starting at the tip of - 'master'. + 'master', this time without using "-c1" to merge all topics. - Then do the same to 'next' + Then do the same to 'next'. $ git checkout next $ sh Meta/redo-jch.sh -c1 -e The "-e" option allows the merge message that comes from the history of the topic and the comments in the "What's cooking" to - be edited. The resulting tree should match 'jch' as the same set - of topics are merged on 'master'; otherwise there is a mismerge. - Investigate why and do not proceed until the mismerge is found - and rectified. + be edited. The resulting tree should match 'jch^{/^### match next'}' + as the same set of topics are merged on 'master'; otherwise there + is a mismerge. Investigate why and do not proceed until the mismerge + is found and rectified. + + If 'master' was updated before you started redoing 'next', then - $ git diff jch next + $ git diff 'jch^{/^### match next}' next - Then build the rest of 'jch': + would show differences that went into 'master' (which 'jch' has, + but 'next' does not yet---often it is updates to the release + notes). Merge 'master' back to 'next' if that is the case. - $ git checkout jch - $ sh Meta/redo-jch.sh + $ git merge -m "Sync with 'master'" --no-log master When all is well, clean up the redo-jch.sh script with @@ -296,12 +353,7 @@ by doing the following: merged to 'master'. This may lose '### match next' marker; add it again to the appropriate place when it happens. - - Rebuild 'seen'. - - $ Meta/Reintegrate jch..seen >Meta/redo-seen.sh - - Edit the result by adding new topics that are not still in 'seen' - in the script. Then + - Rebuild 'seen' on top of 'jch'. $ git checkout -B seen jch $ sh Meta/redo-seen.sh @@ -312,7 +364,7 @@ by doing the following: Double check by running - $ git branch --no-merged seen + $ git branch --no-merged seen '??/*' to see there is no unexpected leftover topics. diff --git a/Documentation/lint-manpages.sh b/Documentation/lint-manpages.sh new file mode 100755 index 0000000000..92cfc0a15a --- /dev/null +++ b/Documentation/lint-manpages.sh @@ -0,0 +1,108 @@ +#!/bin/sh + +extract_variable () { + ( + cat ../Makefile + cat <<EOF +print_variable: + @\$(foreach b,\$($1),echo XXX \$(b:\$X=) YYY;) +EOF + ) | + make -C .. -f - print_variable 2>/dev/null | + sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p' +} + +check_missing_docs () ( + ret=0 + + for v in $ALL_COMMANDS + do + case "$v" in + git-merge-octopus) continue;; + git-merge-ours) continue;; + git-merge-recursive) continue;; + git-merge-resolve) continue;; + git-merge-subtree) continue;; + git-fsck-objects) continue;; + git-init-db) continue;; + git-remote-*) continue;; + git-stage) continue;; + git-legacy-*) continue;; + git-?*--?* ) continue ;; + esac + + if ! test -f "$v.txt" + then + echo "no doc: $v" + ret=1 + fi + + if ! sed -e '1,/^### command list/d' -e '/^#/d' ../command-list.txt | + grep -q "^$v[ ]" + then + case "$v" in + git) + ;; + *) + echo "no link: $v" + ret=1 + ;; + esac + fi + done + + exit $ret +) + +check_extraneous_docs () { + ( + sed -e '1,/^### command list/d' \ + -e '/^#/d' \ + -e '/guide$/d' \ + -e '/interfaces$/d' \ + -e 's/[ ].*//' \ + -e 's/^/listed /' ../command-list.txt + make print-man1 | + grep '\.txt$' | + sed -e 's|^|documented |' \ + -e 's/\.txt//' + ) | ( + all_commands="$(printf "%s " "$ALL_COMMANDS" "$BUILT_INS" "$EXCLUDED_PROGRAMS" | tr '\n' ' ')" + ret=0 + + while read how cmd + do + case " $all_commands " in + *" $cmd "*) ;; + *) + echo "removed but $how: $cmd" + ret=1;; + esac + done + + exit $ret + ) +} + +BUILT_INS="$(extract_variable BUILT_INS)" +ALL_COMMANDS="$(extract_variable ALL_COMMANDS)" +EXCLUDED_PROGRAMS="$(extract_variable EXCLUDED_PROGRAMS)" + +findings=$( + if ! check_missing_docs + then + ret=1 + fi + + if ! check_extraneous_docs + then + ret=1 + fi + + exit $ret +) +ret=$? + +printf "%s" "$findings" | sort + +exit $ret diff --git a/Documentation/technical/bitmap-format.txt b/Documentation/technical/bitmap-format.txt index f5d200939b..bfb0ec7beb 100644 --- a/Documentation/technical/bitmap-format.txt +++ b/Documentation/technical/bitmap-format.txt @@ -255,3 +255,144 @@ triplet is - xor_row (4 byte integer, network byte order): :: The position of the triplet whose bitmap is used to compress this one, or `0xffffffff` if no such bitmap exists. + +Pseudo-merge bitmaps +-------------------- + +If the `BITMAP_OPT_PSEUDO_MERGES` flag is set, a variable number of +bytes (preceding the name-hash cache, commit lookup table, and trailing +checksum) of the `.bitmap` file is used to store pseudo-merge bitmaps. + +For more information on what pseudo-merges are, why they are useful, and +how to configure them, see the information in linkgit:gitpacking[7]. + +=== File format + +If enabled, pseudo-merge bitmaps are stored in an optional section at +the end of a `.bitmap` file. The format is as follows: + +.... ++-------------------------------------------+ +| .bitmap File | ++-------------------------------------------+ +| | +| Pseudo-merge bitmaps (Variable Length) | +| +---------------------------+ | +| | commits_bitmap (EWAH) | | +| +---------------------------+ | +| | merge_bitmap (EWAH) | | +| +---------------------------+ | +| | ++-------------------------------------------+ +| | +| Lookup Table | +| +---------------------------+ | +| | commit_pos (4 bytes) | | +| +---------------------------+ | +| | offset (8 bytes) | | +| +------------+--------------+ | +| | +| Offset Cases: | +| ------------- | +| | +| 1. MSB Unset: single pseudo-merge bitmap | +| + offset to pseudo-merge bitmap | +| | +| 2. MSB Set: multiple pseudo-merges | +| + offset to extended lookup table | +| | ++-------------------------------------------+ +| | +| Extended Lookup Table (Optional) | +| +----+----------+----------+----------+ | +| | N | Offset 1 | .... | Offset N | | +| +----+----------+----------+----------+ | +| | | 8 bytes | .... | 8 bytes | | +| +----+----------+----------+----------+ | +| | ++-------------------------------------------+ +| | +| Pseudo-merge position table | +| +----+----------+----------+----------+ | +| | N | Offset 1 | .... | Offset N | | +| +----+----------+----------+----------+ | +| | | 8 bytes | .... | 8 bytes | | +| +----+----------+----------+----------+ | +| | ++-------------------------------------------+ +| | +| Pseudo-merge Metadata | +| +-----------------------------------+ | +| | # pseudo-merges (4 bytes) | | +| +-----------------------------------+ | +| | # commits (4 bytes) | | +| +-----------------------------------+ | +| | Lookup offset (8 bytes) | | +| +-----------------------------------+ | +| | Extension size (8 bytes) | | +| +-----------------------------------+ | +| | ++-------------------------------------------+ +.... + +* One or more pseudo-merge bitmaps, each containing: + + ** `commits_bitmap`, an EWAH-compressed bitmap describing the set of + commits included in the this psuedo-merge. + + ** `merge_bitmap`, an EWAH-compressed bitmap describing the union of + the set of objects reachable from all commits listed in the + `commits_bitmap`. + +* A lookup table, mapping pseudo-merged commits to the pseudo-merges + they belong to. Entries appear in increasing order of each commit's + bit position. Each entry is 12 bytes wide, and is comprised of the + following: + + ** `commit_pos`, a 4-byte unsigned value (in network byte-order) + containing the bit position for this commit. + + ** `offset`, an 8-byte unsigned value (also in network byte-order) + containing either one of two possible offsets, depending on whether or + not the most-significant bit is set. + + *** If unset (i.e. `offset & ((uint64_t)1<<63) == 0`), the offset + (relative to the beginning of the `.bitmap` file) at which the + pseudo-merge bitmap for this commit can be read. This indicates + only a single pseudo-merge bitmap contains this commit. + + *** If set (i.e. `offset & ((uint64_t)1<<63) != 0`), the offset + (again relative to the beginning of the `.bitmap` file) at which + the extended offset table can be located describing the set of + pseudo-merge bitmaps which contain this commit. This indicates + that multiple pseudo-merge bitmaps contain this commit. + +* An (optional) extended lookup table (written if and only if there is + at least one commit which appears in more than one pseudo-merge). + There are as many entries as commits which appear in multiple + pseudo-merges. Each entry contains the following: + + ** `N`, a 4-byte unsigned value equal to the number of pseudo-merges + which contain a given commit. + + ** An array of `N` 8-byte unsigned values, each of which is + interpreted as an offset (relative to the beginning of the + `.bitmap` file) at which a pseudo-merge bitmap for this commit can + be read. These values occur in no particular order. + +* Positions for all pseudo-merges, each stored as an 8-byte unsigned + value (in network byte-order) containing the offset (relative to the + beginning of the `.bitmap` file) of each consecutive pseudo-merge. + +* A 4-byte unsigned value (in network byte-order) equal to the number of + pseudo-merges. + +* A 4-byte unsigned value (in network byte-order) equal to the number of + unique commits which appear in any pseudo-merge. + +* An 8-byte unsigned value (in network byte-order) equal to the number + of bytes between the start of the pseudo-merge section and the + beginning of the lookup table. + +* An 8-byte unsigned value (in network byte-order) equal to the number + of bytes in the pseudo-merge section (including this field). diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 814cdcf95d..ee71e9d8aa 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.45.GIT +DEF_VER=v2.46.GIT LF=' ' @@ -793,7 +793,6 @@ TEST_BUILTINS_OBJS += test-dump-fsmonitor.o TEST_BUILTINS_OBJS += test-dump-split-index.o TEST_BUILTINS_OBJS += test-dump-untracked-cache.o TEST_BUILTINS_OBJS += test-env-helper.o -TEST_BUILTINS_OBJS += test-example-decorate.o TEST_BUILTINS_OBJS += test-example-tap.o TEST_BUILTINS_OBJS += test-find-pack.o TEST_BUILTINS_OBJS += test-fsmonitor-client.o @@ -810,8 +809,6 @@ TEST_BUILTINS_OBJS += test-match-trees.o TEST_BUILTINS_OBJS += test-mergesort.o TEST_BUILTINS_OBJS += test-mktemp.o TEST_BUILTINS_OBJS += test-oid-array.o -TEST_BUILTINS_OBJS += test-oidmap.o -TEST_BUILTINS_OBJS += test-oidtree.o TEST_BUILTINS_OBJS += test-online-cpus.o TEST_BUILTINS_OBJS += test-pack-mtimes.o TEST_BUILTINS_OBJS += test-parse-options.o @@ -1105,6 +1102,7 @@ LIB_OBJS += prompt.o LIB_OBJS += protocol.o LIB_OBJS += protocol-caps.o LIB_OBJS += prune-packed.o +LIB_OBJS += pseudo-merge.o LIB_OBJS += quote.o LIB_OBJS += range-diff.o LIB_OBJS += reachable.o @@ -1282,6 +1280,7 @@ BUILTIN_OBJS += builtin/read-tree.o BUILTIN_OBJS += builtin/rebase.o BUILTIN_OBJS += builtin/receive-pack.o BUILTIN_OBJS += builtin/reflog.o +BUILTIN_OBJS += builtin/refs.o BUILTIN_OBJS += builtin/remote-ext.o BUILTIN_OBJS += builtin/remote-fd.o BUILTIN_OBJS += builtin/remote.o @@ -1334,8 +1333,16 @@ THIRD_PARTY_SOURCES += sha1collisiondetection/% THIRD_PARTY_SOURCES += sha1dc/% UNIT_TEST_PROGRAMS += t-ctype +UNIT_TEST_PROGRAMS += t-example-decorate +UNIT_TEST_PROGRAMS += t-hash UNIT_TEST_PROGRAMS += t-mem-pool +UNIT_TEST_PROGRAMS += t-oidmap +UNIT_TEST_PROGRAMS += t-oidtree UNIT_TEST_PROGRAMS += t-prio-queue +UNIT_TEST_PROGRAMS += t-reftable-basics +UNIT_TEST_PROGRAMS += t-reftable-merged +UNIT_TEST_PROGRAMS += t-reftable-pq +UNIT_TEST_PROGRAMS += t-reftable-record UNIT_TEST_PROGRAMS += t-reftable-tree UNIT_TEST_PROGRAMS += t-strbuf UNIT_TEST_PROGRAMS += t-strcmp-offset @@ -1344,6 +1351,7 @@ UNIT_TEST_PROGRAMS += t-trailer UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS)) UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS)) UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o +UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-oid.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) @@ -1371,7 +1379,7 @@ PTHREAD_CFLAGS = # For the 'sparse' target SPARSE_FLAGS ?= -std=gnu99 -SP_EXTRA_FLAGS = -Wno-universal-initializer +SP_EXTRA_FLAGS = # For informing GIT-BUILD-OPTIONS of the SANITIZE=leak,address targets SANITIZE_LEAK = @@ -1447,8 +1455,8 @@ ALL_COMMANDS_TO_INSTALL += git-upload-archive$(X) ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X) endif -ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) -ALL_LDFLAGS = $(LDFLAGS) +ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_APPEND) +ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND) ifdef SANITIZE SANITIZERS := $(foreach flag,$(subst $(comma),$(space),$(SANITIZE)),$(flag)) @@ -2673,12 +2681,8 @@ REFTABLE_OBJS += reftable/stack.o REFTABLE_OBJS += reftable/tree.o REFTABLE_OBJS += reftable/writer.o -REFTABLE_TEST_OBJS += reftable/basics_test.o REFTABLE_TEST_OBJS += reftable/block_test.o REFTABLE_TEST_OBJS += reftable/dump.o -REFTABLE_TEST_OBJS += reftable/merged_test.o -REFTABLE_TEST_OBJS += reftable/pq_test.o -REFTABLE_TEST_OBJS += reftable/record_test.o REFTABLE_TEST_OBJS += reftable/readwrite_test.o REFTABLE_TEST_OBJS += reftable/stack_test.o REFTABLE_TEST_OBJS += reftable/test_framework.o @@ -3758,42 +3762,6 @@ ALL_COMMANDS += scalar .PHONY: check-docs check-docs:: $(MAKE) -C Documentation lint-docs - @(for v in $(patsubst %$X,%,$(ALL_COMMANDS)); \ - do \ - case "$$v" in \ - git-merge-octopus | git-merge-ours | git-merge-recursive | \ - git-merge-resolve | git-merge-subtree | \ - git-fsck-objects | git-init-db | \ - git-remote-* | git-stage | git-legacy-* | \ - git-?*--?* ) continue ;; \ - esac ; \ - test -f "Documentation/$$v.txt" || \ - echo "no doc: $$v"; \ - sed -e '1,/^### command list/d' -e '/^#/d' command-list.txt | \ - grep -q "^$$v[ ]" || \ - case "$$v" in \ - git) ;; \ - *) echo "no link: $$v";; \ - esac ; \ - done; \ - ( \ - sed -e '1,/^### command list/d' \ - -e '/^#/d' \ - -e '/guide$$/d' \ - -e '/interfaces$$/d' \ - -e 's/[ ].*//' \ - -e 's/^/listed /' command-list.txt; \ - $(MAKE) -C Documentation print-man1 | \ - grep '\.txt$$' | \ - sed -e 's|^|documented |' \ - -e 's/\.txt//'; \ - ) | while read how cmd; \ - do \ - case " $(patsubst %$X,%,$(ALL_COMMANDS) $(BUILT_INS) $(EXCLUDED_PROGRAMS)) " in \ - *" $$cmd "*) ;; \ - *) echo "removed but $$how: $$cmd" ;; \ - esac; \ - done ) | sort ### Make sure built-ins do not have dups and listed in git.c # @@ -3883,7 +3851,10 @@ $(FUZZ_PROGRAMS): %: %.o oss-fuzz/dummy-cmd-main.o $(GITLIBS) GIT-LDFLAGS -Wl,--allow-multiple-definition \ $(filter %.o,$^) $(filter %.a,$^) $(LIBS) $(LIB_FUZZING_ENGINE) -$(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o $(UNIT_TEST_DIR)/test-lib.o $(GITLIBS) GIT-LDFLAGS +$(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o \ + $(UNIT_TEST_DIR)/test-lib.o \ + $(UNIT_TEST_DIR)/lib-oid.o \ + $(GITLIBS) GIT-LDFLAGS $(call mkdir_p_parent_template) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \ $(filter %.o,$^) $(filter %.a,$^) $(LIBS) @@ -1 +1 @@ -Documentation/RelNotes/2.46.0.txt
\ No newline at end of file +Documentation/RelNotes/2.47.0.txt
\ No newline at end of file diff --git a/add-interactive.c b/add-interactive.c index b5d6cd689a..49042b3026 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "add-interactive.h" #include "color.h" @@ -557,7 +559,7 @@ static int get_modified_files(struct repository *r, s.skip_unseen = filter && i; opt.def = is_initial ? - empty_tree_oid_hex() : oid_to_hex(&head_oid); + empty_tree_oid_hex(the_repository->hash_algo) : oid_to_hex(&head_oid); repo_init_revisions(r, &rev, NULL); setup_revisions(0, NULL, &rev, &opt); diff --git a/add-patch.c b/add-patch.c index 814de57c4a..1cec4ab67b 100644 --- a/add-patch.c +++ b/add-patch.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "add-interactive.h" #include "advice.h" @@ -5,9 +7,11 @@ #include "environment.h" #include "gettext.h" #include "object-name.h" +#include "pager.h" #include "read-cache-ll.h" #include "repository.h" #include "strbuf.h" +#include "sigchain.h" #include "run-command.h" #include "strvec.h" #include "pathspec.h" @@ -299,6 +303,7 @@ static void err(struct add_p_state *s, const char *fmt, ...) va_end(args); } +LAST_ARG_MUST_BE_NULL static void setup_child_process(struct add_p_state *s, struct child_process *cp, ...) { @@ -399,6 +404,12 @@ static void complete_file(char marker, struct hunk *hunk) hunk->splittable_into++; } +/* Empty context lines may omit the leading ' ' */ +static int normalize_marker(const char *p) +{ + return p[0] == '\n' || (p[0] == '\r' && p[1] == '\n') ? ' ' : p[0]; +} + static int parse_diff(struct add_p_state *s, const struct pathspec *ps) { struct strvec args = STRVEC_INIT; @@ -420,7 +431,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) /* could be on an unborn branch */ !strcmp("HEAD", s->revision) && repo_get_oid(the_repository, "HEAD", &oid) ? - empty_tree_oid_hex() : s->revision); + empty_tree_oid_hex(the_repository->hash_algo) : s->revision); } color_arg_index = args.nr; /* Use `--no-color` explicitly, just in case `diff.color = always`. */ @@ -484,6 +495,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) while (p != pend) { char *eol = memchr(p, '\n', pend - p); const char *deleted = NULL, *mode_change = NULL; + char ch = normalize_marker(p); if (!eol) eol = pend; @@ -531,7 +543,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) * Start counting into how many hunks this one can be * split */ - marker = *p; + marker = ch; } else if (hunk == &file_diff->head && starts_with(p, "new file")) { file_diff->added = 1; @@ -585,10 +597,10 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) (int)(eol - (plain->buf + file_diff->head.start)), plain->buf + file_diff->head.start); - if ((marker == '-' || marker == '+') && *p == ' ') + if ((marker == '-' || marker == '+') && ch == ' ') hunk->splittable_into++; - if (marker && *p != '\\') - marker = *p; + if (marker && ch != '\\') + marker = ch; p = eol == pend ? pend : eol + 1; hunk->end = p - plain->buf; @@ -812,7 +824,7 @@ static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff, (int)(hunk->end - hunk->start), plain + hunk->start); - if (plain[overlap_end] != ' ') + if (normalize_marker(&plain[overlap_end]) != ' ') return error(_("expected context line " "#%d in\n%.*s"), (int)(j + 1), @@ -952,7 +964,7 @@ static int split_hunk(struct add_p_state *s, struct file_diff *file_diff, context_line_count = 0; while (splittable_into > 1) { - ch = s->plain.buf[current]; + ch = normalize_marker(&s->plain.buf[current]); if (!ch) BUG("buffer overrun while splitting hunks"); @@ -1170,14 +1182,14 @@ static ssize_t recount_edited_hunk(struct add_p_state *s, struct hunk *hunk, header->old_count = header->new_count = 0; for (i = hunk->start; i < hunk->end; ) { - switch (s->plain.buf[i]) { + switch(normalize_marker(&s->plain.buf[i])) { case '-': header->old_count++; break; case '+': header->new_count++; break; - case ' ': case '\r': case '\n': + case ' ': header->old_count++; header->new_count++; break; @@ -1388,7 +1400,7 @@ N_("j - leave this hunk undecided, see next undecided hunk\n" "/ - search for a hunk matching the given regex\n" "s - split the current hunk into smaller hunks\n" "e - manually edit the current hunk\n" - "p - print the current hunk\n" + "p - print the current hunk, 'P' to use the pager\n" "? - print help\n"); static int patch_update_file(struct add_p_state *s, @@ -1399,7 +1411,7 @@ static int patch_update_file(struct add_p_state *s, struct hunk *hunk; char ch; struct child_process cp = CHILD_PROCESS_INIT; - int colored = !!s->colored.len, quit = 0; + int colored = !!s->colored.len, quit = 0, use_pager = 0; enum prompt_mode_type prompt_mode_type; enum { ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0, @@ -1449,9 +1461,18 @@ static int patch_update_file(struct add_p_state *s, strbuf_reset(&s->buf); if (file_diff->hunk_nr) { if (rendered_hunk_index != hunk_index) { + if (use_pager) { + setup_pager(); + sigchain_push(SIGPIPE, SIG_IGN); + } render_hunk(s, hunk, 0, colored, &s->buf); fputs(s->buf.buf, stdout); rendered_hunk_index = hunk_index; + if (use_pager) { + sigchain_pop(SIGPIPE); + wait_for_pager(); + use_pager = 0; + } } strbuf_reset(&s->buf); @@ -1672,8 +1693,9 @@ soft_increment: hunk->use = USE_HUNK; goto soft_increment; } - } else if (s->answer.buf[0] == 'p') { + } else if (ch == 'p') { rendered_hunk_index = -1; + use_pager = (s->answer.buf[0] == 'P') ? 1 : 0; } else if (s->answer.buf[0] == '?') { const char *p = _(help_patch_remainder), *eol = p; @@ -70,6 +70,7 @@ static struct { [ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName" }, [ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected" }, [ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward" }, /* backwards compatibility */ + [ADVICE_REBASE_TODO_ERROR] = { "rebaseTodoError" }, [ADVICE_REF_SYNTAX] = { "refSyntax" }, [ADVICE_RESET_NO_REFRESH_WARNING] = { "resetNoRefresh" }, [ADVICE_RESOLVE_CONFLICT] = { "resolveConflict" }, @@ -77,6 +78,7 @@ static struct { [ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse" }, [ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure" }, [ADVICE_SKIPPED_CHERRY_PICKS] = { "skippedCherryPicks" }, + [ADVICE_SPARSE_INDEX_EXPANDED] = { "sparseIndexExpanded" }, [ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning" }, [ADVICE_STATUS_HINTS] = { "statusHints" }, [ADVICE_STATUS_U_OPTION] = { "statusUoption" }, @@ -37,6 +37,7 @@ enum advice_type { ADVICE_PUSH_UNQUALIFIED_REF_NAME, ADVICE_PUSH_UPDATE_REJECTED, ADVICE_PUSH_UPDATE_REJECTED_ALIAS, + ADVICE_REBASE_TODO_ERROR, ADVICE_REF_SYNTAX, ADVICE_RESET_NO_REFRESH_WARNING, ADVICE_RESOLVE_CONFLICT, @@ -44,6 +45,7 @@ enum advice_type { ADVICE_SEQUENCER_IN_USE, ADVICE_SET_UPSTREAM_FAILURE, ADVICE_SKIPPED_CHERRY_PICKS, + ADVICE_SPARSE_INDEX_EXPANDED, ADVICE_STATUS_AHEAD_BEHIND_WARNING, ADVICE_STATUS_HINTS, ADVICE_STATUS_U_OPTION, @@ -7,6 +7,8 @@ * */ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "base85.h" @@ -135,6 +137,7 @@ void clear_apply_state(struct apply_state *state) strset_clear(&state->removed_symlinks); strset_clear(&state->kept_symlinks); strbuf_release(&state->root); + FREE_AND_NULL(state->fake_ancestor); /* &state->fn_table is cleared at the end of apply_patch() */ } @@ -992,6 +995,7 @@ static int parse_mode_line(const char *line, int linenr, unsigned int *mode) *mode = strtoul(line, &end, 8); if (end == line || !isspace(*end)) return error(_("invalid mode on line %d: %s"), linenr, line); + *mode = canon_mode(*mode); return 0; } @@ -2493,18 +2497,21 @@ static int match_fragment(struct apply_state *state, int match_beginning, int match_end) { int i; - char *fixed_buf, *buf, *orig, *target; - struct strbuf fixed; - size_t fixed_len, postlen; + const char *orig, *target; + struct strbuf fixed = STRBUF_INIT; + size_t postlen; int preimage_limit; + int ret; if (preimage->nr + current_lno <= img->nr) { /* * The hunk falls within the boundaries of img. */ preimage_limit = preimage->nr; - if (match_end && (preimage->nr + current_lno != img->nr)) - return 0; + if (match_end && (preimage->nr + current_lno != img->nr)) { + ret = 0; + goto out; + } } else if (state->ws_error_action == correct_ws_error && (ws_rule & WS_BLANK_AT_EOF)) { /* @@ -2521,17 +2528,23 @@ static int match_fragment(struct apply_state *state, * we are not removing blanks at the end, so we * should reject the hunk at this position. */ - return 0; + ret = 0; + goto out; } - if (match_beginning && current_lno) - return 0; + if (match_beginning && current_lno) { + ret = 0; + goto out; + } /* Quick hash check */ - for (i = 0; i < preimage_limit; i++) + for (i = 0; i < preimage_limit; i++) { if ((img->line[current_lno + i].flag & LINE_PATCHED) || - (preimage->line[i].hash != img->line[current_lno + i].hash)) - return 0; + (preimage->line[i].hash != img->line[current_lno + i].hash)) { + ret = 0; + goto out; + } + } if (preimage_limit == preimage->nr) { /* @@ -2544,8 +2557,10 @@ static int match_fragment(struct apply_state *state, if ((match_end ? (current + preimage->len == img->len) : (current + preimage->len <= img->len)) && - !memcmp(img->buf + current, preimage->buf, preimage->len)) - return 1; + !memcmp(img->buf + current, preimage->buf, preimage->len)) { + ret = 1; + goto out; + } } else { /* * The preimage extends beyond the end of img, so @@ -2554,7 +2569,7 @@ static int match_fragment(struct apply_state *state, * There must be one non-blank context line that match * a line before the end of img. */ - char *buf_end; + const char *buf, *buf_end; buf = preimage->buf; buf_end = buf; @@ -2564,8 +2579,10 @@ static int match_fragment(struct apply_state *state, for ( ; buf < buf_end; buf++) if (!isspace(*buf)) break; - if (buf == buf_end) - return 0; + if (buf == buf_end) { + ret = 0; + goto out; + } } /* @@ -2573,12 +2590,16 @@ static int match_fragment(struct apply_state *state, * fuzzy matching. We collect all the line length information because * we need it to adjust whitespace if we match. */ - if (state->ws_ignore_action == ignore_ws_change) - return line_by_line_fuzzy_match(img, preimage, postimage, - current, current_lno, preimage_limit); + if (state->ws_ignore_action == ignore_ws_change) { + ret = line_by_line_fuzzy_match(img, preimage, postimage, + current, current_lno, preimage_limit); + goto out; + } - if (state->ws_error_action != correct_ws_error) - return 0; + if (state->ws_error_action != correct_ws_error) { + ret = 0; + goto out; + } /* * The hunk does not apply byte-by-byte, but the hash says @@ -2607,7 +2628,7 @@ static int match_fragment(struct apply_state *state, * but in this loop we will only handle the part of the * preimage that falls within the file. */ - strbuf_init(&fixed, preimage->len + 1); + strbuf_grow(&fixed, preimage->len + 1); orig = preimage->buf; target = img->buf + current; for (i = 0; i < preimage_limit; i++) { @@ -2643,8 +2664,10 @@ static int match_fragment(struct apply_state *state, postlen += tgtfix.len; strbuf_release(&tgtfix); - if (!match) - goto unmatch_exit; + if (!match) { + ret = 0; + goto out; + } orig += oldlen; target += tgtlen; @@ -2665,9 +2688,13 @@ static int match_fragment(struct apply_state *state, /* Try fixing the line in the preimage */ ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL); - for (j = fixstart; j < fixed.len; j++) - if (!isspace(fixed.buf[j])) - goto unmatch_exit; + for (j = fixstart; j < fixed.len; j++) { + if (!isspace(fixed.buf[j])) { + ret = 0; + goto out; + } + } + orig += oldlen; } @@ -2677,16 +2704,16 @@ static int match_fragment(struct apply_state *state, * has whitespace breakages unfixed, and fixing them makes the * hunk match. Update the context lines in the postimage. */ - fixed_buf = strbuf_detach(&fixed, &fixed_len); if (postlen < postimage->len) postlen = 0; update_pre_post_images(preimage, postimage, - fixed_buf, fixed_len, postlen); - return 1; + fixed.buf, fixed.len, postlen); - unmatch_exit: + ret = 1; + +out: strbuf_release(&fixed); - return 0; + return ret; } static int find_pos(struct apply_state *state, @@ -3680,7 +3707,7 @@ static int try_threeway(struct apply_state *state, if (status) { patch->conflicted_threeway = 1; if (patch->is_new) - oidclr(&patch->threeway_stage[0]); + oidclr(&patch->threeway_stage[0], the_repository->hash_algo); else oidcpy(&patch->threeway_stage[0], &pre_oid); oidcpy(&patch->threeway_stage[1], &our_oid); @@ -1,7 +1,7 @@ #ifndef APPLY_H #define APPLY_H -#include "hash-ll.h" +#include "hash.h" #include "lockfile.h" #include "string-list.h" #include "strmap.h" @@ -59,7 +59,7 @@ struct apply_state { struct repository *repo; const char *index_file; enum apply_verbosity apply_verbosity; - const char *fake_ancestor; + char *fake_ancestor; const char *patch_input_file; int line_termination; struct strbuf root; diff --git a/archive-tar.c b/archive-tar.c index 8ae30125f8..e7b3489e1e 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -1,6 +1,9 @@ /* * Copyright (c) 2005, 2006 Rene Scharfe */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "gettext.h" diff --git a/archive-zip.c b/archive-zip.c index fd1d3f816d..9f32730181 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -1,6 +1,9 @@ /* * Copyright (c) 2006 Rene Scharfe */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "archive.h" @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "config.h" @@ -6,6 +6,8 @@ * an insanely large number of attributes. */ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "environment.h" @@ -865,7 +867,8 @@ static struct attr_stack *read_attr_from_index(struct index_state *istate, stack = read_attr_from_blob(istate, &istate->cache[sparse_dir_pos]->oid, relative_path, flags); } else { buf = read_blob_data_from_index(istate, path, &size); - stack = read_attr_from_buf(buf, size, path, flags); + if (buf) + stack = read_attr_from_buf(buf, size, path, flags); } return stack; } @@ -190,6 +190,8 @@ struct attr_check { }; struct attr_check *attr_check_alloc(void); + +LAST_ARG_MUST_BE_NULL struct attr_check *attr_check_initl(const char *, ...); struct attr_check *attr_check_dup(const struct attr_check *check); @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "commit.h" @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "refs.h" #include "object-store-ll.h" @@ -1246,7 +1248,7 @@ static int fill_blob_sha1_and_mode(struct repository *r, goto error_out; return 0; error_out: - oidclr(&origin->blob_oid); + oidclr(&origin->blob_oid, the_repository->hash_algo); origin->mode = S_IFINVALID; return -1; } @@ -2928,6 +2930,10 @@ void setup_blame_bloom_data(struct blame_scoreboard *sb) void cleanup_scoreboard(struct blame_scoreboard *sb) { + free(sb->lineno); + clear_prio_queue(&sb->commits); + oidset_clear(&sb->ignore_list); + if (sb->bloom_data) { int i; for (i = 0; i < sb->bloom_data->nr; i++) { @@ -6,6 +6,10 @@ #include "commit-graph.h" #include "commit.h" #include "commit-slab.h" +#include "tree.h" +#include "tree-walk.h" +#include "config.h" +#include "repository.h" define_commit_slab(bloom_filter_slab, struct bloom_filter); @@ -48,9 +52,9 @@ static int check_bloom_offset(struct commit_graph *g, uint32_t pos, return -1; } -static int load_bloom_filter_from_graph(struct commit_graph *g, - struct bloom_filter *filter, - uint32_t graph_pos) +int load_bloom_filter_from_graph(struct commit_graph *g, + struct bloom_filter *filter, + uint32_t graph_pos) { uint32_t lex_pos, start_index, end_index; @@ -88,6 +92,8 @@ static int load_bloom_filter_from_graph(struct commit_graph *g, filter->data = (unsigned char *)(g->chunk_bloom_data + sizeof(unsigned char) * start_index + BLOOMDATA_CHUNK_HEADER_SIZE); + filter->version = g->bloom_filter_settings->hash_version; + filter->to_free = NULL; return 1; } @@ -99,7 +105,64 @@ static 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(uint32_t seed, const char *data, size_t len) +uint32_t murmur3_seeded_v2(uint32_t seed, const char *data, size_t len) +{ + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + const uint32_t r1 = 15; + const uint32_t r2 = 13; + const uint32_t m = 5; + const uint32_t n = 0xe6546b64; + int i; + uint32_t k1 = 0; + const char *tail; + + int len4 = len / sizeof(uint32_t); + + uint32_t k; + for (i = 0; i < len4; i++) { + uint32_t byte1 = (uint32_t)(unsigned char)data[4*i]; + uint32_t byte2 = ((uint32_t)(unsigned char)data[4*i + 1]) << 8; + uint32_t byte3 = ((uint32_t)(unsigned char)data[4*i + 2]) << 16; + uint32_t byte4 = ((uint32_t)(unsigned char)data[4*i + 3]) << 24; + k = byte1 | byte2 | byte3 | byte4; + k *= c1; + k = rotate_left(k, r1); + k *= c2; + + seed ^= k; + seed = rotate_left(seed, r2) * m + n; + } + + tail = (data + len4 * sizeof(uint32_t)); + + switch (len & (sizeof(uint32_t) - 1)) { + case 3: + k1 ^= ((uint32_t)(unsigned char)tail[2]) << 16; + /*-fallthrough*/ + case 2: + k1 ^= ((uint32_t)(unsigned char)tail[1]) << 8; + /*-fallthrough*/ + case 1: + k1 ^= ((uint32_t)(unsigned char)tail[0]) << 0; + k1 *= c1; + k1 = rotate_left(k1, r1); + k1 *= c2; + seed ^= k1; + break; + } + + seed ^= (uint32_t)len; + seed ^= (seed >> 16); + seed *= 0x85ebca6b; + seed ^= (seed >> 13); + seed *= 0xc2b2ae35; + seed ^= (seed >> 16); + + return seed; +} + +static uint32_t murmur3_seeded_v1(uint32_t seed, const char *data, size_t len) { const uint32_t c1 = 0xcc9e2d51; const uint32_t c2 = 0x1b873593; @@ -164,8 +227,14 @@ void fill_bloom_key(const char *data, int i; const uint32_t seed0 = 0x293ae76f; const uint32_t seed1 = 0x7e646e2c; - const uint32_t hash0 = murmur3_seeded(seed0, data, len); - const uint32_t hash1 = murmur3_seeded(seed1, data, len); + uint32_t hash0, hash1; + if (settings->hash_version == 2) { + hash0 = murmur3_seeded_v2(seed0, data, len); + hash1 = murmur3_seeded_v2(seed1, data, len); + } else { + hash0 = murmur3_seeded_v1(seed0, data, len); + hash1 = murmur3_seeded_v1(seed1, data, len); + } key->hashes = (uint32_t *)xcalloc(settings->num_hashes, sizeof(uint32_t)); for (i = 0; i < settings->num_hashes; i++) @@ -197,6 +266,18 @@ void init_bloom_filters(void) init_bloom_filter_slab(&bloom_filters); } +static void free_one_bloom_filter(struct bloom_filter *filter) +{ + if (!filter) + return; + free(filter->to_free); +} + +void deinit_bloom_filters(void) +{ + deep_clear_bloom_filter_slab(&bloom_filters, free_one_bloom_filter); +} + static int pathmap_cmp(const void *hashmap_cmp_fn_data UNUSED, const struct hashmap_entry *eptr, const struct hashmap_entry *entry_or_key, @@ -210,11 +291,97 @@ static int pathmap_cmp(const void *hashmap_cmp_fn_data UNUSED, return strcmp(e1->path, e2->path); } -static void init_truncated_large_filter(struct bloom_filter *filter) +static void init_truncated_large_filter(struct bloom_filter *filter, + int version) { - filter->data = xmalloc(1); + filter->data = filter->to_free = xmalloc(1); filter->data[0] = 0xFF; filter->len = 1; + filter->version = version; +} + +#define VISITED (1u<<21) +#define HIGH_BITS (1u<<22) + +static int has_entries_with_high_bit(struct repository *r, struct tree *t) +{ + if (parse_tree(t)) + return 1; + + if (!(t->object.flags & VISITED)) { + struct tree_desc desc; + struct name_entry entry; + + init_tree_desc(&desc, &t->object.oid, t->buffer, t->size); + while (tree_entry(&desc, &entry)) { + size_t i; + for (i = 0; i < entry.pathlen; i++) { + if (entry.path[i] & 0x80) { + t->object.flags |= HIGH_BITS; + goto done; + } + } + + if (S_ISDIR(entry.mode)) { + struct tree *sub = lookup_tree(r, &entry.oid); + if (sub && has_entries_with_high_bit(r, sub)) { + t->object.flags |= HIGH_BITS; + goto done; + } + } + + } + +done: + t->object.flags |= VISITED; + } + + return !!(t->object.flags & HIGH_BITS); +} + +static int commit_tree_has_high_bit_paths(struct repository *r, + struct commit *c) +{ + struct tree *t; + if (repo_parse_commit(r, c)) + return 1; + t = repo_get_commit_tree(r, c); + if (!t) + return 1; + return has_entries_with_high_bit(r, t); +} + +static struct bloom_filter *upgrade_filter(struct repository *r, struct commit *c, + struct bloom_filter *filter, + int hash_version) +{ + struct commit_list *p = c->parents; + if (commit_tree_has_high_bit_paths(r, c)) + return NULL; + + if (p && commit_tree_has_high_bit_paths(r, p->item)) + return NULL; + + filter->version = hash_version; + + return filter; +} + +struct bloom_filter *get_bloom_filter(struct repository *r, struct commit *c) +{ + struct bloom_filter *filter; + int hash_version; + + filter = get_or_compute_bloom_filter(r, c, 0, NULL, NULL); + if (!filter) + return NULL; + + prepare_repo_settings(r); + hash_version = r->settings.commit_graph_changed_paths_version; + + if (!(hash_version == -1 || hash_version == filter->version)) + return NULL; /* unusable filter */ + return filter; } struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, @@ -242,8 +409,23 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, filter, graph_pos); } - if (filter->data && filter->len) - return filter; + if (filter->data && filter->len) { + struct bloom_filter *upgrade; + if (!settings || settings->hash_version == filter->version) + return filter; + + /* version mismatch, see if we can upgrade */ + if (compute_if_not_present && + git_env_bool("GIT_TEST_UPGRADE_BLOOM_FILTERS", 1)) { + upgrade = upgrade_filter(r, c, filter, + settings->hash_version); + if (upgrade) { + if (computed) + *computed |= BLOOM_UPGRADED; + return upgrade; + } + } + } if (!compute_if_not_present) return NULL; @@ -299,19 +481,22 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, } if (hashmap_get_size(&pathmap) > settings->max_changed_paths) { - init_truncated_large_filter(filter); + init_truncated_large_filter(filter, + settings->hash_version); if (computed) *computed |= BLOOM_TRUNC_LARGE; goto cleanup; } filter->len = (hashmap_get_size(&pathmap) * settings->bits_per_entry + BITS_PER_WORD - 1) / BITS_PER_WORD; + filter->version = settings->hash_version; if (!filter->len) { if (computed) *computed |= BLOOM_TRUNC_EMPTY; filter->len = 1; } CALLOC_ARRAY(filter->data, filter->len); + filter->to_free = filter->data; hashmap_for_each_entry(&pathmap, &iter, e, entry) { struct bloom_key key; @@ -325,7 +510,7 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, } else { for (i = 0; i < diff_queued_diff.nr; i++) diff_free_filepair(diff_queued_diff.queue[i]); - init_truncated_large_filter(filter); + init_truncated_large_filter(filter, settings->hash_version); if (computed) *computed |= BLOOM_TRUNC_LARGE; @@ -3,13 +3,16 @@ struct commit; struct repository; +struct commit_graph; struct bloom_filter_settings { /* * The version of the hashing technique being used. - * We currently only support version = 1 which is + * The newest version is 2, which is * the seeded murmur3 hashing technique implemented - * in bloom.c. + * in bloom.c. Bloom filters of version 1 were created + * with prior versions of Git, which had a bug in the + * implementation of the hash function. */ uint32_t hash_version; @@ -52,6 +55,9 @@ struct bloom_filter_settings { struct bloom_filter { unsigned char *data; size_t len; + int version; + + void *to_free; }; /* @@ -68,6 +74,10 @@ struct bloom_key { uint32_t *hashes; }; +int load_bloom_filter_from_graph(struct commit_graph *g, + struct bloom_filter *filter, + uint32_t graph_pos); + /* * Calculate the murmur3 32-bit hash value for the given data * using the given seed. @@ -75,7 +85,7 @@ struct bloom_key { * Not considered to be cryptographically secure. * Implemented as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm */ -uint32_t murmur3_seeded(uint32_t seed, const char *data, size_t len); +uint32_t murmur3_seeded_v2(uint32_t seed, const char *data, size_t len); void fill_bloom_key(const char *data, size_t len, @@ -88,12 +98,14 @@ void add_key_to_filter(const struct bloom_key *key, const struct bloom_filter_settings *settings); void init_bloom_filters(void); +void deinit_bloom_filters(void); enum bloom_filter_computed { BLOOM_NOT_COMPUTED = (1 << 0), BLOOM_COMPUTED = (1 << 1), BLOOM_TRUNC_LARGE = (1 << 2), BLOOM_TRUNC_EMPTY = (1 << 3), + BLOOM_UPGRADED = (1 << 4), }; struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, @@ -102,8 +114,24 @@ struct bloom_filter *get_or_compute_bloom_filter(struct repository *r, const struct bloom_filter_settings *settings, enum bloom_filter_computed *computed); -#define get_bloom_filter(r, c) get_or_compute_bloom_filter( \ - (r), (c), 0, NULL, NULL) +/* + * Find the Bloom filter associated with the given commit "c". + * + * If any of the following are true + * + * - the repository does not have a commit-graph, or + * - the repository disables reading from the commit-graph, or + * - the given commit does not have a Bloom filter computed, or + * - there is a Bloom filter for commit "c", but it cannot be read + * because the filter uses an incompatible version of murmur3 + * + * , then `get_bloom_filter()` will return NULL. Otherwise, the corresponding + * Bloom filter will be returned. + * + * For callers who wish to inspect Bloom filters with incompatible hash + * versions, use get_or_compute_bloom_filter(). + */ +struct bloom_filter *get_bloom_filter(struct repository *r, struct commit *c); int bloom_filter_contains(const struct bloom_filter *filter, const struct bloom_key *key, @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "advice.h" #include "config.h" @@ -1,6 +1,14 @@ #ifndef BUILTIN_H #define BUILTIN_H +/* + * TODO: Almost all of our builtins access `the_repository` by necessity + * because they do not get passed a pointer to it. We should adapt the function + * signature of those main functions to accept a `struct repository *` and then + * remove the macro here. + */ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" /* @@ -207,6 +215,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix); int cmd_rebase__interactive(int argc, const char **argv, const char *prefix); int cmd_receive_pack(int argc, const char **argv, const char *prefix); int cmd_reflog(int argc, const char **argv, const char *prefix); +int cmd_refs(int argc, const char **argv, const char *prefix); int cmd_remote(int argc, const char **argv, const char *prefix); int cmd_remote_ext(int argc, const char **argv, const char *prefix); int cmd_remote_fd(int argc, const char **argv, const char *prefix); diff --git a/builtin/add.c b/builtin/add.c index 3dfcfc5fba..40b61ef90d 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -150,11 +150,7 @@ static int refresh(int verbose, const struct pathspec *pathspec) int interactive_add(const char **argv, const char *prefix, int patch) { struct pathspec pathspec; - int unused, ret; - - if (!git_config_get_bool("add.interactive.usebuiltin", &unused)) - warning(_("the add.interactive.useBuiltin setting has been removed!\n" - "See its entry in 'git help config' for details.")); + int ret; parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_FULL | diff --git a/builtin/am.c b/builtin/am.c index 36839029d2..a12be088f7 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -408,7 +408,7 @@ static void am_load(struct am_state *state) read_commit_msg(state); if (read_state_file(&sb, state, "original-commit", 1) < 0) - oidclr(&state->orig_commit); + oidclr(&state->orig_commit, the_repository->hash_algo); else if (get_oid_hex(sb.buf, &state->orig_commit) < 0) die(_("could not parse %s"), am_path(state, "original-commit")); @@ -1121,7 +1121,7 @@ static void am_next(struct am_state *state) unlink(am_path(state, "author-script")); unlink(am_path(state, "final-commit")); - oidclr(&state->orig_commit); + oidclr(&state->orig_commit, the_repository->hash_algo); unlink(am_path(state, "original-commit")); refs_delete_ref(get_main_ref_store(the_repository), NULL, "REBASE_HEAD", NULL, REF_NO_DEREF); @@ -1573,8 +1573,8 @@ static int build_fake_ancestor(const struct am_state *state, const char *index_f */ static int fall_back_threeway(const struct am_state *state, const char *index_path) { - struct object_id orig_tree, their_tree, our_tree; - const struct object_id *bases[1] = { &orig_tree }; + struct object_id their_tree, our_tree; + struct object_id bases[1] = { 0 }; struct merge_options o; struct commit *result; char *their_tree_name; @@ -1588,7 +1588,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa discard_index(the_repository->index); read_index_from(the_repository->index, index_path, get_git_dir()); - if (write_index_as_tree(&orig_tree, the_repository->index, index_path, 0, NULL)) + if (write_index_as_tree(&bases[0], the_repository->index, index_path, 0, NULL)) return error(_("Repository lacks necessary blobs to fall back on 3-way merge.")); say(state, stdout, _("Using index info to reconstruct a base tree...")); @@ -1630,7 +1630,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa * changes. */ - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); o.branch1 = "HEAD"; their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg); @@ -1718,6 +1718,7 @@ static void do_commit(const struct am_state *state) run_hooks("post-applypatch"); + free_commit_list(parents); strbuf_release(&sb); } @@ -2151,11 +2152,11 @@ static int safe_to_abort(const struct am_state *state) if (get_oid_hex(sb.buf, &abort_safety)) die(_("could not parse %s"), am_path(state, "abort-safety")); } else - oidclr(&abort_safety); + oidclr(&abort_safety, the_repository->hash_algo); strbuf_release(&sb); if (repo_get_oid(the_repository, "HEAD", &head)) - oidclr(&head); + oidclr(&head, the_repository->hash_algo); if (oideq(&head, &abort_safety)) return 1; @@ -2393,6 +2394,9 @@ int cmd_am(int argc, const char **argv, const char *prefix) N_("show the patch being applied"), PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, parse_opt_show_current_patch, RESUME_SHOW_PATCH_RAW }, + OPT_CMDMODE(0, "retry", &resume_mode, + N_("try to apply current patch again"), + RESUME_APPLY), OPT_CMDMODE(0, "allow-empty", &resume_mode, N_("record the empty patch as an empty commit"), RESUME_ALLOW_EMPTY), diff --git a/builtin/archive.c b/builtin/archive.c index 15ee1ec7bb..b50981504f 100644 --- a/builtin/archive.c +++ b/builtin/archive.c @@ -31,9 +31,7 @@ static int run_remote_archiver(int argc, const char **argv, struct packet_reader reader; _remote = remote_get(remote); - if (!_remote->url[0]) - die(_("git archive: Remote with no URL")); - transport = transport_get(_remote, _remote->url[0]); + transport = transport_get(_remote, _remote->url.v[0]); transport_connect(transport, "git-upload-archive", exec, fd); /* @@ -92,6 +90,7 @@ int cmd_archive(int argc, const char **argv, const char *prefix) N_("path to the remote git-upload-archive command")), OPT_END() }; + int ret; argc = parse_options(argc, argv, prefix, local_opts, NULL, PARSE_OPT_KEEP_ALL); @@ -106,6 +105,8 @@ int cmd_archive(int argc, const char **argv, const char *prefix) setvbuf(stderr, NULL, _IOLBF, BUFSIZ); - UNLEAK(output); - return write_archive(argc, argv, prefix, the_repository, output, 0); + ret = write_archive(argc, argv, prefix, the_repository, output, 0); + + free(output); + return ret; } diff --git a/builtin/bisect.c b/builtin/bisect.c index a58432b9d9..dabce9b542 100644 --- a/builtin/bisect.c +++ b/builtin/bisect.c @@ -262,7 +262,8 @@ static int bisect_reset(const char *commit) return bisect_clean_state(); } -static void log_commit(FILE *fp, char *fmt, const char *state, +static void log_commit(FILE *fp, + const char *fmt, const char *state, struct commit *commit) { struct pretty_print_context pp = {0}; diff --git a/builtin/blame.c b/builtin/blame.c index e09ff0155a..35e975fb13 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -5,7 +5,7 @@ * See COPYING for licensing conditions */ -#include "git-compat-util.h" +#include "builtin.h" #include "config.h" #include "color.h" #include "builtin.h" @@ -67,7 +67,7 @@ static int no_whole_file_rename; static int show_progress; static char repeated_meta_color[COLOR_MAXLEN]; static int coloring_mode; -static struct string_list ignore_revs_file_list = STRING_LIST_INIT_NODUP; +static struct string_list ignore_revs_file_list = STRING_LIST_INIT_DUP; static int mark_unblamable_lines; static int mark_ignored_lines; @@ -134,7 +134,7 @@ static void get_ac_line(const char *inbuf, const char *what, { struct ident_split ident; size_t len, maillen, namelen; - char *tmp, *endp; + const char *tmp, *endp; const char *namebuf, *mailbuf; tmp = strstr(inbuf, what); @@ -687,7 +687,7 @@ static unsigned parse_score(const char *arg) return score; } -static const char *add_prefix(const char *prefix, const char *path) +static char *add_prefix(const char *prefix, const char *path) { return prefix_path(prefix, prefix ? strlen(prefix) : 0, path); } @@ -725,6 +725,7 @@ static int git_blame_config(const char *var, const char *value, if (ret) return ret; string_list_insert(&ignore_revs_file_list, str); + free(str); return 0; } if (!strcmp(var, "blame.markunblamablelines")) { @@ -852,6 +853,7 @@ static void build_ignorelist(struct blame_scoreboard *sb, oidset_clear(&sb->ignore_list); else oidset_parse_file_carefully(&sb->ignore_list, i->string, + the_repository->hash_algo, peel_to_commit_oid, sb); } for_each_string_list_item(i, ignore_rev_list) { @@ -865,7 +867,7 @@ static void build_ignorelist(struct blame_scoreboard *sb, int cmd_blame(int argc, const char **argv, const char *prefix) { struct rev_info revs; - const char *path; + char *path = NULL; struct blame_scoreboard sb; struct blame_origin *o; struct blame_entry *ent = NULL; @@ -1226,6 +1228,7 @@ parse_done: } cleanup: + free(path); cleanup_scoreboard(&sb); release_revisions(&revs); return 0; diff --git a/builtin/bugreport.c b/builtin/bugreport.c index 25f860a0d9..b3cc77af53 100644 --- a/builtin/bugreport.c +++ b/builtin/bugreport.c @@ -107,7 +107,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix) struct tm tm; enum diagnose_mode diagnose = DIAGNOSE_NONE; char *option_output = NULL; - char *option_suffix = "%Y-%m-%d-%H%M"; + const char *option_suffix = "%Y-%m-%d-%H%M"; const char *user_relative_path = NULL; char *prefixed_filename; size_t output_path_len; diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 43a1d7ac49..18fe58d6b8 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -102,7 +102,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, enum object_type type; char *buf; unsigned long size; - struct object_context obj_context; + struct object_context obj_context = {0}; struct object_info oi = OBJECT_INFO_INIT; struct strbuf sb = STRBUF_INIT; unsigned flags = OBJECT_INFO_LOOKUP_REPLACE; @@ -163,7 +163,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, goto cleanup; case 'e': - return !repo_has_object_file(the_repository, &oid); + ret = !repo_has_object_file(the_repository, &oid); + goto cleanup; case 'w': @@ -268,7 +269,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name, ret = 0; cleanup: free(buf); - free(obj_context.path); + object_context_release(&obj_context); return ret; } @@ -520,7 +521,7 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt, struct expand_data *data) { - struct object_context ctx; + struct object_context ctx = {0}; int flags = GET_OID_HASH_ANY | (opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0); @@ -557,7 +558,8 @@ static void batch_one_object(const char *obj_name, break; } fflush(stdout); - return; + + goto out; } if (ctx.mode == 0) { @@ -565,10 +567,13 @@ static void batch_one_object(const char *obj_name, (uintmax_t)ctx.symlink_path.len, opt->output_delim, ctx.symlink_path.buf, opt->output_delim); fflush(stdout); - return; + goto out; } batch_object_write(obj_name, scratch, opt, data, NULL, 0); + +out: + object_context_release(&ctx); } struct object_cb_data { diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c index 6c43430ec4..2bda6a1d46 100644 --- a/builtin/check-ignore.c +++ b/builtin/check-ignore.c @@ -35,8 +35,8 @@ static const struct option check_ignore_options[] = { static void output_pattern(const char *path, struct path_pattern *pattern) { - char *bang = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) ? "!" : ""; - char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : ""; + const char *bang = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) ? "!" : ""; + const char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : ""; if (!nul_term_line) { if (!verbose) { write_name_quoted(path, stdout, '\n'); diff --git a/builtin/checkout.c b/builtin/checkout.c index 3cf44b4683..0f21ddd2c6 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -884,7 +884,7 @@ static int merge_working_tree(const struct checkout_opts *opts, add_files_to_cache(the_repository, NULL, NULL, NULL, 0, 0); - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); o.verbosity = 0; work = write_in_core_index_as_tree(the_repository); @@ -1572,6 +1572,10 @@ static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts, static int checkout_branch(struct checkout_opts *opts, struct branch_info *new_branch_info) { + int noop_switch = (!new_branch_info->name && + !opts->new_branch && + !opts->force_detach); + if (opts->pathspec.nr) die(_("paths cannot be used with switching branches")); @@ -1583,9 +1587,14 @@ static int checkout_branch(struct checkout_opts *opts, die(_("'%s' cannot be used with switching branches"), "--[no]-overlay"); - if (opts->writeout_stage) - die(_("'%s' cannot be used with switching branches"), - "--ours/--theirs"); + if (opts->writeout_stage) { + const char *msg; + if (noop_switch) + msg = _("'%s' needs the paths to check out"); + else + msg = _("'%s' cannot be used with switching branches"); + die(msg, "--ours/--theirs"); + } if (opts->force && opts->merge) die(_("'%s' cannot be used with '%s'"), "-f", "-m"); @@ -1612,10 +1621,8 @@ static int checkout_branch(struct checkout_opts *opts, die(_("Cannot switch branch to a non-commit '%s'"), new_branch_info->name); - if (!opts->switch_branch_doing_nothing_is_ok && - !new_branch_info->name && - !opts->new_branch && - !opts->force_detach) + if (noop_switch && + !opts->switch_branch_doing_nothing_is_ok) die(_("missing branch or commit argument")); if (!opts->implicit_detach && diff --git a/builtin/clone.c b/builtin/clone.c index 730b3efae6..af6017d41a 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -71,7 +71,7 @@ static char *option_branch = NULL; static struct string_list option_not = STRING_LIST_INIT_NODUP; static const char *real_git_dir; static const char *ref_format; -static char *option_upload_pack = "git-upload-pack"; +static const char *option_upload_pack = "git-upload-pack"; static int option_verbosity; static int option_progress = -1; static int option_sparse_checkout; @@ -177,8 +177,8 @@ static struct option builtin_clone_options[] = { static const char *get_repo_path_1(struct strbuf *path, int *is_bundle) { - static char *suffix[] = { "/.git", "", ".git/.git", ".git" }; - static char *bundle_suffix[] = { ".bundle", "" }; + static const char *suffix[] = { "/.git", "", ".git/.git", ".git" }; + static const char *bundle_suffix[] = { ".bundle", "" }; size_t baselen = path->len; struct stat st; int i; @@ -523,6 +523,9 @@ static struct ref *wanted_peer_refs(const struct ref *refs, struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD")); struct ref *local_refs = head; struct ref **tail = head ? &head->next : &local_refs; + struct refspec_item tag_refspec; + + refspec_item_init(&tag_refspec, TAG_REFSPEC, 0); if (option_single_branch) { struct ref *remote_head = NULL; @@ -530,7 +533,8 @@ static struct ref *wanted_peer_refs(const struct ref *refs, if (!option_branch) remote_head = guess_remote_head(head, refs, 0); else { - local_refs = NULL; + free_one_ref(head); + local_refs = head = NULL; tail = &local_refs; remote_head = copy_ref(find_remote_branch(refs, option_branch)); } @@ -545,7 +549,7 @@ static struct ref *wanted_peer_refs(const struct ref *refs, &tail, 0); /* if --branch=tag, pull the requested tag explicitly */ - get_fetch_map(remote_head, tag_refspec, &tail, 0); + get_fetch_map(remote_head, &tag_refspec, &tail, 0); } free_refs(remote_head); } else { @@ -555,8 +559,9 @@ static struct ref *wanted_peer_refs(const struct ref *refs, } if (!option_mirror && !option_single_branch && !option_no_tags) - get_fetch_map(refs, tag_refspec, &tail, 0); + get_fetch_map(refs, &tag_refspec, &tail, 0); + refspec_item_clear(&tag_refspec); return local_refs; } @@ -576,7 +581,7 @@ static void write_remote_refs(const struct ref *local_refs) if (!r->peer_ref) continue; if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid, - 0, NULL, &err)) + NULL, 0, NULL, &err)) die("%s", err.buf); } @@ -970,7 +975,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) int submodule_progress; int filter_submodules = 0; int hash_algo; - unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN; + enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN; const int do_not_override_repo_unix_permissions = -1; struct transport_ls_refs_options transport_ls_refs_options = @@ -1290,7 +1295,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) refspec_appendf(&remote->fetch, "+%s*:%s*", src_ref_prefix, branch_top.buf); - path = get_repo_path(remote->url[0], &is_bundle); + path = get_repo_path(remote->url.v[0], &is_bundle); is_local = option_local != 0 && path && !is_bundle; if (is_local) { if (option_depth) @@ -1312,7 +1317,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_local > 0 && !is_local) warning(_("--local is ignored")); - transport = transport_get(remote, path ? path : remote->url[0]); + transport = transport_get(remote, path ? path : remote->url.v[0]); transport_set_verbosity(transport, option_verbosity, option_progress); transport->family = family; transport->cloning = 1; diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index 1bb7819839..84bb450222 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -111,6 +111,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, OPT_END() }; + int ret; git_config(git_default_config, NULL); @@ -132,11 +133,15 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) if (commit_tree(buffer.buf, buffer.len, &tree_oid, parents, &commit_oid, NULL, sign_commit)) { - strbuf_release(&buffer); - return 1; + ret = 1; + goto out; } printf("%s\n", oid_to_hex(&commit_oid)); + ret = 0; + +out: + free_commit_list(parents); strbuf_release(&buffer); - return 0; + return ret; } diff --git a/builtin/commit.c b/builtin/commit.c index f53e7e86ff..66427ba82d 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -41,7 +41,7 @@ static const char * const builtin_commit_usage[] = { N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n" - " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]\n" + " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]\n" " [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n" " [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n" " [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n" @@ -106,14 +106,15 @@ static enum { COMMIT_PARTIAL } commit_style; -static const char *logfile, *force_author; +static const char *force_author; +static char *logfile; static char *template_file; /* * The _message variables are commit names from which to take * the commit message and/or authorship. */ static const char *author_message, *author_message_buffer; -static char *edit_message, *use_message; +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; @@ -121,8 +122,8 @@ 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 */ static int no_post_rewrite, allow_empty_message, pathspec_file_nul; -static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg; -static char *sign_commit, *pathspec_from_file; +static const char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg; +static const char *sign_commit, *pathspec_from_file; static struct strvec trailer_args = STRVEC_INIT; /* @@ -1309,7 +1310,7 @@ static int parse_and_validate_options(int argc, const char *argv[], !!use_message, "-C", !!logfile, "-F"); if (use_message || edit_message || logfile ||fixup_message || have_option_m) - template_file = NULL; + FREE_AND_NULL(template_file); if (edit_message) use_message = edit_message; if (amend && !use_message && !fixup_message) @@ -1847,7 +1848,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix) rollback_index_files(); die(_("failed to write commit object")); } - free_commit_extra_headers(extra); if (update_head_with_reflog(current_head, &oid, reflog_msg, &sb, &err)) { @@ -1889,8 +1889,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix) apply_autostash_ref(the_repository, "MERGE_AUTOSTASH"); cleanup: + free_commit_extra_headers(extra); + free_commit_list(parents); strbuf_release(&author_ident); strbuf_release(&err); strbuf_release(&sb); + free(logfile); + free(template_file); return ret; } diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c index 3db8df70a9..aaf2f8438b 100644 --- a/builtin/credential-cache.c +++ b/builtin/credential-cache.c @@ -88,6 +88,8 @@ static void spawn_daemon(const char *socket) die_errno("unable to read result code from cache daemon"); if (r != 3 || memcmp(buf, "ok\n", 3)) die("cache daemon did not start: %.*s", r, buf); + + child_process_clear(&daemon); close(daemon.out); } @@ -137,7 +139,8 @@ static void announce_capabilities(void) int cmd_credential_cache(int argc, const char **argv, const char *prefix) { - char *socket_path = NULL; + const char *socket_path_arg = NULL; + char *socket_path; int timeout = 900; const char *op; const char * const usage[] = { @@ -147,7 +150,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_INTEGER(0, "timeout", &timeout, "number of seconds to cache credentials"), - OPT_STRING(0, "socket", &socket_path, "path", + OPT_STRING(0, "socket", &socket_path_arg, "path", "path of cache-daemon socket"), OPT_END() }; @@ -160,6 +163,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix) if (!have_unix_sockets()) die(_("credential-cache unavailable; no unix socket support")); + socket_path = xstrdup_or_null(socket_path_arg); if (!socket_path) socket_path = get_socket_path(); if (!socket_path) @@ -176,6 +180,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix) else ; /* ignore unknown operation */ + free(socket_path); return 0; } diff --git a/builtin/credential-store.c b/builtin/credential-store.c index 494c809332..97968bfa1c 100644 --- a/builtin/credential-store.c +++ b/builtin/credential-store.c @@ -218,5 +218,6 @@ int cmd_credential_store(int argc, const char **argv, const char *prefix) ; /* Ignore unknown operation. */ string_list_clear(&fns, 0); + credential_clear(&c); return 0; } diff --git a/builtin/describe.c b/builtin/describe.c index e5287eddf2..954929c514 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -53,6 +53,10 @@ static const char *diff_index_args[] = { "diff-index", "--quiet", "HEAD", "--", NULL }; +static const char *update_index_args[] = { + "update-index", "--unmerged", "-q", "--refresh", NULL +}; + struct commit_name { struct hashmap_entry entry; struct object_id peeled; @@ -525,6 +529,7 @@ static void describe_blob(struct object_id oid, struct strbuf *dst) traverse_commit_list(&revs, process_commit, process_object, &pcd); reset_revision_walk(); release_revisions(&revs); + strvec_clear(&args); } static void describe(const char *arg, int last_one) @@ -615,6 +620,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix) if (contains) { struct string_list_item *item; struct strvec args; + const char **argv_copy; + int ret; strvec_init(&args); strvec_pushl(&args, "name-rev", @@ -633,7 +640,21 @@ int cmd_describe(int argc, const char **argv, const char *prefix) strvec_pushv(&args, argv); else strvec_push(&args, "HEAD"); - return cmd_name_rev(args.nr, args.v, prefix); + + /* + * `cmd_name_rev()` modifies the array, so we'd leak its + * contained strings if we didn't do a copy here. + */ + ALLOC_ARRAY(argv_copy, args.nr + 1); + for (size_t i = 0; i < args.nr; i++) + argv_copy[i] = args.v[i]; + argv_copy[args.nr] = NULL; + + ret = cmd_name_rev(args.nr, argv_copy, prefix); + + strvec_clear(&args); + free(argv_copy); + return ret; } hashmap_init(&names, commit_name_neq, NULL, 0); @@ -645,6 +666,14 @@ int cmd_describe(int argc, const char **argv, const char *prefix) if (argc == 0) { if (broken) { struct child_process cp = CHILD_PROCESS_INIT; + + strvec_pushv(&cp.args, update_index_args); + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.no_stdout = 1; + run_command(&cp); + + child_process_init(&cp); strvec_pushv(&cp.args, diff_index_args); cp.git_cmd = 1; cp.no_stdin = 1; @@ -667,7 +696,6 @@ int cmd_describe(int argc, const char **argv, const char *prefix) } else if (dirty) { struct lock_file index_lock = LOCK_INIT; struct rev_info revs; - struct strvec args = STRVEC_INIT; int fd; setup_work_tree(); @@ -682,8 +710,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix) repo_update_index_if_able(the_repository, &index_lock); repo_init_revisions(the_repository, &revs, prefix); - strvec_pushv(&args, diff_index_args); - if (setup_revisions(args.nr, args.v, &revs, NULL) != 1) + + if (setup_revisions(ARRAY_SIZE(diff_index_args) - 1, + diff_index_args, &revs, NULL) != 1) BUG("malformed internal diff-index command line"); run_diff_index(&revs, 0); diff --git a/builtin/diagnose.c b/builtin/diagnose.c index 4f22eb2b55..4857a4395b 100644 --- a/builtin/diagnose.c +++ b/builtin/diagnose.c @@ -18,7 +18,7 @@ int cmd_diagnose(int argc, const char **argv, const char *prefix) struct tm tm; enum diagnose_mode mode = DIAGNOSE_STATS; char *option_output = NULL; - char *option_suffix = "%Y-%m-%d-%H%M"; + const char *option_suffix = "%Y-%m-%d-%H%M"; char *prefixed_filename; const struct option diagnose_options[] = { diff --git a/builtin/difftool.c b/builtin/difftool.c index a1794b7eed..dcc68e190c 100644 --- a/builtin/difftool.c +++ b/builtin/difftool.c @@ -662,6 +662,9 @@ finish: free(lbase_dir); free(rbase_dir); + strbuf_release(&info); + strbuf_release(&lpath); + strbuf_release(&rpath); strbuf_release(&ldir); strbuf_release(&rdir); strbuf_release(&wtdir); diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 4693d18cc9..4b6e8c6832 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -415,7 +415,7 @@ static char *generate_fake_oid(void) struct object_id oid; char *hex = xmallocz(GIT_MAX_HEXSZ); - oidclr(&oid); + oidclr(&oid, the_repository->hash_algo); put_be32(oid.hash + hashsz - 4, counter++); return oid_to_hex_r(hex, &oid); } diff --git a/builtin/fast-import.c b/builtin/fast-import.c index d1c0243d04..d21c4053a7 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -1279,8 +1279,10 @@ static void load_tree(struct tree_entry *root) e->versions[0].mode = e->versions[1].mode; e->name = to_atom(c, strlen(c)); c += e->name->str_len + 1; - oidread(&e->versions[0].oid, (unsigned char *)c); - oidread(&e->versions[1].oid, (unsigned char *)c); + oidread(&e->versions[0].oid, (unsigned char *)c, + the_repository->hash_algo); + oidread(&e->versions[1].oid, (unsigned char *)c, + the_repository->hash_algo); c += the_hash_algo->rawsz; } free(buf); @@ -1386,7 +1388,7 @@ static void tree_content_replace( { if (!S_ISDIR(mode)) die("Root cannot be a non-directory"); - oidclr(&root->versions[0].oid); + oidclr(&root->versions[0].oid, the_repository->hash_algo); oidcpy(&root->versions[1].oid, oid); if (root->tree) release_tree_content_recursive(root->tree); @@ -1445,7 +1447,7 @@ static int tree_content_set( if (S_ISDIR(e->versions[0].mode)) e->versions[0].mode |= NO_DELTA; - oidclr(&root->versions[1].oid); + oidclr(&root->versions[1].oid, the_repository->hash_algo); return 1; } if (!S_ISDIR(e->versions[1].mode)) { @@ -1455,7 +1457,7 @@ static int tree_content_set( if (!e->tree) load_tree(e); if (tree_content_set(e, slash1 + 1, oid, mode, subtree)) { - oidclr(&root->versions[1].oid); + oidclr(&root->versions[1].oid, the_repository->hash_algo); return 1; } return 0; @@ -1467,7 +1469,7 @@ static int tree_content_set( e = new_tree_entry(); e->name = to_atom(p, n); e->versions[0].mode = 0; - oidclr(&e->versions[0].oid); + oidclr(&e->versions[0].oid, the_repository->hash_algo); t->entries[t->entry_count++] = e; if (*slash1) { e->tree = new_tree_content(8); @@ -1478,7 +1480,7 @@ static int tree_content_set( e->versions[1].mode = mode; oidcpy(&e->versions[1].oid, oid); } - oidclr(&root->versions[1].oid); + oidclr(&root->versions[1].oid, the_repository->hash_algo); return 1; } @@ -1523,7 +1525,8 @@ static int tree_content_remove( if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) { for (n = 0; n < e->tree->entry_count; n++) { if (e->tree->entries[n]->versions[1].mode) { - oidclr(&root->versions[1].oid); + oidclr(&root->versions[1].oid, + the_repository->hash_algo); return 1; } } @@ -1542,8 +1545,8 @@ del_entry: release_tree_content_recursive(e->tree); e->tree = NULL; e->versions[1].mode = 0; - oidclr(&e->versions[1].oid); - oidclr(&root->versions[1].oid); + oidclr(&e->versions[1].oid, the_repository->hash_algo); + oidclr(&root->versions[1].oid, the_repository->hash_algo); return 1; } @@ -1609,7 +1612,7 @@ static int update_branch(struct branch *b) return 0; } if (refs_read_ref(get_main_ref_store(the_repository), b->name, &old_oid)) - oidclr(&old_oid); + oidclr(&old_oid, the_repository->hash_algo); if (!force_update && !is_null_oid(&old_oid)) { struct commit *old_cmit, *new_cmit; int ret; @@ -2358,7 +2361,9 @@ static void file_change_m(const char *p, struct branch *b) parse_path_eol(&path, p, "path"); /* Git does not track empty, non-toplevel directories. */ - if (S_ISDIR(mode) && is_empty_tree_oid(&oid) && *path.buf) { + if (S_ISDIR(mode) && + is_empty_tree_oid(&oid, the_repository->hash_algo) && + *path.buf) { tree_content_remove(&b->branch_tree, path.buf, NULL, 0); return; } @@ -2550,8 +2555,8 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa static void file_change_deleteall(struct branch *b) { release_tree_content_recursive(b->branch_tree.tree); - oidclr(&b->branch_tree.versions[0].oid); - oidclr(&b->branch_tree.versions[1].oid); + oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo); + oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo); load_tree(&b->branch_tree); b->num_notes = 0; } @@ -2570,8 +2575,8 @@ static void parse_from_commit(struct branch *b, char *buf, unsigned long size) static void parse_from_existing(struct branch *b) { if (is_null_oid(&b->oid)) { - oidclr(&b->branch_tree.versions[0].oid); - oidclr(&b->branch_tree.versions[1].oid); + oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo); + oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo); } else { unsigned long size; char *buf; @@ -2894,9 +2899,9 @@ static void parse_reset_branch(const char *arg) b = lookup_branch(arg); if (b) { - oidclr(&b->oid); - oidclr(&b->branch_tree.versions[0].oid); - oidclr(&b->branch_tree.versions[1].oid); + oidclr(&b->oid, the_repository->hash_algo); + oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo); + oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo); if (b->branch_tree.tree) { release_tree_content_recursive(b->branch_tree.tree); b->branch_tree.tree = NULL; diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 44c05ee86c..af329e8d5c 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -29,11 +29,11 @@ static void add_sought_entry(struct ref ***sought, int *nr, int *alloc, ; /* <oid>, leave oid as name */ } else { /* <ref>, clear cruft from oid */ - oidclr(&oid); + oidclr(&oid, the_repository->hash_algo); } } else { /* <ref>, clear cruft from get_oid_hex */ - oidclr(&oid); + oidclr(&oid, the_repository->hash_algo); } ref = alloc_ref(name); diff --git a/builtin/fetch.c b/builtin/fetch.c index a319954f9f..693f02b958 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -582,11 +582,16 @@ static struct ref *get_ref_map(struct remote *remote, } } - if (tags == TAGS_SET) + if (tags == TAGS_SET) { + struct refspec_item tag_refspec; + /* also fetch all tags */ - get_fetch_map(remote_refs, tag_refspec, &tail, 0); - else if (tags == TAGS_DEFAULT && *autotags) + refspec_item_init(&tag_refspec, TAG_REFSPEC, 0); + get_fetch_map(remote_refs, &tag_refspec, &tail, 0); + refspec_item_clear(&tag_refspec); + } else if (tags == TAGS_DEFAULT && *autotags) { find_non_local_tags(remote_refs, NULL, &ref_map, &tail); + } /* Now append any refs to be updated opportunistically: */ *tail = orefs; @@ -1386,8 +1391,8 @@ static int prune_refs(struct display_state *display_state, if (!dry_run) { if (transaction) { for (ref = stale_refs; ref; ref = ref->next) { - result = ref_transaction_delete(transaction, ref->name, NULL, 0, - "fetch: prune", &err); + result = ref_transaction_delete(transaction, ref->name, NULL, + NULL, 0, "fetch: prune", &err); if (result) goto cleanup; } diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 0f9855b680..957786d1b3 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -11,7 +11,7 @@ static const char * const fmt_merge_msg_usage[] = { int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) { - const char *inpath = NULL; + char *inpath = NULL; const char *message = NULL; char *into_name = NULL; int shortlog_len = -1; @@ -66,5 +66,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) if (ret) return ret; write_in_full(STDOUT_FILENO, output.buf, output.len); + + free(inpath); return 0; } diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c index 66a7389f9f..7195a072ed 100644 --- a/builtin/get-tar-commit-id.c +++ b/builtin/get-tar-commit-id.c @@ -35,6 +35,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv UNUSED, const char *prefix if (header->typeflag[0] != TYPEFLAG_GLOBAL_HEADER) return 1; + errno = 0; len = strtol(content, &end, 10); if (errno == ERANGE || end == content || len < 0) return 1; diff --git a/builtin/grep.c b/builtin/grep.c index 5777ba82a9..dfc3c3e8bd 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1114,7 +1114,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) for (i = 0; i < argc; i++) { const char *arg = argv[i]; struct object_id oid; - struct object_context oc; + struct object_context oc = {0}; struct object *object; if (!strcmp(arg, "--")) { @@ -1140,7 +1140,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (!seen_dashdash) verify_non_filename(prefix, arg); add_object_array_with_path(object, arg, &list, oc.mode, oc.path); - free(oc.path); + object_context_release(&oc); } /* diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 856428fef9..fd968d673d 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -528,7 +528,8 @@ static void *unpack_raw_entry(struct object_entry *obj, switch (obj->type) { case OBJ_REF_DELTA: - oidread(ref_oid, fill(the_hash_algo->rawsz)); + oidread(ref_oid, fill(the_hash_algo->rawsz), + the_repository->hash_algo); use(the_hash_algo->rawsz); break; case OBJ_OFS_DELTA: @@ -1204,7 +1205,7 @@ static void parse_pack_objects(unsigned char *hash) the_hash_algo->init_fn(&tmp_ctx); the_hash_algo->clone_fn(&tmp_ctx, &input_ctx); the_hash_algo->final_fn(hash, &tmp_ctx); - if (!hasheq(fill(the_hash_algo->rawsz), hash)) + if (!hasheq(fill(the_hash_algo->rawsz), hash, the_repository->hash_algo)) die(_("pack is corrupted (SHA1 mismatch)")); use(the_hash_algo->rawsz); @@ -1307,11 +1308,11 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha stop_progress_msg(&progress, msg.buf); strbuf_release(&msg); finalize_hashfile(f, tail_hash, FSYNC_COMPONENT_PACK, 0); - hashcpy(read_hash, pack_hash); + hashcpy(read_hash, pack_hash, the_repository->hash_algo); fixup_pack_header_footer(output_fd, pack_hash, curr_pack, nr_objects, read_hash, consumed_bytes-the_hash_algo->rawsz); - if (!hasheq(read_hash, tail_hash)) + if (!hasheq(read_hash, tail_hash, the_repository->hash_algo)) die(_("Unexpected tail checksum for %s " "(disk corruption?)"), curr_pack); } @@ -1372,7 +1373,7 @@ static struct object_entry *append_obj_to_pack(struct hashfile *f, obj[1].idx.offset += write_compressed(f, buf, size); obj[0].idx.crc32 = crc32_end(f); hashflush(f); - oidread(&obj->idx.oid, sha1); + oidread(&obj->idx.oid, sha1, the_repository->hash_algo); return obj; } diff --git a/builtin/init-db.c b/builtin/init-db.c index 0170469b84..582dcf20f8 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -81,7 +81,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) const char *ref_format = NULL; const char *initial_branch = NULL; int hash_algo = GIT_HASH_UNKNOWN; - unsigned int ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN; + enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN; int init_shared_repository = -1; const struct option init_db_options[] = { OPT_STRING(0, "template", &template_dir, N_("template-directory"), diff --git a/builtin/log.c b/builtin/log.c index 78a247d8a9..a73a767606 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -4,7 +4,7 @@ * (C) Copyright 2006 Linus Torvalds * 2006 Junio Hamano */ -#include "git-compat-util.h" +#include "builtin.h" #include "abspath.h" #include "config.h" #include "environment.h" @@ -682,7 +682,7 @@ static void show_tagger(const char *buf, struct rev_info *rev) static int show_blob_object(const struct object_id *oid, struct rev_info *rev, const char *obj_name) { struct object_id oidc; - struct object_context obj_context; + struct object_context obj_context = {0}; char *buf; unsigned long size; @@ -698,7 +698,7 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c if (!obj_context.path || !textconv_object(the_repository, obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) { - free(obj_context.path); + object_context_release(&obj_context); return stream_blob_to_fd(1, oid, NULL, 0); } @@ -706,7 +706,7 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c die(_("git show %s: bad file"), obj_name); write_or_die(1, buf, size); - free(obj_context.path); + object_context_release(&obj_context); return 0; } @@ -1283,7 +1283,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids) o2->flags = flags2; } -static void gen_message_id(struct rev_info *info, char *base) +static void gen_message_id(struct rev_info *info, const char *base) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%s.%"PRItime".git.%s", base, @@ -1434,6 +1434,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file, int need_8bit_cte = 0; struct pretty_print_context pp = {0}; struct commit *head = list[0]; + char *to_free = NULL; if (!cmit_fmt_is_mail(rev->commit_format)) die(_("cover letter needs email format")); @@ -1455,7 +1456,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file, } if (!branch_name) - branch_name = find_branch_name(rev); + branch_name = to_free = find_branch_name(rev); pp.fmt = CMIT_FMT_EMAIL; pp.date_mode.type = DATE_RFC2822; @@ -1466,6 +1467,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file, encoding, need_8bit_cte, cfg); fprintf(rev->diffopt.file, "%s\n", sb.buf); + free(to_free); free(pp.after_subject); strbuf_release(&sb); @@ -1938,7 +1940,7 @@ static void print_bases(struct base_tree_info *bases, FILE *file) free(bases->patch_id); bases->nr_patch_id = 0; bases->alloc_patch_id = 0; - oidclr(&bases->base_commit); + oidclr(&bases->base_commit, the_repository->hash_algo); } static const char *diff_title(struct strbuf *sb, @@ -2021,7 +2023,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) const char *rfc = NULL; int creation_factor = -1; const char *signature = git_version_string; - const char *signature_file_arg = NULL; + char *signature_file_arg = NULL; struct keep_callback_data keep_callback_data = { .cfg = &cfg, .revs = &rev, @@ -2382,6 +2384,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (cover_letter == -1) { if (cfg.config_cover_letter == COVER_AUTO) cover_letter = (total > 1); + else if ((idiff_prev.nr || rdiff_prev) && (total > 1)) + cover_letter = (cfg.config_cover_letter != COVER_OFF); else cover_letter = (cfg.config_cover_letter == COVER_ON); } @@ -2559,6 +2563,8 @@ done: strbuf_release(&rdiff1); strbuf_release(&rdiff2); strbuf_release(&rdiff_title); + free(description_file); + free(signature_file_arg); free(to_free); free(rev.message_id); if (rev.ref_message_ids) @@ -2673,16 +2679,16 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) commit_list_insert(commit, &list); } - while (list) { + for (struct commit_list *l = list; l; l = l->next) { char sign = '+'; - commit = list->item; + commit = l->item; if (has_commit_patch_id(commit, &ids)) sign = '-'; print_commit(sign, commit, verbose, abbrev, revs.diffopt.file); - list = list->next; } + free_commit_list(list); free_patch_ids(&ids); return 0; } diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index e8d65ebbdc..0a491595ca 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -9,7 +9,7 @@ #include "wildmatch.h" static const char * const ls_remote_usage[] = { - N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" + N_("git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]"), NULL @@ -19,17 +19,16 @@ static const char * const ls_remote_usage[] = { * Is there one among the list of patterns that match the tail part * of the path? */ -static int tail_match(const char **pattern, const char *path) +static int tail_match(const struct strvec *pattern, const char *path) { - const char *p; char *pathbuf; - if (!pattern) + if (!pattern->nr) return 1; /* no restriction */ pathbuf = xstrfmt("/%s", path); - while ((p = *(pattern++)) != NULL) { - if (!wildmatch(p, pathbuf, 0)) { + for (size_t i = 0; i < pattern->nr; i++) { + if (!wildmatch(pattern->v[i], pathbuf, 0)) { free(pathbuf); return 1; } @@ -47,7 +46,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) int status = 0; int show_symref_target = 0; const char *uploadpack = NULL; - const char **pattern = NULL; + struct strvec pattern = STRVEC_INIT; struct transport_ls_refs_options transport_options = TRANSPORT_LS_REFS_OPTIONS_INIT; int i; @@ -68,7 +67,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) N_("path of git-upload-pack on the remote host"), PARSE_OPT_HIDDEN }, OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS), - OPT_BIT('h', "heads", &flags, N_("limit to heads"), REF_HEADS), + OPT_BIT('b', "branches", &flags, N_("limit to branches"), REF_BRANCHES), + OPT_BIT_F('h', "heads", &flags, + N_("deprecated synonym for --branches"), REF_BRANCHES, + PARSE_OPT_HIDDEN), OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL), OPT_BOOL(0, "get-url", &get_url, N_("take url.<base>.insteadOf into account")), @@ -88,19 +90,29 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) PARSE_OPT_STOP_AT_NON_OPTION); dest = argv[0]; + /* + * TODO: This is buggy, but required for transport helpers. When a + * transport helper advertises a "refspec", then we'd add that to a + * list of refspecs via `refspec_append()`, which transitively depends + * on `the_hash_algo`. Thus, when the hash algorithm isn't properly set + * up, this would lead to a segfault. + * + * We really should fix this in the transport helper logic such that we + * lazily parse refspec capabilities _after_ we have learned about the + * remote's object format. Otherwise, we may end up misparsing refspecs + * depending on what object hash the remote uses. + */ + if (!the_repository->hash_algo) + repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + packet_trace_identity("ls-remote"); - if (argc > 1) { - int i; - CALLOC_ARRAY(pattern, argc); - for (i = 1; i < argc; i++) { - pattern[i - 1] = xstrfmt("*/%s", argv[i]); - } - } + for (int i = 1; i < argc; i++) + strvec_pushf(&pattern, "*/%s", argv[i]); if (flags & REF_TAGS) strvec_push(&transport_options.ref_prefixes, "refs/tags/"); - if (flags & REF_HEADS) + if (flags & REF_BRANCHES) strvec_push(&transport_options.ref_prefixes, "refs/heads/"); remote = remote_get(dest); @@ -109,11 +121,9 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) die("bad repository '%s'", dest); die("No remote configured to list refs from."); } - if (!remote->url_nr) - die("remote %s has no configured URL", dest); if (get_url) { - printf("%s\n", *remote->url); + printf("%s\n", remote->url.v[0]); return 0; } @@ -130,12 +140,12 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) } if (!dest && !quiet) - fprintf(stderr, "From %s\n", *remote->url); + fprintf(stderr, "From %s\n", remote->url.v[0]); for ( ; ref; ref = ref->next) { struct ref_array_item *item; if (!check_ref_type(ref, flags)) continue; - if (!tail_match(pattern, ref->name)) + if (!tail_match(&pattern, ref->name)) continue; item = ref_array_push(&ref_array, ref->name, &ref->old_oid); item->symref = xstrdup_or_null(ref->symref); @@ -157,5 +167,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix) if (transport_disconnect(transport)) status = 1; transport_ls_refs_options_release(&transport_options); + + strvec_clear(&pattern); return status; } diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 7bf84b235c..bf372c67d7 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -367,7 +367,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix) OPT_END() }; struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format; - struct object_context obj_context; + struct object_context obj_context = {0}; int ret; git_config(git_default_config, NULL); @@ -441,5 +441,6 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix) ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options); clear_pathspec(&options.pathspec); + object_context_release(&obj_context); return ret; } diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c index 3af9ddb8ae..fe6dbc5d05 100644 --- a/builtin/mailsplit.c +++ b/builtin/mailsplit.c @@ -113,8 +113,8 @@ static int populate_maildir_list(struct string_list *list, const char *path) DIR *dir; struct dirent *dent; char *name = NULL; - char *subs[] = { "cur", "new", NULL }; - char **sub; + const char *subs[] = { "cur", "new", NULL }; + const char **sub; int ret = -1; for (sub = subs; *sub; ++sub) { diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c index c2ce044a20..e951b09805 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -23,7 +23,7 @@ static char *better_branch_name(const char *branch) int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED) { - const struct object_id *bases[21]; + struct object_id bases[21]; unsigned bases_count = 0; int i, failed; struct object_id h1, h2; @@ -31,7 +31,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED) char *better1, *better2; struct commit *result; - init_merge_options(&o, the_repository); + init_basic_merge_options(&o, the_repository); if (argv[0] && ends_with(argv[0], "-subtree")) o.subtree_shift = ""; @@ -49,10 +49,8 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED) continue; } if (bases_count < ARRAY_SIZE(bases)-1) { - struct object_id *oid = xmalloc(sizeof(struct object_id)); - if (repo_get_oid(the_repository, argv[i], oid)) + if (repo_get_oid(the_repository, argv[i], &bases[bases_count++])) die(_("could not parse object '%s'"), argv[i]); - bases[bases_count++] = oid; } else warning(Q_("cannot handle more than %d base. " diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c index 1082d919fd..9bca9b5f33 100644 --- a/builtin/merge-tree.c +++ b/builtin/merge-tree.c @@ -482,6 +482,7 @@ static int real_merge(struct merge_tree_options *o, die(_("refusing to merge unrelated histories")); merge_bases = reverse_commit_list(merge_bases); merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result); + free_commit_list(merge_bases); } if (result.clean < 0) @@ -570,7 +571,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix) }; /* Init merge options */ - init_merge_options(&o.merge_options, the_repository); + init_ui_merge_options(&o.merge_options, the_repository); /* Parse arguments */ original_argc = argc - 1; /* ignoring argv[0] */ diff --git a/builtin/merge.c b/builtin/merge.c index daed2d4e1e..c896b18d1a 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -164,7 +164,7 @@ static struct strategy *get_strategy(const char *name) { int i; struct strategy *ret; - static struct cmdnames main_cmds, other_cmds; + static struct cmdnames main_cmds = {0}, other_cmds = {0}; static int loaded; char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM"); @@ -182,10 +182,9 @@ static struct strategy *get_strategy(const char *name) return &all_strategy[i]; if (!loaded) { - struct cmdnames not_strategies; + struct cmdnames not_strategies = {0}; loaded = 1; - memset(¬_strategies, 0, sizeof(struct cmdnames)); load_command_list("git-merge-", &main_cmds, &other_cmds); for (i = 0; i < main_cmds.cnt; i++) { int j, found = 0; @@ -197,6 +196,8 @@ static struct strategy *get_strategy(const char *name) add_cmdname(¬_strategies, ent->name, ent->len); } exclude_cmds(&main_cmds, ¬_strategies); + + cmdnames_release(¬_strategies); } if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) { fprintf(stderr, _("Could not find merge strategy '%s'.\n"), name); @@ -216,6 +217,9 @@ static struct strategy *get_strategy(const char *name) CALLOC_ARRAY(ret, 1); ret->name = xstrdup(name); ret->attr = NO_TRIVIAL; + + cmdnames_release(&main_cmds); + cmdnames_release(&other_cmds); return ret; } @@ -330,7 +334,8 @@ static void read_empty(const struct object_id *oid) { struct child_process cmd = CHILD_PROCESS_INIT; - strvec_pushl(&cmd.args, "read-tree", "-m", "-u", empty_tree_oid_hex(), + strvec_pushl(&cmd.args, "read-tree", "-m", "-u", + empty_tree_oid_hex(the_repository->hash_algo), oid_to_hex(oid), NULL); cmd.git_cmd = 1; @@ -494,7 +499,7 @@ static void merge_name(const char *remote, struct strbuf *msg) strbuf_branchname(&bname, remote, 0); remote = bname.buf; - oidclr(&branch_head); + oidclr(&branch_head, the_repository->hash_algo); remote_head = get_merge_parent(remote); if (!remote_head) die(_("'%s' does not point to a commit"), remote); @@ -611,17 +616,19 @@ static int git_merge_config(const char *k, const char *v, return 0; } - if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat")) + if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat")) { show_diffstat = git_config_bool(k, v); - else if (!strcmp(k, "merge.verifysignatures")) + } else if (!strcmp(k, "merge.verifysignatures")) { verify_signatures = git_config_bool(k, v); - else if (!strcmp(k, "pull.twohead")) + } else if (!strcmp(k, "pull.twohead")) { + FREE_AND_NULL(pull_twohead); return git_config_string(&pull_twohead, k, v); - else if (!strcmp(k, "pull.octopus")) + } else if (!strcmp(k, "pull.octopus")) { + FREE_AND_NULL(pull_octopus); return git_config_string(&pull_octopus, k, v); - else if (!strcmp(k, "commit.cleanup")) + } else if (!strcmp(k, "commit.cleanup")) { return git_config_string(&cleanup_arg, k, v); - else if (!strcmp(k, "merge.ff")) { + } else if (!strcmp(k, "merge.ff")) { int boolval = git_parse_maybe_bool(v); if (0 <= boolval) { fast_forward = boolval ? FF_ALLOW : FF_NO; @@ -701,7 +708,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, SKIP_IF_UNCHANGED, 0, NULL, NULL, NULL) < 0) - return error(_("Unable to write index.")); + die(_("Unable to write index.")); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree") || !strcmp(strategy, "ort")) { @@ -717,7 +724,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, return 2; } - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); if (!strcmp(strategy, "subtree")) o.subtree_shift = ""; @@ -742,6 +749,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, else clean = merge_recursive(&o, head, remoteheads->item, reversed, &result); + free_commit_list(reversed); + if (clean < 0) { rollback_lock_file(&lock); return 2; @@ -895,7 +904,7 @@ static void prepare_to_commit(struct commit_list *remoteheads) static int merge_trivial(struct commit *head, struct commit_list *remoteheads) { struct object_id result_tree, result_commit; - struct commit_list *parents, **pptr = &parents; + struct commit_list *parents = NULL, **pptr = &parents; if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, SKIP_IF_UNCHANGED, 0, NULL, NULL, @@ -911,7 +920,9 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads) &result_commit, NULL, sign_commit)) die(_("failed to write commit object")); finish(head, remoteheads, &result_commit, "In-index merge"); + remove_merge_branch_state(the_repository); + free_commit_list(parents); return 0; } @@ -937,8 +948,10 @@ static int finish_automerge(struct commit *head, die(_("failed to write commit object")); strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy); finish(head, remoteheads, &result_commit, buf.buf); + strbuf_release(&buf); remove_merge_branch_state(the_repository); + free_commit_list(parents); return 0; } @@ -1294,7 +1307,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (!pull_twohead) { char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM"); if (default_strategy && !strcmp(default_strategy, "ort")) - pull_twohead = "ort"; + pull_twohead = xstrdup("ort"); } init_diff_ui_defaults(); @@ -1690,7 +1703,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * index and working tree polluted. */ if (save_state(&stash)) - oidclr(&stash); + oidclr(&stash, the_repository->hash_algo); for (i = 0; i < use_strategies_nr; i++) { int ret, cnt; @@ -1793,6 +1806,8 @@ done: } strbuf_release(&buf); free(branch_to_free); + free(pull_twohead); + free(pull_octopus); discard_index(the_repository->index); return ret; } diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c index 8360932d2e..9cf1a32d65 100644 --- a/builtin/multi-pack-index.c +++ b/builtin/multi-pack-index.c @@ -50,7 +50,7 @@ static char const * const builtin_multi_pack_index_usage[] = { static struct opts_multi_pack_index { char *object_dir; const char *preferred_pack; - const char *refs_snapshot; + char *refs_snapshot; unsigned long batch_size; unsigned flags; int stdin_packs; @@ -135,6 +135,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, N_("refs snapshot for selecting bitmap commits")), OPT_END(), }; + int ret; opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE; @@ -157,7 +158,6 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, if (opts.stdin_packs) { struct string_list packs = STRING_LIST_INIT_DUP; - int ret; read_packs_from_stdin(&packs); @@ -166,12 +166,17 @@ static int cmd_multi_pack_index_write(int argc, const char **argv, opts.refs_snapshot, opts.flags); string_list_clear(&packs, 0); + free(opts.refs_snapshot); return ret; } - return write_midx_file(opts.object_dir, opts.preferred_pack, - opts.refs_snapshot, opts.flags); + + ret = write_midx_file(opts.object_dir, opts.preferred_pack, + opts.refs_snapshot, opts.flags); + + free(opts.refs_snapshot); + return ret; } static int cmd_multi_pack_index_verify(int argc, const char **argv, diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 70e9ec4e47..f62c0a36cb 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -677,7 +677,9 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix) always, allow_undefined, data.name_only); } - UNLEAK(string_pool); - UNLEAK(revs); + string_list_clear(&data.ref_filters, 0); + string_list_clear(&data.exclude_filters, 0); + mem_pool_discard(&string_pool, 0); + object_array_clear(&revs); return 0; } diff --git a/builtin/notes.c b/builtin/notes.c index 7f80b3449b..4cc5bfedc3 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -114,7 +114,6 @@ struct note_msg { }; struct note_data { - int given; int use_editor; int stripspace; char *edit_path; @@ -193,7 +192,7 @@ static void write_commented_object(int fd, const struct object_id *object) static void prepare_note_data(const struct object_id *object, struct note_data *d, const struct object_id *old_note) { - if (d->use_editor || !d->given) { + if (d->use_editor || !d->msg_nr) { int fd; struct strbuf buf = STRBUF_INIT; @@ -201,7 +200,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data * d->edit_path = git_pathdup("NOTES_EDITMSG"); fd = xopen(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600); - if (d->given) + if (d->msg_nr) write_or_die(fd, d->buf.buf, d->buf.len); else if (old_note) copy_obj_to_fd(fd, old_note); @@ -515,7 +514,6 @@ static int add(int argc, const char **argv, const char *prefix) if (d.msg_nr) concat_messages(&d); - d.given = !!d.buf.len; object_ref = argc > 1 ? argv[1] : "HEAD"; @@ -528,7 +526,7 @@ static int add(int argc, const char **argv, const char *prefix) if (note) { if (!force) { free_notes(t); - if (d.given) { + if (d.msg_nr) { free_note_data(&d); return error(_("Cannot add notes. " "Found existing notes for object %s. " @@ -690,14 +688,14 @@ static int append_edit(int argc, const char **argv, const char *prefix) usage_with_options(usage, options); } - if (d.msg_nr) + if (d.msg_nr) { concat_messages(&d); - d.given = !!d.buf.len; - - if (d.given && edit) - fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated " - "for the 'edit' subcommand.\n" - "Please use 'git notes add -f -m/-F/-c/-C' instead.\n")); + if (edit) + fprintf(stderr, _("The -m/-F/-c/-C options have been " + "deprecated for the 'edit' subcommand.\n" + "Please use 'git notes add -f -m/-F/-c/-C' " + "instead.\n")); + } object_ref = 1 < argc ? argv[1] : "HEAD"; @@ -828,7 +826,7 @@ static int merge_commit(struct notes_merge_options *o) if (partial->parents) oidcpy(&parent_oid, &partial->parents->item->object.oid); else - oidclr(&parent_oid); + oidclr(&parent_oid, the_repository->hash_algo); CALLOC_ARRAY(t, 1); init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 638f5c57f0..f395488971 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1341,7 +1341,8 @@ static void write_pack_file(void) hash_to_hex(hash)); if (write_bitmap_index) { - bitmap_writer_init(&bitmap_writer); + bitmap_writer_init(&bitmap_writer, + the_repository); bitmap_writer_set_checksum(&bitmap_writer, hash); bitmap_writer_build_type_index(&bitmap_writer, &to_pack, written_list, nr_written); @@ -2078,7 +2079,8 @@ static void check_object(struct object_entry *entry, uint32_t object_index) oidread(&base_ref, use_pack(p, &w_curs, entry->in_pack_offset + used, - NULL)); + NULL), + the_repository->hash_algo); have_base = 1; } entry->in_pack_header_size = used + the_hash_algo->rawsz; diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index 4c735ba069..dd9bf35f5b 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -100,7 +100,7 @@ static inline struct llist_item *llist_insert(struct llist *list, const unsigned char *oid) { struct llist_item *new_item = llist_item_get(); - oidread(&new_item->oid, oid); + oidread(&new_item->oid, oid, the_repository->hash_algo); new_item->next = NULL; if (after) { @@ -155,7 +155,7 @@ redo_from_start: l = (hint == NULL) ? list->front : hint; prev = NULL; while (l) { - const int cmp = hashcmp(l->oid.hash, oid); + const int cmp = hashcmp(l->oid.hash, oid, the_repository->hash_algo); if (cmp > 0) /* not in list, since sorted */ return prev; if (!cmp) { /* found */ @@ -258,7 +258,8 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2) while (p1_off < p1->pack->num_objects * p1_step && p2_off < p2->pack->num_objects * p2_step) { - const int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off); + const int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off, + the_repository->hash_algo); /* cmp ~ p1 - p2 */ if (cmp == 0) { p1_hint = llist_sorted_remove(p1->unique_objects, @@ -296,7 +297,8 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2) while (p1_off < p1->num_objects * p1_step && p2_off < p2->num_objects * p2_step) { - int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off); + int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off, + the_repository->hash_algo); /* cmp ~ p1 - p2 */ if (cmp == 0) { ret++; diff --git a/builtin/patch-id.c b/builtin/patch-id.c index 583099cacf..35c1179f7e 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -7,10 +7,9 @@ #include "parse-options.h" #include "setup.h" -static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result) +static void flush_current_id(struct object_id *id, struct object_id *result) { - if (patchlen) - printf("%s %s\n", oid_to_hex(result), oid_to_hex(id)); + printf("%s %s\n", oid_to_hex(result), oid_to_hex(id)); } static int remove_space(char *line) @@ -60,9 +59,27 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after) return 1; } +/* + * flag bits to control get_one_patchid()'s behaviour. + * + * STABLE/VERBATIM are given from the command line option as + * --stable/--verbatim. FIND_HEADER conveys the internal state + * maintained by the caller to allow the function to avoid mistaking + * lines of log message before seeing the "diff" part as the beginning + * of the next patch. + */ +enum { + GOPID_STABLE = (1<<0), /* --stable */ + GOPID_VERBATIM = (1<<1), /* --verbatim */ + GOPID_FIND_HEADER = (1<<2), /* stop at the beginning of patch message */ +}; + static int get_one_patchid(struct object_id *next_oid, struct object_id *result, - struct strbuf *line_buf, int stable, int verbatim) + struct strbuf *line_buf, unsigned flags) { + int stable = flags & GOPID_STABLE; + int verbatim = flags & GOPID_VERBATIM; + int find_header = flags & GOPID_FIND_HEADER; int patchlen = 0, found_next = 0; int before = -1, after = -1; int diff_is_binary = 0; @@ -70,31 +87,47 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result, git_hash_ctx ctx; the_hash_algo->init_fn(&ctx); - oidclr(result); + oidclr(result, the_repository->hash_algo); while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) { char *line = line_buf->buf; const char *p = line; int len; - /* Possibly skip over the prefix added by "log" or "format-patch" */ - if (!skip_prefix(line, "commit ", &p) && - !skip_prefix(line, "From ", &p) && - starts_with(line, "\\ ") && 12 < strlen(line)) { - if (verbatim) - the_hash_algo->update_fn(&ctx, line, strlen(line)); - continue; - } - - if (!get_oid_hex(p, next_oid)) { - found_next = 1; - break; + /* + * The caller hasn't seen us find a patch header and + * return to it, or we have started processing patch + * and may encounter the beginning of the next patch. + */ + if (find_header) { + /* + * If we see a line that begins with "<object name>", + * "commit <object name>" or "From <object name>", it is + * the beginning of a patch. Return to the caller, as + * we are done with the one we have been processing. + */ + if (skip_prefix(line, "commit ", &p)) + ; + else if (skip_prefix(line, "From ", &p)) + ; + if (!get_oid_hex(p, next_oid)) { + if (verbatim) + the_hash_algo->update_fn(&ctx, line, strlen(line)); + found_next = 1; + break; + } } /* Ignore commit comments */ if (!patchlen && !starts_with(line, "diff ")) continue; + /* + * We are past the commit log message. Prepare to + * stop at the beginning of the next patch header. + */ + find_header = 1; + /* Parsing diff header? */ if (before == -1) { if (starts_with(line, "GIT binary patch") || @@ -127,6 +160,16 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result, break; } + /* + * A hunk about an incomplete line may have this + * marker at the end, which should just be ignored. + */ + if (starts_with(line, "\\ ") && 12 < strlen(line)) { + if (verbatim) + the_hash_algo->update_fn(&ctx, line, strlen(line)); + continue; + } + if (diff_is_binary) { if (starts_with(line, "diff ")) { diff_is_binary = 0; @@ -166,24 +209,27 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result, } if (!found_next) - oidclr(next_oid); + oidclr(next_oid, the_repository->hash_algo); flush_one_hunk(result, &ctx); return patchlen; } -static void generate_id_list(int stable, int verbatim) +static void generate_id_list(unsigned flags) { struct object_id oid, n, result; int patchlen; struct strbuf line_buf = STRBUF_INIT; - oidclr(&oid); + oidclr(&oid, the_repository->hash_algo); + flags |= GOPID_FIND_HEADER; while (!feof(stdin)) { - patchlen = get_one_patchid(&n, &result, &line_buf, stable, verbatim); - flush_current_id(patchlen, &oid, &result); + patchlen = get_one_patchid(&n, &result, &line_buf, flags); + if (patchlen) + flush_current_id(&oid, &result); oidcpy(&oid, &n); + flags &= ~GOPID_FIND_HEADER; } strbuf_release(&line_buf); } @@ -219,6 +265,7 @@ int cmd_patch_id(int argc, const char **argv, const char *prefix) /* if nothing is set, default to unstable */ struct patch_id_opts config = {0, 0}; int opts = 0; + unsigned flags = 0; struct option builtin_patch_id_options[] = { OPT_CMDMODE(0, "unstable", &opts, N_("use the unstable patch-id algorithm"), 1), @@ -250,7 +297,11 @@ int cmd_patch_id(int argc, const char **argv, const char *prefix) if (!the_hash_algo) repo_set_hash_algo(the_repository, GIT_HASH_SHA1); - generate_id_list(opts ? opts > 1 : config.stable, - opts ? opts == 3 : config.verbatim); + if (opts ? opts > 1 : config.stable) + flags |= GOPID_STABLE; + if (opts ? opts == 3 : config.verbatim) + flags |= GOPID_VERBATIM; + generate_id_list(flags); + return 0; } diff --git a/builtin/pull.c b/builtin/pull.c index d622202bce..4c54d8196f 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -71,48 +71,48 @@ static const char * const pull_usage[] = { /* Shared options */ static int opt_verbosity; -static char *opt_progress; +static const char *opt_progress; static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT; /* Options passed to git-merge or git-rebase */ static enum rebase_type opt_rebase = -1; -static char *opt_diffstat; -static char *opt_log; -static char *opt_signoff; -static char *opt_squash; -static char *opt_commit; -static char *opt_edit; -static char *cleanup_arg; -static char *opt_ff; -static char *opt_verify_signatures; -static char *opt_verify; +static const char *opt_diffstat; +static const char *opt_log; +static const char *opt_signoff; +static const char *opt_squash; +static const char *opt_commit; +static const char *opt_edit; +static const char *cleanup_arg; +static const 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 check_trust_level = 1; static struct strvec opt_strategies = STRVEC_INIT; static struct strvec opt_strategy_opts = STRVEC_INIT; -static char *opt_gpg_sign; +static const char *opt_gpg_sign; static int opt_allow_unrelated_histories; /* Options passed to git-fetch */ -static char *opt_all; -static char *opt_append; -static char *opt_upload_pack; +static const char *opt_all; +static const char *opt_append; +static const char *opt_upload_pack; static int opt_force; -static char *opt_tags; -static char *opt_prune; -static char *max_children; +static const char *opt_tags; +static const char *opt_prune; +static const char *max_children; static int opt_dry_run; -static char *opt_keep; -static char *opt_depth; -static char *opt_unshallow; -static char *opt_update_shallow; -static char *opt_refmap; -static char *opt_ipv4; -static char *opt_ipv6; +static const char *opt_keep; +static const char *opt_depth; +static const char *opt_unshallow; +static const char *opt_update_shallow; +static const char *opt_refmap; +static const char *opt_ipv4; +static const char *opt_ipv6; static int opt_show_forced_updates = -1; -static char *set_upstream; +static const char *set_upstream; static struct strvec opt_fetch = STRVEC_INIT; static struct option pull_options[] = { @@ -1038,7 +1038,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix) die_conclude_merge(); if (repo_get_oid(the_repository, "HEAD", &orig_head)) - oidclr(&orig_head); + oidclr(&orig_head, the_repository->hash_algo); if (opt_rebase) { if (opt_autostash == -1) @@ -1053,7 +1053,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix) _("Please commit or stash them."), 1, 0); if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs)) - oidclr(&rebase_fork_point); + oidclr(&rebase_fork_point, the_repository->hash_algo); } if (run_fetch(repo, refspecs)) @@ -1063,7 +1063,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix) return 0; if (repo_get_oid(the_repository, "HEAD", &curr_head)) - oidclr(&curr_head); + oidclr(&curr_head, the_repository->hash_algo); if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) && !oideq(&orig_head, &curr_head)) { diff --git a/builtin/push.c b/builtin/push.c index 2fbb31c3ad..7a67398124 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -96,9 +96,8 @@ static void refspec_append_mapped(struct refspec *refspec, const char *ref, refspec_append(refspec, ref); } -static void set_refspecs(const char **refs, int nr, const char *repo) +static void set_refspecs(const char **refs, int nr, struct remote *remote) { - struct remote *remote = NULL; struct ref *local_refs = NULL; int i; @@ -124,33 +123,16 @@ static void set_refspecs(const char **refs, int nr, const char *repo) local_refs = get_local_heads(); /* Does "ref" uniquely name our ref? */ - if (count_refspec_match(ref, local_refs, &matched) != 1) { + if (count_refspec_match(ref, local_refs, &matched) != 1) refspec_append(&rs, ref); - } else { - /* lazily grab remote */ - if (!remote) - remote = remote_get(repo); - if (!remote) - BUG("must get a remote for repo '%s'", repo); - + else refspec_append_mapped(&rs, ref, remote, matched); - } } else refspec_append(&rs, ref); } free_refs(local_refs); } -static int push_url_of_remote(struct remote *remote, const char ***url_p) -{ - if (remote->pushurl_nr) { - *url_p = remote->pushurl; - return remote->pushurl_nr; - } - *url_p = remote->url; - return remote->url_nr; -} - static NORETURN void die_push_simple(struct branch *branch, struct remote *remote) { @@ -434,8 +416,7 @@ static int do_push(int flags, struct remote *remote) { int i, errs; - const char **url; - int url_nr; + struct strvec *url; struct refspec *push_refspec = &rs; if (push_options->nr) @@ -448,19 +429,10 @@ static int do_push(int flags, setup_default_push_refspecs(&flags, remote); } errs = 0; - url_nr = push_url_of_remote(remote, &url); - if (url_nr) { - for (i = 0; i < url_nr; i++) { - struct transport *transport = - transport_get(remote, url[i]); - if (flags & TRANSPORT_PUSH_OPTIONS) - transport->push_options = push_options; - if (push_with_options(transport, push_refspec, flags)) - errs++; - } - } else { + url = push_url_of_remote(remote); + for (i = 0; i < url->nr; i++) { struct transport *transport = - transport_get(remote, NULL); + transport_get(remote, url->v[i]); if (flags & TRANSPORT_PUSH_OPTIONS) transport->push_options = push_options; if (push_with_options(transport, push_refspec, flags)) @@ -650,10 +622,8 @@ int cmd_push(int argc, const char **argv, const char *prefix) if (tags) refspec_append(&rs, "refs/tags/*"); - if (argc > 0) { + if (argc > 0) repo = argv[0]; - set_refspecs(argv + 1, argc - 1, repo); - } remote = pushremote_get(repo); if (!remote) { @@ -669,6 +639,9 @@ int cmd_push(int argc, const char **argv, const char *prefix) " git push <name>\n")); } + if (argc > 0) + set_refspecs(argv + 1, argc - 1, remote); + if (remote->mirror) flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE); diff --git a/builtin/rebase.c b/builtin/rebase.c index 14d4f0a5e6..e3a8e74cfc 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -135,7 +135,7 @@ struct rebase_options { .type = REBASE_UNSPECIFIED, \ .empty = EMPTY_UNSPECIFIED, \ .keep_empty = 1, \ - .default_backend = "merge", \ + .default_backend = xstrdup("merge"), \ .flags = REBASE_NO_QUIET, \ .git_am_opts = STRVEC_INIT, \ .exec = STRING_LIST_INIT_NODUP, \ @@ -151,6 +151,19 @@ struct rebase_options { .strategy_opts = STRING_LIST_INIT_NODUP,\ } +static void rebase_options_release(struct rebase_options *opts) +{ + free(opts->default_backend); + free(opts->reflog_action); + free(opts->head_name); + strvec_clear(&opts->git_am_opts); + free(opts->gpg_sign_opt); + string_list_clear(&opts->exec, 0); + free(opts->strategy); + string_list_clear(&opts->strategy_opts, 0); + strbuf_release(&opts->git_format_patch_opt); +} + static struct replay_opts get_replay_opts(const struct rebase_options *opts) { struct replay_opts replay = REPLAY_OPTS_INIT; @@ -193,7 +206,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts) return replay; } -static int edit_todo_file(unsigned flags) +static int edit_todo_file(unsigned flags, struct replay_opts *opts) { const char *todo_file = rebase_path_todo(); struct todo_list todo_list = TODO_LIST_INIT, @@ -204,7 +217,8 @@ static int edit_todo_file(unsigned flags) return error_errno(_("could not read '%s'."), todo_file); strbuf_stripspace(&todo_list.buf, comment_line_str); - res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags); + res = edit_todo_list(the_repository, opts, &todo_list, &new_todo, + NULL, NULL, flags); if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file, NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS))) res = error_errno(_("could not write '%s'"), todo_file); @@ -295,8 +309,8 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) error(_("could not generate todo list")); else { discard_index(the_repository->index); - if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, - &todo_list)) + 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, @@ -351,9 +365,13 @@ static int run_sequencer_rebase(struct rebase_options *opts) replay_opts_release(&replay_opts); break; } - case ACTION_EDIT_TODO: - ret = edit_todo_file(flags); + case ACTION_EDIT_TODO: { + struct replay_opts replay_opts = get_replay_opts(opts); + + ret = edit_todo_file(flags, &replay_opts); + replay_opts_release(&replay_opts); break; + } case ACTION_SHOW_CURRENT_PATCH: { struct child_process cmd = CHILD_PROCESS_INIT; @@ -796,6 +814,7 @@ static int rebase_config(const char *var, const char *value, } if (!strcmp(var, "rebase.backend")) { + FREE_AND_NULL(opts->default_backend); return git_config_string(&opts->default_backend, var, value); } @@ -1047,6 +1066,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) { struct rebase_options options = REBASE_OPTIONS_INIT; const char *branch_name; + const char *strategy_opt = NULL; int ret, flags, total_argc, in_progress = 0; int keep_base = 0; int ok_to_skip_pre_rebase = 0; @@ -1161,7 +1181,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) PARSE_OPT_OPTARG, parse_opt_rebase_merges), OPT_BOOL(0, "fork-point", &options.fork_point, N_("use 'merge-base --fork-point' to refine upstream")), - OPT_STRING('s', "strategy", &options.strategy, + OPT_STRING('s', "strategy", &strategy_opt, N_("strategy"), N_("use the given merge strategy")), OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts, N_("option"), @@ -1470,13 +1490,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } } - if (options.strategy_opts.nr && !options.strategy) - options.strategy = "ort"; - - if (options.strategy) { - options.strategy = xstrdup(options.strategy); + if (strategy_opt) + options.strategy = xstrdup(strategy_opt); + else if (options.strategy_opts.nr && !options.strategy) + options.strategy = xstrdup("ort"); + if (options.strategy) imply_merge(&options, "--strategy"); - } if (options.root && !options.onto_name) imply_merge(&options, "--root without --onto"); @@ -1833,14 +1852,7 @@ run_rebase: cleanup: strbuf_release(&buf); strbuf_release(&revisions); - free(options.reflog_action); - free(options.head_name); - strvec_clear(&options.git_am_opts); - free(options.gpg_sign_opt); - string_list_clear(&options.exec, 0); - free(options.strategy); - string_list_clear(&options.strategy_opts, 0); - strbuf_release(&options.git_format_patch_opt); + rebase_options_release(&options); free(squash_onto_name); free(keep_base_onto_name); return !!ret; diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 01c1f04ece..339524ae2a 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -741,7 +741,7 @@ static void prepare_push_cert_sha1(struct child_process *proc) already_done = 1; if (write_object_file(push_cert.buf, push_cert.len, OBJ_BLOB, &push_cert_oid)) - oidclr(&push_cert_oid); + oidclr(&push_cert_oid, the_repository->hash_algo); memset(&sigcheck, '\0', sizeof(sigcheck)); @@ -1249,7 +1249,7 @@ cleanup: return code; } -static char *refuse_unconfigured_deny_msg = +static const char *refuse_unconfigured_deny_msg = N_("By default, updating the current branch in a non-bare repository\n" "is denied, because it will make the index and work tree inconsistent\n" "with what you pushed, and will require 'git reset --hard' to match\n" @@ -1269,7 +1269,7 @@ static void refuse_unconfigured_deny(void) rp_error("%s", _(refuse_unconfigured_deny_msg)); } -static char *refuse_unconfigured_deny_delete_current_msg = +static const char *refuse_unconfigured_deny_delete_current_msg = N_("By default, deleting the current branch is denied, because the next\n" "'git clone' won't result in any file checked out, causing confusion.\n" "\n" @@ -1371,7 +1371,7 @@ static const char *push_to_deploy(unsigned char *sha1, strvec_pushl(&child.args, "diff-index", "--quiet", "--cached", "--ignore-submodules", /* diff-index with either HEAD or an empty tree */ - head_has_history() ? "HEAD" : empty_tree_oid_hex(), + head_has_history() ? "HEAD" : empty_tree_oid_hex(the_repository->hash_algo), "--", NULL); strvec_pushv(&child.env, env->v); child.no_stdin = 1; @@ -1576,7 +1576,8 @@ static const char *update(struct command *cmd, struct shallow_info *si) if (ref_transaction_delete(transaction, namespaced_name, old_oid, - 0, "push", &err)) { + NULL, 0, + "push", &err)) { rp_error("%s", err.buf); ret = "failed to delete"; } else { diff --git a/builtin/refs.c b/builtin/refs.c new file mode 100644 index 0000000000..46dcd150d4 --- /dev/null +++ b/builtin/refs.c @@ -0,0 +1,75 @@ +#include "builtin.h" +#include "parse-options.h" +#include "refs.h" +#include "repository.h" +#include "strbuf.h" + +#define REFS_MIGRATE_USAGE \ + N_("git refs migrate --ref-format=<format> [--dry-run]") + +static int cmd_refs_migrate(int argc, const char **argv, const char *prefix) +{ + const char * const migrate_usage[] = { + REFS_MIGRATE_USAGE, + NULL, + }; + const char *format_str = NULL; + enum ref_storage_format format; + unsigned int flags = 0; + struct option options[] = { + OPT_STRING_F(0, "ref-format", &format_str, N_("format"), + N_("specify the reference format to convert to"), + PARSE_OPT_NONEG), + OPT_BIT(0, "dry-run", &flags, + N_("perform a non-destructive dry-run"), + REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN), + OPT_END(), + }; + struct strbuf errbuf = STRBUF_INIT; + int err; + + argc = parse_options(argc, argv, prefix, options, migrate_usage, 0); + if (argc) + usage(_("too many arguments")); + if (!format_str) + usage(_("missing --ref-format=<format>")); + + format = ref_storage_format_by_name(format_str); + if (format == REF_STORAGE_FORMAT_UNKNOWN) { + err = error(_("unknown ref storage format '%s'"), format_str); + goto out; + } + + if (the_repository->ref_storage_format == format) { + err = error(_("repository already uses '%s' format"), + ref_storage_format_to_name(format)); + goto out; + } + + if (repo_migrate_ref_storage_format(the_repository, format, flags, &errbuf) < 0) { + err = error("%s", errbuf.buf); + goto out; + } + + err = 0; + +out: + strbuf_release(&errbuf); + return err; +} + +int cmd_refs(int argc, const char **argv, const char *prefix) +{ + const char * const refs_usage[] = { + REFS_MIGRATE_USAGE, + NULL, + }; + parse_opt_subcommand_fn *fn = NULL; + struct option opts[] = { + OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate), + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, opts, refs_usage, 0); + return fn(argc, argv, prefix); +} diff --git a/builtin/remote.c b/builtin/remote.c index 447ef1d3c9..9d54fddf8c 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -258,7 +258,7 @@ struct branch_info { char *push_remote_name; }; -static struct string_list branch_list = STRING_LIST_INIT_NODUP; +static struct string_list branch_list = STRING_LIST_INIT_DUP; static const char *abbrev_ref(const char *name, const char *prefix) { @@ -292,8 +292,8 @@ static int config_read_branches(const char *key, const char *value, type = PUSH_REMOTE; else return 0; - name = xmemdupz(key, key_len); + name = xmemdupz(key, key_len); item = string_list_insert(&branch_list, name); if (!item->util) @@ -337,6 +337,7 @@ static int config_read_branches(const char *key, const char *value, BUG("unexpected type=%d", type); } + free(name); return 0; } @@ -493,12 +494,13 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat { struct ref *ref, *matches; struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; - struct refspec_item refspec; + struct refspec_item refspec = { + .force = 0, + .pattern = 1, + .src = (char *) "refs/heads/*", + .dst = (char *) "refs/heads/*", + }; - memset(&refspec, 0, sizeof(refspec)); - refspec.force = 0; - refspec.pattern = 1; - refspec.src = refspec.dst = "refs/heads/*"; get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), fetch_map, 1); @@ -507,7 +509,6 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat free_refs(fetch_map); free_refs(matches); - return 0; } @@ -554,13 +555,16 @@ static int add_branch_for_removal(const char *refname, refspec.dst = (char *)refname; if (remote_find_tracking(branches->remote, &refspec)) return 0; + free(refspec.src); /* don't delete a branch if another remote also uses it */ for (kr = branches->keep->list; kr; kr = kr->next) { memset(&refspec, 0, sizeof(refspec)); refspec.dst = (char *)refname; - if (!remote_find_tracking(kr->remote, &refspec)) + if (!remote_find_tracking(kr->remote, &refspec)) { + free(refspec.src); return 0; + } } /* don't delete non-remote-tracking refs */ @@ -619,8 +623,8 @@ static int migrate_file(struct remote *remote) int i; strbuf_addf(&buf, "remote.%s.url", remote->name); - for (i = 0; i < remote->url_nr; i++) - git_config_set_multivar(buf.buf, remote->url[i], "^$", 0); + for (i = 0; i < remote->url.nr; i++) + git_config_set_multivar(buf.buf, remote->url.v[i], "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.push", remote->name); for (i = 0; i < remote->push.raw_nr; i++) @@ -667,7 +671,11 @@ static int config_read_push_default(const char *key, const char *value, static void handle_push_default(const char* old_name, const char* new_name) { struct push_default_info push_default = { - old_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 }; + .old_name = old_name, + .scope = CONFIG_SCOPE_UNKNOWN, + .origin = STRBUF_INIT, + .linenr = -1, + }; git_config(config_read_push_default, &push_default); if (push_default.scope >= CONFIG_SCOPE_COMMAND) ; /* pass */ @@ -687,6 +695,8 @@ static void handle_push_default(const char* old_name, const char* new_name) push_default.origin.buf, push_default.linenr, old_name); } + + strbuf_release(&push_default.origin); } @@ -784,7 +794,7 @@ static int mv(int argc, const char **argv, const char *prefix) } if (!refspec_updated) - return 0; + goto out; /* * First remove symrefs, then rename the rest, finally create @@ -850,10 +860,15 @@ static int mv(int argc, const char **argv, const char *prefix) display_progress(progress, ++refs_renamed_nr); } stop_progress(&progress); - string_list_clear(&remote_branches, 1); handle_push_default(rename.old_name, rename.new_name); +out: + string_list_clear(&remote_branches, 1); + strbuf_release(&old_remote_context); + strbuf_release(&buf); + strbuf_release(&buf2); + strbuf_release(&buf3); return 0; } @@ -944,12 +959,21 @@ static int rm(int argc, const char **argv, const char *prefix) if (!result) { strbuf_addf(&buf, "remote.%s", remote->name); - if (git_config_rename_section(buf.buf, NULL) < 1) - return error(_("Could not remove config section '%s'"), buf.buf); + if (git_config_rename_section(buf.buf, NULL) < 1) { + result = error(_("Could not remove config section '%s'"), buf.buf); + goto out; + } handle_push_default(remote->name, NULL); } +out: + for (struct known_remote *r = known_remotes.list; r;) { + struct known_remote *next = r->next; + free(r); + r = next; + } + strbuf_release(&buf); return result; } @@ -982,8 +1006,10 @@ static int append_ref_to_tracked_list(const char *refname, memset(&refspec, 0, sizeof(refspec)); refspec.dst = (char *)refname; - if (!remote_find_tracking(states->remote, &refspec)) + if (!remote_find_tracking(states->remote, &refspec)) { string_list_append(&states->tracked, abbrev_branch(refspec.src)); + free(refspec.src); + } return 0; } @@ -1002,8 +1028,7 @@ static int get_remote_ref_states(const char *name, struct transport *transport; const struct ref *remote_refs; - transport = transport_get(states->remote, states->remote->url_nr > 0 ? - states->remote->url[0] : NULL); + transport = transport_get(states->remote, states->remote->url.v[0]); remote_refs = transport_get_remote_refs(transport, NULL); states->queried = 1; @@ -1213,15 +1238,15 @@ static int get_one_entry(struct remote *remote, void *priv) { struct string_list *list = priv; struct strbuf remote_info_buf = STRBUF_INIT; - const char **url; - int i, url_nr; + struct strvec *url; + int i; - if (remote->url_nr > 0) { + if (remote->url.nr > 0) { struct strbuf promisor_config = STRBUF_INIT; const char *partial_clone_filter = NULL; strbuf_addf(&promisor_config, "remote.%s.partialclonefilter", remote->name); - strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url[0]); + strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url.v[0]); if (!git_config_get_string_tmp(promisor_config.buf, &partial_clone_filter)) strbuf_addf(&remote_info_buf, " [%s]", partial_clone_filter); @@ -1230,16 +1255,10 @@ static int get_one_entry(struct remote *remote, void *priv) strbuf_detach(&remote_info_buf, NULL); } else string_list_append(list, remote->name)->util = NULL; - if (remote->pushurl_nr) { - url = remote->pushurl; - url_nr = remote->pushurl_nr; - } else { - url = remote->url; - url_nr = remote->url_nr; - } - for (i = 0; i < url_nr; i++) + url = push_url_of_remote(remote); + for (i = 0; i < url->nr; i++) { - strbuf_addf(&remote_info_buf, "%s (push)", url[i]); + strbuf_addf(&remote_info_buf, "%s (push)", url->v[i]); string_list_append(list, remote->name)->util = strbuf_detach(&remote_info_buf, NULL); } @@ -1295,28 +1314,20 @@ static int show(int argc, const char **argv, const char *prefix) for (; argc; argc--, argv++) { int i; - const char **url; - int url_nr; + struct strvec *url; get_remote_ref_states(*argv, &info.states, query_flag); printf_ln(_("* remote %s"), *argv); - printf_ln(_(" Fetch URL: %s"), info.states.remote->url_nr > 0 ? - info.states.remote->url[0] : _("(no URL)")); - if (info.states.remote->pushurl_nr) { - url = info.states.remote->pushurl; - url_nr = info.states.remote->pushurl_nr; - } else { - url = info.states.remote->url; - url_nr = info.states.remote->url_nr; - } - for (i = 0; i < url_nr; i++) + printf_ln(_(" Fetch URL: %s"), info.states.remote->url.v[0]); + url = push_url_of_remote(info.states.remote); + for (i = 0; i < url->nr; i++) /* * TRANSLATORS: the colon ':' should align * with the one in " Fetch URL: %s" * translation. */ - printf_ln(_(" Push URL: %s"), url[i]); + printf_ln(_(" Push URL: %s"), url->v[i]); if (!i) printf_ln(_(" Push URL: %s"), _("(no URL)")); if (no_query) @@ -1453,10 +1464,7 @@ static int prune_remote(const char *remote, int dry_run) } printf_ln(_("Pruning %s"), remote); - printf_ln(_("URL: %s"), - states.remote->url_nr - ? states.remote->url[0] - : _("(no URL)")); + printf_ln(_("URL: %s"), states.remote->url.v[0]); for_each_string_list_item(item, &states.stale) string_list_append(&refs_to_prune, item->util); @@ -1622,8 +1630,7 @@ static int get_url(int argc, const char **argv, const char *prefix) int i, push_mode = 0, all_mode = 0; const char *remotename = NULL; struct remote *remote; - const char **url; - int url_nr; + struct strvec *url; struct option options[] = { OPT_BOOL('\0', "push", &push_mode, N_("query push URLs rather than fetch URLs")), @@ -1645,27 +1652,13 @@ static int get_url(int argc, const char **argv, const char *prefix) exit(2); } - url_nr = 0; - if (push_mode) { - url = remote->pushurl; - url_nr = remote->pushurl_nr; - } - /* else fetch mode */ - - /* Use the fetch URL when no push URLs were found or requested. */ - if (!url_nr) { - url = remote->url; - url_nr = remote->url_nr; - } - - if (!url_nr) - die(_("no URLs configured for remote '%s'"), remotename); + url = push_mode ? push_url_of_remote(remote) : &remote->url; if (all_mode) { - for (i = 0; i < url_nr; i++) - printf_ln("%s", url[i]); + for (i = 0; i < url->nr; i++) + printf_ln("%s", url->v[i]); } else { - printf_ln("%s", *url); + printf_ln("%s", url->v[0]); } return 0; @@ -1680,8 +1673,7 @@ static int set_url(int argc, const char **argv, const char *prefix) const char *oldurl = NULL; struct remote *remote; regex_t old_regex; - const char **urlset; - int urlset_nr; + struct strvec *urlset; struct strbuf name_buf = STRBUF_INIT; struct option options[] = { OPT_BOOL('\0', "push", &push_mode, @@ -1718,12 +1710,10 @@ static int set_url(int argc, const char **argv, const char *prefix) if (push_mode) { strbuf_addf(&name_buf, "remote.%s.pushurl", remotename); - urlset = remote->pushurl; - urlset_nr = remote->pushurl_nr; + urlset = &remote->pushurl; } else { strbuf_addf(&name_buf, "remote.%s.url", remotename); - urlset = remote->url; - urlset_nr = remote->url_nr; + urlset = &remote->url; } /* Special cases that add new entry. */ @@ -1740,8 +1730,8 @@ static int set_url(int argc, const char **argv, const char *prefix) if (regcomp(&old_regex, oldurl, REG_EXTENDED)) die(_("Invalid old URL pattern: %s"), oldurl); - for (i = 0; i < urlset_nr; i++) - if (!regexec(&old_regex, urlset[i], 0, NULL, 0)) + for (i = 0; i < urlset->nr; i++) + if (!regexec(&old_regex, urlset->v[i], 0, NULL, 0)) matches++; else negative_matches++; diff --git a/builtin/replace.c b/builtin/replace.c index ce9f6974d2..1ef833c07f 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -167,7 +167,7 @@ static int check_ref_valid(struct object_id *object, return error(_("'%s' is not a valid ref name"), ref->buf); if (refs_read_ref(get_main_ref_store(the_repository), ref->buf, prev)) - oidclr(prev); + oidclr(prev, the_repository->hash_algo); else if (!force) return error(_("replace ref '%s' already exists"), ref->buf); return 0; diff --git a/builtin/replay.c b/builtin/replay.c index 6bf0691f15..138198ce9c 100644 --- a/builtin/replay.c +++ b/builtin/replay.c @@ -52,11 +52,11 @@ static struct commit *create_commit(struct tree *tree, struct commit *parent) { struct object_id ret; - struct object *obj; + struct object *obj = NULL; struct commit_list *parents = NULL; char *author; char *sign_commit = NULL; /* FIXME: cli users might want to sign again */ - struct commit_extra_header *extra; + struct commit_extra_header *extra = NULL; struct strbuf msg = STRBUF_INIT; const char *out_enc = get_commit_output_encoding(); const char *message = repo_logmsg_reencode(the_repository, based_on, @@ -73,12 +73,16 @@ static struct commit *create_commit(struct tree *tree, if (commit_tree_extended(msg.buf, msg.len, &tree->object.oid, parents, &ret, author, NULL, sign_commit, extra)) { error(_("failed to write commit object")); - return NULL; + goto out; } - free(author); - strbuf_release(&msg); obj = parse_object(the_repository, &ret); + +out: + free_commit_extra_headers(extra); + free_commit_list(parents); + strbuf_release(&msg); + free(author); return (struct commit *)obj; } @@ -147,7 +151,7 @@ static void get_ref_information(struct rev_cmdline_info *cmd_info, static void determine_replay_mode(struct rev_cmdline_info *cmd_info, const char *onto_name, - const char **advance_name, + char **advance_name, struct commit **onto, struct strset **update_refs) { @@ -170,6 +174,7 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info, *onto = peel_committish(*advance_name); if (repo_dwim_ref(the_repository, *advance_name, strlen(*advance_name), &oid, &fullname, 0) == 1) { + free(*advance_name); *advance_name = fullname; } else { die(_("argument to --advance must be a reference")); @@ -193,6 +198,7 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info, if (negative_refs_complete) { struct hashmap_iter iter; struct strmap_entry *entry; + const char *last_key = NULL; if (rinfo.negative_refexprs == 0) die(_("all positive revisions given must be references")); @@ -204,8 +210,11 @@ static void determine_replay_mode(struct rev_cmdline_info *cmd_info, /* Only one entry, but we have to loop to get it */ strset_for_each_entry(&rinfo.negative_refs, &iter, entry) { - *advance_name = entry->key; + last_key = entry->key; } + + free(*advance_name); + *advance_name = xstrdup_or_null(last_key); } else { /* positive_refs_complete */ if (rinfo.negative_refexprs > 1) die(_("cannot implicitly determine correct base for --onto")); @@ -267,7 +276,8 @@ static struct commit *pick_regular_commit(struct commit *pickme, int cmd_replay(int argc, const char **argv, const char *prefix) { - const char *advance_name = NULL; + const char *advance_name_opt = NULL; + char *advance_name = NULL; struct commit *onto = NULL; const char *onto_name = NULL; int contained = 0; @@ -288,7 +298,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix) NULL }; struct option replay_options[] = { - OPT_STRING(0, "advance", &advance_name, + OPT_STRING(0, "advance", &advance_name_opt, N_("branch"), N_("make replay advance given branch")), OPT_STRING(0, "onto", &onto_name, @@ -302,14 +312,15 @@ int cmd_replay(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, replay_options, replay_usage, PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT); - if (!onto_name && !advance_name) { + if (!onto_name && !advance_name_opt) { error(_("option --onto or --advance is mandatory")); usage_with_options(replay_usage, replay_options); } - if (advance_name && contained) + if (advance_name_opt && contained) die(_("options '%s' and '%s' cannot be used together"), "--advance", "--contained"); + advance_name = xstrdup_or_null(advance_name_opt); repo_init_revisions(the_repository, &revs, prefix); @@ -373,7 +384,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix) goto cleanup; } - init_merge_options(&merge_opt, the_repository); + init_basic_merge_options(&merge_opt, the_repository); memset(&result, 0, sizeof(result)); merge_opt.show_rename_progress = 0; last_commit = onto; @@ -437,6 +448,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix) cleanup: release_revisions(&revs); + free(advance_name); /* Return */ if (ret < 0) diff --git a/builtin/rerere.c b/builtin/rerere.c index b2efc6f640..81b65ffa39 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -73,11 +73,17 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) if (!strcmp(argv[0], "forget")) { struct pathspec pathspec; + int ret; + if (argc < 2) warning(_("'git rerere forget' without paths is deprecated")); parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, argv + 1); - return rerere_forget(the_repository, &pathspec); + + ret = rerere_forget(the_repository, &pathspec); + + clear_pathspec(&pathspec); + return ret; } if (!strcmp(argv[0], "clear")) { diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 77803727e0..97d077a994 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -508,6 +508,8 @@ static int try_bitmap_disk_usage(struct rev_info *revs, size_from_bitmap = get_disk_usage_from_bitmap(bitmap_git, revs); print_disk_usage(size_from_bitmap); + + free_bitmap_index(bitmap_git); return 0; } diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 1e2919fd81..5845d3f59b 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -423,12 +423,12 @@ static char *findspace(const char *s) static int cmd_parseopt(int argc, const char **argv, const char *prefix) { - static int keep_dashdash = 0, stop_at_non_option = 0; - static char const * const parseopt_usage[] = { + int keep_dashdash = 0, stop_at_non_option = 0; + char const * const parseopt_usage[] = { N_("git rev-parse --parseopt [<options>] -- [<args>...]"), NULL }; - static struct option parseopt_opts[] = { + struct option parseopt_opts[] = { OPT_BOOL(0, "keep-dashdash", &keep_dashdash, N_("keep the `--` passed as an arg")), OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option, @@ -438,12 +438,11 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) N_("output in stuck long form")), OPT_END(), }; - static const char * const flag_chars = "*=?!"; - struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT; - const char **usage = NULL; + struct strvec longnames = STRVEC_INIT; + struct strvec usage = STRVEC_INIT; struct option *opts = NULL; - int onb = 0, osz = 0, unb = 0, usz = 0; + size_t opts_nr = 0, opts_alloc = 0; strbuf_addstr(&parsed, "set --"); argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage, @@ -453,16 +452,16 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) /* get the usage up to the first line with a -- on it */ for (;;) { + strbuf_reset(&sb); if (strbuf_getline(&sb, stdin) == EOF) die(_("premature end of input")); - ALLOC_GROW(usage, unb + 1, usz); if (!strcmp("--", sb.buf)) { - if (unb < 1) + if (!usage.nr) die(_("no usage string given before the `--' separator")); - usage[unb] = NULL; break; } - usage[unb++] = strbuf_detach(&sb, NULL); + + strvec_push(&usage, sb.buf); } /* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */ @@ -474,10 +473,10 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) if (!sb.len) continue; - ALLOC_GROW(opts, onb + 1, osz); - memset(opts + onb, 0, sizeof(opts[onb])); + ALLOC_GROW(opts, opts_nr + 1, opts_alloc); + memset(opts + opts_nr, 0, sizeof(*opts)); - o = &opts[onb++]; + o = &opts[opts_nr++]; help = findspace(sb.buf); if (!help || sb.buf == help) { o->type = OPTION_GROUP; @@ -494,20 +493,22 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) o->callback = &parseopt_dump; /* name(s) */ - s = strpbrk(sb.buf, flag_chars); + s = strpbrk(sb.buf, "*=?!"); if (!s) s = help; if (s == sb.buf) die(_("missing opt-spec before option flags")); - if (s - sb.buf == 1) /* short option only */ + if (s - sb.buf == 1) { /* short option only */ o->short_name = *sb.buf; - else if (sb.buf[1] != ',') /* long option only */ - o->long_name = xmemdupz(sb.buf, s - sb.buf); - else { + } else if (sb.buf[1] != ',') { /* long option only */ + o->long_name = strvec_pushf(&longnames, "%.*s", + (int)(s - sb.buf), sb.buf); + } else { o->short_name = *sb.buf; - o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2); + o->long_name = strvec_pushf(&longnames, "%.*s", + (int)(s - sb.buf - 2), sb.buf + 2); } /* flags */ @@ -537,9 +538,9 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) strbuf_release(&sb); /* put an OPT_END() */ - ALLOC_GROW(opts, onb + 1, osz); - memset(opts + onb, 0, sizeof(opts[onb])); - argc = parse_options(argc, argv, prefix, opts, usage, + ALLOC_GROW(opts, opts_nr + 1, opts_alloc); + memset(opts + opts_nr, 0, sizeof(*opts)); + argc = parse_options(argc, argv, prefix, opts, usage.v, (keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) | (stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) | PARSE_OPT_SHELL_EVAL); @@ -547,7 +548,16 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) strbuf_addstr(&parsed, " --"); sq_quote_argv(&parsed, argv); puts(parsed.buf); + strbuf_release(&parsed); + strbuf_release(&sb); + strvec_clear(&longnames); + strvec_clear(&usage); + for (size_t i = 0; i < opts_nr; i++) { + free((char *) opts[i].help); + free((char *) opts[i].argh); + } + free(opts); return 0; } @@ -1121,6 +1131,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) } if (!get_oid_with_context(the_repository, name, flags, &oid, &unused)) { + object_context_release(&unused); if (output_algo) repo_oid_to_algop(the_repository, &oid, output_algo, &oid); @@ -1130,6 +1141,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) show_rev(type, &oid, name); continue; } + object_context_release(&unused); if (verify) die_no_single_rev(quiet); if (has_dashdash) diff --git a/builtin/revert.c b/builtin/revert.c index 53935d2c68..7bf2b4e11d 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -179,7 +179,7 @@ static int run_sequencer(int argc, const char **argv, const char *prefix, /* Check for incompatible command line arguments */ if (cmd) { - char *this_operation; + const char *this_operation; if (cmd == 'q') this_operation = "--quit"; else if (cmd == 'c') diff --git a/builtin/rm.c b/builtin/rm.c index d195c16e74..0e79cbab62 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -377,7 +377,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (!force) { struct object_id oid; if (repo_get_oid(the_repository, "HEAD", &oid)) - oidclr(&oid); + oidclr(&oid, the_repository->hash_algo); if (check_local_mod(&oid, index_only)) exit(1); } diff --git a/builtin/send-pack.c b/builtin/send-pack.c index 3df9eaad09..17cae6bbbd 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -336,5 +336,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) /* stable plumbing output; do not modify or localize */ fprintf(stderr, "Everything up-to-date\n"); + free_refs(remote_refs); + free_refs(local_refs); return ret; } diff --git a/builtin/shortlog.c b/builtin/shortlog.c index d4daf31e22..b529608c92 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -460,11 +460,8 @@ parse_done: else get_from_rev(&rev, &log); - release_revisions(&rev); - shortlog_output(&log); - if (log.file != stdout) - fclose(log.file); + release_revisions(&rev); return 0; } @@ -517,4 +514,5 @@ void shortlog_output(struct shortlog *log) string_list_clear(&log->list, 1); clear_mailmap(&log->mailmap); string_list_clear(&log->format, 0); + string_list_clear(&log->trailers, 0); } diff --git a/builtin/show-branch.c b/builtin/show-branch.c index d72f4cb98d..7d797a880c 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -502,14 +502,14 @@ static int rev_is_head(const char *head, const char *name) return !strcmp(head, name); } -static int show_merge_base(struct commit_list *seen, int num_rev) +static int show_merge_base(const struct commit_list *seen, int num_rev) { int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1); int all_revs = all_mask & ~((1u << REV_SHIFT) - 1); int exit_status = 1; - while (seen) { - struct commit *commit = pop_commit(&seen); + for (const struct commit_list *s = seen; s; s = s->next) { + struct commit *commit = s->item; int flags = commit->object.flags & all_mask; if (!(flags & UNINTERESTING) && ((flags & all_revs) == all_revs)) { @@ -635,7 +635,7 @@ static int parse_reflog_param(const struct option *opt, const char *arg, int cmd_show_branch(int ac, const char **av, const char *prefix) { struct commit *rev[MAX_REVS], *commit; - char *reflog_msg[MAX_REVS]; + char *reflog_msg[MAX_REVS] = {0}; struct commit_list *list = NULL, *seen = NULL; unsigned int rev_mask[MAX_REVS]; int num_rev, i, extra = 0; @@ -692,6 +692,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) parse_reflog_param), OPT_END() }; + const char **args_copy = NULL; + int ret; init_commit_name_slab(&name_slab); @@ -699,8 +701,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) /* If nothing is specified, try the default first */ if (ac == 1 && default_args.nr) { + DUP_ARRAY(args_copy, default_args.v, default_args.nr); ac = default_args.nr; - av = default_args.v; + av = args_copy; } ac = parse_options(ac, av, prefix, builtin_show_branch_options, @@ -780,7 +783,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) } for (i = 0; i < reflog; i++) { - char *logmsg; + char *logmsg = NULL; char *nth_desc; const char *msg; char *end; @@ -790,6 +793,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) if (read_ref_at(get_main_ref_store(the_repository), ref, flags, 0, base + i, &oid, &logmsg, ×tamp, &tz, NULL)) { + free(logmsg); reflog = i; break; } @@ -842,7 +846,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) if (!ref_name_cnt) { fprintf(stderr, "No revs to be shown.\n"); - exit(0); + ret = 0; + goto out; } for (num_rev = 0; ref_name[num_rev]; num_rev++) { @@ -879,11 +884,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) commit_list_sort_by_date(&seen); - if (merge_base) - return show_merge_base(seen, num_rev); + if (merge_base) { + ret = show_merge_base(seen, num_rev); + goto out; + } - if (independent) - return show_independent(rev, num_rev, rev_mask); + if (independent) { + ret = show_independent(rev, num_rev, rev_mask); + goto out; + } /* Show list; --more=-1 means list-only */ if (1 < num_rev || extra < 0) { @@ -919,8 +928,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) putchar('\n'); } } - if (extra < 0) - exit(0); + if (extra < 0) { + ret = 0; + goto out; + } /* Sort topologically */ sort_in_topological_order(&seen, sort_order); @@ -932,8 +943,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) all_mask = ((1u << (REV_SHIFT + num_rev)) - 1); all_revs = all_mask & ~((1u << REV_SHIFT) - 1); - while (seen) { - struct commit *commit = pop_commit(&seen); + for (struct commit_list *l = seen; l; l = l->next) { + struct commit *commit = l->item; int this_flag = commit->object.flags; int is_merge_point = ((this_flag & all_revs) == all_revs); @@ -973,6 +984,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) if (shown_merge_point && --extra < 0) break; } + + ret = 0; + +out: + for (size_t i = 0; i < ARRAY_SIZE(reflog_msg); i++) + free(reflog_msg[i]); + free_commit_list(seen); + free_commit_list(list); + free(args_copy); free(head); - return 0; + return ret; } diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 3114bdc391..85700caae9 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -11,8 +11,8 @@ static const char * const show_ref_usage[] = { N_("git show-ref [--head] [-d | --dereference]\n" - " [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" - " [--heads] [--] [<pattern>...]"), + " [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" + " [--] [<pattern>...]"), N_("git show-ref --verify [-q | --quiet] [-d | --dereference]\n" " [-s | --hash[=<n>]] [--abbrev[=<n>]]\n" " [--] [<ref>...]"), @@ -189,7 +189,7 @@ static int cmd_show_ref__verify(const struct show_one_options *show_one_opts, struct patterns_options { int show_head; - int heads_only; + int branches_only; int tags_only; }; @@ -208,8 +208,8 @@ static int cmd_show_ref__patterns(const struct patterns_options *opts, if (opts->show_head) refs_head_ref(get_main_ref_store(the_repository), show_ref, &show_ref_data); - if (opts->heads_only || opts->tags_only) { - if (opts->heads_only) + if (opts->branches_only || opts->tags_only) { + if (opts->branches_only) refs_for_each_fullref_in(get_main_ref_store(the_repository), "refs/heads/", NULL, show_ref, &show_ref_data); @@ -293,8 +293,10 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix) struct show_one_options show_one_opts = {0}; int verify = 0, exists = 0; const struct option show_ref_options[] = { - OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with heads)")), - OPT_BOOL(0, "heads", &patterns_opts.heads_only, N_("only show heads (can be combined with tags)")), + OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with --branches)")), + OPT_BOOL(0, "branches", &patterns_opts.branches_only, N_("only show branches (can be combined with --tags)")), + OPT_HIDDEN_BOOL(0, "heads", &patterns_opts.branches_only, + N_("deprecated synonym for --branches")), OPT_BOOL(0, "exists", &exists, N_("check for reference existence without resolving")), OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, " "requires exact ref path")), diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 0f52e25249..2604ab04df 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -96,10 +96,11 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix) printf("\n"); } - return 0; + string_list_clear(&sl, 0); + } else { + write_patterns_to_file(stdout, &pl); } - write_patterns_to_file(stdout, &pl); clear_pattern_list(&pl); return 0; @@ -205,11 +206,13 @@ static int update_working_directory(struct pattern_list *pl) struct unpack_trees_options o; struct lock_file lock_file = LOCK_INIT; struct repository *r = the_repository; + struct pattern_list *old_pl; /* If no branch has been checked out, there are no updates to make. */ if (is_index_unborn(r->index)) return UPDATE_SPARSITY_SUCCESS; + old_pl = r->index->sparse_checkout_patterns; r->index->sparse_checkout_patterns = pl; memset(&o, 0, sizeof(o)); @@ -241,7 +244,12 @@ static int update_working_directory(struct pattern_list *pl) clean_tracked_sparse_directories(r); - r->index->sparse_checkout_patterns = NULL; + if (r->index->sparse_checkout_patterns != pl) { + clear_pattern_list(r->index->sparse_checkout_patterns); + FREE_AND_NULL(r->index->sparse_checkout_patterns); + } + r->index->sparse_checkout_patterns = old_pl; + return result; } @@ -311,6 +319,8 @@ static void write_cone_to_file(FILE *fp, struct pattern_list *pl) fprintf(fp, "%s/\n", pattern); free(pattern); } + + string_list_clear(&sl, 0); } static int write_patterns_and_update(struct pattern_list *pl) @@ -440,7 +450,6 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix) char *sparse_filename; int res; struct object_id oid; - struct strbuf pattern = STRBUF_INIT; static struct option builtin_sparse_checkout_init_options[] = { OPT_BOOL(0, "cone", &init_opts.cone_mode, @@ -471,6 +480,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix) /* If we already have a sparse-checkout file, use it. */ if (res >= 0) { free(sparse_filename); + clear_pattern_list(&pl); return update_working_directory(NULL); } @@ -491,10 +501,10 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix) return 0; } - strbuf_addstr(&pattern, "/*"); - add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0); - strbuf_addstr(&pattern, "!/*/"); - add_pattern(strbuf_detach(&pattern, NULL), empty_base, 0, &pl, 0); + free(sparse_filename); + + add_pattern("/*", empty_base, 0, &pl, 0); + add_pattern("!/*/", empty_base, 0, &pl, 0); pl.use_cone_patterns = init_opts.cone_mode; return write_patterns_and_update(&pl); @@ -513,6 +523,7 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat char *slash = strrchr(e->pattern, '/'); char *oldpattern = e->pattern; size_t newlen; + struct pattern_entry *dup; if (!slash || slash == e->pattern) break; @@ -523,8 +534,14 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat e->pattern = xstrndup(oldpattern, newlen); hashmap_entry_init(&e->ent, fspathhash(e->pattern)); - if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL)) + dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL); + if (!dup) { hashmap_add(&pl->parent_hashmap, &e->ent); + } else { + free(e->pattern); + free(e); + e = dup; + } } } @@ -581,15 +598,15 @@ static void add_patterns_from_input(struct pattern_list *pl, strbuf_to_cone_pattern(&line, pl); } } + strbuf_release(&line); } else { if (file) { struct strbuf line = STRBUF_INIT; - while (!strbuf_getline(&line, file)) { - size_t len; - char *buf = strbuf_detach(&line, &len); - add_pattern(buf, empty_base, 0, pl, 0); - } + while (!strbuf_getline(&line, file)) + add_pattern(line.buf, empty_base, 0, pl, 0); + + strbuf_release(&line); } else { for (i = 0; i < argc; i++) add_pattern(argv[i], empty_base, 0, pl, 0); @@ -891,7 +908,6 @@ static int sparse_checkout_disable(int argc, const char **argv, OPT_END(), }; struct pattern_list pl; - struct strbuf match_all = STRBUF_INIT; /* * We do not exit early if !core_apply_sparse_checkout; due to the @@ -917,8 +933,7 @@ static int sparse_checkout_disable(int argc, const char **argv, pl.use_cone_patterns = 0; core_apply_sparse_checkout = 1; - strbuf_addstr(&match_all, "/*"); - add_pattern(strbuf_detach(&match_all, NULL), empty_base, 0, &pl, 0); + add_pattern("/*", empty_base, 0, &pl, 0); prepare_repo_settings(the_repository); the_repository->settings.sparse_index = 0; @@ -1011,6 +1026,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char * ret = check_rules(&pl, check_rules_opts.null_termination); clear_pattern_list(&pl); + free(check_rules_opts.rules_file); return ret; } diff --git a/builtin/stash.c b/builtin/stash.c index 7859bc0866..d90e072ddc 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -574,7 +574,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info, } } - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); o.branch1 = "Updated upstream"; o.branch2 = "Stashed changes"; @@ -975,7 +975,9 @@ static int show_stash(int argc, const char **argv, const char *prefix) log_tree_diff_flush(&rev); ret = diff_result_code(&rev.diffopt); + cleanup: + strvec_clear(&revision_args); strvec_clear(&stash_args); free_stash_info(&info); release_revisions(&rev); @@ -1018,13 +1020,14 @@ static int store_stash(int argc, const char **argv, const char *prefix) int quiet = 0; const char *stash_msg = NULL; struct object_id obj; - struct object_context dummy; + struct object_context dummy = {0}; struct option options[] = { OPT__QUIET(&quiet, N_("be quiet")), OPT_STRING('m', "message", &stash_msg, "message", N_("stash message")), OPT_END() }; + int ret; argc = parse_options(argc, argv, prefix, options, git_stash_store_usage, @@ -1043,10 +1046,15 @@ static int store_stash(int argc, const char **argv, const char *prefix) if (!quiet) fprintf_ln(stderr, _("Cannot update %s with %s"), ref_stash, argv[0]); - return -1; + ret = -1; + goto out; } - return do_store_stash(&obj, stash_msg, quiet); + ret = do_store_stash(&obj, stash_msg, quiet); + +out: + object_context_release(&dummy); + return ret; } static void add_pathspecs(struct strvec *args, @@ -1408,6 +1416,9 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b goto done; } + free_commit_list(parents); + parents = NULL; + if (include_untracked) { if (save_untracked_files(info, &msg, untracked_files)) { if (!quiet) @@ -1453,11 +1464,6 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b else strbuf_insertf(stash_msg_buf, 0, "On %s: ", branch_name); - /* - * `parents` will be empty after calling `commit_tree()`, so there is - * no need to call `free_commit_list()` - */ - parents = NULL; if (untracked_commit_option) commit_list_insert(lookup_commit(the_repository, &info->u_commit), @@ -1479,6 +1485,7 @@ done: strbuf_release(&commit_tree_label); strbuf_release(&msg); strbuf_release(&untracked_files); + free_commit_list(parents); return ret; } @@ -1514,6 +1521,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q struct strbuf patch = STRBUF_INIT; struct strbuf stash_msg_buf = STRBUF_INIT; struct strbuf untracked_files = STRBUF_INIT; + struct strbuf out = STRBUF_INIT; if (patch_mode && keep_index == -1) keep_index = 1; @@ -1619,7 +1627,6 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q struct child_process cp_add = CHILD_PROCESS_INIT; struct child_process cp_diff = CHILD_PROCESS_INIT; struct child_process cp_apply = CHILD_PROCESS_INIT; - struct strbuf out = STRBUF_INIT; cp_add.git_cmd = 1; strvec_push(&cp_add.args, "add"); @@ -1711,6 +1718,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q done: strbuf_release(&patch); + strbuf_release(&out); free_stash_info(&info); strbuf_release(&stash_msg_buf); strbuf_release(&untracked_files); @@ -1862,6 +1870,8 @@ int cmd_stash(int argc, const char **argv, const char *prefix) OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE), OPT_END() }; + const char **args_copy; + int ret; git_config(git_stash_config, NULL); @@ -1885,5 +1895,16 @@ int cmd_stash(int argc, const char **argv, const char *prefix) /* Assume 'stash push' */ strvec_push(&args, "push"); strvec_pushv(&args, argv); - return !!push_stash(args.nr, args.v, prefix, 1); + + /* + * `push_stash()` ends up modifying the array, which causes memory + * leaks if we didn't copy the array here. + */ + DUP_ARRAY(args_copy, args.v, args.nr); + + ret = !!push_stash(args.nr, args_copy, prefix, 1); + + strvec_clear(&args); + free(args_copy); + return ret; } diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 897f19868e..673810d2c0 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -256,11 +256,9 @@ static void module_list_active(struct module_list *list) static char *get_up_path(const char *path) { - int i; struct strbuf sb = STRBUF_INIT; - for (i = count_slashes(path); i; i--) - strbuf_addstr(&sb, "../"); + strbuf_addstrings(&sb, "../", count_slashes(path)); /* * Check if 'path' ends with slash or not @@ -378,8 +376,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item, strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive", NULL); - strvec_pushl(&cpr.args, "--super-prefix", NULL); - strvec_pushf(&cpr.args, "%s/", displaypath); + strvec_pushf(&cpr.args, "--super-prefix=%s/", displaypath); if (info->quiet) strvec_push(&cpr.args, "--quiet"); @@ -704,8 +701,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, strvec_pushl(&cpr.args, "submodule--helper", "status", "--recursive", NULL); - strvec_push(&cpr.args, "--super-prefix"); - strvec_pushf(&cpr.args, "%s/", displaypath); + strvec_pushf(&cpr.args, "--super-prefix=%s/", displaypath); if (flags & OPT_CACHED) strvec_push(&cpr.args, "--cached"); @@ -1306,9 +1302,7 @@ static void sync_submodule(const char *path, const char *prefix, strvec_pushl(&cpr.args, "submodule--helper", "sync", "--recursive", NULL); - strvec_push(&cpr.args, "--super-prefix"); - strvec_pushf(&cpr.args, "%s/", displaypath); - + strvec_pushf(&cpr.args, "--super-prefix=%s/", displaypath); if (flags & OPT_QUIET) strvec_push(&cpr.args, "--quiet"); @@ -1536,7 +1530,7 @@ struct module_clone_data { const char *path; const char *name; const char *url; - const char *depth; + int depth; struct list_objects_filter_options *filter_options; unsigned int quiet: 1; unsigned int progress: 1; @@ -1735,8 +1729,8 @@ static int clone_submodule(const struct module_clone_data *clone_data, strvec_push(&cp.args, "--quiet"); if (clone_data->progress) strvec_push(&cp.args, "--progress"); - if (clone_data->depth && *(clone_data->depth)) - strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL); + if (clone_data->depth > 0) + strvec_pushf(&cp.args, "--depth=%d", clone_data->depth); if (reference->nr) { struct string_list_item *item; @@ -1857,8 +1851,7 @@ static int module_clone(int argc, const char **argv, const char *prefix) N_("reference repository")), OPT_BOOL(0, "dissociate", &dissociate, N_("use --reference only while cloning")), - OPT_STRING(0, "depth", &clone_data.depth, - N_("string"), + OPT_INTEGER(0, "depth", &clone_data.depth, N_("depth for shallow clones")), OPT__QUIET(&quiet, "suppress output for cloning a submodule"), OPT_BOOL(0, "progress", &progress, @@ -2275,6 +2268,7 @@ static int is_tip_reachable(const char *path, const struct object_id *oid) struct child_process cp = CHILD_PROCESS_INIT; struct strbuf rev = STRBUF_INIT; char *hex = oid_to_hex(oid); + int reachable; cp.git_cmd = 1; cp.dir = path; @@ -2284,9 +2278,12 @@ static int is_tip_reachable(const char *path, const struct object_id *oid) prepare_submodule_repo_env(&cp.env); if (capture_command(&cp, &rev, GIT_MAX_HEXSZ + 1) || rev.len) - return 0; + reachable = 0; + else + reachable = 1; - return 1; + strbuf_release(&rev); + return reachable; } static int fetch_in_submodule(const char *module_path, int depth, int quiet, @@ -2536,10 +2533,9 @@ static void update_data_to_args(const struct update_data *update_data, enum submodule_update_type update_type = update_data->update_default; strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL); - if (update_data->displaypath) { - strvec_push(args, "--super-prefix"); - strvec_pushf(args, "%s/", update_data->displaypath); - } + if (update_data->displaypath) + strvec_pushf(args, "--super-prefix=%s/", + update_data->displaypath); strvec_pushf(args, "--jobs=%d", update_data->max_jobs); if (update_data->quiet) strvec_push(args, "--quiet"); @@ -3207,7 +3203,7 @@ static int add_submodule(const struct add_data *add_data) } clone_data.dissociate = add_data->dissociate; if (add_data->depth >= 0) - clone_data.depth = xstrfmt("%d", add_data->depth); + clone_data.depth = add_data->depth; if (clone_submodule(&clone_data, &reference)) goto cleanup; @@ -3230,6 +3226,7 @@ static int add_submodule(const struct add_data *add_data) die(_("unable to checkout submodule '%s'"), add_data->sm_path); } ret = 0; + cleanup: string_list_clear(&reference, 1); return ret; diff --git a/builtin/tag.c b/builtin/tag.c index 6e2c0cf342..a1fb218512 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -650,7 +650,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) die(_("'%s' is not a valid tag name."), tag); if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev)) - oidclr(&prev); + oidclr(&prev, the_repository->hash_algo); else if (!force) die(_("tag '%s' already exists"), tag); diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index f1c85a00ae..08fa2a7a74 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -439,7 +439,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size, struct object_id base_oid; if (type == OBJ_REF_DELTA) { - oidread(&base_oid, fill(the_hash_algo->rawsz)); + oidread(&base_oid, fill(the_hash_algo->rawsz), the_repository->hash_algo); use(the_hash_algo->rawsz); delta_data = get_data(delta_size); if (!delta_data) @@ -451,7 +451,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size, return; /* we are done */ else { /* cannot resolve yet --- queue it */ - oidclr(&obj_list[nr].oid); + oidclr(&obj_list[nr].oid, the_repository->hash_algo); add_delta_to_list(nr, &base_oid, 0, delta_data, delta_size); return; } @@ -500,7 +500,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size, * The delta base object is itself a delta that * has not been resolved yet. */ - oidclr(&obj_list[nr].oid); + oidclr(&obj_list[nr].oid, the_repository->hash_algo); add_delta_to_list(nr, null_oid(), base_offset, delta_data, delta_size); return; @@ -674,7 +674,8 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED) if (fsck_finish(&fsck_options)) die(_("fsck error in pack objects")); } - if (!hasheq(fill(the_hash_algo->rawsz), oid.hash)) + if (!hasheq(fill(the_hash_algo->rawsz), oid.hash, + the_repository->hash_algo)) die("final sha1 did not match"); use(the_hash_algo->rawsz); diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 6cda1c08aa..6a6a2ff55d 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -77,6 +77,65 @@ static char *parse_refname(const char **next) } /* + * Wrapper around parse_refname which skips the next delimiter. + */ +static char *parse_next_refname(const char **next) +{ + if (line_termination) { + /* Without -z, consume SP and use next argument */ + if (!**next || **next == line_termination) + return NULL; + if (**next != ' ') + die("expected SP but got: %s", *next); + } else { + /* With -z, read the next NUL-terminated line */ + if (**next) + return NULL; + } + /* Skip the delimiter */ + (*next)++; + + return parse_refname(next); +} + +/* + * Wrapper around parse_arg which skips the next delimiter. + */ +static char *parse_next_arg(const char **next) +{ + struct strbuf arg = STRBUF_INIT; + + if (line_termination) { + /* Without -z, consume SP and use next argument */ + if (!**next || **next == line_termination) + return NULL; + if (**next != ' ') + die("expected SP but got: %s", *next); + } else { + /* With -z, read the next NUL-terminated line */ + if (**next) + return NULL; + } + /* Skip the delimiter */ + (*next)++; + + if (line_termination) { + /* Without -z, use the next argument */ + *next = parse_arg(*next, &arg); + } else { + /* With -z, use everything up to the next NUL */ + strbuf_addstr(&arg, *next); + *next += arg.len; + } + + if (arg.len) + return strbuf_detach(&arg, NULL); + + strbuf_release(&arg); + return NULL; +} + +/* * The value being parsed is <old-oid> (as opposed to <new-oid>; the * difference affects which error messages are generated): */ @@ -122,7 +181,7 @@ static int parse_next_oid(const char **next, const char *end, goto invalid; } else { /* Without -z, an empty value means all zeros: */ - oidclr(oid); + oidclr(oid, the_repository->hash_algo); } } else { /* With -z, read the next NUL-terminated line */ @@ -142,7 +201,7 @@ static int parse_next_oid(const char **next, const char *end, /* With -z, treat an empty value as all zeros: */ warning("%s %s: missing <new-oid>, treating as zero", command, refname); - oidclr(oid); + oidclr(oid, the_repository->hash_algo); } else { /* * With -z, an empty non-required value means @@ -214,6 +273,61 @@ static void parse_cmd_update(struct ref_transaction *transaction, strbuf_release(&err); } +static void parse_cmd_symref_update(struct ref_transaction *transaction, + const char *next, const char *end) +{ + char *refname, *new_target, *old_arg; + char *old_target = NULL; + struct strbuf err = STRBUF_INIT; + struct object_id old_oid; + int have_old_oid = 0; + + refname = parse_refname(&next); + if (!refname) + die("symref-update: missing <ref>"); + + new_target = parse_next_refname(&next); + if (!new_target) + die("symref-update %s: missing <new-target>", refname); + + old_arg = parse_next_arg(&next); + if (old_arg) { + old_target = parse_next_arg(&next); + if (!old_target) + die("symref-update %s: expected old value", refname); + + if (!strcmp(old_arg, "oid")) { + if (repo_get_oid(the_repository, old_target, &old_oid)) + die("symref-update %s: invalid oid: %s", refname, old_target); + + have_old_oid = 1; + } else if (!strcmp(old_arg, "ref")) { + if (check_refname_format(old_target, REFNAME_ALLOW_ONELEVEL)) + die("symref-update %s: invalid ref: %s", refname, old_target); + } else { + die("symref-update %s: invalid arg '%s' for old value", refname, old_arg); + } + } + + if (*next != line_termination) + die("symref-update %s: extra input: %s", refname, next); + + if (ref_transaction_update(transaction, refname, NULL, + have_old_oid ? &old_oid : NULL, + new_target, + have_old_oid ? NULL : old_target, + update_flags | create_reflog_flag, + msg, &err)) + die("%s", err.buf); + + update_flags = default_flags; + free(refname); + free(old_arg); + free(old_target); + free(new_target); + strbuf_release(&err); +} + static void parse_cmd_create(struct ref_transaction *transaction, const char *next, const char *end) { @@ -234,13 +348,42 @@ static void parse_cmd_create(struct ref_transaction *transaction, if (*next != line_termination) die("create %s: extra input: %s", refname, next); - if (ref_transaction_create(transaction, refname, &new_oid, + if (ref_transaction_create(transaction, refname, &new_oid, NULL, + update_flags | create_reflog_flag, + msg, &err)) + die("%s", err.buf); + + update_flags = default_flags; + free(refname); + strbuf_release(&err); +} + + +static void parse_cmd_symref_create(struct ref_transaction *transaction, + const char *next, const char *end) +{ + struct strbuf err = STRBUF_INIT; + char *refname, *new_target; + + refname = parse_refname(&next); + if (!refname) + die("symref-create: missing <ref>"); + + new_target = parse_next_refname(&next); + if (!new_target) + die("symref-create %s: missing <new-target>", refname); + + if (*next != line_termination) + die("symref-create %s: extra input: %s", refname, next); + + if (ref_transaction_create(transaction, refname, NULL, new_target, update_flags | create_reflog_flag, msg, &err)) die("%s", err.buf); update_flags = default_flags; free(refname); + free(new_target); strbuf_release(&err); } @@ -270,7 +413,7 @@ static void parse_cmd_delete(struct ref_transaction *transaction, if (ref_transaction_delete(transaction, refname, have_old ? &old_oid : NULL, - update_flags, msg, &err)) + NULL, update_flags, msg, &err)) die("%s", err.buf); update_flags = default_flags; @@ -278,6 +421,36 @@ static void parse_cmd_delete(struct ref_transaction *transaction, strbuf_release(&err); } + +static void parse_cmd_symref_delete(struct ref_transaction *transaction, + const char *next, const char *end) +{ + struct strbuf err = STRBUF_INIT; + char *refname, *old_target; + + if (!(update_flags & REF_NO_DEREF)) + die("symref-delete: cannot operate with deref mode"); + + refname = parse_refname(&next); + if (!refname) + die("symref-delete: missing <ref>"); + + old_target = parse_next_refname(&next); + + if (*next != line_termination) + die("symref-delete %s: extra input: %s", refname, next); + + if (ref_transaction_delete(transaction, refname, NULL, + old_target, update_flags, msg, &err)) + die("%s", err.buf); + + update_flags = default_flags; + free(refname); + free(old_target); + strbuf_release(&err); +} + + static void parse_cmd_verify(struct ref_transaction *transaction, const char *next, const char *end) { @@ -291,17 +464,53 @@ static void parse_cmd_verify(struct ref_transaction *transaction, if (parse_next_oid(&next, end, &old_oid, "verify", refname, PARSE_SHA1_OLD)) - oidclr(&old_oid); + oidclr(&old_oid, the_repository->hash_algo); if (*next != line_termination) die("verify %s: extra input: %s", refname, next); if (ref_transaction_verify(transaction, refname, &old_oid, - update_flags, &err)) + NULL, update_flags, &err)) + die("%s", err.buf); + + update_flags = default_flags; + free(refname); + strbuf_release(&err); +} + +static void parse_cmd_symref_verify(struct ref_transaction *transaction, + const char *next, const char *end) +{ + struct strbuf err = STRBUF_INIT; + struct object_id old_oid; + char *refname, *old_target; + + if (!(update_flags & REF_NO_DEREF)) + die("symref-verify: cannot operate with deref mode"); + + refname = parse_refname(&next); + if (!refname) + die("symref-verify: missing <ref>"); + + /* + * old_ref is optional, if not provided, we need to ensure that the + * ref doesn't exist. + */ + old_target = parse_next_refname(&next); + if (!old_target) + oidcpy(&old_oid, null_oid()); + + if (*next != line_termination) + die("symref-verify %s: extra input: %s", refname, next); + + if (ref_transaction_verify(transaction, refname, + old_target ? NULL : &old_oid, + old_target, update_flags, &err)) die("%s", err.buf); update_flags = default_flags; free(refname); + free(old_target); strbuf_release(&err); } @@ -380,15 +589,19 @@ static const struct parse_cmd { unsigned args; enum update_refs_state state; } command[] = { - { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN }, - { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN }, - { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN }, - { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN }, - { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN }, - { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED }, - { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED }, - { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED }, - { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED }, + { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN }, + { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN }, + { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN }, + { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN }, + { "symref-update", parse_cmd_symref_update, 4, UPDATE_REFS_OPEN }, + { "symref-create", parse_cmd_symref_create, 2, UPDATE_REFS_OPEN }, + { "symref-delete", parse_cmd_symref_delete, 2, UPDATE_REFS_OPEN }, + { "symref-verify", parse_cmd_symref_verify, 2, UPDATE_REFS_OPEN }, + { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN }, + { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED }, + { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED }, + { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED }, + { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED }, }; static void update_refs_stdin(void) @@ -564,7 +777,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) * The empty string implies that the reference * must not already exist: */ - oidclr(&oldoid); + oidclr(&oldoid, the_repository->hash_algo); else if (repo_get_oid(the_repository, oldval, &oldoid)) die("%s: not a valid old SHA1", oldval); } diff --git a/builtin/var.c b/builtin/var.c index 5dc384810c..e30ff45be1 100644 --- a/builtin/var.c +++ b/builtin/var.c @@ -12,6 +12,7 @@ #include "refs.h" #include "path.h" #include "strbuf.h" +#include "run-command.h" static const char var_usage[] = "git var (-l | <variable>)"; @@ -51,7 +52,7 @@ static char *default_branch(int ident_flag UNUSED) static char *shell_path(int ident_flag UNUSED) { - return xstrdup(SHELL_PATH); + return git_shell_path(); } static char *git_attr_val_system(int ident_flag UNUSED) diff --git a/builtin/worktree.c b/builtin/worktree.c index 1d51e54fcd..cec3ada6b0 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -769,7 +769,7 @@ static int add(int ac, const char **av, const char *prefix) char *branch_to_free = NULL; char *new_branch_to_free = NULL; const char *new_branch = NULL; - const char *opt_track = NULL; + char *opt_track = NULL; const char *lock_reason = NULL; int keep_locked = 0; int used_new_branch_options; @@ -846,7 +846,7 @@ static int add(int ac, const char **av, const char *prefix) if (opts.orphan && !new_branch) { int n; const char *s = worktree_basename(path, &n); - new_branch = xstrndup(s, n); + new_branch = new_branch_to_free = xstrndup(s, n); } else if (opts.orphan) { ; /* no-op */ } else if (opts.detach) { @@ -875,7 +875,7 @@ static int add(int ac, const char **av, const char *prefix) remote = unique_tracking_name(branch, &oid, NULL); if (remote) { new_branch = branch; - branch = remote; + branch = new_branch_to_free = remote; } } @@ -923,6 +923,7 @@ static int add(int ac, const char **av, const char *prefix) ret = add_worktree(path, branch, &opts); free(path); + free(opt_track); free(branch_to_free); free(new_branch_to_free); return ret; diff --git a/bulk-checkin.c b/bulk-checkin.c index eb46b88637..da8673199b 100644 --- a/bulk-checkin.c +++ b/bulk-checkin.c @@ -1,6 +1,9 @@ /* * Copyright (c) 2011, Google Inc. */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "bulk-checkin.h" #include "environment.h" diff --git a/bundle-uri.c b/bundle-uri.c index 91b3319a5c..1e0ee156ba 100644 --- a/bundle-uri.c +++ b/bundle-uri.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "bundle-uri.h" #include "bundle.h" @@ -9,6 +11,7 @@ #include "hashmap.h" #include "pkt-line.h" #include "config.h" +#include "fetch-pack.h" #include "remote.h" static struct { @@ -373,7 +376,7 @@ static int unbundle_from_file(struct repository *r, const char *file) * the prerequisite commits. */ if ((result = unbundle(r, &header, bundle_fd, NULL, - VERIFY_BUNDLE_QUIET))) + VERIFY_BUNDLE_QUIET | (fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0)))) return 1; /* @@ -400,8 +403,7 @@ static int unbundle_from_file(struct repository *r, const char *file) refs_update_ref(get_main_ref_store(the_repository), "fetched bundle", bundle_ref.buf, oid, has_old ? &old_oid : NULL, - REF_SKIP_OID_VERIFICATION, - UPDATE_REFS_MSG_ON_ERR); + 0, UPDATE_REFS_MSG_ON_ERR); } bundle_header_release(&header); @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "lockfile.h" #include "bundle.h" @@ -500,6 +502,7 @@ int create_bundle(struct repository *r, const char *path, struct rev_info revs, revs_copy; int min_version = 2; struct bundle_prerequisites_info bpi; + int ret; int i; /* init revs to list objects for pack-objects later */ @@ -525,8 +528,8 @@ int create_bundle(struct repository *r, const char *path, min_version = 3; if (argc > 1) { - error(_("unrecognized argument: %s"), argv[1]); - goto err; + ret = error(_("unrecognized argument: %s"), argv[1]); + goto out; } bundle_to_stdout = !strcmp(path, "-"); @@ -591,23 +594,31 @@ int create_bundle(struct repository *r, const char *path, /* write bundle refs */ ref_count = write_bundle_refs(bundle_fd, &revs_copy); - if (!ref_count) + if (!ref_count) { die(_("Refusing to create empty bundle.")); - else if (ref_count < 0) - goto err; + } else if (ref_count < 0) { + ret = -1; + goto out; + } /* write pack */ - if (write_pack_data(bundle_fd, &revs_copy, pack_options)) - goto err; + if (write_pack_data(bundle_fd, &revs_copy, pack_options)) { + ret = -1; + goto out; + } if (!bundle_to_stdout) { if (commit_lock_file(&lock)) die_errno(_("cannot create '%s'"), path); } - return 0; -err: + + ret = 0; + +out: + object_array_clear(&revs_copy.pending); + release_revisions(&revs); rollback_lock_file(&lock); - return -1; + return ret; } int unbundle(struct repository *r, struct bundle_header *header, @@ -625,6 +636,9 @@ int unbundle(struct repository *r, struct bundle_header *header, if (header->filter.choice) strvec_push(&ip.args, "--promisor=from-bundle"); + if (flags & VERIFY_BUNDLE_FSCK) + strvec_push(&ip.args, "--fsck-objects"); + if (extra_index_pack_args) { strvec_pushv(&ip.args, extra_index_pack_args->v); strvec_clear(extra_index_pack_args); @@ -33,6 +33,7 @@ int create_bundle(struct repository *r, const char *path, enum verify_bundle_flags { VERIFY_BUNDLE_VERBOSE = (1 << 0), VERIFY_BUNDLE_QUIET = (1 << 1), + VERIFY_BUNDLE_FSCK = (1 << 2), }; int verify_bundle(struct repository *r, struct bundle_header *header, diff --git a/cache-tree.c b/cache-tree.c index 387c0a3e5b..50610c3f3c 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "hex.h" @@ -422,7 +424,7 @@ static int update_one(struct cache_tree *it, /* * "sub" can be an empty tree if all subentries are i-t-a. */ - if (contains_ita && is_empty_tree_oid(oid)) + if (contains_ita && is_empty_tree_oid(oid, the_repository->hash_algo)) continue; strbuf_grow(&buffer, entlen + 100); @@ -578,7 +580,8 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p) if (0 <= it->entry_count) { if (size < rawsz) goto free_return; - oidread(&it->oid, (const unsigned char *)buf); + oidread(&it->oid, (const unsigned char *)buf, + the_repository->hash_algo); buf += rawsz; size -= rawsz; } diff --git a/checkout.c b/checkout.c index cfaea4bd10..0b1cf8b40b 100644 --- a/checkout.c +++ b/checkout.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "object-name.h" #include "remote.h" diff --git a/checkout.h b/checkout.h index ba15a13fb3..55920e7aeb 100644 --- a/checkout.h +++ b/checkout.h @@ -1,7 +1,7 @@ #ifndef CHECKOUT_H #define CHECKOUT_H -#include "hash-ll.h" +#include "hash.h" /* * Check if the branch name uniquely matches a branch name on a remote diff --git a/chunk-format.c b/chunk-format.c index cdc7f39b70..2dde24e6a3 100644 --- a/chunk-format.c +++ b/chunk-format.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "chunk-format.h" #include "csum-file.h" diff --git a/chunk-format.h b/chunk-format.h index 14b76180ef..212a0a6af1 100644 --- a/chunk-format.h +++ b/chunk-format.h @@ -1,7 +1,7 @@ #ifndef CHUNK_FORMAT_H #define CHUNK_FORMAT_H -#include "hash-ll.h" +#include "hash.h" struct hashfile; struct chunkfile; diff --git a/ci/check-directional-formatting.bash b/ci/check-directional-formatting.bash index e6211b141a..3cbbb7030e 100755 --- a/ci/check-directional-formatting.bash +++ b/ci/check-directional-formatting.bash @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # This script verifies that the non-binary files tracked in the Git index do # not contain any Unicode directional formatting: such formatting could be used diff --git a/ci/check-whitespace.sh b/ci/check-whitespace.sh index db399097a5..c40804394c 100755 --- a/ci/check-whitespace.sh +++ b/ci/check-whitespace.sh @@ -9,7 +9,7 @@ baseCommit=$1 outputFile=$2 url=$3 -if test "$#" -ne 1 && test "$#" -ne 3 +if test "$#" -ne 1 && test "$#" -ne 3 || test -z "$1" then echo "USAGE: $0 <BASE_COMMIT> [<OUTPUT_FILE> <URL>]" exit 1 @@ -21,6 +21,12 @@ commitText= commitTextmd= goodParent= +if ! git rev-parse --quiet --verify "${baseCommit}" +then + echo "Invalid <BASE_COMMIT> '${baseCommit}'" + exit 1 +fi + while read dash sha etc do case "${dash}" in @@ -67,7 +73,7 @@ then goodParent=${baseCommit: 0:7} fi - echo "A whitespace issue was found in onen of more of the commits." + echo "A whitespace issue was found in one or more of the commits." echo "Run the following command to resolve whitespace issues:" echo "git rebase --whitespace=fix ${goodParent}" diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh index 6ec0f85972..4781cd20bb 100755 --- a/ci/install-dependencies.sh +++ b/ci/install-dependencies.sh @@ -7,7 +7,7 @@ begin_group "Install dependencies" -P4WHENCE=https://cdist2.perforce.com/perforce/r21.2 +P4WHENCE=https://cdist2.perforce.com/perforce/r23.2 LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION JGITWHENCE=https://repo.eclipse.org/content/groups/releases//org/eclipse/jgit/org.eclipse.jgit.pgm/6.8.0.202311291450-r/org.eclipse.jgit.pgm-6.8.0.202311291450-r.sh @@ -87,6 +87,10 @@ macos-*) esac case "$jobname" in +ClangFormat) + sudo apt-get -q update + sudo apt-get -q -y install clang-format + ;; StaticAnalysis) sudo apt-get -q update sudo apt-get -q -y install coccinelle libcurl4-openssl-dev libssl-dev \ @@ -328,7 +328,7 @@ ubuntu-*) # Python 2 is end of life, and Ubuntu 23.04 and newer don't actually # have it anymore. We thus only test with Python 2 on older LTS # releases. - if "$distro" = "ubuntu-20.04" + if test "$distro" = "ubuntu-20.04" then PYTHON_PACKAGE=python2 else @@ -370,7 +370,6 @@ linux-musl) linux-leaks|linux-reftable-leaks) export SANITIZE=leak export GIT_TEST_PASSING_SANITIZE_LEAK=true - export GIT_TEST_SANITIZE_LEAK_LOG=true ;; linux-asan-ubsan) export SANITIZE=address,undefined diff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh index 797d65c661..af8065f349 100755 --- a/ci/run-build-and-minimal-fuzzers.sh +++ b/ci/run-build-and-minimal-fuzzers.sh @@ -6,6 +6,7 @@ . ${0%/*}/lib.sh group "Build fuzzers" make \ + NO_CURL=NoThanks \ CC=clang \ FUZZ_CXX=clang++ \ CFLAGS="-fsanitize=fuzzer-no-link,address" \ diff --git a/ci/run-style-check.sh b/ci/run-style-check.sh new file mode 100755 index 0000000000..6cd4b1d934 --- /dev/null +++ b/ci/run-style-check.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Perform style check +# + +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 \ + --diff --extensions c,h "$baseCommit" diff --git a/ci/test-documentation.sh b/ci/test-documentation.sh index de41888430..02b3af3941 100755 --- a/ci/test-documentation.sh +++ b/ci/test-documentation.sh @@ -11,6 +11,7 @@ filter_log () { -e '/^ \* new asciidoc flags$/d' \ -e '/stripped namespace before processing/d' \ -e '/Attributed.*IDs for element/d' \ + -e '/SyntaxWarning: invalid escape sequence/d' \ "$1" } diff --git a/combine-diff.c b/combine-diff.c index 4960d904ac..829a44e416 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "object-store-ll.h" #include "commit.h" diff --git a/command-list.txt b/command-list.txt index c4cd0f352b..e0bb87b3b5 100644 --- a/command-list.txt +++ b/command-list.txt @@ -157,6 +157,7 @@ git-read-tree plumbingmanipulators git-rebase mainporcelain history git-receive-pack synchelpers git-reflog ancillarymanipulators complete +git-refs ancillarymanipulators complete git-remote ancillarymanipulators complete git-repack ancillarymanipulators complete git-replace ancillarymanipulators complete diff --git a/commit-graph.c b/commit-graph.c index e5dd3553df..79b0e72cc4 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "csum-file.h" @@ -344,7 +346,6 @@ static int graph_read_bloom_data(const unsigned char *chunk_start, size_t chunk_size, void *data) { struct commit_graph *g = data; - uint32_t hash_version; if (chunk_size < BLOOMDATA_CHUNK_HEADER_SIZE) { warning(_("ignoring too-small changed-path chunk" @@ -356,13 +357,9 @@ static int graph_read_bloom_data(const unsigned char *chunk_start, g->chunk_bloom_data = chunk_start; g->chunk_bloom_data_size = chunk_size; - hash_version = get_be32(chunk_start); - - if (hash_version != 1) - return 0; g->bloom_filter_settings = xmalloc(sizeof(struct bloom_filter_settings)); - g->bloom_filter_settings->hash_version = hash_version; + g->bloom_filter_settings->hash_version = get_be32(chunk_start); g->bloom_filter_settings->num_hashes = get_be32(chunk_start + 4); g->bloom_filter_settings->bits_per_entry = get_be32(chunk_start + 8); g->bloom_filter_settings->max_changed_paths = DEFAULT_BLOOM_MAX_CHANGES; @@ -459,7 +456,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s, graph->read_generation_data = 1; } - if (s->commit_graph_read_changed_paths) { + if (s->commit_graph_changed_paths_version) { read_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES, graph_read_bloom_index, graph); read_chunk(cf, GRAPH_CHUNKID_BLOOMDATA, @@ -475,7 +472,8 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s, FREE_AND_NULL(graph->bloom_filter_settings); } - oidread(&graph->oid, graph->data + graph->data_len - graph->hash_len); + oidread(&graph->oid, graph->data + graph->data_len - graph->hash_len, + the_repository->hash_algo); free_chunkfile(cf); return graph; @@ -543,6 +541,31 @@ static int validate_mixed_generation_chain(struct commit_graph *g) return 0; } +static void validate_mixed_bloom_settings(struct commit_graph *g) +{ + struct bloom_filter_settings *settings = NULL; + for (; g; g = g->base_graph) { + if (!g->bloom_filter_settings) + continue; + if (!settings) { + settings = g->bloom_filter_settings; + continue; + } + + if (g->bloom_filter_settings->bits_per_entry != settings->bits_per_entry || + g->bloom_filter_settings->num_hashes != settings->num_hashes || + g->bloom_filter_settings->hash_version != settings->hash_version) { + g->chunk_bloom_indexes = NULL; + g->chunk_bloom_data = NULL; + FREE_AND_NULL(g->bloom_filter_settings); + + warning(_("disabling Bloom filters for commit-graph " + "layer '%s' due to incompatible settings"), + oid_to_hex(&g->oid)); + } + } +} + static int add_graph_to_chain(struct commit_graph *g, struct commit_graph *chain, struct object_id *oids, @@ -565,7 +588,8 @@ static int add_graph_to_chain(struct commit_graph *g, if (!cur_g || !oideq(&oids[n], &cur_g->oid) || - !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n))) { + !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n), + the_repository->hash_algo)) { warning(_("commit-graph chain does not match")); return 0; } @@ -666,6 +690,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r, } validate_mixed_generation_chain(graph_chain); + validate_mixed_bloom_settings(graph_chain); free(oids); fclose(fp); @@ -810,6 +835,7 @@ void close_commit_graph(struct raw_object_store *o) return; clear_commit_graph_data_slab(&commit_graph_data_slab); + deinit_bloom_filters(); free_commit_graph(o->commit_graph); o->commit_graph = NULL; } @@ -837,7 +863,8 @@ static void load_oid_from_graph(struct commit_graph *g, lex_index = pos - g->num_commits_in_base; - oidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index)); + oidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index), + the_repository->hash_algo); } static struct commit_list **insert_parent_or_die(struct repository *r, @@ -1079,7 +1106,7 @@ static struct tree *load_tree_for_commit(struct repository *r, commit_data = g->chunk_commit_data + st_mult(GRAPH_DATA_WIDTH, graph_pos - g->num_commits_in_base); - oidread(&oid, commit_data); + oidread(&oid, commit_data, the_repository->hash_algo); set_commit_tree(c, lookup_tree(r, &oid)); return c->maybe_tree; @@ -1147,6 +1174,7 @@ struct write_commit_graph_context { int count_bloom_filter_not_computed; int count_bloom_filter_trunc_empty; int count_bloom_filter_trunc_large; + int count_bloom_filter_upgraded; }; static int write_graph_chunk_fanout(struct hashfile *f, @@ -1597,7 +1625,7 @@ static void compute_reachable_generation_numbers( timestamp_t gen; repo_parse_commit(info->r, c); gen = info->get_generation(c, info->data); - display_progress(info->progress, info->progress_cnt + 1); + display_progress(info->progress, ++info->progress_cnt); if (gen != GENERATION_NUMBER_ZERO && gen != GENERATION_NUMBER_INFINITY) continue; @@ -1754,6 +1782,8 @@ static void trace2_bloom_filter_write_statistics(struct write_commit_graph_conte ctx->count_bloom_filter_trunc_empty); trace2_data_intmax("commit-graph", ctx->r, "filter-trunc-large", ctx->count_bloom_filter_trunc_large); + trace2_data_intmax("commit-graph", ctx->r, "filter-upgraded", + ctx->count_bloom_filter_upgraded); } static void compute_bloom_filters(struct write_commit_graph_context *ctx) @@ -1795,6 +1825,8 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx) ctx->count_bloom_filter_trunc_empty++; if (computed & BLOOM_TRUNC_LARGE) ctx->count_bloom_filter_trunc_large++; + } else if (computed & BLOOM_UPGRADED) { + ctx->count_bloom_filter_upgraded++; } else if (computed & BLOOM_NOT_COMPUTED) ctx->count_bloom_filter_not_computed++; ctx->total_bloom_filter_data_size += filter @@ -2002,8 +2034,8 @@ static int write_graph_chunk_base(struct hashfile *f, static int write_commit_graph_file(struct write_commit_graph_context *ctx) { uint32_t i; - int fd; struct hashfile *f; + struct tempfile *graph_layer; /* when ctx->split is non-zero */ struct lock_file lk = LOCK_INIT; const unsigned hashsz = the_hash_algo->rawsz; struct strbuf progress_title = STRBUF_INIT; @@ -2035,24 +2067,23 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) LOCK_DIE_ON_ERROR, 0444); free(lock_name); - fd = git_mkstemp_mode(ctx->graph_name, 0444); - if (fd < 0) { + graph_layer = mks_tempfile_m(ctx->graph_name, 0444); + if (!graph_layer) { error(_("unable to create temporary graph layer")); return -1; } - if (adjust_shared_perm(ctx->graph_name)) { + if (adjust_shared_perm(get_tempfile_path(graph_layer))) { error(_("unable to adjust shared permissions for '%s'"), - ctx->graph_name); + get_tempfile_path(graph_layer)); return -1; } - f = hashfd(fd, ctx->graph_name); + f = hashfd(get_tempfile_fd(graph_layer), get_tempfile_path(graph_layer)); } else { hold_lock_file_for_update_mode(&lk, ctx->graph_name, LOCK_DIE_ON_ERROR, 0444); - fd = get_lock_file_fd(&lk); - f = hashfd(fd, get_lock_file_path(&lk)); + f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk)); } cf = init_chunkfile(f); @@ -2133,8 +2164,6 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) char *final_graph_name; int result; - close(fd); - if (!chainf) { error(_("unable to open commit-graph chain file")); return -1; @@ -2169,7 +2198,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1]); ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name; - result = rename(ctx->graph_name, final_graph_name); + result = rename_tempfile(&graph_layer, final_graph_name); for (i = 0; i < ctx->num_commit_graphs_after; i++) fprintf(get_lock_file_fp(&lk), "%s\n", ctx->commit_graph_hash_after[i]); @@ -2479,6 +2508,13 @@ int write_commit_graph(struct object_directory *odb, } if (!commit_graph_compatible(r)) return 0; + if (r->settings.commit_graph_changed_paths_version < -1 + || r->settings.commit_graph_changed_paths_version > 2) { + warning(_("attempting to write a commit-graph, but " + "'commitGraph.changedPathsVersion' (%d) is not supported"), + r->settings.commit_graph_changed_paths_version); + return 0; + } CALLOC_ARRAY(ctx, 1); ctx->r = r; @@ -2491,6 +2527,7 @@ int write_commit_graph(struct object_directory *odb, ctx->write_generation_data = (get_configured_generation_version(r) == 2); ctx->num_generation_data_overflows = 0; + bloom_settings.hash_version = r->settings.commit_graph_changed_paths_version; bloom_settings.bits_per_entry = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY", bloom_settings.bits_per_entry); bloom_settings.num_hashes = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_NUM_HASHES", @@ -2520,12 +2557,20 @@ int write_commit_graph(struct object_directory *odb, g = ctx->r->objects->commit_graph; /* We have changed-paths already. Keep them in the next graph */ - if (g && g->chunk_bloom_data) { + if (g && g->bloom_filter_settings) { ctx->changed_paths = 1; - ctx->bloom_settings = g->bloom_filter_settings; + + /* don't propagate the hash_version unless unspecified */ + if (bloom_settings.hash_version == -1) + bloom_settings.hash_version = g->bloom_filter_settings->hash_version; + bloom_settings.bits_per_entry = g->bloom_filter_settings->bits_per_entry; + bloom_settings.num_hashes = g->bloom_filter_settings->num_hashes; + bloom_settings.max_changed_paths = g->bloom_filter_settings->max_changed_paths; } } + bloom_settings.hash_version = bloom_settings.hash_version == 2 ? 2 : 1; + if (ctx->split) { struct commit_graph *g = ctx->r->objects->commit_graph; @@ -2555,7 +2600,8 @@ int write_commit_graph(struct object_directory *odb, struct commit_graph *g = ctx->r->objects->commit_graph; for (i = 0; i < g->num_commits; i++) { struct object_id oid; - oidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i)); + oidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i), + the_repository->hash_algo); oid_array_append(&ctx->oids, &oid); } } @@ -2608,6 +2654,9 @@ int write_commit_graph(struct object_directory *odb, res = write_commit_graph_file(ctx); + if (ctx->changed_paths) + deinit_bloom_filters(); + if (ctx->split) mark_commit_graphs(ctx); @@ -2674,7 +2723,8 @@ static int verify_one_commit_graph(struct repository *r, for (i = 0; i < g->num_commits; i++) { struct commit *graph_commit; - oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i)); + oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i), + the_repository->hash_algo); if (i && oidcmp(&prev_oid, &cur_oid) >= 0) graph_report(_("commit-graph has incorrect OID order: %s then %s"), @@ -2718,7 +2768,8 @@ static int verify_one_commit_graph(struct repository *r, timestamp_t generation; display_progress(progress, ++(*seen)); - oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i)); + oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i), + the_repository->hash_algo); graph_commit = lookup_commit(r, &cur_oid); odb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r)); diff --git a/commit-graph.h b/commit-graph.h index e519cb81cb..6781940195 100644 --- a/commit-graph.h +++ b/commit-graph.h @@ -122,6 +122,8 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r, struct commit_graph *read_commit_graph_one(struct repository *r, struct object_directory *odb); +struct repo_settings; + /* * Callers should initialize the repo_settings with prepare_repo_settings() * prior to calling parse_commit_graph(). diff --git a/commit-reach.c b/commit-reach.c index 384aee1ab3..02f8218b8e 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "commit.h" #include "commit-graph.h" @@ -1225,4 +1227,5 @@ void tips_reachable_from_bases(struct repository *r, done: free(commits); repo_clear_commit_marks(r, SEEN); + free_commit_list(stack); } @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "tag.h" #include "commit.h" @@ -680,7 +682,7 @@ unsigned commit_list_count(const struct commit_list *l) return c; } -struct commit_list *copy_commit_list(struct commit_list *list) +struct commit_list *copy_commit_list(const struct commit_list *list) { struct commit_list *head = NULL; struct commit_list **pp = &head; @@ -1262,7 +1264,7 @@ int remove_signature(struct strbuf *buf) return sigs[0].start != NULL; } -static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail) +static void handle_signed_tag(const struct commit *parent, struct commit_extra_header ***tail) { struct merge_remote_desc *desc; struct commit_extra_header *mergetag; @@ -1359,17 +1361,17 @@ void verify_merge_signature(struct commit *commit, int verbosity, signature_check_clear(&signature_check); } -void append_merge_tag_headers(struct commit_list *parents, +void append_merge_tag_headers(const struct commit_list *parents, struct commit_extra_header ***tail) { while (parents) { - struct commit *parent = parents->item; + const struct commit *parent = parents->item; handle_signed_tag(parent, tail); parents = parents->next; } } -static int convert_commit_extra_headers(struct commit_extra_header *orig, +static int convert_commit_extra_headers(const struct commit_extra_header *orig, struct commit_extra_header **result) { const struct git_hash_algo *compat = the_repository->compat_hash_algo; @@ -1403,7 +1405,7 @@ static int convert_commit_extra_headers(struct commit_extra_header *orig, } static void add_extra_header(struct strbuf *buffer, - struct commit_extra_header *extra) + const struct commit_extra_header *extra) { strbuf_addstr(buffer, extra->key); if (extra->len) @@ -1517,7 +1519,7 @@ void free_commit_extra_headers(struct commit_extra_header *extra) } int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree, - struct commit_list *parents, struct object_id *ret, + const struct commit_list *parents, struct object_id *ret, const char *author, const char *sign_commit) { struct commit_extra_header *extra = NULL, **tail = &extra; @@ -1649,7 +1651,7 @@ static void write_commit_tree(struct strbuf *buffer, const char *msg, size_t msg const struct object_id *tree, const struct object_id *parents, size_t parents_len, const char *author, const char *committer, - struct commit_extra_header *extra) + const struct commit_extra_header *extra) { int encoding_is_utf8; size_t i; @@ -1690,10 +1692,10 @@ static void write_commit_tree(struct strbuf *buffer, const char *msg, size_t msg int commit_tree_extended(const char *msg, size_t msg_len, const struct object_id *tree, - struct commit_list *parents, struct object_id *ret, + const struct commit_list *parents, struct object_id *ret, const char *author, const char *committer, const char *sign_commit, - struct commit_extra_header *extra) + const struct commit_extra_header *extra) { struct repository *r = the_repository; int result = 0; @@ -1715,10 +1717,8 @@ int commit_tree_extended(const char *msg, size_t msg_len, nparents = commit_list_count(parents); CALLOC_ARRAY(parent_buf, nparents); i = 0; - while (parents) { - struct commit *parent = pop_commit(&parents); - oidcpy(&parent_buf[i++], &parent->object.oid); - } + for (const struct commit_list *p = parents; p; p = p->next) + oidcpy(&parent_buf[i++], &p->item->object.oid); write_commit_tree(&buffer, msg, msg_len, tree, parent_buf, nparents, author, committer, extra); if (sign_commit && sign_commit_to_strbuf(&sig, &buffer, sign_commit)) { @@ -1814,7 +1814,7 @@ out: define_commit_slab(merge_desc_slab, struct merge_remote_desc *); static struct merge_desc_slab merge_desc_slab = COMMIT_SLAB_INIT(1, merge_desc_slab); -struct merge_remote_desc *merge_remote_util(struct commit *commit) +struct merge_remote_desc *merge_remote_util(const struct commit *commit) { return *merge_desc_slab_at(&merge_desc_slab, commit); } @@ -1870,20 +1870,12 @@ struct commit_list **commit_list_append(struct commit *commit, return &new_commit->next; } -const char *find_header_mem(const char *msg, size_t len, - const char *key, size_t *out_len) +const char *find_commit_header(const char *msg, const char *key, size_t *out_len) { int key_len = strlen(key); const char *line = msg; - /* - * NEEDSWORK: It's possible for strchrnul() to scan beyond the range - * given by len. However, current callers are safe because they compute - * len by scanning a NUL-terminated block of memory starting at msg. - * Nonetheless, it would be better to ensure the function does not look - * at msg beyond the len provided by the caller. - */ - while (line && line < msg + len) { + while (line) { const char *eol = strchrnul(line, '\n'); if (line == eol) @@ -1900,10 +1892,6 @@ const char *find_header_mem(const char *msg, size_t len, return NULL; } -const char *find_commit_header(const char *msg, const char *key, size_t *out_len) -{ - return find_header_mem(msg, strlen(msg), key, out_len); -} /* * Inspect the given string and determine the true "end" of the log message, in * order to find where to put a new Signed-off-by trailer. Ignored are @@ -181,7 +181,7 @@ struct commit_list *commit_list_insert_by_date(struct commit *item, void commit_list_sort_by_date(struct commit_list **list); /* Shallow copy of the input list */ -struct commit_list *copy_commit_list(struct commit_list *list); +struct commit_list *copy_commit_list(const struct commit_list *list); /* Modify list in-place to reverse it, returning new head; list will be tail */ struct commit_list *reverse_commit_list(struct commit_list *list); @@ -260,19 +260,19 @@ struct commit_extra_header { size_t len; }; -void append_merge_tag_headers(struct commit_list *parents, +void append_merge_tag_headers(const struct commit_list *parents, struct commit_extra_header ***tail); int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree, - struct commit_list *parents, struct object_id *ret, + const struct commit_list *parents, struct object_id *ret, const char *author, const char *sign_commit); int commit_tree_extended(const char *msg, size_t msg_len, const struct object_id *tree, - struct commit_list *parents, struct object_id *ret, + const struct commit_list *parents, struct object_id *ret, const char *author, const char *committer, - const char *sign_commit, struct commit_extra_header *); + const char *sign_commit, const struct commit_extra_header *); struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **); @@ -280,17 +280,12 @@ void free_commit_extra_headers(struct commit_extra_header *extra); /* * Search the commit object contents given by "msg" for the header "key". - * Reads up to "len" bytes of "msg". * Returns a pointer to the start of the header contents, or NULL. The length * of the header, up to the first newline, is returned via out_len. * * Note that some headers (like mergetag) may be multi-line. It is the caller's * responsibility to parse further in this case! */ -const char *find_header_mem(const char *msg, size_t len, - const char *key, - size_t *out_len); - const char *find_commit_header(const char *msg, const char *key, size_t *out_len); @@ -306,7 +301,7 @@ struct merge_remote_desc { struct object *obj; /* the named object, could be a tag */ char name[FLEX_ARRAY]; }; -struct merge_remote_desc *merge_remote_util(struct commit *); +struct merge_remote_desc *merge_remote_util(const struct commit *); void set_merge_remote_desc(struct commit *commit, const char *name, struct object *obj); diff --git a/common-main.c b/common-main.c index b86f40600f..8e68ac9e42 100644 --- a/common-main.c +++ b/common-main.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "exec-cmd.h" #include "gettext.h" diff --git a/compat/basename.c b/compat/basename.c index 96bd9533b4..c33579ef61 100644 --- a/compat/basename.c +++ b/compat/basename.c @@ -10,7 +10,13 @@ char *gitbasename (char *path) skip_dos_drive_prefix(&path); if (!path || !*path) - return "."; + /* + * basename(3P) is mis-specified because it returns a + * non-constant pointer even though it is specified to return a + * pointer to internal memory at times. The cast is a result of + * that. + */ + return (char *) "."; for (base = path; *path; path++) { if (!is_dir_sep(*path)) @@ -34,7 +40,13 @@ char *gitdirname(char *path) int dos_drive_prefix; if (!p) - return "."; + /* + * dirname(3P) is mis-specified because it returns a + * non-constant pointer even though it is specified to return a + * pointer to internal memory at times. The cast is a result of + * that. + */ + return (char *) "."; if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p) goto dot; diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c index 6f3a95410c..52f4f29720 100644 --- a/compat/fsmonitor/fsm-ipc-darwin.c +++ b/compat/fsmonitor/fsm-ipc-darwin.c @@ -17,7 +17,7 @@ const char *fsmonitor_ipc__get_path(struct repository *r) git_SHA_CTX sha1ctx; char *sock_dir = NULL; struct strbuf ipc_file = STRBUF_INIT; - unsigned char hash[GIT_MAX_RAWSZ]; + unsigned char hash[GIT_SHA1_RAWSZ]; if (!r) BUG("No repository passed into fsmonitor_ipc__get_path"); @@ -41,9 +41,10 @@ const char *fsmonitor_ipc__get_path(struct repository *r) /* Create the socket file in either socketDir or $HOME */ if (sock_dir && *sock_dir) { strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s", - sock_dir, hash_to_hex(hash)); + sock_dir, hash_to_hex_algop(hash, &hash_algos[GIT_HASH_SHA1])); } else { - strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash)); + strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", + hash_to_hex_algop(hash, &hash_algos[GIT_HASH_SHA1])); } free(sock_dir); diff --git a/compat/mingw.c b/compat/mingw.c index 6b06ea540f..29d3f09768 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -26,7 +26,6 @@ static const int delay[] = { 0, 1, 10, 20, 40 }; void open_in_gdb(void) { static struct child_process cp = CHILD_PROCESS_INIT; - extern char *_pgmptr; strvec_pushl(&cp.args, "mintty", "gdb", NULL); strvec_pushf(&cp.args, "--pid=%d", getpid()); @@ -1547,7 +1546,7 @@ static int is_msys2_sh(const char *cmd) return ret; } - if (ends_with(cmd, "\\sh.exe")) { + if (ends_with(cmd, "\\sh.exe") || ends_with(cmd, "/sh.exe")) { static char *sh; if (!sh) @@ -2279,7 +2278,11 @@ struct passwd *getpwuid(int uid) p->pw_name = user_name; p->pw_gecos = get_extended_user_info(NameDisplay); if (!p->pw_gecos) - p->pw_gecos = "unknown"; + /* + * Data returned by getpwuid(3P) is treated as internal and + * must never be written to or freed. + */ + p->pw_gecos = (char *) "unknown"; p->pw_dir = NULL; initialized = 1; @@ -2800,16 +2803,16 @@ int is_path_owned_by_current_sid(const char *path, struct strbuf *report) strbuf_addf(report, "'%s' is on a file system that does " "not record ownership\n", path); } else if (report) { - LPSTR str1, str2, str3, str4, to_free1 = NULL, - to_free3 = NULL, to_local_free2 = NULL, - to_local_free4 = NULL; + PCSTR str1, str2, str3, str4; + LPSTR to_free1 = NULL, to_free3 = NULL, + to_local_free2 = NULL, to_local_free4 = NULL; - if (user_sid_to_user_name(sid, &str1)) - to_free1 = str1; + if (user_sid_to_user_name(sid, &to_free1)) + str1 = to_free1; else str1 = "(inconvertible)"; - if (ConvertSidToStringSidA(sid, &str2)) - to_local_free2 = str2; + if (ConvertSidToStringSidA(sid, &to_local_free2)) + str2 = to_local_free2; else str2 = "(inconvertible)"; @@ -2822,13 +2825,13 @@ int is_path_owned_by_current_sid(const char *path, struct strbuf *report) str4 = "(invalid)"; } else { if (user_sid_to_user_name(current_user_sid, - &str3)) - to_free3 = str3; + &to_free3)) + str3 = to_free3; else str3 = "(inconvertible)"; if (ConvertSidToStringSidA(current_user_sid, - &str4)) - to_local_free4 = str4; + &to_local_free4)) + str4 = to_local_free4; else str4 = "(inconvertible)"; } diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c index 2bc0f1187a..6c5d455e92 100644 --- a/compat/regex/regcomp.c +++ b/compat/regex/regcomp.c @@ -848,7 +848,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len) { unsigned int table_size; #ifndef _LIBC - char *codeset_name; + const char *codeset_name; #endif memset (dfa, '\0', sizeof (re_dfa_t)); diff --git a/compat/sha1-chunked.c b/compat/sha1-chunked.c index a4a6f930d7..0446f9983f 100644 --- a/compat/sha1-chunked.c +++ b/compat/sha1-chunked.c @@ -1,5 +1,5 @@ #include "git-compat-util.h" -#include "hash-ll.h" +#include "hash.h" int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len) { diff --git a/compat/win32/path-utils.c b/compat/win32/path-utils.c index ebf2f12eb6..b658ca3f81 100644 --- a/compat/win32/path-utils.c +++ b/compat/win32/path-utils.c @@ -1,4 +1,5 @@ #include "../../git-compat-util.h" +#include "../../environment.h" int win32_has_dos_drive_prefix(const char *path) { @@ -50,3 +51,39 @@ int win32_offset_1st_component(const char *path) return pos + is_dir_sep(*pos) - path; } + +int win32_fspathncmp(const char *a, const char *b, size_t count) +{ + int diff; + + for (;;) { + if (!count--) + return 0; + if (!*a) + return *b ? -1 : 0; + if (!*b) + return +1; + + if (is_dir_sep(*a)) { + if (!is_dir_sep(*b)) + return -1; + a++; + b++; + continue; + } else if (is_dir_sep(*b)) + return +1; + + diff = ignore_case ? + (unsigned char)tolower(*a) - (int)(unsigned char)tolower(*b) : + (unsigned char)*a - (int)(unsigned char)*b; + if (diff) + return diff; + a++; + b++; + } +} + +int win32_fspathcmp(const char *a, const char *b) +{ + return win32_fspathncmp(a, b, (size_t)-1); +} diff --git a/compat/win32/path-utils.h b/compat/win32/path-utils.h index 65fa3b9263..a561c700e7 100644 --- a/compat/win32/path-utils.h +++ b/compat/win32/path-utils.h @@ -29,5 +29,9 @@ static inline int win32_has_dir_sep(const char *path) #define has_dir_sep(path) win32_has_dir_sep(path) int win32_offset_1st_component(const char *path); #define offset_1st_component win32_offset_1st_component +int win32_fspathcmp(const char *a, const char *b); +#define fspathcmp win32_fspathcmp +int win32_fspathncmp(const char *a, const char *b, size_t count); +#define fspathncmp win32_fspathncmp #endif diff --git a/compat/win32/trace2_win32_process_info.c b/compat/win32/trace2_win32_process_info.c index 3ef0936f6f..f147da706a 100644 --- a/compat/win32/trace2_win32_process_info.c +++ b/compat/win32/trace2_win32_process_info.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "../../git-compat-util.h" #include "../../json-writer.h" #include "../../repository.h" diff --git a/compat/winansi.c b/compat/winansi.c index f83610f684..575813bde8 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -139,7 +139,7 @@ static void write_console(unsigned char *str, size_t len) /* convert utf-8 to utf-16 */ int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len); if (wlen < 0) { - wchar_t *err = L"[invalid]"; + const wchar_t *err = L"[invalid]"; WriteConsoleW(console, err, wcslen(err), &dummy, NULL); return; } @@ -5,6 +5,9 @@ * Copyright (C) Johannes Schindelin, 2005 * */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "advice.h" @@ -1244,6 +1247,15 @@ ssize_t git_config_ssize_t(const char *name, const char *value, return ret; } +double git_config_double(const char *name, const char *value, + const struct key_value_info *kvi) +{ + double ret; + if (!git_parse_double(value, &ret)) + die_bad_number(name, value, kvi); + return ret; +} + static const struct fsync_component_name { const char *name; enum fsync_component component_bits; @@ -1460,10 +1472,10 @@ static int git_default_core_config(const char *var, const char *value, if (!strcasecmp(value, "auto")) default_abbrev = -1; else if (!git_parse_maybe_bool_text(value)) - default_abbrev = the_hash_algo->hexsz; + default_abbrev = GIT_MAX_HEXSZ; else { int abbrev = git_config_int(var, value, ctx->kvi); - if (abbrev < minimum_abbrev || abbrev > the_hash_algo->hexsz) + if (abbrev < minimum_abbrev) return error(_("abbrev length out of range: %d"), abbrev); default_abbrev = abbrev; } @@ -1565,6 +1577,7 @@ static int git_default_core_config(const char *var, const char *value, if (!strcmp(var, "core.notesref")) { if (!value) return config_error_nonbool(var); + free(notes_ref_name); notes_ref_name = xstrdup(value); return 0; } @@ -2844,7 +2857,6 @@ void git_die_config_linenr(const char *key, const char *filename, int linenr) key, filename, linenr); } -NORETURN __attribute__((format(printf, 2, 3))) void git_die_config(const char *key, const char *err, ...) { const struct string_list *values; @@ -2902,7 +2914,7 @@ static int matches(const char *key, const char *value, { if (strcmp(key, store->key)) return 0; /* not ours */ - if (store->fixed_value) + if (store->fixed_value && value) return !strcmp(store->fixed_value, value); if (!store->value_pattern) return 1; /* always matches */ @@ -262,6 +262,13 @@ ssize_t git_config_ssize_t(const char *, const char *, const struct key_value_info *); /** + * Identically to `git_config_double`, but for double-precision floating point + * values. + */ +double git_config_double(const char *, const char *, + const struct key_value_info *); + +/** * Same as `git_config_bool`, except that integers are returned as-is, and * an `is_bool` flag is unset. */ diff --git a/config.mak.dev b/config.mak.dev index 981304727c..5229c35484 100644 --- a/config.mak.dev +++ b/config.mak.dev @@ -10,7 +10,7 @@ endif DEVELOPER_CFLAGS += -Wall ifeq ($(filter no-pedantic,$(DEVOPTS)),) DEVELOPER_CFLAGS += -pedantic -ifneq (($or $(filter gcc5,$(COMPILER_FEATURES)),$(filter clang4,$(COMPILER_FEATURES))),) +ifneq ($(or $(filter gcc5,$(COMPILER_FEATURES)),$(filter clang4,$(COMPILER_FEATURES))),) DEVELOPER_CFLAGS += -Wpedantic ifneq ($(filter gcc10,$(COMPILER_FEATURES)),) ifeq ($(uname_S),MINGW) @@ -37,6 +37,7 @@ DEVELOPER_CFLAGS += -Wpointer-arith DEVELOPER_CFLAGS += -Wstrict-prototypes DEVELOPER_CFLAGS += -Wunused DEVELOPER_CFLAGS += -Wvla +DEVELOPER_CFLAGS += -Wwrite-strings DEVELOPER_CFLAGS += -fno-common ifneq ($(filter clang4,$(COMPILER_FEATURES)),) diff --git a/config.mak.uname b/config.mak.uname index 85d63821ec..aa0fd26bd5 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -8,7 +8,6 @@ uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') uname_M := $(shell sh -c 'uname -m 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') -uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') ifneq ($(findstring MINGW,$(uname_S)),) @@ -38,8 +38,8 @@ static int check_ref(const char *name, unsigned int flags) REFNAME_ALLOW_ONELEVEL)) return 0; - /* REF_HEADS means that we want regular branch heads */ - if ((flags & REF_HEADS) && starts_with(name, "heads/")) + /* REF_BRANCHES means that we want regular branch heads */ + if ((flags & REF_BRANCHES) && starts_with(name, "heads/")) return 1; /* REF_TAGS means that we want tags */ diff --git a/connected.c b/connected.c index 8f89376dbc..87cc4b57a1 100644 --- a/connected.c +++ b/connected.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "hex.h" diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 2f9c33585c..832f46b316 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -976,11 +976,12 @@ list(TRANSFORM test-reftable_SOURCES PREPEND "${CMAKE_SOURCE_DIR}/") #unit-tests add_library(unit-test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c) +add_library(unit-test-lib-oid OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/lib-oid.c) parse_makefile_for_scripts(unit_test_PROGRAMS "UNIT_TEST_PROGRAMS" "") foreach(unit_test ${unit_test_PROGRAMS}) add_executable("${unit_test}" "${CMAKE_SOURCE_DIR}/t/unit-tests/${unit_test}.c") - target_link_libraries("${unit_test}" unit-test-lib common-main) + target_link_libraries("${unit_test}" unit-test-lib unit-test-lib-oid common-main) set_target_properties("${unit_test}" PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin) if(MSVC) diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c index 6ce22a28ed..1c8310d7fe 100644 --- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c +++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c @@ -141,7 +141,7 @@ static void find_username_in_item(CFDictionaryRef item) username_buf, buffer_len, ENCODING)) { - write_item("username", username_buf, buffer_len - 1); + write_item("username", username_buf, strlen(username_buf)); } free(username_buf); } @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "advice.h" #include "config.h" @@ -322,6 +324,9 @@ static void trace_encoding(const char *context, const char *path, struct strbuf trace = STRBUF_INIT; int i; + if (!trace_want(&coe)) + return; + strbuf_addf(&trace, "%s (%s, considered %s):\n", context, path, encoding); for (i = 0; i < len && buf; ++i) { strbuf_addf( @@ -958,7 +963,7 @@ int async_query_available_blobs(const char *cmd, struct string_list *available_p while ((line = packet_read_line(process->out, NULL))) { const char *path; if (skip_prefix(line, "pathname=", &path)) - string_list_insert(available_paths, xstrdup(path)); + string_list_insert(available_paths, path); else ; /* ignore unknown keys */ } @@ -1048,14 +1053,20 @@ static int read_convert_config(const char *var, const char *value, * The command-line will not be interpolated in any way. */ - if (!strcmp("smudge", key)) + if (!strcmp("smudge", key)) { + FREE_AND_NULL(drv->smudge); return git_config_string(&drv->smudge, var, value); + } - if (!strcmp("clean", key)) + if (!strcmp("clean", key)) { + FREE_AND_NULL(drv->clean); return git_config_string(&drv->clean, var, value); + } - if (!strcmp("process", key)) + if (!strcmp("process", key)) { + FREE_AND_NULL(drv->process); return git_config_string(&drv->process, var, value); + } if (!strcmp("required", key)) { drv->required = git_config_bool(var, value); @@ -4,7 +4,7 @@ #ifndef CONVERT_H #define CONVERT_H -#include "hash-ll.h" +#include "hash.h" #include "string-list.h" struct index_state; diff --git a/credential.c b/credential.c index 758528b291..4b1a2b94fe 100644 --- a/credential.c +++ b/credential.c @@ -20,12 +20,11 @@ void credential_init(struct credential *c) void credential_clear(struct credential *c) { + credential_clear_secrets(c); free(c->protocol); free(c->host); free(c->path); free(c->username); - free(c->password); - free(c->credential); free(c->oauth_refresh_token); free(c->authtype); string_list_clear(&c->helpers, 0); @@ -479,9 +478,15 @@ void credential_fill(struct credential *c, int all_capabilities) for (i = 0; i < c->helpers.nr; i++) { credential_do(c, c->helpers.items[i].string, "get"); + if (c->password_expiry_utc < time(NULL)) { - /* Discard expired password */ - FREE_AND_NULL(c->password); + /* + * Don't use credential_clear() here: callers such as + * cmd_credential() expect to still be able to call + * credential_write() on a struct credential whose + * secrets have expired. + */ + credential_clear_secrets(c); /* Reset expiry to maintain consistency */ c->password_expiry_utc = TIME_MAX; } @@ -528,9 +533,8 @@ void credential_reject(struct credential *c) for (i = 0; i < c->helpers.nr; i++) credential_do(c, c->helpers.items[i].string, "erase"); + credential_clear_secrets(c); FREE_AND_NULL(c->username); - FREE_AND_NULL(c->password); - FREE_AND_NULL(c->credential); FREE_AND_NULL(c->oauth_refresh_token); c->password_expiry_utc = TIME_MAX; c->approved = 0; diff --git a/credential.h b/credential.h index af8c287ff2..5f9e6ff2ef 100644 --- a/credential.h +++ b/credential.h @@ -5,8 +5,8 @@ #include "strvec.h" /** - * The credentials API provides an abstracted way of gathering username and - * password credentials from the user. + * The credentials API provides an abstracted way of gathering + * authentication credentials from the user. * * Typical setup * ------------- @@ -116,11 +116,12 @@ struct credential_capability { }; /** - * This struct represents a single username/password combination - * along with any associated context. All string fields should be - * heap-allocated (or NULL if they are not known or not applicable). - * The meaning of the individual context fields is the same as - * their counterparts in the helper protocol. + * This struct represents a single login credential (typically a + * username/password combination) along with any associated + * context. All string fields should be heap-allocated (or NULL if + * they are not known or not applicable). The meaning of the + * individual context fields is the same as their counterparts in + * the helper protocol. * * This struct should always be initialized with `CREDENTIAL_INIT` or * `credential_init`. @@ -207,11 +208,12 @@ void credential_clear(struct credential *); /** * Instruct the credential subsystem to fill the username and - * password fields of the passed credential struct by first - * consulting helpers, then asking the user. After this function - * returns, the username and password fields of the credential are - * guaranteed to be non-NULL. If an error occurs, the function will - * die(). + * password (or authtype and credential) fields of the passed + * credential struct by first consulting helpers, then asking the + * user. After this function returns, either the username and + * password fields or the credential field of the credential are + * guaranteed to be non-NULL. If an error occurs, the function + * will die(). * * If all_capabilities is set, this is an internal user that is prepared * to deal with all known capabilities, and we should advertise that fact. @@ -232,10 +234,10 @@ void credential_approve(struct credential *); * have been rejected. This will cause the credential subsystem to * notify any helpers of the rejection (which allows them, for * example, to purge the invalid credentials from storage). It - * will also free() the username and password fields of the - * credential and set them to NULL (readying the credential for - * another call to `credential_fill`). Any errors from helpers are - * ignored. + * will also free() the username, password, and credential fields + * of the credential and set them to NULL (readying the credential + * for another call to `credential_fill`). Any errors from helpers + * are ignored. */ void credential_reject(struct credential *); diff --git a/csum-file.c b/csum-file.c index 870748e016..2131ee6b12 100644 --- a/csum-file.c +++ b/csum-file.c @@ -7,6 +7,9 @@ * files. Useful when you write a file that you want to be * able to verify hasn't been messed with afterwards. */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "progress.h" #include "csum-file.h" @@ -68,12 +71,12 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result, hashflush(f); if (f->skip_hash) - hashclr(f->buffer); + hashclr(f->buffer, the_repository->hash_algo); else the_hash_algo->final_fn(f->buffer, &f->ctx); if (result) - hashcpy(result, f->buffer); + hashcpy(result, f->buffer, the_repository->hash_algo); if (flags & CSUM_HASH_IN_STREAM) flush(f, f->buffer, the_hash_algo->rawsz); if (flags & CSUM_FSYNC) @@ -99,6 +102,15 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result, return fd; } +void discard_hashfile(struct hashfile *f) +{ + if (0 <= f->check_fd) + close(f->check_fd); + if (0 <= f->fd) + close(f->fd); + free_hashfile(f); +} + void hashwrite(struct hashfile *f, const void *buf, unsigned int count) { while (count) { @@ -237,5 +249,5 @@ int hashfile_checksum_valid(const unsigned char *data, size_t total_len) the_hash_algo->update_fn(&ctx, data, data_len); the_hash_algo->final_fn(got, &ctx); - return hasheq(got, data + data_len); + return hasheq(got, data + data_len, the_repository->hash_algo); } diff --git a/csum-file.h b/csum-file.h index bc5bec27ac..36c7c5585f 100644 --- a/csum-file.h +++ b/csum-file.h @@ -1,7 +1,7 @@ #ifndef CSUM_FILE_H #define CSUM_FILE_H -#include "hash-ll.h" +#include "hash.h" #include "write-or-die.h" struct progress; @@ -47,6 +47,7 @@ struct hashfile *hashfd(int fd, const char *name); struct hashfile *hashfd_check(const char *name); struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp); int finalize_hashfile(struct hashfile *, unsigned char *, enum fsync_component, unsigned int); +void discard_hashfile(struct hashfile *); void hashwrite(struct hashfile *, const void *, unsigned int); void hashflush(struct hashfile *f); void crc32_begin(struct hashfile *); @@ -868,6 +868,10 @@ static int match_object_header_date(const char *date, timestamp_t *timestamp, in return 0; } + +/* timestamp of 2099-12-31T23:59:59Z, including 32 leap days */ +static const timestamp_t timestamp_max = (((timestamp_t)2100 - 1970) * 365 + 32) * 24 * 60 * 60 - 1; + /* Gr. strptime is crap for this; it doesn't have a way to require RFC2822 (i.e. English) day/month names, and it doesn't work correctly with %z. */ int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset) @@ -937,8 +941,14 @@ int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset) } } - if (!tm_gmt) + if (!tm_gmt) { + if (*offset > 0 && *offset * 60 > *timestamp) + return -1; + if (*offset < 0 && -*offset * 60 > timestamp_max - *timestamp) + return -1; *timestamp -= *offset * 60; + } + return 0; /* success */ } diff --git a/decorate.h b/decorate.h index cdeb17c9df..08af658d34 100644 --- a/decorate.h +++ b/decorate.h @@ -3,7 +3,7 @@ /* * A data structure that associates Git objects to void pointers. See - * t/helper/test-example-decorate.c for a demonstration of how to use these + * t/unit-tests/t-example-decorate.c for a demonstration of how to use these * functions. */ diff --git a/delta-islands.c b/delta-islands.c index 89d51b72e3..ffe1ca2814 100644 --- a/delta-islands.c +++ b/delta-islands.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "object.h" #include "commit.h" diff --git a/diagnose.c b/diagnose.c index 4d096c857f..cc2d535b60 100644 --- a/diagnose.c +++ b/diagnose.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "diagnose.h" #include "compat/disk.h" diff --git a/diff-lib.c b/diff-lib.c index 5a5a50c5a1..7a1eb63757 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -1,6 +1,9 @@ /* * Copyright (C) 2005 Junio C Hamano */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "commit.h" #include "diff.h" @@ -160,7 +163,7 @@ void run_diff_files(struct rev_info *revs, unsigned int option) dpath->next = NULL; memcpy(dpath->path, ce->name, path_len); dpath->path[path_len] = '\0'; - oidclr(&dpath->oid); + oidclr(&dpath->oid, the_repository->hash_algo); memset(&(dpath->parent[0]), 0, sizeof(struct combine_diff_parent)*5); @@ -412,7 +415,7 @@ static int show_modified(struct rev_info *revs, memcpy(p->path, new_entry->name, pathlen); p->path[pathlen] = 0; p->mode = mode; - oidclr(&p->oid); + oidclr(&p->oid, the_repository->hash_algo); memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent)); p->parent[0].status = DIFF_STATUS_MODIFIED; p->parent[0].mode = new_entry->ce_mode; @@ -662,9 +665,11 @@ int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt) repo_init_revisions(opt->repo, &revs, NULL); copy_pathspec(&revs.prune_data, &opt->pathspec); revs.diffopt = *opt; + revs.diffopt.no_free = 1; if (diff_cache(&revs, tree_oid, NULL, 1)) exit(128); + release_revisions(&revs); return 0; } @@ -1,6 +1,9 @@ /* * Copyright (C) 2005 Junio C Hamano */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "base85.h" @@ -57,7 +60,7 @@ static int diff_color_moved_ws_default; static int diff_context_default = 3; static int diff_interhunk_context_default; static char *diff_word_regex_cfg; -static char *external_diff_cmd_cfg; +static struct external_diff external_diff_cfg; static char *diff_order_file_cfg; int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; @@ -431,7 +434,11 @@ int git_diff_ui_config(const char *var, const char *value, return 0; } if (!strcmp(var, "diff.external")) - return git_config_string(&external_diff_cmd_cfg, var, value); + return git_config_string(&external_diff_cfg.cmd, var, value); + if (!strcmp(var, "diff.trustexitcode")) { + external_diff_cfg.trust_exit_code = git_config_bool(var, value); + return 0; + } if (!strcmp(var, "diff.wordregex")) return git_config_string(&diff_word_regex_cfg, var, value); if (!strcmp(var, "diff.orderfile")) @@ -548,18 +555,22 @@ static char *quote_two(const char *one, const char *two) return strbuf_detach(&res, NULL); } -static const char *external_diff(void) +static const struct external_diff *external_diff(void) { - static const char *external_diff_cmd = NULL; + static struct external_diff external_diff_env, *external_diff_ptr; static int done_preparing = 0; if (done_preparing) - return external_diff_cmd; - external_diff_cmd = xstrdup_or_null(getenv("GIT_EXTERNAL_DIFF")); - if (!external_diff_cmd) - external_diff_cmd = external_diff_cmd_cfg; + return external_diff_ptr; + external_diff_env.cmd = xstrdup_or_null(getenv("GIT_EXTERNAL_DIFF")); + if (git_env_bool("GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE", 0)) + external_diff_env.trust_exit_code = 1; + if (external_diff_env.cmd) + external_diff_ptr = &external_diff_env; + else if (external_diff_cfg.cmd) + external_diff_ptr = &external_diff_cfg; done_preparing = 1; - return external_diff_cmd; + return external_diff_ptr; } /* @@ -3764,7 +3775,7 @@ static void builtin_diff(const char *name_a, return; } -static char *get_compact_summary(const struct diff_filepair *p, int is_renamed) +static const char *get_compact_summary(const struct diff_filepair *p, int is_renamed) { if (!is_renamed) { if (p->status == DIFF_STATUS_ADDED) { @@ -4076,7 +4087,7 @@ static int reuse_worktree_file(struct index_state *istate, static int diff_populate_gitlink(struct diff_filespec *s, int size_only) { struct strbuf buf = STRBUF_INIT; - char *dirty = ""; + const char *dirty = ""; /* Are we looking at the work tree? */ if (s->dirty_submodule) @@ -4375,7 +4386,7 @@ static void add_external_diff_name(struct repository *r, * infile2 infile2-sha1 infile2-mode [ rename-to ] * */ -static void run_external_diff(const char *pgm, +static void run_external_diff(const struct external_diff *pgm, const char *name, const char *other, struct diff_filespec *one, @@ -4385,8 +4396,21 @@ static void run_external_diff(const char *pgm, { struct child_process cmd = CHILD_PROCESS_INIT; struct diff_queue_struct *q = &diff_queued_diff; + int quiet = !(o->output_format & DIFF_FORMAT_PATCH); + int rc; + + /* + * Trivial equality is handled by diff_unmodified_pair() before + * we get here. If we don't need to show the diff and the + * external diff program lacks the ability to tell us whether + * it's empty then we consider it non-empty without even asking. + */ + if (!pgm->trust_exit_code && quiet) { + o->found_changes = 1; + return; + } - strvec_push(&cmd.args, pgm); + strvec_push(&cmd.args, pgm->cmd); strvec_push(&cmd.args, name); if (one && two) { @@ -4406,7 +4430,15 @@ static void run_external_diff(const char *pgm, diff_free_filespec_data(one); diff_free_filespec_data(two); cmd.use_shell = 1; - if (run_command(&cmd)) + cmd.no_stdout = quiet; + rc = run_command(&cmd); + if (!pgm->trust_exit_code && rc == 0) + o->found_changes = 1; + else if (pgm->trust_exit_code && rc == 0) + ; /* nothing */ + else if (pgm->trust_exit_code && rc == 1) + o->found_changes = 1; + else die(_("external diff died, stopping at %s"), name); remove_tempfile(); @@ -4512,7 +4544,7 @@ static void fill_metainfo(struct strbuf *msg, } } -static void run_diff_cmd(const char *pgm, +static void run_diff_cmd(const struct external_diff *pgm, const char *name, const char *other, const char *attr_path, @@ -4530,8 +4562,8 @@ static void run_diff_cmd(const char *pgm, if (o->flags.allow_external || !o->ignore_driver_algorithm) drv = userdiff_find_by_path(o->repo->index, attr_path); - if (o->flags.allow_external && drv && drv->external) - pgm = drv->external; + if (o->flags.allow_external && drv && drv->external.cmd) + pgm = &drv->external; if (msg) { /* @@ -4567,7 +4599,7 @@ static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *is if (!one->oid_valid) { struct stat st; if (one->is_stdin) { - oidclr(&one->oid); + oidclr(&one->oid, the_repository->hash_algo); return; } if (lstat(one->path, &st) < 0) @@ -4577,7 +4609,7 @@ static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *is } } else - oidclr(&one->oid); + oidclr(&one->oid, the_repository->hash_algo); } static void strip_prefix(int prefix_length, const char **namep, const char **otherp) @@ -4597,7 +4629,7 @@ static void strip_prefix(int prefix_length, const char **namep, const char **oth static void run_diff(struct diff_filepair *p, struct diff_options *o) { - const char *pgm = external_diff(); + const struct external_diff *pgm = external_diff(); struct strbuf msg; struct diff_filespec *one = p->one; struct diff_filespec *two = p->two; @@ -4924,12 +4956,20 @@ void diff_setup_done(struct diff_options *options) options->flags.exit_with_status = 1; } + /* + * External diffs could declare non-identical contents equal + * (think diff --ignore-space-change). + */ + if (options->flags.allow_external && options->flags.exit_with_status) + options->flags.diff_from_contents = 1; + options->diff_path_counter = 0; if (options->flags.follow_renames) diff_check_follow_pathspec(&options->pathspec, 1); - if (!options->use_color || external_diff()) + if (!options->use_color || + (options->flags.allow_external && external_diff())) options->color_moved = 0; if (options->filter_not) { @@ -6404,7 +6444,7 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid the_hash_algo->init_fn(&ctx); memset(&data, 0, sizeof(struct patch_id_t)); data.ctx = &ctx; - oidclr(oid); + oidclr(oid, the_repository->hash_algo); for (i = 0; i < q->nr; i++) { xpparam_t xpp; @@ -6649,8 +6689,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o) static void diff_free_file(struct diff_options *options) { - if (options->close_file) + if (options->close_file && options->file) { fclose(options->file); + options->file = NULL; + } } static void diff_free_ignore_regex(struct diff_options *options) @@ -6661,7 +6703,9 @@ static void diff_free_ignore_regex(struct diff_options *options) regfree(options->ignore_regex[i]); free(options->ignore_regex[i]); } - free(options->ignore_regex); + + FREE_AND_NULL(options->ignore_regex); + options->ignore_regex_nr = 0; } void diff_free(struct diff_options *options) @@ -7235,7 +7279,7 @@ size_t fill_textconv(struct repository *r, if (!driver) { if (!DIFF_FILE_VALID(df)) { - *outbuf = ""; + *outbuf = (char *) ""; return 0; } if (diff_populate_filespec(r, df, NULL)) @@ -4,7 +4,7 @@ #ifndef DIFF_H #define DIFF_H -#include "hash-ll.h" +#include "hash.h" #include "pathspec.h" #include "strbuf.h" diff --git a/diffcore-break.c b/diffcore-break.c index 49ba38aa7c..831b66b5c3 100644 --- a/diffcore-break.c +++ b/diffcore-break.c @@ -1,6 +1,9 @@ /* * Copyright (C) 2005 Junio C Hamano */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "diffcore.h" #include "hash.h" diff --git a/diffcore-rename.c b/diffcore-rename.c index 5a6e2bcac7..fab45b10d7 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -2,6 +2,9 @@ * * Copyright (C) 2005 Junio C Hamano */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "diff.h" #include "diffcore.h" @@ -406,7 +409,7 @@ static const char *get_highest_rename_path(struct strintmap *counts) return highest_destination_dir; } -static char *UNKNOWN_DIR = "/"; /* placeholder -- short, illegal directory */ +static const char *UNKNOWN_DIR = "/"; /* placeholder -- short, illegal directory */ static int dir_rename_already_determinable(struct strintmap *counts) { @@ -429,8 +432,8 @@ static int dir_rename_already_determinable(struct strintmap *counts) } static void increment_count(struct dir_rename_info *info, - char *old_dir, - char *new_dir) + const char *old_dir, + const char *new_dir) { struct strintmap *counts; struct strmap_entry *e; @@ -1422,7 +1425,7 @@ void diffcore_rename_extended(struct diff_options *options, strcmp(options->single_follow, p->two->path)) continue; /* not interested */ else if (!options->flags.rename_empty && - is_empty_blob_oid(&p->two->oid)) + is_empty_blob_oid(&p->two->oid, the_repository->hash_algo)) continue; else if (add_rename_dst(p) < 0) { warning("skipping rename detection, detected" @@ -1432,7 +1435,7 @@ void diffcore_rename_extended(struct diff_options *options, } } else if (!options->flags.rename_empty && - is_empty_blob_oid(&p->one->oid)) + is_empty_blob_oid(&p->one->oid, the_repository->hash_algo)) continue; else if (!DIFF_PAIR_UNMERGED(p) && !DIFF_FILE_VALID(p->two)) { /* diff --git a/diffcore.h b/diffcore.h index 5ffe4ec788..1701ed50b9 100644 --- a/diffcore.h +++ b/diffcore.h @@ -4,7 +4,7 @@ #ifndef DIFFCORE_H #define DIFFCORE_H -#include "hash-ll.h" +#include "hash.h" struct diff_options; struct mem_pool; @@ -5,6 +5,9 @@ * Copyright (C) Linus Torvalds, 2005-2006 * Junio Hamano, 2005-2006 */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "config.h" @@ -30,6 +33,13 @@ #include "symlinks.h" #include "trace2.h" #include "tree.h" +#include "hex.h" + + /* + * The maximum size of a pattern/exclude file. If the file exceeds this size + * we will ignore it. + */ +#define PATTERN_MAX_FILE_SIZE (100 * 1024 * 1024) /* * Tells read_directory_recursive how a file or directory should be treated. @@ -85,7 +95,7 @@ int count_slashes(const char *s) return cnt; } -int fspathcmp(const char *a, const char *b) +int git_fspathcmp(const char *a, const char *b) { return ignore_case ? strcasecmp(a, b) : strcmp(a, b); } @@ -95,7 +105,7 @@ int fspatheq(const char *a, const char *b) return !fspathcmp(a, b); } -int fspathncmp(const char *a, const char *b, size_t count) +int git_fspathncmp(const char *a, const char *b, size_t count) { return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count); } @@ -726,6 +736,17 @@ static char *dup_and_filter_pattern(const char *pattern) return result; } +static void clear_pattern_entry_hashmap(struct hashmap *map) +{ + struct hashmap_iter iter; + struct pattern_entry *entry; + + hashmap_for_each_entry(map, &iter, entry, ent) { + free(entry->pattern); + } + hashmap_clear_and_free(map, struct pattern_entry, ent); +} + static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern *given) { struct pattern_entry *translated; @@ -799,6 +820,8 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern if (given->patternlen > 2 && !strcmp(given->pattern + given->patternlen - 2, "/*")) { + struct pattern_entry *old; + if (!(given->flags & PATTERN_FLAG_NEGATIVE)) { /* Not a cone pattern. */ warning(_("unrecognized pattern: '%s'"), given->pattern); @@ -824,7 +847,11 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern } hashmap_add(&pl->parent_hashmap, &translated->ent); - hashmap_remove(&pl->recursive_hashmap, &translated->ent, &data); + old = hashmap_remove_entry(&pl->recursive_hashmap, translated, ent, &data); + if (old) { + free(old->pattern); + free(old); + } free(data); return; } @@ -855,8 +882,8 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern clear_hashmaps: warning(_("disabling cone pattern matching")); - hashmap_clear_and_free(&pl->parent_hashmap, struct pattern_entry, ent); - hashmap_clear_and_free(&pl->recursive_hashmap, struct pattern_entry, ent); + clear_pattern_entry_hashmap(&pl->recursive_hashmap); + clear_pattern_entry_hashmap(&pl->parent_hashmap); pl->use_cone_patterns = 0; } @@ -908,12 +935,7 @@ void add_pattern(const char *string, const char *base, int nowildcardlen; parse_path_pattern(&string, &patternlen, &flags, &nowildcardlen); - if (flags & PATTERN_FLAG_MUSTBEDIR) { - FLEXPTR_ALLOC_MEM(pattern, pattern, string, patternlen); - } else { - pattern = xmalloc(sizeof(*pattern)); - pattern->pattern = string; - } + FLEX_ALLOC_MEM(pattern, pattern, string, patternlen); pattern->patternlen = patternlen; pattern->nowildcardlen = nowildcardlen; pattern->base = base; @@ -955,9 +977,8 @@ void clear_pattern_list(struct pattern_list *pl) for (i = 0; i < pl->nr; i++) free(pl->patterns[i]); free(pl->patterns); - free(pl->filebuf); - hashmap_clear_and_free(&pl->recursive_hashmap, struct pattern_entry, ent); - hashmap_clear_and_free(&pl->parent_hashmap, struct pattern_entry, ent); + clear_pattern_entry_hashmap(&pl->recursive_hashmap); + clear_pattern_entry_hashmap(&pl->parent_hashmap); memset(pl, 0, sizeof(*pl)); } @@ -1148,7 +1169,14 @@ static int add_patterns(const char *fname, const char *base, int baselen, } } + if (size > PATTERN_MAX_FILE_SIZE) { + warning("ignoring excessively large pattern file: %s", fname); + free(buf); + return -1; + } + add_patterns_from_buffer(buf, size, base, baselen, pl); + free(buf); return 0; } @@ -1156,16 +1184,15 @@ static int add_patterns_from_buffer(char *buf, size_t size, const char *base, int baselen, struct pattern_list *pl) { + char *orig = buf; int i, lineno = 1; char *entry; hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0); hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0); - pl->filebuf = buf; - if (skip_utf8_bom(&buf, size)) - size -= buf - pl->filebuf; + size -= buf - orig; entry = buf; @@ -1204,7 +1231,15 @@ int add_patterns_from_blob_to_list( if (r != 1) return r; + if (size > PATTERN_MAX_FILE_SIZE) { + warning("ignoring excessively large pattern blob: %s", + oid_to_hex(oid)); + free(buf); + return -1; + } + add_patterns_from_buffer(buf, size, base, baselen, pl); + free(buf); return 0; } @@ -1655,7 +1690,7 @@ static void prep_exclude(struct dir_struct *dir, } /* Try to read per-directory file */ - oidclr(&oid_stat.oid); + oidclr(&oid_stat.oid, the_repository->hash_algo); oid_stat.valid = 0; if (dir->exclude_per_dir && /* @@ -3762,7 +3797,7 @@ static void read_oid(size_t pos, void *cb) rd->data = rd->end + 1; return; } - oidread(&ud->exclude_oid, rd->data); + oidread(&ud->exclude_oid, rd->data, the_repository->hash_algo); rd->data += the_hash_algo->rawsz; } @@ -3770,7 +3805,7 @@ static void load_oid_stat(struct oid_stat *oid_stat, const unsigned char *data, const unsigned char *sha1) { stat_data_from_disk(&oid_stat->stat, data); - oidread(&oid_stat->oid, sha1); + oidread(&oid_stat->oid, sha1, the_repository->hash_algo); oid_stat->valid = 1; } @@ -1,7 +1,7 @@ #ifndef DIR_H #define DIR_H -#include "hash-ll.h" +#include "hash.h" #include "hashmap.h" #include "pathspec.h" #include "statinfo.h" @@ -62,7 +62,6 @@ struct path_pattern { */ struct pattern_list *pl; - const char *pattern; int patternlen; int nowildcardlen; const char *base; @@ -74,6 +73,8 @@ struct path_pattern { * and from -1 decrementing for patterns from CLI args. */ int srcpos; + + char pattern[FLEX_ARRAY]; }; /* used for hashmaps for cone patterns */ @@ -94,9 +95,6 @@ struct pattern_list { int nr; int alloc; - /* remember pointer to exclude file contents so we can free() */ - char *filebuf; - /* origin of list, e.g. path to filename, or descriptive string */ const char *src; @@ -543,9 +541,9 @@ int remove_dir_recursively(struct strbuf *path, int flag); */ int remove_path(const char *path); -int fspathcmp(const char *a, const char *b); +int git_fspathcmp(const char *a, const char *b); int fspatheq(const char *a, const char *b); -int fspathncmp(const char *a, const char *b, size_t count); +int git_fspathncmp(const char *a, const char *b, size_t count); unsigned int fspathhash(const char *str); /* @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "object-store-ll.h" #include "dir.h" @@ -167,6 +169,11 @@ static int remove_available_paths(struct string_list_item *item, void *cb_data) return !available; } +static int string_is_not_null(struct string_list_item *item, void *data UNUSED) +{ + return !!item->string; +} + int finish_delayed_checkout(struct checkout *state, int show_progress) { int errs = 0; @@ -184,12 +191,12 @@ int finish_delayed_checkout(struct checkout *state, int show_progress) progress = start_delayed_progress(_("Filtering content"), dco->paths.nr); while (dco->filters.nr > 0) { for_each_string_list_item(filter, &dco->filters) { - struct string_list available_paths = STRING_LIST_INIT_NODUP; + struct string_list available_paths = STRING_LIST_INIT_DUP; if (!async_query_available_blobs(filter->string, &available_paths)) { /* Filter reported an error */ errs = 1; - filter->string = ""; + filter->string = NULL; continue; } if (available_paths.nr <= 0) { @@ -199,7 +206,7 @@ int finish_delayed_checkout(struct checkout *state, int show_progress) * filter from the list (see * "string_list_remove_empty_items" call below). */ - filter->string = ""; + filter->string = NULL; continue; } @@ -225,7 +232,7 @@ int finish_delayed_checkout(struct checkout *state, int show_progress) * Do not ask the filter for available blobs, * again, as the filter is likely buggy. */ - filter->string = ""; + filter->string = NULL; continue; } ce = index_file_exists(state->istate, path->string, @@ -238,8 +245,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress) } else errs = 1; } + + string_list_clear(&available_paths, 0); } - string_list_remove_empty_items(&dco->filters, 0); + + filter_string_list(&dco->filters, 0, string_is_not_null, NULL); } stop_progress(&progress); string_list_clear(&dco->filters, 0); diff --git a/environment.c b/environment.c index 701d515135..5cea2c9f54 100644 --- a/environment.c +++ b/environment.c @@ -7,6 +7,9 @@ * even if you might want to know where the git directory etc * are. */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "branch.h" diff --git a/ewah/bitmap.c b/ewah/bitmap.c index ac7e0af622..55928dada8 100644 --- a/ewah/bitmap.c +++ b/ewah/bitmap.c @@ -138,6 +138,49 @@ void bitmap_or(struct bitmap *self, const struct bitmap *other) self->words[i] |= other->words[i]; } +int ewah_bitmap_is_subset(struct ewah_bitmap *self, struct bitmap *other) +{ + struct ewah_iterator it; + eword_t word; + size_t i; + + ewah_iterator_init(&it, self); + + for (i = 0; i < other->word_alloc; i++) { + if (!ewah_iterator_next(&word, &it)) { + /* + * If we reached the end of `self`, and haven't + * rejected `self` as a possible subset of + * `other` yet, then we are done and `self` is + * indeed a subset of `other`. + */ + return 1; + } + if (word & ~other->words[i]) { + /* + * Otherwise, compare the next two pairs of + * words. If the word from `self` has bit(s) not + * in the word from `other`, `self` is not a + * subset of `other`. + */ + return 0; + } + } + + /* + * If we got to this point, there may be zero or more words + * remaining in `self`, with no remaining words left in `other`. + * If there are any bits set in the remaining word(s) in `self`, + * then `self` is not a subset of `other`. + */ + while (ewah_iterator_next(&word, &it)) + if (word) + return 0; + + /* `self` is definitely a subset of `other` */ + return 1; +} + void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other) { size_t original_size = self->word_alloc; @@ -169,6 +212,20 @@ size_t bitmap_popcount(struct bitmap *self) return count; } +size_t ewah_bitmap_popcount(struct ewah_bitmap *self) +{ + struct ewah_iterator it; + eword_t word; + size_t count = 0; + + ewah_iterator_init(&it, self); + + while (ewah_iterator_next(&word, &it)) + count += ewah_bit_popcount64(word); + + return count; +} + int bitmap_is_empty(struct bitmap *self) { size_t i; @@ -204,6 +261,25 @@ int bitmap_equals(struct bitmap *self, struct bitmap *other) return 1; } +int bitmap_equals_ewah(struct bitmap *self, struct ewah_bitmap *other) +{ + struct ewah_iterator it; + eword_t word; + size_t i = 0; + + ewah_iterator_init(&it, other); + + while (ewah_iterator_next(&word, &it)) + if (word != (i < self->word_alloc ? self->words[i++] : 0)) + return 0; + + for (; i < self->word_alloc; i++) + if (self->words[i]) + return 0; + + return 1; +} + int bitmap_is_subset(struct bitmap *self, struct bitmap *other) { size_t common_size, i; diff --git a/ewah/ewok.h b/ewah/ewok.h index c11d76c6f3..5e357e2493 100644 --- a/ewah/ewok.h +++ b/ewah/ewok.h @@ -179,7 +179,14 @@ void bitmap_unset(struct bitmap *self, size_t pos); int bitmap_get(struct bitmap *self, size_t pos); void bitmap_free(struct bitmap *self); int bitmap_equals(struct bitmap *self, struct bitmap *other); +int bitmap_equals_ewah(struct bitmap *self, struct ewah_bitmap *other); + +/* + * Both `bitmap_is_subset()` and `ewah_bitmap_is_subset()` return 1 if the set + * of bits in 'self' are a subset of the bits in 'other'. Returns 0 otherwise. + */ int bitmap_is_subset(struct bitmap *self, struct bitmap *other); +int ewah_bitmap_is_subset(struct ewah_bitmap *self, struct bitmap *other); struct ewah_bitmap * bitmap_to_ewah(struct bitmap *bitmap); struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah); @@ -189,6 +196,7 @@ void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other); void bitmap_or(struct bitmap *self, const struct bitmap *other); size_t bitmap_popcount(struct bitmap *self); +size_t ewah_bitmap_popcount(struct ewah_bitmap *self); int bitmap_is_empty(struct bitmap *self); #endif diff --git a/fetch-pack.c b/fetch-pack.c index eba9e420ea..732511604b 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "repository.h" #include "config.h" @@ -954,12 +956,7 @@ static int get_pack(struct fetch_pack_args *args, strvec_push(&cmd.args, alternate_shallow_file); } - if (fetch_fsck_objects >= 0 - ? fetch_fsck_objects - : transfer_fsck_objects >= 0 - ? transfer_fsck_objects - : 0) - fsck_objects = 1; + fsck_objects = fetch_pack_fsck_objects(); if (do_keep || args->from_promisor || index_pack_args || fsck_objects) { if (pack_lockfiles || fsck_objects) @@ -1038,8 +1035,10 @@ static int get_pack(struct fetch_pack_args *args, if (!is_well_formed) die(_("fetch-pack: invalid index-pack output")); - if (pack_lockfile) + if (pack_lockfiles && pack_lockfile) string_list_append_nodup(pack_lockfiles, pack_lockfile); + else + free(pack_lockfile); parse_gitmodules_oids(cmd.out, gitmodules_oids); close(cmd.out); } @@ -2046,6 +2045,16 @@ static const struct object_id *iterate_ref_map(void *cb_data) return &ref->old_oid; } +int fetch_pack_fsck_objects(void) +{ + fetch_pack_setup(); + if (fetch_fsck_objects >= 0) + return fetch_fsck_objects; + if (transfer_fsck_objects >= 0) + return transfer_fsck_objects; + return 0; +} + struct ref *fetch_pack(struct fetch_pack_args *args, int fd[], const struct ref *ref, diff --git a/fetch-pack.h b/fetch-pack.h index 6775d26517..b5c579cdae 100644 --- a/fetch-pack.h +++ b/fetch-pack.h @@ -101,4 +101,9 @@ void negotiate_using_fetch(const struct oid_array *negotiation_tips, */ int report_unmatched_refs(struct ref **sought, int nr_sought); +/* + * Return true if checks for broken objects in received pack are required. + */ +int fetch_pack_fsck_objects(void); + #endif diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c index 7d144b803a..6acb37b480 100644 --- a/fmt-merge-msg.c +++ b/fmt-merge-msg.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "environment.h" @@ -447,7 +449,7 @@ static void fmt_merge_msg_title(struct strbuf *out, const char *current_branch) { int i = 0; - char *sep = ""; + const char *sep = ""; strbuf_addstr(out, "Merge "); for (i = 0; i < srcs.nr; i++) { @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "date.h" #include "dir.h" @@ -203,7 +205,8 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values) if (!strcmp(buf, "skiplist")) { if (equal == len) die("skiplist requires a path"); - oidset_parse_file(&options->skiplist, buf + equal + 1); + oidset_parse_file(&options->skiplist, buf + equal + 1, + the_repository->hash_algo); buf += len + 1; continue; } @@ -1179,7 +1182,7 @@ int fsck_object(struct object *obj, void *data, unsigned long size, } int fsck_buffer(const struct object_id *oid, enum object_type type, - void *data, unsigned long size, + const void *data, unsigned long size, struct fsck_options *options) { if (type == OBJ_BLOB) @@ -190,7 +190,7 @@ int fsck_object(struct object *obj, void *data, unsigned long size, * struct. */ int fsck_buffer(const struct object_id *oid, enum object_type, - void *data, unsigned long size, + const void *data, unsigned long size, struct fsck_options *options); /* diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c index 45471b5b74..f1b1631111 100644 --- a/fsmonitor-ipc.c +++ b/fsmonitor-ipc.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "simple-ipc.h" diff --git a/git-compat-util.h b/git-compat-util.h index ca7678a379..71b4d23f03 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -506,6 +506,14 @@ static inline int git_offset_1st_component(const char *path) #define offset_1st_component git_offset_1st_component #endif +#ifndef fspathcmp +#define fspathcmp git_fspathcmp +#endif + +#ifndef fspathncmp +#define fspathncmp git_fspathncmp +#endif + #ifndef is_valid_path #define is_valid_path(path) 1 #endif diff --git a/git-gui/README.md b/git-gui/README.md index b460b649a8..948e9250d5 100644 --- a/git-gui/README.md +++ b/git-gui/README.md @@ -42,8 +42,8 @@ You probably need to have root/admin permissions to install. # Contributing -The project is currently maintained by Pratyush Yadav over at -https://github.com/prati0100/git-gui. Even though the project is hosted at +The project is currently maintained by Johannes Sixt at +https://github.com/j6t/git-gui. Even though the project is hosted at GitHub, the development does not happen over GitHub Issues and Pull Requests. Instead, an email based workflow is used. The Git mailing list [git@vger.kernel.org](mailto:git@vger.kernel.org) is where the patches are diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 507fb2b682..8fe7538e72 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2301,7 +2301,7 @@ proc do_quit {{rc {1}}} { # set save [gitdir GITGUI_MSG] if {$GITGUI_BCK_exists && ![$ui_comm edit modified]} { - file rename -force [gitdir GITGUI_BCK] $save + catch { file rename -force [gitdir GITGUI_BCK] $save } set GITGUI_BCK_exists 0 } elseif {[$ui_comm edit modified]} { set msg [string trim [$ui_comm get 0.0 end]] diff --git a/git-gui/po/fr.po b/git-gui/po/fr.po index 0aff18691d..878df65399 100644 --- a/git-gui/po/fr.po +++ b/git-gui/po/fr.po @@ -1646,7 +1646,7 @@ msgstr "Dépôt Git (sous projet)" #: lib/diff.tcl:222 msgid "* Binary file (not showing content)." -msgstr "* Fichier binaire (pas d'apperçu du contenu)." +msgstr "* Fichier binaire (pas d'aperçu du contenu)." #: lib/diff.tcl:227 #, tcl-format diff --git a/git-gui/po/sv.po b/git-gui/po/sv.po index 1b4ad8368e..de65c18584 100644 --- a/git-gui/po/sv.po +++ b/git-gui/po/sv.po @@ -3,14 +3,14 @@ # This file is distributed under the same license as the git-gui package. # # Mikael Magnusson <mikachu@gmail.com>, 2008. -# Peter Krefting <peter@softwolves.pp.se>, 2007-2008, 2015. +# Peter Krefting <peter@softwolves.pp.se>, 2007-2023. # msgid "" msgstr "" -"Project-Id-Version: sv\n" +"Project-Id-Version: git-gui 0.21.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-03-27 10:15+0100\n" -"PO-Revision-Date: 2015-03-27 10:24+0100\n" +"POT-Creation-Date: 2023-10-26 21:17+0100\n" +"PO-Revision-Date: 2023-10-26 21:23+0100\n" "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n" "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" "Language: sv\n" @@ -18,35 +18,35 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Gtranslator 2.91.6\n" +"X-Generator: Gtranslator 3.38.0\n" -#: git-gui.sh:861 +#: git-gui.sh:884 #, tcl-format msgid "Invalid font specified in %s:" msgstr "Ogiltigt teckensnitt angivet i %s:" -#: git-gui.sh:915 +#: git-gui.sh:939 msgid "Main Font" msgstr "Huvudteckensnitt" -#: git-gui.sh:916 +#: git-gui.sh:940 msgid "Diff/Console Font" msgstr "Diff/konsolteckensnitt" -#: git-gui.sh:931 git-gui.sh:945 git-gui.sh:958 git-gui.sh:1048 -#: git-gui.sh:1067 git-gui.sh:3125 +#: git-gui.sh:955 git-gui.sh:969 git-gui.sh:982 git-gui.sh:1072 git-gui.sh:1091 +#: git-gui.sh:3233 msgid "git-gui: fatal error" msgstr "git-gui: ödesdigert fel" -#: git-gui.sh:932 +#: git-gui.sh:956 msgid "Cannot find git in PATH." msgstr "Hittar inte git i PATH." -#: git-gui.sh:959 +#: git-gui.sh:983 msgid "Cannot parse Git version string:" msgstr "Kan inte tolka versionssträng frÃ¥n Git:" -#: git-gui.sh:984 +#: git-gui.sh:1008 #, tcl-format msgid "" "Git version cannot be determined.\n" @@ -59,53 +59,53 @@ msgid "" msgstr "" "Kan inte avgöra Gits version.\n" "\n" -"%s säger att dess version är \"%s\".\n" +"%s säger att dess version är â€%sâ€.\n" "\n" "%s kräver minst Git 1.5.0 eller senare.\n" "\n" -"Anta att \"%s\" är version 1.5.0?\n" +"Anta att â€%s†är version 1.5.0?\n" -#: git-gui.sh:1281 +#: git-gui.sh:1302 msgid "Git directory not found:" msgstr "Git-katalogen hittades inte:" -#: git-gui.sh:1315 +#: git-gui.sh:1332 msgid "Cannot move to top of working directory:" msgstr "Kan inte gÃ¥ till början pÃ¥ arbetskatalogen:" -#: git-gui.sh:1323 +#: git-gui.sh:1340 msgid "Cannot use bare repository:" msgstr "Kan inte använda naket arkiv:" -#: git-gui.sh:1331 +#: git-gui.sh:1348 msgid "No working directory" msgstr "Ingen arbetskatalog" -#: git-gui.sh:1503 lib/checkout_op.tcl:306 +#: git-gui.sh:1523 lib/checkout_op.tcl:306 msgid "Refreshing file status..." msgstr "Uppdaterar filstatus..." -#: git-gui.sh:1563 +#: git-gui.sh:1567 msgid "Scanning for modified files ..." msgstr "Söker efter ändrade filer..." -#: git-gui.sh:1639 +#: git-gui.sh:1651 msgid "Calling prepare-commit-msg hook..." msgstr "" "Anropar kroken för förberedelse av incheckningsmeddelande (prepare-commit-" "msg)..." -#: git-gui.sh:1656 +#: git-gui.sh:1668 msgid "Commit declined by prepare-commit-msg hook." msgstr "" "Incheckningen avvisades av kroken för förberedelse av incheckningsmeddelande " "(prepare-commit-msg)." -#: git-gui.sh:1814 lib/browser.tcl:252 +#: git-gui.sh:1826 lib/browser.tcl:252 msgid "Ready." msgstr "Klar." -#: git-gui.sh:1978 +#: git-gui.sh:1990 #, tcl-format msgid "" "Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files." @@ -113,524 +113,811 @@ msgstr "" "Visningsgräns (gui.maxfilesdisplayed = %s) nÃ¥dd, visare inte samtliga %s " "filer." -#: git-gui.sh:2101 +#: git-gui.sh:2113 msgid "Unmodified" msgstr "Oförändrade" -#: git-gui.sh:2103 +#: git-gui.sh:2115 msgid "Modified, not staged" msgstr "Förändrade, ej köade" -#: git-gui.sh:2104 git-gui.sh:2116 +#: git-gui.sh:2116 git-gui.sh:2128 msgid "Staged for commit" msgstr "Köade för incheckning" -#: git-gui.sh:2105 git-gui.sh:2117 +#: git-gui.sh:2117 git-gui.sh:2129 msgid "Portions staged for commit" msgstr "Delar köade för incheckning" -#: git-gui.sh:2106 git-gui.sh:2118 +#: git-gui.sh:2118 git-gui.sh:2130 msgid "Staged for commit, missing" msgstr "Köade för incheckning, saknade" -#: git-gui.sh:2108 +#: git-gui.sh:2120 msgid "File type changed, not staged" msgstr "Filtyp ändrad, ej köade" -#: git-gui.sh:2109 git-gui.sh:2110 +#: git-gui.sh:2121 git-gui.sh:2122 msgid "File type changed, old type staged for commit" msgstr "Filtyp ändrad, gammal typ köade för incheckning" -#: git-gui.sh:2111 +#: git-gui.sh:2123 msgid "File type changed, staged" msgstr "Filtyp ändrad, köade" -#: git-gui.sh:2112 +#: git-gui.sh:2124 msgid "File type change staged, modification not staged" msgstr "Filtypsändringar köade, innehÃ¥llsändringar ej köade" -#: git-gui.sh:2113 +#: git-gui.sh:2125 msgid "File type change staged, file missing" msgstr "Filtypsändringar köade, fil saknas" -#: git-gui.sh:2115 +#: git-gui.sh:2127 msgid "Untracked, not staged" msgstr "Ej spÃ¥rade, ej köade" -#: git-gui.sh:2120 +#: git-gui.sh:2132 msgid "Missing" msgstr "Saknade" -#: git-gui.sh:2121 +#: git-gui.sh:2133 msgid "Staged for removal" msgstr "Köade för borttagning" -#: git-gui.sh:2122 +#: git-gui.sh:2134 msgid "Staged for removal, still present" msgstr "Köade för borttagning, fortfarande närvarande" -#: git-gui.sh:2124 git-gui.sh:2125 git-gui.sh:2126 git-gui.sh:2127 -#: git-gui.sh:2128 git-gui.sh:2129 +#: git-gui.sh:2136 git-gui.sh:2137 git-gui.sh:2138 git-gui.sh:2139 +#: git-gui.sh:2140 git-gui.sh:2141 msgid "Requires merge resolution" msgstr "Kräver konflikthantering efter sammanslagning" -#: git-gui.sh:2164 -msgid "Starting gitk... please wait..." -msgstr "Startar gitk... vänta..." - -#: git-gui.sh:2176 +#: git-gui.sh:2186 msgid "Couldn't find gitk in PATH" msgstr "Hittade inte gitk i PATH." -#: git-gui.sh:2235 +#: git-gui.sh:2233 git-gui.sh:2269 +#, tcl-format +msgid "Starting %s... please wait..." +msgstr "Startar %s... vänta..." + +#: git-gui.sh:2248 msgid "Couldn't find git gui in PATH" msgstr "Hittade inte git gui i PATH." -#: git-gui.sh:2654 lib/choose_repository.tcl:41 +#: git-gui.sh:2751 lib/choose_repository.tcl:53 msgid "Repository" msgstr "Arkiv" -#: git-gui.sh:2655 +#: git-gui.sh:2752 msgid "Edit" msgstr "Redigera" -#: git-gui.sh:2657 lib/choose_rev.tcl:567 +#: git-gui.sh:2754 lib/choose_rev.tcl:567 msgid "Branch" msgstr "Gren" -#: git-gui.sh:2660 lib/choose_rev.tcl:554 +#: git-gui.sh:2757 lib/choose_rev.tcl:554 msgid "Commit@@noun" msgstr "Incheckning" -#: git-gui.sh:2663 lib/merge.tcl:123 lib/merge.tcl:152 lib/merge.tcl:170 +#: git-gui.sh:2760 lib/merge.tcl:127 lib/merge.tcl:174 msgid "Merge" msgstr "SlÃ¥ ihop" -#: git-gui.sh:2664 lib/choose_rev.tcl:563 +#: git-gui.sh:2761 lib/choose_rev.tcl:563 msgid "Remote" msgstr "Fjärrarkiv" -#: git-gui.sh:2667 +#: git-gui.sh:2764 msgid "Tools" msgstr "Verktyg" -#: git-gui.sh:2676 +#: git-gui.sh:2773 msgid "Explore Working Copy" msgstr "Utforska arbetskopia" -#: git-gui.sh:2682 +#: git-gui.sh:2788 msgid "Git Bash" msgstr "Git Bash" -#: git-gui.sh:2692 +#: git-gui.sh:2797 msgid "Browse Current Branch's Files" msgstr "Bläddra i grenens filer" -#: git-gui.sh:2696 +#: git-gui.sh:2801 msgid "Browse Branch Files..." msgstr "Bläddra filer pÃ¥ gren..." -#: git-gui.sh:2701 +#: git-gui.sh:2806 msgid "Visualize Current Branch's History" msgstr "Visualisera grenens historik" -#: git-gui.sh:2705 +#: git-gui.sh:2810 msgid "Visualize All Branch History" msgstr "Visualisera alla grenars historik" -#: git-gui.sh:2712 +#: git-gui.sh:2817 #, tcl-format msgid "Browse %s's Files" msgstr "Bläddra i filer för %s" -#: git-gui.sh:2714 +#: git-gui.sh:2819 #, tcl-format msgid "Visualize %s's History" msgstr "Visualisera historik för %s" -#: git-gui.sh:2719 lib/database.tcl:40 lib/database.tcl:66 +#: git-gui.sh:2824 lib/database.tcl:40 msgid "Database Statistics" msgstr "Databasstatistik" -#: git-gui.sh:2722 lib/database.tcl:33 +#: git-gui.sh:2827 lib/database.tcl:33 msgid "Compress Database" msgstr "Komprimera databas" -#: git-gui.sh:2725 +#: git-gui.sh:2830 msgid "Verify Database" msgstr "Verifiera databas" -#: git-gui.sh:2732 git-gui.sh:2736 git-gui.sh:2740 lib/shortcut.tcl:8 -#: lib/shortcut.tcl:40 lib/shortcut.tcl:72 +#: git-gui.sh:2837 git-gui.sh:2841 git-gui.sh:2845 msgid "Create Desktop Icon" msgstr "Skapa skrivbordsikon" -#: git-gui.sh:2748 lib/choose_repository.tcl:193 lib/choose_repository.tcl:201 +#: git-gui.sh:2853 lib/choose_repository.tcl:206 lib/choose_repository.tcl:214 msgid "Quit" msgstr "Avsluta" -#: git-gui.sh:2756 +#: git-gui.sh:2861 msgid "Undo" msgstr "Ã…ngra" -#: git-gui.sh:2759 +#: git-gui.sh:2864 msgid "Redo" msgstr "Gör om" -#: git-gui.sh:2763 git-gui.sh:3368 +#: git-gui.sh:2868 git-gui.sh:3493 msgid "Cut" msgstr "Klipp ut" -#: git-gui.sh:2766 git-gui.sh:3371 git-gui.sh:3445 git-gui.sh:3530 +#: git-gui.sh:2871 git-gui.sh:3496 git-gui.sh:3572 git-gui.sh:3665 #: lib/console.tcl:69 msgid "Copy" msgstr "Kopiera" -#: git-gui.sh:2769 git-gui.sh:3374 +#: git-gui.sh:2874 git-gui.sh:3499 msgid "Paste" msgstr "Klistra in" -#: git-gui.sh:2772 git-gui.sh:3377 lib/remote_branch_delete.tcl:39 -#: lib/branch_delete.tcl:28 +#: git-gui.sh:2877 git-gui.sh:3502 lib/branch_delete.tcl:28 +#: lib/remote_branch_delete.tcl:39 msgid "Delete" msgstr "Ta bort" -#: git-gui.sh:2776 git-gui.sh:3381 git-gui.sh:3534 lib/console.tcl:71 +#: git-gui.sh:2881 git-gui.sh:3506 git-gui.sh:3669 lib/console.tcl:71 msgid "Select All" msgstr "Markera alla" -#: git-gui.sh:2785 +#: git-gui.sh:2890 msgid "Create..." msgstr "Skapa..." -#: git-gui.sh:2791 +#: git-gui.sh:2896 msgid "Checkout..." msgstr "Checka ut..." -#: git-gui.sh:2797 +#: git-gui.sh:2902 msgid "Rename..." msgstr "Byt namn..." -#: git-gui.sh:2802 +#: git-gui.sh:2907 msgid "Delete..." msgstr "Ta bort..." -#: git-gui.sh:2807 +#: git-gui.sh:2912 msgid "Reset..." msgstr "Ã…terställ..." -#: git-gui.sh:2817 +#: git-gui.sh:2922 msgid "Done" msgstr "Färdig" -#: git-gui.sh:2819 +#: git-gui.sh:2924 msgid "Commit@@verb" msgstr "Checka in" -#: git-gui.sh:2828 git-gui.sh:3309 -msgid "New Commit" -msgstr "Ny incheckning" - -#: git-gui.sh:2836 git-gui.sh:3316 +#: git-gui.sh:2933 git-gui.sh:3432 msgid "Amend Last Commit" msgstr "Lägg till föregÃ¥ende incheckning" -#: git-gui.sh:2846 git-gui.sh:3270 lib/remote_branch_delete.tcl:101 +#: git-gui.sh:2943 git-gui.sh:3393 lib/remote_branch_delete.tcl:101 msgid "Rescan" msgstr "Sök pÃ¥ nytt" -#: git-gui.sh:2852 +#: git-gui.sh:2949 msgid "Stage To Commit" msgstr "Köa för incheckning" -#: git-gui.sh:2858 +#: git-gui.sh:2955 msgid "Stage Changed Files To Commit" msgstr "Köa ändrade filer för incheckning" -#: git-gui.sh:2864 +#: git-gui.sh:2961 msgid "Unstage From Commit" msgstr "Ta bort frÃ¥n incheckningskö" -#: git-gui.sh:2870 lib/index.tcl:442 +#: git-gui.sh:2967 lib/index.tcl:521 msgid "Revert Changes" msgstr "Ã…terställ ändringar" -#: git-gui.sh:2878 git-gui.sh:3581 git-gui.sh:3612 +#: git-gui.sh:2975 git-gui.sh:3732 git-gui.sh:3763 msgid "Show Less Context" msgstr "Visa mindre sammanhang" -#: git-gui.sh:2882 git-gui.sh:3585 git-gui.sh:3616 +#: git-gui.sh:2979 git-gui.sh:3736 git-gui.sh:3767 msgid "Show More Context" msgstr "Visa mer sammanhang" -#: git-gui.sh:2889 git-gui.sh:3283 git-gui.sh:3392 +#: git-gui.sh:2986 git-gui.sh:3406 git-gui.sh:3517 msgid "Sign Off" msgstr "Skriv under" -#: git-gui.sh:2905 +#: git-gui.sh:3002 msgid "Local Merge..." msgstr "Lokal sammanslagning..." -#: git-gui.sh:2910 +#: git-gui.sh:3007 msgid "Abort Merge..." msgstr "Avbryt sammanslagning..." -#: git-gui.sh:2922 git-gui.sh:2950 +#: git-gui.sh:3019 git-gui.sh:3047 msgid "Add..." msgstr "Lägg till..." -#: git-gui.sh:2926 +#: git-gui.sh:3023 msgid "Push..." msgstr "Sänd..." -#: git-gui.sh:2930 +#: git-gui.sh:3027 msgid "Delete Branch..." msgstr "Ta bort gren..." -#: git-gui.sh:2940 git-gui.sh:3563 +#: git-gui.sh:3037 git-gui.sh:3698 msgid "Options..." msgstr "Alternativ..." -#: git-gui.sh:2951 +#: git-gui.sh:3048 msgid "Remove..." msgstr "Ta bort..." -#: git-gui.sh:2960 lib/choose_repository.tcl:55 +#: git-gui.sh:3057 lib/choose_repository.tcl:67 msgid "Help" msgstr "Hjälp" -#: git-gui.sh:2964 git-gui.sh:2968 lib/choose_repository.tcl:49 -#: lib/choose_repository.tcl:58 lib/about.tcl:14 +#: git-gui.sh:3061 git-gui.sh:3065 lib/about.tcl:14 +#: lib/choose_repository.tcl:61 lib/choose_repository.tcl:70 #, tcl-format msgid "About %s" msgstr "Om %s" -#: git-gui.sh:2992 +#: git-gui.sh:3085 msgid "Online Documentation" msgstr "Webbdokumentation" -#: git-gui.sh:2995 lib/choose_repository.tcl:52 lib/choose_repository.tcl:61 +#: git-gui.sh:3088 lib/choose_repository.tcl:64 lib/choose_repository.tcl:73 msgid "Show SSH Key" msgstr "Visa SSH-nyckel" -#: git-gui.sh:3014 git-gui.sh:3146 +#: git-gui.sh:3118 git-gui.sh:3250 +msgid "usage:" +msgstr "användning:" + +#: git-gui.sh:3122 git-gui.sh:3254 msgid "Usage" msgstr "Användning" -#: git-gui.sh:3095 lib/blame.tcl:573 +#: git-gui.sh:3203 lib/blame.tcl:576 msgid "Error" msgstr "Fel" -#: git-gui.sh:3126 +#: git-gui.sh:3234 #, tcl-format msgid "fatal: cannot stat path %s: No such file or directory" msgstr "" "ödesdigert: kunde inte ta status pÃ¥ sökvägen %s: Fil eller katalog saknas" -#: git-gui.sh:3159 +#: git-gui.sh:3267 msgid "Current Branch:" msgstr "Aktuell gren:" -#: git-gui.sh:3185 -msgid "Staged Changes (Will Commit)" -msgstr "Köade ändringar (kommer att checkas in)" - -#: git-gui.sh:3205 +#: git-gui.sh:3292 msgid "Unstaged Changes" msgstr "Oköade ändringar" -#: git-gui.sh:3276 +#: git-gui.sh:3314 +msgid "Staged Changes (Will Commit)" +msgstr "Köade ändringar (kommer att checkas in)" + +#: git-gui.sh:3399 msgid "Stage Changed" msgstr "Köa ändrade" -#: git-gui.sh:3295 lib/transport.tcl:137 lib/transport.tcl:229 +#: git-gui.sh:3418 lib/transport.tcl:137 msgid "Push" msgstr "Sänd" -#: git-gui.sh:3330 +#: git-gui.sh:3445 msgid "Initial Commit Message:" msgstr "Inledande incheckningsmeddelande:" -#: git-gui.sh:3331 +#: git-gui.sh:3446 msgid "Amended Commit Message:" msgstr "Utökat incheckningsmeddelande:" -#: git-gui.sh:3332 +#: git-gui.sh:3447 msgid "Amended Initial Commit Message:" msgstr "Utökat inledande incheckningsmeddelande:" -#: git-gui.sh:3333 +#: git-gui.sh:3448 msgid "Amended Merge Commit Message:" msgstr "Utökat incheckningsmeddelande för sammanslagning:" -#: git-gui.sh:3334 +#: git-gui.sh:3449 msgid "Merge Commit Message:" msgstr "Incheckningsmeddelande för sammanslagning:" -#: git-gui.sh:3335 +#: git-gui.sh:3450 msgid "Commit Message:" msgstr "Incheckningsmeddelande:" -#: git-gui.sh:3384 git-gui.sh:3538 lib/console.tcl:73 +#: git-gui.sh:3509 git-gui.sh:3673 lib/console.tcl:73 msgid "Copy All" msgstr "Kopiera alla" -#: git-gui.sh:3408 lib/blame.tcl:105 +#: git-gui.sh:3533 lib/blame.tcl:106 msgid "File:" msgstr "Fil:" -#: git-gui.sh:3526 +#: git-gui.sh:3581 lib/choose_repository.tcl:1054 +msgid "Open" +msgstr "Öppna" + +#: git-gui.sh:3661 msgid "Refresh" msgstr "Uppdatera" -#: git-gui.sh:3547 +#: git-gui.sh:3682 msgid "Decrease Font Size" msgstr "Minska teckensnittsstorlek" -#: git-gui.sh:3551 +#: git-gui.sh:3686 msgid "Increase Font Size" msgstr "Öka teckensnittsstorlek" -#: git-gui.sh:3559 lib/blame.tcl:294 +#: git-gui.sh:3694 lib/blame.tcl:296 msgid "Encoding" msgstr "Teckenkodning" -#: git-gui.sh:3570 +#: git-gui.sh:3705 msgid "Apply/Reverse Hunk" msgstr "Använd/Ã¥terställ del" -#: git-gui.sh:3575 +#: git-gui.sh:3710 msgid "Apply/Reverse Line" msgstr "Använd/Ã¥terställ rad" -#: git-gui.sh:3594 +#: git-gui.sh:3716 git-gui.sh:3826 git-gui.sh:3837 +msgid "Revert Hunk" +msgstr "Ã…terställ del" + +#: git-gui.sh:3721 git-gui.sh:3833 git-gui.sh:3844 +msgid "Revert Line" +msgstr "Ã…terställ rad" + +#: git-gui.sh:3726 git-gui.sh:3823 +msgid "Undo Last Revert" +msgstr "Ã…ngra senaste Ã¥terställning" + +#: git-gui.sh:3745 msgid "Run Merge Tool" msgstr "Starta verktyg för sammanslagning" -#: git-gui.sh:3599 +#: git-gui.sh:3750 msgid "Use Remote Version" msgstr "Använd versionen frÃ¥n fjärrarkivet" -#: git-gui.sh:3603 +#: git-gui.sh:3754 msgid "Use Local Version" msgstr "Använd lokala versionen" -#: git-gui.sh:3607 +#: git-gui.sh:3758 msgid "Revert To Base" msgstr "Ã…terställ till basversionen" -#: git-gui.sh:3625 +#: git-gui.sh:3776 msgid "Visualize These Changes In The Submodule" msgstr "Visualisera ändringarna i undermodulen" -#: git-gui.sh:3629 +#: git-gui.sh:3780 msgid "Visualize Current Branch History In The Submodule" msgstr "Visualisera grenens historik i undermodulen" -#: git-gui.sh:3633 +#: git-gui.sh:3784 msgid "Visualize All Branch History In The Submodule" msgstr "Visualisera alla grenars historik i undermodulen" -#: git-gui.sh:3638 +#: git-gui.sh:3789 msgid "Start git gui In The Submodule" msgstr "Starta git gui i undermodulen" -#: git-gui.sh:3673 +#: git-gui.sh:3825 msgid "Unstage Hunk From Commit" msgstr "Ta bort del ur incheckningskö" -#: git-gui.sh:3675 +#: git-gui.sh:3829 msgid "Unstage Lines From Commit" msgstr "Ta bort rader ur incheckningskö" -#: git-gui.sh:3677 +#: git-gui.sh:3830 git-gui.sh:3841 +msgid "Revert Lines" +msgstr "Ã…terställ rader" + +#: git-gui.sh:3832 msgid "Unstage Line From Commit" msgstr "Ta bort rad ur incheckningskö" -#: git-gui.sh:3680 +#: git-gui.sh:3836 msgid "Stage Hunk For Commit" msgstr "Ställ del i incheckningskö" -#: git-gui.sh:3682 +#: git-gui.sh:3840 msgid "Stage Lines For Commit" msgstr "Ställ rader i incheckningskö" -#: git-gui.sh:3684 +#: git-gui.sh:3843 msgid "Stage Line For Commit" msgstr "Ställ rad i incheckningskö" -#: git-gui.sh:3709 +#: git-gui.sh:3893 msgid "Initializing..." msgstr "Initierar..." -#: git-gui.sh:3852 +#: lib/about.tcl:26 +msgid "git-gui - a graphical user interface for Git." +msgstr "git-gui - ett grafiskt användargränssnitt för Git." + +#: lib/blame.tcl:74 #, 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 "" -"Det finns möjliga problem med miljövariabler.\n" -"\n" -"Följande miljövariabler kommer troligen att\n" -"ignoreras av alla Git-underprocesser som körs\n" -"av %s:\n" -"\n" +msgid "%s (%s): File Viewer" +msgstr "%s (%s): Filvisare" + +#: lib/blame.tcl:80 +msgid "Commit:" +msgstr "Incheckning:" + +#: lib/blame.tcl:282 +msgid "Copy Commit" +msgstr "Kopiera incheckning" + +#: lib/blame.tcl:286 +msgid "Find Text..." +msgstr "Sök text..." + +#: lib/blame.tcl:290 +msgid "Goto Line..." +msgstr "GÃ¥ till rad..." + +#: lib/blame.tcl:299 +msgid "Do Full Copy Detection" +msgstr "Gör full kopieringsigenkänning" + +#: lib/blame.tcl:303 +msgid "Show History Context" +msgstr "Visa historiksammanhang" + +#: lib/blame.tcl:306 +msgid "Blame Parent Commit" +msgstr "Klandra föräldraincheckning" + +#: lib/blame.tcl:469 +#, tcl-format +msgid "Reading %s..." +msgstr "Läser %s..." + +#: lib/blame.tcl:597 +msgid "Loading copy/move tracking annotations..." +msgstr "Läser annoteringar för kopiering/flyttning..." + +#: lib/blame.tcl:614 +msgid "lines annotated" +msgstr "rader annoterade" + +#: lib/blame.tcl:816 +msgid "Loading original location annotations..." +msgstr "Läser in annotering av originalplacering..." + +#: lib/blame.tcl:819 +msgid "Annotation complete." +msgstr "Annotering fullbordad." + +#: lib/blame.tcl:850 +msgid "Busy" +msgstr "Upptagen" + +#: lib/blame.tcl:851 +msgid "Annotation process is already running." +msgstr "Annoteringsprocess körs redan." + +#: lib/blame.tcl:890 +msgid "Running thorough copy detection..." +msgstr "Kör grundlig kopieringsigenkänning..." + +#: lib/blame.tcl:958 +msgid "Loading annotation..." +msgstr "Läser in annotering..." + +#: lib/blame.tcl:1011 +msgid "Author:" +msgstr "Författare:" + +#: lib/blame.tcl:1015 +msgid "Committer:" +msgstr "Incheckare:" + +#: lib/blame.tcl:1020 +msgid "Original File:" +msgstr "Ursprunglig fil:" + +#: lib/blame.tcl:1068 +msgid "Cannot find HEAD commit:" +msgstr "Hittar inte incheckning för HEAD:" + +#: lib/blame.tcl:1123 +msgid "Cannot find parent commit:" +msgstr "Hittar inte föräldraincheckning:" + +#: lib/blame.tcl:1138 +msgid "Unable to display parent" +msgstr "Kan inte visa förälder" + +#: lib/blame.tcl:1139 lib/diff.tcl:345 +msgid "Error loading diff:" +msgstr "Fel vid inläsning av differens:" + +#: lib/blame.tcl:1280 +msgid "Originally By:" +msgstr "Ursprungligen av:" + +#: lib/blame.tcl:1286 +msgid "In File:" +msgstr "I filen:" + +#: lib/blame.tcl:1291 +msgid "Copied Or Moved Here By:" +msgstr "Kopierad eller flyttad hit av:" + +#: lib/branch_checkout.tcl:16 +#, tcl-format +msgid "%s (%s): Checkout Branch" +msgstr "%s (%s): Checka ut gren" + +#: lib/branch_checkout.tcl:21 +msgid "Checkout Branch" +msgstr "Checka ut gren" + +#: lib/branch_checkout.tcl:26 +msgid "Checkout" +msgstr "Checka ut" + +#: lib/branch_checkout.tcl:30 lib/branch_create.tcl:37 lib/branch_delete.tcl:34 +#: lib/branch_rename.tcl:32 lib/browser.tcl:292 lib/checkout_op.tcl:580 +#: lib/choose_font.tcl:45 lib/merge.tcl:178 lib/option.tcl:127 +#: lib/remote_add.tcl:34 lib/remote_branch_delete.tcl:43 lib/tools_dlg.tcl:41 +#: lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 lib/transport.tcl:141 +msgid "Cancel" +msgstr "Avbryt" + +#: lib/branch_checkout.tcl:35 lib/browser.tcl:297 lib/tools_dlg.tcl:321 +msgid "Revision" +msgstr "Revision" + +#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:69 lib/option.tcl:310 +msgid "Options" +msgstr "Alternativ" + +#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 +msgid "Fetch Tracking Branch" +msgstr "Hämta spÃ¥rande gren" + +#: lib/branch_checkout.tcl:47 +msgid "Detach From Local Branch" +msgstr "Koppla bort frÃ¥n lokal gren" + +#: lib/branch_create.tcl:23 +#, tcl-format +msgid "%s (%s): Create Branch" +msgstr "%s (%s): Skapa gren" + +#: lib/branch_create.tcl:28 +msgid "Create New Branch" +msgstr "Skapa ny gren" + +#: lib/branch_create.tcl:33 lib/choose_repository.tcl:386 +msgid "Create" +msgstr "Skapa" + +#: lib/branch_create.tcl:42 +msgid "Branch Name" +msgstr "Namn pÃ¥ gren" + +#: lib/branch_create.tcl:44 lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 +msgid "Name:" +msgstr "Namn:" + +#: lib/branch_create.tcl:57 +msgid "Match Tracking Branch Name" +msgstr "Använd namn pÃ¥ spÃ¥rad gren" + +#: lib/branch_create.tcl:66 +msgid "Starting Revision" +msgstr "Inledande revision" + +#: lib/branch_create.tcl:72 +msgid "Update Existing Branch:" +msgstr "Uppdatera befintlig gren:" + +#: lib/branch_create.tcl:75 +msgid "No" +msgstr "Nej" + +#: lib/branch_create.tcl:80 +msgid "Fast Forward Only" +msgstr "Endast snabbspolning" + +#: lib/branch_create.tcl:85 lib/checkout_op.tcl:572 +msgid "Reset" +msgstr "Ã…terställ" + +#: lib/branch_create.tcl:97 +msgid "Checkout After Creation" +msgstr "Checka ut när skapad" + +#: lib/branch_create.tcl:132 +msgid "Please select a tracking branch." +msgstr "Välj en gren att spÃ¥ra." + +#: lib/branch_create.tcl:141 +#, tcl-format +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "Den spÃ¥rade grenen %s är inte en gren i fjärrarkivet." + +#: lib/branch_create.tcl:154 lib/branch_rename.tcl:92 +msgid "Please supply a branch name." +msgstr "Ange ett namn för grenen." + +#: lib/branch_create.tcl:165 lib/branch_rename.tcl:112 +#, tcl-format +msgid "'%s' is not an acceptable branch name." +msgstr "â€%s†kan inte användas som namn pÃ¥ grenen." + +#: lib/branch_delete.tcl:16 +#, tcl-format +msgid "%s (%s): Delete Branch" +msgstr "%s (%s): Ta bort gren" + +#: lib/branch_delete.tcl:21 +msgid "Delete Local Branch" +msgstr "Ta bort lokal gren" + +#: lib/branch_delete.tcl:39 +msgid "Local Branches" +msgstr "Lokala grenar" + +#: lib/branch_delete.tcl:51 +msgid "Delete Only If Merged Into" +msgstr "Ta bara bort om sammanslagen med" + +#: lib/branch_delete.tcl:53 lib/remote_branch_delete.tcl:120 +msgid "Always (Do not perform merge checks)" +msgstr "Alltid (utför inte sammanslagningstest)" -#: git-gui.sh:3881 +#: lib/branch_delete.tcl:103 +#, tcl-format +msgid "The following branches are not completely merged into %s:" +msgstr "Följande grenar är inte till fullo sammanslagna med %s:" + +#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:218 msgid "" +"Recovering deleted branches is difficult.\n" "\n" -"This is due to a known issue with the\n" -"Tcl binary distributed by Cygwin." +"Delete the selected branches?" msgstr "" +"Det kan vara svÃ¥rt att Ã¥terställa borttagna grenar.\n" "\n" -"Detta beror pÃ¥ ett känt problem med\n" -"Tcl-binären som följer med Cygwin." +"Ta bort de valda grenarna?" -#: git-gui.sh:3886 +#: lib/branch_delete.tcl:131 +#, tcl-format +msgid " - %s:" +msgstr " - %s:" + +#: lib/branch_delete.tcl:141 #, 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" +"Failed to delete branches:\n" +"%s" msgstr "" -"\n" -"\n" -"Du kan ersätta %s\n" -"med att lägga in värden för inställningarna\n" -"user.name och user.email i din personliga\n" -"~/.gitconfig-fil.\n" +"Kunde inte ta bort grenar:\n" +"%s" -#: lib/line.tcl:17 -msgid "Goto Line:" -msgstr "GÃ¥ till rad:" +#: lib/branch_rename.tcl:15 +#, tcl-format +msgid "%s (%s): Rename Branch" +msgstr "%s (%s): Byt namn pÃ¥ gren" -#: lib/line.tcl:23 -msgid "Go" -msgstr "GÃ¥" +#: lib/branch_rename.tcl:23 +msgid "Rename Branch" +msgstr "Byt namn pÃ¥ gren" -#: lib/console.tcl:59 -msgid "Working... please wait..." -msgstr "Arbetar... vänta..." +#: lib/branch_rename.tcl:28 +msgid "Rename" +msgstr "Byt namn" -#: lib/console.tcl:81 lib/checkout_op.tcl:146 lib/sshkey.tcl:55 -#: lib/database.tcl:30 -msgid "Close" -msgstr "Stäng" +#: lib/branch_rename.tcl:38 +msgid "Branch:" +msgstr "Gren:" -#: lib/console.tcl:186 -msgid "Success" -msgstr "Lyckades" +#: lib/branch_rename.tcl:46 +msgid "New Name:" +msgstr "Nytt namn:" -#: lib/console.tcl:200 -msgid "Error: Command Failed" -msgstr "Fel: Kommando misslyckades" +#: lib/branch_rename.tcl:81 +msgid "Please select a branch to rename." +msgstr "Välj en gren att byta namn pÃ¥." + +#: lib/branch_rename.tcl:102 lib/checkout_op.tcl:202 +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "Grenen â€%s†finns redan." + +#: lib/branch_rename.tcl:123 +#, tcl-format +msgid "Failed to rename '%s'." +msgstr "Kunde inte byta namn pÃ¥ â€%sâ€." + +#: lib/browser.tcl:17 +msgid "Starting..." +msgstr "Startar..." + +#: lib/browser.tcl:27 +#, tcl-format +msgid "%s (%s): File Browser" +msgstr "%s (%s): Filbläddrare" + +#: lib/browser.tcl:132 lib/browser.tcl:149 +#, tcl-format +msgid "Loading %s..." +msgstr "Läser %s..." + +#: lib/browser.tcl:193 +msgid "[Up To Parent]" +msgstr "[Upp till förälder]" + +#: lib/browser.tcl:275 +#, tcl-format +msgid "%s (%s): Browse Branch Files" +msgstr "%s (%s): Bläddra filer pÃ¥ grenen" + +#: lib/browser.tcl:282 +msgid "Browse Branch Files" +msgstr "Bläddra filer pÃ¥ grenen" + +#: lib/browser.tcl:288 lib/choose_repository.tcl:401 +#: lib/choose_repository.tcl:488 lib/choose_repository.tcl:497 +#: lib/choose_repository.tcl:1069 +msgid "Browse" +msgstr "Bläddra" #: lib/checkout_op.tcl:85 #, tcl-format @@ -642,21 +929,21 @@ msgstr "Hämtar %s frÃ¥n %s" msgid "fatal: Cannot resolve %s" msgstr "ödesdigert: Kunde inte slÃ¥ upp %s" +#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:30 +#: lib/sshkey.tcl:58 +msgid "Close" +msgstr "Stäng" + #: lib/checkout_op.tcl:175 #, tcl-format msgid "Branch '%s' does not exist." -msgstr "Grenen \"%s\" finns inte." +msgstr "Grenen â€%s†finns inte." #: lib/checkout_op.tcl:194 #, tcl-format msgid "Failed to configure simplified git-pull for '%s'." msgstr "Kunde inte konfigurera förenklad git-pull för '%s'." -#: lib/checkout_op.tcl:202 lib/branch_rename.tcl:102 -#, tcl-format -msgid "Branch '%s' already exists." -msgstr "Grenen \"%s\" finns redan." - #: lib/checkout_op.tcl:229 #, tcl-format msgid "" @@ -665,7 +952,7 @@ msgid "" "It cannot fast-forward to %s.\n" "A merge is required." msgstr "" -"Grenen \"%s\" finns redan.\n" +"Grenen â€%s†finns redan.\n" "\n" "Den kan inte snabbspolas till %s.\n" "En sammanslagning krävs." @@ -673,12 +960,12 @@ msgstr "" #: lib/checkout_op.tcl:243 #, tcl-format msgid "Merge strategy '%s' not supported." -msgstr "Sammanslagningsstrategin \"%s\" stöds inte." +msgstr "Sammanslagningsstrategin â€%s†stöds inte." #: lib/checkout_op.tcl:262 #, tcl-format msgid "Failed to update '%s'." -msgstr "Misslyckades med att uppdatera \"%s\"." +msgstr "Misslyckades med att uppdatera â€%sâ€." #: lib/checkout_op.tcl:274 msgid "Staging area (index) is already locked." @@ -703,27 +990,27 @@ msgstr "" #: lib/checkout_op.tcl:345 #, tcl-format msgid "Updating working directory to '%s'..." -msgstr "Uppdaterar arbetskatalogen till \"%s\"..." +msgstr "Uppdaterar arbetskatalogen till â€%sâ€..." #: lib/checkout_op.tcl:346 msgid "files checked out" msgstr "filer utcheckade" -#: lib/checkout_op.tcl:376 +#: lib/checkout_op.tcl:377 #, tcl-format msgid "Aborted checkout of '%s' (file level merging is required)." -msgstr "Avbryter utcheckning av \"%s\" (sammanslagning pÃ¥ filnivÃ¥ krävs)." +msgstr "Avbryter utcheckning av â€%s†(sammanslagning pÃ¥ filnivÃ¥ krävs)." -#: lib/checkout_op.tcl:377 +#: lib/checkout_op.tcl:378 msgid "File level merge required." msgstr "Sammanslagning pÃ¥ filnivÃ¥ krävs." -#: lib/checkout_op.tcl:381 +#: lib/checkout_op.tcl:382 #, tcl-format msgid "Staying on branch '%s'." -msgstr "Stannar pÃ¥ grenen \"%s\"." +msgstr "Stannar pÃ¥ grenen â€%sâ€." -#: lib/checkout_op.tcl:452 +#: lib/checkout_op.tcl:453 msgid "" "You are no longer on a local branch.\n" "\n" @@ -732,47 +1019,33 @@ msgid "" msgstr "" "Du är inte längre pÃ¥ en lokal gren.\n" "\n" -"Om du ville vara pÃ¥ en gren skapar du en nu, baserad pÃ¥ \"Denna frÃ¥nkopplade " -"utcheckning\"." +"Om du ville vara pÃ¥ en gren skapar du en nu, baserad pÃ¥ â€Denna frÃ¥nkopplade " +"utcheckningâ€." -#: lib/checkout_op.tcl:503 lib/checkout_op.tcl:507 +#: lib/checkout_op.tcl:504 lib/checkout_op.tcl:508 #, tcl-format msgid "Checked out '%s'." -msgstr "Checkade ut \"%s\"." +msgstr "Checkade ut â€%sâ€." -#: lib/checkout_op.tcl:535 +#: lib/checkout_op.tcl:536 #, tcl-format msgid "Resetting '%s' to '%s' will lose the following commits:" -msgstr "" -"Om du Ã¥terställer \"%s\" till \"%s\" gÃ¥r följande incheckningar förlorade:" +msgstr "Om du Ã¥terställer â€%s†till â€%s†gÃ¥r följande incheckningar förlorade:" -#: lib/checkout_op.tcl:557 +#: lib/checkout_op.tcl:558 msgid "Recovering lost commits may not be easy." msgstr "Det kanske inte är sÃ¥ enkelt att Ã¥terskapa förlorade incheckningar." -#: lib/checkout_op.tcl:562 +#: lib/checkout_op.tcl:563 #, tcl-format msgid "Reset '%s'?" -msgstr "Ã…terställa \"%s\"?" +msgstr "Ã…terställa â€%sâ€?" -#: lib/checkout_op.tcl:567 lib/merge.tcl:166 lib/tools_dlg.tcl:336 +#: lib/checkout_op.tcl:568 lib/merge.tcl:170 lib/tools_dlg.tcl:336 msgid "Visualize" msgstr "Visualisera" -#: lib/checkout_op.tcl:571 lib/branch_create.tcl:85 -msgid "Reset" -msgstr "Ã…terställ" - -#: lib/checkout_op.tcl:579 lib/transport.tcl:141 lib/remote_add.tcl:34 -#: lib/browser.tcl:292 lib/merge.tcl:174 lib/branch_checkout.tcl:30 -#: 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/branch_rename.tcl:32 -#: lib/remote_branch_delete.tcl:43 lib/branch_create.tcl:37 -#: lib/branch_delete.tcl:34 -msgid "Cancel" -msgstr "Avbryt" - -#: lib/checkout_op.tcl:635 +#: lib/checkout_op.tcl:636 #, tcl-format msgid "" "Failed to set current branch.\n" @@ -789,440 +1062,577 @@ msgstr "" "\n" "Detta skulle inte ha hänt. %s kommer nu stängas och ge upp." -#: lib/transport.tcl:6 lib/remote_add.tcl:132 -#, tcl-format -msgid "fetch %s" -msgstr "hämta %s" +#: lib/choose_font.tcl:41 +msgid "Select" +msgstr "Välj" -#: lib/transport.tcl:7 -#, tcl-format -msgid "Fetching new changes from %s" -msgstr "Hämtar nya ändringar frÃ¥n %s" +#: lib/choose_font.tcl:55 +msgid "Font Family" +msgstr "Teckensnittsfamilj" -#: lib/transport.tcl:18 -#, tcl-format -msgid "remote prune %s" -msgstr "fjärrborttagning %s" +#: lib/choose_font.tcl:76 +msgid "Font Size" +msgstr "Storlek" -#: lib/transport.tcl:19 -#, tcl-format -msgid "Pruning tracking branches deleted from %s" -msgstr "Tar bort spÃ¥rande grenar som tagits bort frÃ¥n %s" +#: lib/choose_font.tcl:93 +msgid "Font Example" +msgstr "Exempel" -#: lib/transport.tcl:25 -msgid "fetch all remotes" -msgstr "hämta alla fjärrarkiv" +#: lib/choose_font.tcl:105 +msgid "" +"This is example text.\n" +"If you like this text, it can be your font." +msgstr "" +"Detta är en exempeltext.\n" +"Om du tycker om den här texten kan den vara ditt teckensnitt." -#: lib/transport.tcl:26 -msgid "Fetching new changes from all remotes" -msgstr "Hämtar nya ändringar frÃ¥n alla fjärrarkiv" +#: lib/choose_repository.tcl:45 +msgid "Git Gui" +msgstr "Git Gui" -#: lib/transport.tcl:40 -msgid "remote prune all remotes" -msgstr "rensa alla fjärrarkiv" +#: lib/choose_repository.tcl:104 lib/choose_repository.tcl:391 +msgid "Create New Repository" +msgstr "Skapa nytt arkiv" -#: lib/transport.tcl:41 -msgid "Pruning tracking branches deleted from all remotes" -msgstr "Rensar spÃ¥rande grenar som tagits bort, frÃ¥n alla fjärrarkiv" +#: lib/choose_repository.tcl:110 +msgid "New..." +msgstr "Nytt..." -#: lib/transport.tcl:54 lib/transport.tcl:92 lib/transport.tcl:110 -#: lib/remote_add.tcl:162 -#, tcl-format -msgid "push %s" -msgstr "sänd %s" +#: lib/choose_repository.tcl:117 lib/choose_repository.tcl:475 +msgid "Clone Existing Repository" +msgstr "Klona befintligt arkiv" -#: lib/transport.tcl:55 +#: lib/choose_repository.tcl:128 +msgid "Clone..." +msgstr "Klona..." + +#: lib/choose_repository.tcl:135 lib/choose_repository.tcl:1059 +msgid "Open Existing Repository" +msgstr "Öppna befintligt arkiv" + +#: lib/choose_repository.tcl:141 +msgid "Open..." +msgstr "Öppna..." + +#: lib/choose_repository.tcl:154 +msgid "Recent Repositories" +msgstr "Senaste arkiven" + +#: lib/choose_repository.tcl:164 +msgid "Open Recent Repository:" +msgstr "Öppna tidigare arkiv:" + +#: lib/choose_repository.tcl:328 lib/choose_repository.tcl:335 +#: lib/choose_repository.tcl:342 #, tcl-format -msgid "Pushing changes to %s" -msgstr "Sänder ändringar till %s" +msgid "Failed to create repository %s:" +msgstr "Kunde inte skapa arkivet %s:" -#: lib/transport.tcl:93 +#: lib/choose_repository.tcl:396 +msgid "Directory:" +msgstr "Katalog:" + +#: lib/choose_repository.tcl:426 lib/choose_repository.tcl:552 +#: lib/choose_repository.tcl:1093 +msgid "Git Repository" +msgstr "Gitarkiv" + +#: lib/choose_repository.tcl:451 #, tcl-format -msgid "Mirroring to %s" -msgstr "Speglar till %s" +msgid "Directory %s already exists." +msgstr "Katalogen %s finns redan." -#: lib/transport.tcl:111 +#: lib/choose_repository.tcl:455 #, tcl-format -msgid "Pushing %s %s to %s" -msgstr "Sänder %s %s till %s" +msgid "File %s already exists." +msgstr "Filen %s finns redan." -#: lib/transport.tcl:132 -msgid "Push Branches" -msgstr "Sänd grenar" +#: lib/choose_repository.tcl:470 +msgid "Clone" +msgstr "Klona" -#: lib/transport.tcl:147 -msgid "Source Branches" -msgstr "Källgrenar" +#: lib/choose_repository.tcl:483 +msgid "Source Location:" +msgstr "Plats för källkod:" -#: lib/transport.tcl:162 -msgid "Destination Repository" -msgstr "Destinationsarkiv" +#: lib/choose_repository.tcl:492 +msgid "Target Directory:" +msgstr "MÃ¥lkatalog:" -#: lib/transport.tcl:165 lib/remote_branch_delete.tcl:51 -msgid "Remote:" -msgstr "Fjärrarkiv:" +#: lib/choose_repository.tcl:502 +msgid "Clone Type:" +msgstr "Typ av klon:" -#: lib/transport.tcl:187 lib/remote_branch_delete.tcl:72 -msgid "Arbitrary Location:" -msgstr "Godtycklig plats:" +#: lib/choose_repository.tcl:507 +msgid "Standard (Fast, Semi-Redundant, Hardlinks)" +msgstr "Standard (snabb, semiredundant, hÃ¥rda länkar)" -#: lib/transport.tcl:205 -msgid "Transfer Options" -msgstr "Överföringsalternativ" +#: lib/choose_repository.tcl:512 +msgid "Full Copy (Slower, Redundant Backup)" +msgstr "Full kopia (lÃ¥ngsammare, redundant säkerhetskopia)" -#: lib/transport.tcl:207 -msgid "Force overwrite existing branch (may discard changes)" -msgstr "Tvinga överskrivning av befintlig gren (kan kasta bort ändringar)" +#: lib/choose_repository.tcl:517 +msgid "Shared (Fastest, Not Recommended, No Backup)" +msgstr "Delad (snabbast, rekommenderas ej, ingen säkerhetskopia)" -#: lib/transport.tcl:211 -msgid "Use thin pack (for slow network connections)" -msgstr "Använd tunt paket (för lÃ¥ngsamma nätverksanslutningar)" +#: lib/choose_repository.tcl:524 +msgid "Recursively clone submodules too" +msgstr "Klona även rekursivt undermoduler" -#: lib/transport.tcl:215 -msgid "Include tags" -msgstr "Ta med taggar" +#: lib/choose_repository.tcl:558 lib/choose_repository.tcl:605 +#: lib/choose_repository.tcl:744 lib/choose_repository.tcl:818 +#: lib/choose_repository.tcl:1099 lib/choose_repository.tcl:1107 +#, tcl-format +msgid "Not a Git repository: %s" +msgstr "Inte ett Gitarkiv: %s" -#: lib/remote_add.tcl:20 -msgid "Add Remote" -msgstr "Lägg till fjärrarkiv" +#: lib/choose_repository.tcl:594 +msgid "Standard only available for local repository." +msgstr "Standard är endast tillgängligt för lokala arkiv." -#: lib/remote_add.tcl:25 -msgid "Add New Remote" -msgstr "Lägg till nytt fjärrarkiv" +#: lib/choose_repository.tcl:598 +msgid "Shared only available for local repository." +msgstr "Delat är endast tillgängligt för lokala arkiv." -#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 -msgid "Add" -msgstr "Lägg till" +#: lib/choose_repository.tcl:613 +#, tcl-format +msgid "Location %s already exists." +msgstr "Platsen %s finns redan." -#: lib/remote_add.tcl:39 -msgid "Remote Details" -msgstr "Detaljer för fjärrarkiv" +#: lib/choose_repository.tcl:624 +msgid "Failed to configure origin" +msgstr "Kunde inte konfigurera ursprung" -#: lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 lib/branch_create.tcl:44 -msgid "Name:" -msgstr "Namn:" +#: lib/choose_repository.tcl:636 +msgid "Counting objects" +msgstr "Räknar objekt" -#: lib/remote_add.tcl:50 -msgid "Location:" -msgstr "Plats:" +#: lib/choose_repository.tcl:637 +msgid "buckets" +msgstr "hinkar" -#: lib/remote_add.tcl:60 -msgid "Further Action" -msgstr "Ytterligare Ã¥tgärd" +#: lib/choose_repository.tcl:657 +#, tcl-format +msgid "Unable to copy objects/info/alternates: %s" +msgstr "Kunde inte kopiera objekt/info/alternativ: %s" -#: lib/remote_add.tcl:63 -msgid "Fetch Immediately" -msgstr "Hämta omedelbart" +#: lib/choose_repository.tcl:694 +#, tcl-format +msgid "Nothing to clone from %s." +msgstr "Ingenting att klona frÃ¥n %s." -#: lib/remote_add.tcl:69 -msgid "Initialize Remote Repository and Push" -msgstr "Initiera fjärrarkiv och sänd till" +#: lib/choose_repository.tcl:696 lib/choose_repository.tcl:916 +#: lib/choose_repository.tcl:928 +msgid "The 'master' branch has not been initialized." +msgstr "Grenen â€master†har inte initierats." -#: lib/remote_add.tcl:75 -msgid "Do Nothing Else Now" -msgstr "Gör ingent mer nu" +#: lib/choose_repository.tcl:709 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "HÃ¥rda länkar är inte tillgängliga. Faller tillbaka pÃ¥ kopiering." -#: lib/remote_add.tcl:100 -msgid "Please supply a remote name." -msgstr "Ange ett namn för fjärrarkivet." +#: lib/choose_repository.tcl:723 +#, tcl-format +msgid "Cloning from %s" +msgstr "Klonar frÃ¥n %s" -#: lib/remote_add.tcl:113 +#: lib/choose_repository.tcl:754 +msgid "Copying objects" +msgstr "Kopierar objekt" + +#: lib/choose_repository.tcl:755 +msgid "KiB" +msgstr "KiB" + +#: lib/choose_repository.tcl:779 #, tcl-format -msgid "'%s' is not an acceptable remote name." -msgstr "\"%s\" kan inte användas som namn pÃ¥ fjärrarkivet." +msgid "Unable to copy object: %s" +msgstr "Kunde inte kopiera objekt: %s" -#: lib/remote_add.tcl:124 +#: lib/choose_repository.tcl:791 +msgid "Linking objects" +msgstr "Länkar objekt" + +#: lib/choose_repository.tcl:792 +msgid "objects" +msgstr "objekt" + +#: lib/choose_repository.tcl:800 #, tcl-format -msgid "Failed to add remote '%s' of location '%s'." -msgstr "Kunde inte lägga till fjärrarkivet \"%s\" pÃ¥ platsen \"%s\"." +msgid "Unable to hardlink object: %s" +msgstr "Kunde inte hÃ¥rdlänka objekt: %s" -#: lib/remote_add.tcl:133 +#: lib/choose_repository.tcl:857 +msgid "Cannot fetch branches and objects. See console output for details." +msgstr "Kunde inte hämta grenar och objekt. Se konsolutdata för detaljer." + +#: lib/choose_repository.tcl:868 +msgid "Cannot fetch tags. See console output for details." +msgstr "Kunde inte hämta taggar. Se konsolutdata för detaljer." + +#: lib/choose_repository.tcl:892 +msgid "Cannot determine HEAD. See console output for details." +msgstr "Kunde inte avgöra HEAD. Se konsolutdata för detaljer." + +#: lib/choose_repository.tcl:901 #, tcl-format -msgid "Fetching the %s" -msgstr "Hämtar %s" +msgid "Unable to cleanup %s" +msgstr "Kunde inte städa upp %s" -#: lib/remote_add.tcl:156 +#: lib/choose_repository.tcl:907 +msgid "Clone failed." +msgstr "Kloning misslyckades." + +#: lib/choose_repository.tcl:914 +msgid "No default branch obtained." +msgstr "Hämtade ingen standardgren." + +#: lib/choose_repository.tcl:925 #, tcl-format -msgid "Do not know how to initialize repository at location '%s'." -msgstr "Vet inte hur arkivet pÃ¥ platsen \"%s\" skall initieras." +msgid "Cannot resolve %s as a commit." +msgstr "Kunde inte slÃ¥ upp %s till nÃ¥gon incheckning." -#: lib/remote_add.tcl:163 +#: lib/choose_repository.tcl:952 +msgid "Creating working directory" +msgstr "Skapar arbetskatalog" + +#: lib/choose_repository.tcl:953 lib/index.tcl:77 lib/index.tcl:146 +#: lib/index.tcl:220 lib/index.tcl:589 +msgid "files" +msgstr "filer" + +#: lib/choose_repository.tcl:982 +msgid "Initial file checkout failed." +msgstr "Inledande filutcheckning misslyckades." + +#: lib/choose_repository.tcl:1026 +msgid "Cloning submodules" +msgstr "Klonar undermoduler" + +#: lib/choose_repository.tcl:1041 +msgid "Cannot clone submodules." +msgstr "Kan inte klona undermoduler." + +#: lib/choose_repository.tcl:1064 +msgid "Repository:" +msgstr "Arkiv:" + +#: lib/choose_repository.tcl:1113 #, tcl-format -msgid "Setting up the %s (at %s)" -msgstr "Konfigurerar %s (pÃ¥ %s)" +msgid "Failed to open repository %s:" +msgstr "Kunde inte öppna arkivet %s:" -#: lib/browser.tcl:17 -msgid "Starting..." -msgstr "Startar..." +#: lib/choose_rev.tcl:52 +msgid "This Detached Checkout" +msgstr "Denna frÃ¥nkopplade utcheckning" -#: lib/browser.tcl:27 -msgid "File Browser" -msgstr "Filbläddrare" +#: lib/choose_rev.tcl:60 +msgid "Revision Expression:" +msgstr "Revisionsuttryck:" -#: lib/browser.tcl:132 lib/browser.tcl:149 +#: lib/choose_rev.tcl:72 +msgid "Local Branch" +msgstr "Lokal gren" + +#: lib/choose_rev.tcl:77 +msgid "Tracking Branch" +msgstr "SpÃ¥rande gren" + +#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544 +msgid "Tag" +msgstr "Tagg" + +#: lib/choose_rev.tcl:321 #, tcl-format -msgid "Loading %s..." -msgstr "Läser %s..." +msgid "Invalid revision: %s" +msgstr "Ogiltig revision: %s" -#: lib/browser.tcl:193 -msgid "[Up To Parent]" -msgstr "[Upp till förälder]" +#: lib/choose_rev.tcl:342 +msgid "No revision selected." +msgstr "Ingen revision vald." -#: lib/browser.tcl:275 lib/browser.tcl:282 -msgid "Browse Branch Files" -msgstr "Bläddra filer pÃ¥ grenen" +#: lib/choose_rev.tcl:350 +msgid "Revision expression is empty." +msgstr "Revisionsuttrycket är tomt." -#: lib/browser.tcl:288 lib/choose_repository.tcl:422 -#: lib/choose_repository.tcl:509 lib/choose_repository.tcl:518 -#: lib/choose_repository.tcl:1074 -msgid "Browse" -msgstr "Bläddra" +#: lib/choose_rev.tcl:537 +msgid "Updated" +msgstr "Uppdaterad" -#: lib/browser.tcl:297 lib/branch_checkout.tcl:35 lib/tools_dlg.tcl:321 -msgid "Revision" -msgstr "Revision" +#: lib/choose_rev.tcl:565 +msgid "URL" +msgstr "Webbadress" -#: lib/merge.tcl:13 +#: lib/commit.tcl:9 msgid "" -"Cannot merge while amending.\n" +"There is nothing to amend.\n" "\n" -"You must finish amending this commit before starting any type of merge.\n" +"You are about to create the initial commit. There is no commit before this " +"to amend.\n" msgstr "" -"Kan inte slÃ¥ ihop vid utökning.\n" +"Det finns ingenting att utöka.\n" "\n" -"Du mÃ¥ste göra färdig utökningen av incheckningen innan du pÃ¥börjar nÃ¥gon " -"slags sammanslagning.\n" +"Du hÃ¥ller pÃ¥ att skapa den inledande incheckningen. Det finns ingen tidigare " +"incheckning att utöka.\n" -#: lib/merge.tcl:27 +#: lib/commit.tcl:18 +msgid "" +"Cannot amend while merging.\n" +"\n" +"You are currently in the middle of a merge that has not been fully " +"completed. You cannot amend the prior commit unless you first abort the " +"current merge activity.\n" +msgstr "" +"Kan inte utöka vid sammanslagning.\n" +"\n" +"Du är i mitten av en sammanslagning som inte är fullbordad. Du kan inte " +"utöka tidigare incheckningar om du inte först avbryter den pÃ¥gÃ¥ende " +"sammanslagningen.\n" + +#: lib/commit.tcl:56 +msgid "Error loading commit data for amend:" +msgstr "Fel vid inläsning av incheckningsdata för utökning:" + +#: lib/commit.tcl:83 +msgid "Unable to obtain your identity:" +msgstr "Kunde inte hämta din identitet:" + +#: lib/commit.tcl:88 +msgid "Invalid GIT_COMMITTER_IDENT:" +msgstr "Felaktig GIT_COMMITTER_IDENT:" + +#: lib/commit.tcl:138 +#, tcl-format +msgid "warning: Tcl does not support encoding '%s'." +msgstr "varning: Tcl stöder inte teckenkodningen â€%sâ€." + +#: lib/commit.tcl:158 msgid "" "Last scanned state does not match repository state.\n" "\n" "Another Git program has modified this repository since the last scan. A " -"rescan must be performed before a merge can be performed.\n" +"rescan must be performed before another commit can be created.\n" "\n" "The rescan will be automatically started now.\n" msgstr "" "Det senaste inlästa tillstÃ¥ndet motsvarar inte tillstÃ¥ndet i arkivet.\n" "\n" "Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du mÃ¥ste " -"utföra en ny sökning innan du kan utföra en sammanslagning.\n" +"utföra en ny sökning innan du kan göra en ny incheckning.\n" "\n" "Sökningen kommer att startas automatiskt nu.\n" -#: lib/merge.tcl:45 +#: lib/commit.tcl:182 #, tcl-format msgid "" -"You are in the middle of a conflicted merge.\n" -"\n" -"File %s has merge conflicts.\n" +"Unmerged files cannot be committed.\n" "\n" -"You must resolve them, stage the file, and commit to complete the current " -"merge. Only then can you begin another merge.\n" +"File %s has merge conflicts. You must resolve them and stage the file " +"before committing.\n" msgstr "" -"Du är mitt i en sammanslagning med konflikter.\n" -"\n" -"Filen %s har sammanslagningskonflikter.\n" +"Osammanslagna filer kan inte checkas in.\n" "\n" -"Du mÃ¥ste lösa dem, köa filen och checka in för att fullborda den aktuella " -"sammanslagningen. När du gjort det kan du pÃ¥börja en ny sammanslagning.\n" +"Filen %s har sammanslagningskonflikter. Du mÃ¥ste lösa dem och köa filen " +"innan du checkar in den.\n" -#: lib/merge.tcl:55 +#: lib/commit.tcl:190 #, tcl-format msgid "" -"You are in the middle of a change.\n" -"\n" -"File %s is modified.\n" +"Unknown file state %s detected.\n" "\n" -"You should complete the current commit before starting a merge. Doing so " -"will help you abort a failed merge, should the need arise.\n" +"File %s cannot be committed by this program.\n" msgstr "" -"Du är mitt i en ändring.\n" -"\n" -"Filen %s har ändringar.\n" +"Okänd filstatus %s upptäckt.\n" "\n" -"Du bör fullborda den aktuella incheckningen innan du pÃ¥börjar en " -"sammanslagning. Om du gör det blir det enklare att avbryta en misslyckad " -"sammanslagning, om det skulle vara nödvändigt.\n" - -#: lib/merge.tcl:108 -#, tcl-format -msgid "%s of %s" -msgstr "%s av %s" - -#: lib/merge.tcl:122 -#, tcl-format -msgid "Merging %s and %s..." -msgstr "SlÃ¥r ihop %s och %s..." - -#: lib/merge.tcl:133 -msgid "Merge completed successfully." -msgstr "Sammanslagningen avslutades framgÃ¥ngsrikt." - -#: lib/merge.tcl:135 -msgid "Merge failed. Conflict resolution is required." -msgstr "Sammanslagningen misslyckades. Du mÃ¥ste lösa konflikterna." - -#: lib/merge.tcl:160 -#, tcl-format -msgid "Merge Into %s" -msgstr "SlÃ¥ ihop i %s" - -#: lib/merge.tcl:179 -msgid "Revision To Merge" -msgstr "Revisioner att slÃ¥ ihop" +"Filen %s kan inte checkas in av programmet.\n" -#: lib/merge.tcl:214 +#: lib/commit.tcl:198 msgid "" -"Cannot abort while amending.\n" +"No changes to commit.\n" "\n" -"You must finish amending this commit.\n" +"You must stage at least 1 file before you can commit.\n" msgstr "" -"Kan inte avbryta vid utökning.\n" +"Inga ändringar att checka in.\n" "\n" -"Du mÃ¥ste göra dig färdig med att utöka incheckningen.\n" +"Du mÃ¥ste köa Ã¥tminstone en fil innan du kan checka in.\n" -#: lib/merge.tcl:224 +#: lib/commit.tcl:213 msgid "" -"Abort merge?\n" +"Please supply a commit message.\n" "\n" -"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" +"A good commit message has the following format:\n" "\n" -"Continue with aborting the current merge?" +"- First line: Describe in one sentence what you did.\n" +"- Second line: Blank\n" +"- Remaining lines: Describe why this change is good.\n" msgstr "" -"Avbryt sammanslagning?\n" +"Ange ett incheckningsmeddelande.\n" "\n" -"Om du avbryter sammanslagningen kommer *ALLA* ej incheckade ändringar att gÃ¥ " -"förlorade.\n" +"Ett bra incheckningsmeddelande har följande format:\n" "\n" -"GÃ¥ vidare med att avbryta den aktuella sammanslagningen?" +"- Första raden: Beskriv i en mening vad du gjorde.\n" +"- Andra raden: Tom\n" +"- Följande rader: Beskriv varför det här är en bra ändring.\n" + +#: lib/commit.tcl:244 +msgid "Calling pre-commit hook..." +msgstr "Anropar kroken före incheckning (pre-commit)..." + +#: lib/commit.tcl:259 +msgid "Commit declined by pre-commit hook." +msgstr "Incheckningen avvisades av kroken före incheckning (pre-commit)." -#: lib/merge.tcl:230 +#: lib/commit.tcl:278 msgid "" -"Reset changes?\n" -"\n" -"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" -"\n" -"Continue with resetting the current changes?" +"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 " +"changes and it can be difficult to retrieve them later from the reflog. You " +"should probably cancel this commit and create a new branch to continue.\n" +" \n" +" Do you really want to proceed with your Commit?" msgstr "" -"Ã…terställ ändringar?\n" -"\n" -"Om du Ã¥terställer ändringarna kommer *ALLA* ej incheckade ändringar att gÃ¥ " -"förlorade.\n" -"\n" -"GÃ¥ vidare med att Ã¥terställa de aktuella ändringarna?" +"Du är pÃ¥ väg att checka in pÃ¥ ett frÃ¥nkopplat huvud. Det kan potentiellt " +"vara farligt, eftersom du kommer förlora dina ändringar om du växlar till en " +"annan gren och det kan vara svÃ¥rt att hämta dem senare frÃ¥n ref-loggen. Du " +"bör troligen avbryta incheckningen och skapa en ny gren för att fortsätta.\n" +" \n" +" Vill du verkligen fortsätta checka in?" -#: lib/merge.tcl:241 -msgid "Aborting" -msgstr "Avbryter" +#: lib/commit.tcl:299 +msgid "Calling commit-msg hook..." +msgstr "Anropar kroken för incheckningsmeddelande (commit-msg)..." -#: lib/merge.tcl:241 -msgid "files reset" -msgstr "filer Ã¥terställda" +#: lib/commit.tcl:314 +msgid "Commit declined by commit-msg hook." +msgstr "Incheckning avvisad av kroken för incheckningsmeddelande (commit-msg)." -#: lib/merge.tcl:269 -msgid "Abort failed." -msgstr "Misslyckades avbryta." +#: lib/commit.tcl:327 +msgid "Committing changes..." +msgstr "Checkar in ändringar..." -#: lib/merge.tcl:271 -msgid "Abort completed. Ready." -msgstr "Avbrytning fullbordad. Redo." +#: lib/commit.tcl:344 +msgid "write-tree failed:" +msgstr "write-tree misslyckades:" -#: lib/tools.tcl:75 -#, tcl-format -msgid "Running %s requires a selected file." -msgstr "För att starta %s mÃ¥ste du välja en fil." +#: lib/commit.tcl:345 lib/commit.tcl:395 lib/commit.tcl:422 +msgid "Commit failed." +msgstr "Incheckningen misslyckades." -#: lib/tools.tcl:91 +#: lib/commit.tcl:362 #, tcl-format -msgid "Are you sure you want to run %1$s on file \"%2$s\"?" -msgstr "Är du säker pÃ¥ att du vill starta %1$s med filen \"%2$s\"?" +msgid "Commit %s appears to be corrupt" +msgstr "Incheckningen %s verkar vara trasig" -#: lib/tools.tcl:95 -#, tcl-format -msgid "Are you sure you want to run %s?" -msgstr "Är du säker pÃ¥ att du vill starta %s?" +#: lib/commit.tcl:367 +msgid "" +"No changes to commit.\n" +"\n" +"No files were modified by this commit and it was not a merge commit.\n" +"\n" +"A rescan will be automatically started now.\n" +msgstr "" +"Inga ändringar att checka in.\n" +"\n" +"Inga filer ändrades av incheckningen och det var inte en sammanslagning.\n" +"\n" +"En sökning kommer att startas automatiskt nu.\n" -#: lib/tools.tcl:116 -#, tcl-format -msgid "Tool: %s" -msgstr "Verktyg: %s" +#: lib/commit.tcl:374 +msgid "No changes to commit." +msgstr "Inga ändringar att checka in." -#: lib/tools.tcl:117 -#, tcl-format -msgid "Running: %s" -msgstr "Exekverar: %s" +#: lib/commit.tcl:394 +msgid "commit-tree failed:" +msgstr "commit-tree misslyckades:" -#: lib/tools.tcl:155 -#, tcl-format -msgid "Tool completed successfully: %s" -msgstr "Verktyget avslutades framgÃ¥ngsrikt: %s" +#: lib/commit.tcl:421 +msgid "update-ref failed:" +msgstr "update-ref misslyckades:" -#: lib/tools.tcl:157 +#: lib/commit.tcl:515 #, tcl-format -msgid "Tool failed: %s" -msgstr "Verktyget misslyckades: %s" +msgid "Created commit %s: %s" +msgstr "Skapade incheckningen %s: %s" -#: lib/branch_checkout.tcl:16 lib/branch_checkout.tcl:21 -msgid "Checkout Branch" -msgstr "Checka ut gren" +#: lib/console.tcl:59 +msgid "Working... please wait..." +msgstr "Arbetar... vänta..." -#: lib/branch_checkout.tcl:26 -msgid "Checkout" -msgstr "Checka ut" +#: lib/console.tcl:186 +msgid "Success" +msgstr "Lyckades" -#: lib/branch_checkout.tcl:39 lib/option.tcl:310 lib/branch_create.tcl:69 -msgid "Options" -msgstr "Alternativ" +#: lib/console.tcl:200 +msgid "Error: Command Failed" +msgstr "Fel: Kommando misslyckades" -#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92 -msgid "Fetch Tracking Branch" -msgstr "Hämta spÃ¥rande gren" +#: lib/database.tcl:42 +msgid "Number of loose objects" +msgstr "Antal lösa objekt" -#: lib/branch_checkout.tcl:47 -msgid "Detach From Local Branch" -msgstr "Koppla bort frÃ¥n lokal gren" +#: lib/database.tcl:43 +msgid "Disk space used by loose objects" +msgstr "Diskutrymme använt av lösa objekt" -#: lib/spellcheck.tcl:57 -msgid "Unsupported spell checker" -msgstr "Stavningskontrollprogrammet stöds inte" +#: lib/database.tcl:44 +msgid "Number of packed objects" +msgstr "Antal packade objekt" -#: lib/spellcheck.tcl:65 -msgid "Spell checking is unavailable" -msgstr "Stavningskontroll är ej tillgänglig" +#: lib/database.tcl:45 +msgid "Number of packs" +msgstr "Antal paket" -#: lib/spellcheck.tcl:68 -msgid "Invalid spell checking configuration" -msgstr "Ogiltig inställning för stavningskontroll" +#: lib/database.tcl:46 +msgid "Disk space used by packed objects" +msgstr "Diskutrymme använt av packade objekt" -#: lib/spellcheck.tcl:70 -#, tcl-format -msgid "Reverting dictionary to %s." -msgstr "Ã…terställer ordlistan till %s." +#: lib/database.tcl:47 +msgid "Packed objects waiting for pruning" +msgstr "Packade objekt som väntar pÃ¥ städning" -#: lib/spellcheck.tcl:73 -msgid "Spell checker silently failed on startup" -msgstr "Stavningskontroll misslyckades tyst vid start" +#: lib/database.tcl:48 +msgid "Garbage files" +msgstr "Skräpfiler" -#: lib/spellcheck.tcl:80 -msgid "Unrecognized spell checker" -msgstr "Stavningskontrollprogrammet känns inte igen" +#: lib/database.tcl:57 lib/option.tcl:182 lib/option.tcl:197 lib/option.tcl:220 +#: lib/option.tcl:282 +#, tcl-format +msgid "%s:" +msgstr "%s:" -#: lib/spellcheck.tcl:186 -msgid "No Suggestions" -msgstr "Inga förslag" +#: lib/database.tcl:66 +#, tcl-format +msgid "%s (%s): Database Statistics" +msgstr "%s (%s): Databasstatistik" -#: lib/spellcheck.tcl:388 -msgid "Unexpected EOF from spell checker" -msgstr "Oväntat filslut frÃ¥n stavningskontroll" +#: lib/database.tcl:72 +msgid "Compressing the object database" +msgstr "Komprimerar objektdatabasen" -#: lib/spellcheck.tcl:392 -msgid "Spell Checker Failed" -msgstr "Stavningskontroll misslyckades" +#: lib/database.tcl:83 +msgid "Verifying the object database with fsck-objects" +msgstr "Verifierar objektdatabasen med fsck-objects" -#: lib/status_bar.tcl:87 +#: lib/database.tcl:107 #, tcl-format -msgid "%s ... %*i of %*i %s (%3i%%)" -msgstr "%s... %*i av %*i %s (%3i%%)" +msgid "" +"This repository currently has approximately %i loose objects.\n" +"\n" +"To maintain optimal performance it is strongly recommended that you compress " +"the database.\n" +"\n" +"Compress the database now?" +msgstr "" +"Arkivet har för närvarande omkring %i lösa objekt.\n" +"\n" +"För att bibehÃ¥lla optimal prestanda rekommenderas det Ã¥ det bestämdaste att " +"du komprimerar databasen.\n" +"\n" +"Komprimera databasen nu?" + +#: lib/date.tcl:25 +#, tcl-format +msgid "Invalid date from Git: %s" +msgstr "Ogiltigt datum frÃ¥n Git: %s" #: lib/diff.tcl:77 #, tcl-format @@ -1252,7 +1662,7 @@ msgstr "" msgid "Loading diff of %s..." msgstr "Läser differens för %s..." -#: lib/diff.tcl:140 +#: lib/diff.tcl:143 msgid "" "LOCAL: deleted\n" "REMOTE:\n" @@ -1260,7 +1670,7 @@ msgstr "" "LOKAL: borttagen\n" "FJÄRR:\n" -#: lib/diff.tcl:145 +#: lib/diff.tcl:148 msgid "" "REMOTE: deleted\n" "LOCAL:\n" @@ -1268,32 +1678,32 @@ msgstr "" "FJÄRR: borttagen\n" "LOKAL:\n" -#: lib/diff.tcl:152 +#: lib/diff.tcl:155 msgid "LOCAL:\n" msgstr "LOKAL:\n" -#: lib/diff.tcl:155 +#: lib/diff.tcl:158 msgid "REMOTE:\n" msgstr "FJÄRR:\n" -#: lib/diff.tcl:217 lib/diff.tcl:355 +#: lib/diff.tcl:220 lib/diff.tcl:344 #, tcl-format msgid "Unable to display %s" msgstr "Kan inte visa %s" -#: lib/diff.tcl:218 +#: lib/diff.tcl:221 msgid "Error loading file:" msgstr "Fel vid läsning av fil:" -#: lib/diff.tcl:225 +#: lib/diff.tcl:227 msgid "Git Repository (subproject)" msgstr "Gitarkiv (underprojekt)" -#: lib/diff.tcl:237 +#: lib/diff.tcl:239 msgid "* Binary file (not showing content)." msgstr "* Binärfil (visar inte innehÃ¥llet)." -#: lib/diff.tcl:242 +#: lib/diff.tcl:244 #, tcl-format msgid "" "* Untracked file is %d bytes.\n" @@ -1302,7 +1712,7 @@ msgstr "" "* Den ospÃ¥rade filen är %d byte.\n" "* Visar endast inledande %d byte.\n" -#: lib/diff.tcl:248 +#: lib/diff.tcl:250 #, tcl-format msgid "" "\n" @@ -1313,75 +1723,444 @@ msgstr "" "* Den ospÃ¥rade filen klipptes här av %s.\n" "* För att se hela filen, använd ett externt redigeringsprogram.\n" -#: lib/diff.tcl:356 lib/blame.tcl:1128 -msgid "Error loading diff:" -msgstr "Fel vid inläsning av differens:" - -#: lib/diff.tcl:578 +#: lib/diff.tcl:583 msgid "Failed to unstage selected hunk." msgstr "Kunde inte ta bort den valda delen frÃ¥n kön." -#: lib/diff.tcl:585 +#: lib/diff.tcl:591 +msgid "Failed to revert selected hunk." +msgstr "Kunde inte Ã¥terställa den valda delen." + +#: lib/diff.tcl:594 msgid "Failed to stage selected hunk." msgstr "Kunde inte lägga till den valda delen till kön." -#: lib/diff.tcl:664 +#: lib/diff.tcl:687 msgid "Failed to unstage selected line." msgstr "Kunde inte ta bort den valda raden frÃ¥n kön." -#: lib/diff.tcl:672 +#: lib/diff.tcl:696 +msgid "Failed to revert selected line." +msgstr "Kunde inte Ã¥terställa den valda raden." + +#: lib/diff.tcl:700 msgid "Failed to stage selected line." msgstr "Kunde inte lägga till den valda raden till kön." -#: lib/remote.tcl:200 -msgid "Push to" -msgstr "Sänd till" +#: lib/diff.tcl:889 +msgid "Failed to undo last revert." +msgstr "Kunde inte Ã¥ngra den senaste Ã¥terställningen." -#: lib/remote.tcl:218 -msgid "Remove Remote" -msgstr "Ta bort fjärrarkiv" +#: lib/encoding.tcl:443 +msgid "Default" +msgstr "Standard" -#: lib/remote.tcl:223 -msgid "Prune from" -msgstr "Ta bort frÃ¥n" +#: lib/encoding.tcl:448 +#, tcl-format +msgid "System (%s)" +msgstr "Systemets (%s)" -#: lib/remote.tcl:228 -msgid "Fetch from" -msgstr "Hämta frÃ¥n" +#: lib/encoding.tcl:459 lib/encoding.tcl:465 +msgid "Other" +msgstr "Annan" -#: lib/choose_font.tcl:41 -msgid "Select" -msgstr "Välj" +#: lib/error.tcl:20 +#, tcl-format +msgid "%s: error" +msgstr "%s: fel" -#: lib/choose_font.tcl:55 -msgid "Font Family" -msgstr "Teckensnittsfamilj" +#: lib/error.tcl:36 +#, tcl-format +msgid "%s: warning" +msgstr "%s: varning" -#: lib/choose_font.tcl:76 -msgid "Font Size" -msgstr "Storlek" +#: lib/error.tcl:80 +#, tcl-format +msgid "%s hook failed:" +msgstr "%s-krok misslyckades:" -#: lib/choose_font.tcl:93 -msgid "Font Example" -msgstr "Exempel" +#: lib/error.tcl:96 +msgid "You must correct the above errors before committing." +msgstr "Du mÃ¥ste rätta till felen ovan innan du checkar in." -#: lib/choose_font.tcl:105 +#: lib/error.tcl:116 +#, tcl-format +msgid "%s (%s): error" +msgstr "%s (%s): fel" + +#: lib/index.tcl:6 +msgid "Unable to unlock the index." +msgstr "Kunde inte lÃ¥sa upp indexet." + +#: lib/index.tcl:30 +msgid "Index Error" +msgstr "Indexfel" + +#: lib/index.tcl:32 msgid "" -"This is example text.\n" -"If you like this text, it can be your font." +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." msgstr "" -"Detta är en exempeltext.\n" -"Om du tycker om den här texten kan den vara ditt teckensnitt." +"Misslyckades med att uppdatera Gitindexet. En omsökning kommer att startas " +"automatiskt för att synkronisera om git-gui." + +#: lib/index.tcl:43 +msgid "Continue" +msgstr "Fortsätt" + +#: lib/index.tcl:46 +msgid "Unlock Index" +msgstr "LÃ¥s upp index" + +#: lib/index.tcl:326 +msgid "Unstaging selected files from commit" +msgstr "Tar bort valda filer frÃ¥n incheckningskön" + +#: lib/index.tcl:330 +#, tcl-format +msgid "Unstaging %s from commit" +msgstr "Tar bort %s frÃ¥n incheckningskön" + +#: lib/index.tcl:369 +msgid "Ready to commit." +msgstr "Redo att checka in." + +#: lib/index.tcl:378 +msgid "Adding selected files" +msgstr "Lägger till valda filer" + +#: lib/index.tcl:382 +#, tcl-format +msgid "Adding %s" +msgstr "Lägger till %s" + +#: lib/index.tcl:412 +#, tcl-format +msgid "Stage %d untracked files?" +msgstr "Köa %d ospÃ¥rade filer?" + +#: lib/index.tcl:420 +msgid "Adding all changed files" +msgstr "Lägger till alla ändrade filer" + +#: lib/index.tcl:503 +#, tcl-format +msgid "Revert changes in file %s?" +msgstr "Ã…terställ ändringarna i filen %s?" + +#: lib/index.tcl:508 +#, tcl-format +msgid "Revert changes in these %i files?" +msgstr "Ã…terställ ändringarna i dessa %i filer?" + +#: lib/index.tcl:517 +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" +"Alla oköade ändringar kommer permanent gÃ¥ förlorade vid Ã¥terställningen." + +#: lib/index.tcl:520 lib/index.tcl:564 +msgid "Do Nothing" +msgstr "Gör ingenting" + +#: lib/index.tcl:546 +#, tcl-format +msgid "Delete untracked file %s?" +msgstr "Ta bort den ospÃ¥rade filen %s?" + +#: lib/index.tcl:551 +#, tcl-format +msgid "Delete these %i untracked files?" +msgstr "Ta bort dessa %i ospÃ¥rade filer?" + +#: lib/index.tcl:561 +msgid "Files will be permanently deleted." +msgstr "Filerna kommer tas bort permanent." + +#: lib/index.tcl:565 +msgid "Delete Files" +msgstr "Ta bort filer" + +#: lib/index.tcl:588 +msgid "Deleting" +msgstr "Tar bort" + +#: lib/index.tcl:667 +msgid "Encountered errors deleting files:\n" +msgstr "Fel uppstod vid borttagning av filer:\n" + +#: lib/index.tcl:676 +#, tcl-format +msgid "None of the %d selected files could be deleted." +msgstr "Ingen av de %d valda filerna kunde tas bort." + +#: lib/index.tcl:681 +#, tcl-format +msgid "%d of the %d selected files could not be deleted." +msgstr "%d av de %d valda filerna kunde inte tas bort." + +#: lib/index.tcl:728 +msgid "Reverting selected files" +msgstr "Ã…terställer valda filer" + +#: lib/index.tcl:732 +#, tcl-format +msgid "Reverting %s" +msgstr "Ã…terställer %s" + +#: lib/line.tcl:17 +msgid "Goto Line:" +msgstr "GÃ¥ till rad:" + +#: lib/line.tcl:23 +msgid "Go" +msgstr "GÃ¥" + +#: lib/merge.tcl:13 +msgid "" +"Cannot merge while amending.\n" +"\n" +"You must finish amending this commit before starting any type of merge.\n" +msgstr "" +"Kan inte slÃ¥ ihop vid utökning.\n" +"\n" +"Du mÃ¥ste göra färdig utökningen av incheckningen innan du pÃ¥börjar nÃ¥gon " +"slags sammanslagning.\n" + +#: lib/merge.tcl:27 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before a merge can be performed.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" +"Det senaste inlästa tillstÃ¥ndet motsvarar inte tillstÃ¥ndet i arkivet.\n" +"\n" +"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du mÃ¥ste " +"utföra en ny sökning innan du kan utföra en sammanslagning.\n" +"\n" +"Sökningen kommer att startas automatiskt nu.\n" + +#: lib/merge.tcl:45 +#, tcl-format +msgid "" +"You are in the middle of a conflicted merge.\n" +"\n" +"File %s has merge conflicts.\n" +"\n" +"You must resolve them, stage the file, and commit to complete the current " +"merge. Only then can you begin another merge.\n" +msgstr "" +"Du är mitt i en sammanslagning med konflikter.\n" +"\n" +"Filen %s har sammanslagningskonflikter.\n" +"\n" +"Du mÃ¥ste lösa dem, köa filen och checka in för att fullborda den aktuella " +"sammanslagningen. När du gjort det kan du pÃ¥börja en ny sammanslagning.\n" + +#: lib/merge.tcl:55 +#, tcl-format +msgid "" +"You are in the middle of a change.\n" +"\n" +"File %s is modified.\n" +"\n" +"You should complete the current commit before starting a merge. Doing so " +"will help you abort a failed merge, should the need arise.\n" +msgstr "" +"Du är mitt i en ändring.\n" +"\n" +"Filen %s har ändringar.\n" +"\n" +"Du bör fullborda den aktuella incheckningen innan du pÃ¥börjar en " +"sammanslagning. Om du gör det blir det enklare att avbryta en misslyckad " +"sammanslagning, om det skulle vara nödvändigt.\n" + +#: lib/merge.tcl:108 +#, tcl-format +msgid "%s of %s" +msgstr "%s av %s" + +#: lib/merge.tcl:126 +#, tcl-format +msgid "Merging %s and %s..." +msgstr "SlÃ¥r ihop %s och %s..." + +#: lib/merge.tcl:137 +msgid "Merge completed successfully." +msgstr "Sammanslagningen avslutades framgÃ¥ngsrikt." + +#: lib/merge.tcl:139 +msgid "Merge failed. Conflict resolution is required." +msgstr "Sammanslagningen misslyckades. Du mÃ¥ste lösa konflikterna." + +#: lib/merge.tcl:156 +#, tcl-format +msgid "%s (%s): Merge" +msgstr "%s (%s): Sammanslagning" + +#: lib/merge.tcl:164 +#, tcl-format +msgid "Merge Into %s" +msgstr "SlÃ¥ ihop i %s" + +#: lib/merge.tcl:183 +msgid "Revision To Merge" +msgstr "Revisioner att slÃ¥ ihop" + +#: lib/merge.tcl:218 +msgid "" +"Cannot abort while amending.\n" +"\n" +"You must finish amending this commit.\n" +msgstr "" +"Kan inte avbryta vid utökning.\n" +"\n" +"Du mÃ¥ste göra dig färdig med att utöka incheckningen.\n" + +#: lib/merge.tcl:228 +msgid "" +"Abort merge?\n" +"\n" +"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with aborting the current merge?" +msgstr "" +"Avbryt sammanslagning?\n" +"\n" +"Om du avbryter sammanslagningen kommer *ALLA* ej incheckade ändringar att gÃ¥ " +"förlorade.\n" +"\n" +"GÃ¥ vidare med att avbryta den aktuella sammanslagningen?" + +#: lib/merge.tcl:234 +msgid "" +"Reset changes?\n" +"\n" +"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with resetting the current changes?" +msgstr "" +"Ã…terställ ändringar?\n" +"\n" +"Om du Ã¥terställer ändringarna kommer *ALLA* ej incheckade ändringar att gÃ¥ " +"förlorade.\n" +"\n" +"GÃ¥ vidare med att Ã¥terställa de aktuella ändringarna?" + +#: lib/merge.tcl:246 +msgid "Aborting" +msgstr "Avbryter" + +#: lib/merge.tcl:247 +msgid "files reset" +msgstr "filer Ã¥terställda" + +#: lib/merge.tcl:277 +msgid "Abort failed." +msgstr "Misslyckades avbryta." + +#: lib/merge.tcl:279 +msgid "Abort completed. Ready." +msgstr "Avbrytning fullbordad. Redo." + +#: lib/mergetool.tcl:8 +msgid "Force resolution to the base version?" +msgstr "Tvinga lösning att använda basversionen?" + +#: lib/mergetool.tcl:9 +msgid "Force resolution to this branch?" +msgstr "Tvinga lösning att använda den aktuella grenen?" + +#: lib/mergetool.tcl:10 +msgid "Force resolution to the other branch?" +msgstr "Tvinga lösning att använda den andra grenen?" + +#: 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 "" +"Observera att diffen endast visar de ändringar som stÃ¥r i konflikt.\n" +"\n" +"%s kommer att skrivas över.\n" +"\n" +"Du mÃ¥ste starta om sammanslagningen för att göra den här operationen ogjord." + +#: lib/mergetool.tcl:45 +#, tcl-format +msgid "File %s seems to have unresolved conflicts, still stage?" +msgstr "Filen %s verkar innehÃ¥lla olösta konflikter. Vill du köa ändÃ¥?" + +#: lib/mergetool.tcl:60 +#, tcl-format +msgid "Adding resolution for %s" +msgstr "Lägger till lösning för %s" + +#: lib/mergetool.tcl:141 +msgid "Cannot resolve deletion or link conflicts using a tool" +msgstr "Kan inte lösa borttagnings- eller länkkonflikter med ett verktyg" + +#: lib/mergetool.tcl:146 +msgid "Conflict file does not exist" +msgstr "Konfliktfil existerar inte" + +#: lib/mergetool.tcl:246 +#, tcl-format +msgid "Not a GUI merge tool: '%s'" +msgstr "Inte ett grafiskt verktyg för sammanslagning: %s" + +#: lib/mergetool.tcl:275 +#, tcl-format +msgid "Unsupported merge tool '%s'" +msgstr "Verktyget â€%s†för sammanslagning stöds inte" + +#: lib/mergetool.tcl:310 +msgid "Merge tool is already running, terminate it?" +msgstr "Verktyget för sammanslagning körs redan. Vill du avsluta det?" + +#: lib/mergetool.tcl:330 +#, tcl-format +msgid "" +"Error retrieving versions:\n" +"%s" +msgstr "" +"Fel vid hämtning av versioner:\n" +"%s" + +#: lib/mergetool.tcl:350 +#, tcl-format +msgid "" +"Could not start the merge tool:\n" +"\n" +"%s" +msgstr "" +"Kunde inte starta verktyg för sammanslagning:\n" +"\n" +"%s" + +#: lib/mergetool.tcl:354 +msgid "Running merge tool..." +msgstr "Kör verktyg för sammanslagning..." + +#: lib/mergetool.tcl:382 lib/mergetool.tcl:390 +msgid "Merge tool failed." +msgstr "Verktyget för sammanslagning misslyckades." #: lib/option.tcl:11 #, tcl-format msgid "Invalid global encoding '%s'" -msgstr "Den globala teckenkodningen \"%s\" är ogiltig" +msgstr "Den globala teckenkodningen â€%s†är ogiltig" #: lib/option.tcl:19 #, tcl-format msgid "Invalid repo encoding '%s'" -msgstr "Arkivets teckenkodning \"%s\" är ogiltig" +msgstr "Arkivets teckenkodning â€%s†är ogiltig" #: lib/option.tcl:119 msgid "Restore Defaults" @@ -1521,239 +2300,89 @@ msgstr "Inställningar" msgid "Failed to completely save options:" msgstr "Misslyckades med att helt spara alternativ:" -#: lib/mergetool.tcl:8 -msgid "Force resolution to the base version?" -msgstr "Tvinga lösning att använda basversionen?" - -#: lib/mergetool.tcl:9 -msgid "Force resolution to this branch?" -msgstr "Tvinga lösning att använda den aktuella grenen?" +#: lib/remote_add.tcl:20 +#, tcl-format +msgid "%s (%s): Add Remote" +msgstr "%s (%s): Lägg till fjärrarkiv" -#: lib/mergetool.tcl:10 -msgid "Force resolution to the other branch?" -msgstr "Tvinga lösning att använda den andra grenen?" +#: lib/remote_add.tcl:25 +msgid "Add New Remote" +msgstr "Lägg till nytt fjärrarkiv" -#: 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 "" -"Observera att diffen endast visar de ändringar som stÃ¥r i konflikt.\n" -"\n" -"%s kommer att skrivas över.\n" -"\n" -"Du mÃ¥ste starta om sammanslagningen för att göra den här operationen ogjord." +#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37 +msgid "Add" +msgstr "Lägg till" -#: lib/mergetool.tcl:45 -#, tcl-format -msgid "File %s seems to have unresolved conflicts, still stage?" -msgstr "Filen %s verkar innehÃ¥lla olösta konflikter. Vill du köa ändÃ¥?" +#: lib/remote_add.tcl:39 +msgid "Remote Details" +msgstr "Detaljer för fjärrarkiv" -#: lib/mergetool.tcl:60 -#, tcl-format -msgid "Adding resolution for %s" -msgstr "Lägger till lösning för %s" +#: lib/remote_add.tcl:50 +msgid "Location:" +msgstr "Plats:" -#: lib/mergetool.tcl:141 -msgid "Cannot resolve deletion or link conflicts using a tool" -msgstr "Kan inte lösa borttagnings- eller länkkonflikter med ett verktyg" +#: lib/remote_add.tcl:60 +msgid "Further Action" +msgstr "Ytterligare Ã¥tgärd" -#: lib/mergetool.tcl:146 -msgid "Conflict file does not exist" -msgstr "Konfliktfil existerar inte" +#: lib/remote_add.tcl:63 +msgid "Fetch Immediately" +msgstr "Hämta omedelbart" -#: lib/mergetool.tcl:246 -#, tcl-format -msgid "Not a GUI merge tool: '%s'" -msgstr "Inte ett grafiskt verktyg för sammanslagning: %s" +#: lib/remote_add.tcl:69 +msgid "Initialize Remote Repository and Push" +msgstr "Initiera fjärrarkiv och sänd till" -#: lib/mergetool.tcl:275 -#, tcl-format -msgid "Unsupported merge tool '%s'" -msgstr "Verktyget \"%s\" för sammanslagning stöds inte" +#: lib/remote_add.tcl:75 +msgid "Do Nothing Else Now" +msgstr "Gör ingent mer nu" -#: lib/mergetool.tcl:310 -msgid "Merge tool is already running, terminate it?" -msgstr "Verktyget för sammanslagning körs redan. Vill du avsluta det?" +#: lib/remote_add.tcl:100 +msgid "Please supply a remote name." +msgstr "Ange ett namn för fjärrarkivet." -#: lib/mergetool.tcl:330 +#: lib/remote_add.tcl:113 #, tcl-format -msgid "" -"Error retrieving versions:\n" -"%s" -msgstr "" -"Fel vid hämtning av versioner:\n" -"%s" +msgid "'%s' is not an acceptable remote name." +msgstr "â€%s†kan inte användas som namn pÃ¥ fjärrarkivet." -#: lib/mergetool.tcl:350 +#: lib/remote_add.tcl:124 #, tcl-format -msgid "" -"Could not start the merge tool:\n" -"\n" -"%s" -msgstr "" -"Kunde inte starta verktyg för sammanslagning:\n" -"\n" -"%s" - -#: lib/mergetool.tcl:354 -msgid "Running merge tool..." -msgstr "Kör verktyg för sammanslagning..." - -#: lib/mergetool.tcl:382 lib/mergetool.tcl:390 -msgid "Merge tool failed." -msgstr "Verktyget för sammanslagning misslyckades." - -#: lib/tools_dlg.tcl:22 -msgid "Add Tool" -msgstr "Lägg till verktyg" - -#: lib/tools_dlg.tcl:28 -msgid "Add New Tool Command" -msgstr "Lägg till nytt verktygskommando" - -#: lib/tools_dlg.tcl:34 -msgid "Add globally" -msgstr "Lägg till globalt" - -#: lib/tools_dlg.tcl:46 -msgid "Tool Details" -msgstr "Detaljer för verktyg" - -#: lib/tools_dlg.tcl:49 -msgid "Use '/' separators to create a submenu tree:" -msgstr "Använd \"/\"-avdelare för att skapa ett undermenyträd:" - -#: lib/tools_dlg.tcl:60 -msgid "Command:" -msgstr "Kommando:" - -#: lib/tools_dlg.tcl:71 -msgid "Show a dialog before running" -msgstr "Visa dialog innan programmet startas" - -#: lib/tools_dlg.tcl:77 -msgid "Ask the user to select a revision (sets $REVISION)" -msgstr "Be användaren välja en version (sätter $REVISION)" - -#: lib/tools_dlg.tcl:82 -msgid "Ask the user for additional arguments (sets $ARGS)" -msgstr "Be användaren om ytterligare parametrar (sätter $ARGS)" - -#: lib/tools_dlg.tcl:89 -msgid "Don't show the command output window" -msgstr "Visa inte kommandots utdatafönster" - -#: lib/tools_dlg.tcl:94 -msgid "Run only if a diff is selected ($FILENAME not empty)" -msgstr "Kör endast om en diff har markerats ($FILENAME är inte tomt)" - -#: lib/tools_dlg.tcl:118 -msgid "Please supply a name for the tool." -msgstr "Ange ett namn för verktyget." +msgid "Failed to add remote '%s' of location '%s'." +msgstr "Kunde inte lägga till fjärrarkivet â€%s†pÃ¥ platsen â€%sâ€." -#: lib/tools_dlg.tcl:126 +#: lib/remote_add.tcl:132 lib/transport.tcl:6 #, tcl-format -msgid "Tool '%s' already exists." -msgstr "Verktyget \"%s\" finns redan." +msgid "fetch %s" +msgstr "hämta %s" -#: lib/tools_dlg.tcl:148 +#: lib/remote_add.tcl:133 #, tcl-format -msgid "" -"Could not add tool:\n" -"%s" -msgstr "" -"Kunde inte lägga till verktyget:\n" -"%s" - -#: lib/tools_dlg.tcl:187 -msgid "Remove Tool" -msgstr "Ta bort verktyg" - -#: lib/tools_dlg.tcl:193 -msgid "Remove Tool Commands" -msgstr "Ta bort verktygskommandon" - -#: lib/tools_dlg.tcl:198 -msgid "Remove" -msgstr "Ta bort" - -#: lib/tools_dlg.tcl:231 -msgid "(Blue denotes repository-local tools)" -msgstr "(BlÃ¥tt anger verktyg lokala för arkivet)" +msgid "Fetching the %s" +msgstr "Hämtar %s" -#: lib/tools_dlg.tcl:292 +#: lib/remote_add.tcl:156 #, tcl-format -msgid "Run Command: %s" -msgstr "Kör kommandot: %s" - -#: lib/tools_dlg.tcl:306 -msgid "Arguments" -msgstr "Argument" - -#: lib/tools_dlg.tcl:341 -msgid "OK" -msgstr "OK" - -#: lib/search.tcl:48 -msgid "Find:" -msgstr "Sök:" - -#: lib/search.tcl:50 -msgid "Next" -msgstr "Nästa" - -#: lib/search.tcl:51 -msgid "Prev" -msgstr "Föreg" - -#: lib/search.tcl:52 -msgid "RegExp" -msgstr "Reg.uttr." - -#: lib/search.tcl:54 -msgid "Case" -msgstr "Skiftläge" - -#: lib/branch_rename.tcl:15 lib/branch_rename.tcl:23 -msgid "Rename Branch" -msgstr "Byt namn pÃ¥ gren" - -#: lib/branch_rename.tcl:28 -msgid "Rename" -msgstr "Byt namn" - -#: lib/branch_rename.tcl:38 -msgid "Branch:" -msgstr "Gren:" - -#: lib/branch_rename.tcl:46 -msgid "New Name:" -msgstr "Nytt namn:" - -#: lib/branch_rename.tcl:81 -msgid "Please select a branch to rename." -msgstr "Välj en gren att byta namn pÃ¥." +msgid "Do not know how to initialize repository at location '%s'." +msgstr "Vet inte hur arkivet pÃ¥ platsen â€%s†skall initieras." -#: lib/branch_rename.tcl:92 lib/branch_create.tcl:154 -msgid "Please supply a branch name." -msgstr "Ange ett namn för grenen." +#: lib/remote_add.tcl:162 lib/transport.tcl:54 lib/transport.tcl:92 +#: lib/transport.tcl:110 +#, tcl-format +msgid "push %s" +msgstr "sänd %s" -#: lib/branch_rename.tcl:112 lib/branch_create.tcl:165 +#: lib/remote_add.tcl:163 #, tcl-format -msgid "'%s' is not an acceptable branch name." -msgstr "\"%s\" kan inte användas som namn pÃ¥ grenen." +msgid "Setting up the %s (at %s)" +msgstr "Konfigurerar %s (pÃ¥ %s)" -#: lib/branch_rename.tcl:123 +#: lib/remote_branch_delete.tcl:29 #, tcl-format -msgid "Failed to rename '%s'." -msgstr "Kunde inte byta namn pÃ¥ \"%s\"." +msgid "%s (%s): Delete Branch Remotely" +msgstr "%s (%s): Ta bort gren frÃ¥n fjärrarkiv" -#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 +#: lib/remote_branch_delete.tcl:34 msgid "Delete Branch Remotely" msgstr "Ta bort gren frÃ¥n fjärrarkiv" @@ -1761,6 +2390,14 @@ msgstr "Ta bort gren frÃ¥n fjärrarkiv" msgid "From Repository" msgstr "FrÃ¥n arkiv" +#: lib/remote_branch_delete.tcl:51 lib/transport.tcl:165 +msgid "Remote:" +msgstr "Fjärrarkiv:" + +#: lib/remote_branch_delete.tcl:72 lib/transport.tcl:187 +msgid "Arbitrary Location:" +msgstr "Godtycklig plats:" + #: lib/remote_branch_delete.tcl:88 msgid "Branches" msgstr "Grenar" @@ -1773,13 +2410,9 @@ msgstr "Ta endast bort om" msgid "Merged Into:" msgstr "Sammanslagen i:" -#: lib/remote_branch_delete.tcl:120 lib/branch_delete.tcl:53 -msgid "Always (Do not perform merge checks)" -msgstr "Alltid (utför inte sammanslagningstest)" - #: lib/remote_branch_delete.tcl:153 msgid "A branch is required for 'Merged Into'." -msgstr "En gren krävs för \"Sammanslagen i\"." +msgstr "En gren krävs för â€Sammanslagen iâ€." #: lib/remote_branch_delete.tcl:185 #, tcl-format @@ -1805,16 +2438,6 @@ msgstr "" msgid "Please select one or more branches to delete." msgstr "Välj en eller flera grenar att ta bort." -#: lib/remote_branch_delete.tcl:218 lib/branch_delete.tcl:115 -msgid "" -"Recovering deleted branches is difficult.\n" -"\n" -"Delete the selected branches?" -msgstr "" -"Det kan vara svÃ¥rt att Ã¥terställa borttagna grenar.\n" -"\n" -"Ta bort de valda grenarna?" - #: lib/remote_branch_delete.tcl:227 #, tcl-format msgid "Deleting branches from %s" @@ -1829,384 +2452,122 @@ msgstr "Inget arkiv markerat." msgid "Scanning %s..." msgstr "Söker %s..." -#: lib/choose_repository.tcl:33 -msgid "Git Gui" -msgstr "Git Gui" - -#: lib/choose_repository.tcl:92 lib/choose_repository.tcl:412 -msgid "Create New Repository" -msgstr "Skapa nytt arkiv" - -#: lib/choose_repository.tcl:98 -msgid "New..." -msgstr "Nytt..." - -#: lib/choose_repository.tcl:105 lib/choose_repository.tcl:496 -msgid "Clone Existing Repository" -msgstr "Klona befintligt arkiv" - -#: lib/choose_repository.tcl:116 -msgid "Clone..." -msgstr "Klona..." - -#: lib/choose_repository.tcl:123 lib/choose_repository.tcl:1064 -msgid "Open Existing Repository" -msgstr "Öppna befintligt arkiv" - -#: lib/choose_repository.tcl:129 -msgid "Open..." -msgstr "Öppna..." - -#: lib/choose_repository.tcl:142 -msgid "Recent Repositories" -msgstr "Senaste arkiven" - -#: lib/choose_repository.tcl:148 -msgid "Open Recent Repository:" -msgstr "Öppna tidigare arkiv:" - -#: lib/choose_repository.tcl:316 lib/choose_repository.tcl:323 -#: lib/choose_repository.tcl:330 -#, tcl-format -msgid "Failed to create repository %s:" -msgstr "Kunde inte skapa arkivet %s:" - -#: lib/choose_repository.tcl:407 lib/branch_create.tcl:33 -msgid "Create" -msgstr "Skapa" - -#: lib/choose_repository.tcl:417 -msgid "Directory:" -msgstr "Katalog:" - -#: lib/choose_repository.tcl:447 lib/choose_repository.tcl:573 -#: lib/choose_repository.tcl:1098 -msgid "Git Repository" -msgstr "Gitarkiv" - -#: lib/choose_repository.tcl:472 -#, tcl-format -msgid "Directory %s already exists." -msgstr "Katalogen %s finns redan." - -#: lib/choose_repository.tcl:476 -#, tcl-format -msgid "File %s already exists." -msgstr "Filen %s finns redan." - -#: lib/choose_repository.tcl:491 -msgid "Clone" -msgstr "Klona" - -#: lib/choose_repository.tcl:504 -msgid "Source Location:" -msgstr "Plats för källkod:" - -#: lib/choose_repository.tcl:513 -msgid "Target Directory:" -msgstr "MÃ¥lkatalog:" - -#: lib/choose_repository.tcl:523 -msgid "Clone Type:" -msgstr "Typ av klon:" - -#: lib/choose_repository.tcl:528 -msgid "Standard (Fast, Semi-Redundant, Hardlinks)" -msgstr "Standard (snabb, semiredundant, hÃ¥rda länkar)" - -#: lib/choose_repository.tcl:533 -msgid "Full Copy (Slower, Redundant Backup)" -msgstr "Full kopia (lÃ¥ngsammare, redundant säkerhetskopia)" - -#: lib/choose_repository.tcl:538 -msgid "Shared (Fastest, Not Recommended, No Backup)" -msgstr "Delad (snabbast, rekommenderas ej, ingen säkerhetskopia)" - -#: lib/choose_repository.tcl:545 -msgid "Recursively clone submodules too" -msgstr "Klona även rekursivt undermoduler" - -#: lib/choose_repository.tcl:579 lib/choose_repository.tcl:626 -#: lib/choose_repository.tcl:772 lib/choose_repository.tcl:842 -#: lib/choose_repository.tcl:1104 lib/choose_repository.tcl:1112 -#, tcl-format -msgid "Not a Git repository: %s" -msgstr "Inte ett Gitarkiv: %s" - -#: lib/choose_repository.tcl:615 -msgid "Standard only available for local repository." -msgstr "Standard är endast tillgängligt för lokala arkiv." - -#: lib/choose_repository.tcl:619 -msgid "Shared only available for local repository." -msgstr "Delat är endast tillgängligt för lokala arkiv." - -#: lib/choose_repository.tcl:640 -#, tcl-format -msgid "Location %s already exists." -msgstr "Platsen %s finns redan." - -#: lib/choose_repository.tcl:651 -msgid "Failed to configure origin" -msgstr "Kunde inte konfigurera ursprung" - -#: lib/choose_repository.tcl:663 -msgid "Counting objects" -msgstr "Räknar objekt" - -#: lib/choose_repository.tcl:664 -msgid "buckets" -msgstr "hinkar" - -#: lib/choose_repository.tcl:688 -#, tcl-format -msgid "Unable to copy objects/info/alternates: %s" -msgstr "Kunde inte kopiera objekt/info/alternativ: %s" - -#: lib/choose_repository.tcl:724 -#, tcl-format -msgid "Nothing to clone from %s." -msgstr "Ingenting att klona frÃ¥n %s." - -#: lib/choose_repository.tcl:726 lib/choose_repository.tcl:940 -#: lib/choose_repository.tcl:952 -msgid "The 'master' branch has not been initialized." -msgstr "Grenen \"master\" har inte initierats." - -#: lib/choose_repository.tcl:739 -msgid "Hardlinks are unavailable. Falling back to copying." -msgstr "HÃ¥rda länkar är inte tillgängliga. Faller tillbaka pÃ¥ kopiering." - -#: lib/choose_repository.tcl:751 -#, tcl-format -msgid "Cloning from %s" -msgstr "Klonar frÃ¥n %s" - -#: lib/choose_repository.tcl:782 -msgid "Copying objects" -msgstr "Kopierar objekt" - -#: lib/choose_repository.tcl:783 -msgid "KiB" -msgstr "KiB" - -#: lib/choose_repository.tcl:807 -#, tcl-format -msgid "Unable to copy object: %s" -msgstr "Kunde inte kopiera objekt: %s" - -#: lib/choose_repository.tcl:817 -msgid "Linking objects" -msgstr "Länkar objekt" - -#: lib/choose_repository.tcl:818 -msgid "objects" -msgstr "objekt" - -#: lib/choose_repository.tcl:826 -#, tcl-format -msgid "Unable to hardlink object: %s" -msgstr "Kunde inte hÃ¥rdlänka objekt: %s" - -#: lib/choose_repository.tcl:881 -msgid "Cannot fetch branches and objects. See console output for details." -msgstr "Kunde inte hämta grenar och objekt. Se konsolutdata för detaljer." - -#: lib/choose_repository.tcl:892 -msgid "Cannot fetch tags. See console output for details." -msgstr "Kunde inte hämta taggar. Se konsolutdata för detaljer." - -#: lib/choose_repository.tcl:916 -msgid "Cannot determine HEAD. See console output for details." -msgstr "Kunde inte avgöra HEAD. Se konsolutdata för detaljer." - -#: lib/choose_repository.tcl:925 -#, tcl-format -msgid "Unable to cleanup %s" -msgstr "Kunde inte städa upp %s" - -#: lib/choose_repository.tcl:931 -msgid "Clone failed." -msgstr "Kloning misslyckades." +#: lib/remote.tcl:200 +msgid "Push to" +msgstr "Sänd till" -#: lib/choose_repository.tcl:938 -msgid "No default branch obtained." -msgstr "Hämtade ingen standardgren." +#: lib/remote.tcl:218 +msgid "Remove Remote" +msgstr "Ta bort fjärrarkiv" -#: lib/choose_repository.tcl:949 -#, tcl-format -msgid "Cannot resolve %s as a commit." -msgstr "Kunde inte slÃ¥ upp %s till nÃ¥gon incheckning." +#: lib/remote.tcl:223 +msgid "Prune from" +msgstr "Ta bort frÃ¥n" -#: lib/choose_repository.tcl:961 -msgid "Creating working directory" -msgstr "Skapar arbetskatalog" +#: lib/remote.tcl:228 +msgid "Fetch from" +msgstr "Hämta frÃ¥n" -#: lib/choose_repository.tcl:962 lib/index.tcl:70 lib/index.tcl:136 -#: lib/index.tcl:207 -msgid "files" -msgstr "filer" +#: lib/remote.tcl:249 lib/remote.tcl:253 lib/remote.tcl:258 lib/remote.tcl:264 +msgid "All" +msgstr "Alla" -#: lib/choose_repository.tcl:981 -msgid "Cannot clone submodules." -msgstr "Kan inte klona undermoduler." +#: lib/search.tcl:48 +msgid "Find:" +msgstr "Sök:" -#: lib/choose_repository.tcl:990 -msgid "Cloning submodules" -msgstr "Klonar undermoduler" +#: lib/search.tcl:50 +msgid "Next" +msgstr "Nästa" -#: lib/choose_repository.tcl:1015 -msgid "Initial file checkout failed." -msgstr "Inledande filutcheckning misslyckades." +#: lib/search.tcl:51 +msgid "Prev" +msgstr "Föreg" -#: lib/choose_repository.tcl:1059 -msgid "Open" -msgstr "Öppna" +#: lib/search.tcl:52 +msgid "RegExp" +msgstr "Reg.uttr." -#: lib/choose_repository.tcl:1069 -msgid "Repository:" -msgstr "Arkiv:" +#: lib/search.tcl:54 +msgid "Case" +msgstr "Skiftläge" -#: lib/choose_repository.tcl:1118 +#: lib/shortcut.tcl:8 lib/shortcut.tcl:40 lib/shortcut.tcl:72 #, tcl-format -msgid "Failed to open repository %s:" -msgstr "Kunde inte öppna arkivet %s:" - -#: lib/about.tcl:26 -msgid "git-gui - a graphical user interface for Git." -msgstr "git-gui - ett grafiskt användargränssnitt för Git." - -#: lib/blame.tcl:73 -msgid "File Viewer" -msgstr "Filvisare" - -#: lib/blame.tcl:79 -msgid "Commit:" -msgstr "Incheckning:" - -#: lib/blame.tcl:280 -msgid "Copy Commit" -msgstr "Kopiera incheckning" +msgid "%s (%s): Create Desktop Icon" +msgstr "%s (%s): Skapa skrivbordsikon" -#: lib/blame.tcl:284 -msgid "Find Text..." -msgstr "Sök text..." +#: lib/shortcut.tcl:24 lib/shortcut.tcl:62 +msgid "Cannot write shortcut:" +msgstr "Kan inte skriva genväg:" -#: lib/blame.tcl:288 -msgid "Goto Line..." -msgstr "GÃ¥ till rad..." +#: lib/shortcut.tcl:137 +msgid "Cannot write icon:" +msgstr "Kan inte skriva ikon:" -#: lib/blame.tcl:297 -msgid "Do Full Copy Detection" -msgstr "Gör full kopieringsigenkänning" +#: lib/spellcheck.tcl:57 +msgid "Unsupported spell checker" +msgstr "Stavningskontrollprogrammet stöds inte" -#: lib/blame.tcl:301 -msgid "Show History Context" -msgstr "Visa historiksammanhang" +#: lib/spellcheck.tcl:65 +msgid "Spell checking is unavailable" +msgstr "Stavningskontroll är ej tillgänglig" -#: lib/blame.tcl:304 -msgid "Blame Parent Commit" -msgstr "Klandra föräldraincheckning" +#: lib/spellcheck.tcl:68 +msgid "Invalid spell checking configuration" +msgstr "Ogiltig inställning för stavningskontroll" -#: lib/blame.tcl:466 +#: lib/spellcheck.tcl:70 #, tcl-format -msgid "Reading %s..." -msgstr "Läser %s..." - -#: lib/blame.tcl:594 -msgid "Loading copy/move tracking annotations..." -msgstr "Läser annoteringar för kopiering/flyttning..." - -#: lib/blame.tcl:614 -msgid "lines annotated" -msgstr "rader annoterade" - -#: lib/blame.tcl:806 -msgid "Loading original location annotations..." -msgstr "Läser in annotering av originalplacering..." - -#: lib/blame.tcl:809 -msgid "Annotation complete." -msgstr "Annotering fullbordad." - -#: lib/blame.tcl:839 -msgid "Busy" -msgstr "Upptagen" - -#: lib/blame.tcl:840 -msgid "Annotation process is already running." -msgstr "Annoteringsprocess körs redan." - -#: lib/blame.tcl:879 -msgid "Running thorough copy detection..." -msgstr "Kör grundlig kopieringsigenkänning..." - -#: lib/blame.tcl:947 -msgid "Loading annotation..." -msgstr "Läser in annotering..." - -#: lib/blame.tcl:1000 -msgid "Author:" -msgstr "Författare:" - -#: lib/blame.tcl:1004 -msgid "Committer:" -msgstr "Incheckare:" - -#: lib/blame.tcl:1009 -msgid "Original File:" -msgstr "Ursprunglig fil:" - -#: lib/blame.tcl:1057 -msgid "Cannot find HEAD commit:" -msgstr "Hittar inte incheckning för HEAD:" +msgid "Reverting dictionary to %s." +msgstr "Ã…terställer ordlistan till %s." -#: lib/blame.tcl:1112 -msgid "Cannot find parent commit:" -msgstr "Hittar inte föräldraincheckning:" +#: lib/spellcheck.tcl:73 +msgid "Spell checker silently failed on startup" +msgstr "Stavningskontroll misslyckades tyst vid start" -#: lib/blame.tcl:1127 -msgid "Unable to display parent" -msgstr "Kan inte visa förälder" +#: lib/spellcheck.tcl:80 +msgid "Unrecognized spell checker" +msgstr "Stavningskontrollprogrammet känns inte igen" -#: lib/blame.tcl:1269 -msgid "Originally By:" -msgstr "Ursprungligen av:" +#: lib/spellcheck.tcl:186 +msgid "No Suggestions" +msgstr "Inga förslag" -#: lib/blame.tcl:1275 -msgid "In File:" -msgstr "I filen:" +#: lib/spellcheck.tcl:388 +msgid "Unexpected EOF from spell checker" +msgstr "Oväntat filslut frÃ¥n stavningskontroll" -#: lib/blame.tcl:1280 -msgid "Copied Or Moved Here By:" -msgstr "Kopierad eller flyttad hit av:" +#: lib/spellcheck.tcl:392 +msgid "Spell Checker Failed" +msgstr "Stavningskontroll misslyckades" -#: lib/sshkey.tcl:31 +#: lib/sshkey.tcl:34 msgid "No keys found." msgstr "Inga nycklar hittades." -#: lib/sshkey.tcl:34 +#: lib/sshkey.tcl:37 #, tcl-format msgid "Found a public key in: %s" msgstr "Hittade öppen nyckel i: %s" -#: lib/sshkey.tcl:40 +#: lib/sshkey.tcl:43 msgid "Generate Key" msgstr "Skapa nyckel" -#: lib/sshkey.tcl:58 +#: lib/sshkey.tcl:61 msgid "Copy To Clipboard" msgstr "Kopiera till Urklipp" -#: lib/sshkey.tcl:72 +#: lib/sshkey.tcl:75 msgid "Your OpenSSH Public Key" msgstr "Din öppna OpenSSH-nyckel" -#: lib/sshkey.tcl:80 +#: lib/sshkey.tcl:83 msgid "Generating..." msgstr "Skapar..." -#: lib/sshkey.tcl:86 +#: lib/sshkey.tcl:89 #, tcl-format msgid "" "Could not start ssh-keygen:\n" @@ -2217,520 +2578,232 @@ msgstr "" "\n" "%s" -#: lib/sshkey.tcl:113 +#: lib/sshkey.tcl:116 msgid "Generation failed." msgstr "Misslyckades med att skapa." -#: lib/sshkey.tcl:120 +#: lib/sshkey.tcl:123 msgid "Generation succeeded, but no keys found." msgstr "Lyckades skapa nyckeln, men hittar inte nÃ¥gon nyckel." -#: lib/sshkey.tcl:123 +#: lib/sshkey.tcl:126 #, tcl-format msgid "Your key is in: %s" msgstr "Din nyckel finns i: %s" -#: lib/branch_create.tcl:23 -msgid "Create Branch" -msgstr "Skapa gren" - -#: lib/branch_create.tcl:28 -msgid "Create New Branch" -msgstr "Skapa ny gren" - -#: lib/branch_create.tcl:42 -msgid "Branch Name" -msgstr "Namn pÃ¥ gren" - -#: lib/branch_create.tcl:57 -msgid "Match Tracking Branch Name" -msgstr "Använd namn pÃ¥ spÃ¥rad gren" - -#: lib/branch_create.tcl:66 -msgid "Starting Revision" -msgstr "Inledande revision" - -#: lib/branch_create.tcl:72 -msgid "Update Existing Branch:" -msgstr "Uppdatera befintlig gren:" - -#: lib/branch_create.tcl:75 -msgid "No" -msgstr "Nej" - -#: lib/branch_create.tcl:80 -msgid "Fast Forward Only" -msgstr "Endast snabbspolning" - -#: lib/branch_create.tcl:97 -msgid "Checkout After Creation" -msgstr "Checka ut när skapad" - -#: lib/branch_create.tcl:132 -msgid "Please select a tracking branch." -msgstr "Välj en gren att spÃ¥ra." - -#: lib/branch_create.tcl:141 +#: lib/status_bar.tcl:263 #, tcl-format -msgid "Tracking branch %s is not a branch in the remote repository." -msgstr "Den spÃ¥rade grenen %s är inte en gren i fjärrarkivet." - -#: lib/shortcut.tcl:21 lib/shortcut.tcl:62 -msgid "Cannot write shortcut:" -msgstr "Kan inte skriva genväg:" - -#: lib/shortcut.tcl:137 -msgid "Cannot write icon:" -msgstr "Kan inte skriva ikon:" - -#: lib/choose_rev.tcl:52 -msgid "This Detached Checkout" -msgstr "Denna frÃ¥nkopplade utcheckning" - -#: lib/choose_rev.tcl:60 -msgid "Revision Expression:" -msgstr "Revisionsuttryck:" - -#: lib/choose_rev.tcl:72 -msgid "Local Branch" -msgstr "Lokal gren" - -#: lib/choose_rev.tcl:77 -msgid "Tracking Branch" -msgstr "SpÃ¥rande gren" - -#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544 -msgid "Tag" -msgstr "Tagg" +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "%s... %*i av %*i %s (%3i%%)" -#: lib/choose_rev.tcl:321 +#: lib/tools_dlg.tcl:22 #, tcl-format -msgid "Invalid revision: %s" -msgstr "Ogiltig revision: %s" +msgid "%s (%s): Add Tool" +msgstr "%s (%s): Lägg till verktyg" -#: lib/choose_rev.tcl:342 -msgid "No revision selected." -msgstr "Ingen revision vald." +#: lib/tools_dlg.tcl:28 +msgid "Add New Tool Command" +msgstr "Lägg till nytt verktygskommando" -#: lib/choose_rev.tcl:350 -msgid "Revision expression is empty." -msgstr "Revisionsuttrycket är tomt." +#: lib/tools_dlg.tcl:34 +msgid "Add globally" +msgstr "Lägg till globalt" -#: lib/choose_rev.tcl:537 -msgid "Updated" -msgstr "Uppdaterad" +#: lib/tools_dlg.tcl:46 +msgid "Tool Details" +msgstr "Detaljer för verktyg" -#: lib/choose_rev.tcl:565 -msgid "URL" -msgstr "Webbadress" +#: lib/tools_dlg.tcl:49 +msgid "Use '/' separators to create a submenu tree:" +msgstr "Använd â€/â€-avdelare för att skapa ett undermenyträd:" -#: lib/commit.tcl:9 -msgid "" -"There is nothing to amend.\n" -"\n" -"You are about to create the initial commit. There is no commit before this " -"to amend.\n" -msgstr "" -"Det finns ingenting att utöka.\n" -"\n" -"Du hÃ¥ller pÃ¥ att skapa den inledande incheckningen. Det finns ingen tidigare " -"incheckning att utöka.\n" +#: lib/tools_dlg.tcl:60 +msgid "Command:" +msgstr "Kommando:" -#: lib/commit.tcl:18 -msgid "" -"Cannot amend while merging.\n" -"\n" -"You are currently in the middle of a merge that has not been fully " -"completed. You cannot amend the prior commit unless you first abort the " -"current merge activity.\n" -msgstr "" -"Kan inte utöka vid sammanslagning.\n" -"\n" -"Du är i mitten av en sammanslagning som inte är fullbordad. Du kan inte " -"utöka tidigare incheckningar om du inte först avbryter den pÃ¥gÃ¥ende " -"sammanslagningen.\n" +#: lib/tools_dlg.tcl:71 +msgid "Show a dialog before running" +msgstr "Visa dialog innan programmet startas" -#: lib/commit.tcl:48 -msgid "Error loading commit data for amend:" -msgstr "Fel vid inläsning av incheckningsdata för utökning:" +#: lib/tools_dlg.tcl:77 +msgid "Ask the user to select a revision (sets $REVISION)" +msgstr "Be användaren välja en version (sätter $REVISION)" -#: lib/commit.tcl:75 -msgid "Unable to obtain your identity:" -msgstr "Kunde inte hämta din identitet:" +#: lib/tools_dlg.tcl:82 +msgid "Ask the user for additional arguments (sets $ARGS)" +msgstr "Be användaren om ytterligare parametrar (sätter $ARGS)" -#: lib/commit.tcl:80 -msgid "Invalid GIT_COMMITTER_IDENT:" -msgstr "Felaktig GIT_COMMITTER_IDENT:" +#: lib/tools_dlg.tcl:89 +msgid "Don't show the command output window" +msgstr "Visa inte kommandots utdatafönster" -#: lib/commit.tcl:129 -#, tcl-format -msgid "warning: Tcl does not support encoding '%s'." -msgstr "varning: Tcl stöder inte teckenkodningen \"%s\"." +#: lib/tools_dlg.tcl:94 +msgid "Run only if a diff is selected ($FILENAME not empty)" +msgstr "Kör endast om en diff har markerats ($FILENAME är inte tomt)" -#: lib/commit.tcl:149 -msgid "" -"Last scanned state does not match repository state.\n" -"\n" -"Another Git program has modified this repository since the last scan. A " -"rescan must be performed before another commit can be created.\n" -"\n" -"The rescan will be automatically started now.\n" -msgstr "" -"Det senaste inlästa tillstÃ¥ndet motsvarar inte tillstÃ¥ndet i arkivet.\n" -"\n" -"Ett annat Git-program har ändrat arkivet sedan senaste avsökningen. Du mÃ¥ste " -"utföra en ny sökning innan du kan göra en ny incheckning.\n" -"\n" -"Sökningen kommer att startas automatiskt nu.\n" +#: lib/tools_dlg.tcl:118 +msgid "Please supply a name for the tool." +msgstr "Ange ett namn för verktyget." -#: lib/commit.tcl:173 +#: lib/tools_dlg.tcl:126 #, tcl-format -msgid "" -"Unmerged files cannot be committed.\n" -"\n" -"File %s has merge conflicts. You must resolve them and stage the file " -"before committing.\n" -msgstr "" -"Osammanslagna filer kan inte checkas in.\n" -"\n" -"Filen %s har sammanslagningskonflikter. Du mÃ¥ste lösa dem och köa filen " -"innan du checkar in den.\n" +msgid "Tool '%s' already exists." +msgstr "Verktyget â€%s†finns redan." -#: lib/commit.tcl:181 +#: lib/tools_dlg.tcl:148 #, tcl-format msgid "" -"Unknown file state %s detected.\n" -"\n" -"File %s cannot be committed by this program.\n" -msgstr "" -"Okänd filstatus %s upptäckt.\n" -"\n" -"Filen %s kan inte checkas in av programmet.\n" - -#: lib/commit.tcl:189 -msgid "" -"No changes to commit.\n" -"\n" -"You must stage at least 1 file before you can commit.\n" -msgstr "" -"Inga ändringar att checka in.\n" -"\n" -"Du mÃ¥ste köa Ã¥tminstone en fil innan du kan checka in.\n" - -#: lib/commit.tcl:204 -msgid "" -"Please supply a commit message.\n" -"\n" -"A good commit message has the following format:\n" -"\n" -"- First line: Describe in one sentence what you did.\n" -"- Second line: Blank\n" -"- Remaining lines: Describe why this change is good.\n" -msgstr "" -"Ange ett incheckningsmeddelande.\n" -"\n" -"Ett bra incheckningsmeddelande har följande format:\n" -"\n" -"- Första raden: Beskriv i en mening vad du gjorde.\n" -"- Andra raden: Tom\n" -"- Följande rader: Beskriv varför det här är en bra ändring.\n" - -#: lib/commit.tcl:235 -msgid "Calling pre-commit hook..." -msgstr "Anropar kroken före incheckning (pre-commit)..." - -#: lib/commit.tcl:250 -msgid "Commit declined by pre-commit hook." -msgstr "Incheckningen avvisades av kroken före incheckning (pre-commit)." - -#: lib/commit.tcl:269 -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 " -"changes and it can be difficult to retrieve them later from the reflog. You " -"should probably cancel this commit and create a new branch to continue.\n" -" \n" -" Do you really want to proceed with your Commit?" +"Could not add tool:\n" +"%s" msgstr "" -"Du är pÃ¥ väg att checka in pÃ¥ ett frÃ¥nkopplat huvud. Det kan potentiellt " -"vara farligt, eftersom du kommer förlora dina ändringar om du växlar till en " -"annan gren och det kan vara svÃ¥rt att hämta dem senare frÃ¥n ref-loggen. Du " -"bör troligen avbryta incheckningen och skapa en ny gren för att fortsätta.\n" -" \n" -" Vill du verkligen fortsätta checka in?" - -#: lib/commit.tcl:290 -msgid "Calling commit-msg hook..." -msgstr "Anropar kroken för incheckningsmeddelande (commit-msg)..." - -#: lib/commit.tcl:305 -msgid "Commit declined by commit-msg hook." -msgstr "Incheckning avvisad av kroken för incheckningsmeddelande (commit-msg)." - -#: lib/commit.tcl:318 -msgid "Committing changes..." -msgstr "Checkar in ändringar..." - -#: lib/commit.tcl:334 -msgid "write-tree failed:" -msgstr "write-tree misslyckades:" - -#: lib/commit.tcl:335 lib/commit.tcl:379 lib/commit.tcl:400 -msgid "Commit failed." -msgstr "Incheckningen misslyckades." +"Kunde inte lägga till verktyget:\n" +"%s" -#: lib/commit.tcl:352 +#: lib/tools_dlg.tcl:187 #, tcl-format -msgid "Commit %s appears to be corrupt" -msgstr "Incheckningen %s verkar vara trasig" +msgid "%s (%s): Remove Tool" +msgstr "%s (%s): Ta bort verktyg" -#: lib/commit.tcl:357 -msgid "" -"No changes to commit.\n" -"\n" -"No files were modified by this commit and it was not a merge commit.\n" -"\n" -"A rescan will be automatically started now.\n" -msgstr "" -"Inga ändringar att checka in.\n" -"\n" -"Inga filer ändrades av incheckningen och det var inte en sammanslagning.\n" -"\n" -"En sökning kommer att startas automatiskt nu.\n" - -#: lib/commit.tcl:364 -msgid "No changes to commit." -msgstr "Inga ändringar att checka in." +#: lib/tools_dlg.tcl:193 +msgid "Remove Tool Commands" +msgstr "Ta bort verktygskommandon" -#: lib/commit.tcl:378 -msgid "commit-tree failed:" -msgstr "commit-tree misslyckades:" +#: lib/tools_dlg.tcl:198 +msgid "Remove" +msgstr "Ta bort" -#: lib/commit.tcl:399 -msgid "update-ref failed:" -msgstr "update-ref misslyckades:" +#: lib/tools_dlg.tcl:231 +msgid "(Blue denotes repository-local tools)" +msgstr "(BlÃ¥tt anger verktyg lokala för arkivet)" -#: lib/commit.tcl:492 +#: lib/tools_dlg.tcl:283 #, tcl-format -msgid "Created commit %s: %s" -msgstr "Skapade incheckningen %s: %s" +msgid "%s (%s):" +msgstr "%s (%s):" -#: lib/branch_delete.tcl:16 -msgid "Delete Branch" -msgstr "Ta bort gren" - -#: lib/branch_delete.tcl:21 -msgid "Delete Local Branch" -msgstr "Ta bort lokal gren" +#: lib/tools_dlg.tcl:292 +#, tcl-format +msgid "Run Command: %s" +msgstr "Kör kommandot: %s" -#: lib/branch_delete.tcl:39 -msgid "Local Branches" -msgstr "Lokala grenar" +#: lib/tools_dlg.tcl:306 +msgid "Arguments" +msgstr "Argument" -#: lib/branch_delete.tcl:51 -msgid "Delete Only If Merged Into" -msgstr "Ta bara bort om sammanslagen med" +#: lib/tools_dlg.tcl:341 +msgid "OK" +msgstr "OK" -#: lib/branch_delete.tcl:103 +#: lib/tools.tcl:76 #, tcl-format -msgid "The following branches are not completely merged into %s:" -msgstr "Följande grenar är inte till fullo sammanslagna med %s:" +msgid "Running %s requires a selected file." +msgstr "För att starta %s mÃ¥ste du välja en fil." -#: lib/branch_delete.tcl:141 +#: lib/tools.tcl:92 #, tcl-format -msgid "" -"Failed to delete branches:\n" -"%s" -msgstr "" -"Kunde inte ta bort grenar:\n" -"%s" - -#: lib/index.tcl:6 -msgid "Unable to unlock the index." -msgstr "Kunde inte lÃ¥sa upp indexet." - -#: lib/index.tcl:17 -msgid "Index Error" -msgstr "Indexfel" - -#: lib/index.tcl:19 -msgid "" -"Updating the Git index failed. A rescan will be automatically started to " -"resynchronize git-gui." -msgstr "" -"Misslyckades med att uppdatera Gitindexet. En omsökning kommer att startas " -"automatiskt för att synkronisera om git-gui." - -#: lib/index.tcl:30 -msgid "Continue" -msgstr "Fortsätt" - -#: lib/index.tcl:33 -msgid "Unlock Index" -msgstr "LÃ¥s upp index" +msgid "Are you sure you want to run %1$s on file \"%2$s\"?" +msgstr "Är du säker pÃ¥ att du vill starta %1$s med filen â€%2$sâ€?" -#: lib/index.tcl:298 +#: lib/tools.tcl:96 #, tcl-format -msgid "Unstaging %s from commit" -msgstr "Tar bort %s för incheckningskön" - -#: lib/index.tcl:337 -msgid "Ready to commit." -msgstr "Redo att checka in." +msgid "Are you sure you want to run %s?" +msgstr "Är du säker pÃ¥ att du vill starta %s?" -#: lib/index.tcl:350 +#: lib/tools.tcl:118 #, tcl-format -msgid "Adding %s" -msgstr "Lägger till %s" +msgid "Tool: %s" +msgstr "Verktyg: %s" -#: lib/index.tcl:380 +#: lib/tools.tcl:119 #, tcl-format -msgid "Stage %d untracked files?" -msgstr "Köa %d ospÃ¥rade filer?" +msgid "Running: %s" +msgstr "Exekverar: %s" -#: lib/index.tcl:428 +#: lib/tools.tcl:158 #, tcl-format -msgid "Revert changes in file %s?" -msgstr "Ã…terställ ändringarna i filen %s?" +msgid "Tool completed successfully: %s" +msgstr "Verktyget avslutades framgÃ¥ngsrikt: %s" -#: lib/index.tcl:430 +#: lib/tools.tcl:160 #, tcl-format -msgid "Revert changes in these %i files?" -msgstr "Ã…terställ ändringarna i dessa %i filer?" - -#: lib/index.tcl:438 -msgid "Any unstaged changes will be permanently lost by the revert." -msgstr "" -"Alla oköade ändringar kommer permanent gÃ¥ förlorade vid Ã¥terställningen." - -#: lib/index.tcl:441 -msgid "Do Nothing" -msgstr "Gör ingenting" - -#: lib/index.tcl:459 -msgid "Reverting selected files" -msgstr "Ã…terställer valda filer" +msgid "Tool failed: %s" +msgstr "Verktyget misslyckades: %s" -#: lib/index.tcl:463 +#: lib/transport.tcl:7 #, tcl-format -msgid "Reverting %s" -msgstr "Ã…terställer %s" - -#: lib/encoding.tcl:443 -msgid "Default" -msgstr "Standard" +msgid "Fetching new changes from %s" +msgstr "Hämtar nya ändringar frÃ¥n %s" -#: lib/encoding.tcl:448 +#: lib/transport.tcl:18 #, tcl-format -msgid "System (%s)" -msgstr "Systemets (%s)" - -#: lib/encoding.tcl:459 lib/encoding.tcl:465 -msgid "Other" -msgstr "Annan" +msgid "remote prune %s" +msgstr "fjärrborttagning %s" -#: lib/date.tcl:25 +#: lib/transport.tcl:19 #, tcl-format -msgid "Invalid date from Git: %s" -msgstr "Ogiltigt datum frÃ¥n Git: %s" - -#: lib/database.tcl:42 -msgid "Number of loose objects" -msgstr "Antal lösa objekt" - -#: lib/database.tcl:43 -msgid "Disk space used by loose objects" -msgstr "Diskutrymme använt av lösa objekt" - -#: lib/database.tcl:44 -msgid "Number of packed objects" -msgstr "Antal packade objekt" - -#: lib/database.tcl:45 -msgid "Number of packs" -msgstr "Antal paket" - -#: lib/database.tcl:46 -msgid "Disk space used by packed objects" -msgstr "Diskutrymme använt av packade objekt" +msgid "Pruning tracking branches deleted from %s" +msgstr "Tar bort spÃ¥rande grenar som tagits bort frÃ¥n %s" -#: lib/database.tcl:47 -msgid "Packed objects waiting for pruning" -msgstr "Packade objekt som väntar pÃ¥ städning" +#: lib/transport.tcl:25 +msgid "fetch all remotes" +msgstr "hämta alla fjärrarkiv" -#: lib/database.tcl:48 -msgid "Garbage files" -msgstr "Skräpfiler" +#: lib/transport.tcl:26 +msgid "Fetching new changes from all remotes" +msgstr "Hämtar nya ändringar frÃ¥n alla fjärrarkiv" -#: lib/database.tcl:72 -msgid "Compressing the object database" -msgstr "Komprimerar objektdatabasen" +#: lib/transport.tcl:40 +msgid "remote prune all remotes" +msgstr "rensa alla fjärrarkiv" -#: lib/database.tcl:83 -msgid "Verifying the object database with fsck-objects" -msgstr "Verifierar objektdatabasen med fsck-objects" +#: lib/transport.tcl:41 +msgid "Pruning tracking branches deleted from all remotes" +msgstr "Rensar spÃ¥rande grenar som tagits bort, frÃ¥n alla fjärrarkiv" -#: lib/database.tcl:107 +#: lib/transport.tcl:55 #, tcl-format -msgid "" -"This repository currently has approximately %i loose objects.\n" -"\n" -"To maintain optimal performance it is strongly recommended that you compress " -"the database.\n" -"\n" -"Compress the database now?" -msgstr "" -"Arkivet har för närvarande omkring %i lösa objekt.\n" -"\n" -"För att bibehÃ¥lla optimal prestanda rekommenderas det Ã¥ det bestämdaste att " -"du komprimerar databasen.\n" -"\n" -"Komprimera databasen nu?" - -#: lib/error.tcl:20 lib/error.tcl:116 -msgid "error" -msgstr "fel" - -#: lib/error.tcl:36 -msgid "warning" -msgstr "varning" - -#: lib/error.tcl:96 -msgid "You must correct the above errors before committing." -msgstr "Du mÃ¥ste rätta till felen ovan innan du checkar in." +msgid "Pushing changes to %s" +msgstr "Sänder ändringar till %s" -#~ msgid "Displaying only %s of %s files." -#~ msgstr "Visar endast %s av %s filer." +#: lib/transport.tcl:93 +#, tcl-format +msgid "Mirroring to %s" +msgstr "Speglar till %s" -#~ msgid "Case-Sensitive" -#~ msgstr "Skilj pÃ¥ VERSALER/gemener" +#: lib/transport.tcl:111 +#, tcl-format +msgid "Pushing %s %s to %s" +msgstr "Sänder %s %s till %s" -#~ msgid "Cannot use funny .git directory:" -#~ msgstr "Kan inte använda underlig .git-katalog:" +#: lib/transport.tcl:132 +msgid "Push Branches" +msgstr "Sänd grenar" -#~ msgid "Preferences..." -#~ msgstr "Inställningar..." +#: lib/transport.tcl:147 +msgid "Source Branches" +msgstr "Källgrenar" -#~ msgid "Always (Do not perform merge test.)" -#~ msgstr "Alltid (utför inte sammanslagningstest)." +#: lib/transport.tcl:162 +msgid "Destination Repository" +msgstr "Destinationsarkiv" -#~ msgid "URL:" -#~ msgstr "Webbadress:" +#: lib/transport.tcl:205 +msgid "Transfer Options" +msgstr "Överföringsalternativ" -#~ msgid "Delete Remote Branch" -#~ msgstr "Ta bort fjärrgren" +#: lib/transport.tcl:207 +msgid "Force overwrite existing branch (may discard changes)" +msgstr "Tvinga överskrivning av befintlig gren (kan kasta bort ändringar)" -#~ msgid "" -#~ "Unable to start gitk:\n" -#~ "\n" -#~ "%s does not exist" -#~ msgstr "" -#~ "Kan inte starta gitk:\n" -#~ "\n" -#~ "%s finns inte" +#: lib/transport.tcl:211 +msgid "Use thin pack (for slow network connections)" +msgstr "Använd tunt paket (för lÃ¥ngsamma nätverksanslutningar)" -#~ msgid "Apple" -#~ msgstr "Äpple" +#: lib/transport.tcl:215 +msgid "Include tags" +msgstr "Ta med taggar" -#~ msgid "Not connected to aspell" -#~ msgstr "Inte ansluten till aspell" +#: lib/transport.tcl:229 +#, tcl-format +msgid "%s (%s): Push" +msgstr "%s (%s): Sänd" diff --git a/git-send-email.perl b/git-send-email.perl index f0be4b4560..72044e5ef3 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1847,9 +1847,9 @@ sub pre_process_file { $what, $_) unless $quiet; next; } - push @cc, $c; + push @cc, $sc; printf(__("(body) Adding cc: %s from line '%s'\n"), - $c, $_) unless $quiet; + $sc, $_) unless $quiet; } } close $fh; @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "builtin.h" #include "config.h" #include "environment.h" @@ -594,6 +596,7 @@ static struct cmd_struct commands[] = { { "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE }, { "receive-pack", cmd_receive_pack }, { "reflog", cmd_reflog, RUN_SETUP }, + { "refs", cmd_refs, RUN_SETUP }, { "remote", cmd_remote, RUN_SETUP }, { "remote-ext", cmd_remote_ext, NO_PARSEOPT }, { "remote-fd", cmd_remote_fd, NO_PARSEOPT }, diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ccd14e0e30..b09a8d0523 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -8326,10 +8326,10 @@ XML my %co = %{$commitlist[$i]}; my $commit = $co{'id'}; # we read 150, we always show 30 and the ones more recent than 48 hours - if (($i >= 20) && ((time - $co{'author_epoch'}) > 48*60*60)) { + if (($i >= 20) && ((time - $co{'committer_epoch'}) > 48*60*60)) { last; } - my %cd = parse_date($co{'author_epoch'}, $co{'author_tz'}); + my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'}); # get list of changed files open my $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, diff --git a/gpg-interface.c b/gpg-interface.c index 5193223714..5c824aeb25 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -34,7 +34,7 @@ static enum signature_trust_level configured_min_trust_level = TRUST_UNDEFINED; struct gpg_format { const char *name; - char *program; + const char *program; const char **verify_args; const char **sigs; int (*verify_signed_buffer)(struct signature_check *sigc, @@ -727,7 +727,7 @@ static int git_gpg_config(const char *var, const char *value, void *cb UNUSED) { struct gpg_format *fmt = NULL; - char *fmtname = NULL; + const char *fmtname = NULL; char *trust; int ret; @@ -783,7 +783,7 @@ static int git_gpg_config(const char *var, const char *value, if (fmtname) { fmt = get_format_by_name(fmtname); - return git_config_string(&fmt->program, var, value); + return git_config_string((char **) &fmt->program, var, value); } return 0; @@ -1735,7 +1735,8 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle peek_eol = end_of_line(peek_bol, &peek_left); } - if (match_funcname(opt, gs, peek_bol, peek_eol)) + if (peek_bol >= gs->buf + gs->size || + match_funcname(opt, gs, peek_bol, peek_eol)) show_function = 0; } if (show_function || diff --git a/hash-ll.h b/hash-ll.h deleted file mode 100644 index 2cfde63ae1..0000000000 --- a/hash-ll.h +++ /dev/null @@ -1,310 +0,0 @@ -#ifndef HASH_LL_H -#define HASH_LL_H - -#if defined(SHA1_APPLE) -#include <CommonCrypto/CommonDigest.h> -#elif defined(SHA1_OPENSSL) -# include <openssl/sha.h> -# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3 -# define SHA1_NEEDS_CLONE_HELPER -# include "sha1/openssl.h" -# endif -#elif defined(SHA1_DC) -#include "sha1dc_git.h" -#else /* SHA1_BLK */ -#include "block-sha1/sha1.h" -#endif - -#if defined(SHA256_NETTLE) -#include "sha256/nettle.h" -#elif defined(SHA256_GCRYPT) -#define SHA256_NEEDS_CLONE_HELPER -#include "sha256/gcrypt.h" -#elif defined(SHA256_OPENSSL) -# include <openssl/sha.h> -# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3 -# define SHA256_NEEDS_CLONE_HELPER -# include "sha256/openssl.h" -# endif -#else -#include "sha256/block/sha256.h" -#endif - -#ifndef platform_SHA_CTX -/* - * platform's underlying implementation of SHA-1; could be OpenSSL, - * blk_SHA, Apple CommonCrypto, etc... Note that the relevant - * SHA-1 header may have already defined platform_SHA_CTX for our - * own implementations like block-sha1, so we list - * the default for OpenSSL compatible SHA-1 implementations here. - */ -#define platform_SHA_CTX SHA_CTX -#define platform_SHA1_Init SHA1_Init -#define platform_SHA1_Update SHA1_Update -#define platform_SHA1_Final SHA1_Final -#endif - -#define git_SHA_CTX platform_SHA_CTX -#define git_SHA1_Init platform_SHA1_Init -#define git_SHA1_Update platform_SHA1_Update -#define git_SHA1_Final platform_SHA1_Final - -#ifdef platform_SHA1_Clone -#define git_SHA1_Clone platform_SHA1_Clone -#endif - -#ifndef platform_SHA256_CTX -#define platform_SHA256_CTX SHA256_CTX -#define platform_SHA256_Init SHA256_Init -#define platform_SHA256_Update SHA256_Update -#define platform_SHA256_Final SHA256_Final -#endif - -#define git_SHA256_CTX platform_SHA256_CTX -#define git_SHA256_Init platform_SHA256_Init -#define git_SHA256_Update platform_SHA256_Update -#define git_SHA256_Final platform_SHA256_Final - -#ifdef platform_SHA256_Clone -#define git_SHA256_Clone platform_SHA256_Clone -#endif - -#ifdef SHA1_MAX_BLOCK_SIZE -#include "compat/sha1-chunked.h" -#undef git_SHA1_Update -#define git_SHA1_Update git_SHA1_Update_Chunked -#endif - -#ifndef SHA1_NEEDS_CLONE_HELPER -static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src) -{ - memcpy(dst, src, sizeof(*dst)); -} -#endif - -#ifndef SHA256_NEEDS_CLONE_HELPER -static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src) -{ - memcpy(dst, src, sizeof(*dst)); -} -#endif - -/* - * Note that these constants are suitable for indexing the hash_algos array and - * comparing against each other, but are otherwise arbitrary, so they should not - * be exposed to the user or serialized to disk. To know whether a - * git_hash_algo struct points to some usable hash function, test the format_id - * field for being non-zero. Use the name field for user-visible situations and - * the format_id field for fixed-length fields on disk. - */ -/* An unknown hash function. */ -#define GIT_HASH_UNKNOWN 0 -/* SHA-1 */ -#define GIT_HASH_SHA1 1 -/* SHA-256 */ -#define GIT_HASH_SHA256 2 -/* Number of algorithms supported (including unknown). */ -#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1) - -/* "sha1", big-endian */ -#define GIT_SHA1_FORMAT_ID 0x73686131 - -/* The length in bytes and in hex digits of an object name (SHA-1 value). */ -#define GIT_SHA1_RAWSZ 20 -#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ) -/* The block size of SHA-1. */ -#define GIT_SHA1_BLKSZ 64 - -/* "s256", big-endian */ -#define GIT_SHA256_FORMAT_ID 0x73323536 - -/* The length in bytes and in hex digits of an object name (SHA-256 value). */ -#define GIT_SHA256_RAWSZ 32 -#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ) -/* The block size of SHA-256. */ -#define GIT_SHA256_BLKSZ 64 - -/* The length in byte and in hex digits of the largest possible hash value. */ -#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ -#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ -/* The largest possible block size for any supported hash. */ -#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ - -struct object_id { - unsigned char hash[GIT_MAX_RAWSZ]; - int algo; /* XXX requires 4-byte alignment */ -}; - -#define GET_OID_QUIETLY 01 -#define GET_OID_COMMIT 02 -#define GET_OID_COMMITTISH 04 -#define GET_OID_TREE 010 -#define GET_OID_TREEISH 020 -#define GET_OID_BLOB 040 -#define GET_OID_FOLLOW_SYMLINKS 0100 -#define GET_OID_RECORD_PATH 0200 -#define GET_OID_ONLY_TO_DIE 04000 -#define GET_OID_REQUIRE_PATH 010000 -#define GET_OID_HASH_ANY 020000 - -#define GET_OID_DISAMBIGUATORS \ - (GET_OID_COMMIT | GET_OID_COMMITTISH | \ - GET_OID_TREE | GET_OID_TREEISH | \ - GET_OID_BLOB) - -enum get_oid_result { - FOUND = 0, - MISSING_OBJECT = -1, /* The requested object is missing */ - SHORT_NAME_AMBIGUOUS = -2, - /* The following only apply when symlinks are followed */ - DANGLING_SYMLINK = -4, /* - * The initial symlink is there, but - * (transitively) points to a missing - * in-tree file - */ - SYMLINK_LOOP = -5, - NOT_DIR = -6, /* - * Somewhere along the symlink chain, a path is - * requested which contains a file as a - * non-final element. - */ -}; - -/* A suitably aligned type for stack allocations of hash contexts. */ -union git_hash_ctx { - git_SHA_CTX sha1; - git_SHA256_CTX sha256; -}; -typedef union git_hash_ctx git_hash_ctx; - -typedef void (*git_hash_init_fn)(git_hash_ctx *ctx); -typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src); -typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len); -typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx); -typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx); - -struct git_hash_algo { - /* - * The name of the algorithm, as appears in the config file and in - * messages. - */ - const char *name; - - /* A four-byte version identifier, used in pack indices. */ - uint32_t format_id; - - /* The length of the hash in binary. */ - size_t rawsz; - - /* The length of the hash in hex characters. */ - size_t hexsz; - - /* The block size of the hash. */ - size_t blksz; - - /* The hash initialization function. */ - git_hash_init_fn init_fn; - - /* The hash context cloning function. */ - git_hash_clone_fn clone_fn; - - /* The hash update function. */ - git_hash_update_fn update_fn; - - /* The hash finalization function. */ - git_hash_final_fn final_fn; - - /* The hash finalization function for object IDs. */ - git_hash_final_oid_fn final_oid_fn; - - /* The OID of the empty tree. */ - const struct object_id *empty_tree; - - /* The OID of the empty blob. */ - const struct object_id *empty_blob; - - /* The all-zeros OID. */ - const struct object_id *null_oid; -}; -extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS]; - -/* - * Return a GIT_HASH_* constant based on the name. Returns GIT_HASH_UNKNOWN if - * the name doesn't match a known algorithm. - */ -int hash_algo_by_name(const char *name); -/* Identical, except based on the format ID. */ -int hash_algo_by_id(uint32_t format_id); -/* Identical, except based on the length. */ -int hash_algo_by_length(int len); -/* Identical, except for a pointer to struct git_hash_algo. */ -static inline int hash_algo_by_ptr(const struct git_hash_algo *p) -{ - return p - hash_algos; -} - -const struct object_id *null_oid(void); - -static inline int hashcmp_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop) -{ - /* - * Teach the compiler that there are only two possibilities of hash size - * here, so that it can optimize for this case as much as possible. - */ - if (algop->rawsz == GIT_MAX_RAWSZ) - return memcmp(sha1, sha2, GIT_MAX_RAWSZ); - return memcmp(sha1, sha2, GIT_SHA1_RAWSZ); -} - -static inline int hasheq_algop(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop) -{ - /* - * We write this here instead of deferring to hashcmp so that the - * compiler can properly inline it and avoid calling memcmp. - */ - if (algop->rawsz == GIT_MAX_RAWSZ) - return !memcmp(sha1, sha2, GIT_MAX_RAWSZ); - return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ); -} - -static inline void oidcpy(struct object_id *dst, const struct object_id *src) -{ - memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ); - dst->algo = src->algo; -} - -static inline struct object_id *oiddup(const struct object_id *src) -{ - struct object_id *dst = xmalloc(sizeof(struct object_id)); - oidcpy(dst, src); - return dst; -} - -static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop) -{ - oid->algo = hash_algo_by_ptr(algop); -} - -/* - * Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code - * for use in hash tables. Cryptographic hashes are supposed to have - * uniform distribution, so in contrast to `memhash()`, this just copies - * the first `sizeof(int)` bytes without shuffling any bits. Note that - * the results will be different on big-endian and little-endian - * platforms, so they should not be stored or transferred over the net. - */ -static inline unsigned int oidhash(const struct object_id *oid) -{ - /* - * Equivalent to 'return *(unsigned int *)oid->hash;', but safe on - * platforms that don't support unaligned reads. - */ - unsigned int hash; - memcpy(&hash, oid->hash, sizeof(hash)); - return hash; -} - -const char *empty_tree_oid_hex(void); -const char *empty_blob_oid_hex(void); - -#endif diff --git a/hash-lookup.c b/hash-lookup.c index 9f0f95e2b9..5f808caa51 100644 --- a/hash-lookup.c +++ b/hash-lookup.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "hash.h" #include "hash-lookup.h" @@ -112,7 +114,8 @@ int bsearch_hash(const unsigned char *hash, const uint32_t *fanout_nbo, while (lo < hi) { unsigned mi = lo + (hi - lo) / 2; - int cmp = hashcmp(table + mi * stride, hash); + int cmp = hashcmp(table + mi * stride, hash, + the_repository->hash_algo); if (!cmp) { if (result) @@ -1,107 +1,369 @@ #ifndef HASH_H #define HASH_H -#include "hash-ll.h" -#include "repository.h" +#if defined(SHA1_APPLE) +#include <CommonCrypto/CommonDigest.h> +#elif defined(SHA1_OPENSSL) +# include <openssl/sha.h> +# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3 +# define SHA1_NEEDS_CLONE_HELPER +# include "sha1/openssl.h" +# endif +#elif defined(SHA1_DC) +#include "sha1dc_git.h" +#else /* SHA1_BLK */ +#include "block-sha1/sha1.h" +#endif + +#if defined(SHA256_NETTLE) +#include "sha256/nettle.h" +#elif defined(SHA256_GCRYPT) +#define SHA256_NEEDS_CLONE_HELPER +#include "sha256/gcrypt.h" +#elif defined(SHA256_OPENSSL) +# include <openssl/sha.h> +# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3 +# define SHA256_NEEDS_CLONE_HELPER +# include "sha256/openssl.h" +# endif +#else +#include "sha256/block/sha256.h" +#endif + +#ifndef platform_SHA_CTX +/* + * platform's underlying implementation of SHA-1; could be OpenSSL, + * blk_SHA, Apple CommonCrypto, etc... Note that the relevant + * SHA-1 header may have already defined platform_SHA_CTX for our + * own implementations like block-sha1, so we list + * the default for OpenSSL compatible SHA-1 implementations here. + */ +#define platform_SHA_CTX SHA_CTX +#define platform_SHA1_Init SHA1_Init +#define platform_SHA1_Update SHA1_Update +#define platform_SHA1_Final SHA1_Final +#endif + +#define git_SHA_CTX platform_SHA_CTX +#define git_SHA1_Init platform_SHA1_Init +#define git_SHA1_Update platform_SHA1_Update +#define git_SHA1_Final platform_SHA1_Final + +#ifdef platform_SHA1_Clone +#define git_SHA1_Clone platform_SHA1_Clone +#endif -#define the_hash_algo the_repository->hash_algo +#ifndef platform_SHA256_CTX +#define platform_SHA256_CTX SHA256_CTX +#define platform_SHA256_Init SHA256_Init +#define platform_SHA256_Update SHA256_Update +#define platform_SHA256_Final SHA256_Final +#endif + +#define git_SHA256_CTX platform_SHA256_CTX +#define git_SHA256_Init platform_SHA256_Init +#define git_SHA256_Update platform_SHA256_Update +#define git_SHA256_Final platform_SHA256_Final + +#ifdef platform_SHA256_Clone +#define git_SHA256_Clone platform_SHA256_Clone +#endif -static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2) +#ifdef SHA1_MAX_BLOCK_SIZE +#include "compat/sha1-chunked.h" +#undef git_SHA1_Update +#define git_SHA1_Update git_SHA1_Update_Chunked +#endif + +#ifndef SHA1_NEEDS_CLONE_HELPER +static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src) { - return hashcmp_algop(sha1, sha2, the_hash_algo); + memcpy(dst, src, sizeof(*dst)); } +#endif -static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2) +#ifndef SHA256_NEEDS_CLONE_HELPER +static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src) +{ + memcpy(dst, src, sizeof(*dst)); +} +#endif + +/* + * Note that these constants are suitable for indexing the hash_algos array and + * comparing against each other, but are otherwise arbitrary, so they should not + * be exposed to the user or serialized to disk. To know whether a + * git_hash_algo struct points to some usable hash function, test the format_id + * field for being non-zero. Use the name field for user-visible situations and + * the format_id field for fixed-length fields on disk. + */ +/* An unknown hash function. */ +#define GIT_HASH_UNKNOWN 0 +/* SHA-1 */ +#define GIT_HASH_SHA1 1 +/* SHA-256 */ +#define GIT_HASH_SHA256 2 +/* Number of algorithms supported (including unknown). */ +#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1) + +/* "sha1", big-endian */ +#define GIT_SHA1_FORMAT_ID 0x73686131 + +/* The length in bytes and in hex digits of an object name (SHA-1 value). */ +#define GIT_SHA1_RAWSZ 20 +#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ) +/* The block size of SHA-1. */ +#define GIT_SHA1_BLKSZ 64 + +/* "s256", big-endian */ +#define GIT_SHA256_FORMAT_ID 0x73323536 + +/* The length in bytes and in hex digits of an object name (SHA-256 value). */ +#define GIT_SHA256_RAWSZ 32 +#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ) +/* The block size of SHA-256. */ +#define GIT_SHA256_BLKSZ 64 + +/* The length in byte and in hex digits of the largest possible hash value. */ +#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ +#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ +/* The largest possible block size for any supported hash. */ +#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ + +struct object_id { + unsigned char hash[GIT_MAX_RAWSZ]; + int algo; /* XXX requires 4-byte alignment */ +}; + +#define GET_OID_QUIETLY 01 +#define GET_OID_COMMIT 02 +#define GET_OID_COMMITTISH 04 +#define GET_OID_TREE 010 +#define GET_OID_TREEISH 020 +#define GET_OID_BLOB 040 +#define GET_OID_FOLLOW_SYMLINKS 0100 +#define GET_OID_RECORD_PATH 0200 +#define GET_OID_ONLY_TO_DIE 04000 +#define GET_OID_REQUIRE_PATH 010000 +#define GET_OID_HASH_ANY 020000 + +#define GET_OID_DISAMBIGUATORS \ + (GET_OID_COMMIT | GET_OID_COMMITTISH | \ + GET_OID_TREE | GET_OID_TREEISH | \ + GET_OID_BLOB) + +enum get_oid_result { + FOUND = 0, + MISSING_OBJECT = -1, /* The requested object is missing */ + SHORT_NAME_AMBIGUOUS = -2, + /* The following only apply when symlinks are followed */ + DANGLING_SYMLINK = -4, /* + * The initial symlink is there, but + * (transitively) points to a missing + * in-tree file + */ + SYMLINK_LOOP = -5, + NOT_DIR = -6, /* + * Somewhere along the symlink chain, a path is + * requested which contains a file as a + * non-final element. + */ +}; + +#ifdef USE_THE_REPOSITORY_VARIABLE +# include "repository.h" +# define the_hash_algo the_repository->hash_algo +#endif + +/* A suitably aligned type for stack allocations of hash contexts. */ +union git_hash_ctx { + git_SHA_CTX sha1; + git_SHA256_CTX sha256; +}; +typedef union git_hash_ctx git_hash_ctx; + +typedef void (*git_hash_init_fn)(git_hash_ctx *ctx); +typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src); +typedef void (*git_hash_update_fn)(git_hash_ctx *ctx, const void *in, size_t len); +typedef void (*git_hash_final_fn)(unsigned char *hash, git_hash_ctx *ctx); +typedef void (*git_hash_final_oid_fn)(struct object_id *oid, git_hash_ctx *ctx); + +struct git_hash_algo { + /* + * The name of the algorithm, as appears in the config file and in + * messages. + */ + const char *name; + + /* A four-byte version identifier, used in pack indices. */ + uint32_t format_id; + + /* The length of the hash in binary. */ + size_t rawsz; + + /* The length of the hash in hex characters. */ + size_t hexsz; + + /* The block size of the hash. */ + size_t blksz; + + /* The hash initialization function. */ + git_hash_init_fn init_fn; + + /* The hash context cloning function. */ + git_hash_clone_fn clone_fn; + + /* The hash update function. */ + git_hash_update_fn update_fn; + + /* The hash finalization function. */ + git_hash_final_fn final_fn; + + /* The hash finalization function for object IDs. */ + git_hash_final_oid_fn final_oid_fn; + + /* The OID of the empty tree. */ + const struct object_id *empty_tree; + + /* The OID of the empty blob. */ + const struct object_id *empty_blob; + + /* The all-zeros OID. */ + const struct object_id *null_oid; +}; +extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS]; + +/* + * Return a GIT_HASH_* constant based on the name. Returns GIT_HASH_UNKNOWN if + * the name doesn't match a known algorithm. + */ +int hash_algo_by_name(const char *name); +/* Identical, except based on the format ID. */ +int hash_algo_by_id(uint32_t format_id); +/* Identical, except based on the length. */ +int hash_algo_by_length(int len); +/* Identical, except for a pointer to struct git_hash_algo. */ +static inline int hash_algo_by_ptr(const struct git_hash_algo *p) { - const struct git_hash_algo *algop; - if (!oid1->algo) - algop = the_hash_algo; - else - algop = &hash_algos[oid1->algo]; - return hashcmp_algop(oid1->hash, oid2->hash, algop); + return p - hash_algos; } -static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2) +const struct object_id *null_oid(void); + +static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop) { - return hasheq_algop(sha1, sha2, the_hash_algo); + /* + * Teach the compiler that there are only two possibilities of hash size + * here, so that it can optimize for this case as much as possible. + */ + if (algop->rawsz == GIT_MAX_RAWSZ) + return memcmp(sha1, sha2, GIT_MAX_RAWSZ); + return memcmp(sha1, sha2, GIT_SHA1_RAWSZ); } -static inline int oideq(const struct object_id *oid1, const struct object_id *oid2) +static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2, const struct git_hash_algo *algop) { - const struct git_hash_algo *algop; - if (!oid1->algo) - algop = the_hash_algo; - else - algop = &hash_algos[oid1->algo]; - return hasheq_algop(oid1->hash, oid2->hash, algop); + /* + * We write this here instead of deferring to hashcmp so that the + * compiler can properly inline it and avoid calling memcmp. + */ + if (algop->rawsz == GIT_MAX_RAWSZ) + return !memcmp(sha1, sha2, GIT_MAX_RAWSZ); + return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ); } -static inline int is_null_oid(const struct object_id *oid) +static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src, + const struct git_hash_algo *algop) { - return oideq(oid, null_oid()); + memcpy(sha_dst, sha_src, algop->rawsz); } -static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src) +static inline void hashclr(unsigned char *hash, const struct git_hash_algo *algop) { - memcpy(sha_dst, sha_src, the_hash_algo->rawsz); + memset(hash, 0, algop->rawsz); } -/* Like oidcpy() but zero-pads the unused bytes in dst's hash array. */ -static inline void oidcpy_with_padding(struct object_id *dst, - const struct object_id *src) +static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2) { - size_t hashsz; + return memcmp(oid1->hash, oid2->hash, GIT_MAX_RAWSZ); +} - if (!src->algo) - hashsz = the_hash_algo->rawsz; - else - hashsz = hash_algos[src->algo].rawsz; +static inline int oideq(const struct object_id *oid1, const struct object_id *oid2) +{ + return !memcmp(oid1->hash, oid2->hash, GIT_MAX_RAWSZ); +} - memcpy(dst->hash, src->hash, hashsz); - memset(dst->hash + hashsz, 0, GIT_MAX_RAWSZ - hashsz); +static inline void oidcpy(struct object_id *dst, const struct object_id *src) +{ + memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ); dst->algo = src->algo; } -static inline void hashclr(unsigned char *hash) +static inline void oidread(struct object_id *oid, const unsigned char *hash, + const struct git_hash_algo *algop) { - memset(hash, 0, the_hash_algo->rawsz); + memcpy(oid->hash, hash, algop->rawsz); + if (algop->rawsz < GIT_MAX_RAWSZ) + memset(oid->hash + algop->rawsz, 0, GIT_MAX_RAWSZ - algop->rawsz); + oid->algo = hash_algo_by_ptr(algop); } -static inline void oidclr(struct object_id *oid) +static inline void oidclr(struct object_id *oid, + const struct git_hash_algo *algop) { memset(oid->hash, 0, GIT_MAX_RAWSZ); - oid->algo = hash_algo_by_ptr(the_hash_algo); + oid->algo = hash_algo_by_ptr(algop); } -static inline void oidread_algop(struct object_id *oid, const unsigned char *hash, const struct git_hash_algo *algop) +static inline struct object_id *oiddup(const struct object_id *src) { - memcpy(oid->hash, hash, algop->rawsz); - oid->algo = hash_algo_by_ptr(algop); + struct object_id *dst = xmalloc(sizeof(struct object_id)); + oidcpy(dst, src); + return dst; } -static inline void oidread(struct object_id *oid, const unsigned char *hash) +static inline void oid_set_algo(struct object_id *oid, const struct git_hash_algo *algop) { - oidread_algop(oid, hash, the_hash_algo); + oid->algo = hash_algo_by_ptr(algop); } -static inline int is_empty_blob_sha1(const unsigned char *sha1) +/* + * Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code + * for use in hash tables. Cryptographic hashes are supposed to have + * uniform distribution, so in contrast to `memhash()`, this just copies + * the first `sizeof(int)` bytes without shuffling any bits. Note that + * the results will be different on big-endian and little-endian + * platforms, so they should not be stored or transferred over the net. + */ +static inline unsigned int oidhash(const struct object_id *oid) { - return hasheq(sha1, the_hash_algo->empty_blob->hash); + /* + * Equivalent to 'return *(unsigned int *)oid->hash;', but safe on + * platforms that don't support unaligned reads. + */ + unsigned int hash; + memcpy(&hash, oid->hash, sizeof(hash)); + return hash; } -static inline int is_empty_blob_oid(const struct object_id *oid) +static inline int is_null_oid(const struct object_id *oid) { - return oideq(oid, the_hash_algo->empty_blob); + static const unsigned char null_hash[GIT_MAX_RAWSZ]; + return !memcmp(oid->hash, null_hash, GIT_MAX_RAWSZ); } -static inline int is_empty_tree_sha1(const unsigned char *sha1) +const char *empty_tree_oid_hex(const struct git_hash_algo *algop); + +static inline int is_empty_blob_oid(const struct object_id *oid, + const struct git_hash_algo *algop) { - return hasheq(sha1, the_hash_algo->empty_tree->hash); + return oideq(oid, algop->empty_blob); } -static inline int is_empty_tree_oid(const struct object_id *oid) +static inline int is_empty_tree_oid(const struct object_id *oid, + const struct git_hash_algo *algop) { - return oideq(oid, the_hash_algo->empty_tree); + return oideq(oid, algop->empty_tree); } #endif @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "builtin.h" @@ -15,6 +17,10 @@ #include "prompt.h" #include "fsmonitor-ipc.h" +#ifndef NO_CURL +#include "git-curl-compat.h" /* For LIBCURL_VERSION only */ +#endif + struct category_description { uint32_t category; const char *desc; @@ -157,7 +163,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len) cmds->names[cmds->cnt++] = ent; } -static void clean_cmdnames(struct cmdnames *cmds) +void cmdnames_release(struct cmdnames *cmds) { int i; for (i = 0; i < cmds->cnt; ++i) @@ -359,8 +365,8 @@ void list_all_main_cmds(struct string_list *list) for (i = 0; i < main_cmds.cnt; i++) string_list_append(list, main_cmds.names[i]->name); - clean_cmdnames(&main_cmds); - clean_cmdnames(&other_cmds); + cmdnames_release(&main_cmds); + cmdnames_release(&other_cmds); } void list_all_other_cmds(struct string_list *list) @@ -375,8 +381,8 @@ void list_all_other_cmds(struct string_list *list) for (i = 0; i < other_cmds.cnt; i++) string_list_append(list, other_cmds.names[i]->name); - clean_cmdnames(&main_cmds); - clean_cmdnames(&other_cmds); + cmdnames_release(&main_cmds); + cmdnames_release(&other_cmds); } void list_cmds_by_category(struct string_list *list, @@ -689,7 +695,7 @@ const char *help_unknown_cmd(const char *cmd) if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) { const char *assumed = main_cmds.names[0]->name; main_cmds.names[0] = NULL; - clean_cmdnames(&main_cmds); + cmdnames_release(&main_cmds); fprintf_ln(stderr, _("WARNING: You called a Git command named '%s', " "which does not exist."), @@ -757,6 +763,15 @@ void get_version_info(struct strbuf *buf, int show_build_options) if (fsmonitor_ipc__is_supported()) strbuf_addstr(buf, "feature: fsmonitor--daemon\n"); +#if defined LIBCURL_VERSION + strbuf_addf(buf, "libcurl: %s\n", LIBCURL_VERSION); +#endif +#if defined OPENSSL_VERSION_TEXT + strbuf_addf(buf, "OpenSSL: %s\n", OPENSSL_VERSION_TEXT); +#endif +#if defined ZLIB_VERSION + strbuf_addf(buf, "zlib: %s\n", ZLIB_VERSION); +#endif } } @@ -13,6 +13,8 @@ struct cmdnames { } **names; }; +void cmdnames_release(struct cmdnames *cmds); + static inline void mput_char(char c, unsigned int num) { while (num--) @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "hash.h" #include "hex.h" @@ -25,8 +27,12 @@ int get_oid_hex_algop(const char *hex, struct object_id *oid, const struct git_hash_algo *algop) { int ret = get_hash_hex_algop(hex, oid->hash, algop); - if (!ret) + if (!ret) { oid_set_algo(oid, algop); + if (algop->rawsz != GIT_MAX_RAWSZ) + memset(oid->hash + algop->rawsz, 0, + GIT_MAX_RAWSZ - algop->rawsz); + } return ret; } @@ -1,7 +1,7 @@ #ifndef HEX_H #define HEX_H -#include "hash-ll.h" +#include "hash.h" #include "hex-ll.h" /* @@ -13,10 +13,6 @@ * input, so it is safe to pass this function an arbitrary * null-terminated string. */ -int get_hash_hex(const char *hex, unsigned char *hash); -int get_oid_hex(const char *hex, struct object_id *oid); - -/* Like get_oid_hex, but for an arbitrary hash algorithm. */ int get_oid_hex_algop(const char *hex, struct object_id *oid, const struct git_hash_algo *algop); /* @@ -35,7 +31,6 @@ int get_oid_hex_algop(const char *hex, struct object_id *oid, const struct git_h char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, const struct git_hash_algo *); char *oid_to_hex_r(char *out, const struct object_id *oid); char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *); /* static buffer result! */ -char *hash_to_hex(const unsigned char *hash); /* same static buffer */ char *oid_to_hex(const struct object_id *oid); /* same static buffer */ /* @@ -45,13 +40,9 @@ char *oid_to_hex(const struct object_id *oid); /* same static buffer */ * other invalid character. end is only updated on success; otherwise, it is * unmodified. */ -int parse_oid_hex(const char *hex, struct object_id *oid, const char **end); - -/* Like parse_oid_hex, but for an arbitrary hash algorithm. */ int parse_oid_hex_algop(const char *hex, struct object_id *oid, const char **end, const struct git_hash_algo *algo); - /* * These functions work like get_oid_hex and parse_oid_hex, but they will parse * a hex value for any algorithm. The algorithm is detected based on the length @@ -61,4 +52,19 @@ int parse_oid_hex_algop(const char *hex, struct object_id *oid, const char **end int get_oid_hex_any(const char *hex, struct object_id *oid); int parse_oid_hex_any(const char *hex, struct object_id *oid, const char **end); -#endif +#ifdef USE_THE_REPOSITORY_VARIABLE + +/* Like get_oid_hex_algop, but for `the_hash_algo`. */ +int get_hash_hex(const char *hex, unsigned char *hash); +int get_oid_hex(const char *hex, struct object_id *oid); + +/* Like parse_oid_hex_algop, but uses `the_hash_algo`. */ +int parse_oid_hex(const char *hex, struct object_id *oid, const char **end); + +/* + * Same as `hash_to_hex_algop()`, but uses `the_hash_algo`. + */ +char *hash_to_hex(const unsigned char *hash); + +#endif /* USE_THE_REPOSITORY_VARIABLE */ +#endif /* HEX_H */ @@ -86,5 +86,6 @@ int run_hooks(const char *hook_name); * argument. These things will be used as positional arguments to the * hook. This function behaves like the old run_hook_le() API. */ +LAST_ARG_MUST_BE_NULL int run_hooks_l(const char *hook_name, ...); #endif diff --git a/http-backend.c b/http-backend.c index 5b65287ac9..461424972b 100644 --- a/http-backend.c +++ b/http-backend.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "environment.h" @@ -753,7 +755,7 @@ static int bad_request(struct strbuf *hdr, const struct service_cmd *c) int cmd_main(int argc UNUSED, const char **argv UNUSED) { - char *method = getenv("REQUEST_METHOD"); + const char *method = getenv("REQUEST_METHOD"); const char *proto_header; char *dir; struct service_cmd *cmd = NULL; diff --git a/http-fetch.c b/http-fetch.c index bec94988bb..d460bb1837 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "gettext.h" @@ -127,8 +129,12 @@ int cmd_main(int argc, const char **argv) } else if (skip_prefix(argv[arg], "--packfile=", &p)) { const char *end; + if (nongit) + die(_("not a git repository")); + packfile = 1; - if (parse_oid_hex(p, &packfile_hash, &end) || *end) + if (parse_oid_hex_algop(p, &packfile_hash, &end, + the_repository->hash_algo) || *end) die(_("argument to --packfile must be a valid hash (got '%s')"), p); } else if (skip_prefix(argv[arg], "--index-pack-arg=", &p)) { strvec_push(&index_pack_args, p); diff --git a/http-push.c b/http-push.c index 1fe51226fd..7315a694aa 100644 --- a/http-push.c +++ b/http-push.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "hex.h" @@ -1016,6 +1018,7 @@ static void remote_ls(const char *path, int flags, /* extract hex from sharded "xx/x{38}" filename */ static int get_oid_hex_from_objpath(const char *path, struct object_id *oid) { + memset(oid->hash, 0, GIT_MAX_RAWSZ); oid->algo = hash_algo_by_ptr(the_hash_algo); if (strlen(path) != the_hash_algo->hexsz + 1) @@ -1552,7 +1555,7 @@ static void fetch_symref(const char *path, char **symref, struct object_id *oid) free(url); FREE_AND_NULL(*symref); - oidclr(oid); + oidclr(oid, the_repository->hash_algo); if (buffer.len == 0) return; diff --git a/http-walker.c b/http-walker.c index b395ef1327..e417a7f51c 100644 --- a/http-walker.c +++ b/http-walker.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "repository.h" #include "hex.h" @@ -152,7 +154,7 @@ static void prefetch(struct walker *walker, unsigned char *sha1) newreq = xmalloc(sizeof(*newreq)); newreq->walker = walker; - oidread(&newreq->oid, sha1); + oidread(&newreq->oid, sha1, the_repository->hash_algo); newreq->repo = data->alt; newreq->state = WAITING; newreq->req = NULL; @@ -485,7 +487,7 @@ static int fetch_object(struct walker *walker, unsigned char *hash) list_for_each(pos, head) { obj_req = list_entry(pos, struct object_request, node); - if (hasheq(obj_req->oid.hash, hash)) + if (hasheq(obj_req->oid.hash, hash, the_repository->hash_algo)) break; } if (!obj_req) @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "git-curl-compat.h" #include "hex.h" @@ -106,12 +108,19 @@ static struct { }; #endif +enum proactive_auth { + PROACTIVE_AUTH_NONE = 0, + PROACTIVE_AUTH_IF_CREDENTIALS, + PROACTIVE_AUTH_AUTO, + PROACTIVE_AUTH_BASIC, +}; + static struct credential proxy_auth = CREDENTIAL_INIT; static const char *curl_proxyuserpwd; static char *curl_cookie_file; static int curl_save_cookies; struct credential http_auth = CREDENTIAL_INIT; -static int http_proactive_auth; +static enum proactive_auth http_proactive_auth; static char *user_agent; static int curl_empty_auth = -1; @@ -146,6 +155,12 @@ static int http_schannel_check_revoke = 1; */ static int http_schannel_use_ssl_cainfo; +static int always_auth_proactively(void) +{ + return http_proactive_auth != PROACTIVE_AUTH_NONE && + http_proactive_auth != PROACTIVE_AUTH_IF_CREDENTIALS; +} + size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_) { size_t size = eltsize * nmemb; @@ -537,6 +552,20 @@ static int http_options(const char *var, const char *value, return 0; } + if (!strcmp("http.proactiveauth", var)) { + if (!value) + return config_error_nonbool(var); + if (!strcmp(value, "auto")) + http_proactive_auth = PROACTIVE_AUTH_AUTO; + else if (!strcmp(value, "basic")) + http_proactive_auth = PROACTIVE_AUTH_BASIC; + else if (!strcmp(value, "none")) + http_proactive_auth = PROACTIVE_AUTH_NONE; + else + warning(_("Unknown value for http.proactiveauth")); + return 0; + } + /* Fall back on the default ones */ return git_default_config(var, value, ctx, data); } @@ -578,14 +607,29 @@ static void init_curl_http_auth(CURL *result) { if ((!http_auth.username || !*http_auth.username) && (!http_auth.credential || !*http_auth.credential)) { - if (curl_empty_auth_enabled()) + int empty_auth = curl_empty_auth_enabled(); + if ((empty_auth != -1 && !always_auth_proactively()) || empty_auth == 1) { curl_easy_setopt(result, CURLOPT_USERPWD, ":"); - return; + return; + } else if (!always_auth_proactively()) { + return; + } else if (http_proactive_auth == PROACTIVE_AUTH_BASIC) { + strvec_push(&http_auth.wwwauth_headers, "Basic"); + } } credential_fill(&http_auth, 1); if (http_auth.password) { + if (always_auth_proactively()) { + /* + * We got a credential without an authtype and we don't + * know what's available. Since our only two options at + * the moment are auto (which defaults to basic) and + * basic, use basic for now. + */ + curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + } curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username); curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password); } @@ -1048,7 +1092,7 @@ static CURL *get_curl_handle(void) #endif } - if (http_proactive_auth) + if (http_proactive_auth != PROACTIVE_AUTH_NONE) init_curl_http_auth(result); if (getenv("GIT_SSL_VERSION")) @@ -1183,6 +1227,8 @@ static CURL *get_curl_handle(void) */ curl_easy_setopt(result, CURLOPT_PROXY, ""); } else if (curl_http_proxy) { + struct strbuf proxy = STRBUF_INIT; + if (starts_with(curl_http_proxy, "socks5h")) curl_easy_setopt(result, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME); @@ -1221,7 +1267,27 @@ static CURL *get_curl_handle(void) if (!proxy_auth.host) die("Invalid proxy URL '%s'", curl_http_proxy); - curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host); + strbuf_addstr(&proxy, proxy_auth.host); + if (proxy_auth.path) { + curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW); + + if (ver->version_num < 0x075400) + die("libcurl 7.84 or later is required to support paths in proxy URLs"); + + if (!starts_with(proxy_auth.protocol, "socks")) + die("Invalid proxy URL '%s': only SOCKS proxies support paths", + curl_http_proxy); + + if (strcasecmp(proxy_auth.host, "localhost")) + die("Invalid proxy URL '%s': host must be localhost if a path is present", + curl_http_proxy); + + strbuf_addch(&proxy, '/'); + strbuf_add_percentencode(&proxy, proxy_auth.path, 0); + } + curl_easy_setopt(result, CURLOPT_PROXY, proxy.buf); + strbuf_release(&proxy); + var_override(&curl_no_proxy, getenv("NO_PROXY")); var_override(&curl_no_proxy, getenv("no_proxy")); curl_easy_setopt(result, CURLOPT_NOPROXY, curl_no_proxy); @@ -1292,7 +1358,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth) if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) die("curl_global_init failed"); - http_proactive_auth = proactive_auth; + if (proactive_auth && http_proactive_auth == PROACTIVE_AUTH_NONE) + http_proactive_auth = PROACTIVE_AUTH_IF_CREDENTIALS; if (remote && remote->http_proxy) curl_http_proxy = xstrdup(remote->http_proxy); @@ -1464,7 +1531,16 @@ struct active_request_slot *get_active_slot(void) slot->finished = NULL; slot->callback_data = NULL; slot->callback_func = NULL; + + if (curl_cookie_file && !strcmp(curl_cookie_file, "-")) { + warning(_("refusing to read cookies from http.cookiefile '-'")); + FREE_AND_NULL(curl_cookie_file); + } curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file); + if (curl_save_cookies && (!curl_cookie_file || !curl_cookie_file[0])) { + curl_save_cookies = 0; + warning(_("ignoring http.savecookies for empty http.cookiefile")); + } if (curl_save_cookies) curl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header); @@ -1788,6 +1864,8 @@ static int handle_curl_result(struct slot_results *results) return HTTP_REAUTH; } credential_reject(&http_auth); + if (always_auth_proactively()) + http_proactive_auth = PROACTIVE_AUTH_NONE; return HTTP_NOAUTH; } else { http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE; @@ -1974,7 +2052,7 @@ static void write_accept_language(struct strbuf *buf) /* add '*' */ REALLOC_ARRAY(language_tags, num_langs + 1); - language_tags[num_langs++] = "*"; /* it's OK; this won't be freed */ + language_tags[num_langs++] = xstrdup("*"); /* compute decimal_places */ for (max_q = 1, decimal_places = 0; @@ -2004,8 +2082,7 @@ static void write_accept_language(struct strbuf *buf) } } - /* free language tags -- last one is a static '*' */ - for (i = 0; i < num_langs - 1; i++) + for (i = 0; i < num_langs; i++) free(language_tags[i]); free(language_tags); } @@ -2185,7 +2262,12 @@ static int http_request_reauth(const char *url, struct http_get_options *options) { int i = 3; - int ret = http_request(url, result, target, options); + int ret; + + if (always_auth_proactively()) + credential_fill(&http_auth, 1); + + ret = http_request(url, result, target, options); if (ret != HTTP_OK && ret != HTTP_REAUTH) return ret; @@ -46,9 +46,9 @@ static struct passwd *xgetpwuid_self(int *is_bogus) pw = getpwuid(getuid()); if (!pw) { static struct passwd fallback; - fallback.pw_name = "unknown"; + fallback.pw_name = (char *) "unknown"; #ifndef NO_GECOS_IN_PWENT - fallback.pw_gecos = "Unknown"; + fallback.pw_gecos = (char *) "Unknown"; #endif pw = &fallback; if (is_bogus) diff --git a/imap-send.c b/imap-send.c index a5d1510180..01404e5047 100644 --- a/imap-send.c +++ b/imap-send.c @@ -69,7 +69,6 @@ static void imap_warn(const char *, ...); static char *next_arg(char **); struct imap_server_conf { - const char *name; char *tunnel; char *host; int port; @@ -82,10 +81,6 @@ struct imap_server_conf { char *auth_method; }; -static struct imap_server_conf server = { - .ssl_verify = 1, -}; - struct imap_socket { int fd[2]; SSL *ssl; @@ -110,6 +105,7 @@ struct imap { }; struct imap_store { + const struct imap_server_conf *cfg; /* currently open mailbox */ const char *name; /* foreign! maybe preset? */ int uidvalidity; @@ -194,8 +190,8 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret) #ifdef NO_OPENSSL static int ssl_socket_connect(struct imap_socket *sock UNUSED, - int use_tls_only UNUSED, - int verify UNUSED) + const struct imap_server_conf *cfg, + int use_tls_only UNUSED) { fprintf(stderr, "SSL requested but SSL support not compiled in\n"); return -1; @@ -250,7 +246,9 @@ static int verify_hostname(X509 *cert, const char *hostname) cname, hostname); } -static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify) +static int ssl_socket_connect(struct imap_socket *sock, + const struct imap_server_conf *cfg, + int use_tls_only) { #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) const SSL_METHOD *meth; @@ -279,7 +277,7 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve if (use_tls_only) SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); - if (verify) + if (cfg->ssl_verify) SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); if (!SSL_CTX_set_default_verify_paths(ctx)) { @@ -306,9 +304,9 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve * OpenSSL does not document this function, but the implementation * returns 1 on success, 0 on failure after calling SSLerr(). */ - ret = SSL_set_tlsext_host_name(sock->ssl, server.host); + ret = SSL_set_tlsext_host_name(sock->ssl, cfg->host); if (ret != 1) - warning("SSL_set_tlsext_host_name(%s) failed.", server.host); + warning("SSL_set_tlsext_host_name(%s) failed.", cfg->host); #endif ret = SSL_connect(sock->ssl); @@ -317,12 +315,12 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve return -1; } - if (verify) { + if (cfg->ssl_verify) { /* make sure the hostname matches that of the certificate */ cert = SSL_get_peer_certificate(sock->ssl); if (!cert) return error("unable to get peer certificate."); - if (verify_hostname(cert, server.host) < 0) + if (verify_hostname(cert, cfg->host) < 0) return -1; } @@ -895,7 +893,7 @@ static int auth_cram_md5(struct imap_store *ctx, const char *prompt) int ret; char *response; - response = cram(prompt, server.user, server.pass); + response = cram(prompt, ctx->cfg->user, ctx->cfg->pass); ret = socket_write(&ctx->imap->buf.sock, response, strlen(response)); if (ret != strlen(response)) @@ -935,6 +933,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c CALLOC_ARRAY(ctx, 1); + ctx->cfg = srvc; ctx->imap = CALLOC_ARRAY(imap, 1); imap->buf.sock.fd[0] = imap->buf.sock.fd[1] = -1; imap->in_progress_append = &imap->in_progress; @@ -1035,7 +1034,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c imap->buf.sock.fd[1] = dup(s); if (srvc->use_ssl && - ssl_socket_connect(&imap->buf.sock, 0, srvc->ssl_verify)) { + ssl_socket_connect(&imap->buf.sock, srvc, 0)) { close(s); goto bail; } @@ -1068,8 +1067,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c if (!srvc->use_ssl && CAP(STARTTLS)) { if (imap_exec(ctx, NULL, "STARTTLS") != RESP_OK) goto bail; - if (ssl_socket_connect(&imap->buf.sock, 1, - srvc->ssl_verify)) + if (ssl_socket_connect(&imap->buf.sock, srvc, 1)) goto bail; /* capabilities may have changed, so get the new capabilities */ if (imap_exec(ctx, NULL, "CAPABILITY") != RESP_OK) @@ -1215,9 +1213,9 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg) static void wrap_in_html(struct strbuf *msg) { struct strbuf buf = STRBUF_INIT; - static char *content_type = "Content-Type: text/html;\n"; - static char *pre_open = "<pre>\n"; - static char *pre_close = "</pre>\n"; + static const char *content_type = "Content-Type: text/html;\n"; + static const char *pre_open = "<pre>\n"; + static const char *pre_close = "</pre>\n"; const char *body = strstr(msg->buf, "\n\n"); if (!body) @@ -1299,24 +1297,30 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs) static int git_imap_config(const char *var, const char *val, const struct config_context *ctx, void *cb) { - - if (!strcmp("imap.sslverify", var)) - server.ssl_verify = git_config_bool(var, val); - else if (!strcmp("imap.preformattedhtml", var)) - server.use_html = git_config_bool(var, val); - else if (!strcmp("imap.folder", var)) - return git_config_string(&server.folder, var, val); - else if (!strcmp("imap.user", var)) - return git_config_string(&server.user, var, val); - else if (!strcmp("imap.pass", var)) - return git_config_string(&server.pass, var, val); - else if (!strcmp("imap.tunnel", var)) - return git_config_string(&server.tunnel, var, val); - else if (!strcmp("imap.authmethod", var)) - return git_config_string(&server.auth_method, var, val); - else if (!strcmp("imap.port", var)) - server.port = git_config_int(var, val, ctx->kvi); - else if (!strcmp("imap.host", var)) { + struct imap_server_conf *cfg = cb; + + if (!strcmp("imap.sslverify", var)) { + cfg->ssl_verify = git_config_bool(var, val); + } else if (!strcmp("imap.preformattedhtml", var)) { + cfg->use_html = git_config_bool(var, val); + } else if (!strcmp("imap.folder", var)) { + FREE_AND_NULL(cfg->folder); + return git_config_string(&cfg->folder, var, val); + } else if (!strcmp("imap.user", var)) { + FREE_AND_NULL(cfg->folder); + return git_config_string(&cfg->user, var, val); + } else if (!strcmp("imap.pass", var)) { + FREE_AND_NULL(cfg->folder); + return git_config_string(&cfg->pass, var, val); + } else if (!strcmp("imap.tunnel", var)) { + FREE_AND_NULL(cfg->folder); + return git_config_string(&cfg->tunnel, var, val); + } else if (!strcmp("imap.authmethod", var)) { + FREE_AND_NULL(cfg->folder); + return git_config_string(&cfg->auth_method, var, val); + } else if (!strcmp("imap.port", var)) { + cfg->port = git_config_int(var, val, ctx->kvi); + } else if (!strcmp("imap.host", var)) { if (!val) { return config_error_nonbool(var); } else { @@ -1324,14 +1328,15 @@ static int git_imap_config(const char *var, const char *val, val += 5; else if (starts_with(val, "imaps:")) { val += 6; - server.use_ssl = 1; + cfg->use_ssl = 1; } if (starts_with(val, "//")) val += 2; - server.host = xstrdup(val); + cfg->host = xstrdup(val); } - } else + } else { return git_default_config(var, val, ctx, cb); + } return 0; } @@ -1497,12 +1502,16 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server, int cmd_main(int argc, const char **argv) { + struct imap_server_conf server = { + .ssl_verify = 1, + }; struct strbuf all_msgs = STRBUF_INIT; int total; int nongit_ok; + int ret; setup_git_directory_gently(&nongit_ok); - git_config(git_imap_config, NULL); + git_config(git_imap_config, &server); argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0); @@ -1526,42 +1535,56 @@ int cmd_main(int argc, const char **argv) if (!server.folder) { fprintf(stderr, "no imap store specified\n"); - return 1; + ret = 1; + goto out; } if (!server.host) { if (!server.tunnel) { fprintf(stderr, "no imap host specified\n"); - return 1; + ret = 1; + goto out; } - server.host = "tunnel"; + server.host = xstrdup("tunnel"); } /* read the messages */ if (strbuf_read(&all_msgs, 0, 0) < 0) { error_errno(_("could not read from stdin")); - return 1; + ret = 1; + goto out; } if (all_msgs.len == 0) { fprintf(stderr, "nothing to send\n"); - return 1; + ret = 1; + goto out; } total = count_messages(&all_msgs); if (!total) { fprintf(stderr, "no messages to send\n"); - return 1; + ret = 1; + goto out; } /* write it to the imap server */ if (server.tunnel) - return append_msgs_to_imap(&server, &all_msgs, total); - + ret = append_msgs_to_imap(&server, &all_msgs, total); #ifdef USE_CURL_FOR_IMAP_SEND - if (use_curl) - return curl_append_msgs_to_imap(&server, &all_msgs, total); + else if (use_curl) + ret = curl_append_msgs_to_imap(&server, &all_msgs, total); #endif - - return append_msgs_to_imap(&server, &all_msgs, total); + else + ret = append_msgs_to_imap(&server, &all_msgs, total); + +out: + free(server.tunnel); + free(server.host); + free(server.folder); + free(server.user); + free(server.pass); + free(server.auth_method); + strbuf_release(&all_msgs); + return ret; } diff --git a/json-writer.c b/json-writer.c index 005c820aa4..25b9201f9c 100644 --- a/json-writer.c +++ b/json-writer.c @@ -46,10 +46,7 @@ static void append_quoted_string(struct strbuf *out, const char *in) static void indent_pretty(struct json_writer *jw) { - int k; - - for (k = 0; k < jw->open_stack.len; k++) - strbuf_addstr(&jw->json, " "); + strbuf_addstrings(&jw->json, " ", jw->open_stack.len); } /* diff --git a/line-log.c b/line-log.c index 8ff6ccb772..67c80b39a0 100644 --- a/line-log.c +++ b/line-log.c @@ -899,14 +899,12 @@ static void print_line(const char *prefix, char first, static char *output_prefix(struct diff_options *opt) { - char *prefix = ""; - if (opt->output_prefix) { struct strbuf *sb = opt->output_prefix(opt, opt->output_prefix_data); - prefix = sb->buf; + return sb->buf; + } else { + return xstrdup(""); } - - return prefix; } static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *range) @@ -927,7 +925,7 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang const char *c_context = diff_get_color(opt->use_color, DIFF_CONTEXT); if (!pair || !diff) - return; + goto out; if (pair->one->oid_valid) fill_line_ends(rev->diffopt.repo, pair->one, &p_lines, &p_ends); @@ -1002,8 +1000,10 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang c_context, c_reset, opt->file); } +out: free(p_ends); free(t_ends); + free(prefix); } /* @@ -1012,7 +1012,11 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang */ static void dump_diff_hacky(struct rev_info *rev, struct line_log_data *range) { - fprintf(rev->diffopt.file, "%s\n", output_prefix(&rev->diffopt)); + char *prefix = output_prefix(&rev->diffopt); + + fprintf(rev->diffopt.file, "%s\n", prefix); + free(prefix); + while (range) { dump_diff_hacky_one(rev, range); range = range->next; @@ -1032,6 +1036,7 @@ static int process_diff_filepair(struct rev_info *rev, struct range_set tmp; struct diff_ranges diff; mmfile_t file_parent, file_target; + char *parent_data_to_free = NULL; assert(pair->two->path); while (rg) { @@ -1056,7 +1061,7 @@ static int process_diff_filepair(struct rev_info *rev, file_parent.ptr = pair->one->data; file_parent.size = pair->one->size; } else { - file_parent.ptr = ""; + file_parent.ptr = parent_data_to_free = xstrdup(""); file_parent.size = 0; } @@ -1075,6 +1080,7 @@ static int process_diff_filepair(struct rev_info *rev, diff_ranges_release(&diff); + free(parent_data_to_free); return ((*diff_out)->parent.nr > 0); } diff --git a/line-range.c b/line-range.c index 60f0e5ada8..b99f0d9895 100644 --- a/line-range.c +++ b/line-range.c @@ -234,6 +234,8 @@ static const char *parse_range_funcname( } regfree(®exp); + if (xecfg) + xdiff_clear_find_func(xecfg); free(xecfg); free(pattern); diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c index c5f363ca6f..00611107d2 100644 --- a/list-objects-filter-options.c +++ b/list-objects-filter-options.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "gettext.h" diff --git a/list-objects-filter.c b/list-objects-filter.c index 4346f8da45..dc598a081b 100644 --- a/list-objects-filter.c +++ b/list-objects-filter.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "dir.h" #include "gettext.h" @@ -542,6 +544,8 @@ static void filter_sparse_oid__init( filter->filter_data = d; filter->filter_object_fn = filter_sparse; filter->free_fn = filter_sparse_free; + + object_context_release(&oc); } /* diff --git a/list-objects.c b/list-objects.c index 11ad8be411..985d008799 100644 --- a/list-objects.c +++ b/list-objects.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "tag.h" #include "commit.h" diff --git a/log-tree.c b/log-tree.c index 41416de4e3..576ef30d90 100644 --- a/log-tree.c +++ b/log-tree.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "commit-reach.h" #include "config.h" @@ -673,6 +675,51 @@ static void next_commentary_block(struct rev_info *opt, struct strbuf *sb) opt->shown_dashes = 1; } +static void show_diff_of_diff(struct rev_info *opt) +{ + if (!cmit_fmt_is_mail(opt->commit_format)) + return; + + if (opt->idiff_oid1) { + struct diff_queue_struct dq; + + memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff)); + DIFF_QUEUE_CLEAR(&diff_queued_diff); + + fprintf_ln(opt->diffopt.file, "\n%s", opt->idiff_title); + show_interdiff(opt->idiff_oid1, opt->idiff_oid2, 2, + &opt->diffopt); + + memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff)); + } + + if (opt->rdiff1) { + struct diff_queue_struct dq; + struct diff_options opts; + struct range_diff_options range_diff_opts = { + .creation_factor = opt->creation_factor, + .dual_color = 1, + .diffopt = &opts + }; + + memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff)); + DIFF_QUEUE_CLEAR(&diff_queued_diff); + + fprintf_ln(opt->diffopt.file, "\n%s", opt->rdiff_title); + /* + * Pass minimum required diff-options to range-diff; others + * can be added later if deemed desirable. + */ + repo_diff_setup(the_repository, &opts); + opts.file = opt->diffopt.file; + opts.use_color = opt->diffopt.use_color; + diff_setup_done(&opts); + show_range_diff(opt->rdiff1, opt->rdiff2, &range_diff_opts); + + memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff)); + } +} + void show_log(struct rev_info *opt) { struct strbuf msgbuf = STRBUF_INIT; @@ -856,47 +903,6 @@ void show_log(struct rev_info *opt) strbuf_release(&msgbuf); free(ctx.notes_message); free(ctx.after_subject); - - if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) { - struct diff_queue_struct dq; - - memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff)); - DIFF_QUEUE_CLEAR(&diff_queued_diff); - - next_commentary_block(opt, NULL); - fprintf_ln(opt->diffopt.file, "%s", opt->idiff_title); - show_interdiff(opt->idiff_oid1, opt->idiff_oid2, 2, - &opt->diffopt); - - memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff)); - } - - if (cmit_fmt_is_mail(ctx.fmt) && opt->rdiff1) { - struct diff_queue_struct dq; - struct diff_options opts; - struct range_diff_options range_diff_opts = { - .creation_factor = opt->creation_factor, - .dual_color = 1, - .diffopt = &opts - }; - - memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff)); - DIFF_QUEUE_CLEAR(&diff_queued_diff); - - next_commentary_block(opt, NULL); - fprintf_ln(opt->diffopt.file, "%s", opt->rdiff_title); - /* - * Pass minimum required diff-options to range-diff; others - * can be added later if deemed desirable. - */ - repo_diff_setup(the_repository, &opts); - opts.file = opt->diffopt.file; - opts.use_color = opt->diffopt.use_color; - diff_setup_done(&opts); - show_range_diff(opt->rdiff1, opt->rdiff2, &range_diff_opts); - - memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff)); - } } int log_tree_diff_flush(struct rev_info *opt) @@ -1019,7 +1025,7 @@ static int do_remerge_diff(struct rev_info *opt, struct strbuf parent2_desc = STRBUF_INIT; /* Setup merge options */ - init_merge_options(&o, the_repository); + init_ui_merge_options(&o, the_repository); o.show_rename_progress = 0; o.record_conflict_msgs_as_headers = 1; o.msg_header_prefix = "remerge"; @@ -1047,6 +1053,7 @@ static int do_remerge_diff(struct rev_info *opt, log_tree_diff_flush(opt); /* Cleanup */ + free_commit_list(bases); cleanup_additional_headers(&opt->diffopt); strbuf_release(&parent1_desc); strbuf_release(&parent2_desc); @@ -1165,9 +1172,12 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit) } if (opt->track_linear && !opt->linear && opt->reverse_output_stage) fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar); + if (shown) + show_diff_of_diff(opt); opt->loginfo = NULL; maybe_flush_or_die(opt->diffopt.file, "stdout"); opt->diffopt.no_free = no_free; + diff_free(&opt->diffopt); return shown; } @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "hash.h" #include "path.h" @@ -3,6 +3,8 @@ #include "khash.h" +struct repository; + struct loose_object_map { kh_oid_map_t *to_compat; kh_oid_map_t *to_storage; @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "gettext.h" @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "string-list.h" @@ -199,8 +201,10 @@ static int read_mailmap_blob(struct string_list *map, const char *name) buf = repo_read_object_file(the_repository, &oid, &type, &size); if (!buf) return error("unable to read mailmap object at %s", name); - if (type != OBJ_BLOB) + if (type != OBJ_BLOB) { + free(buf); return error("mailmap is not a blob: %s", name); + } read_mailmap_string(map, buf); @@ -216,7 +220,7 @@ int read_mailmap(struct string_list *map) map->cmp = namemap_cmp; if (!git_mailmap_blob && is_bare_repository()) - git_mailmap_blob = "HEAD:.mailmap"; + git_mailmap_blob = xstrdup("HEAD:.mailmap"); if (!startup_info->have_repository || !is_bare_repository()) err |= read_mailmap_file(map, ".mailmap", diff --git a/match-trees.c b/match-trees.c index 3412b6a140..f17c74d483 100644 --- a/match-trees.c +++ b/match-trees.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "hex.h" #include "match-trees.h" @@ -229,7 +231,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix, oid_to_hex(oid1)); if (*subpath) { struct object_id tree_oid; - oidread(&tree_oid, rewrite_here); + oidread(&tree_oid, rewrite_here, the_repository->hash_algo); status = splice_tree(&tree_oid, subpath, oid2, &subtree); if (status) return status; @@ -237,7 +239,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix, } else { rewrite_with = oid2; } - hashcpy(rewrite_here, rewrite_with->hash); + hashcpy(rewrite_here, rewrite_with->hash, the_repository->hash_algo); status = write_object_file(buf, sz, OBJ_TREE, result); free(buf); return status; diff --git a/mem-pool.h b/mem-pool.h index d1c66413ec..321d86a63c 100644 --- a/mem-pool.h +++ b/mem-pool.h @@ -50,6 +50,7 @@ char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len); /* * Allocate memory from the memory pool and format a string into it. */ +__attribute__((format (printf, 2, 3))) char *mem_pool_strfmt(struct mem_pool *pool, const char *fmt, ...); /* diff --git a/merge-blobs.c b/merge-blobs.c index 2f659fd014..0ad0390fea 100644 --- a/merge-blobs.c +++ b/merge-blobs.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "merge-ll.h" #include "blob.h" diff --git a/merge-ll.c b/merge-ll.c index e29b15fa4a..180c19df67 100644 --- a/merge-ll.c +++ b/merge-ll.c @@ -27,7 +27,7 @@ typedef enum ll_merge_result (*ll_merge_fn)(const struct ll_merge_driver *, struct ll_merge_driver { const char *name; - char *description; + const char *description; ll_merge_fn fn; char *recursive; struct ll_merge_driver *next; @@ -304,8 +304,13 @@ static int read_merge_config(const char *var, const char *value, ll_user_merge_tail = &(fn->next); } - if (!strcmp("name", key)) - return git_config_string(&fn->description, var, value); + if (!strcmp("name", key)) { + /* + * The description is leaking, but that's okay as we want to + * keep around the merge drivers anyway. + */ + return git_config_string((char **) &fn->description, var, value); + } if (!strcmp("driver", key)) { if (!value) diff --git a/merge-ort-wrappers.c b/merge-ort-wrappers.c index 4acedf3c33..d6f6135996 100644 --- a/merge-ort-wrappers.c +++ b/merge-ort-wrappers.c @@ -48,7 +48,7 @@ int merge_ort_nonrecursive(struct merge_options *opt, int merge_ort_recursive(struct merge_options *opt, struct commit *side1, struct commit *side2, - struct commit_list *merge_bases, + const struct commit_list *merge_bases, struct commit **result) { struct tree *head = repo_get_commit_tree(opt->repo, side1); diff --git a/merge-ort-wrappers.h b/merge-ort-wrappers.h index 0c4c57adbb..90af1f69c5 100644 --- a/merge-ort-wrappers.h +++ b/merge-ort-wrappers.h @@ -19,7 +19,7 @@ int merge_ort_nonrecursive(struct merge_options *opt, int merge_ort_recursive(struct merge_options *opt, struct commit *h1, struct commit *h2, - struct commit_list *ancestors, + const struct commit_list *ancestors, struct commit **result); #endif diff --git a/merge-ort.c b/merge-ort.c index eaede6cead..e9d01ac7f7 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -14,6 +14,8 @@ * "cale", "peedy", or "ins" instead of "ort"?) */ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "merge-ort.h" @@ -543,17 +545,35 @@ enum conflict_and_info_types { CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE, CONFLICT_SUBMODULE_MAY_HAVE_REWINDS, CONFLICT_SUBMODULE_NULL_MERGE_BASE, - CONFLICT_SUBMODULE_CORRUPT, + + /* INSERT NEW ENTRIES HERE */ + + /* + * Keep this entry after all regular conflict and info types; only + * errors (failures causing immediate abort of the merge) should + * come after this. + */ + NB_REGULAR_CONFLICT_TYPES, + + /* + * Something is seriously wrong; cannot even perform merge; + * Keep this group _last_ other than NB_TOTAL_TYPES + */ + ERROR_SUBMODULE_CORRUPT, + ERROR_THREEWAY_CONTENT_MERGE_FAILED, + ERROR_OBJECT_WRITE_FAILED, + ERROR_OBJECT_READ_FAILED, + ERROR_OBJECT_NOT_A_BLOB, /* Keep this entry _last_ in the list */ - NB_CONFLICT_TYPES, + NB_TOTAL_TYPES, }; /* * Short description of conflict type, relied upon by external tools. * * We can add more entries, but DO NOT change any of these strings. Also, - * Order MUST match conflict_info_and_types. + * please ensure the order matches what is used in conflict_info_and_types. */ static const char *type_short_descriptions[] = { /*** "Simple" conflicts and informational messages ***/ @@ -597,8 +617,18 @@ static const char *type_short_descriptions[] = { "CONFLICT (submodule may have rewinds)", [CONFLICT_SUBMODULE_NULL_MERGE_BASE] = "CONFLICT (submodule lacks merge base)", - [CONFLICT_SUBMODULE_CORRUPT] = - "CONFLICT (submodule corrupt)" + + /* Something is seriously wrong; cannot even perform merge */ + [ERROR_SUBMODULE_CORRUPT] = + "ERROR (submodule corrupt)", + [ERROR_THREEWAY_CONTENT_MERGE_FAILED] = + "ERROR (three-way content merge failed)", + [ERROR_OBJECT_WRITE_FAILED] = + "ERROR (object write failed)", + [ERROR_OBJECT_READ_FAILED] = + "ERROR (object read failed)", + [ERROR_OBJECT_NOT_A_BLOB] = + "ERROR (object is not a blob)", }; struct logical_conflict_info { @@ -762,7 +792,8 @@ static void path_msg(struct merge_options *opt, /* Sanity checks */ assert(omittable_hint == - !starts_with(type_short_descriptions[type], "CONFLICT") || + (!starts_with(type_short_descriptions[type], "CONFLICT") && + !starts_with(type_short_descriptions[type], "ERROR")) || type == CONFLICT_DIR_RENAME_SUGGESTED); if (opt->record_conflict_msgs_as_headers && omittable_hint) return; /* Do not record mere hints in headers */ @@ -1817,9 +1848,9 @@ static int merge_submodule(struct merge_options *opt, /* check whether both changes are forward */ ret2 = repo_in_merge_bases(&subrepo, commit_o, commit_a); if (ret2 < 0) { - path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0, + path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0, path, NULL, NULL, NULL, - _("Failed to merge submodule %s " + _("error: failed to merge submodule %s " "(repository corrupt)"), path); ret = -1; @@ -1828,9 +1859,9 @@ static int merge_submodule(struct merge_options *opt, if (ret2 > 0) ret2 = repo_in_merge_bases(&subrepo, commit_o, commit_b); if (ret2 < 0) { - path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0, + path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0, path, NULL, NULL, NULL, - _("Failed to merge submodule %s " + _("error: failed to merge submodule %s " "(repository corrupt)"), path); ret = -1; @@ -1848,9 +1879,9 @@ static int merge_submodule(struct merge_options *opt, /* Case #1: a is contained in b or vice versa */ ret2 = repo_in_merge_bases(&subrepo, commit_a, commit_b); if (ret2 < 0) { - path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0, + path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0, path, NULL, NULL, NULL, - _("Failed to merge submodule %s " + _("error: failed to merge submodule %s " "(repository corrupt)"), path); ret = -1; @@ -1867,9 +1898,9 @@ static int merge_submodule(struct merge_options *opt, } ret2 = repo_in_merge_bases(&subrepo, commit_b, commit_a); if (ret2 < 0) { - path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0, + path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0, path, NULL, NULL, NULL, - _("Failed to merge submodule %s " + _("error: failed to merge submodule %s " "(repository corrupt)"), path); ret = -1; @@ -1901,9 +1932,9 @@ static int merge_submodule(struct merge_options *opt, &merges); switch (parent_count) { case -1: - path_msg(opt, CONFLICT_SUBMODULE_CORRUPT, 0, + path_msg(opt, ERROR_SUBMODULE_CORRUPT, 0, path, NULL, NULL, NULL, - _("Failed to merge submodule %s " + _("error: failed to merge submodule %s " "(repository corrupt)"), path); ret = -1; @@ -2109,7 +2140,7 @@ static int handle_content_merge(struct merge_options *opt, * merges, which happens for example with rename/rename(2to1) and * rename/add conflicts. */ - unsigned clean = 1; + int clean = 1; /* * handle_content_merge() needs both files to be of the same type, i.e. @@ -2173,18 +2204,28 @@ static int handle_content_merge(struct merge_options *opt, pathnames, extra_marker_size, &result_buf); - if ((merge_status < 0) || !result_buf.ptr) - ret = error(_("failed to execute internal merge")); + if ((merge_status < 0) || !result_buf.ptr) { + path_msg(opt, ERROR_THREEWAY_CONTENT_MERGE_FAILED, 0, + pathnames[0], pathnames[1], pathnames[2], NULL, + _("error: failed to execute internal merge for %s"), + path); + ret = -1; + } if (!ret && write_object_file(result_buf.ptr, result_buf.size, - OBJ_BLOB, &result->oid)) - ret = error(_("unable to add %s to database"), path); - + OBJ_BLOB, &result->oid)) { + path_msg(opt, ERROR_OBJECT_WRITE_FAILED, 0, + pathnames[0], pathnames[1], pathnames[2], NULL, + _("error: unable to add %s to database"), path); + ret = -1; + } free(result_buf.ptr); + if (ret) return -1; - clean &= (merge_status == 0); + if (merge_status > 0) + clean = 0; path_msg(opt, INFO_AUTO_MERGING, 1, path, NULL, NULL, NULL, _("Auto-merging %s"), path); } else if (S_ISGITLINK(a->mode)) { @@ -2192,6 +2233,8 @@ static int handle_content_merge(struct merge_options *opt, clean = merge_submodule(opt, pathnames[0], two_way ? null_oid() : &o->oid, &a->oid, &b->oid, &result->oid); + if (clean < 0) + return -1; if (opt->priv->call_depth && two_way && !clean) { result->mode = o->mode; oidcpy(&result->oid, &o->oid); @@ -3557,18 +3600,27 @@ static int sort_dirs_next_to_their_children(const char *one, const char *two) return c1 - c2; } -static int read_oid_strbuf(const struct object_id *oid, - struct strbuf *dst) +static int read_oid_strbuf(struct merge_options *opt, + const struct object_id *oid, + struct strbuf *dst, + const char *path) { void *buf; enum object_type type; unsigned long size; buf = repo_read_object_file(the_repository, oid, &type, &size); - if (!buf) - return error(_("cannot read object %s"), oid_to_hex(oid)); + if (!buf) { + path_msg(opt, ERROR_OBJECT_READ_FAILED, 0, + path, NULL, NULL, NULL, + _("error: cannot read object %s"), oid_to_hex(oid)); + return -1; + } if (type != OBJ_BLOB) { free(buf); - return error(_("object %s is not a blob"), oid_to_hex(oid)); + path_msg(opt, ERROR_OBJECT_NOT_A_BLOB, 0, + path, NULL, NULL, NULL, + _("error: object %s is not a blob"), oid_to_hex(oid)); + return -1; } strbuf_attach(dst, buf, size, size + 1); return 0; @@ -3592,8 +3644,8 @@ static int blob_unchanged(struct merge_options *opt, if (oideq(&base->oid, &side->oid)) return 1; - if (read_oid_strbuf(&base->oid, &basebuf) || - read_oid_strbuf(&side->oid, &sidebuf)) + if (read_oid_strbuf(opt, &base->oid, &basebuf, path) || + read_oid_strbuf(opt, &side->oid, &sidebuf, path)) goto error_return; /* * Note: binary | is used so that both renormalizations are @@ -4643,6 +4695,7 @@ void merge_display_update_messages(struct merge_options *opt, struct hashmap_iter iter; struct strmap_entry *e; struct string_list olist = STRING_LIST_INIT_NODUP; + FILE *o = stdout; if (opt->record_conflict_msgs_as_headers) BUG("Either display conflict messages or record them as headers, not both"); @@ -4659,6 +4712,10 @@ void merge_display_update_messages(struct merge_options *opt, } string_list_sort(&olist); + /* Print to stderr if we hit errors rather than just conflicts */ + if (result->clean < 0) + o = stderr; + /* Iterate over the items, printing them */ for (int path_nr = 0; path_nr < olist.nr; ++path_nr) { struct string_list *conflicts = olist.items[path_nr].util; @@ -4666,25 +4723,31 @@ void merge_display_update_messages(struct merge_options *opt, struct logical_conflict_info *info = conflicts->items[i].util; + /* On failure, ignore regular conflict types */ + if (result->clean < 0 && + info->type < NB_REGULAR_CONFLICT_TYPES) + continue; + if (detailed) { - printf("%lu", (unsigned long)info->paths.nr); - putchar('\0'); + fprintf(o, "%lu", (unsigned long)info->paths.nr); + fputc('\0', o); for (int n = 0; n < info->paths.nr; n++) { - fputs(info->paths.v[n], stdout); - putchar('\0'); + fputs(info->paths.v[n], o); + fputc('\0', o); } - fputs(type_short_descriptions[info->type], - stdout); - putchar('\0'); + fputs(type_short_descriptions[info->type], o); + fputc('\0', o); } - puts(conflicts->items[i].string); + fputs(conflicts->items[i].string, o); + fputc('\n', o); if (detailed) - putchar('\0'); + fputc('\0', o); } } string_list_clear(&olist, 0); - print_submodule_conflict_suggestion(&opti->conflicted_submodules); + if (result->clean >= 0) + print_submodule_conflict_suggestion(&opti->conflicted_submodules); /* Also include needed rename limit adjustment now */ diff_warn_rename_limit("merge.renamelimit", @@ -5000,6 +5063,26 @@ static void merge_check_renames_reusable(struct merge_result *result, /*** Function Grouping: merge_incore_*() and their internal variants ***/ +static void move_opt_priv_to_result_priv(struct merge_options *opt, + struct merge_result *result) +{ + /* + * opt->priv and result->priv are a bit weird. opt->priv contains + * information that we can re-use in subsequent merge operations to + * enable our cached renames optimization. The best way to provide + * that to subsequent merges is putting it in result->priv. + * However, putting it directly there would mean retrofitting lots + * of functions in this file to also take a merge_result pointer, + * which is ugly and annoying. So, we just make sure at the end of + * the merge (the outer merge if there are internal recursive ones) + * to move it. + */ + assert(opt->priv && !result->priv); + result->priv = opt->priv; + result->_properly_initialized = RESULT_INITIALIZED; + opt->priv = NULL; +} + /* * Originally from merge_trees_internal(); heavily adapted, though. */ @@ -5030,6 +5113,7 @@ redo: oid_to_hex(&side1->object.oid), oid_to_hex(&side2->object.oid)); result->clean = -1; + move_opt_priv_to_result_priv(opt, result); return; } trace2_region_leave("merge", "collect_merge_info", opt->repo); @@ -5060,22 +5144,20 @@ redo: /* existence of conflicted entries implies unclean */ result->clean &= strmap_empty(&opt->priv->conflicted); } - if (!opt->priv->call_depth) { - result->priv = opt->priv; - result->_properly_initialized = RESULT_INITIALIZED; - opt->priv = NULL; - } + if (!opt->priv->call_depth || result->clean < 0) + move_opt_priv_to_result_priv(opt, result); } /* * Originally from merge_recursive_internal(); somewhat adapted, though. */ static void merge_ort_internal(struct merge_options *opt, - struct commit_list *merge_bases, + const struct commit_list *_merge_bases, struct commit *h1, struct commit *h2, struct merge_result *result) { + struct commit_list *merge_bases = copy_commit_list(_merge_bases); struct commit *next; struct commit *merged_merge_bases; const char *ancestor_name; @@ -5085,7 +5167,7 @@ static void merge_ort_internal(struct merge_options *opt, if (repo_get_merge_bases(the_repository, h1, h2, &merge_bases) < 0) { result->clean = -1; - return; + goto out; } /* See merge-ort.h:merge_incore_recursive() declaration NOTE */ merge_bases = reverse_commit_list(merge_bases); @@ -5129,7 +5211,7 @@ static void merge_ort_internal(struct merge_options *opt, opt->branch2 = "Temporary merge branch 2"; merge_ort_internal(opt, NULL, prev, next, result); if (result->clean < 0) - return; + goto out; opt->branch1 = saved_b1; opt->branch2 = saved_b2; opt->priv->call_depth--; @@ -5152,6 +5234,9 @@ static void merge_ort_internal(struct merge_options *opt, result); strbuf_release(&merge_base_abbrev); opt->ancestor = NULL; /* avoid accidental re-use of opt->ancestor */ + +out: + free_commit_list(merge_bases); } void merge_incore_nonrecursive(struct merge_options *opt, @@ -5181,7 +5266,7 @@ void merge_incore_nonrecursive(struct merge_options *opt, } void merge_incore_recursive(struct merge_options *opt, - struct commit_list *merge_bases, + const struct commit_list *merge_bases, struct commit *side1, struct commit *side2, struct merge_result *result) diff --git a/merge-ort.h b/merge-ort.h index ce56ec1a78..82f2b3222d 100644 --- a/merge-ort.h +++ b/merge-ort.h @@ -2,7 +2,7 @@ #define MERGE_ORT_H #include "merge-recursive.h" -#include "hash-ll.h" +#include "hash.h" struct commit; struct tree; @@ -59,7 +59,7 @@ struct merge_result { * first", 2006-08-09) */ void merge_incore_recursive(struct merge_options *opt, - struct commit_list *merge_bases, + const struct commit_list *merge_bases, struct commit *side1, struct commit *side2, struct merge_result *result); diff --git a/merge-recursive.c b/merge-recursive.c index 8ff29ed09e..ed64a4c537 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -3,6 +3,9 @@ * Fredrik Kuivinen. * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006 */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "merge-recursive.h" @@ -239,7 +242,8 @@ enum rename_type { struct stage_data { struct diff_filespec stages[4]; /* mostly for oid & mode; maybe path */ struct rename_conflict_info *rename_conflict_info; - unsigned processed:1; + unsigned processed:1, + rename_conflict_info_owned:1; }; struct rename { @@ -308,6 +312,7 @@ static inline void setup_rename_conflict_info(enum rename_type rename_type, ci->ren1->dst_entry->processed = 0; ci->ren1->dst_entry->rename_conflict_info = ci; + ci->ren1->dst_entry->rename_conflict_info_owned = 1; if (ren2) { ci->ren2->dst_entry->rename_conflict_info = ci; } @@ -3055,6 +3060,10 @@ static void final_cleanup_rename(struct string_list *rename) for (i = 0; i < rename->nr; i++) { re = rename->items[i].util; diff_free_filepair(re->pair); + if (re->src_entry->rename_conflict_info_owned) + FREE_AND_NULL(re->src_entry->rename_conflict_info); + if (re->dst_entry->rename_conflict_info_owned) + FREE_AND_NULL(re->dst_entry->rename_conflict_info); } string_list_clear(rename, 1); free(rename); @@ -3627,15 +3636,16 @@ static int merge_trees_internal(struct merge_options *opt, static int merge_recursive_internal(struct merge_options *opt, struct commit *h1, struct commit *h2, - struct commit_list *merge_bases, + const struct commit_list *_merge_bases, struct commit **result) { + struct commit_list *merge_bases = copy_commit_list(_merge_bases); struct commit_list *iter; struct commit *merged_merge_bases; struct tree *result_tree; - int clean; const char *ancestor_name; struct strbuf merge_base_abbrev = STRBUF_INIT; + int ret; if (show(opt, 4)) { output(opt, 4, _("Merging:")); @@ -3645,8 +3655,10 @@ static int merge_recursive_internal(struct merge_options *opt, if (!merge_bases) { if (repo_get_merge_bases(the_repository, h1, h2, - &merge_bases) < 0) - return -1; + &merge_bases) < 0) { + ret = -1; + goto out; + } merge_bases = reverse_commit_list(merge_bases); } @@ -3696,14 +3708,18 @@ static int merge_recursive_internal(struct merge_options *opt, opt->branch1 = "Temporary merge branch 1"; opt->branch2 = "Temporary merge branch 2"; if (merge_recursive_internal(opt, merged_merge_bases, iter->item, - NULL, &merged_merge_bases) < 0) - return -1; + NULL, &merged_merge_bases) < 0) { + ret = -1; + goto out; + } opt->branch1 = saved_b1; opt->branch2 = saved_b2; opt->priv->call_depth--; - if (!merged_merge_bases) - return err(opt, _("merge returned no commit")); + if (!merged_merge_bases) { + ret = err(opt, _("merge returned no commit")); + goto out; + } } /* @@ -3720,17 +3736,16 @@ static int merge_recursive_internal(struct merge_options *opt, repo_read_index(opt->repo); opt->ancestor = ancestor_name; - clean = merge_trees_internal(opt, - repo_get_commit_tree(opt->repo, h1), - repo_get_commit_tree(opt->repo, h2), - repo_get_commit_tree(opt->repo, - merged_merge_bases), - &result_tree); - strbuf_release(&merge_base_abbrev); + ret = merge_trees_internal(opt, + repo_get_commit_tree(opt->repo, h1), + repo_get_commit_tree(opt->repo, h2), + repo_get_commit_tree(opt->repo, + merged_merge_bases), + &result_tree); opt->ancestor = NULL; /* avoid accidental re-use of opt->ancestor */ - if (clean < 0) { + if (ret < 0) { flush_output(opt); - return clean; + goto out; } if (opt->priv->call_depth) { @@ -3739,7 +3754,11 @@ static int merge_recursive_internal(struct merge_options *opt, commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); } - return clean; + +out: + strbuf_release(&merge_base_abbrev); + free_commit_list(merge_bases); + return ret; } static int merge_start(struct merge_options *opt, struct tree *head) @@ -3794,6 +3813,9 @@ static void merge_finalize(struct merge_options *opt) if (show(opt, 2)) diff_warn_rename_limit("merge.renamelimit", opt->priv->needed_rename_limit, 0); + hashmap_clear_and_free(&opt->priv->current_file_dir_set, + struct path_hashmap_entry, e); + string_list_clear(&opt->priv->df_conflict_file_set, 0); FREE_AND_NULL(opt->priv); } @@ -3818,7 +3840,7 @@ int merge_trees(struct merge_options *opt, int merge_recursive(struct merge_options *opt, struct commit *h1, struct commit *h2, - struct commit_list *merge_bases, + const struct commit_list *merge_bases, struct commit **result) { int clean; @@ -3860,7 +3882,7 @@ int merge_recursive_generic(struct merge_options *opt, const struct object_id *head, const struct object_id *merge, int num_merge_bases, - const struct object_id **merge_bases, + const struct object_id *merge_bases, struct commit **result) { int clean; @@ -3873,10 +3895,10 @@ int merge_recursive_generic(struct merge_options *opt, int i; for (i = 0; i < num_merge_bases; ++i) { struct commit *base; - if (!(base = get_ref(opt->repo, merge_bases[i], - oid_to_hex(merge_bases[i])))) + if (!(base = get_ref(opt->repo, &merge_bases[i], + oid_to_hex(&merge_bases[i])))) return err(opt, _("Could not parse object '%s'"), - oid_to_hex(merge_bases[i])); + oid_to_hex(&merge_bases[i])); commit_list_insert(base, &ca); } if (num_merge_bases == 1) @@ -3886,6 +3908,7 @@ int merge_recursive_generic(struct merge_options *opt, repo_hold_locked_index(opt->repo, &lock, LOCK_DIE_ON_ERROR); clean = merge_recursive(opt, head_commit, next_commit, ca, result); + free_commit_list(ca); if (clean < 0) { rollback_lock_file(&lock); return clean; @@ -3898,7 +3921,7 @@ int merge_recursive_generic(struct merge_options *opt, return clean ? 0 : 1; } -static void merge_recursive_config(struct merge_options *opt) +static void merge_recursive_config(struct merge_options *opt, int ui) { char *value = NULL; int renormalize = 0; @@ -3927,11 +3950,20 @@ static void merge_recursive_config(struct merge_options *opt) } /* avoid erroring on values from future versions of git */ free(value); } + if (ui) { + if (!git_config_get_string("diff.algorithm", &value)) { + long diff_algorithm = parse_algorithm_value(value); + if (diff_algorithm < 0) + die(_("unknown value for config '%s': %s"), "diff.algorithm", value); + opt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm; + free(value); + } + } git_config(git_xmerge_config, NULL); } -void init_merge_options(struct merge_options *opt, - struct repository *repo) +static void init_merge_options(struct merge_options *opt, + struct repository *repo, int ui) { const char *merge_verbosity; memset(opt, 0, sizeof(struct merge_options)); @@ -3950,7 +3982,7 @@ void init_merge_options(struct merge_options *opt, opt->conflict_style = -1; - merge_recursive_config(opt); + merge_recursive_config(opt, ui); merge_verbosity = getenv("GIT_MERGE_VERBOSITY"); if (merge_verbosity) opt->verbosity = strtol(merge_verbosity, NULL, 10); @@ -3958,6 +3990,18 @@ void init_merge_options(struct merge_options *opt, opt->buffer_output = 0; } +void init_ui_merge_options(struct merge_options *opt, + struct repository *repo) +{ + init_merge_options(opt, repo, 1); +} + +void init_basic_merge_options(struct merge_options *opt, + struct repository *repo) +{ + init_merge_options(opt, repo, 0); +} + /* * For now, members of merge_options do not need deep copying, but * it may change in the future, in which case we would need to update diff --git a/merge-recursive.h b/merge-recursive.h index e67d38c303..0b91f28f90 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -54,7 +54,10 @@ struct merge_options { struct merge_options_internal *priv; }; -void init_merge_options(struct merge_options *opt, struct repository *repo); +/* for use by porcelain commands */ +void init_ui_merge_options(struct merge_options *opt, struct repository *repo); +/* for use by plumbing commands */ +void init_basic_merge_options(struct merge_options *opt, struct repository *repo); void copy_merge_options(struct merge_options *dst, struct merge_options *src); void clear_merge_options(struct merge_options *opt); @@ -104,7 +107,7 @@ int merge_trees(struct merge_options *opt, int merge_recursive(struct merge_options *opt, struct commit *h1, struct commit *h2, - struct commit_list *merge_bases, + const struct commit_list *merge_bases, struct commit **result); /* @@ -123,7 +126,7 @@ int merge_recursive_generic(struct merge_options *opt, const struct object_id *head, const struct object_id *merge, int num_merge_bases, - const struct object_id **merge_bases, + const struct object_id *merge_bases, struct commit **result); #endif @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "hash.h" diff --git a/midx-write.c b/midx-write.c index 55a6b63bac..a77ee73c68 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "config.h" @@ -101,13 +103,27 @@ struct write_midx_context { }; static int should_include_pack(const struct write_midx_context *ctx, - const char *file_name, - int exclude_from_midx) + const char *file_name) { - if (exclude_from_midx && ctx->m && midx_contains_pack(ctx->m, file_name)) + /* + * Note that at most one of ctx->m and ctx->to_include are set, + * so we are testing midx_contains_pack() and + * string_list_has_string() independently (guarded by the + * appropriate NULL checks). + * + * We could support passing to_include while reusing an existing + * MIDX, but don't currently since the reuse process drags + * forward all packs from an existing MIDX (without checking + * whether or not they appear in the to_include list). + * + * If we added support for that, these next two conditional + * should be performed independently (likely checking + * to_include before the existing MIDX). + */ + if (ctx->m && midx_contains_pack(ctx->m, file_name)) return 0; - if (ctx->to_include && !string_list_has_string(ctx->to_include, - file_name)) + else if (ctx->to_include && + !string_list_has_string(ctx->to_include, file_name)) return 0; return 1; } @@ -121,7 +137,7 @@ static void add_pack_to_midx(const char *full_path, size_t full_path_len, if (ends_with(file_name, ".idx")) { display_progress(ctx->progress, ++ctx->pack_paths_checked); - if (!should_include_pack(ctx, file_name, 1)) + if (!should_include_pack(ctx, file_name)) return; ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc); @@ -809,7 +825,7 @@ static int write_midx_bitmap(const char *midx_name, for (i = 0; i < pdata->nr_objects; i++) index[i] = &pdata->objects[i].idx; - bitmap_writer_init(&writer); + bitmap_writer_init(&writer, the_repository); bitmap_writer_show_progress(&writer, flags & MIDX_PROGRESS); bitmap_writer_build_type_index(&writer, pdata, index, pdata->nr_objects); @@ -880,9 +896,6 @@ static int fill_packs_from_midx(struct write_midx_context *ctx, uint32_t i; for (i = 0; i < ctx->m->num_packs; i++) { - if (!should_include_pack(ctx, ctx->m->pack_names[i], 0)) - continue; - ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc); if (flags & MIDX_WRITE_REV_INDEX || preferred_pack_name) { @@ -937,7 +950,15 @@ static int write_midx_internal(const char *object_dir, die_errno(_("unable to create leading directories of %s"), midx_name.buf); - ctx.m = lookup_multi_pack_index(the_repository, object_dir); + if (!packs_to_include) { + /* + * Only reference an existing MIDX when not filtering which + * packs to include, since all packs and objects are copied + * blindly from an existing MIDX if one is present. + */ + ctx.m = lookup_multi_pack_index(the_repository, object_dir); + } + if (ctx.m && !midx_checksum_valid(ctx.m)) { warning(_("ignoring existing multi-pack-index; checksum mismatch")); ctx.m = NULL; @@ -946,7 +967,6 @@ static int write_midx_internal(const char *object_dir, ctx.nr = 0; ctx.alloc = ctx.m ? ctx.m->num_packs : 16; ctx.info = NULL; - ctx.to_include = packs_to_include; ALLOC_ARRAY(ctx.info, ctx.alloc); if (ctx.m && fill_packs_from_midx(&ctx, preferred_pack_name, @@ -963,6 +983,8 @@ static int write_midx_internal(const char *object_dir, else ctx.progress = NULL; + ctx.to_include = packs_to_include; + for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx); stop_progress(&ctx.progress); @@ -1477,8 +1499,7 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, repo_config_get_bool(r, "repack.usedeltabaseoffset", &delta_base_offset); repo_config_get_bool(r, "repack.usedeltaislands", &use_delta_islands); - strvec_pushl(&cmd.args, "pack-objects", "--stdin-packs", "--non-empty", - NULL); + strvec_push(&cmd.args, "pack-objects"); strvec_pushf(&cmd.args, "%s/pack/pack", object_dir); @@ -1502,15 +1523,16 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size, } cmd_in = xfdopen(cmd.in, "w"); - for (i = 0; i < m->num_packs; i++) { - struct packed_git *p = m->packs[i]; - if (!p) + + for (i = 0; i < m->num_objects; i++) { + struct object_id oid; + uint32_t pack_int_id = nth_midxed_pack_int_id(m, i); + + if (!include_pack[pack_int_id]) continue; - if (include_pack[i]) - fprintf(cmd_in, "%s\n", pack_basename(p)); - else - fprintf(cmd_in, "^%s\n", pack_basename(p)); + nth_midxed_object_oid(&oid, m, i); + fprintf(cmd_in, "%s\n", oid_to_hex(&oid)); } fclose(cmd_in); @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "dir.h" @@ -304,7 +306,8 @@ struct object_id *nth_midxed_object_oid(struct object_id *oid, if (n >= m->num_objects) return NULL; - oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n)); + oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n), + the_repository->hash_algo); return oid; } diff --git a/negotiator/default.c b/negotiator/default.c index 518b3c43b2..e3fa5c3324 100644 --- a/negotiator/default.c +++ b/negotiator/default.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "default.h" #include "../commit.h" diff --git a/negotiator/skipping.c b/negotiator/skipping.c index b7e008c2fd..f109928ad0 100644 --- a/negotiator/skipping.c +++ b/negotiator/skipping.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "skipping.h" #include "../commit.h" diff --git a/notes-cache.c b/notes-cache.c index 038db01ca0..ecfdf6e43b 100644 --- a/notes-cache.c +++ b/notes-cache.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "notes-cache.h" #include "object-store-ll.h" diff --git a/notes-merge.c b/notes-merge.c index 6a9a139b12..dadbbabf86 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "advice.h" #include "commit.h" @@ -240,7 +242,7 @@ static void diff_tree_local(struct notes_merge_options *o, * (will be overwritten by following addition) */ if (oideq(&mp->local, &uninitialized)) - oidclr(&mp->local); + oidclr(&mp->local, the_repository->hash_algo); } else if (is_null_oid(&p->one->oid)) { /* addition */ /* * Either this is a true addition (1), or it is part @@ -556,7 +558,7 @@ int notes_merge(struct notes_merge_options *o, assert(o->local_ref && o->remote_ref); assert(!strcmp(o->local_ref, local_tree->ref)); - oidclr(result_oid); + oidclr(result_oid, the_repository->hash_algo); trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n", o->local_ref, o->remote_ref); @@ -579,7 +581,7 @@ int notes_merge(struct notes_merge_options *o, * unborn ref, perform the merge using an empty notes tree. */ if (!check_refname_format(o->remote_ref, 0)) { - oidclr(&remote_oid); + oidclr(&remote_oid, the_repository->hash_algo); remote = NULL; } else { die("Failed to resolve remote notes ref '%s'", @@ -661,6 +663,7 @@ int notes_merge(struct notes_merge_options *o, commit_list_insert(local, &parents); create_notes_commit(o->repo, local_tree, parents, o->commit_msg.buf, o->commit_msg.len, result_oid); + free_commit_list(parents); } found_result: diff --git a/notes-utils.c b/notes-utils.c index e33aa86c4b..ac66b82dd3 100644 --- a/notes-utils.c +++ b/notes-utils.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "commit.h" @@ -9,10 +11,11 @@ void create_notes_commit(struct repository *r, struct notes_tree *t, - struct commit_list *parents, + const struct commit_list *parents, const char *msg, size_t msg_len, struct object_id *result_oid) { + struct commit_list *parents_to_free = NULL; struct object_id tree_oid; assert(t->initialized); @@ -27,7 +30,8 @@ void create_notes_commit(struct repository *r, struct commit *parent = lookup_commit(r, &parent_oid); if (repo_parse_commit(r, parent)) die("Failed to find/parse commit %s", t->ref); - commit_list_insert(parent, &parents); + commit_list_insert(parent, &parents_to_free); + parents = parents_to_free; } /* else: t->ref points to nothing, assume root/orphan commit */ } @@ -35,6 +39,8 @@ void create_notes_commit(struct repository *r, if (commit_tree(msg, msg_len, &tree_oid, parents, result_oid, NULL, NULL)) die("Failed to commit notes tree to database"); + + free_commit_list(parents_to_free); } void commit_notes(struct repository *r, struct notes_tree *t, const char *msg) @@ -187,6 +193,7 @@ void finish_copy_notes_for_rewrite(struct repository *r, for (i = 0; c->trees[i]; i++) { commit_notes(r, c->trees[i], msg); free_notes(c->trees[i]); + free(c->trees[i]); } free(c->trees); free(c); diff --git a/notes-utils.h b/notes-utils.h index d9b3c09eaf..c54b1fe141 100644 --- a/notes-utils.h +++ b/notes-utils.h @@ -20,7 +20,7 @@ struct repository; */ void create_notes_commit(struct repository *r, struct notes_tree *t, - struct commit_list *parents, + const struct commit_list *parents, const char *msg, size_t msg_len, struct object_id *result_oid); @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "environment.h" @@ -149,7 +151,7 @@ static struct leaf_node *note_tree_find(struct notes_tree *t, void **p = note_tree_search(t, &tree, &n, key_sha1); if (GET_PTR_TYPE(*p) == PTR_TYPE_NOTE) { struct leaf_node *l = (struct leaf_node *) CLR_PTR_TYPE(*p); - if (hasheq(key_sha1, l->key_oid.hash)) + if (hasheq(key_sha1, l->key_oid.hash, the_repository->hash_algo)) return l; } return NULL; @@ -353,7 +355,7 @@ static void add_non_note(struct notes_tree *t, char *path, n->next = NULL; n->path = path; n->mode = mode; - oidread(&n->oid, sha1); + oidread(&n->oid, sha1, the_repository->hash_algo); t->prev_non_note = n; if (!t->first_non_note) { @@ -427,6 +429,8 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree, hashsz - prefix_len)) goto handle_non_note; /* entry.path is not a SHA1 */ + memset(object_oid.hash + hashsz, 0, GIT_MAX_RAWSZ - hashsz); + type = PTR_TYPE_NOTE; } else if (path_len == 2) { /* This is potentially an internal node */ @@ -1036,7 +1040,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref, die("Failed to read notes tree referenced by %s (%s)", notes_ref, oid_to_hex(&object_oid)); - oidclr(&root_tree.key_oid); + oidclr(&root_tree.key_oid, the_repository->hash_algo); oidcpy(&root_tree.val_oid, &oid); load_subtree(t, &root_tree, t->root, 0); } @@ -1060,6 +1064,12 @@ void init_display_notes(struct display_notes_opt *opt) { memset(opt, 0, sizeof(*opt)); opt->use_default_notes = -1; + string_list_init_dup(&opt->extra_notes_refs); +} + +void release_display_notes(struct display_notes_opt *opt) +{ + string_list_clear(&opt->extra_notes_refs, 0); } void enable_default_display_notes(struct display_notes_opt *opt, int *show_notes) @@ -1073,19 +1083,15 @@ void enable_ref_display_notes(struct display_notes_opt *opt, int *show_notes, struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, ref); expand_notes_ref(&buf); - string_list_append(&opt->extra_notes_refs, - strbuf_detach(&buf, NULL)); + string_list_append_nodup(&opt->extra_notes_refs, + strbuf_detach(&buf, NULL)); *show_notes = 1; } void disable_display_notes(struct display_notes_opt *opt, int *show_notes) { opt->use_default_notes = -1; - /* we have been strdup'ing ourselves, so trick - * string_list into free()ing strings */ - opt->extra_notes_refs.strdup_strings = 1; string_list_clear(&opt->extra_notes_refs, 0); - opt->extra_notes_refs.strdup_strings = 0; *show_notes = 0; } @@ -1146,8 +1152,8 @@ int remove_note(struct notes_tree *t, const unsigned char *object_sha1) if (!t) t = &default_notes_tree; assert(t->initialized); - oidread(&l.key_oid, object_sha1); - oidclr(&l.val_oid); + oidread(&l.key_oid, object_sha1, the_repository->hash_algo); + oidclr(&l.val_oid, the_repository->hash_algo); note_tree_remove(t, t->root, 0, &l); if (is_null_oid(&l.val_oid)) /* no note was removed */ return 1; @@ -1217,11 +1223,16 @@ void prune_notes(struct notes_tree *t, int flags) for_each_note(t, 0, prune_notes_helper, &l); while (l) { + struct note_delete_list *next; + if (flags & NOTES_PRUNE_VERBOSE) printf("%s\n", hash_to_hex(l->sha1)); if (!(flags & NOTES_PRUNE_DRYRUN)) remove_note(t, l->sha1); - l = l->next; + + next = l->next; + free(l); + l = next; } } @@ -276,6 +276,11 @@ struct display_notes_opt { void init_display_notes(struct display_notes_opt *opt); /* + * Release resources acquired by the display_notes_opt. + */ +void release_display_notes(struct display_notes_opt *opt); + +/* * This family of functions enables or disables the display of notes. In * particular, 'enable_default_display_notes' will display the default notes, * 'enable_ref_display_notes' will display the notes ref 'ref' and diff --git a/object-file-convert.c b/object-file-convert.c index 4f6189095b..3887d6d57b 100644 --- a/object-file-convert.c +++ b/object-file-convert.c @@ -1,9 +1,11 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "strbuf.h" #include "hex.h" #include "repository.h" -#include "hash-ll.h" +#include "hash.h" #include "hash.h" #include "object.h" #include "loose.h" @@ -56,7 +58,7 @@ static int decode_tree_entry_raw(struct object_id *oid, const char **path, return -1; *len = strlen(*path) + 1; - oidread_algop(oid, (const unsigned char *)*path + *len, algo); + oidread(oid, (const unsigned char *)*path + *len, algo); return 0; } diff --git a/object-file.c b/object-file.c index a40300ce4a..065103be3e 100644 --- a/object-file.c +++ b/object-file.c @@ -6,6 +6,9 @@ * This handles basic git object files - packing, unpacking, * creation etc. */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "config.h" @@ -227,16 +230,10 @@ const struct object_id *null_oid(void) return the_hash_algo->null_oid; } -const char *empty_tree_oid_hex(void) -{ - static char buf[GIT_MAX_HEXSZ + 1]; - return oid_to_hex_r(buf, the_hash_algo->empty_tree); -} - -const char *empty_blob_oid_hex(void) +const char *empty_tree_oid_hex(const struct git_hash_algo *algop) { static char buf[GIT_MAX_HEXSZ + 1]; - return oid_to_hex_r(buf, the_hash_algo->empty_blob); + return oid_to_hex_r(buf, algop->empty_tree); } int hash_algo_by_name(const char *name) @@ -277,7 +274,7 @@ int hash_algo_by_length(int len) static struct cached_object { struct object_id oid; enum object_type type; - void *buf; + const void *buf; unsigned long size; } *cached_objects; static int cached_object_nr, cached_object_alloc; @@ -1446,7 +1443,7 @@ static int loose_object_info(struct repository *r, int allow_unknown = flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE; if (oi->delta_base_oid) - oidclr(oi->delta_base_oid); + oidclr(oi->delta_base_oid, the_repository->hash_algo); /* * If we don't care about type or size, then we don't @@ -1580,7 +1577,7 @@ static int do_oid_object_info_extended(struct repository *r, if (oi->disk_sizep) *(oi->disk_sizep) = 0; if (oi->delta_base_oid) - oidclr(oi->delta_base_oid); + oidclr(oi->delta_base_oid, the_repository->hash_algo); if (oi->type_name) strbuf_addstr(oi->type_name, type_name(co->type)); if (oi->contentp) @@ -1711,9 +1708,9 @@ static int oid_object_info_convert(struct repository *r, ret = convert_object_file(&outbuf, the_hash_algo, input_algo, content, size, type, !do_die); + free(content); if (ret == -1) return -1; - free(content); size = outbuf.len; content = strbuf_detach(&outbuf, NULL); } @@ -1778,6 +1775,7 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type, struct object_id *oid) { struct cached_object *co; + char *co_buf; hash_object_file(the_hash_algo, buf, len, type, oid); if (repo_has_object_file_with_flags(the_repository, oid, OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT) || @@ -1787,8 +1785,9 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type, co = &cached_objects[cached_object_nr++]; co->size = len; co->type = type; - co->buf = xmalloc(len); - memcpy(co->buf, buf, len); + co_buf = xmalloc(len); + memcpy(co_buf, buf, len); + co->buf = co_buf; oidcpy(&co->oid, oid); return 0; } @@ -2482,12 +2481,13 @@ static int hash_format_check_report(struct fsck_options *opts UNUSED, } static int index_mem(struct index_state *istate, - struct object_id *oid, void *buf, size_t size, + struct object_id *oid, + const void *buf, size_t size, enum object_type type, const char *path, unsigned flags) { + struct strbuf nbuf = STRBUF_INIT; int ret = 0; - int re_allocated = 0; int write_object = flags & HASH_WRITE_OBJECT; if (!type) @@ -2497,11 +2497,10 @@ static int index_mem(struct index_state *istate, * Convert blobs to git internal format */ if ((type == OBJ_BLOB) && path) { - struct strbuf nbuf = STRBUF_INIT; if (convert_to_git(istate, path, buf, size, &nbuf, get_conv_flags(flags))) { - buf = strbuf_detach(&nbuf, &size); - re_allocated = 1; + buf = nbuf.buf; + size = nbuf.len; } } if (flags & HASH_FORMAT_CHECK) { @@ -2518,8 +2517,8 @@ static int index_mem(struct index_state *istate, ret = write_object_file(buf, size, type, oid); else hash_object_file(the_hash_algo, buf, size, type, oid); - if (re_allocated) - free(buf); + + strbuf_release(&nbuf); return ret; } @@ -2743,6 +2742,8 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr, !hex_to_bytes(oid.hash + 1, de->d_name, the_hash_algo->rawsz - 1)) { oid_set_algo(&oid, the_hash_algo); + memset(oid.hash + the_hash_algo->rawsz, 0, + GIT_MAX_RAWSZ - the_hash_algo->rawsz); if (obj_cb) { r = obj_cb(&oid, path->buf, data); if (r) diff --git a/object-name.c b/object-name.c index 523af6f64f..240a93e7ce 100644 --- a/object-name.c +++ b/object-name.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "object-name.h" #include "advice.h" @@ -25,7 +27,8 @@ #include "date.h" #include "object-file-convert.h" -static int get_oid_oneline(struct repository *r, const char *, struct object_id *, struct commit_list *); +static int get_oid_oneline(struct repository *r, const char *, struct object_id *, + const struct commit_list *); typedef int (*disambiguate_hint_fn)(struct repository *, const struct object_id *, void *); @@ -837,7 +840,7 @@ int repo_find_unique_abbrev_r(struct repository *r, char *hex, } oid_to_hex_r(hex, oid); - if (len == hexsz || !len) + if (len >= hexsz || !len) return hexsz; mad.repo = r; @@ -1252,6 +1255,8 @@ static int peel_onion(struct repository *r, const char *name, int len, prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1)); commit_list_insert((struct commit *)o, &list); ret = get_oid_oneline(r, prefix, oid, list); + + free_commit_list(list); free(prefix); return ret; } @@ -1386,9 +1391,10 @@ static int handle_one_ref(const char *path, const struct object_id *oid, static int get_oid_oneline(struct repository *r, const char *prefix, struct object_id *oid, - struct commit_list *list) + const struct commit_list *list) { - struct commit_list *backup = NULL, *l; + struct commit_list *copy = NULL; + const struct commit_list *l; int found = 0; int negative = 0; regex_t regex; @@ -1409,14 +1415,14 @@ static int get_oid_oneline(struct repository *r, for (l = list; l; l = l->next) { l->item->object.flags |= ONELINE_SEEN; - commit_list_insert(l->item, &backup); + commit_list_insert(l->item, ©); } - while (list) { + while (copy) { const char *p, *buf; struct commit *commit; int matches; - commit = pop_most_recent_commit(&list, ONELINE_SEEN); + commit = pop_most_recent_commit(©, ONELINE_SEEN); if (!parse_object(r, &commit->object.oid)) continue; buf = repo_get_commit_buffer(r, commit, NULL); @@ -1431,10 +1437,9 @@ static int get_oid_oneline(struct repository *r, } } regfree(®ex); - free_commit_list(list); - for (l = backup; l; l = l->next) + for (l = list; l; l = l->next) clear_commit_marks(l->item, ONELINE_SEEN); - free_commit_list(backup); + free_commit_list(copy); return found ? 0 : -1; } @@ -1757,6 +1762,11 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name) return check_refname_format(sb->buf, 0); } +void object_context_release(struct object_context *ctx) +{ + free(ctx->path); +} + /* * This is like "get_oid_basic()", except it allows "object ID expressions", * notably "xyz^" for "parent of xyz" @@ -1764,7 +1774,9 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name) int repo_get_oid(struct repository *r, const char *name, struct object_id *oid) { struct object_context unused; - return get_oid_with_context(r, name, 0, oid, &unused); + int ret = get_oid_with_context(r, name, 0, oid, &unused); + object_context_release(&unused); + return ret; } /* @@ -1802,8 +1814,10 @@ int repo_get_oid_committish(struct repository *r, struct object_id *oid) { struct object_context unused; - return get_oid_with_context(r, name, GET_OID_COMMITTISH, - oid, &unused); + int ret = get_oid_with_context(r, name, GET_OID_COMMITTISH, + oid, &unused); + object_context_release(&unused); + return ret; } int repo_get_oid_treeish(struct repository *r, @@ -1811,8 +1825,10 @@ int repo_get_oid_treeish(struct repository *r, struct object_id *oid) { struct object_context unused; - return get_oid_with_context(r, name, GET_OID_TREEISH, - oid, &unused); + int ret = get_oid_with_context(r, name, GET_OID_TREEISH, + oid, &unused); + object_context_release(&unused); + return ret; } int repo_get_oid_commit(struct repository *r, @@ -1820,8 +1836,10 @@ int repo_get_oid_commit(struct repository *r, struct object_id *oid) { struct object_context unused; - return get_oid_with_context(r, name, GET_OID_COMMIT, - oid, &unused); + int ret = get_oid_with_context(r, name, GET_OID_COMMIT, + oid, &unused); + object_context_release(&unused); + return ret; } int repo_get_oid_tree(struct repository *r, @@ -1829,8 +1847,10 @@ int repo_get_oid_tree(struct repository *r, struct object_id *oid) { struct object_context unused; - return get_oid_with_context(r, name, GET_OID_TREE, - oid, &unused); + int ret = get_oid_with_context(r, name, GET_OID_TREE, + oid, &unused); + object_context_release(&unused); + return ret; } int repo_get_oid_blob(struct repository *r, @@ -1838,8 +1858,10 @@ int repo_get_oid_blob(struct repository *r, struct object_id *oid) { struct object_context unused; - return get_oid_with_context(r, name, GET_OID_BLOB, - oid, &unused); + int ret = get_oid_with_context(r, name, GET_OID_BLOB, + oid, &unused); + object_context_release(&unused); + return ret; } /* Must be called only when object_name:filename doesn't exist. */ @@ -2005,7 +2027,10 @@ static enum get_oid_result get_oid_with_context_1(struct repository *repo, 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); - return get_oid_oneline(repo, name + 2, oid, list); + ret = get_oid_oneline(repo, name + 2, oid, list); + + free_commit_list(list); + return ret; } if (namelen < 3 || name[2] != ':' || @@ -2117,6 +2142,7 @@ void maybe_die_on_misspelt_object_name(struct repository *r, struct object_id oid; get_oid_with_context_1(r, name, GET_OID_ONLY_TO_DIE | GET_OID_QUIETLY, prefix, &oid, &oc); + object_context_release(&oc); } enum get_oid_result get_oid_with_context(struct repository *repo, diff --git a/object-name.h b/object-name.h index 064ddc97d1..8dba4a47a4 100644 --- a/object-name.h +++ b/object-name.h @@ -22,6 +22,8 @@ struct object_context { char *path; }; +void object_context_release(struct object_context *ctx); + /* * Return an abbreviated sha1 unique within this repository's object database. * The result will be at least `len` characters long, and will be NUL @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "hex.h" @@ -1,7 +1,7 @@ #ifndef OBJECT_H #define OBJECT_H -#include "hash-ll.h" +#include "hash.h" struct buffer_slab; struct repository; @@ -62,7 +62,7 @@ void object_array_init(struct object_array *array); /* * object flag allocation: - * revision.h: 0---------10 15 23------27 + * revision.h: 0---------10 15 23------27 * fetch-pack.c: 01 67 * negotiator/default.c: 2--5 * walker.c: 0-2 @@ -75,13 +75,14 @@ void object_array_init(struct object_array *array); * commit-reach.c: 16-----19 * sha1-name.c: 20 * list-objects-filter.c: 21 + * bloom.c: 2122 * builtin/fsck.c: 0--3 * builtin/gc.c: 0 * builtin/index-pack.c: 2021 * reflog.c: 10--12 * builtin/show-branch.c: 0-------------------------------------------26 * builtin/unpack-objects.c: 2021 - * pack-bitmap.h: 22 + * pack-bitmap.h: 2122 */ #define FLAG_BITS 28 diff --git a/oid-array.c b/oid-array.c index 1f36651754..9cac974395 100644 --- a/oid-array.c +++ b/oid-array.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "oid-array.h" #include "hash-lookup.h" @@ -1,7 +1,7 @@ #ifndef OIDMAP_H #define OIDMAP_H -#include "hash-ll.h" +#include "hash.h" #include "hashmap.h" /* @@ -48,12 +48,14 @@ void oidset_clear(struct oidset *set) oidset_init(set, 0); } -void oidset_parse_file(struct oidset *set, const char *path) +void oidset_parse_file(struct oidset *set, const char *path, + const struct git_hash_algo *algop) { - oidset_parse_file_carefully(set, path, NULL, NULL); + oidset_parse_file_carefully(set, path, algop, NULL, NULL); } void oidset_parse_file_carefully(struct oidset *set, const char *path, + const struct git_hash_algo *algop, oidset_parse_tweak_fn fn, void *cbdata) { FILE *fp; @@ -79,7 +81,7 @@ void oidset_parse_file_carefully(struct oidset *set, const char *path, if (!sb.len) continue; - if (parse_oid_hex(sb.buf, &oid, &p) || *p != '\0') + if (parse_oid_hex_algop(sb.buf, &oid, &p, algop) || *p != '\0') die("invalid object name: %s", sb.buf); if (fn && fn(&oid, cbdata)) continue; @@ -80,7 +80,8 @@ void oidset_clear(struct oidset *set); * are allowed. Leading whitespace and empty or white-space only lines are * ignored. */ -void oidset_parse_file(struct oidset *set, const char *path); +void oidset_parse_file(struct oidset *set, const char *path, + const struct git_hash_algo *algop); /* * Similar to the above, but with a callback which can (1) return non-zero to @@ -89,6 +90,7 @@ void oidset_parse_file(struct oidset *set, const char *path); */ typedef int (*oidset_parse_tweak_fn)(struct object_id *, void *); void oidset_parse_file_carefully(struct oidset *set, const char *path, + const struct git_hash_algo *algop, oidset_parse_tweak_fn fn, void *cbdata); struct oidset_iter { @@ -42,7 +42,7 @@ void oidtree_insert(struct oidtree *ot, const struct object_id *oid) * Clear the padding and copy the result in separate steps to * respect the 4-byte alignment needed by struct object_id. */ - oidcpy_with_padding(&k, oid); + oidcpy(&k, oid); memcpy(on->k, &k, sizeof(k)); /* @@ -60,7 +60,7 @@ int oidtree_contains(struct oidtree *ot, const struct object_id *oid) struct object_id k; size_t klen = sizeof(k); - oidcpy_with_padding(&k, oid); + oidcpy(&k, oid); if (oid->algo == GIT_HASH_UNKNOWN) klen -= sizeof(oid->algo); @@ -2,7 +2,7 @@ #define OIDTREE_H #include "cbtree.h" -#include "hash-ll.h" +#include "hash.h" #include "mem-pool.h" struct oidtree { diff --git a/oss-fuzz/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c index 75e668a057..fbb77fec19 100644 --- a/oss-fuzz/fuzz-commit-graph.c +++ b/oss-fuzz/fuzz-commit-graph.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "commit-graph.h" #include "repository.h" @@ -21,7 +23,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) */ repo_set_hash_algo(the_repository, GIT_HASH_SHA1); the_repository->settings.commit_graph_generation_version = 2; - the_repository->settings.commit_graph_read_changed_paths = 1; + the_repository->settings.commit_graph_changed_paths_version = 1; g = parse_commit_graph(&the_repository->settings, (void *)data, size); repo_clear(the_repository); free_commit_graph(g); diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c index 6cae670412..bf96c80898 100644 --- a/pack-bitmap-write.c +++ b/pack-bitmap-write.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "gettext.h" @@ -17,6 +19,12 @@ #include "trace2.h" #include "tree.h" #include "tree-walk.h" +#include "pseudo-merge.h" +#include "oid-array.h" +#include "config.h" +#include "alloc.h" +#include "refs.h" +#include "strmap.h" struct bitmapped_commit { struct commit *commit; @@ -25,16 +33,39 @@ struct bitmapped_commit { int flags; int xor_offset; uint32_t commit_pos; + unsigned pseudo_merge : 1; }; -void bitmap_writer_init(struct bitmap_writer *writer) +static inline int bitmap_writer_nr_selected_commits(struct bitmap_writer *writer) +{ + return writer->selected_nr - writer->pseudo_merges_nr; +} + +void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r) { memset(writer, 0, sizeof(struct bitmap_writer)); + if (writer->bitmaps) + BUG("bitmap writer already initialized"); + writer->bitmaps = kh_init_oid_map(); + writer->pseudo_merge_commits = kh_init_oid_map(); + + string_list_init_dup(&writer->pseudo_merge_groups); + + load_pseudo_merges_from_config(&writer->pseudo_merge_groups); +} + +static void free_pseudo_merge_commit_idx(struct pseudo_merge_commit_idx *idx) +{ + if (!idx) + return; + free(idx->pseudo_merge); + free(idx); } void bitmap_writer_free(struct bitmap_writer *writer) { uint32_t i; + struct pseudo_merge_commit_idx *idx; if (!writer) return; @@ -46,6 +77,10 @@ void bitmap_writer_free(struct bitmap_writer *writer) kh_destroy_oid_map(writer->bitmaps); + kh_foreach_value(writer->pseudo_merge_commits, idx, + free_pseudo_merge_commit_idx(idx)); + kh_destroy_oid_map(writer->pseudo_merge_commits); + for (i = 0; i < writer->selected_nr; i++) { struct bitmapped_commit *bc = &writer->selected[i]; if (bc->write_as != bc->bitmap) @@ -121,22 +156,41 @@ void bitmap_writer_build_type_index(struct bitmap_writer *writer, } } +int bitmap_writer_has_bitmapped_object_id(struct bitmap_writer *writer, + const struct object_id *oid) +{ + return kh_get_oid_map(writer->bitmaps, *oid) != kh_end(writer->bitmaps); +} + /** * Compute the actual bitmaps */ -static inline void push_bitmapped_commit(struct bitmap_writer *writer, - struct commit *commit) +void bitmap_writer_push_commit(struct bitmap_writer *writer, + struct commit *commit, unsigned pseudo_merge) { if (writer->selected_nr >= writer->selected_alloc) { writer->selected_alloc = (writer->selected_alloc + 32) * 2; REALLOC_ARRAY(writer->selected, writer->selected_alloc); } + if (!pseudo_merge) { + int hash_ret; + khiter_t hash_pos = kh_put_oid_map(writer->bitmaps, + commit->object.oid, + &hash_ret); + + if (!hash_ret) + die(_("duplicate entry when writing bitmap index: %s"), + oid_to_hex(&commit->object.oid)); + kh_value(writer->bitmaps, hash_pos) = NULL; + } + writer->selected[writer->selected_nr].commit = commit; writer->selected[writer->selected_nr].bitmap = NULL; writer->selected[writer->selected_nr].write_as = NULL; writer->selected[writer->selected_nr].flags = 0; + writer->selected[writer->selected_nr].pseudo_merge = pseudo_merge; writer->selected_nr++; } @@ -167,16 +221,20 @@ static void compute_xor_offsets(struct bitmap_writer *writer) while (next < writer->selected_nr) { struct bitmapped_commit *stored = &writer->selected[next]; - int best_offset = 0; struct ewah_bitmap *best_bitmap = stored->bitmap; struct ewah_bitmap *test_xor; + if (stored->pseudo_merge) + goto next; + for (i = 1; i <= MAX_XOR_OFFSET_SEARCH; ++i) { int curr = next - i; if (curr < 0) break; + if (writer->selected[curr].pseudo_merge) + continue; test_xor = ewah_pool_new(); ewah_xor(writer->selected[curr].bitmap, stored->bitmap, test_xor); @@ -192,6 +250,7 @@ static void compute_xor_offsets(struct bitmap_writer *writer) } } +next: stored->xor_offset = best_offset; stored->write_as = best_bitmap; @@ -204,7 +263,8 @@ struct bb_commit { struct bitmap *commit_mask; struct bitmap *bitmap; unsigned selected:1, - maximal:1; + maximal:1, + pseudo_merge:1; unsigned idx; /* within selected array */ }; @@ -242,17 +302,18 @@ static void bitmap_builder_init(struct bitmap_builder *bb, revs.first_parent_only = 1; for (i = 0; i < writer->selected_nr; i++) { - struct commit *c = writer->selected[i].commit; - struct bb_commit *ent = bb_data_at(&bb->data, c); + struct bitmapped_commit *bc = &writer->selected[i]; + struct bb_commit *ent = bb_data_at(&bb->data, bc->commit); ent->selected = 1; ent->maximal = 1; + ent->pseudo_merge = bc->pseudo_merge; ent->idx = i; ent->commit_mask = bitmap_new(); bitmap_set(ent->commit_mask, i); - add_pending_object(&revs, &c->object, ""); + add_pending_object(&revs, &bc->commit->object, ""); } if (prepare_revision_walk(&revs)) @@ -410,6 +471,7 @@ static int fill_bitmap_tree(struct bitmap_writer *writer, } static int reused_bitmaps_nr; +static int reused_pseudo_merge_bitmaps_nr; static int fill_bitmap_commit(struct bitmap_writer *writer, struct bb_commit *ent, @@ -431,8 +493,13 @@ static int fill_bitmap_commit(struct bitmap_writer *writer, struct commit *c = prio_queue_get(queue); if (old_bitmap && mapping) { - struct ewah_bitmap *old = bitmap_for_commit(old_bitmap, c); + struct ewah_bitmap *old; struct bitmap *remapped = bitmap_new(); + + if (commit->object.flags & BITMAP_PSEUDO_MERGE) + old = pseudo_merge_bitmap_for_commit(old_bitmap, c); + else + old = bitmap_for_commit(old_bitmap, c); /* * If this commit has an old bitmap, then translate that * bitmap and add its bits to this one. No need to walk @@ -441,7 +508,10 @@ static int fill_bitmap_commit(struct bitmap_writer *writer, if (old && !rebuild_bitmap(mapping, old, remapped)) { bitmap_or(ent->bitmap, remapped); bitmap_free(remapped); - reused_bitmaps_nr++; + if (commit->object.flags & BITMAP_PSEUDO_MERGE) + reused_pseudo_merge_bitmaps_nr++; + else + reused_bitmaps_nr++; continue; } bitmap_free(remapped); @@ -451,12 +521,14 @@ static int fill_bitmap_commit(struct bitmap_writer *writer, * Mark ourselves and queue our tree. The commit * walk ensures we cover all parents. */ - pos = find_object_pos(writer, &c->object.oid, &found); - if (!found) - return -1; - bitmap_set(ent->bitmap, pos); - prio_queue_put(tree_queue, - repo_get_commit_tree(the_repository, c)); + if (!(c->object.flags & BITMAP_PSEUDO_MERGE)) { + pos = find_object_pos(writer, &c->object.oid, &found); + if (!found) + return -1; + bitmap_set(ent->bitmap, pos); + prio_queue_put(tree_queue, + repo_get_commit_tree(the_repository, c)); + } for (p = c->parents; p; p = p->next) { pos = find_object_pos(writer, &p->item->object.oid, @@ -483,14 +555,17 @@ static void store_selected(struct bitmap_writer *writer, { struct bitmapped_commit *stored = &writer->selected[ent->idx]; khiter_t hash_pos; - int hash_ret; stored->bitmap = bitmap_to_ewah(ent->bitmap); - hash_pos = kh_put_oid_map(writer->bitmaps, commit->object.oid, &hash_ret); - if (hash_ret == 0) - die("Duplicate entry when writing index: %s", + if (ent->pseudo_merge) + return; + + hash_pos = kh_get_oid_map(writer->bitmaps, commit->object.oid); + if (hash_pos == kh_end(writer->bitmaps)) + die(_("attempted to store non-selected commit: '%s'"), oid_to_hex(&commit->object.oid)); + kh_value(writer->bitmaps, hash_pos) = stored; } @@ -506,7 +581,6 @@ int bitmap_writer_build(struct bitmap_writer *writer, uint32_t *mapping; int closed = 1; /* until proven otherwise */ - writer->bitmaps = kh_init_oid_map(); writer->to_pack = to_pack; if (writer->show_progress) @@ -567,6 +641,9 @@ int bitmap_writer_build(struct bitmap_writer *writer, the_repository); trace2_data_intmax("pack-bitmap-write", the_repository, "building_bitmaps_reused", reused_bitmaps_nr); + trace2_data_intmax("pack-bitmap-write", the_repository, + "building_bitmaps_pseudo_merge_reused", + reused_pseudo_merge_bitmaps_nr); stop_progress(&writer->progress); @@ -619,7 +696,7 @@ void bitmap_writer_select_commits(struct bitmap_writer *writer, if (indexed_commits_nr < 100) { for (i = 0; i < indexed_commits_nr; ++i) - push_bitmapped_commit(writer, indexed_commits[i]); + bitmap_writer_push_commit(writer, indexed_commits[i], 0); return; } @@ -652,13 +729,15 @@ void bitmap_writer_select_commits(struct bitmap_writer *writer, } } - push_bitmapped_commit(writer, chosen); + bitmap_writer_push_commit(writer, chosen, 0); i += next + 1; display_progress(writer->progress, i); } stop_progress(&writer->progress); + + select_pseudo_merges(writer, indexed_commits, indexed_commits_nr); } @@ -689,8 +768,11 @@ static void write_selected_commits_v1(struct bitmap_writer *writer, { int i; - for (i = 0; i < writer->selected_nr; ++i) { + for (i = 0; i < bitmap_writer_nr_selected_commits(writer); ++i) { struct bitmapped_commit *stored = &writer->selected[i]; + if (stored->pseudo_merge) + BUG("unexpected pseudo-merge among selected: %s", + oid_to_hex(&stored->commit->object.oid)); if (offsets) offsets[i] = hashfile_total(f); @@ -703,6 +785,130 @@ static void write_selected_commits_v1(struct bitmap_writer *writer, } } +static void write_pseudo_merges(struct bitmap_writer *writer, + struct hashfile *f) +{ + struct oid_array commits = OID_ARRAY_INIT; + struct bitmap **commits_bitmap = NULL; + off_t *pseudo_merge_ofs = NULL; + off_t start, table_start, next_ext; + + uint32_t base = bitmap_writer_nr_selected_commits(writer); + size_t i, j = 0; + + CALLOC_ARRAY(commits_bitmap, writer->pseudo_merges_nr); + CALLOC_ARRAY(pseudo_merge_ofs, writer->pseudo_merges_nr); + + for (i = 0; i < writer->pseudo_merges_nr; i++) { + struct bitmapped_commit *merge = &writer->selected[base + i]; + struct commit_list *p; + + if (!merge->pseudo_merge) + BUG("found non-pseudo merge commit at %"PRIuMAX, (uintmax_t)i); + + commits_bitmap[i] = bitmap_new(); + + for (p = merge->commit->parents; p; p = p->next) + bitmap_set(commits_bitmap[i], + find_object_pos(writer, &p->item->object.oid, + NULL)); + } + + start = hashfile_total(f); + + for (i = 0; i < writer->pseudo_merges_nr; i++) { + struct ewah_bitmap *commits_ewah = bitmap_to_ewah(commits_bitmap[i]); + + pseudo_merge_ofs[i] = hashfile_total(f); + + dump_bitmap(f, commits_ewah); + dump_bitmap(f, writer->selected[base+i].write_as); + + ewah_free(commits_ewah); + } + + next_ext = st_add(hashfile_total(f), + st_mult(kh_size(writer->pseudo_merge_commits), + sizeof(uint64_t))); + + table_start = hashfile_total(f); + + commits.alloc = kh_size(writer->pseudo_merge_commits); + CALLOC_ARRAY(commits.oid, commits.alloc); + + for (i = kh_begin(writer->pseudo_merge_commits); i != kh_end(writer->pseudo_merge_commits); i++) { + if (!kh_exist(writer->pseudo_merge_commits, i)) + continue; + oid_array_append(&commits, &kh_key(writer->pseudo_merge_commits, i)); + } + + oid_array_sort(&commits); + + /* write lookup table (non-extended) */ + for (i = 0; i < commits.nr; i++) { + int hash_pos; + struct pseudo_merge_commit_idx *c; + + hash_pos = kh_get_oid_map(writer->pseudo_merge_commits, + commits.oid[i]); + if (hash_pos == kh_end(writer->pseudo_merge_commits)) + BUG("could not find pseudo-merge commit %s", + oid_to_hex(&commits.oid[i])); + + c = kh_value(writer->pseudo_merge_commits, hash_pos); + + hashwrite_be32(f, find_object_pos(writer, &commits.oid[i], + NULL)); + if (c->nr == 1) + hashwrite_be64(f, pseudo_merge_ofs[c->pseudo_merge[0]]); + else if (c->nr > 1) { + if (next_ext & ((uint64_t)1<<63)) + die(_("too many pseudo-merges")); + hashwrite_be64(f, next_ext | ((uint64_t)1<<63)); + next_ext = st_add3(next_ext, + sizeof(uint32_t), + st_mult(c->nr, sizeof(uint64_t))); + } else + BUG("expected commit '%s' to have at least one " + "pseudo-merge", oid_to_hex(&commits.oid[i])); + } + + /* write lookup table (extended) */ + for (i = 0; i < commits.nr; i++) { + int hash_pos; + struct pseudo_merge_commit_idx *c; + + hash_pos = kh_get_oid_map(writer->pseudo_merge_commits, + commits.oid[i]); + if (hash_pos == kh_end(writer->pseudo_merge_commits)) + BUG("could not find pseudo-merge commit %s", + oid_to_hex(&commits.oid[i])); + + c = kh_value(writer->pseudo_merge_commits, hash_pos); + if (c->nr == 1) + continue; + + hashwrite_be32(f, c->nr); + for (j = 0; j < c->nr; j++) + hashwrite_be64(f, pseudo_merge_ofs[c->pseudo_merge[j]]); + } + + /* write positions for all pseudo merges */ + for (i = 0; i < writer->pseudo_merges_nr; i++) + hashwrite_be64(f, pseudo_merge_ofs[i]); + + hashwrite_be32(f, writer->pseudo_merges_nr); + hashwrite_be32(f, kh_size(writer->pseudo_merge_commits)); + hashwrite_be64(f, table_start - start); + hashwrite_be64(f, hashfile_total(f) - start + sizeof(uint64_t)); + + for (i = 0; i < writer->pseudo_merges_nr; i++) + bitmap_free(commits_bitmap[i]); + + free(pseudo_merge_ofs); + free(commits_bitmap); +} + static int table_cmp(const void *_va, const void *_vb, void *_data) { struct bitmap_writer *writer = _data; @@ -723,10 +929,10 @@ static void write_lookup_table(struct bitmap_writer *writer, struct hashfile *f, uint32_t i; uint32_t *table, *table_inv; - ALLOC_ARRAY(table, writer->selected_nr); - ALLOC_ARRAY(table_inv, writer->selected_nr); + ALLOC_ARRAY(table, bitmap_writer_nr_selected_commits(writer)); + ALLOC_ARRAY(table_inv, bitmap_writer_nr_selected_commits(writer)); - for (i = 0; i < writer->selected_nr; i++) + for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) table[i] = i; /* @@ -734,16 +940,16 @@ static void write_lookup_table(struct bitmap_writer *writer, struct hashfile *f, * bitmap corresponds to j'th bitmapped commit (among the selected * commits) in lex order of OIDs. */ - QSORT_S(table, writer->selected_nr, table_cmp, writer); + QSORT_S(table, bitmap_writer_nr_selected_commits(writer), table_cmp, writer); /* table_inv helps us discover that relationship (i'th bitmap * to j'th commit by j = table_inv[i]) */ - for (i = 0; i < writer->selected_nr; i++) + for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) table_inv[table[i]] = i; trace2_region_enter("pack-bitmap-write", "writing_lookup_table", the_repository); - for (i = 0; i < writer->selected_nr; i++) { + for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) { struct bitmapped_commit *selected = &writer->selected[table[i]]; uint32_t xor_offset = selected->xor_offset; uint32_t xor_row; @@ -790,7 +996,7 @@ static void write_hash_cache(struct hashfile *f, void bitmap_writer_set_checksum(struct bitmap_writer *writer, const unsigned char *sha1) { - hashcpy(writer->pack_checksum, sha1); + hashcpy(writer->pack_checksum, sha1, the_repository->hash_algo); } void bitmap_writer_finish(struct bitmap_writer *writer, @@ -810,13 +1016,16 @@ void bitmap_writer_finish(struct bitmap_writer *writer, int fd = odb_mkstemp(&tmp_file, "pack/tmp_bitmap_XXXXXX"); + if (writer->pseudo_merges_nr) + options |= BITMAP_OPT_PSEUDO_MERGES; + f = hashfd(fd, tmp_file.buf); memcpy(header.magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE)); header.version = htons(default_version); header.options = htons(flags | options); - header.entry_count = htonl(writer->selected_nr); - hashcpy(header.checksum, writer->pack_checksum); + header.entry_count = htonl(bitmap_writer_nr_selected_commits(writer)); + hashcpy(header.checksum, writer->pack_checksum, the_repository->hash_algo); hashwrite(f, &header, sizeof(header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz); dump_bitmap(f, writer->commits); @@ -827,7 +1036,7 @@ void bitmap_writer_finish(struct bitmap_writer *writer, if (options & BITMAP_OPT_LOOKUP_TABLE) CALLOC_ARRAY(offsets, index_nr); - for (i = 0; i < writer->selected_nr; i++) { + for (i = 0; i < bitmap_writer_nr_selected_commits(writer); i++) { struct bitmapped_commit *stored = &writer->selected[i]; int commit_pos = oid_pos(&stored->commit->object.oid, index, index_nr, oid_access); @@ -839,6 +1048,9 @@ void bitmap_writer_finish(struct bitmap_writer *writer, write_selected_commits_v1(writer, f, offsets); + if (options & BITMAP_OPT_PSEUDO_MERGES) + write_pseudo_merges(writer, f); + if (options & BITMAP_OPT_LOOKUP_TABLE) write_lookup_table(writer, f, offsets); diff --git a/pack-bitmap.c b/pack-bitmap.c index fe8e8a51d3..2e657a2aa4 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "commit.h" #include "gettext.h" @@ -20,6 +22,7 @@ #include "list-objects-filter-options.h" #include "midx.h" #include "config.h" +#include "pseudo-merge.h" /* * An entry on the bitmap index, representing the bitmap for a given @@ -86,6 +89,9 @@ struct bitmap_index { */ unsigned char *table_lookup; + /* This contains the pseudo-merge cache within 'map' (if found). */ + struct pseudo_merge_map pseudo_merges; + /* * Extended index. * @@ -110,6 +116,13 @@ struct bitmap_index { unsigned int version; }; +static int pseudo_merges_satisfied_nr; +static int pseudo_merges_cascades_nr; +static int existing_bitmaps_hits_nr; +static int existing_bitmaps_misses_nr; +static int roots_with_bitmaps_nr; +static int roots_without_bitmaps_nr; + static struct ewah_bitmap *lookup_stored_bitmap(struct stored_bitmap *st) { struct ewah_bitmap *parent; @@ -129,17 +142,13 @@ static struct ewah_bitmap *lookup_stored_bitmap(struct stored_bitmap *st) return composed; } -/* - * Read a bitmap from the current read position on the mmaped - * index, and increase the read position accordingly - */ -static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index) +struct ewah_bitmap *read_bitmap(const unsigned char *map, + size_t map_size, size_t *map_pos) { struct ewah_bitmap *b = ewah_pool_new(); - ssize_t bitmap_size = ewah_read_mmap(b, - index->map + index->map_pos, - index->map_size - index->map_pos); + ssize_t bitmap_size = ewah_read_mmap(b, map + *map_pos, + map_size - *map_pos); if (bitmap_size < 0) { error(_("failed to load bitmap index (corrupted?)")); @@ -147,10 +156,20 @@ static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index) return NULL; } - index->map_pos += bitmap_size; + *map_pos += bitmap_size; + return b; } +/* + * Read a bitmap from the current read position on the mmaped + * index, and increase the read position accordingly + */ +static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index) +{ + return read_bitmap(index->map, index->map_size, &index->map_pos); +} + static uint32_t bitmap_num_objects(struct bitmap_index *index) { if (index->midx) @@ -199,6 +218,46 @@ static int load_bitmap_header(struct bitmap_index *index) index->table_lookup = (void *)(index_end - table_size); index_end -= table_size; } + + if (flags & BITMAP_OPT_PSEUDO_MERGES) { + unsigned char *pseudo_merge_ofs; + size_t table_size; + uint32_t i; + + if (sizeof(table_size) > index_end - index->map - header_size) + return error(_("corrupted bitmap index file (too short to fit pseudo-merge table header)")); + + table_size = get_be64(index_end - 8); + if (table_size > index_end - index->map - header_size) + return error(_("corrupted bitmap index file (too short to fit pseudo-merge table)")); + + if (git_env_bool("GIT_TEST_USE_PSEUDO_MERGES", 1)) { + const unsigned char *ext = (index_end - table_size); + + index->pseudo_merges.map = index->map; + index->pseudo_merges.map_size = index->map_size; + index->pseudo_merges.commits = ext + get_be64(index_end - 16); + index->pseudo_merges.commits_nr = get_be32(index_end - 20); + index->pseudo_merges.nr = get_be32(index_end - 24); + + if (st_add(st_mult(index->pseudo_merges.nr, + sizeof(uint64_t)), + 24) > table_size) + return error(_("corrupted bitmap index file, pseudo-merge table too short")); + + CALLOC_ARRAY(index->pseudo_merges.v, + index->pseudo_merges.nr); + + pseudo_merge_ofs = index_end - 24 - + (index->pseudo_merges.nr * sizeof(uint64_t)); + for (i = 0; i < index->pseudo_merges.nr; i++) { + index->pseudo_merges.v[i].at = get_be64(pseudo_merge_ofs); + pseudo_merge_ofs += sizeof(uint64_t); + } + } + + index_end -= table_size; + } } index->entry_count = ntohl(header->entry_count); @@ -367,7 +426,8 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git, if (load_bitmap_header(bitmap_git) < 0) goto cleanup; - if (!hasheq(get_midx_checksum(bitmap_git->midx), bitmap_git->checksum)) { + if (!hasheq(get_midx_checksum(bitmap_git->midx), bitmap_git->checksum, + the_repository->hash_algo)) { error(_("checksum doesn't match in MIDX and bitmap")); goto cleanup; } @@ -960,6 +1020,22 @@ static void show_commit(struct commit *commit UNUSED, { } +static unsigned apply_pseudo_merges_for_commit_1(struct bitmap_index *bitmap_git, + struct bitmap *result, + struct commit *commit, + uint32_t commit_pos) +{ + int ret; + + ret = apply_pseudo_merges_for_commit(&bitmap_git->pseudo_merges, + result, commit, commit_pos); + + if (ret) + pseudo_merges_satisfied_nr += ret; + + return ret; +} + static int add_to_include_set(struct bitmap_index *bitmap_git, struct include_data *data, struct commit *commit, @@ -975,11 +1051,19 @@ static int add_to_include_set(struct bitmap_index *bitmap_git, partial = bitmap_for_commit(bitmap_git, commit); if (partial) { + existing_bitmaps_hits_nr++; + bitmap_or_ewah(data->base, partial); return 0; } + existing_bitmaps_misses_nr++; + bitmap_set(data->base, bitmap_pos); + if (apply_pseudo_merges_for_commit_1(bitmap_git, data->base, commit, + bitmap_pos)) + return 0; + return 1; } @@ -1030,8 +1114,12 @@ static int add_commit_to_bitmap(struct bitmap_index *bitmap_git, { struct ewah_bitmap *or_with = bitmap_for_commit(bitmap_git, commit); - if (!or_with) + if (!or_with) { + existing_bitmaps_misses_nr++; return 0; + } + + existing_bitmaps_hits_nr++; if (!*base) *base = ewah_to_bitmap(or_with); @@ -1105,6 +1193,20 @@ static void show_boundary_object(struct object *object UNUSED, BUG("should not be called"); } +static unsigned cascade_pseudo_merges_1(struct bitmap_index *bitmap_git, + struct bitmap *result, + struct bitmap *roots) +{ + int ret = cascade_pseudo_merges(&bitmap_git->pseudo_merges, + result, roots); + if (ret) { + pseudo_merges_cascades_nr++; + pseudo_merges_satisfied_nr += ret; + } + + return ret; +} + static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, struct rev_info *revs, struct object_list *roots) @@ -1114,6 +1216,7 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, unsigned int i; unsigned int tmp_blobs, tmp_trees, tmp_tags; int any_missing = 0; + int existing_bitmaps = 0; cb.bitmap_git = bitmap_git; cb.base = bitmap_new(); @@ -1121,6 +1224,25 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, revs->ignore_missing_links = 1; + if (bitmap_git->pseudo_merges.nr) { + struct bitmap *roots_bitmap = bitmap_new(); + struct object_list *objects = NULL; + + for (objects = roots; objects; objects = objects->next) { + struct object *object = objects->item; + int pos; + + pos = bitmap_position(bitmap_git, &object->oid); + if (pos < 0) + continue; + + bitmap_set(roots_bitmap, pos); + } + + if (!cascade_pseudo_merges_1(bitmap_git, cb.base, roots_bitmap)) + bitmap_free(roots_bitmap); + } + /* * OR in any existing reachability bitmaps among `roots` into * `cb.base`. @@ -1132,8 +1254,10 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, continue; if (add_commit_to_bitmap(bitmap_git, &cb.base, - (struct commit *)object)) + (struct commit *)object)) { + existing_bitmaps = 1; continue; + } any_missing = 1; } @@ -1141,6 +1265,9 @@ static struct bitmap *find_boundary_objects(struct bitmap_index *bitmap_git, if (!any_missing) goto cleanup; + if (existing_bitmaps) + cascade_pseudo_merges_1(bitmap_git, cb.base, NULL); + tmp_blobs = revs->blob_objects; tmp_trees = revs->tree_objects; tmp_tags = revs->blob_objects; @@ -1196,6 +1323,44 @@ cleanup: return cb.base; } +struct ewah_bitmap *pseudo_merge_bitmap_for_commit(struct bitmap_index *bitmap_git, + struct commit *commit) +{ + struct commit_list *p; + struct bitmap *parents; + struct pseudo_merge *match = NULL; + + if (!bitmap_git->pseudo_merges.nr) + return NULL; + + parents = bitmap_new(); + + for (p = commit->parents; p; p = p->next) { + int pos = bitmap_position(bitmap_git, &p->item->object.oid); + if (pos < 0 || pos >= bitmap_num_objects(bitmap_git)) + goto done; + + bitmap_set(parents, pos); + } + + match = pseudo_merge_for_parents(&bitmap_git->pseudo_merges, + parents); + +done: + bitmap_free(parents); + if (match) + return pseudo_merge_bitmap(&bitmap_git->pseudo_merges, match); + + return NULL; +} + +static void unsatisfy_all_pseudo_merges(struct bitmap_index *bitmap_git) +{ + uint32_t i; + for (i = 0; i < bitmap_git->pseudo_merges.nr; i++) + bitmap_git->pseudo_merges.v[i].satisfied = 0; +} + static struct bitmap *find_objects(struct bitmap_index *bitmap_git, struct rev_info *revs, struct object_list *roots, @@ -1203,9 +1368,32 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git, { struct bitmap *base = NULL; int needs_walk = 0; + unsigned existing_bitmaps = 0; struct object_list *not_mapped = NULL; + unsatisfy_all_pseudo_merges(bitmap_git); + + if (bitmap_git->pseudo_merges.nr) { + struct bitmap *roots_bitmap = bitmap_new(); + struct object_list *objects = NULL; + + for (objects = roots; objects; objects = objects->next) { + struct object *object = objects->item; + int pos; + + pos = bitmap_position(bitmap_git, &object->oid); + if (pos < 0) + continue; + + bitmap_set(roots_bitmap, pos); + } + + base = bitmap_new(); + if (!cascade_pseudo_merges_1(bitmap_git, base, roots_bitmap)) + bitmap_free(roots_bitmap); + } + /* * Go through all the roots for the walk. The ones that have bitmaps * on the bitmap index will be `or`ed together to form an initial @@ -1216,11 +1404,21 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git, */ while (roots) { struct object *object = roots->item; + roots = roots->next; + if (base) { + int pos = bitmap_position(bitmap_git, &object->oid); + if (pos > 0 && bitmap_get(base, pos)) { + object->flags |= SEEN; + continue; + } + } + if (object->type == OBJ_COMMIT && add_commit_to_bitmap(bitmap_git, &base, (struct commit *)object)) { object->flags |= SEEN; + existing_bitmaps = 1; continue; } @@ -1236,6 +1434,9 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git, roots = not_mapped; + if (existing_bitmaps) + cascade_pseudo_merges_1(bitmap_git, base, NULL); + /* * Let's iterate through all the roots that don't have bitmaps to * check if we can determine them to be reachable from the existing @@ -1256,8 +1457,12 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git, object->flags &= ~UNINTERESTING; add_pending_object(revs, object, ""); needs_walk = 1; + + roots_without_bitmaps_nr++; } else { object->flags |= SEEN; + + roots_with_bitmaps_nr++; } } @@ -1820,6 +2025,19 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs, object_list_free(&wants); object_list_free(&haves); + trace2_data_intmax("bitmap", the_repository, "pseudo_merges_satisfied", + pseudo_merges_satisfied_nr); + trace2_data_intmax("bitmap", the_repository, "pseudo_merges_cascades", + pseudo_merges_cascades_nr); + trace2_data_intmax("bitmap", the_repository, "bitmap/hits", + existing_bitmaps_hits_nr); + trace2_data_intmax("bitmap", the_repository, "bitmap/misses", + existing_bitmaps_misses_nr); + trace2_data_intmax("bitmap", the_repository, "bitmap/roots_with_bitmap", + roots_with_bitmaps_nr); + trace2_data_intmax("bitmap", the_repository, "bitmap/roots_without_bitmap", + roots_without_bitmaps_nr); + return bitmap_git; cleanup: @@ -2073,6 +2291,7 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, QSORT(packs, packs_nr, bitmapped_pack_cmp); } else { struct packed_git *pack; + uint32_t pack_int_id; if (bitmap_is_midx(bitmap_git)) { uint32_t preferred_pack_pos; @@ -2083,12 +2302,24 @@ void reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git, } pack = bitmap_git->midx->packs[preferred_pack_pos]; + pack_int_id = preferred_pack_pos; } else { pack = bitmap_git->pack; + /* + * Any value for 'pack_int_id' will do here. When we + * process the pack via try_partial_reuse(), we won't + * use the `pack_int_id` field since we have a non-MIDX + * bitmap. + * + * Use '-1' as a sentinel value to make it clear + * that we do not expect to read this field. + */ + pack_int_id = -1; } ALLOC_GROW(packs, packs_nr + 1, packs_alloc); packs[packs_nr].p = pack; + packs[packs_nr].pack_int_id = pack_int_id; packs[packs_nr].bitmap_nr = pack->num_objects; packs[packs_nr].bitmap_pos = 0; @@ -2397,6 +2628,132 @@ cleanup: return 0; } +static void bit_pos_to_object_id(struct bitmap_index *bitmap_git, + uint32_t bit_pos, + struct object_id *oid) +{ + uint32_t index_pos; + + if (bitmap_is_midx(bitmap_git)) + index_pos = pack_pos_to_midx(bitmap_git->midx, bit_pos); + else + index_pos = pack_pos_to_index(bitmap_git->pack, bit_pos); + + nth_bitmap_object_oid(bitmap_git, oid, index_pos); +} + +int test_bitmap_pseudo_merges(struct repository *r) +{ + struct bitmap_index *bitmap_git; + uint32_t i; + + bitmap_git = prepare_bitmap_git(r); + if (!bitmap_git || !bitmap_git->pseudo_merges.nr) + goto cleanup; + + for (i = 0; i < bitmap_git->pseudo_merges.nr; i++) { + struct pseudo_merge *merge; + struct ewah_bitmap *commits_bitmap, *merge_bitmap; + + merge = use_pseudo_merge(&bitmap_git->pseudo_merges, + &bitmap_git->pseudo_merges.v[i]); + commits_bitmap = merge->commits; + merge_bitmap = pseudo_merge_bitmap(&bitmap_git->pseudo_merges, + merge); + + printf("at=%"PRIuMAX", commits=%"PRIuMAX", objects=%"PRIuMAX"\n", + (uintmax_t)merge->at, + (uintmax_t)ewah_bitmap_popcount(commits_bitmap), + (uintmax_t)ewah_bitmap_popcount(merge_bitmap)); + } + +cleanup: + free_bitmap_index(bitmap_git); + return 0; +} + +static void dump_ewah_object_ids(struct bitmap_index *bitmap_git, + struct ewah_bitmap *bitmap) + +{ + struct ewah_iterator it; + eword_t word; + uint32_t pos = 0; + + ewah_iterator_init(&it, bitmap); + + while (ewah_iterator_next(&word, &it)) { + struct object_id oid; + uint32_t offset; + + for (offset = 0; offset < BITS_IN_EWORD; offset++) { + if (!(word >> offset)) + break; + + offset += ewah_bit_ctz64(word >> offset); + + bit_pos_to_object_id(bitmap_git, pos + offset, &oid); + printf("%s\n", oid_to_hex(&oid)); + } + pos += BITS_IN_EWORD; + } +} + +int test_bitmap_pseudo_merge_commits(struct repository *r, uint32_t n) +{ + struct bitmap_index *bitmap_git; + struct pseudo_merge *merge; + int ret = 0; + + bitmap_git = prepare_bitmap_git(r); + if (!bitmap_git || !bitmap_git->pseudo_merges.nr) + goto cleanup; + + if (n >= bitmap_git->pseudo_merges.nr) { + ret = error(_("pseudo-merge index out of range " + "(%"PRIu32" >= %"PRIuMAX")"), + n, (uintmax_t)bitmap_git->pseudo_merges.nr); + goto cleanup; + } + + merge = use_pseudo_merge(&bitmap_git->pseudo_merges, + &bitmap_git->pseudo_merges.v[n]); + dump_ewah_object_ids(bitmap_git, merge->commits); + +cleanup: + free_bitmap_index(bitmap_git); + return ret; +} + +int test_bitmap_pseudo_merge_objects(struct repository *r, uint32_t n) +{ + struct bitmap_index *bitmap_git; + struct pseudo_merge *merge; + int ret = 0; + + bitmap_git = prepare_bitmap_git(r); + if (!bitmap_git || !bitmap_git->pseudo_merges.nr) + goto cleanup; + + if (n >= bitmap_git->pseudo_merges.nr) { + ret = error(_("pseudo-merge index out of range " + "(%"PRIu32" >= %"PRIuMAX")"), + n, (uintmax_t)bitmap_git->pseudo_merges.nr); + goto cleanup; + } + + merge = use_pseudo_merge(&bitmap_git->pseudo_merges, + &bitmap_git->pseudo_merges.v[n]); + + dump_ewah_object_ids(bitmap_git, + pseudo_merge_bitmap(&bitmap_git->pseudo_merges, + merge)); + +cleanup: + free_bitmap_index(bitmap_git); + return ret; +} + int rebuild_bitmap(const uint32_t *reposition, struct ewah_bitmap *source, struct bitmap *dest) @@ -2503,6 +2860,7 @@ void free_bitmap_index(struct bitmap_index *b) */ close_midx_revindex(b->midx); } + free_pseudo_merge_map(&b->pseudo_merges); free(b); } diff --git a/pack-bitmap.h b/pack-bitmap.h index 3091095f33..1171e6d989 100644 --- a/pack-bitmap.h +++ b/pack-bitmap.h @@ -21,6 +21,7 @@ struct bitmap_disk_header { unsigned char checksum[GIT_MAX_RAWSZ]; }; +#define BITMAP_PSEUDO_MERGE (1u<<21) #define NEEDS_BITMAP (1u<<22) /* @@ -36,6 +37,7 @@ enum pack_bitmap_opts { BITMAP_OPT_FULL_DAG = 0x1, BITMAP_OPT_HASH_CACHE = 0x4, BITMAP_OPT_LOOKUP_TABLE = 0x10, + BITMAP_OPT_PSEUDO_MERGES = 0x20, }; enum pack_bitmap_flags { @@ -71,6 +73,9 @@ void traverse_bitmap_commit_list(struct bitmap_index *, void test_bitmap_walk(struct rev_info *revs); int test_bitmap_commits(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); +int test_bitmap_pseudo_merge_objects(struct repository *r, uint32_t n); #define GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL \ "GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL" @@ -109,12 +114,16 @@ struct bitmap_writer { struct bitmapped_commit *selected; unsigned int selected_nr, selected_alloc; + struct string_list pseudo_merge_groups; + kh_oid_map_t *pseudo_merge_commits; /* oid -> pseudo merge(s) */ + uint32_t pseudo_merges_nr; + struct progress *progress; int show_progress; unsigned char pack_checksum[GIT_MAX_RAWSZ]; }; -void bitmap_writer_init(struct bitmap_writer *writer); +void bitmap_writer_init(struct bitmap_writer *writer, struct repository *r); void bitmap_writer_show_progress(struct bitmap_writer *writer, int show); void bitmap_writer_set_checksum(struct bitmap_writer *writer, const unsigned char *sha1); @@ -122,6 +131,10 @@ void bitmap_writer_build_type_index(struct bitmap_writer *writer, struct packing_data *to_pack, struct pack_idx_entry **index, uint32_t index_nr); +int bitmap_writer_has_bitmapped_object_id(struct bitmap_writer *writer, + const struct object_id *oid); +void bitmap_writer_push_commit(struct bitmap_writer *writer, + struct commit *commit, unsigned pseudo_merge); uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git, struct packing_data *mapping); int rebuild_bitmap(const uint32_t *reposition, @@ -129,6 +142,8 @@ int rebuild_bitmap(const uint32_t *reposition, struct bitmap *dest); struct ewah_bitmap *bitmap_for_commit(struct bitmap_index *bitmap_git, struct commit *commit); +struct ewah_bitmap *pseudo_merge_bitmap_for_commit(struct bitmap_index *bitmap_git, + struct commit *commit); void bitmap_writer_select_commits(struct bitmap_writer *writer, struct commit **indexed_commits, unsigned int indexed_commits_nr); @@ -150,4 +165,6 @@ int bitmap_is_preferred_refname(struct repository *r, const char *refname); int verify_bitmap_files(struct repository *r); +struct ewah_bitmap *read_bitmap(const unsigned char *map, + size_t map_size, size_t *map_pos); #endif diff --git a/pack-check.c b/pack-check.c index 25104d5b14..e883dae3f2 100644 --- a/pack-check.c +++ b/pack-check.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "hex.h" @@ -78,10 +80,11 @@ static int verify_packfile(struct repository *r, } while (offset < pack_sig_ofs); r->hash_algo->final_fn(hash, &ctx); pack_sig = use_pack(p, w_curs, pack_sig_ofs, NULL); - if (!hasheq(hash, pack_sig)) + if (!hasheq(hash, pack_sig, the_repository->hash_algo)) err = error("%s pack checksum mismatch", p->pack_name); - if (!hasheq(index_base + index_size - r->hash_algo->hexsz, pack_sig)) + if (!hasheq(index_base + index_size - r->hash_algo->hexsz, pack_sig, + the_repository->hash_algo)) err = error("%s pack checksum does not match its index", p->pack_name); unuse_pack(w_curs); diff --git a/pack-revindex.c b/pack-revindex.c index fc63aa76a2..22d3c23464 100644 --- a/pack-revindex.c +++ b/pack-revindex.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "pack-revindex.h" @@ -527,6 +529,9 @@ static int midx_key_to_pack_pos(struct multi_pack_index *m, { uint32_t *found; + if (key->pack >= m->num_packs) + BUG("MIDX pack lookup out of bounds (%"PRIu32" >= %"PRIu32")", + key->pack, m->num_packs); /* * The preferred pack sorts first, so determine its identifier by * looking at the first object in pseudo-pack order. diff --git a/pack-write.c b/pack-write.c index 80ecfa544c..d07f03d0ab 100644 --- a/pack-write.c +++ b/pack-write.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "gettext.h" @@ -428,7 +430,8 @@ void fixup_pack_header_footer(int pack_fd, if (partial_pack_offset == 0) { unsigned char hash[GIT_MAX_RAWSZ]; the_hash_algo->final_fn(hash, &old_hash_ctx); - if (!hasheq(hash, partial_pack_hash)) + if (!hasheq(hash, partial_pack_hash, + the_repository->hash_algo)) die("Unexpected checksum for %s " "(disk corruption?)", pack_name); /* diff --git a/packfile.c b/packfile.c index d4df7fdeea..813584646f 100644 --- a/packfile.c +++ b/packfile.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "gettext.h" @@ -242,7 +244,7 @@ struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path) struct packed_git *p = alloc_packed_git(alloc); memcpy(p->pack_name, path, alloc); /* includes NUL */ - hashcpy(p->hash, sha1); + hashcpy(p->hash, sha1, the_repository->hash_algo); if (check_packed_git_idx(idx_path, p)) { free(p); return NULL; @@ -596,7 +598,7 @@ static int open_packed_git_1(struct packed_git *p) if (read_result != hashsz) return error("packfile %s signature is unavailable", p->pack_name); idx_hash = ((unsigned char *)p->index_data) + p->index_size - hashsz * 2; - if (!hasheq(hash, idx_hash)) + if (!hasheq(hash, idx_hash, the_repository->hash_algo)) return error("packfile %s does not match index", p->pack_name); return 0; } @@ -751,7 +753,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local) p->mtime = st.st_mtime; if (path_len < the_hash_algo->hexsz || get_hash_hex(path + path_len - the_hash_algo->hexsz, p->hash)) - hashclr(p->hash); + hashclr(p->hash, the_repository->hash_algo); return p; } @@ -1251,7 +1253,7 @@ static int get_delta_base_oid(struct packed_git *p, { if (type == OBJ_REF_DELTA) { unsigned char *base = use_pack(p, w_curs, curpos, NULL); - oidread(oid, base); + oidread(oid, base, the_repository->hash_algo); return 0; } else if (type == OBJ_OFS_DELTA) { uint32_t base_pos; @@ -1593,7 +1595,7 @@ int packed_object_info(struct repository *r, struct packed_git *p, goto out; } } else - oidclr(oi->delta_base_oid); + oidclr(oi->delta_base_oid, the_repository->hash_algo); } oi->whence = in_delta_base_cache(p, obj_offset) ? OI_DBCACHED : @@ -1917,10 +1919,12 @@ int nth_packed_object_id(struct object_id *oid, return -1; index += 4 * 256; if (p->index_version == 1) { - oidread(oid, index + st_add(st_mult(hashsz + 4, n), 4)); + oidread(oid, index + st_add(st_mult(hashsz + 4, n), 4), + the_repository->hash_algo); } else { index += 8; - oidread(oid, index + st_mult(hashsz, n)); + oidread(oid, index + st_mult(hashsz, n), + the_repository->hash_algo); } return 0; } @@ -1971,7 +1975,7 @@ off_t find_pack_entry_one(const unsigned char *sha1, return 0; } - hashcpy(oid.hash, sha1); + hashcpy(oid.hash, sha1, the_repository->hash_algo); if (bsearch_pack(&oid, p, &result)) return nth_packed_object_offset(p, result); return 0; diff --git a/packfile.h b/packfile.h index 28c8fd3e39..eb18ec15db 100644 --- a/packfile.h +++ b/packfile.h @@ -101,6 +101,8 @@ int close_pack_fd(struct packed_git *p); uint32_t get_pack_fanout(struct packed_git *p, uint32_t value); +struct raw_object_store; + unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *); void close_pack_windows(struct packed_git *); void close_pack(struct packed_git *); @@ -14,6 +14,7 @@ int pager_use_color = 1; static struct child_process pager_process; static char *pager_program; +static int old_fd1 = -1, old_fd2 = -1; /* Is the value coming back from term_columns() just a guess? */ static int term_columns_guessed; @@ -23,10 +24,11 @@ static void close_pager_fds(void) { /* signal EOF to pager */ close(1); - close(2); + if (old_fd2 != -1) + close(2); } -static void wait_for_pager_atexit(void) +static void finish_pager(void) { fflush(stdout); fflush(stderr); @@ -34,8 +36,37 @@ static void wait_for_pager_atexit(void) finish_command(&pager_process); } +static void wait_for_pager_atexit(void) +{ + if (old_fd1 == -1) + return; + + finish_pager(); +} + +void wait_for_pager(void) +{ + if (old_fd1 == -1) + return; + + finish_pager(); + sigchain_pop_common(); + unsetenv("GIT_PAGER_IN_USE"); + dup2(old_fd1, 1); + close(old_fd1); + old_fd1 = -1; + if (old_fd2 != -1) { + dup2(old_fd2, 2); + close(old_fd2); + old_fd2 = -1; + } +} + static void wait_for_pager_signal(int signo) { + if (old_fd1 == -1) + return; + close_pager_fds(); finish_command_in_signal(&pager_process); sigchain_pop(signo); @@ -111,6 +142,7 @@ void prepare_pager_args(struct child_process *pager_process, const char *pager) void setup_pager(void) { + static int once = 0; const char *pager = git_pager(isatty(1)); if (!pager) @@ -137,17 +169,23 @@ void setup_pager(void) pager_process.in = -1; strvec_push(&pager_process.env, "GIT_PAGER_IN_USE"); if (start_command(&pager_process)) - return; + die("unable to execute pager '%s'", pager); /* original process continues, but writes to the pipe */ + old_fd1 = dup(1); dup2(pager_process.in, 1); - if (isatty(2)) + if (isatty(2)) { + old_fd2 = dup(2); dup2(pager_process.in, 2); + } close(pager_process.in); - /* this makes sure that the parent terminates after the pager */ sigchain_push_common(wait_for_pager_signal); - atexit(wait_for_pager_atexit); + + if (!once) { + once++; + atexit(wait_for_pager_atexit); + } } int pager_in_use(void) @@ -5,6 +5,7 @@ struct child_process; const char *git_pager(int stdout_is_tty); void setup_pager(void); +void wait_for_pager(void); int pager_in_use(void); int term_columns(void); void term_clear_line(void); diff --git a/parallel-checkout.c b/parallel-checkout.c index b5a714c711..08b960aac8 100644 --- a/parallel-checkout.c +++ b/parallel-checkout.c @@ -429,13 +429,7 @@ static void send_one_item(int fd, struct parallel_checkout_item *pc_item) fixed_portion->ident = pc_item->ca.ident; fixed_portion->name_len = name_len; fixed_portion->working_tree_encoding_len = working_tree_encoding_len; - /* - * We pad the unused bytes in the hash array because, otherwise, - * Valgrind would complain about passing uninitialized bytes to a - * write() syscall. The warning doesn't represent any real risk here, - * but it could hinder the detection of actual errors. - */ - oidcpy_with_padding(&fixed_portion->oid, &pc_item->ce->oid); + oidcpy(&fixed_portion->oid, &pc_item->ce->oid); variant = data + sizeof(*fixed_portion); if (working_tree_encoding_len) { diff --git a/parse-options-cb.c b/parse-options-cb.c index d99d688d3c..166d35e0eb 100644 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "parse-options.h" #include "branch.h" @@ -30,8 +32,6 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset) opt->long_name); if (v && v < MINIMUM_ABBREV) v = MINIMUM_ABBREV; - else if (startup_info->have_repository && v > the_hash_algo->hexsz) - v = the_hash_algo->hexsz; } *(int *)(opt->value) = v; return 0; diff --git a/parse-options.h b/parse-options.h index bd62e20268..ae15342390 100644 --- a/parse-options.h +++ b/parse-options.h @@ -355,7 +355,7 @@ struct option { .type = OPTION_ALIAS, \ .short_name = (s), \ .long_name = (l), \ - .value = (source_long_name), \ + .value = (char *)(source_long_name), \ } #define OPT_SUBCOMMAND_F(l, v, fn, f) { \ @@ -125,6 +125,35 @@ int git_parse_ssize_t(const char *value, ssize_t *ret) return 1; } +int git_parse_double(const char *value, double *ret) +{ + char *end; + double val; + uintmax_t factor; + + if (!value || !*value) { + errno = EINVAL; + return 0; + } + + errno = 0; + val = strtod(value, &end); + if (errno == ERANGE) + return 0; + if (end == value) { + errno = EINVAL; + return 0; + } + factor = get_unit_factor(end); + if (!factor) { + errno = EINVAL; + return 0; + } + val *= factor; + *ret = val; + return 1; +} + int git_parse_maybe_bool_text(const char *value) { if (!value) @@ -6,6 +6,7 @@ int git_parse_ssize_t(const char *, ssize_t *); int git_parse_ulong(const char *, unsigned long *); int git_parse_int(const char *value, int *ret); int git_parse_int64(const char *value, int64_t *ret); +int git_parse_double(const char *value, double *ret); /** * Same as `git_config_bool`, except that it returns -1 on error rather @@ -1,6 +1,9 @@ /* * Utilities for paths and pathnames */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "environment.h" @@ -4,6 +4,7 @@ struct repository; struct strbuf; struct string_list; +struct worktree; /* * The result to all functions which return statically allocated memory may be @@ -82,6 +83,14 @@ const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); /* + * Similar to git_path() but can produce paths for a specified + * worktree instead of current one + */ +const char *worktree_git_path(const struct worktree *wt, + const char *fmt, ...) + __attribute__((format (printf, 2, 3))); + +/* * Return a path into the main repository's (the_repository) git directory. */ char *git_pathdup(const char *fmt, ...) diff --git a/pathspec.c b/pathspec.c index 2133b9fe60..fe1f0f41af 100644 --- a/pathspec.c +++ b/pathspec.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "parse.h" diff --git a/pathspec.h b/pathspec.h index fec4399bbc..de537cff3c 100644 --- a/pathspec.h +++ b/pathspec.h @@ -23,7 +23,7 @@ struct index_state; #define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */ /** - * See glossary-context.txt for the syntax of pathspec. + * See glossary-content.txt for the syntax of pathspec. * In memory, a pathspec set is represented by "struct pathspec" and is * prepared by parse_pathspec(). */ diff --git a/perl/Git.pm b/perl/Git.pm index 03bf570bf4..aebfe0c6e0 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -418,7 +418,7 @@ argument is required if you want to see the command name in the error message, and it is the fourth value returned by C<command_bidi_pipe()>. The call idiom is: - my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe('cat-file --batch-check'); + my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe(qw(cat-file --batch-check)); print $out "000000000\n"; while (<$in>) { ... } $r->command_close_bidi_pipe($pid, $in, $out, $ctx); @@ -431,7 +431,7 @@ C<PIPE_IN> and C<PIPE_OUT> may be C<undef> if they have been closed prior to calling this function. This may be useful in a query-response type of commands where caller first writes a query and later reads response, eg: - my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe('cat-file --batch-check'); + my ($pid, $in, $out, $ctx) = $r->command_bidi_pipe(qw(cat-file --batch-check)); print $out "000000000\n"; close $out; while (<$in>) { ... } @@ -218,8 +218,10 @@ # symref файл Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ» (regular file that stores a string that begins with ref: refs/) # human-readable четим от хора # pseudoref пÑевдоуказател, напр. MERGE_HEAD, CHERRY_PICK_HEAD, REVERT_HEAD или REBASE_HEAD +# pseudo-merge пÑевдо Ñливанe # reftable таблица Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ð¸ # its referent '%s' ÑÐ¾Ñ‡ÐµÑ‰Ð¸Ñ Ð³Ð¾ „%s“ +# dry run пробно изпълнение # # # ------------------------ @@ -249,8 +251,8 @@ msgid "" msgstr "" "Project-Id-Version: git 2.45\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-21 16:59+0200\n" -"PO-Revision-Date: 2024-04-21 17:00+0200\n" +"POT-Creation-Date: 2024-07-20 07:37+0200\n" +"PO-Revision-Date: 2024-07-21 22:27+0300\n" "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n" "Language-Team: Bulgarian <dict@fsa-bg.org>\n" "Language: bg\n" @@ -820,6 +822,10 @@ msgstr "" "p — извеждане на текущото парче\n" "? — извеждане на помощта\n" +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "Очаква Ñе Ñамо един знак, а не „%s“" + msgid "No previous hunk" msgstr "ÐÑма друго парче преди това" @@ -868,9 +874,19 @@ msgstr "РазделÑне на %d парчета." msgid "Sorry, cannot edit this hunk" msgstr "Това парче не може да Ñе редактира" +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "Ðепозната команда „%s“ (за помощ натиÑнете „?“)" + msgid "'git apply' failed" msgstr "неуÑпешно изпълнение на „git apply“" +msgid "No changes." +msgstr "ÐÑма промѐни." + +msgid "Only binary files changed." +msgstr "Променени Ñа Ñамо двоични файлове." + #, c-format msgid "" "\n" @@ -1399,10 +1415,6 @@ msgstr[0] "Прилагане на кръпката „%%s“ Ñ %d отхвър msgstr[1] "Прилагане на кръпката „%%s“ Ñ %d отхвърлени парчета…" #, c-format -msgid "truncating .rej filename to %.*s.rej" -msgstr "Ñъкращаване на името на файла Ñ Ð¾Ñ‚Ñ…Ð²ÑŠÑ€Ð»ÐµÐ½Ð¸Ñ‚Ðµ парчета на „%.*s.rej“" - -#, c-format msgid "cannot open %s" msgstr "„%s“ не може да Ñе отвори" @@ -1752,6 +1764,10 @@ msgstr "преÑкачане на прекалено Ð³Ð¾Ð»ÐµÐ¼Ð¸Ñ Ñ„Ð°Ð¹Ð» зРmsgid "ignoring overly large gitattributes blob '%s'" msgstr "преÑкачане на прекалено Ð³Ð¾Ð»ÐµÐ¼Ð¸Ñ Ð¾Ð±ÐµÐºÑ‚-BLOB за атрибути на git: „%s“" +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "" +"опциÑта „--attr-source“ и променливата „GIT_ATTR_SOURCE“ изиÑкват хранилище" + msgid "bad --attr-source or GIT_ATTR_SOURCE" msgstr "" "неправилна ÑтойноÑÑ‚ за опциÑта „--attr-source“ или променливата " @@ -1834,6 +1850,10 @@ msgid "could not create file '%s'" msgstr "файлът „%s“ не може да Ñе Ñъздаде" #, c-format +msgid "unable to start 'show' for object '%s'" +msgstr "дейÑтвието „show“ не може да Ñе изпълни за обект „%s“" + +#, c-format msgid "could not read file '%s'" msgstr "файлът „%s“ не може да Ñе прочете" @@ -2072,13 +2092,6 @@ msgstr "права̀та на „%2$s“ не може да Ñе зададат msgid "Unstaged changes after refreshing the index:" msgstr "Промѐни, които и Ñлед обновÑването на индекÑа не Ñа добавени към него:" -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"ÐаÑтройката „add.interactive.useBuiltin“ е премахната!\n" -"За подробноÑти Ñ Ð¿Ð¾Ñ‚ÑŠÑ€Ñете в изхода от „git help config“." - msgid "could not read the index" msgstr "индекÑÑŠÑ‚ не може да Ñе прочете" @@ -2541,6 +2554,9 @@ msgstr "" msgid "show the patch being applied" msgstr "показване на прилаганата кръпка" +msgid "try to apply current patch again" +msgstr "нов опит за прилагане на текущата кръпка" + msgid "record the empty patch as an empty commit" msgstr "прилагане на празна кръпка като празно подаване" @@ -2598,9 +2614,6 @@ msgstr "git apply [ОПЦИЯ…] [КРЪПКÐ…]" msgid "could not redirect output" msgstr "изходът не може да Ñе пренаÑочи" -msgid "git archive: Remote with no URL" -msgstr "git archive: ЛипÑва Ð°Ð´Ñ€ÐµÑ Ð·Ð° отдалеченото хранилище" - msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "" "git archive: очакваше Ñе „ACK“/„NAK“, а бе получен изчиÑтващ пакет „flush“" @@ -3535,6 +3548,9 @@ msgstr "За Ñъздаването на пратка е необходимо Ñ… msgid "do not show bundle details" msgstr "без подробна Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° пратките" +msgid "need a repository to verify a bundle" +msgstr "за проверката на пратка е необходимо хранилище" + #, c-format msgid "%s is okay\n" msgstr "Пратката „%s“ е наред\n" @@ -4410,9 +4426,7 @@ msgid "remove only ignored files" msgstr "изтриване Ñамо на игнорирани файлове" msgid "clean.requireForce is true and -f not given: refusing to clean" -msgstr "" -"ÐаÑтройката „clean.requireForce“ е зададена, което изиÑква опцииÑта „-f“. " -"ÐÑма да Ñе извърши изчиÑтване" +msgstr "ÐаÑтройката „clean.requireForce“ е зададена, което изиÑква опциÑта „-f“. ÐÑма да Ñе извърши изчиÑтване" msgid "git clone [<options>] [--] <repo> [<dir>]" msgstr "git clone [ОПЦИЯ…] [--] ХРÐÐИЛИЩЕ [ДИРЕКТОРИЯ]" @@ -4569,6 +4583,14 @@ msgid "failed to unlink '%s'" msgstr "неуÑпешно изтриване на „%s“" #, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "твърдата връзка не може да Ñе провери при „%s“" + +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "твърдата връзка е различна от източника „%s“" + +#, c-format msgid "failed to create link '%s'" msgstr "връзката „%s“ не може да бъде Ñъздадена" @@ -5438,15 +5460,49 @@ msgstr "" "\n" " git restore --staged :/" -msgid "git config [<options>]" -msgstr "git config [ОПЦИЯ…]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "git config list [ОПЦИЯ_ЗÐ_ФÐЙЛ] [ОПЦИЯ_ЗÐ_ИЗВЕЖДÐÐЕ] [--includes]" -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "непознат аргумент към „--type“: %s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [ОПЦИЯ_ЗÐ_ФÐЙЛ] [ОПЦИЯ_ЗÐ_ИЗВЕЖДÐÐЕ] [--includes] [--all] [--" +"regexp=РЕГ_ИЗР][--value=СТОЙÐОСТ] [--fixed-value] [--default=СТÐÐДÐРТÐО] ИМЕ" -msgid "only one type at a time" -msgstr "Ñамо по един вид" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [ОПЦИЯ_ЗÐ_ФÐЙЛ] [--type=ВИД] [--all] [--value=СТОЙÐОСТ] [--" +"fixed-value] ИМЕ СТОЙÐОСТ" + +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [ОПЦИЯ_ЗÐ_ФÐЙЛ] [--all] [--value=СТОЙÐОСТ] [--fixed-value]" + +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "git config rename-section [ОПЦИЯ_ЗÐ_ФÐЙЛ] СТÐРО_ИМЕ ÐОВО_ИМЕ" + +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [ОПЦИЯ_ЗÐ_ФÐЙЛ] ИМЕ" + +msgid "git config edit [<file-option>]" +msgstr "git config edit [ОПЦИЯ_ЗÐ_ФÐЙЛ]" + +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "" +"git config [ОПЦИЯ_ЗÐ_ФÐЙЛ] --get-colorbool ИМЕ [СТÐÐД_ИЗХОД_ÐÐ_ТЕРМИÐÐЛ]" + +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [ОПЦИЯ_ЗÐ_ФÐЙЛ] [--type=ВИД] [--comment=СЪОБЩЕÐИЕ] [--all] [--" +"value=СТОЙÐОСТ] [--fixed-value] ИМЕ СТОЙÐОСТ" msgid "Config file location" msgstr "МеÑтоположение на ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»" @@ -5473,57 +5529,6 @@ msgid "read config from given blob object" msgstr "" "изчитане на конфигурациÑта от BLOB Ñ Ñ‚Ð¾Ð·Ð¸ ИДЕÐТИФИКÐТОРна Ñъдържанието" -msgid "Action" -msgstr "ДейÑтвие" - -msgid "get value: name [value-pattern]" -msgstr "извеждане на ÑтойноÑÑ‚: ИМЕ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" - -msgid "get all values: key [value-pattern]" -msgstr "извеждане на вÑички ÑтойноÑти: ключ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" - -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "" -"извеждане на ÑтойноÑтите за РЕГУЛЯРÐиÑ_ИЗРÐЗ: РЕГУЛЯРЕÐ_ИЗРÐЗ_ЗÐ_ИМЕТО " -"[ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" - -msgid "get value specific for the URL: section[.var] URL" -msgstr "извеждане на ÑтойноÑтта за ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð°Ð´Ñ€ÐµÑ: Ð ÐЗДЕЛ[.ПРОМЕÐЛИВÐ] ÐДРЕС" - -msgid "replace all matching variables: name value [value-pattern]" -msgstr "" -"замÑна на вÑички Ñъвпадащи променливи: ИМЕ СТОЙÐОСТ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" - -msgid "add a new variable: name value" -msgstr "добавÑне на нова променлива: ИМЕ СТОЙÐОСТ" - -msgid "remove a variable: name [value-pattern]" -msgstr "изтриване на променлива: ИМЕ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" - -msgid "remove all matches: name [value-pattern]" -msgstr "изтриване на вÑички Ñъвпадащи: ИМЕ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" - -msgid "rename section: old-name new-name" -msgstr "преименуване на раздел: СТÐРО_ИМЕ ÐОВО_ИМЕ" - -msgid "remove a section: name" -msgstr "изтриване на раздел: ИМЕ" - -msgid "list all" -msgstr "изброÑване на вÑички" - -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "доÑловно равенÑтво при ÑравнÑване ÑÑŠÑ Ð¨ÐБЛОÐ_ЗÐ_СТОЙÐОСТ" - -msgid "open an editor" -msgstr "отварÑне на редактор" - -msgid "find the color configured: slot [default]" -msgstr "извеждане на Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ñ†Ð²ÑÑ‚: номер [Ñтандартно]" - -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "извеждане на Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ñ†Ð²ÑÑ‚: номер (ÑтандартниÑÑ‚ изход е терминал)" - msgid "Type" msgstr "Вид" @@ -5551,8 +5556,8 @@ msgstr "СТОЙÐОСТТРе път (до файл или Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ msgid "value is an expiry date" msgstr "ÑтойноÑтта е период на валидноÑÑ‚/запазване" -msgid "Other" -msgstr "Други" +msgid "Display options" +msgstr "Опции за извеждането" msgid "terminate values with NUL byte" msgstr "разделÑне на ÑтойноÑтите Ñ Ð½ÑƒÐ»ÐµÐ²Ð¸Ñ Ð·Ð½Ð°Ðº „NUL“" @@ -5560,9 +5565,6 @@ msgstr "разделÑне на ÑтойноÑтите Ñ Ð½ÑƒÐ»ÐµÐ²Ð¸Ñ Ð·Ð½Ð°Ð msgid "show variable names only" msgstr "извеждане на имената на променливите" -msgid "respect include directives on lookup" -msgstr "при търÑене да Ñе уважат и директивите за включване" - msgid "show origin of config (file, standard input, blob, command line)" msgstr "" "извеждане на мÑÑтото на задаване на наÑтройката (файл, Ñтандартен вход, " @@ -5573,14 +5575,15 @@ msgstr "" "извеждане на обхвата на наÑтройката „worktree“ (работно дърво), „local“ " "(хранилище), „global“ (потребител), „system“ (ÑиÑтема), „command“ (команда)" -msgid "value" -msgstr "СТОЙÐОСТ" +msgid "show config keys in addition to their values" +msgstr "извеждане на ключовете в наÑтройките заедно ÑÑŠÑ ÑтойноÑтите им" -msgid "with --get, use default value when missing entry" -msgstr "Ñ â€ž--get“ Ñе използва Ñтандартна СТОЙÐОСТ при липÑваща" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "непознат аргумент към „--type“: %s" -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "низ за подаване четим от хора (при нужда отпред Ñе Ð´Ð¾Ð±Ð°Ð²Ñ â€ž#“)" +msgid "only one type at a time" +msgstr "Ñамо по един вид" #, c-format msgid "wrong number of arguments, should be %d" @@ -5657,50 +5660,73 @@ msgstr "" "повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ раздела „CONFIGURATION FILE“ в\n" "„git help worktree“" -msgid "--get-color and variable type are incoherent" -msgstr "опциÑта „--get-color“ не ÑъответÑтва на вида на променливата" +msgid "Other" +msgstr "Други" -msgid "only one action at a time" -msgstr "Ñамо по едно дейÑтвие" +msgid "respect include directives on lookup" +msgstr "при търÑене да Ñе уважат и директивите за включване" -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "" -"опциÑта „--name-only“ е приложима Ñамо към опциите „--list“ и „--get-regexp“" +#, c-format +msgid "unable to read config file '%s'" +msgstr "конфигурационниÑÑ‚ файл „%s“ не може да бъде прочетен" -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" -msgstr "" -"опциÑта „--show-origin“ е приложима Ñамо към опциите „--get“, „--get-all“, " -"„--get-regexp“ и „--list“" +msgid "error processing config file(s)" +msgstr "грешка при обработката на конфигурационен файл" -msgid "--default is only applicable to --get" -msgstr "опциÑта „--default“ е приложима Ñамо към опциÑта „--get“" +msgid "Filter options" +msgstr "Опции за филтриране" -msgid "--comment is only applicable to add/set/replace operations" +msgid "return all values for multi-valued config options" +msgstr "връщане на вÑички ÑтойноÑти за опциите, поддържащи много ÑтойноÑти" + +msgid "interpret the name as a regular expression" +msgstr "третиране на името като регулÑрен израз" + +msgid "show config with values matching the pattern" +msgstr "извеждане на наÑтройките ÑÑŠÑ ÑтойноÑти напаÑващи на ШÐБЛОÐа" + +msgid "use string equality when comparing values to value pattern" msgstr "" -"опциÑта „--comment“ е ÑъвмеÑтима Ñамо Ñ Ð´ÐµÐ¹ÑтвиÑта „add“ (добавÑне)/„set“ " -"(задаване)/„replace“ (замÑна)" +"ползване на равенÑтво на низ при ÑравнÑване на ÑтойноÑÑ‚ Ñ Ð¨ÐБЛОÐ_ЗÐ_СТОЙÐОСТ" + +msgid "URL" +msgstr "ÐдреÑ" + +msgid "show config matching the given URL" +msgstr "извеждане на наÑтройките напаÑващи на Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ð°Ð´Ñ€ÐµÑ" + +msgid "value" +msgstr "СТОЙÐОСТ" + +msgid "use default value when missing entry" +msgstr "ползване на Ñтандартна СТОЙÐОСТ при липÑваща" msgid "--fixed-value only applies with 'value-pattern'" -msgstr "опциÑта „--fixed-value“ е приложима Ñамо ÑÑŠÑ Ð¨ÐБЛОÐ_ЗÐ_СТОЙÐОСТ" +msgstr "опциÑта „--fixed-value“ изиÑква ШÐБЛОÐ_ЗÐ_СТОЙÐОСТ" -#, c-format -msgid "unable to read config file '%s'" -msgstr "конфигурационниÑÑ‚ файл „%s“ не може да бъде прочетен" +msgid "--default= cannot be used with --all or --url=" +msgstr "опциÑта „--default=“ е неÑъвмеÑтима Ñ â€ž--all“, „--url=“" -msgid "error processing config file(s)" -msgstr "грешка при обработката на конфигурационен файл" +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "опциÑта „--url=“ е неÑъвмеÑтима Ñ â€ž--all“, „--regexp“, „--value“" -msgid "editing stdin is not supported" -msgstr "не Ñе поддържа редактиране на ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´" +msgid "Filter" +msgstr "Филтриране" -msgid "editing blobs is not supported" -msgstr "не Ñе поддържа редактиране на обекти-BLOB" +msgid "replace multi-valued config option with new value" +msgstr "замÑна на наÑтройка, приемаща много ÑтойноÑти, Ñ Ð½Ð¾Ð²Ð° ÑтойноÑÑ‚" -#, c-format -msgid "cannot create configuration file %s" -msgstr "конфигурационниÑÑ‚ файл „%s“ не може да бъде Ñъздаден" +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "низ за подаване четим от хора (при нужда отпред Ñе Ð´Ð¾Ð±Ð°Ð²Ñ â€ž#“)" + +msgid "add a new line without altering any existing values" +msgstr "добавÑне на нов ред без промÑна на ÑъщеÑтвуващи ÑтойноÑти" + +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "опциÑта „--fixed-value“ изиÑква опциÑта „--value=ШÐБЛОÐ_ЗÐ_СТОЙÐОСТ“" + +msgid "--append cannot be used with --value=<pattern>" +msgstr "опциитe „--append“ и „--value=ШÐБЛОÐ_ЗÐ_СТОЙÐОСТ“ Ñа неÑъвмеÑтими" #, c-format msgid "" @@ -5715,6 +5741,92 @@ msgstr "" msgid "no such section: %s" msgstr "такъв раззел нÑма: %s" +msgid "editing stdin is not supported" +msgstr "не Ñе поддържа редактиране на ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´" + +msgid "editing blobs is not supported" +msgstr "не Ñе поддържа редактиране на обекти-BLOB" + +#, c-format +msgid "cannot create configuration file %s" +msgstr "конфигурационниÑÑ‚ файл „%s“ не може да бъде Ñъздаден" + +msgid "Action" +msgstr "ДейÑтвие" + +msgid "get value: name [<value-pattern>]" +msgstr "извеждане на ÑтойноÑÑ‚: ИМЕ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" + +msgid "get all values: key [<value-pattern>]" +msgstr "извеждане на вÑички ÑтойноÑти: ключ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" + +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "" +"извеждане на ÑтойноÑтите за РЕГУЛЯРÐиÑ_ИЗРÐЗ: name-regex " +"[ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" + +msgid "get value specific for the URL: section[.var] URL" +msgstr "извеждане на ÑтойноÑтта за ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð°Ð´Ñ€ÐµÑ: Ð ÐЗДЕЛ[.ПРОМЕÐЛИВÐ] ÐДРЕС" + +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "" +"замÑна на вÑички Ñъвпадащи променливи: ИМЕ СТОЙÐОСТ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" + +msgid "add a new variable: name value" +msgstr "добавÑне на нова променлива: ИМЕ СТОЙÐОСТ" + +msgid "remove a variable: name [<value-pattern>]" +msgstr "изтриване на променлива: ИМЕ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" + +msgid "remove all matches: name [<value-pattern>]" +msgstr "изтриване на вÑички Ñъвпадащи: ИМЕ [ШÐБЛОÐ_ЗÐ_СТОЙÐОСТТÐ]" + +msgid "rename section: old-name new-name" +msgstr "преименуване на раздел: СТÐРО_ИМЕ ÐОВО_ИМЕ" + +msgid "remove a section: name" +msgstr "изтриване на раздел: ИМЕ" + +msgid "list all" +msgstr "изброÑване на вÑички" + +msgid "open an editor" +msgstr "отварÑне на редактор" + +msgid "find the color configured: slot [<default>]" +msgstr "намиране на Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ñ†Ð²ÑÑ‚: номер [СТÐÐДÐРТÐО]" + +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "извеждане на Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸Ñ Ñ†Ð²ÑÑ‚: номер (СТÐÐД_ИЗХОД_ÐÐ_ТЕРМИÐÐЛ)" + +msgid "with --get, use default value when missing entry" +msgstr "Ñ â€ž--get“ Ñе използва Ñтандартна СТОЙÐОСТ при липÑваща" + +msgid "--get-color and variable type are incoherent" +msgstr "опциÑта „--get-color“ не ÑъответÑтва на вида на променливата" + +msgid "no action specified" +msgstr "не е зададено дейÑтвие" + +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "" +"опциÑта „--name-only“ е приложима Ñамо към опциите „--list“ и „--get-regexp“" + +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "" +"опциÑта „--show-origin“ е приложима Ñамо към опциите „--get“, „--get-all“, " +"„--get-regexp“ и „--list“" + +msgid "--default is only applicable to --get" +msgstr "опциÑта „--default“ е приложима Ñамо към опциÑта „--get“" + +msgid "--comment is only applicable to add/set/replace operations" +msgstr "" +"опциÑта „--comment“ е ÑъвмеÑтима Ñамо Ñ Ð´ÐµÐ¹ÑтвиÑта „add“ (добавÑне)/„set“ " +"(задаване)/„replace“ (замÑна)" + msgid "print sizes in human readable format" msgstr "извеждане на размерите на обектите във формат четим от хора" @@ -6545,7 +6657,7 @@ msgid "read reference patterns from stdin" msgstr "изчитане на шаблоните за указатели от ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð²Ñ…Ð¾Ð´" msgid "also include HEAD ref and pseudorefs" -msgstr "включване и на ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€žHEAD“ както и пÑевдоуказателите" +msgstr "включване и на ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€žHEAD“ както и пÑевдо указателите" msgid "unknown arguments supplied with --stdin" msgstr "непознат аргумент към опциÑта „--stdin“" @@ -6559,12 +6671,15 @@ msgstr "наÑтройка" msgid "config key storing a list of repository paths" msgstr "наÑтройка, коÑто Ñъдържа ÑпиÑък Ñ Ð¿ÑŠÑ‚Ð¸Ñ‰Ð° към хранилища" +msgid "keep going even if command fails in a repository" +msgstr "продължаване на дейÑтвието дори и командата да е неуÑпешна в нÑкое хранилище" + msgid "missing --config=<config>" msgstr "липÑва --config=ÐÐСТРОЙКÐ" #, c-format msgid "got bad config --config=%s" -msgstr "получена е неправилена наÑтройка „--config=%s“" +msgstr "получена е неправилна наÑтройка „--config=%s“" msgid "unknown" msgstr "непознат" @@ -8041,8 +8156,11 @@ msgstr "отбелÑзване, че това е N-тата поредна реРmsgid "max length of output filename" msgstr "макÑимална дължина на име на вÑеки пакетен файл" -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "използване на „[RFC PATCH]“ вмеÑто „[PATCH]“" +msgid "rfc" +msgstr "ПРЕФИКС" + +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "добавÑне на този ПРЕФИКС (Ñтандартно е „RFC“) пред „PATCH“" msgid "cover-from-description-mode" msgstr "режим-придружаващо-пиÑмо-по-опиÑание" @@ -8282,7 +8400,7 @@ msgid "show resolve-undo information" msgstr "извеждане на информациÑта за отмÑна на разрешените подаваниÑ" msgid "skip files matching pattern" -msgstr "преÑкачане на файловете напаÑващи ШÐБЛОÐа" +msgstr "преÑкачане на файловете напаÑващи на ШÐБЛОÐа" msgid "read exclude patterns from <file>" msgstr "изчитане на шаблоните за игнориране от ФÐЙЛ" @@ -8325,13 +8443,13 @@ msgstr "" "deduplicate“/„--eol“" msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=КОМÐÐДÐ]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=КОМÐÐДÐ]\n" " [-q|--quiet] [--exit-code] [--get-url] [--sort=КЛЮЧ]\n" -" [--symref] [ХРÐÐИЛИЩЕ [ШÐБЛОÐ]]" +" [--symref] [ХРÐÐИЛИЩЕ [ШÐБЛОÐ…]]" msgid "do not print remote URL" msgstr "без извеждане на адреÑите на отдалечените хранилища" @@ -8345,8 +8463,11 @@ msgstr "път към командата „git-upload-pack“ на отдале msgid "limit to tags" msgstr "Ñамо етикетите" -msgid "limit to heads" -msgstr "Ñамо върховете" +msgid "limit to branches" +msgstr "Ñамо клоните" + +msgid "deprecated synonym for --branches" +msgstr "оÑтарÑл Ñиноним на „--branches“" msgid "do not show peeled tags" msgstr "без проÑледÑване на непреките етикети" @@ -9206,10 +9327,6 @@ msgstr "git notes prune [ОПЦИЯ…]" msgid "Write/edit the notes for the following object:" msgstr "ЗапиÑване/редактиране на бележките за ÑÐ»ÐµÐ´Ð½Ð¸Ñ Ð¾Ð±ÐµÐºÑ‚:" -#, c-format -msgid "unable to start 'show' for object '%s'" -msgstr "дейÑтвието „show“ не може да Ñе изпълни за обект „%s“" - msgid "could not read 'show' output" msgstr "изведената Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ñ‚ дейÑтвието „show“ не може да Ñе прочете" @@ -11076,6 +11193,22 @@ msgstr "не е указан журнал Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð·Ð° изтриРmsgid "invalid ref format: %s" msgstr "неправилен формат на указател: %s" +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=ФОРМÐТ [--dry-run]" + +msgid "specify the reference format to convert to" +msgstr "указване на форма̀та за указател, към който да Ñе конвертира" + +msgid "perform a non-destructive dry-run" +msgstr "пробно изпълнение — без промÑна на данни" + +msgid "missing --ref-format=<format>" +msgstr "липÑва опциÑта --ref-format=ФОРМÐТ" + +#, c-format +msgid "repository already uses '%s' format" +msgstr "хранилището вече ползва форма̀та „%s“" + msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" "mirror=<fetch|push>] <name> <url>" @@ -11363,9 +11496,6 @@ msgstr "◠отдалечено хранилище „%s“" msgid " Fetch URL: %s" msgstr " ÐÐ´Ñ€ÐµÑ Ð·Ð° доÑтавÑне: %s" -msgid "(no URL)" -msgstr "(без адреÑ)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -11374,6 +11504,9 @@ msgstr "(без адреÑ)" msgid " Push URL: %s" msgstr " ÐÐ´Ñ€ÐµÑ Ð·Ð° изтлаÑкване: %s" +msgid "(no URL)" +msgstr "(без адреÑ)" + #, c-format msgid " HEAD branch: %s" msgstr " клон Ñочен от HEAD: %s" @@ -11483,10 +11616,6 @@ msgstr "запитване към адреÑите за изтлаÑкване, msgid "return all URLs" msgstr "извеждане на вÑички адреÑи" -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "не е зададен Ð°Ð´Ñ€ÐµÑ Ð·Ð° отдалеченото хранилище „%s“" - msgid "manipulate push URLs" msgstr "промÑна на адреÑите за изтлаÑкване" @@ -12511,12 +12640,12 @@ msgstr "Ðепознат алгоритъм за контролни Ñуми" msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d|--dereference]\n" -" [-s|--hash[=БРОЙ]] [--abbrev[=БРОЙ]] [--tags]\n" -" [--heads] [--] [ШÐБЛОÐ…]" +" [-s|--hash[=БРОЙ]] [--abbrev[=БРОЙ]] [--branches] [--tags]\n" +" [--] [ШÐБЛОÐ…]" msgid "" "git show-ref --verify [-q | --quiet] [-d | --dereference]\n" @@ -12539,11 +12668,11 @@ msgstr "указателÑÑ‚ не ÑъщеÑтвува" msgid "failed to look up reference" msgstr "Ñоченото от ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ Ð»Ð¸Ð¿Ñва" -msgid "only show tags (can be combined with heads)" -msgstr "извеждане на етикетите (може да Ñе комбинира Ñ Ð²ÑŠÑ€Ñ…Ð¾Ð²ÐµÑ‚Ðµ)" +msgid "only show tags (can be combined with branches)" +msgstr "извеждане на етикетите (може да Ñе комбинира Ñ â€ž--branches“ за клони)" -msgid "only show heads (can be combined with tags)" -msgstr "извеждане на върховете (може да Ñе комбинира Ñ ÐµÑ‚Ð¸ÐºÐµÑ‚Ð¸Ñ‚Ðµ)" +msgid "only show branches (can be combined with tags)" +msgstr "извеждане на клоните (може да Ñе комбинира Ñ â€ž--tags“ за етикети)" msgid "check for reference existence without resolving" msgstr "проверка за ÑъщеÑтвуване на указател без проÑледÑването му" @@ -13183,14 +13312,14 @@ msgstr "" "друг подмодул" #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "ÐеуÑпешно клониране на адреÑа „%s“ в Ð¿ÑŠÑ‚Ñ â€ž%s“ като подмодул" - -#, c-format msgid "directory not empty: '%s'" msgstr "директориÑта не е празна: „%s“" #, c-format +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "ÐеуÑпешно клониране на адреÑа „%s“ в Ð¿ÑŠÑ‚Ñ â€ž%s“ като подмодул" + +#, c-format msgid "could not get submodule directory for '%s'" msgstr "директориÑта на подмодула „%s“ не може да бъде получена" @@ -13555,9 +13684,11 @@ msgstr "причина за обновÑването" msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" "git tag [-a|-s|-u ИДЕÐТИФИКÐТОР_ÐÐ_КЛЮЧ] [-f] [-m СЪОБЩЕÐИЕ|-F ФÐЙЛ] [-e]\n" +" [(--trailer ЛЕКСЕМÐ[(=|:)СТОЙÐОСТ])…]\n" " ЕТИКЕТ [ПОДÐÐ’ÐÐЕ|ОБЕКТ]" msgid "git tag -d <tagname>..." @@ -14443,9 +14574,6 @@ msgstr "непозната заглавна чаÑÑ‚: %s%s (%d)" msgid "Repository lacks these prerequisite commits:" msgstr "Ð’ хранилището липÑват Ñледните необходими подаваниÑ:" -msgid "need a repository to verify a bundle" -msgstr "за проверката на пратка е необходимо хранилище" - msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -14856,6 +14984,9 @@ msgstr "Получаване на изтлаÑканото в хранилище msgid "Manage reflog information" msgstr "Управление на информациÑта в журнала на указателите" +msgid "Low-level access to refs" +msgstr "ДоÑтъп от ниÑко ниво до указателите" + msgid "Manage set of tracked repositories" msgstr "Управление на набор от Ñледени хранилища" @@ -15167,6 +15298,14 @@ msgid "commit-graph required commit data chunk missing or corrupted" msgstr "" "откъÑÑŠÑ‚ за данните необходими на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта липÑва или е повреден" +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "" +"изключване на филтрите на Блум за Ñлой „%s“ на гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта поради " +"неÑъвмеÑтими наÑтройки" + msgid "commit-graph has no base graphs chunk" msgstr "базовиÑÑ‚ Ð¾Ñ‚ÐºÑŠÑ Ð»Ð¸Ð¿Ñва в гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта" @@ -15298,6 +15437,14 @@ msgstr "" "опит за Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта, но наÑтройката „core.commitGraph“ е " "изключена" +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " +"(%d) is not supported" +msgstr "" +"опит за Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° гра̀фа Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта, но наÑтройката „commitGraph." +"changedPathsVersion“ (%d) не Ñе поддържа" + msgid "too many commits to write graph" msgstr "прекалено много Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ Ð·Ð° запиÑване на гра̀фа" @@ -17213,16 +17360,21 @@ msgstr "" msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v|--version] [-h|--help] [-C ПЪТ] [-c ИМЕ=СТОЙÐОСТ]\n" " [--exec-path[=ПЪТ]] [--html-path] [--man-path] [--info-path]\n" -" [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]\n" -" [--git-dir=ПЪТ] [--work-tree=ПЪТ] [--namespace=ИМЕ]\n" -" [--config-env=ИМЕ=ПРОМЕÐЛИВÐ_ÐÐ_СРЕДÐТÐ] КОМÐÐДР[ÐРГ…]" +" [-p|--paginate|-P|--no-pager] [--no-replace-objects] [--no-lazy-" +"fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=ПЪТ]\n" +" [--work-tree=ПЪТ] [--namespace=ИМЕ] [--config-" +"env=ИМЕ=ПРОМЕÐЛИВÐ_ÐÐ_СРЕДÐТÐ]\n" +" КОМÐÐДР[ÐРГ…]" msgid "" "'git help -a' and 'git help -g' list available subcommands and some\n" @@ -17576,13 +17728,13 @@ msgstr "" "За да изключите това предупреждение, изпълнете:\n" " git config advice.ignoredHook false" +msgid "not a git repository" +msgstr "не е хранилище на Git" + #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "опциÑта „--packfile“ изиÑква валидна контролна Ñума (а не „%s“)" -msgid "not a git repository" -msgstr "не е хранилище на Git" - #, c-format msgid "negative value for http.postBuffer; defaulting to %d" msgstr "" @@ -17594,6 +17746,9 @@ msgstr "Управлението на делегирането не Ñе подРmsgid "Public key pinning not supported with cURL < 7.39.0" msgstr "Задаването на поÑтоÑнен публичен ключ не Ñе поддържа от cURL < 7.39.0" +msgid "Unknown value for http.proactiveauth" +msgstr "Ðепозната ÑтойноÑÑ‚ за „http.proactiveauth“" + msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "„CURLSSLOPT_NO_REVOKE“ не Ñе поддържа от cURL < 7.44.0" @@ -17613,6 +17768,12 @@ msgstr "" "РеализациÑта на SSL не може да Ñе зададе да е „%s“, защото вече е зададена " "друга" +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "отказ от прочитане на биÑквитките от „http.cookiefile“: „-“" + +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "преÑкачане на „http.savecookies“ за празен „http.cookiefile“" + #, c-format msgid "" "unable to update url base from redirection:\n" @@ -17776,6 +17937,10 @@ msgid "quoted CRLF detected" msgstr "цитирани знаци CRLF" #, c-format +msgid "unable to format message: %s" +msgstr "Ñъобщението не може да Ñе форматира: %s" + +#, c-format msgid "Failed to merge submodule %s (not checked out)" msgstr "ÐеуÑпешно Ñливане на подмодула „%s“ (не е изтеглен)" @@ -17788,8 +17953,8 @@ msgid "Failed to merge submodule %s (commits not present)" msgstr "ÐеуÑпешно Ñливане на подмодула „%s“ (нÑма подаваниÑ)" #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" -msgstr "ÐеуÑпешно Ñливане на подмодула „%s“ (хранилището е Ñ Ð³Ñ€ÐµÑˆÐºÐ¸)" +msgid "error: failed to merge submodule %s (repository corrupt)" +msgstr "ГРЕШКÐ: неуÑпешно Ñливане на подмодула „%s“ (хранилището е Ñ Ð³Ñ€ÐµÑˆÐºÐ¸)" #, c-format msgid "Failed to merge submodule %s (commits don't follow merge-base)" @@ -17818,12 +17983,13 @@ msgstr "" "ÐеуÑпешно Ñливане на подмодула „%s“, но Ñа открити множеÑтво решениÑ:\n" "%s" -msgid "failed to execute internal merge" -msgstr "неуÑпешно вътрешно Ñливане" +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "ГРЕШКÐ: неуÑпешно вътрешно Ñливане за „%s“" #, c-format -msgid "unable to add %s to database" -msgstr "„%s“ не може да Ñе добави в базата от данни" +msgid "error: unable to add %s to database" +msgstr "ГРЕШКÐ: „%s“ не може да Ñе добави в базата от данни" #, c-format msgid "Auto-merging %s" @@ -17919,12 +18085,12 @@ msgstr "" "е изтрит в „%s“." #, c-format -msgid "cannot read object %s" -msgstr "обектът „%s“ не може да Ñе прочете" +msgid "error: cannot read object %s" +msgstr "ГРЕШКÐ: обектът „%s“ не може да Ñе прочете" #, c-format -msgid "object %s is not a blob" -msgstr "обектът „%s“ не е BLOB" +msgid "error: object %s is not a blob" +msgstr "ГРЕШКÐ: обектът „%s“ не е BLOB" #, c-format msgid "" @@ -18067,6 +18233,10 @@ msgstr "" "не е ÑÑно какво да Ñе прави Ñ Ð¾Ð±ÐµÐºÑ‚Ð° „%2$s“ (%3$s) Ñ Ð¿Ñ€Ð°Ð²Ð°Ì€ за доÑтъп „%1$06o“" #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "ÐеуÑпешно Ñливане на подмодула „%s“ (хранилището е Ñ Ð³Ñ€ÐµÑˆÐºÐ¸)" + +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "Превъртане на подмодула „%s“ до Ñледното подаване:" @@ -18108,6 +18278,13 @@ msgstr "" msgid "Failed to merge submodule %s (multiple merges found)" msgstr "ÐеуÑпешно Ñливане на подмодула „%s“ (открити Ñа множеÑтво ÑливаниÑ)" +msgid "failed to execute internal merge" +msgstr "неуÑпешно вътрешно Ñливане" + +#, c-format +msgid "unable to add %s to database" +msgstr "„%s“ не може да Ñе добави в базата от данни" + #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "Грешка: за да не Ñе изтрие неÑледениÑÑ‚ файл „%s“, Ñе запиÑва в „%s“." @@ -18210,6 +18387,14 @@ msgstr "" "КОÐФЛИКТ (преименуване/преименуване): „%s“ е преименуван на „%s“ в клон " "„%s“, а „%s“ е преименуван на „%s“ в „%s“" +#, c-format +msgid "cannot read object %s" +msgstr "обектът „%s“ не може да Ñе прочете" + +#, c-format +msgid "object %s is not a blob" +msgstr "обектът „%s“ не е BLOB" + msgid "modify" msgstr "промÑна" @@ -18294,11 +18479,6 @@ msgstr "редът не може да Ñе анализира: „%s“" msgid "malformed line: %s" msgstr "неправилен ред: „%s“." -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "" -"индекÑÑŠÑ‚ за множеÑтво пакети Ñе преÑкача, защото Ñумата за проверка не " -"Ñъвпада" - msgid "could not load pack" msgstr "пакетът не може да Ñе зареди" @@ -18306,6 +18486,11 @@ msgstr "пакетът не може да Ñе зареди" msgid "could not open index for %s" msgstr "индекÑÑŠÑ‚ за „%s“ не може да Ñе отвори" +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "" +"индекÑÑŠÑ‚ за множеÑтво пакети Ñе преÑкача, защото Ñумата за проверка не " +"Ñъвпада" + msgid "Adding packfiles to multi-pack-index" msgstr "ДобавÑне на пакетни файлове към Ð¸Ð½Ð´ÐµÐºÑ Ð·Ð° множеÑтво пакети" @@ -18946,6 +19131,17 @@ msgstr "обектът „%s“ не може да бъде анализиран msgid "hash mismatch %s" msgstr "разлика в контролната Ñума: „%s“" +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "повтарÑщ Ñе Ð·Ð°Ð¿Ð¸Ñ Ð¿Ñ€Ð¸ запазване на Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки: „%s“" + +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "опит за ÑъхранÑване на подаване, което не е избрано: „%s“" + +msgid "too many pseudo-merges" +msgstr "прекалено много пÑевдо ÑливаниÑ" + msgid "trying to write commit not in index" msgstr "опит за запиÑване на обект за подаване извън индекÑа" @@ -18973,6 +19169,22 @@ msgstr "" "повреден файл за Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки (прекалено е малък дори и за " "таблицата ÑÑŠÑ ÑъответÑтвиÑ)" +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "" +"повреден файл за Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки (прекалено е малък дори и за " +"заглавната чаÑÑ‚ на таблицата за пÑевдо ÑливаниÑта)" + +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "" +"повреден файл за Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки (прекалено е малък дори и за " +"таблицата Ñ Ð¿Ñевдо ÑливаниÑ)" + +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "" +"повреден Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки, таблицата Ñ Ð¿Ñевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ðµ " +"прекалено малка" + #, c-format msgid "duplicate entry in bitmap index: '%s'" msgstr "повтарÑщ Ñе Ð·Ð°Ð¿Ð¸Ñ Ð² Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° база битови маÑки: „%s“" @@ -19045,6 +19257,11 @@ msgid "unable to load pack: '%s', disabling pack-reuse" msgstr "" "пакетът не може да Ñе зареди: „%s“, преизползването на пакети Ñе изключва" +msgid "unable to compute preferred pack, disabling pack-reuse" +msgstr "" +"предпочитаниÑÑ‚ пакет не може да Ñе определи, преизползването на пакети Ñе " +"изключва" + #, c-format msgid "object '%s' not found in type bitmaps" msgstr "обектът „%s“ липÑва в битовата маÑка на видовете" @@ -19075,6 +19292,10 @@ msgid "mismatch in bitmap results" msgstr "различие в резултатите от битовите маÑки" #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "индекÑÑŠÑ‚ за пÑевдо Ñливане е извън диапазона (%<PRIu32> ≥ %<PRIuMAX>)" + +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "„%s“ липÑва в пакет „%s“ при отмеÑтване %<PRIuMAX>" @@ -19244,18 +19465,6 @@ msgstr "непознат флаг „%c“" msgid "unknown non-ascii option in string: `%s'" msgstr "непозната ÑтойноÑÑ‚ извън „ascii“ в низа: „%s“" -#, c-format -msgid "[=<%s>]" -msgstr "[=%s]" - -#, c-format -msgid "[<%s>]" -msgstr "[%s]" - -#, c-format -msgid " <%s>" -msgstr " %s" - msgid "..." msgstr "…" @@ -19468,6 +19677,9 @@ msgstr "не може да Ñе Ñъздаде нишка за изпълненРmsgid "unable to parse --pretty format" msgstr "аргументът към опциÑта „--pretty“ не може да Ñе анализира" +msgid "lazy fetching disabled; some objects may not be available" +msgstr "отложеното доÑтавÑне е изключено, нÑкои обекти може и да липÑват" + msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "хранилище-гарант: неуÑпешно Ñъздаване на Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð·Ð° доÑтавÑне" @@ -19494,6 +19706,66 @@ msgstr "object-info: Ñлед аргументите Ñе очаква Ð¸Ð·Ñ‡Ð¸Ñ msgid "Removing duplicate objects" msgstr "Изтриване на повтарÑщите Ñе обекти" +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "" +"регулÑрниÑÑ‚ израз за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ð·Ð° „%s“, не може да бъде зареден: „%s“" + +#, c-format +msgid "%s must be non-negative, using default" +msgstr "%s трÑбва да е неотрицателно, ще Ñе ползва Ñтандартната ÑтойноÑÑ‚" + +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "%s трÑбва да е между 0 и 1, ще Ñе ползва Ñтандартната ÑтойноÑÑ‚" + +#, c-format +msgid "%s must be positive, using default" +msgstr "%s трÑбва да е положително, ще Ñе ползва Ñтандартната ÑтойноÑÑ‚" + +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "в групата за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ â€ž%s“ липÑва задължителен шаблон" + +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "в групата за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ â€ž%s“ има неÑтабилен праг пред ÑтабилниÑ" + +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "" +"регулÑрниÑÑ‚ израз за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ð² ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð» Ñъдържа повече " +"от макÑимално поддържаните прихващащи групи (max=%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"опит за четене на разширено пÑевдо Ñливане извън диапазона (%<PRIuMAX> ≥ " +"%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"прекалено кратък Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° разширено пÑевдо Ñливане (%<PRIuMAX> ≥ %<PRIuMAX>)" + +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "липÑва пÑевдо Ñливане за подаване „%s“ при отмеÑтване %<PRIuMAX>" + +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "" +"четене за група за пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ð·Ð°Ð´ границите (%<PRIu32> ≥ %<PRIu32>)" + +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "четене зад границите (%<PRIuMAX> ≥ %<PRIuMAX>)" + +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "таблицата Ñ Ñ€Ð°Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ‚Ðµ пÑевдо ÑÐ»Ð¸Ð²Ð°Ð½Ð¸Ñ Ð·Ð° „%s“ не може да Ñе прочете" + msgid "could not start `log`" msgstr "командата за журнала Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ â€žlog“ не може да Ñе Ñтартира" @@ -20077,14 +20349,13 @@ msgid "" "\n" "\tgit branch -m <name>\n" msgstr "" -"ПървоначалниÑÑ‚ клон ще Ñе казва „%s“. Това може да Ñе променÑ. Може да " -"зададете\n" +"ПървоначалниÑÑ‚ клон ще Ñе казва „%s“. Това може да Ñе променÑ. Може да зададете\n" "наÑтройката и да Ñпрете това Ñъобщение. За това изпълнете:\n" "\n" " git config --global init.defaultBranch ИМЕ\n" "\n" "ЧеÑто ползвани варианти вмеÑто „master“ Ñа „main“, „trunk“ и „development“.\n" -"За да преименувата току що Ñъздаден клон, изпълнете:\n" +"За да преименувате току що Ñъздаден клон, изпълнете:\n" "\n" " git branch -m ИМЕ\n" @@ -20112,11 +20383,20 @@ msgstr "журналът Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта за ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€ž%s msgid "log for %s is empty" msgstr "журналът Ñ Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñта за ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ â€ž%s“ е празен" +msgid "refusing to force and skip creation of reflog" +msgstr "" +"принудителна Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð±ÐµÐ· Ñъздаване на журнал на указателите нÑма да Ñе " +"приеме" + #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "указател не може да Ñе обнови Ñ Ð³Ñ€ÐµÑˆÐ½Ð¾ име „%s“" #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "пÑевдо указателÑÑ‚ „%s“ нÑма да Ñе обнови" + +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "неуÑпешно обновÑване на ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ»Ñ (update_ref) „%s“: %s" @@ -20147,6 +20427,25 @@ msgid "could not delete references: %s" msgstr "Указателите не може да бъдат изтрити: %s" #, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "Пробната Ð¼Ð¸Ð³Ñ€Ð°Ñ†Ð¸Ñ Ð½Ð° указатели завърши, резултатите Ñа в „%s“\n" + +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "временната Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð·Ð° Ð¼Ð¸Ð³Ñ€Ð°Ñ†Ð¸Ñ â€ž%s“ не може да Ñе изтрие" + +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "мигрираните указатели Ñа в „%s“" + +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "" +"указателÑÑ‚ „%s“ не може да Ñе заключи: очакваше Ñе файл Ñ ÑƒÐºÐ°Ð·Ð°Ñ‚ÐµÐ» Ñ Ñ†ÐµÐ» " +"„%s“, но вмеÑто това е обикновен указател" + +#, c-format msgid "refname is dangerous: %s" msgstr "опаÑно име на указател: %s" @@ -20694,9 +20993,7 @@ msgstr "„%s“ ÑъщеÑтвува и не е Ñимволна връзка" msgid "" "--merge requires one of the pseudorefs MERGE_HEAD, CHERRY_PICK_HEAD, " "REVERT_HEAD or REBASE_HEAD" -msgstr "" -"„--merge“ изиÑква нÑкой от пÑевдоуказателите „MERGE_HEAD“, " -"„CHERRY_PICK_HEAD“, „REVERT_HEAD“ или „REBASE_HEAD“" +msgstr "„--merge“ изиÑква нÑкой от пÑевдо указателите „MERGE_HEAD“, „CHERRY_PICK_HEAD“, „REVERT_HEAD“ или „REBASE_HEAD“" #, c-format msgid "could not get commit for --ancestry-path argument %s" @@ -21357,6 +21654,56 @@ msgstr "" "командата „update-ref“ изиÑква пълно име на указател, напр. „refs/heads/%s“" #, c-format +msgid "'%s' does not accept merge commits" +msgstr "„%s“ не приема Ð¿Ð¾Ð´Ð°Ð²Ð°Ð½Ð¸Ñ ÑÑŠÑ Ñливане" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"„pick“ не приема подаване ÑÑŠÑ Ñливане. Ðко иÑкате да приложите\n" +"Ñливането наново изпълнате:\n" +"\n" +" git merge -C ПОДÐÐ’ÐÐЕ" + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"„reword“ не приема подаване ÑÑŠÑ Ñливане. Ðко иÑкате да приложите\n" +"Ñливането наново и да промените Ñъобщението при подаване, изпълнете\n" +"\n" +" git merge -C ПОДÐÐ’ÐÐЕ" + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"„edit“ не приема подаване ÑÑŠÑ Ñливане. Ðко иÑкате да приложите\n" +"Ñливането наново, изпълнете\n" +"\n" +" git merge -C ПОДÐÐ’ÐÐЕ\n" +"\n" +"а Ñлед него задайте „break“, за да получите контрол и да изпълнете:\n" +"\n" +" git commit --amend && git rebase --continue" + +msgid "cannot squash merge commit into another commit" +msgstr "подаване ÑÑŠÑ Ñливане не може да Ñе вкара в друго" + +#, c-format msgid "invalid command '%.*s'" msgstr "неправилна команда „%.*s“" @@ -21483,9 +21830,8 @@ msgstr "" msgid "cannot read HEAD" msgstr "указателÑÑ‚ „HEAD“ не може да бъде прочетен" -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "„%s“ не може да Ñе копира като „%s“" +msgid "could not write commit message file" +msgstr "файлът ÑÑŠÑ Ñъобщението за подаване не може да бъде запиÑан" #, c-format msgid "" @@ -21894,6 +22240,18 @@ msgstr "процеÑÑŠÑ‚ не може да Ñе върне към предишРmsgid "failed to stat '%*s%s%s'" msgstr "не може да бъде получена Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€ÐµÐ· „stat“ за „%*s%s%s“" +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"заÑечено е проблемно притежание на хранилището „%s“\n" +"%sЗа да зададете изключение за тази директориÑ, изпълнете:\n" +"\n" +" git config --global --add safe.directory %s" + msgid "Unable to read current working directory" msgstr "Текущата работна Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ðµ може да бъде прочетена" @@ -21918,18 +22276,6 @@ msgstr "" "„GIT_DISCOVERY_ACROSS_FILESYSTEM“ не е зададена." #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"заÑечено е проблемно притежание на хранилището „%s“\n" -"%sЗа да зададете изключение за тази директориÑ, изпълнете:\n" -"\n" -" git config --global --add safe.directory %s" - -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" msgstr "" "голото хранилище „%s“ не може да Ñе ползва („safe.bareRepository“ е „%s“)" @@ -22241,6 +22587,14 @@ msgid "submodule git dir '%s' is inside git dir '%.*s'" msgstr "„%s“ (Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ñ Ð½Ð° подмодул) е в директориÑта на git: „%.*s“" #, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "„%.*s“ в Ð¿ÑŠÑ‚Ñ Ð·Ð° подмодул „%s“ не трÑбва да е Ñимволна връзка" + +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "пътÑÑ‚ за подмодул „%s“ не трÑбва да е Ñимволна връзка" + +#, c-format msgid "" "relocate_gitdir for submodule '%s' with more than one worktree not supported" msgstr "" @@ -22279,10 +22633,6 @@ msgstr "не може да бъде получена Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡Ñ€Ðµ msgid "no remote configured to get bundle URIs from" msgstr "не е наÑтроено отдалечено хранилище за ÑпиÑъците Ñ Ð°Ð´Ñ€ÐµÑи на пратки" -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "не е зададен никакъв Ð°Ð´Ñ€ÐµÑ Ð·Ð° отдалеченото хранилище„%s“" - msgid "could not get the bundle-uri list" msgstr "ÑпиÑъкът Ñ Ð°Ð´Ñ€ÐµÑи на пратки не може да Ñе получи" @@ -22613,9 +22963,7 @@ msgid "bundle-uri operation not supported by protocol" msgstr "операциÑта „bundle-uri“ (адреÑи на пратки) не Ñе поддържа от протокола" msgid "could not retrieve server-advertised bundle-uri list" -msgstr "" -"ÑпъÑъкът Ñ Ð°Ð´Ñ€ÐµÑи на пратки обÑвени за налични от Ñървъра не може да Ñе " -"получи " +msgstr "ÑпиÑъкът Ñ Ð°Ð´Ñ€ÐµÑи на пратки обÑвени за налични от Ñървъра не може да Ñе получи " msgid "operation not supported by protocol" msgstr "опциÑта не Ñе поддържа от протокола" @@ -23379,7 +23727,7 @@ msgid "" "but the results were cached, and subsequent runs may be faster." msgstr "" "ИзброÑването на неÑледените файлове отне %.2f Ñекунди, но\n" -"резултатите Ñа запомнени и може да забързат поÑледващиге изброÑваниÑ." +"резултатите Ñа запомнени и може да забързат поÑледващите изброÑваниÑ." #, c-format msgid "It took %.2f seconds to enumerate untracked files." @@ -23785,24 +24133,24 @@ msgid "Failed to send %s\n" msgstr "„%s“ не може да бъде изпратен\n" #, perl-format -msgid "Dry-Sent %s\n" -msgstr "Проба за изпращане на „%s“\n" +msgid "Dry-Sent %s" +msgstr "Проба за изпращане на „%s“" #, perl-format -msgid "Sent %s\n" -msgstr "Изпращане на „%s“\n" +msgid "Sent %s" +msgstr "Изпращане на „%s“" -msgid "Dry-OK. Log says:\n" -msgstr "УÑпех при пробата. От журнала:\n" +msgid "Dry-OK. Log says:" +msgstr "УÑпех при пробата. От журнала:" -msgid "OK. Log says:\n" -msgstr "УÑпех. От журнала:\n" +msgid "OK. Log says:" +msgstr "УÑпех. От журнала:" msgid "Result: " msgstr "Резултат: " -msgid "Result: OK\n" -msgstr "Резултат: уÑпех\n" +msgid "Result: OK" +msgstr "Резултат: уÑпех" #, perl-format msgid "can't open file %s" @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-26 16:16+0200\n" -"PO-Revision-Date: 2024-04-26 16:22+0200\n" +"POT-Creation-Date: 2024-07-19 19:21+0200\n" +"PO-Revision-Date: 2024-07-19 19:25+0200\n" "Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n" "Language-Team: German\n" "Language: de\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" -"X-Generator: Poedit 3.4.1\n" +"X-Generator: Poedit 3.4.4\n" #, c-format msgid "Huh (%s)?" @@ -582,6 +582,10 @@ msgstr "" "p - aktuellen Patch-Block anzeigen\n" "? - Hilfe anzeigen\n" +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "Es wird nur ein Buchstabe erwartet, '%s' erhalten" + msgid "No previous hunk" msgstr "Kein vorheriger Patch-Block" @@ -630,9 +634,19 @@ msgstr "In %d Patch-Block aufgeteilt." msgid "Sorry, cannot edit this hunk" msgstr "Entschuldigung, kann diesen Patch-Block nicht bearbeiten" +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "Unbekannter Befehl '%s' (für Hilfe '?' verwenden)" + msgid "'git apply' failed" msgstr "'git apply' schlug fehl" +msgid "No changes." +msgstr "Keine Änderungen." + +msgid "Only binary files changed." +msgstr "Nur Binärdateien geändert." + #, c-format msgid "" "\n" @@ -1517,6 +1531,10 @@ msgstr "ignoriere übermäßig große gitattributes-Datei '%s'" msgid "ignoring overly large gitattributes blob '%s'" msgstr "ignoriere übermäßig großen gitattribute-Blob '%s'" +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "" +"kann nicht --attr-source oder GIT_ATTR_SOURCE ohne Repository verwenden" + msgid "bad --attr-source or GIT_ATTR_SOURCE" msgstr "ungültiges --attr-source oder GIT_ATTR_SOURCE" @@ -1838,13 +1856,6 @@ msgid "Unstaged changes after refreshing the index:" msgstr "" "Nicht zum Commit vorgemerkte Änderungen nach Aktualisierung der Staging-Area:" -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"Die Einstellung add.interactive.useBuiltin wurde entfernt!\n" -"Siehe den Eintrag in 'git help config' für Details." - msgid "could not read the index" msgstr "konnte den Index nicht lesen" @@ -2302,6 +2313,9 @@ msgstr "Patch-Operation abbrechen, aber HEAD an aktueller Stelle belassen" msgid "show the patch being applied" msgstr "den Patch, der gerade angewendet wird, anzeigen" +msgid "try to apply current patch again" +msgstr "den aktuellen Patch erneut versuchen anzuwenden" + msgid "record the empty patch as an empty commit" msgstr "leerer Patch als leeren Commit gespeichert" @@ -2357,9 +2371,6 @@ msgstr "git apply [<Optionen>] [<Patch>...]" msgid "could not redirect output" msgstr "konnte Ausgabe nicht umleiten" -msgid "git archive: Remote with no URL" -msgstr "git archive: Externes Archiv ohne URL" - msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "git archive: ACK/NAK erwartet, Flush-Paket bekommen" @@ -3282,6 +3293,9 @@ msgstr "Um ein Paket zu erstellen wird ein Repository benötigt." msgid "do not show bundle details" msgstr "Keine Bundle-Details anzeigen" +msgid "need a repository to verify a bundle" +msgstr "um ein Paket zu überprüfen wird ein Repository benötigt" + #, c-format msgid "%s is okay\n" msgstr "%s ist in Ordnung\n" @@ -4324,6 +4338,14 @@ msgid "failed to unlink '%s'" msgstr "Konnte '%s' nicht entfernen." #, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "Hardlink bei '%s' kann nicht geprüft werden" + +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "Hardlink unterscheidet sich von der Quelle bei '%s'" + +#, c-format msgid "failed to create link '%s'" msgstr "Konnte Verweis '%s' nicht erstellen" @@ -5180,15 +5202,52 @@ msgstr "" "voll und Ihr Kontingent nicht aufgebraucht ist und führen Sie\n" "anschließend \"git restore --staged :/\" zur Wiederherstellung aus." -msgid "git config [<options>]" -msgstr "git config [<Optionen>]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "git config list [<Datei-Option>] [<Anzeige-Option>] [--includes]" -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "nicht erkanntes --type Argument, %s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [<Datei-Option>] [<Anzeige-Option>] [--includes] [--all] [--" +"regexp=<Regex>] [--value=<Wert>] [--fixed-value] [--default=<Standardwert>] " +"<Name>" -msgid "only one type at a time" -msgstr "nur ein Typ erlaubt" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [<Datei-Option>] [--type=<Typ>] [--all] [--value=<Wert>] [--" +"fixed-value] <Name> <Wert>" + +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [<Datei-Option>] [--all] [--value=<Wert>] [--fixed-value] " +"<Name> <Wert>" + +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "git config rename-section [<Datei-Option>] <alter-Name> <neuer-Name>" + +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [<Datei-Option>] <Name>" + +msgid "git config edit [<file-option>]" +msgstr "git config edit [<Datei-Option>]" + +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "" +"git config [<Datei-Option>] --get-colorbool <Name> [<Standard-Ausgabe-ist-" +"Terminal>]" + +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [<Datei-Option>] [--type=<Typ>] [--comment=<Nachricht>] [--" +"all] [--value=<Wert>] [--fixed-value] <Name> <Wert>" msgid "Config file location" msgstr "Ort der Konfigurationsdatei" @@ -5214,55 +5273,6 @@ msgstr "Blob-Id" msgid "read config from given blob object" msgstr "Konfiguration von angegebenem Blob-Objekt lesen" -msgid "Action" -msgstr "Aktion" - -msgid "get value: name [value-pattern]" -msgstr "Wert zurückgeben: Name [Wert-Muster]" - -msgid "get all values: key [value-pattern]" -msgstr "alle Werte zurückgeben: Schlüssel [Wert-Muster]" - -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "Werte für den regulären Ausdruck zurückgeben: Name-Regex [Wert-Muster]" - -msgid "get value specific for the URL: section[.var] URL" -msgstr "Wert spezifisch für eine URL zurückgeben: section[.var] URL" - -msgid "replace all matching variables: name value [value-pattern]" -msgstr "alle passenden Variablen ersetzen: Name Wert [Wert-Muster] " - -msgid "add a new variable: name value" -msgstr "neue Variable hinzufügen: Name Wert" - -msgid "remove a variable: name [value-pattern]" -msgstr "eine Variable entfernen: Name [Wert-Muster]" - -msgid "remove all matches: name [value-pattern]" -msgstr "alle Übereinstimmungen entfernen: Name [Wert-Muster]" - -msgid "rename section: old-name new-name" -msgstr "eine Sektion umbenennen: alter-Name neuer-Name" - -msgid "remove a section: name" -msgstr "eine Sektion entfernen: Name" - -msgid "list all" -msgstr "alles auflisten" - -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "" -"nutze String-Gleichheit beim Vergleich von Werten mit dem 'Wert-Muster'" - -msgid "open an editor" -msgstr "einen Editor öffnen" - -msgid "find the color configured: slot [default]" -msgstr "die konfigurierte Farbe finden: Slot [Standard]" - -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "die Farbeinstellung finden: Slot [Standard-Ausgabe-ist-Terminal]" - msgid "Type" msgstr "Typ" @@ -5290,8 +5300,8 @@ msgstr "Wert ist ein Pfad (Datei oder Verzeichnisname)" msgid "value is an expiry date" msgstr "Wert ist ein Verfallsdatum" -msgid "Other" -msgstr "Sonstiges" +msgid "Display options" +msgstr "Anzeigeoptionen" msgid "terminate values with NUL byte" msgstr "schließt Werte mit NUL-Byte ab" @@ -5299,9 +5309,6 @@ msgstr "schließt Werte mit NUL-Byte ab" msgid "show variable names only" msgstr "nur Variablennamen anzeigen" -msgid "respect include directives on lookup" -msgstr "beachtet \"include\"-Direktiven beim Nachschlagen" - msgid "show origin of config (file, standard input, blob, command line)" msgstr "" "Ursprung der Konfiguration anzeigen (Datei, Standard-Eingabe, Blob, " @@ -5312,15 +5319,15 @@ msgstr "" "Zeige Geltungsbereich der Konfiguration (Arbeitsverzeichnis, lokal, global, " "systemweit, Befehl)" -msgid "value" -msgstr "Wert" +msgid "show config keys in addition to their values" +msgstr "Konfigurationsschlüssel zusätzlich zu dessen Werten anzeigen" -msgid "with --get, use default value when missing entry" -msgstr "mit --get, benutze den Standardwert, wenn der Eintrag fehlt" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "nicht erkanntes --type Argument, %s" -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "" -"menschenlesbare Kommentarzeichenfolge (# wird bei Bedarf vorangestellt)" +msgid "only one type at a time" +msgstr "nur ein Typ erlaubt" #, c-format msgid "wrong number of arguments, should be %d" @@ -5398,47 +5405,73 @@ msgstr "" "lesen Sie die Sektion \"CONFIGURATION FILE\" in \"git help worktree\" für " "Details" -msgid "--get-color and variable type are incoherent" -msgstr "Angabe von --get-color und Variablentyp sind ungültig." +msgid "Other" +msgstr "Sonstiges" -msgid "only one action at a time" -msgstr "Nur eine Aktion erlaubt." +msgid "respect include directives on lookup" +msgstr "beachtet \"include\"-Direktiven beim Nachschlagen" -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "--name-only ist nur anwendbar auf --list oder --get-regexp" +#, c-format +msgid "unable to read config file '%s'" +msgstr "Konnte Konfigurationsdatei '%s' nicht lesen." -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" -msgstr "" -"--show-origin ist nur anwendbar auf --get, --get-all, --get-regexp und --list" +msgid "error processing config file(s)" +msgstr "Fehler beim Verarbeiten der Konfigurationsdatei(en)." -msgid "--default is only applicable to --get" -msgstr "--default ist nur anwendbar auf --get" +msgid "Filter options" +msgstr "Filter-Optionen" -msgid "--comment is only applicable to add/set/replace operations" -msgstr "" -"--comment darf nur für die Operationen add/set/replace verwendet werden" +msgid "return all values for multi-valued config options" +msgstr "alle Werte für mehrwertige Konfigurationsoptionen zurückgeben" + +msgid "interpret the name as a regular expression" +msgstr "den Namen als regulären Ausdruck interpretieren" + +msgid "show config with values matching the pattern" +msgstr "Anzeige von Konfiguration mit Werten, die dem Muster entsprechen" + +msgid "use string equality when comparing values to value pattern" +msgstr "String-Gleichheit beim Vergleich von Werten mit Wertmustern verwenden" + +msgid "URL" +msgstr "URL" + +msgid "show config matching the given URL" +msgstr "Konfiguration für die angegebene URL anzeigen" + +msgid "value" +msgstr "Wert" + +msgid "use default value when missing entry" +msgstr "Standardwert verwenden, wenn Eintrag fehlt" msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value wird nur zusammen mit 'Wert-Muster' angewendet" -#, c-format -msgid "unable to read config file '%s'" -msgstr "Konnte Konfigurationsdatei '%s' nicht lesen." +msgid "--default= cannot be used with --all or --url=" +msgstr "--default= kann nicht mit --all oder --url= verwendet werden" -msgid "error processing config file(s)" -msgstr "Fehler beim Verarbeiten der Konfigurationsdatei(en)." +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "--url= kann nicht mit --all, --regexp oder --value verwendet werden" -msgid "editing stdin is not supported" -msgstr "Das Bearbeiten der Standard-Eingabe wird nicht unterstützt." +msgid "Filter" +msgstr "Filter" -msgid "editing blobs is not supported" -msgstr "Das Bearbeiten von Blobs wird nicht unterstützt." +msgid "replace multi-valued config option with new value" +msgstr "mehrwertige Konfigurationsoption durch einen neuen Wert ersetzen" -#, c-format -msgid "cannot create configuration file %s" -msgstr "Konnte Konfigurationsdatei '%s' nicht erstellen." +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "" +"menschenlesbare Kommentarzeichenfolge (# wird bei Bedarf vorangestellt)" + +msgid "add a new line without altering any existing values" +msgstr "eine neue Zeile hinzufügen, ohne bestehende Werte zu ändern" + +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "--fixed-value gilt nur mit --value=<pattern>" + +msgid "--append cannot be used with --value=<pattern>" +msgstr "--append kann nicht mit --value=<pattern> verwendet werden" #, c-format msgid "" @@ -5453,6 +5486,86 @@ msgstr "" msgid "no such section: %s" msgstr "Sektion nicht gefunden: %s" +msgid "editing stdin is not supported" +msgstr "Das Bearbeiten der Standard-Eingabe wird nicht unterstützt." + +msgid "editing blobs is not supported" +msgstr "Das Bearbeiten von Blobs wird nicht unterstützt." + +#, c-format +msgid "cannot create configuration file %s" +msgstr "Konnte Konfigurationsdatei '%s' nicht erstellen." + +msgid "Action" +msgstr "Aktion" + +msgid "get value: name [<value-pattern>]" +msgstr "Wert zurückgeben: Name [<Wert-Muster>]" + +msgid "get all values: key [<value-pattern>]" +msgstr "alle Werte zurückgeben: Schlüssel [<Wert-Muster>]" + +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "Werte für den regulären Ausdruck zurückgeben: Name-Regex <Wert-Muster>" + +msgid "get value specific for the URL: section[.var] URL" +msgstr "Wert spezifisch für eine URL zurückgeben: section[.var] URL" + +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "alle passenden Variablen ersetzen: Name Wert [<Wert-Muster>]" + +msgid "add a new variable: name value" +msgstr "neue Variable hinzufügen: Name Wert" + +msgid "remove a variable: name [<value-pattern>]" +msgstr "eine Variable entfernen: Name [<Wert-Muster>]" + +msgid "remove all matches: name [<value-pattern>]" +msgstr "alle Treffer entfernen: Name [<Wert-Muster>]" + +msgid "rename section: old-name new-name" +msgstr "eine Sektion umbenennen: alter-Name neuer-Name" + +msgid "remove a section: name" +msgstr "eine Sektion entfernen: Name" + +msgid "list all" +msgstr "alles auflisten" + +msgid "open an editor" +msgstr "einen Editor öffnen" + +msgid "find the color configured: slot [<default>]" +msgstr "die konfigurierte Farbe finden: Slot [<Standard>]" + +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "die Farbeinstellung finden: Slot [Standard-Ausgabe-ist-Terminal]" + +msgid "with --get, use default value when missing entry" +msgstr "mit --get, benutze den Standardwert, wenn der Eintrag fehlt" + +msgid "--get-color and variable type are incoherent" +msgstr "Angabe von --get-color und Variablentyp sind ungültig." + +msgid "no action specified" +msgstr "keine Aktion angegeben" + +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "--name-only ist nur anwendbar auf --list oder --get-regexp" + +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "" +"--show-origin ist nur anwendbar auf --get, --get-all, --get-regexp und --list" + +msgid "--default is only applicable to --get" +msgstr "--default ist nur anwendbar auf --get" + +msgid "--comment is only applicable to add/set/replace operations" +msgstr "" +"--comment darf nur für die Operationen add/set/replace verwendet werden" + msgid "print sizes in human readable format" msgstr "gibt Größenangaben in menschenlesbaren Format aus" @@ -6306,6 +6419,9 @@ msgstr "Konfiguration" msgid "config key storing a list of repository paths" msgstr "Konfigurationsschlüssel für eine Liste von Repository-Pfaden" +msgid "keep going even if command fails in a repository" +msgstr "weiterarbeiten, auch wenn der Befehl in einem Repository fehlschlägt" + msgid "missing --config=<config>" msgstr "Option --config=<Konfiguration> fehlt" @@ -7781,8 +7897,11 @@ msgstr "die Serie als n-te Fassung kennzeichnen" msgid "max length of output filename" msgstr "maximale Länge des Dateinamens für die Ausgabe" -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "[RFC PATCH] statt [PATCH] verwenden" +msgid "rfc" +msgstr "rfc" + +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "<rfc> (standardmäßig 'RFC') vor 'PATCH' hinzufügen" msgid "cover-from-description-mode" msgstr "Modus für Erstellung des Deckblattes aus der Beschreibung" @@ -8058,11 +8177,11 @@ msgstr "" "verwendet werden" msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<Programm>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<Programm>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<Schlüssel>]\n" " [--symref] [<Repository> [<Muster>...]]" @@ -8078,8 +8197,11 @@ msgstr "Pfad zu \"git-upload-pack\" auf der Gegenseite" msgid "limit to tags" msgstr "auf Tags einschränken" -msgid "limit to heads" -msgstr "auf Branches einschränken" +msgid "limit to branches" +msgstr "Beschränkung auf Branches" + +msgid "deprecated synonym for --branches" +msgstr "veraltetes Synonym für --branches" msgid "do not show peeled tags" msgstr "keine Tags anzeigen, die andere Tags enthalten" @@ -10805,6 +10927,22 @@ msgstr "Kein Reflog zum Löschen angegeben." msgid "invalid ref format: %s" msgstr "Ungültiges Format für Referenzen: %s" +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=<Format> [--dry-run]" + +msgid "specify the reference format to convert to" +msgstr "das Referenzformat angeben, in das konvertiert werden soll" + +msgid "perform a non-destructive dry-run" +msgstr "einen zerstörungsfreien Trockenlauf durchführen" + +msgid "missing --ref-format=<format>" +msgstr "fehlendes --ref-format=<Format>" + +#, c-format +msgid "repository already uses '%s' format" +msgstr "das Repository verwendet bereits das Format '%s'" + msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" "mirror=<fetch|push>] <name> <url>" @@ -11092,9 +11230,6 @@ msgstr "* Remote-Repository %s" msgid " Fetch URL: %s" msgstr " URL zum Abholen: %s" -msgid "(no URL)" -msgstr "(keine URL)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -11103,6 +11238,9 @@ msgstr "(keine URL)" msgid " Push URL: %s" msgstr " URL zum Versenden: %s" +msgid "(no URL)" +msgstr "(keine URL)" + #, c-format msgid " HEAD branch: %s" msgstr " Hauptbranch: %s" @@ -11212,10 +11350,6 @@ msgstr "nur URLs für Push ausgeben" msgid "return all URLs" msgstr "alle URLs ausgeben" -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "Keine URLs für Remote-Repository '%s' konfiguriert." - msgid "manipulate push URLs" msgstr "URLs für \"push\" manipulieren" @@ -12235,12 +12369,12 @@ msgstr "Unbekannter Hash-Algorithmus" msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<Muster>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<Muster>...]" msgid "" "git show-ref --verify [-q | --quiet] [-d | --dereference]\n" @@ -12263,11 +12397,11 @@ msgstr "Referenz nicht vorhanden" msgid "failed to look up reference" msgstr "Fehler beim Nachschlagen der Referenz" -msgid "only show tags (can be combined with heads)" -msgstr "nur Tags anzeigen (kann mit \"heads\" kombiniert werden)" +msgid "only show tags (can be combined with branches)" +msgstr "nur Tags anzeigen (kann mit Branches kombiniert werden)" -msgid "only show heads (can be combined with tags)" -msgstr "nur Branches anzeigen (kann mit \"tags\" kombiniert werden)" +msgid "only show branches (can be combined with tags)" +msgstr "nur Branches anzeigen (kann mit Tags kombiniert werden)" msgid "check for reference existence without resolving" msgstr "Prüfung auf Vorhandensein einer Referenz, ohne diese aufzulösen" @@ -12919,14 +13053,14 @@ msgstr "" "verweigert." #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "Klonen von '%s' in Submodul-Pfad '%s' fehlgeschlagen." - -#, c-format msgid "directory not empty: '%s'" msgstr "Verzeichnis ist nicht leer: '%s'" #, c-format +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "Klonen von '%s' in Submodul-Pfad '%s' fehlgeschlagen." + +#, c-format msgid "could not get submodule directory for '%s'" msgstr "Konnte Submodul-Verzeichnis '%s' nicht finden." @@ -13297,9 +13431,11 @@ msgstr "Grund für die Aktualisierung" msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" "git tag [-a | -s | -u <Key-ID>] [-f] [-m <Beschreibung> | -F <Datei>] [-e]\n" +" [(--trailer <Token>[(=|:)<Wert>])...]\n" " <Tagname> [<Commit> | <Objekt>]" msgid "git tag -d <tagname>..." @@ -14189,9 +14325,6 @@ msgstr "nicht erkannter Kopfbereich: %s%s (%d)" msgid "Repository lacks these prerequisite commits:" msgstr "Dem Repository fehlen folgende vorausgesetzte Commits:" -msgid "need a repository to verify a bundle" -msgstr "um ein Paket zu überprüfen wird ein Repository benötigt" - msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -14615,6 +14748,9 @@ msgstr "Empfangen was in das Repository übertragen wurde" msgid "Manage reflog information" msgstr "Reflog Informationen verwalten" +msgid "Low-level access to refs" +msgstr "Low-Level Zugang zu Referenzen" + msgid "Manage set of tracked repositories" msgstr "Menge von hinterlegten Repositories verwalten" @@ -14925,6 +15061,14 @@ msgid "commit-graph required commit data chunk missing or corrupted" msgstr "" "Commit-Graph erforderlicher Commit-Daten Chunk fehlt oder ist beschädigt" +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "" +"deaktiviere Bloom-Filter für die Commit-Graph-Ebene '%s' aufgrund " +"inkompatibler Einstellungen" + msgid "commit-graph has no base graphs chunk" msgstr "Commit-Graph hat keinen Basis-Graph-Chunk" @@ -15052,6 +15196,14 @@ msgstr "" "versuche einen Commit-Graph zu schreiben, aber 'core.commitGraph' ist " "deaktiviert" +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " +"(%d) is not supported" +msgstr "" +"versuche, einen Commit-Graphen zu schreiben, aber 'commitGraph." +"changedPathsVersion' (%d) wird nicht unterstützt" + msgid "too many commits to write graph" msgstr "zu viele Commits zum Schreiben des Graphen" @@ -16941,17 +17093,21 @@ msgstr "" msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v | --version] [-h | --help] [-C <Pfad>] [-c <Name>=<Wert>]\n" " [--exec-path[=<Pfad>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<Pfad>] [--work-tree=<Pfad>] [--namespace=<Name>]\n" -" [--config-env=<Name>=<Umgebungsvariable>] <Befehl> [<Argumente>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<Pfad>]\n" +" [--work-tree=<Pfad>] [--namespace=<Name>] [--config-" +"env=<Name>=<Umgebungsvariable>]\n" +" <Befehl> [<Argumente>]" msgid "" "'git help -a' and 'git help -g' list available subcommands and some\n" @@ -17293,13 +17449,13 @@ msgstr "" "Sie können diese Warnung mit `git config advice.ignoredHook false` " "deaktivieren." +msgid "not a git repository" +msgstr "kein Git-Repository" + #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "Argument für --packfile muss ein gültiger Hash sein ('%s' erhalten)" -msgid "not a git repository" -msgstr "kein Git-Repository" - #, c-format msgid "negative value for http.postBuffer; defaulting to %d" msgstr "negativer Wert für http.postBuffer; benutze Standardwert %d" @@ -17312,6 +17468,9 @@ msgstr "" "Das Anheften des öffentlichen Schlüssels wird mit cURL < 7.39.0 nicht " "unterstützt" +msgid "Unknown value for http.proactiveauth" +msgstr "Unbekannter Wert für http.proactiveauth" + msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "CURLSSLOPT_NO_REVOKE wird mit cURL < 7.44.0 nicht unterstützt." @@ -17328,6 +17487,12 @@ msgstr "" msgid "Could not set SSL backend to '%s': already set" msgstr "Konnte SSL-Backend nicht zu '%s' setzen: bereits gesetzt" +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "Lesen von Cookies von http.cookiefile '-' verweigert" + +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "http.savecookies wird bei leerem http.cookiefile ignoriert" + #, c-format msgid "" "unable to update url base from redirection:\n" @@ -17505,9 +17670,10 @@ msgid "Failed to merge submodule %s (commits not present)" msgstr "Fehler beim Merge von Submodul %s (Commits nicht vorhanden)." #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" +msgid "error: failed to merge submodule %s (repository corrupt)" msgstr "" -"Submodul %s konnte nicht zusammengeführt werden (Repository beschädigt)" +"Fehler: Submodul %s konnte nicht zusammengeführt werden (Repository " +"beschädigt)" #, c-format msgid "Failed to merge submodule %s (commits don't follow merge-base)" @@ -17537,12 +17703,13 @@ msgstr "" "sind vorhanden:\n" "%s" -msgid "failed to execute internal merge" -msgstr "Fehler bei Ausführung des internen Merges" +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "Fehler: Der interne Merge für %s konnte nicht ausgeführt werden" #, c-format -msgid "unable to add %s to database" -msgstr "konnte %s nicht zur Datenbank hinzufügen" +msgid "error: unable to add %s to database" +msgstr "Fehler: kann %s nicht zur Datenbank hinzufügen" #, c-format msgid "Auto-merging %s" @@ -17640,12 +17807,12 @@ msgstr "" "KONFLIKT (umbenennen/löschen): %s zu %s in %s umbenannt, aber in %s gelöscht." #, c-format -msgid "cannot read object %s" -msgstr "kann Objekt %s nicht lesen" +msgid "error: cannot read object %s" +msgstr "Fehler: kann Objekt %s nicht lesen" #, c-format -msgid "object %s is not a blob" -msgstr "Objekt %s ist kein Blob" +msgid "error: object %s is not a blob" +msgstr "Fehler: Objekt %s ist kein Blob" #, c-format msgid "" @@ -17698,7 +17865,7 @@ msgstr "" #. conflict in a submodule. The first argument is the submodule #. name, and the second argument is the abbreviated id of the #. commit that needs to be merged. For example: -#. - go to submodule (mysubmodule), and either merge commit abc1234" +#. - go to submodule (mysubmodule), and either merge commit abc1234" #. #, c-format msgid "" @@ -17788,6 +17955,11 @@ msgid "do not know what to do with %06o %s '%s'" msgstr "weiß nicht was mit %06o %s '%s' zu machen ist" #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "" +"Submodul %s konnte nicht zusammengeführt werden (Repository beschädigt)" + +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "Spule Submodul %s zu dem folgenden Commit vor:" @@ -17828,6 +18000,13 @@ msgstr "" msgid "Failed to merge submodule %s (multiple merges found)" msgstr "Fehler beim Merge von Submodul %s (mehrere Merges gefunden)" +msgid "failed to execute internal merge" +msgstr "Fehler bei Ausführung des internen Merges" + +#, c-format +msgid "unable to add %s to database" +msgstr "konnte %s nicht zur Datenbank hinzufügen" + #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "" @@ -17935,6 +18114,14 @@ msgstr "" "KONFLIKT (umbenennen/umbenennen): Benenne Verzeichnis um %s->%s in %s.\n" "Benenne Verzeichnis um %s->%s in %s" +#, c-format +msgid "cannot read object %s" +msgstr "kann Objekt %s nicht lesen" + +#, c-format +msgid "object %s is not a blob" +msgstr "Objekt %s ist kein Blob" + msgid "modify" msgstr "ändern" @@ -18019,10 +18206,6 @@ msgstr "Zeile konnte nicht geparst werden: %s" msgid "malformed line: %s" msgstr "fehlerhafte Zeile: %s" -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "" -"ignoriere existierenden Multi-Pack-Index; Prüfsumme stimmt nicht überein" - msgid "could not load pack" msgstr "Paket konnte nicht geladen werden" @@ -18030,6 +18213,10 @@ msgstr "Paket konnte nicht geladen werden" msgid "could not open index for %s" msgstr "konnte Index für %s nicht öffnen" +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "" +"ignoriere existierenden Multi-Pack-Index; Prüfsumme stimmt nicht überein" + msgid "Adding packfiles to multi-pack-index" msgstr "Packdateien zum Multi-Pack-Index hinzufügen" @@ -18489,7 +18676,7 @@ msgstr "%s [ungültiges Objekt]" #. TRANSLATORS: This is a line of ambiguous commit #. object output. E.g.: #. * -#. "deadbeef commit 2021-01-01 - Some Commit Message" +#. "deadbeef commit 2021-01-01 - Some Commit Message" #. #, c-format msgid "%s commit %s - %s" @@ -18498,7 +18685,7 @@ msgstr "%s Commit %s - %s" #. TRANSLATORS: This is a line of ambiguous #. tag object output. E.g.: #. * -#. "deadbeef tag 2022-01-01 - Some Tag Message" +#. "deadbeef tag 2022-01-01 - Some Tag Message" #. * #. The second argument is the YYYY-MM-DD found #. in the tag. @@ -18514,7 +18701,7 @@ msgstr "%s Tag %s - %s" #. tag object output where we couldn't parse #. the tag itself. E.g.: #. * -#. "deadbeef [bad tag, could not parse it]" +#. "deadbeef [bad tag, could not parse it]" #. #, c-format msgid "%s [bad tag, could not parse it]" @@ -18655,6 +18842,17 @@ msgstr "Konnte Objekt '%s' nicht parsen." msgid "hash mismatch %s" msgstr "Hash stimmt nicht mit %s überein." +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "doppelter Eintrag beim Schreiben des Bitmap-Index: %s" + +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "versuchte, nicht gewählten Commit '%s' zu speichern" + +msgid "too many pseudo-merges" +msgstr "zu viele Pseudo-Merges" + msgid "trying to write commit not in index" msgstr "Versuch, einen Commit zu schreiben, der nicht im Index steht" @@ -18679,6 +18877,17 @@ msgid "corrupted bitmap index file (too short to fit lookup table)" msgstr "" "beschädigte Bitmap-Indexdatei (zu kurz, um in die Lookup-Tabelle zu passen)" +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "" +"beschädigte Bitmap-Indexdatei (zu kurz für den Pseudo-Merge-Tabellenkopf)" + +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "beschädigte Bitmap-Indexdatei (zu kurz für die Pseudo-Merge-Tabelle)" + +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "beschädigte Bitmap-Indexdatei, Pseudo-Merge-Tabelle zu kurz" + #, c-format msgid "duplicate entry in bitmap index: '%s'" msgstr "duplizierter Eintrag im Bitmap-Index: '%s'" @@ -18776,6 +18985,10 @@ msgid "mismatch in bitmap results" msgstr "Unstimmigkeiten bei Bitmap-Ergebnissen" #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "Pseudo-Merge-Index außerhalb des Bereichs (%<PRIu32> >= %<PRIuMAX>)" + +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "konnte '%s' in Paket '%s' bei Offset %<PRIuMAX> nicht finden" @@ -19145,6 +19358,10 @@ msgstr "Kann Thread für lstat nicht erzeugen: %s" msgid "unable to parse --pretty format" msgstr "Konnte --pretty Format nicht parsen." +msgid "lazy fetching disabled; some objects may not be available" +msgstr "" +"lazy fetching deaktiviert; einige Objekte sind möglicherweise nicht verfügbar" + msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "Promisor-Remote: konnte Fetch-Subprozess nicht abspalten" @@ -19170,6 +19387,67 @@ msgstr "object-info: erwartete Flush nach Argumenten" msgid "Removing duplicate objects" msgstr "Lösche doppelte Objekte" +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "Pseudo-Merge-Regex konnte nicht geladen werden für %s: '%s'" + +#, c-format +msgid "%s must be non-negative, using default" +msgstr "%s muss nicht-negativ sein, Standardwert wird verwendet" + +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "%s muss zwischen 0 und 1 liegen, Standardwert wird verwendet" + +#, c-format +msgid "%s must be positive, using default" +msgstr "%s muss positiv sein, verwende Standardwert" + +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "Pseudo-Merge-Gruppe '%s' fehlt erforderliches Muster" + +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "" +"Pseudo-Merge-Gruppe '%s' hat einen instabilen vor einem stabilen " +"Schwellenwert" + +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "" +"Pseudo-Merge-Regex aus der Konfiguration hat zu viele Capture-Gruppen " +"(maximum=%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"erweiterter Pseudo-Merge liest außerhalb des Bereichs (%<PRIuMAX> >= " +"%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"erweiterter Pseudo-Merge-Eintrag ist zu kurz (%<PRIuMAX> >= %<PRIuMAX>)" + +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "konnte keinen Pseudo-Merge für Commit %s bei Offset %<PRIuMAX> finden" + +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "" +"erweiterte Pseudo-Merge-Suche außerhalb des Bereichs (%<PRIu32> >= %<PRIu32>)" + +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "Lesen außerhalb des zulässigen Bereichs: (%<PRIuMAX> >= %<PRIuMAX>)" + +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "konnte erweiterte Pseudo-Merge-Tabelle für Commit %s nicht lesen" + msgid "could not start `log`" msgstr "Konnte `log` nicht starten." @@ -19778,11 +20056,18 @@ msgstr "Log für Referenz %s unerwartet bei %s beendet." msgid "log for %s is empty" msgstr "Log für %s ist leer." +msgid "refusing to force and skip creation of reflog" +msgstr "Erzwingen der Aktion verweigert; überspringe Erstellung des Reflogs" + #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "verweigere Aktualisierung einer Referenz mit fehlerhaftem Namen '%s'" #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "Aktualisierung von Pseudoreferenz '%s' verweigert" + +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "update_ref für Referenz '%s' fehlgeschlagen: %s" @@ -19815,6 +20100,27 @@ msgid "could not delete references: %s" msgstr "konnte Referenzen nicht entfernen: %s" #, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "" +"Trockenlauf der Migration von Referenzen abgeschlossen. Das Ergebnis kann " +"unter '%s' gefunden werden.\n" + +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "konnte das temporäre Migrationsverzeichnis '%s' nicht entfernen" + +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "migrierte Referenzen befinden sich unter '%s'" + +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "" +"kann Referenz '%s' nicht sperren: erwartete symbolische Referenz mit Ziel " +"'%s': ist aber eine reguläre Referenz" + +#, c-format msgid "refname is dangerous: %s" msgstr "Referenzname ist gefährlich: %s" @@ -20993,6 +21299,50 @@ msgstr "" "refs/heads/%s" #, c-format +msgid "'%s' does not accept merge commits" +msgstr "'%s' akzeptiert keine Merge-Commits" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"'pick' nimmt keinen Merge-Commit an. Wenn Sie den Merge wiederholen\n" +"wollen, verwenden Sie 'merge -C' auf den Commit." + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"'reword' erfordert keinen Merge-Commit. Wenn Sie\n" +"den Merge wiederholen und die Commit-Nachricht\n" +"neu formulieren wollen, verwenden Sie\n" +"'merge -c' auf den Commit" + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"'edit' nimmt keinen Merge-Commit an. Wenn Sie den Merge wiederholen\n" +"wollen, verwenden Sie 'merge -C' auf den Commit und dann\n" +"break', um die Kontrolle zurückzugewinnen, sodass Sie\n" +"'git commit --amend && git rebase --continue' ausführen können." + +msgid "cannot squash merge commit into another commit" +msgstr "kann einen Merge-Commit nicht mit einem anderen Commit zusammenfassen" + +#, c-format msgid "invalid command '%.*s'" msgstr "ungültiger Befehl '%.*s'" @@ -21110,9 +21460,8 @@ msgstr "" msgid "cannot read HEAD" msgstr "kann HEAD nicht lesen" -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "konnte '%s' nicht nach '%s' kopieren" +msgid "could not write commit message file" +msgstr "konnte keine Commit-Beschreibungsdatei schreiben" #, c-format msgid "" @@ -21522,6 +21871,18 @@ msgstr "Kann nicht zum aktuellen Arbeitsverzeichnis zurückwechseln." msgid "failed to stat '%*s%s%s'" msgstr "Konnte '%*s%s%s' nicht lesen." +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"dubiose Besitzverhältnisse im Repository bei '%s' entdeckt\n" +"%sUm eine Ausnahme für dieses Verzeichnis hinzuzufügen, rufen Sie auf:\n" +"\n" +"\tgit config --global --add safe.directory %s" + msgid "Unable to read current working directory" msgstr "Konnte aktuelles Arbeitsverzeichnis nicht lesen." @@ -21543,18 +21904,6 @@ msgstr "" "Stoppe bei Dateisystemgrenze (GIT_DISCOVERY_ACROSS_FILESYSTEM nicht gesetzt)." #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"dubiose Besitzverhältnisse im Repository bei '%s' entdeckt\n" -"%sUm eine Ausnahme für dieses Verzeichnis hinzuzufügen, rufen Sie auf:\n" -"\n" -"\tgit config --global --add safe.directory %s" - -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" msgstr "" "kann Bare-Repository '%s' nicht verwenden (safe.bareRepository ist '%s')" @@ -21862,6 +22211,14 @@ msgstr "" "Git-Verzeichnis des Submoduls '%s' ist im Git-Verzeichnis '%.*s' enthalten." #, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "erwartete, dass '%.*s' im Submodulpfad '%s' kein symbolischer Link ist" + +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "erwartete, dass der Submodulpfad '%s' kein symbolischer Link ist" + +#, c-format msgid "" "relocate_gitdir for submodule '%s' with more than one worktree not supported" msgstr "" @@ -21900,10 +22257,6 @@ msgstr "'lstat' für '%s' fehlgeschlagen" msgid "no remote configured to get bundle URIs from" msgstr "kein Remote-Repository zum Erhalten von Bundle-URIs konfiguriert" -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "Remote-Repository '%s' hat keine konfigurierte URL" - msgid "could not get the bundle-uri list" msgstr "konnte die Bundle-uri-Liste nicht erhalten" @@ -23459,24 +23812,24 @@ msgid "Failed to send %s\n" msgstr "Fehler beim Senden %s\n" #, perl-format -msgid "Dry-Sent %s\n" -msgstr "Probeversand %s\n" +msgid "Dry-Sent %s" +msgstr "Probeversand %s" #, perl-format -msgid "Sent %s\n" -msgstr "%s gesendet\n" +msgid "Sent %s" +msgstr "%s gesendet" -msgid "Dry-OK. Log says:\n" -msgstr "Probeversand OK. Log enthält:\n" +msgid "Dry-OK. Log says:" +msgstr "Probelauf OK. Das Protokoll enthält:" -msgid "OK. Log says:\n" -msgstr "OK. Log enthält:\n" +msgid "OK. Log says:" +msgstr "OK. Das Protokoll enthält:" msgid "Result: " msgstr "Ergebnis: " -msgid "Result: OK\n" -msgstr "Ergebnis: OK\n" +msgid "Result: OK" +msgstr "Ergebnis: OK" #, perl-format msgid "can't open file %s" @@ -80,8 +80,8 @@ msgid "" msgstr "" "Project-Id-Version: git\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-16 22:57+0000\n" -"PO-Revision-Date: 2024-04-20 17:11+0800\n" +"POT-Creation-Date: 2024-07-17 21:57+0000\n" +"PO-Revision-Date: 2024-07-19 20:25+0200\n" "Last-Translator: Cédric Malard <c.malard-git@valdun.net>\n" "Language-Team: Jean-Noël Avila <jn.avila@free.fr>\n" "Language: fr\n" @@ -642,6 +642,10 @@ msgstr "" "p - afficher la section actuelle\n" "? - afficher l'aide\n" +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "une seule lettre est attendue, mais '%s' a été reçu" + msgid "No previous hunk" msgstr "Pas de section précédente" @@ -690,9 +694,19 @@ msgstr "Découpée en %d sections." msgid "Sorry, cannot edit this hunk" msgstr "Désolé, impossible d'éditer cette section" +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "commande inconnue : '%s' (utilisez '?' pour de l'aide)" + msgid "'git apply' failed" msgstr "'git apply' a échoué" +msgid "No changes." +msgstr "Aucune modification." + +msgid "Only binary files changed." +msgstr "Seuls des fichiers binaires ont changé." + #, c-format msgid "" "\n" @@ -1219,10 +1233,6 @@ msgstr[0] "Application du patch %%s avec %d rejet..." msgstr[1] "Application du patch %%s avec %d rejets..." #, c-format -msgid "truncating .rej filename to %.*s.rej" -msgstr "troncature du nom de fichier .rej en %.*s.rej" - -#, c-format msgid "cannot open %s" msgstr "impossible d'ouvrir %s" @@ -1573,6 +1583,9 @@ msgstr "fichier gitattributes trop gros ignoré '%s'" msgid "ignoring overly large gitattributes blob '%s'" msgstr "blob gitattributes trop gros ignoré '%s'" +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "impossible d'utiliser --attr-source ou GIT_ATTR_SOURCE sans dépôt" + msgid "bad --attr-source or GIT_ATTR_SOURCE" msgstr "mauvais --attr-source ou GIT_ATTR_SOURCE" @@ -1654,6 +1667,10 @@ msgid "could not create file '%s'" msgstr "impossible de créer le fichier '%s'" #, c-format +msgid "unable to start 'show' for object '%s'" +msgstr "impossible de démarrer 'show' pour l'objet '%s'" + +#, c-format msgid "could not read file '%s'" msgstr "impossible de lire le fichier '%s'" @@ -1887,13 +1904,6 @@ msgstr "impossible de chmod %cx '%s'" msgid "Unstaged changes after refreshing the index:" msgstr "Modifications non indexées après rafraîchissement de l'index :" -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"le réglage add.interactive.useBuiltin a été supprimé !\n" -"Référez-vous à cette entrée dans 'git help config' pour plus de détails." - msgid "could not read the index" msgstr "impossible de lire l'index" @@ -2006,7 +2016,7 @@ msgid "adding embedded git repository: %s" msgstr "dépôt git embarqué ajouté : %s" msgid "Use -f if you really want to add them." -msgstr "Utilisez -f si vous voulez vraiment les ajouter" +msgstr "Utilisez -f si vous voulez vraiment les ajouter<." msgid "adding files failed" msgstr "échec de l'ajout de fichiers" @@ -2340,6 +2350,9 @@ msgstr "abandonne l'opération de patch mais garde HEAD où il est" msgid "show the patch being applied" msgstr "afficher le patch en cours d'application" +msgid "try to apply current patch again" +msgstr "essayer d'appliquer de nouveau la rustine" + msgid "record the empty patch as an empty commit" msgstr "enregistrer la rustine vide comme un commit vide" @@ -2398,9 +2411,6 @@ msgstr "git apply [<options>] [<patch>...]" msgid "could not redirect output" msgstr "impossible de rediriger la sortie" -msgid "git archive: Remote with no URL" -msgstr "git archive : Dépôt distant sans URL" - msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "git archive : ACK/NACK attendu, paquet de nettoyage reçu" @@ -3321,6 +3331,9 @@ msgstr "La création d'un colis requiert un dépôt." msgid "do not show bundle details" msgstr "ne pas afficher les détails du colis" +msgid "need a repository to verify a bundle" +msgstr "la vérification d'un colis requiert un dépôt" + #, c-format msgid "%s is okay\n" msgstr "%s est correct\n" @@ -4351,6 +4364,14 @@ msgid "failed to unlink '%s'" msgstr "échec pour délier '%s'" #, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "le lien dur ne peut pas être vérifier à '%s'" + +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "le lien dur est différent de la source à '%s'" + +#, c-format msgid "failed to create link '%s'" msgstr "échec de la création du lien '%s'" @@ -5195,15 +5216,53 @@ msgstr "" "d'index. Vérifiez que le disque n'est pas plein ou que le quota\n" "n'a pas été dépassé, puis lancez \"git restore --staged :/\" pour réparer." -msgid "git config [<options>]" -msgstr "git config [<options>]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "" +"git config list [<option-de-fichier>] [<option-d-affichage>] [--includes]" -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "argument --type non reconnu, %s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [<option-de-fichier>] [<option-d-affichage>] [--includes] [--" +"all] [--regexp=<regexp>] [--value=<valeur>] [--fixed-value] [--" +"default=<défaut>] <name>" -msgid "only one type at a time" -msgstr "qu'un seul type à la fois" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [<option-de-fichier>] [--type=<type>] [--all] [--" +"value=<valeur>] [--fixed-value] <nom> <valeur>" + +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [<option-de-fichier>] [--all] [--value=<valeur>] [--fixed-" +"value] <nom> <valeur>" + +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "" +"git config rename-section [<option-de-fichier>] <ancien-nom> <nouveau-nom>" + +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [<option-de-fichier>] <nom>" + +msgid "git config edit [<file-option>]" +msgstr "git config edit [<option-de-fichier>]" + +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "" +"git config [<option-de-fichier>] --get-colorbool <nom> [<stdout-est-tty>]" + +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [<option-de-fichier>] [--type=<type>] [--comment=<message>] " +"[--all] [--value=<valeur>] [--fixed-value] <nom> <valeur>" msgid "Config file location" msgstr "Emplacement du fichier de configuration" @@ -5229,56 +5288,6 @@ msgstr "blob-id" msgid "read config from given blob object" msgstr "lire la configuration depuis l'objet blob fourni" -msgid "Action" -msgstr "Action" - -msgid "get value: name [value-pattern]" -msgstr "obtenir la valeur : nom [motif-de-valeur]" - -msgid "get all values: key [value-pattern]" -msgstr "obtenir toutes les valeurs : clé [motif-de-valeur]" - -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "obtenir les valeur pour la regexp : regex-de-nom [motif-de-valeur]" - -msgid "get value specific for the URL: section[.var] URL" -msgstr "obtenir la valeur spécifique pour l'URL : section[.var] URL" - -msgid "replace all matching variables: name value [value-pattern]" -msgstr "" -"remplacer toutes les variables correspondant : nom valeur [motif-de-valeur]" - -msgid "add a new variable: name value" -msgstr "ajouter une nouvelle variable : nom valeur" - -msgid "remove a variable: name [value-pattern]" -msgstr "supprimer une variable : nom [motif-de-valeur]" - -msgid "remove all matches: name [value-pattern]" -msgstr "supprimer toutes les correspondances nom [motif-de-valeur]" - -msgid "rename section: old-name new-name" -msgstr "renommer une section : ancien-nom nouveau-nom" - -msgid "remove a section: name" -msgstr "supprimer une section : nom" - -msgid "list all" -msgstr "afficher tout" - -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "" -"utiliser l'égalité de chaînes lors de la comparaison de 'motif-de-valeur'" - -msgid "open an editor" -msgstr "ouvrir un éditeur" - -msgid "find the color configured: slot [default]" -msgstr "trouver la couleur configurée : slot [par défaut]" - -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "trouver le réglage de la couleur : slot [stdout-est-tty]" - msgid "Type" msgstr "Type" @@ -5306,8 +5315,8 @@ msgstr "la valeur est un chemin (vers un fichier ou un répertoire)" msgid "value is an expiry date" msgstr "la valeur est une date d'expiration" -msgid "Other" -msgstr "Autre" +msgid "Display options" +msgstr "Options d'affichage" msgid "terminate values with NUL byte" msgstr "terminer les valeurs avec un caractère NUL" @@ -5315,9 +5324,6 @@ msgstr "terminer les valeurs avec un caractère NUL" msgid "show variable names only" msgstr "n'afficher que les noms de variable" -msgid "respect include directives on lookup" -msgstr "respecter les directives d'inclusion lors de la recherche" - msgid "show origin of config (file, standard input, blob, command line)" msgstr "" "afficher l'origine de la configuration (fichier, entrée standard, blob, " @@ -5328,16 +5334,15 @@ msgstr "" "afficher la portée de configuration (arbre de travail, local, global, " "système, commande)" -msgid "value" -msgstr "valeur" +msgid "show config keys in addition to their values" +msgstr "afficher les clés de configuration en plus des valeurs" -msgid "with --get, use default value when missing entry" -msgstr "avec --get, utiliser le valeur par défaut quand l'entrée n'existe pas" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "argument --type non reconnu, %s" -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "" -"chaîne des commentaires lisibles par l'utilisateur (# sera ajouté en préfixe " -"selon les besoins)" +msgid "only one type at a time" +msgstr "qu'un seul type à la fois" #, c-format msgid "wrong number of arguments, should be %d" @@ -5414,47 +5419,77 @@ msgstr "" "la section \"CONFIGURATION FILE\" de \"git help worktree\" pour plus de " "détails" -msgid "--get-color and variable type are incoherent" -msgstr "--get-color et le type de la variable sont incohérents" +msgid "Other" +msgstr "Autre" -msgid "only one action at a time" -msgstr "une seule action à la fois" +msgid "respect include directives on lookup" +msgstr "respecter les directives d'inclusion lors de la recherche" -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "--name-only n'est applicable qu'avec --list ou --get-regexp" +#, c-format +msgid "unable to read config file '%s'" +msgstr "lecture du fichier de configuration '%s' impossible" -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" +msgid "error processing config file(s)" +msgstr "erreur lors du traitement de fichier(s) de configuration" + +msgid "Filter options" +msgstr "Options de filtre" + +msgid "return all values for multi-valued config options" msgstr "" -"--show-origin n'est applicable qu'avec --get, --get-all, --get-regexp ou --" -"list" +"renvoyer toutes les valeurs pour les options de configuration multi-valeurs" -msgid "--default is only applicable to --get" -msgstr "--default n'est applicable qu'avec --get" +msgid "interpret the name as a regular expression" +msgstr "interpréter le nom comme une expression régulière" -msgid "--comment is only applicable to add/set/replace operations" -msgstr "--comment n'est applicable qu'avec les opérations add/set/replace" +msgid "show config with values matching the pattern" +msgstr "afficher les configurations dont le nom correspond au motif" + +msgid "use string equality when comparing values to value pattern" +msgstr "" +"utiliser l'égalité de chaînes lors de la comparaison des valeurs au motif de " +"valeur" + +msgid "URL" +msgstr "URL" + +msgid "show config matching the given URL" +msgstr "afficher les configs qui correspondent à l'URL donné" + +msgid "value" +msgstr "valeur" + +msgid "use default value when missing entry" +msgstr "utiliser le valeur par défaut quand l'entrée n'existe pas" msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value ne s'applique qu'à 'motif-de-valeur'" -#, c-format -msgid "unable to read config file '%s'" -msgstr "lecture du fichier de configuration '%s' impossible" +msgid "--default= cannot be used with --all or --url=" +msgstr "--default= ne peut pas être utilisé avec --all ou --url=" -msgid "error processing config file(s)" -msgstr "erreur lors du traitement de fichier(s) de configuration" +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "--url= ne peut pas être utilisé avec --all, --regexp ou --value" -msgid "editing stdin is not supported" -msgstr "l'édition de stdin n'est pas supportée" +msgid "Filter" +msgstr "Filtre" -msgid "editing blobs is not supported" -msgstr "l'édition de blobs n'est pas supportée" +msgid "replace multi-valued config option with new value" +msgstr "remplacer l'option de config multi-valeur par la nouvelle valeur" -#, c-format -msgid "cannot create configuration file %s" -msgstr "création impossible du fichier de configuration '%s'" +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "" +"chaîne des commentaires lisibles par l'utilisateur (# sera ajouté en préfixe " +"selon les besoins)" + +msgid "add a new line without altering any existing values" +msgstr "ajouter une nouvelle ligne sans modifier les valeurs existantes" + +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "--fixed-value ne s'applique qu'avec --value=<motif>" + +msgid "--append cannot be used with --value=<pattern>" +msgstr "--append ne s'applique pas avec --value=<motif>" #, c-format msgid "" @@ -5468,6 +5503,87 @@ msgstr "" msgid "no such section: %s" msgstr "section inexistante : %s" +msgid "editing stdin is not supported" +msgstr "l'édition de stdin n'est pas supportée" + +msgid "editing blobs is not supported" +msgstr "l'édition de blobs n'est pas supportée" + +#, c-format +msgid "cannot create configuration file %s" +msgstr "création impossible du fichier de configuration '%s'" + +msgid "Action" +msgstr "Action" + +msgid "get value: name [<value-pattern>]" +msgstr "obtenir la valeur : nom [<motif-de-valeur>]" + +msgid "get all values: key [<value-pattern>]" +msgstr "obtenir toutes les valeurs : clé [<motif-de-valeur>]" + +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "obtenir les valeur pour la regexp : name-regex [<motif-de-valeur>]" + +msgid "get value specific for the URL: section[.var] URL" +msgstr "obtenir la valeur spécifique pour l'URL : section[.var] URL" + +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "" +"remplacer toutes les variables correspondant : nom valeur [<motif-de-valeur>]" + +msgid "add a new variable: name value" +msgstr "ajouter une nouvelle variable : nom valeur" + +msgid "remove a variable: name [<value-pattern>]" +msgstr "supprimer une variable : nom [<motif-de-valeur>]" + +msgid "remove all matches: name [<value-pattern>]" +msgstr "supprimer toutes les correspondances nom [<motif-de-valeur>]" + +msgid "rename section: old-name new-name" +msgstr "renommer une section : ancien-nom nouveau-nom" + +msgid "remove a section: name" +msgstr "supprimer une section : nom" + +msgid "list all" +msgstr "afficher tout" + +msgid "open an editor" +msgstr "ouvrir un éditeur" + +msgid "find the color configured: slot [<default>]" +msgstr "trouver la couleur configurée : slot [<valeur-par-défaut>]" + +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "trouver le réglage de la couleur : slot [<stdout-est-tty>]" + +msgid "with --get, use default value when missing entry" +msgstr "avec --get, utiliser le valeur par défaut quand l'entrée n'existe pas" + +msgid "--get-color and variable type are incoherent" +msgstr "--get-color et le type de la variable sont incohérents" + +msgid "no action specified" +msgstr "aucune action spécifiée" + +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "--name-only n'est applicable qu'avec --list ou --get-regexp" + +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "" +"--show-origin n'est applicable qu'avec --get, --get-all, --get-regexp ou --" +"list" + +msgid "--default is only applicable to --get" +msgstr "--default n'est applicable qu'avec --get" + +msgid "--comment is only applicable to add/set/replace operations" +msgstr "--comment n'est applicable qu'avec les opérations add/set/replace" + msgid "print sizes in human readable format" msgstr "affiche les tailles dans un format humainement lisible" @@ -6307,6 +6423,9 @@ msgstr "config" msgid "config key storing a list of repository paths" msgstr "clé de config qui stocke la liste des chemins de dépôts" +msgid "keep going even if command fails in a repository" +msgstr "continuer mêm si la commande échoue dans un dépôt" + msgid "missing --config=<config>" msgstr "--config=<config> manquant" @@ -7788,8 +7907,11 @@ msgstr "marquer la série comme une Nième réédition" msgid "max length of output filename" msgstr "taille maximum du nom du fichier de sortie" -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "utiliser [RFC PATCH] au lieu de [PATCH]" +msgid "rfc" +msgstr "rfc" + +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "ajouter <rfc> (par défaut 'RFC') avant 'PATCH'" msgid "cover-from-description-mode" msgstr "cover-from-description-mode" @@ -8066,11 +8188,11 @@ msgstr "" "deduplicate, --eol" msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--brances] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<clé>]\n" " [--symref] [<dépôt> [<motif>...]]" @@ -8086,8 +8208,11 @@ msgstr "chemin vers git-upload-pack sur le serveur distant" msgid "limit to tags" msgstr "limiter aux étiquettes" -msgid "limit to heads" -msgstr "limiter aux heads" +msgid "limit to branches" +msgstr "limiter aux branches" + +msgid "deprecated synonym for --branches" +msgstr "synonyme obsolète de --branches" msgid "do not show peeled tags" msgstr "ne pas afficher les étiquettes pelées" @@ -8938,10 +9063,6 @@ msgstr "git notes prune [<options>]" msgid "Write/edit the notes for the following object:" msgstr "Écrire/éditer les notes pour l'objet suivant :" -#, c-format -msgid "unable to start 'show' for object '%s'" -msgstr "impossible de démarrer 'show' pour l'objet '%s'" - msgid "could not read 'show' output" msgstr "impossible de lire la sortie de 'show'" @@ -10779,6 +10900,22 @@ msgstr "pas de journal de références à supprimer spécifié" msgid "invalid ref format: %s" msgstr "format de référence invalide : %s" +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=<format> [--dry-run]" + +msgid "specify the reference format to convert to" +msgstr "spécifier le format de réference vers lequel convertir" + +msgid "perform a non-destructive dry-run" +msgstr "faire l'action en mode simulé non destructif" + +msgid "missing --ref-format=<format>" +msgstr "--ref-format=<format> manquant" + +#, c-format +msgid "repository already uses '%s' format" +msgstr "le dépôt utilise déjà le format '%s'" + msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" "mirror=<fetch|push>] <name> <url>" @@ -11067,9 +11204,6 @@ msgstr "* distant %s" msgid " Fetch URL: %s" msgstr " URL de rapatriement : %s" -msgid "(no URL)" -msgstr "(pas d'URL)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -11078,6 +11212,9 @@ msgstr "(pas d'URL)" msgid " Push URL: %s" msgstr " URL push : %s" +msgid "(no URL)" +msgstr "(pas d'URL)" + #, c-format msgid " HEAD branch: %s" msgstr " Branche HEAD : %s" @@ -11187,10 +11324,6 @@ msgstr "interroger les URLs de poussée plutôt que les URLs de récupération" msgid "return all URLs" msgstr "retourner toutes les URLs" -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "aucune URL configurée pour le dépôt distant '%s'" - msgid "manipulate push URLs" msgstr "manipuler les URLs push" @@ -12209,12 +12342,12 @@ msgstr "Algorithme d'empreinte inconnu" msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<motif>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<motif>...]" msgid "" "git show-ref --verify [-q | --quiet] [-d | --dereference]\n" @@ -12237,11 +12370,13 @@ msgstr "la référence n'existe pas" msgid "failed to look up reference" msgstr "échec de la recherche de la référence" -msgid "only show tags (can be combined with heads)" -msgstr "afficher seulement les étiquettes (peut être combiné avec heads)" +msgid "only show tags (can be combined with branches)" +msgstr "" +"afficher seulement les étiquettes (peut être combiné avec les branches)" -msgid "only show heads (can be combined with tags)" -msgstr "afficher seulement les têtes (peut être combiné avec tags)" +msgid "only show branches (can be combined with tags)" +msgstr "" +"afficher seulement les branches (peut être combiné avec les étiquettes)" msgid "check for reference existence without resolving" msgstr "vérifier l'existence de la référence sans la résoudre" @@ -12893,14 +13028,14 @@ msgstr "" "refus de créer/utiliser '%s' dans un répertoire git d'un autre sous-module" #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "le clonage de '%s' dans le chemin de sous-module '%s' a échoué" - -#, c-format msgid "directory not empty: '%s'" msgstr "le répertoire n'est pas vide : '%s'" #, c-format +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "le clonage de '%s' dans le chemin de sous-module '%s' a échoué" + +#, c-format msgid "could not get submodule directory for '%s'" msgstr "impossible de créer le répertoire de sous-module pour '%s'" @@ -13266,9 +13401,11 @@ msgstr "raison de la mise à jour" msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" "git tag [-a | -s | -u <id-clé>] [-f] [-m <msg> | -F <fichier>] [-e]\n" +" [(--trailer <jeton>[(=|:)<valeur>)...]\n" " <nom-d-étiquette> [<commit> | <objet>]" msgid "git tag -d <tagname>..." @@ -14147,9 +14284,6 @@ msgstr "en-tête non reconnu : %s%s (%d)" msgid "Repository lacks these prerequisite commits:" msgstr "Le dépôt ne dispose pas des commits prérequis suivants :" -msgid "need a repository to verify a bundle" -msgstr "la vérification d'un colis requiert un dépôt" - msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -14565,6 +14699,9 @@ msgstr "Recevoir ce qui est poussé dans le dépôt" msgid "Manage reflog information" msgstr "Gérer l'information de reflog" +msgid "Low-level access to refs" +msgstr "accès de bas-niveau aux réfs" + msgid "Manage set of tracked repositories" msgstr "Gérer un ensemble de dépôts suivis" @@ -14884,6 +15021,14 @@ msgstr "" "le tronçon d'étalement OID requis par le graphe de commits est manquant ou " "corrompu" +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "" +"désactivation des filtres de Bloom opur la couche de graphe de commits '%s' " +"à cause de réglages incompatibles" + msgid "commit-graph has no base graphs chunk" msgstr "le graphe de commit n'a pas de tronçon de graphes de base" @@ -15018,6 +15163,14 @@ msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled" msgstr "" "essai d'écriture de graphe de commits, mais 'core.commitGraph' est désactivé" +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " +"(%d) is not supported" +msgstr "" +"essai d'écriture de graphe de commits, mais 'commitGraph." +"changedPathsVersion' (%d) n'est pas pris en charge" + msgid "too many commits to write graph" msgstr "trop de commits pour écrire un graphe" @@ -16931,19 +17084,23 @@ msgstr "" msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v | --version] [-h | --help] [-C <chemin>] [-c <nom>=<valeur>]\n" " [--exec-path[=<chemin>]] [--html-path] [--man-path] [--info-" "path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<chemin>] [--work-tree=<chemin>] [--namespace=<nom>]\n" -" [--config-env=<nom>=<variable-d-environnement>] <commande> " -"[<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-" +"dir=<chemin>]\n" +" [--work-tree=<chemin>] [--namespace=<nom>] [--config-" +"env=<nom>=<var-d-env>] \n" +" <commande> [<args>]" msgid "" "'git help -a' and 'git help -g' list available subcommands and some\n" @@ -17284,13 +17441,13 @@ msgstr "" "Vous pouvez désactiver cet avertissement avec `git config advice.ignoredHook " "false`." +msgid "not a git repository" +msgstr "pas un dépôt git" + #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "l'argument de --packfile doit être une empreinte valide ('%s' reçu)" -msgid "not a git repository" -msgstr "pas un dépôt git" - #, c-format msgid "negative value for http.postBuffer; defaulting to %d" msgstr "" @@ -17302,6 +17459,9 @@ msgstr "La délégation de commande n'est pas supporté avec cuRL < 7.22.0" msgid "Public key pinning not supported with cURL < 7.39.0" msgstr "L'épinglage de clé publique n'est pas supporté avec cuRL < 7.39.0" +msgid "Unknown value for http.proactiveauth" +msgstr "valeur inconnue pour http.proactiveauth" + msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "CURLSSLOPT_NO_REVOKE n'est pas supporté avec cuRL < 7.44.0" @@ -17319,6 +17479,12 @@ msgstr "" msgid "Could not set SSL backend to '%s': already set" msgstr "Impossible de spécifier le dorsal SSL à '%s' : déjà spécifié" +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "refus de lire des cookies depuis http.cookiefile '-'" + +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "http.savecookies ignoré pour http.cookiefile vide" + #, c-format msgid "" "unable to update url base from redirection:\n" @@ -17481,6 +17647,10 @@ msgid "quoted CRLF detected" msgstr "CRLF citées détectées" #, c-format +msgid "unable to format message: %s" +msgstr "impossible de formater le message : %s" + +#, c-format msgid "Failed to merge submodule %s (not checked out)" msgstr "Échec de la fusion du sous-module %s (non extrait)" @@ -17493,8 +17663,8 @@ msgid "Failed to merge submodule %s (commits not present)" msgstr "Échec de fusion du sous-module %s (commits non présents)" #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" -msgstr "Échec de la fusion du sous-module %s (dépôt corrompu)" +msgid "error: failed to merge submodule %s (repository corrupt)" +msgstr "erreur : échec de la fusion du sous-module %s (dépôt corrompu)" #, c-format msgid "Failed to merge submodule %s (commits don't follow merge-base)" @@ -17526,12 +17696,13 @@ msgstr "" "existent :\n" "%s" -msgid "failed to execute internal merge" -msgstr "échec à l'exécution de la fusion interne" +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "erreur : échec à l'exécution de la fusion interne pour %s" #, c-format -msgid "unable to add %s to database" -msgstr "impossible d'ajouter %s à la base de données" +msgid "error: unable to add %s to database" +msgstr "erreur : impossible d'ajouter %s à la base de données" #, c-format msgid "Auto-merging %s" @@ -17627,12 +17798,12 @@ msgstr "" "supprimé dans %s." #, c-format -msgid "cannot read object %s" -msgstr "impossible de lire l'objet %s" +msgid "error: cannot read object %s" +msgstr "erreur : impossible de lire l'objet %s" #, c-format -msgid "object %s is not a blob" -msgstr "l'objet %s n'est pas un blob" +msgid "error: object %s is not a blob" +msgstr "erreur : l'objet %s n'est pas un blob" #, c-format msgid "" @@ -17771,6 +17942,10 @@ msgid "do not know what to do with %06o %s '%s'" msgstr "ne sait pas traiter %06o %s '%s'" #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "Échec de la fusion du sous-module %s (dépôt corrompu)" + +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "Avance rapide du sous-module %s au commit suivant :" @@ -17810,6 +17985,13 @@ msgstr "" msgid "Failed to merge submodule %s (multiple merges found)" msgstr "Échec de fusion du sous-module %s (plusieurs fusions trouvées)" +msgid "failed to execute internal merge" +msgstr "échec à l'exécution de la fusion interne" + +#, c-format +msgid "unable to add %s to database" +msgstr "impossible d'ajouter %s à la base de données" + #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "" @@ -17910,6 +18092,14 @@ msgstr "" "CONFLIT (renommage/renommage) : renommage du répertoire %s->%s dans %s. " "Renommage de répertoire %s->%s dans %s" +#, c-format +msgid "cannot read object %s" +msgstr "impossible de lire l'objet %s" + +#, c-format +msgid "object %s is not a blob" +msgstr "l'objet %s n'est pas un blob" + msgid "modify" msgstr "modification" @@ -17993,10 +18183,6 @@ msgstr "impossible d'analyser la ligne : %s" msgid "malformed line: %s" msgstr "ligne malformée : %s" -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "" -"index multi-paquet existant ignoré ; non-concordance de la somme de contrôle" - msgid "could not load pack" msgstr "impossible de charger le paquet" @@ -18004,6 +18190,10 @@ msgstr "impossible de charger le paquet" msgid "could not open index for %s" msgstr "impossible d'ouvrir l'index pour %s" +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "" +"index multi-paquet existant ignoré ; non-concordance de la somme de contrôle" + msgid "Adding packfiles to multi-pack-index" msgstr "Ajout de fichiers paquet à un index multi-paquet" @@ -18628,6 +18818,17 @@ msgstr "impossible d'analyser l'objet : %s" msgid "hash mismatch %s" msgstr "incohérence de hachage %s" +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "entrée dupliquée dans l'index en bitmap : '%s'" + +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "essai de stockage d'un commit non-sélectionné : '%s'" + +msgid "too many pseudo-merges" +msgstr "trop de pseudo-fusions" + msgid "trying to write commit not in index" msgstr "échec de l'écriture de l'objet commit absent de l'index" @@ -18654,6 +18855,20 @@ msgstr "" "fichier d'index en bitmap corrompu (trop court pour correspondre à une table " "de recherche)" +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "" +"fichier d'index en bitmap corrompu (trop court pour correspondre à un entête " +"de table de pseudo-fusion)" + +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "" +"fichier d'index en bitmap corrompu (trop court pour correspondre à une table " +"de pseudo-fusion)" + +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "fichier d'index en bitmap corrompu, table de pseudo-fusion trop courte" + #, c-format msgid "duplicate entry in bitmap index: '%s'" msgstr "entrée dupliquée dans l'index en bitmap : '%s'" @@ -18713,6 +18928,9 @@ msgstr "bitmap ewah corrompue : entête tronqué pour la bitmap du commit '%s'" msgid "unable to load pack: '%s', disabling pack-reuse" msgstr "impossible de charger le paquet : '%s', pack-reuse désactivé" +msgid "unable to compute preferred pack, disabling pack-reuse" +msgstr "impossible de calculer le paquet préféré, pack-reuse désactivé" + #, c-format msgid "object '%s' not found in type bitmaps" msgstr "objet '%s' non trouvé dans les bitmaps de type" @@ -18743,6 +18961,10 @@ msgid "mismatch in bitmap results" msgstr "décalage dans le résultats de bitmap" #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "l'index de pseudo-fusion est hors-limite (%<PRIu32> ≥ %<PRIuMAX>)" + +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "impossible de trouver '%s' dans le paquet '%s' à l'offset %<PRIuMAX>" @@ -19115,6 +19337,11 @@ msgstr "impossible de créer le lstat en fil : %s" msgid "unable to parse --pretty format" msgstr "impossible d'analyser le format --pretty" +msgid "lazy fetching disabled; some objects may not be available" +msgstr "" +"récupération paresseuse désactivée ; certains objets pourraient ne pas être " +"disponibles" + msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "" "promisor-remote : impossible de créer un sous-processus de récupération" @@ -19142,6 +19369,68 @@ msgstr "object-info : vidage attendu après les arguments" msgid "Removing duplicate objects" msgstr "Suppression des objets dupliqués" +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "impossible de charger la regex de pseudo-fusion pour %s : '%s'" + +#, c-format +msgid "%s must be non-negative, using default" +msgstr "%s doit être non négatif, utilisation de la valeur par défaut" + +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "%s doit valoir entre 0 et 1, utilisation de la valeur par défaut" + +#, c-format +msgid "%s must be positive, using default" +msgstr "%s doit être positif, utilisation de la valeur par défaut" + +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "le groupe de pseudo-fusion '%s' n'a pas de motif requis" + +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "" +"le group de pseudo-fusion '%s' a un seuil instable avec un seuil stable" + +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "" +"l'expression rationnelle de pseudo-fusion a trop de groupes de capture " +"(max=%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"la lecture de la pseudo-fusion étendue est hors-limite " +"(%<PRIuMAX>=%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"l'entrée de pseudo-fusion étendue est trop courte (%<PRIuMAX> ≥ %<PRIuMAX>)" + +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "" +"impossible de trouver la pseudo-fusion pour le commit '%s' à l'offset " +"%<PRIuMAX>" + +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "recherche de pseudo-fusion étendue hors-limite (%<PRIu32> ≥ %<PRIu32>)" + +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "lecture hors-limite : (%<PRIuMAX> ≥ %<PRIuMAX>)" + +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "" +"impossible de lire la table de pseudo-fusions étendues pour le commit %s" + msgid "could not start `log`" msgstr "impossible de démarrer `log`" @@ -19749,11 +20038,18 @@ msgstr "le journal pour la réf %s s'arrête de manière inattendue sur %s" msgid "log for %s is empty" msgstr "le journal pour la réf %s est vide" +msgid "refusing to force and skip creation of reflog" +msgstr "refus de forcer et sauter la création du reflog" + #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "refus de mettre à jour une réf avec un nom cassé '%s'" #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "refus de mettre à jour la pseudo-réf '%s'" + +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "échec de update_ref pour la réf '%s' : %s" @@ -19784,6 +20080,26 @@ msgid "could not delete references: %s" msgstr "impossible de supprimer les références : %s" #, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "" +"Migration simulée des réfs terminée, le résultat peut être trouvé à '%s'\n" + +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "impossible de supprimer le répetoire de migration temporaire '%s'" + +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "les références migrées peuvent être trouvées dans '%s'" + +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "" +"impossible de vérrouiller '%s' : symref attendu avec la cible '%s', mais réf " +"normale trouvée" + +#, c-format msgid "refname is dangerous: %s" msgstr "le nom de réference est dangereux : %s" @@ -20963,6 +21279,49 @@ msgstr "" "heads/%s" #, c-format +msgid "'%s' does not accept merge commits" +msgstr "'%s' n'accepte pas de commit de fusion" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"'pick' n'accepte pas de commit de fusion. Si vous voulez\n" +"rejouer la fusion, utilisez 'merge -C' sur le commit." + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"'reword' n'accepte pas de commit de fusion.\n" +"Si vous vouliez rejouer la fusion et la reformuler,\n" +"utilisez 'merge -c' sur le commit" + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"'edit' n'accepte pas de commit de fusion. Si vous vouliez\n" +"rejouer la fusion, utilisez 'merge -C' sur le commit, puis\n" +"'break' pour vous redonner le contrôle pour pouvoir faire\n" +"'git commit --amend && git rebase --continue'." + +msgid "cannot squash merge commit into another commit" +msgstr "impossible d'écraser un commit de fusion avec un autre commit" + +#, c-format msgid "invalid command '%.*s'" msgstr "commande '%.*s' invalide" @@ -21079,9 +21438,8 @@ msgstr "" msgid "cannot read HEAD" msgstr "impossible de lire HEAD" -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "impossible de copier '%s' vers '%s'" +msgid "could not write commit message file" +msgstr "impossible d'écrire le fichier de message de validation" #, c-format msgid "" @@ -21487,6 +21845,18 @@ msgstr "impossible de revenir au répertoire de travail courant" msgid "failed to stat '%*s%s%s'" msgstr "échec du stat de '%*s%s%s'" +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"propriétaire douteux détecté dans le dépôt à '%s'\n" +"%sPour ajouter une exception pour ce dépôt, lancez :\n" +"\n" +"\tgit config --global --add safe.directory %s" + msgid "Unable to read current working directory" msgstr "Impossible d'accéder au répertoire de travail courant" @@ -21509,18 +21879,6 @@ msgstr "" "n'est pas défini)." #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"propriétaire douteux détecté dans le dépôt à '%s'\n" -"%sPour ajouter une exception pour ce dépôt, lancez :\n" -"\n" -"\tgit config --global --add safe.directory %s" - -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" msgstr "impossible d'utiliser le dépôt nu '%s' (safe.bareRepository vaut '%s')" @@ -21830,6 +22188,16 @@ msgstr "" "'%.*s'" #, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "" +"'%.*s' dans le chemin du sous-module '%s' ne devait pas être un lien " +"symbolique" + +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "le chemin du sous-module '%s' ne devait pas être un lien symbolique" + +#, c-format msgid "" "relocate_gitdir for submodule '%s' with more than one worktree not supported" msgstr "" @@ -21868,10 +22236,6 @@ msgstr "échec du lstat de '%s'" msgid "no remote configured to get bundle URIs from" msgstr "aucun distant configuré depuis lequel récupérer des URIs de colis" -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "le distant '%s' n'a pas d'URL configuré" - msgid "could not get the bundle-uri list" msgstr "impossible d'avoir la liste de bundle-uris" @@ -23374,24 +23738,24 @@ msgid "Failed to send %s\n" msgstr "Échec de l'envoi de %s\n" #, perl-format -msgid "Dry-Sent %s\n" -msgstr "Envoi simulé de %s\n" +msgid "Dry-Sent %s" +msgstr "Envoi simulé de %s" #, perl-format -msgid "Sent %s\n" -msgstr "%s envoyé\n" +msgid "Sent %s" +msgstr "%s envoyé" -msgid "Dry-OK. Log says:\n" -msgstr "Simulation OK. Le journal indique :\n" +msgid "Dry-OK. Log says:" +msgstr "Simulation OK. Le journal indique :" -msgid "OK. Log says:\n" -msgstr "OK. Le journal indique :\n" +msgid "OK. Log says:" +msgstr "OK. Le journal indique :" msgid "Result: " msgstr "Résultat : " -msgid "Result: OK\n" -msgstr "Résultat : OK\n" +msgid "Result: OK" +msgstr "Résultat : OK" #, perl-format msgid "can't open file %s" @@ -23466,6 +23830,38 @@ msgstr "%s sauté avec un suffix de sauvegarde '%s'.\n" msgid "Do you really want to send %s? [y|N]: " msgstr "Souhaitez-vous réellement envoyer %s ?[y|N] : " +#, c-format +#~ msgid "truncating .rej filename to %.*s.rej" +#~ msgstr "troncature du nom de fichier .rej en %.*s.rej" + +#~ msgid "" +#~ "the add.interactive.useBuiltin setting has been removed!\n" +#~ "See its entry in 'git help config' for details." +#~ msgstr "" +#~ "le réglage add.interactive.useBuiltin a été supprimé !\n" +#~ "Référez-vous à cette entrée dans 'git help config' pour plus de détails." + +#~ msgid "git archive: Remote with no URL" +#~ msgstr "git archive : Dépôt distant sans URL" + +#~ msgid "only one action at a time" +#~ msgstr "une seule action à la fois" + +#~ msgid "use [RFC PATCH] instead of [PATCH]" +#~ msgstr "utiliser [RFC PATCH] au lieu de [PATCH]" + +#, c-format +#~ msgid "no URLs configured for remote '%s'" +#~ msgstr "aucune URL configurée pour le dépôt distant '%s'" + +#, c-format +#~ msgid "unable to copy '%s' to '%s'" +#~ msgstr "impossible de copier '%s' vers '%s'" + +#, c-format +#~ msgid "remote '%s' has no configured URL" +#~ msgstr "le distant '%s' n'a pas d'URL configuré" + #~ msgid "" #~ "Use -f if you really want to add them.\n" #~ "Turn this message off by running\n" @@ -23509,9 +23905,6 @@ msgstr "Souhaitez-vous réellement envoyer %s ?[y|N] : " #~ msgid "core.commentChar should only be one ASCII character" #~ msgstr "core.commentChar ne devrait être qu'un unique caractère ASCII" -#~ msgid "-x and -X cannot be used together" -#~ msgstr "-x et -X ne peuvent pas être utilisés ensemble" - #~ msgid "" #~ "--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-" #~ "exclude" @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-25 18:57+0000\n" -"PO-Revision-Date: 2024-04-26 15:33+0700\n" +"POT-Creation-Date: 2024-07-19 14:03+0700\n" +"PO-Revision-Date: 2024-07-19 14:25+0700\n" "Last-Translator: Bagas Sanjaya <bagasdotme@gmail.com>\n" "Language-Team: Indonesian\n" "Language: id\n" @@ -104,12 +104,12 @@ msgstr[1] "%d jalur ditambahkan\n" msgid "ignoring unmerged: %s" msgstr "mengabaikan tak tergabung: %s" -#: add-interactive.c add-patch.c +#: add-interactive.c #, c-format msgid "Only binary files changed.\n" msgstr "Hanya berkas biner yang berubah.\n" -#: add-interactive.c add-patch.c +#: add-interactive.c #, c-format msgid "No changes.\n" msgstr "Tidak ada perubahan.\n" @@ -666,6 +666,11 @@ msgstr "" "? - lihat bantuan\n" #: add-patch.c +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "Hanya satu huruf yang diharapkan, dapat '%s'" + +#: add-patch.c msgid "No previous hunk" msgstr "Tidak ada bingkah sebelumnya" @@ -728,9 +733,22 @@ msgid "Sorry, cannot edit this hunk" msgstr "Maaf, tidak dapat menyunting bingkah ini" #: add-patch.c +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "Perintah tidak dikenal '%s' (gunakan '?' untuk bantuan)" + +#: add-patch.c msgid "'git apply' failed" msgstr "'git apply' gagal" +#: add-patch.c +msgid "No changes." +msgstr "Tidak ada perubahan." + +#: add-patch.c +msgid "Only binary files changed." +msgstr "Hanya berkas biner yang berubah." + #: advice.c #, c-format msgid "" @@ -911,7 +929,7 @@ msgid "unclosed quote" msgstr "tanda kutip tak ditutup" #: alias.c builtin/cat-file.c builtin/notes.c builtin/prune-packed.c -#: builtin/receive-pack.c builtin/tag.c t/helper/test-pkt-line.c +#: builtin/receive-pack.c builtin/refs.c builtin/tag.c t/helper/test-pkt-line.c msgid "too many arguments" msgstr "terlalu banyak argumen" @@ -1808,6 +1826,11 @@ msgid "ignoring overly large gitattributes blob '%s'" msgstr "mengabaikan blob gitattributes '%s' yang terlalu besar" #: attr.c +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "" +"tidak dapat menggunakan --attr-source atau GIT_ATTR_SOURCE tanpa repositori" + +#: attr.c msgid "bad --attr-source or GIT_ATTR_SOURCE" msgstr "--attr-source atau GIT_ATTR_SOURCE jelek" @@ -2183,14 +2206,6 @@ msgid "Unstaged changes after refreshing the index:" msgstr "Perubahan tak tergelar setelah menyegarkan indeks:" #: builtin/add.c -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"setelan add.interactive.useBuiltin sudah dihapus!\n" -"Selengkapnya lihat entrinya di 'git help config'." - -#: builtin/add.c msgid "could not read the index" msgstr "tidak dapat membaca indeks" @@ -2644,7 +2659,7 @@ msgstr "" "Sepertinya Anda telah memindahkan HEAD sejak kegagalan 'am' terakhir.\n" "Tidak memutar ulang ke ORIG_HEAD" -#: builtin/am.c builtin/bisect.c worktree.c +#: builtin/am.c builtin/bisect.c builtin/tag.c worktree.c #, c-format msgid "failed to read '%s'" msgstr "gagal membaca '%s'" @@ -2722,8 +2737,8 @@ msgstr "n" #: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c #: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c -#: builtin/ls-files.c builtin/ls-tree.c builtin/replace.c builtin/tag.c -#: builtin/verify-tag.c +#: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c +#: builtin/tag.c builtin/verify-tag.c msgid "format" msgstr "format" @@ -2760,6 +2775,10 @@ msgid "show the patch being applied" msgstr "perlihatkan tambalan yang diterapkan" #: builtin/am.c +msgid "try to apply current patch again" +msgstr "coba terapkan lagi tambalan saat ini" + +#: builtin/am.c msgid "record the empty patch as an empty commit" msgstr "rekam tambalan kosong sebagai komit kosong" @@ -2832,10 +2851,6 @@ msgid "could not redirect output" msgstr "tidak dapat mengalihkan keluaran" #: builtin/archive.c -msgid "git archive: Remote with no URL" -msgstr "git archive: Remote tanpa URL" - -#: builtin/archive.c msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "git archive: ACK/NAK diharapkan, dapat paket bilasan" @@ -3960,6 +3975,10 @@ msgstr "Perlu sebuah repositori untuk membuat bundel." msgid "do not show bundle details" msgstr "jangan perlihatkan detail bundel" +#: builtin/bundle.c bundle.c +msgid "need a repository to verify a bundle" +msgstr "perlu sebuah repositori untuk verifikasi bundel" + #: builtin/bundle.c #, c-format msgid "%s is okay\n" @@ -5018,9 +5037,9 @@ msgstr "pembersihan interaktif" msgid "remove whole directories" msgstr "hapus keseluruhan direktori" -#: builtin/clean.c builtin/describe.c builtin/grep.c builtin/log.c -#: builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c builtin/show-ref.c -#: ref-filter.h +#: builtin/clean.c builtin/config.c builtin/describe.c builtin/grep.c +#: builtin/log.c builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c +#: builtin/show-ref.c ref-filter.h msgid "pattern" msgstr "pola" @@ -5239,6 +5258,16 @@ msgstr "gagal menghapus tautan '%s'" #: builtin/clone.c #, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "tautan keras tidak dapat diperiksa pada '%s'" + +#: builtin/clone.c +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "tautan keras berbeda dari sumber pada '%s'" + +#: builtin/clone.c +#, c-format msgid "failed to create link '%s'" msgstr "gagal membuat tautan '%s'" @@ -5313,7 +5342,7 @@ msgstr "Terlalu banyak argumen." msgid "You must specify a repository to clone." msgstr "Anda harus sebutkan repositori untuk diklon." -#: builtin/clone.c builtin/init-db.c setup.c +#: builtin/clone.c builtin/init-db.c builtin/refs.c setup.c #, c-format msgid "unknown ref storage format '%s'" msgstr "format penyimpanan referensi tidak dikenal '%s'" @@ -5936,7 +5965,7 @@ msgstr "%sPengkomit: %.*s <%.*s>" msgid "Cannot read index" msgstr "Tidak dapat membaca indeks" -#: builtin/commit.c +#: builtin/commit.c builtin/tag.c msgid "unable to pass trailers to --trailers" msgstr "tidak dapat melewatkan trailer ke --trailers" @@ -6152,11 +6181,11 @@ msgstr "gunakan pesan terformat autosquash untuk lumat komit tersebut" msgid "the commit is authored by me now (used with -C/-c/--amend)" msgstr "komit sekarang dikarang olehku (gunakan dengan -C/-c/--amend)" -#: builtin/commit.c builtin/interpret-trailers.c +#: builtin/commit.c builtin/interpret-trailers.c builtin/tag.c msgid "trailer" msgstr "trailer" -#: builtin/commit.c +#: builtin/commit.c builtin/tag.c msgid "add custom trailer(s)" msgstr "tambahkan trailer kustom" @@ -6269,17 +6298,58 @@ msgstr "" "tidak terlampaui, lalu \"git restore --staged :/\" untuk pulihkan." #: builtin/config.c -msgid "git config [<options>]" -msgstr "git config [<opsi>]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "git config list [<opsi berkas>] [<opsi tampilan>] [--includes]" #: builtin/config.c -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "argumen --type tidak dikenal %s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [<opsi berkas>] [<opsi tampilan] [--includes] [--all] [--" +"regexp=<regexp> [--value=<nilai>] [--fixed-value] [--default=<default>] " +"<nama>" #: builtin/config.c -msgid "only one type at a time" -msgstr "hanya satu tipe pada suatu saat" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [<opsi berkas>] [--type=<tipe>] [--all] [--value=<nilai>] [--" +"fixed-value] <nama> <nilai>" + +#: builtin/config.c +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [<opsi berkas] [--all] [--value=<nilai>] [--fixed-value] " +"<nama> <nilai>" + +#: builtin/config.c +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "git config rename-section [<opsi berkas>] <nama lama> <nama baru>" + +#: builtin/config.c +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [<opsi berkas>] <nama>" + +#: builtin/config.c +msgid "git config edit [<file-option>]" +msgstr "git config edit [<opsi berkas>]" + +#: builtin/config.c +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "git config [<opsi berkas>] --get-colorbool <nama> [<stdout-is-tty>]" + +#: builtin/config.c +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [<opsi berkas>] [--type=<tipe>] [--comment=<pesan>] [--all] " +"[--value=<nilai>] [--fixed-value] <nama> <nilai>" #: builtin/config.c msgid "Config file location" @@ -6314,70 +6384,6 @@ msgid "read config from given blob object" msgstr "baca konfigurasi dari objek blob yang diberikan" #: builtin/config.c -msgid "Action" -msgstr "Tindakan" - -#: builtin/config.c -msgid "get value: name [value-pattern]" -msgstr "dapatkan nilai: name [pola nilai]" - -#: builtin/config.c -msgid "get all values: key [value-pattern]" -msgstr "dapatkan semua nilai: key [pola nilai]" - -#: builtin/config.c -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "dapatkan nilai dari regexp: name-regex [pola nilai]" - -#: builtin/config.c -msgid "get value specific for the URL: section[.var] URL" -msgstr "dapatkan nilai spesifik untuk URL: section[.var] URL" - -#: builtin/config.c -msgid "replace all matching variables: name value [value-pattern]" -msgstr "ganti semua variabel yang cocok: name value [pola nilai]" - -#: builtin/config.c -msgid "add a new variable: name value" -msgstr "tambahkan variabel baru: name value" - -#: builtin/config.c -msgid "remove a variable: name [value-pattern]" -msgstr "hapus variabel: name [pola nilai]" - -#: builtin/config.c -msgid "remove all matches: name [value-pattern]" -msgstr "hapus semua cocokan: name [pola nilai]" - -#: builtin/config.c -msgid "rename section: old-name new-name" -msgstr "ganti nama bagian: old-name new-name" - -#: builtin/config.c -msgid "remove a section: name" -msgstr "hapus bagian: name" - -#: builtin/config.c -msgid "list all" -msgstr "daftar semua" - -#: builtin/config.c -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "gunakan kesamaan untai ketika membandingkan nilai ke 'pola nilai'" - -#: builtin/config.c -msgid "open an editor" -msgstr "buka penyunting" - -#: builtin/config.c -msgid "find the color configured: slot [default]" -msgstr "temukan warna terkonfigurasi: slot [asali]" - -#: builtin/config.c -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "temukan setelan warna: slot [stdout-is-tty]" - -#: builtin/config.c msgid "Type" msgstr "Tipe" @@ -6414,8 +6420,8 @@ msgid "value is an expiry date" msgstr "nilai adalah tanggal kadaluarsa" #: builtin/config.c -msgid "Other" -msgstr "Lainnya" +msgid "Display options" +msgstr "Tampilkan opsi" #: builtin/config.c msgid "terminate values with NUL byte" @@ -6426,10 +6432,6 @@ msgid "show variable names only" msgstr "perlihatkan hanya nama variabel" #: builtin/config.c -msgid "respect include directives on lookup" -msgstr "segani arahan masukkan pada pencarian" - -#: builtin/config.c msgid "show origin of config (file, standard input, blob, command line)" msgstr "" "perlihatkan asal konfigurasi (berkas, masukan standar, blob, baris perintah)" @@ -6441,17 +6443,17 @@ msgstr "" "perintah)" #: builtin/config.c -msgid "value" -msgstr "nilai" +msgid "show config keys in addition to their values" +msgstr "perlihatkan kunci opsi beserta nilainya" #: builtin/config.c -msgid "with --get, use default value when missing entry" -msgstr "dengan --get, gunakan nilai asali ketika kehilangan entri" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "argumen --type tidak dikenal %s" #: builtin/config.c -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "" -"untai komentar yang dapat dibaca manusia (# akan ditambahkan bila diperlukan" +msgid "only one type at a time" +msgstr "hanya satu tipe pada suatu saat" #: builtin/config.c #, c-format @@ -6545,60 +6547,94 @@ msgstr "" "\"CONFIGURATION FILE\" di \"git help worktree\" untuk selengkapnya" #: builtin/config.c -msgid "--get-color and variable type are incoherent" -msgstr "--get-color dan tipe variabel raban" +msgid "Other" +msgstr "Lainnya" #: builtin/config.c -msgid "only one action at a time" -msgstr "hanya satu tindakan pada suatu saat" +msgid "respect include directives on lookup" +msgstr "segani arahan masukkan pada pencarian" #: builtin/config.c -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "--name-only hanya dapat diterapkan pada --list atau --get-regexp" +#, c-format +msgid "unable to read config file '%s'" +msgstr "tidak dapat membaca berkas konfigurasi '%s'" #: builtin/config.c -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" -msgstr "" -"--show-origin hanya dapat diterapkan pada --get, --get-all, --get-regexp, " -"dan --list" +msgid "error processing config file(s)" +msgstr "kesalahan memproses berkas konfigurasi" #: builtin/config.c -msgid "--default is only applicable to --get" -msgstr "--default hanya dapat diterapkan pada --get" +msgid "Filter options" +msgstr "Opsi penyaringan" #: builtin/config.c -msgid "--comment is only applicable to add/set/replace operations" -msgstr "" -"--comment hanya dapat diterapkan pada operasi penambahan/penyetelan/" -"penggantian" +msgid "return all values for multi-valued config options" +msgstr "dapatkan semua nilai untuk opsi konfigurasi multi-nilai" + +#: builtin/config.c +msgid "interpret the name as a regular expression" +msgstr "tafsirkan nama sebagai ekspresi reguler" + +#: builtin/config.c +msgid "show config with values matching the pattern" +msgstr "perlihatkan konfigurasi dengan nilai yang cocok dengan pola" + +#: builtin/config.c +msgid "use string equality when comparing values to value pattern" +msgstr "gunakan kesamaan untai ketika membandingkan nilai dan pola nilai" + +#: builtin/config.c +msgid "URL" +msgstr "URL" + +#: builtin/config.c +msgid "show config matching the given URL" +msgstr "perlihatkan konfigurasi yang cocok dengan URL yang diberikan" + +#: builtin/config.c +msgid "value" +msgstr "nilai" + +#: builtin/config.c +msgid "use default value when missing entry" +msgstr "gunakan nilai asali ketika entri hilang" #: builtin/config.c msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value hanya diterapkan dengan 'pola nilai'" #: builtin/config.c -#, c-format -msgid "unable to read config file '%s'" -msgstr "tidak dapat membaca berkas konfigurasi '%s'" +msgid "--default= cannot be used with --all or --url=" +msgstr "--default= tidak dapat digunakan dengan --all atau --url=" #: builtin/config.c -msgid "error processing config file(s)" -msgstr "kesalahan memproses berkas konfigurasi" +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "--url= tidak dapat digunakan dengan --all, --regexp atau --value" #: builtin/config.c -msgid "editing stdin is not supported" -msgstr "menyunting stdin tidak didukung" +msgid "Filter" +msgstr "Penyaring" #: builtin/config.c -msgid "editing blobs is not supported" -msgstr "menyunting blob tidak didukung" +msgid "replace multi-valued config option with new value" +msgstr "ganti opsi konfigurasi multi-nilai dengan nilai baru" #: builtin/config.c -#, c-format -msgid "cannot create configuration file %s" -msgstr "tidak dapat membuat berkas konfigurasi %s" +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "" +"untai komentar yang dapat dibaca manusia (# akan ditambahkan bila diperlukan" + +#: builtin/config.c +msgid "add a new line without altering any existing values" +msgstr "tambahkan baris baru tanpa mengubah nilai yang ada" + +#: builtin/config.c +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "--fixed-value hanya diterapkan dengan --value=<pola>" + +#: builtin/config.c +msgid "--append cannot be used with --value=<pattern>" +msgstr "--append tidak dapat digunakan dengan --value=<pola>" #: builtin/config.c #, c-format @@ -6614,6 +6650,113 @@ msgstr "" msgid "no such section: %s" msgstr "tidak ada bagian seperti: %s" +#: builtin/config.c +msgid "editing stdin is not supported" +msgstr "menyunting stdin tidak didukung" + +#: builtin/config.c +msgid "editing blobs is not supported" +msgstr "menyunting blob tidak didukung" + +#: builtin/config.c +#, c-format +msgid "cannot create configuration file %s" +msgstr "tidak dapat membuat berkas konfigurasi %s" + +#: builtin/config.c +msgid "Action" +msgstr "Tindakan" + +#: builtin/config.c +msgid "get value: name [<value-pattern>]" +msgstr "dapatkan nilai: name [<pola nilai>]" + +#: builtin/config.c +msgid "get all values: key [<value-pattern>]" +msgstr "dapatkan semua nilai: key [<pola nilai>]" + +#: builtin/config.c +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "dapatkan nilai dari ekspresi reguler: name-regex [<pola nilai>]" + +#: builtin/config.c +msgid "get value specific for the URL: section[.var] URL" +msgstr "dapatkan nilai spesifik untuk URL: section[.var] URL" + +#: builtin/config.c +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "ganti semua variabel yang cocok: name value [<pola nilai>]" + +#: builtin/config.c +msgid "add a new variable: name value" +msgstr "tambahkan variabel baru: name value" + +#: builtin/config.c +msgid "remove a variable: name [<value-pattern>]" +msgstr "hapus variabel: name [<pola nilai>]" + +#: builtin/config.c +msgid "remove all matches: name [<value-pattern>]" +msgstr "hapus semua cocokan: name [<pola nilai>]" + +#: builtin/config.c +msgid "rename section: old-name new-name" +msgstr "ganti nama bagian: old-name new-name" + +#: builtin/config.c +msgid "remove a section: name" +msgstr "hapus bagian: name" + +#: builtin/config.c +msgid "list all" +msgstr "daftar semua" + +#: builtin/config.c +msgid "open an editor" +msgstr "buka penyunting" + +#: builtin/config.c +msgid "find the color configured: slot [<default>]" +msgstr "temukan warna terkonfigurasi: slot [<asali>]" + +#: builtin/config.c +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "temukan setelan warna: slot [<stdout-is-tty>]" + +#: builtin/config.c +msgid "with --get, use default value when missing entry" +msgstr "dengan --get, gunakan nilai asali ketika kehilangan entri" + +#: builtin/config.c +msgid "--get-color and variable type are incoherent" +msgstr "--get-color dan tipe variabel raban" + +#: builtin/config.c +msgid "no action specified" +msgstr "tidak ada tindakan yang dipilih" + +#: builtin/config.c +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "--name-only hanya dapat diterapkan pada --list atau --get-regexp" + +#: builtin/config.c +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "" +"--show-origin hanya dapat diterapkan pada --get, --get-all, --get-regexp, " +"dan --list" + +#: builtin/config.c +msgid "--default is only applicable to --get" +msgstr "--default hanya dapat diterapkan pada --get" + +#: builtin/config.c +msgid "--comment is only applicable to add/set/replace operations" +msgstr "" +"--comment hanya dapat diterapkan pada operasi penambahan/penyetelan/" +"penggantian" + #: builtin/count-objects.c msgid "print sizes in human readable format" msgstr "cetak ukuran dalam format yang bisa dibaca manusia" @@ -7662,6 +7805,10 @@ msgid "config key storing a list of repository paths" msgstr "kunci konfigurasi yang menampung daftar jalur repositori" #: builtin/for-each-repo.c +msgid "keep going even if command fails in a repository" +msgstr "tetap lanjut meski perintah gagal pada repositori" + +#: builtin/for-each-repo.c msgid "missing --config=<config>" msgstr "kehilangan --config=<config>" @@ -9518,8 +9665,12 @@ msgid "max length of output filename" msgstr "panjang nama berkas keluaran maksimum" #: builtin/log.c -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "gunakan [RFC PATCH] daripada [PATCH]" +msgid "rfc" +msgstr "rfc" + +#: builtin/log.c +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "tambahkan <rfc> (asali 'RFC') sebelum 'PATCH'" #: builtin/log.c msgid "cover-from-description-mode" @@ -9870,11 +10021,11 @@ msgstr "" #: builtin/ls-remote.c msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<kunci>]\n" " [--symref] [<repositori> [<pola>...]]" @@ -9895,8 +10046,12 @@ msgid "limit to tags" msgstr "batasi ke tag" #: builtin/ls-remote.c -msgid "limit to heads" -msgstr "batasi ke kepala" +msgid "limit to branches" +msgstr "batasi ke cabang" + +#: builtin/ls-remote.c builtin/show-ref.c +msgid "deprecated synonym for --branches" +msgstr "sinonim usang untuk --branches" #: builtin/ls-remote.c msgid "do not show peeled tags" @@ -13177,6 +13332,27 @@ msgstr "tidak ada log referensi yang disebutkan untuk dihapus" msgid "invalid ref format: %s" msgstr "format referensi tidak valid: %s" +#: builtin/refs.c +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=<format> [--dry-run]" + +#: builtin/refs.c +msgid "specify the reference format to convert to" +msgstr "sebutkan format referensi untuk dikonversi" + +#: builtin/refs.c +msgid "perform a non-destructive dry-run" +msgstr "lakukan uji coba non desktruktif" + +#: builtin/refs.c +msgid "missing --ref-format=<format>" +msgstr "--ref-format=<format> hilang" + +#: builtin/refs.c +#, c-format +msgid "repository already uses '%s' format" +msgstr "repositori telah menggunakan format '%s'" + #: builtin/remote.c msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" @@ -13530,10 +13706,6 @@ msgstr "* remote %s" msgid " Fetch URL: %s" msgstr " URL pengambilan: %s" -#: builtin/remote.c -msgid "(no URL)" -msgstr "(tidak ada URL)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -13544,6 +13716,10 @@ msgid " Push URL: %s" msgstr " URL pendorongan: %s" #: builtin/remote.c +msgid "(no URL)" +msgstr "(tidak ada URL)" + +#: builtin/remote.c #, c-format msgid " HEAD branch: %s" msgstr " Cabang HEAD: %s" @@ -13678,11 +13854,6 @@ msgid "return all URLs" msgstr "kembalikan semua URL" #: builtin/remote.c -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "tidak ada URL yang dikonfigurasi untuk remote '%s'" - -#: builtin/remote.c msgid "manipulate push URLs" msgstr "manipulasi URL pendorongan" @@ -14951,12 +15122,12 @@ msgstr "algoritma hash tidak dikenal" #: builtin/show-ref.c msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pola>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pola>...]" #: builtin/show-ref.c msgid "" @@ -14985,12 +15156,12 @@ msgid "failed to look up reference" msgstr "gagal mencari referensi" #: builtin/show-ref.c -msgid "only show tags (can be combined with heads)" -msgstr "hanya perlihatkan tag (bisa dikombinasikan dengan kepala)" +msgid "only show tags (can be combined with branches)" +msgstr "hanya perlihatkan tag (bisa dikombinasikan dengan cabang)" #: builtin/show-ref.c -msgid "only show heads (can be combined with tags)" -msgstr "hanya perlihatkan kepala (bisa dikombinasikan dengan tag)" +msgid "only show branches (can be combined with tags)" +msgstr "hanya perlihatkan cabang (bisa dikombinasikan dengan tag)" #: builtin/show-ref.c msgid "check for reference existence without resolving" @@ -15765,7 +15936,7 @@ msgstr "Nilai '%s' untuk submodule.alternateErrorStrategy tidak dikenal" msgid "Value '%s' for submodule.alternateLocation is not recognized" msgstr "Nilai '%s' untuk submodule.alternateLocation tidak dikenal" -#: builtin/submodule--helper.c +#: builtin/submodule--helper.c submodule.c #, c-format msgid "refusing to create/use '%s' in another submodule's git dir" msgstr "" @@ -15773,13 +15944,13 @@ msgstr "" #: builtin/submodule--helper.c #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "gagal mengkloning '%s' ke dalam jalur submodul '%s'" +msgid "directory not empty: '%s'" +msgstr "direktori tidak kosong: '%s'" #: builtin/submodule--helper.c #, c-format -msgid "directory not empty: '%s'" -msgstr "direktori tidak kosong: '%s'" +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "gagal mengkloning '%s' ke dalam jalur submodul '%s'" #: builtin/submodule--helper.c #, c-format @@ -16230,9 +16401,11 @@ msgstr "alasan pembaruan" #: builtin/tag.c msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" "git tag [-a | -s | -u <id kunci>] [-f] [-m <pesan> | -F <berkas>] [-e]\n" +" [(--trailer <token>[(=|:)<nilai>])...]\n" " <nama tag> [<komit> | <objek>]" #: builtin/tag.c @@ -17292,10 +17465,6 @@ msgid "Repository lacks these prerequisite commits:" msgstr "Repositori kekurangan komit prasyarat berikut:" #: bundle.c -msgid "need a repository to verify a bundle" -msgstr "perlu sebuah repositori untuk verifikasi bundel" - -#: bundle.c msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -17825,6 +17994,10 @@ msgid "Manage reflog information" msgstr "Kelola informasi log referensi" #: command-list.h +msgid "Low-level access to refs" +msgstr "Akses tingat bawah ke referensi" + +#: command-list.h msgid "Manage set of tracked repositories" msgstr "Kelola set repositori terlacak" @@ -18226,6 +18399,15 @@ msgid "commit-graph required commit data chunk missing or corrupted" msgstr "bingkah grafik komit data komit yang diperlukan hilang atau rusak" #: commit-graph.c +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "" +"menonaktifkan penyaring Bloom untuk lapisan grafik komit '%s' karena setelan " +"yang tidak cocok" + +#: commit-graph.c msgid "commit-graph has no base graphs chunk" msgstr "grafik komit tidak punya bingkah grafik dasar" @@ -18384,6 +18566,15 @@ msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled" msgstr "mencoba menulis grafik komit, tapi 'core.commitGraph' dimatikan" #: commit-graph.c +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " +"(%d) is not supported" +msgstr "" +"mencoba menulis grafik komit, tapi 'commitGraph.changedPathsVersion (%d) " +"tidak didukung" + +#: commit-graph.c msgid "too many commits to write graph" msgstr "terlalu banyak komit untuk menulis grafik" @@ -20693,15 +20884,17 @@ msgstr "" msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v| --version] [-h | --help] [-C <jalur>] [-c <nama>=<nilai>]\n" " [--exec-path[=<jalur>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects]\n" +" [--no-lazy-fetch] [--no-optional-locks] [--no-advice] [--bare]\n" " [--git-dir=<jalur>] [--work-tree=<jalur>] [--namespace=<nama>]\n" " [--config-env=<nama>=<variabel lingkungan>]\n" " <perintah> [<argumen>]" @@ -21117,14 +21310,14 @@ msgstr "" "ignoredHook false`." #: http-fetch.c +msgid "not a git repository" +msgstr "bukan sebuah repositori git" + +#: http-fetch.c #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "argumen ke --packfile harus sebuah hash valid (dapat '%s')" -#: http-fetch.c -msgid "not a git repository" -msgstr "bukan sebuah repositori git" - #: http.c #, c-format msgid "negative value for http.postBuffer; defaulting to %d" @@ -21139,6 +21332,10 @@ msgid "Public key pinning not supported with cURL < 7.39.0" msgstr "Penyematan kunci publik tidak didukung oleh cURL < 7.39.0" #: http.c +msgid "Unknown value for http.proactiveauth" +msgstr "nilai tidak dikenal untuk http.proactiveauth" + +#: http.c msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "CURLSSLOPT_NO_REVOKE tidak didukung dengan cURL < 7.44.0" @@ -21160,6 +21357,14 @@ msgid "Could not set SSL backend to '%s': already set" msgstr "Tidak dapat menyetel tulang punggung SSL ke '%s': sudah disetel" #: http.c +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "menolak membaca kuki dari http.cookiefile '-'" + +#: http.c +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "mengabaikan http.savecookies karena http.cookiefile kosong" + +#: http.c #, c-format msgid "" "unable to update url base from redirection:\n" @@ -21367,10 +21572,10 @@ msgstr "Gagal menggabungkan submodul %s (tidak ada dasar penggabungan)" msgid "Failed to merge submodule %s (commits not present)" msgstr "Gagal menggabungkan submodul %s (komit tidak ada)" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" -msgstr "Gagal menggabungkan submodul %s (repositori rusak)" +msgid "error: failed to merge submodule %s (repository corrupt)" +msgstr "kesalahan: gagal menggabungkan submodul %s (repositori rusak)" #: merge-ort.c merge-recursive.c #, c-format @@ -21406,14 +21611,15 @@ msgstr "" "mungkin:\n" "%s" -#: merge-ort.c merge-recursive.c -msgid "failed to execute internal merge" -msgstr "gagal menjalankan penggabungan internal" +#: merge-ort.c +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "kesalahan: gagal menjalankan penggabungan internal untuk %s" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "unable to add %s to database" -msgstr "tidak dapat menambahkan %s ke basis data" +msgid "error: unable to add %s to database" +msgstr "kesalahan: tidak dapat menambahkan %s ke basis data" #: merge-ort.c merge-recursive.c #, c-format @@ -21520,15 +21726,15 @@ msgstr "" "KONFLIK (penamaan ulang/penghapusan): %s dinamai ulang ke %s di %s, tetapi " "dihapus di %s." -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "cannot read object %s" -msgstr "tidak dapat membaca objek %s" +msgid "error: cannot read object %s" +msgstr "kesalahan: tidak dapat membaca objek %s" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "object %s is not a blob" -msgstr "objek %s bukanlah sebuah blob" +msgid "error: object %s is not a blob" +msgstr "kesalahan: objek %s bukanlah suatu blob" #: merge-ort.c #, c-format @@ -21689,6 +21895,11 @@ msgstr "tidak tahu apa yang dilakukan dengan %06o %s '%s'" #: merge-recursive.c #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "Gagal menggabungkan submodul %s (repositori rusak)" + +#: merge-recursive.c +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "Memaju-cepat submodul %s ke komit berikut:" @@ -21735,6 +21946,15 @@ msgid "Failed to merge submodule %s (multiple merges found)" msgstr "Gagal menggabungkan submodul %s (banyak penggabungan ditemukan)" #: merge-recursive.c +msgid "failed to execute internal merge" +msgstr "gagal menjalankan penggabungan internal" + +#: merge-recursive.c +#, c-format +msgid "unable to add %s to database" +msgstr "tidak dapat menambahkan %s ke basis data" + +#: merge-recursive.c #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "" @@ -21857,6 +22077,16 @@ msgstr "" "%s. Penamaan ulang %s->%s di %s" #: merge-recursive.c +#, c-format +msgid "cannot read object %s" +msgstr "tidak dapat membaca objek %s" + +#: merge-recursive.c +#, c-format +msgid "object %s is not a blob" +msgstr "objek %s bukanlah sebuah blob" + +#: merge-recursive.c msgid "modify" msgstr "ubah" @@ -21962,10 +22192,6 @@ msgid "malformed line: %s" msgstr "baris jelek '%s'." #: midx-write.c -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "abaikan indeks multipak yang sudah ada; checksum tidak cocok" - -#: midx-write.c msgid "could not load pack" msgstr "tidak dapat memuat pak" @@ -21975,6 +22201,10 @@ msgid "could not open index for %s" msgstr "tidak dapat membuka indeks untuk %s" #: midx-write.c +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "abaikan indeks multipak yang sudah ada; checksum tidak cocok" + +#: midx-write.c msgid "Adding packfiles to multi-pack-index" msgstr "Menambahkan berkas pak ke indeks multipak" @@ -22723,6 +22953,20 @@ msgid "hash mismatch %s" msgstr "hash tidak cocok %s" #: pack-bitmap-write.c +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "entri duplikat ketika menulis indeks bitmap: %s" + +#: pack-bitmap-write.c +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "mencoba menyimpan komit yang tidak dipilih: '%s'" + +#: pack-bitmap-write.c +msgid "too many pseudo-merges" +msgstr "terlalu banyak penggabungan semu" + +#: pack-bitmap-write.c msgid "trying to write commit not in index" msgstr "mencoba menulis komit yang bukan di indeks" @@ -22753,6 +22997,23 @@ msgstr "" "berkas indeks bitmap rusak (terlalu pendek untuk masuk tabel pencarian)" #: pack-bitmap.c +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "" +"berkas indeks bitmap rusak (terlalu pendek untuk masuk kepala tabel " +"penggabungan semu)" + +#: pack-bitmap.c +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "" +"berkas indeks bitmap rusak (terlalu pendek untuk masuk tabel penggabungan " +"semu)" + +#: pack-bitmap.c +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "berkas indeks bitmap rusak (tabel penggabungan semu terlalu pendek)" + +#: pack-bitmap.c #, c-format msgid "duplicate entry in bitmap index: '%s'" msgstr "entri duplikat di indeks bitmap: '%s'" @@ -22868,6 +23129,11 @@ msgstr "ketidaksesuaian di dalam hasil bitmap" #: pack-bitmap.c #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "indeks penggabungan semu di luar jangkauan (%<PRIu32> >= %<PRIuMAX>)" + +#: pack-bitmap.c +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "tidak dapat menemukan %s di dalam pak '%s' pada offset %<PRIuMAX>" @@ -23325,6 +23591,10 @@ msgid "unable to parse --pretty format" msgstr "tidak dapat menguraikan format --pretty" #: promisor-remote.c +msgid "lazy fetching disabled; some objects may not be available" +msgstr "pengambilan malas dimatikan; beberapa objek mungkin tidak tersedia" + +#: promisor-remote.c msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "promisor-remote: tidak dapat menggarpu subproses pengambilan" @@ -23355,6 +23625,83 @@ msgstr "object-info: bilasan diharapkan setelah argumen" msgid "Removing duplicate objects" msgstr "Menghapus objek duplikat" +#: pseudo-merge.c +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "gagal memuat regex penggabungan semu untuk %s: '%s'" + +#: pseudo-merge.c +#, c-format +msgid "%s must be non-negative, using default" +msgstr "%s harus non-negatif, menggunakan yang asali" + +#: pseudo-merge.c +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "%s harus di antara 0 atau 1, menggunakan yang asali" + +#: pseudo-merge.c +#, c-format +msgid "%s must be positive, using default" +msgstr "%s harus positif, menggunakan yang asali" + +#: pseudo-merge.c +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "grup penggabungan semu '%s' kehilangan pola yang diperlukan" + +#: pseudo-merge.c +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "" +"grup penggabungan semu '%s' punya ambang batas tidak stabil sebelum yang " +"stabil" + +#: pseudo-merge.c +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "" +"regex penggabungan semu dari konfigurasi punya terlalu banyak grup tangkap " +"(max=%<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"pembacaan penggabungan semu yang diperluas di luar batas (%<PRIuMAX> >= " +"%<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"entri penggabungan semu yang diperluas terlalu pendek (%<PRIuMAX> >= " +"%<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "" +"tidak dapat menemukan penggabungan semu untuk %s pada offset %<PRIuMAX>" + +#: pseudo-merge.c +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "" +"pencarian penggabungan semu yang diperluas di luar batas (%<PRIu32> >= " +"%<PRIu32>)" + +#: pseudo-merge.c +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "pembacaan di luar batas: (%<PRIuMAX> >= %<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "tidak dapat membaca tabel penggabungan semu untuk komit %s" + #: range-diff.c msgid "could not start `log`" msgstr "tidak dapat memulai `log`" @@ -24081,12 +24428,21 @@ msgid "log for %s is empty" msgstr "log untuk %s kosong" #: refs.c +msgid "refusing to force and skip creation of reflog" +msgstr "menolak memaksa dan melewatkan pembuatan reflog" + +#: refs.c #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "menolak memperbarui referensi dengan nama jelek '%s'" #: refs.c #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "menolak memperbarui referensi semu '%s'" + +#: refs.c +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "update_ref gagal untuk referensi '%s': %s" @@ -24123,6 +24479,29 @@ msgstr "tidak dapat menghapus referensi %s: %s" msgid "could not delete references: %s" msgstr "tidak dapat menghapus referensi: %s" +#: refs.c +#, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "Selesai uji coba migrasi referensi, hasilnya bisa dilihat di '%s'\n" + +#: refs.c +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "tidak dapat menamai ulang direktori migrasi sementara '%s'" + +#: refs.c +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "referensi termigrasi dapat ditemukan pada '%s'" + +#: refs/files-backend.c refs/reftable-backend.c +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "" +"tidak dapat mengunci referensi '%s': diharapkan referensi simbolik dengan " +"target '%s': tetapi bukan referensi reguler" + #: refs/reftable-backend.c #, c-format msgid "refname is dangerous: %s" @@ -25545,6 +25924,55 @@ msgstr "" #: sequencer.c #, c-format +msgid "'%s' does not accept merge commits" +msgstr "'%s' tidak menerima komit penggabungan" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +#: sequencer.c +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"'pick' tidak mengambil komit penggabungan. Apabila Anda\n" +"ingin memainkan ulang penggabungan, gunakan 'merge -C'\n" +"pada komit." + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +#: sequencer.c +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"'reword' tidak mengambil komit penggabungan. Apabila Anda\n" +"ingin memainkan ulang penggabungan dan menulis ulang pesan\n" +"komit, gunakan 'merge -c' pada komit" + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +#: sequencer.c +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"'edit' tidak mengambil komit penggabungan. Apabila Anda\n" +"ingin memainkan ulang komit, gunakan 'merge -C' pada komit,\n" +"lalu 'break' untuk memberikan Anda kembali kendali agar\n" +"Anda dapat menjalankan 'git commit --amend && git rebase --continue'." + +#: sequencer.c +msgid "cannot squash merge commit into another commit" +msgstr "tidak dapat melumatkan komit penggabungan ke dalam komit lainnya" + +#: sequencer.c +#, c-format msgid "invalid command '%.*s'" msgstr "perintah tidak valid '%.*s'" @@ -25695,9 +26123,8 @@ msgid "cannot read HEAD" msgstr "tidak dapat membaca HEAD" #: sequencer.c -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "tidak dapat menyalin '%s' ke '%s'" +msgid "could not write commit message file" +msgstr "tidak dapat menulis berkas pesan komit" #: sequencer.c #, c-format @@ -26180,6 +26607,19 @@ msgid "failed to stat '%*s%s%s'" msgstr "gagal men-stat '%*s%s%s'" #: setup.c +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"perizinan meragukan terdeteksi di dalam repositori pada '%s'\n" +"%sUntuk menambahkan pengecualian untuk direktori ini, panggil:\n" +"\n" +"\tgit config --global --add safe.directory %s" + +#: setup.c msgid "Unable to read current working directory" msgstr "tidak dapat membaca direktori kerja saat ini" @@ -26205,19 +26645,6 @@ msgstr "" #: setup.c #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"perizinan meragukan terdeteksi di dalam repositori pada '%s'\n" -"%sUntuk menambahkan pengecualian untuk direktori ini, panggil:\n" -"\n" -"\tgit config --global --add safe.directory %s" - -#: setup.c -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" msgstr "" "tidak dapat menggunakan repositori bare '%s' (safe.bareRepository yaitu '%s')" @@ -26591,6 +27018,17 @@ msgstr "direktori submodul git '%s' di dalam direktori git '%.*s'" #: submodule.c #, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "" +"'%.*s' diharapkan di jalur submodul '%s' yang tidak menjadi tautan simbolik" + +#: submodule.c +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "jalur submodul '%s' diharapkan yang tidak menjadi tautan simbolik" + +#: submodule.c +#, c-format msgid "" "relocate_gitdir for submodule '%s' with more than one worktree not supported" msgstr "" @@ -26637,11 +27075,6 @@ msgid "no remote configured to get bundle URIs from" msgstr "tidak ada remote yang dikonfigurasi untuk mendapatkan URI bundel" #: t/helper/test-bundle-uri.c -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "remote '%s' tidak punya URL terkonfigurasi" - -#: t/helper/test-bundle-uri.c msgid "could not get the bundle-uri list" msgstr "tidak dapat mendapatkan daftar bundle-uri" @@ -28440,29 +28873,29 @@ msgstr "Gagal mengirim %s\n" #: git-send-email.perl #, perl-format -msgid "Dry-Sent %s\n" -msgstr "Terkirim-kering %s\n" +msgid "Dry-Sent %s" +msgstr "Uji-coba-Terkirim %s" #: git-send-email.perl #, perl-format -msgid "Sent %s\n" -msgstr "Terkirim %s\n" +msgid "Sent %s" +msgstr "Terkirim %s" #: git-send-email.perl -msgid "Dry-OK. Log says:\n" -msgstr "OK-kering. Log berkata:\n" +msgid "Dry-OK. Log says:" +msgstr "Uji-coba-OK. Log berkata:" #: git-send-email.perl -msgid "OK. Log says:\n" -msgstr "OK. Log berkata:\n" +msgid "OK. Log says:" +msgstr "OK. Log berkata:" #: git-send-email.perl msgid "Result: " msgstr "Hasil: " #: git-send-email.perl -msgid "Result: OK\n" -msgstr "Hasil: OK\n" +msgid "Result: OK" +msgstr "Hasil: OK" #: git-send-email.perl #, perl-format @@ -5,10 +5,10 @@ # msgid "" msgstr "" -"Project-Id-Version: git 2.45.0\n" +"Project-Id-Version: git 2.46.0\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-27 15:19+0100\n" -"PO-Revision-Date: 2024-04-27 15:20+0100\n" +"POT-Creation-Date: 2024-07-20 21:56+0100\n" +"PO-Revision-Date: 2024-07-21 14:53+0100\n" "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n" "Language-Team: Svenska <tp-sv@listor.tp-sv.se>\n" "Language: sv\n" @@ -556,6 +556,10 @@ msgstr "" "p - visa aktuellt stycke\n" "? - visa hjälp\n" +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "Förväntade endast en bokstav, fick â€%sâ€" + msgid "No previous hunk" msgstr "Inget föregÃ¥ende stycke" @@ -604,9 +608,19 @@ msgstr "Dela i %d stycken." msgid "Sorry, cannot edit this hunk" msgstr "Beklagar, kan inte redigera stycket" +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "Okänt kommando â€%s†(använd â€?†för hjälp)" + msgid "'git apply' failed" msgstr "â€git apply†misslyckades" +msgid "No changes." +msgstr "Inga ändringar." + +msgid "Only binary files changed." +msgstr "Endast binära filer ändrade." + #, c-format msgid "" "\n" @@ -1461,6 +1475,9 @@ msgstr "ignorerar allt för stor gitattributes-fil â€%sâ€" msgid "ignoring overly large gitattributes blob '%s'" msgstr "ignorerar allt för stor gitattributes-objekt â€%sâ€" +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "kan inte använda --attr-source eller GIT_ATTR_SOURCE utan arkiv" + msgid "bad --attr-source or GIT_ATTR_SOURCE" msgstr "felaktig --attr-source eller GIT_ATTR_SOURCE" @@ -1778,13 +1795,6 @@ msgstr "kan inte utföra chmod %cx â€%sâ€" msgid "Unstaged changes after refreshing the index:" msgstr "Oköade ändringar efter att ha uppdaterat indexet:" -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"inställningen add.interactive.useBuiltin har tagits bort!\n" -"Se dess post i â€git help config†för detaljer." - msgid "could not read the index" msgstr "kunde inte läsa indexet" @@ -2219,6 +2229,9 @@ msgstr "avbryt patchningen men behÃ¥ll HEAD där det är" msgid "show the patch being applied" msgstr "visa patchen som tillämpas" +msgid "try to apply current patch again" +msgstr "försök applicera aktuell patch pÃ¥ nytt" + msgid "record the empty patch as an empty commit" msgstr "lagra den tomma patchen som en tom incheckning" @@ -2274,9 +2287,6 @@ msgstr "git apply [<flaggor>] [<patch>...]" msgid "could not redirect output" msgstr "kunde inte omdirigera utdata" -msgid "git archive: Remote with no URL" -msgstr "git archive: Fjärr utan URL" - msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "git archive: förväntade ACK/NAK, fick flush-paket" @@ -3169,6 +3179,9 @@ msgstr "Behöver ett arkiv för att skapa en bunt." msgid "do not show bundle details" msgstr "visa inte buntdetaljer" +msgid "need a repository to verify a bundle" +msgstr "behöver ett arkiv för att bekräfta en bunt." + #, c-format msgid "%s is okay\n" msgstr "%s är okej\n" @@ -4174,6 +4187,14 @@ msgid "failed to unlink '%s'" msgstr "misslyckades ta bort länken â€%sâ€" #, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "hÃ¥rd länk kan inte kontrolleras vid â€%sâ€" + +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "hÃ¥rd länk skiljer sig frÃ¥n källan vid â€%sâ€" + +#, c-format msgid "failed to create link '%s'" msgstr "misslyckades skapa länken â€%sâ€" @@ -4996,15 +5017,50 @@ msgstr "" "att kvoten inte har överskridits, och kör sedan\n" "â€git restore --staged :/†för att Ã¥terställa." -msgid "git config [<options>]" -msgstr "git config [<flaggor>]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "git config list [<filflagga>] [<visningsflagga>] [--includes]" -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "okänt argument för --type, %s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [<filflagga>] [<visningsflagga>] [--includes] [--all] [--" +"regexp=<reguttr>] [--value=<värde>] [--fixed-value] [--default=<förval>] " +"<namn>" -msgid "only one type at a time" -msgstr "endast en typ Ã¥t gÃ¥ngen" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [<filflagga>] [--type=<typ>] [--all] [--value=<värde>] [--" +"fixed-value] <namn> <värde>" + +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [<filflagga>] [--all] [--value=<värde>] [--fixed-value] " +"<namn> <värde>" + +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "git config rename-section [<filflagga>] <gammalt-namn> <nytt-namn>" + +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [<filflagga>] <namn>" + +msgid "git config edit [<file-option>]" +msgstr "git config edit [<filflagga>]" + +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "git config [<filflagga>] --get-colorbool <namn> [<stdout-är-tty>]" + +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [<filflagga>] [--type=<typ>] [--comment=<meddelande>] [--all] " +"[--value=<värde>] [--fixed-value] <namn> <värde>" msgid "Config file location" msgstr "Konfigurationsfilens plats" @@ -5030,54 +5086,6 @@ msgstr "blob-id" msgid "read config from given blob object" msgstr "läs konfiguration frÃ¥n givet blob-objekt" -msgid "Action" -msgstr "Ã…tgärd" - -msgid "get value: name [value-pattern]" -msgstr "hämta värde: namn [värde-mönster]" - -msgid "get all values: key [value-pattern]" -msgstr "hämta alla värden: nyckel [värde-mönster]" - -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "hämta värden för reguttr: namn-reguttr [värde-mönster]" - -msgid "get value specific for the URL: section[.var] URL" -msgstr "hämta värde specifikt URL:en: sektion[.var] URL" - -msgid "replace all matching variables: name value [value-pattern]" -msgstr "ersätt alla motsvarande variabler: namn värde [värde-mönster]" - -msgid "add a new variable: name value" -msgstr "lägg till en ny variabel: namn värde" - -msgid "remove a variable: name [value-pattern]" -msgstr "ta bort en variabel: namn [värde-mönster]" - -msgid "remove all matches: name [value-pattern]" -msgstr "ta bort alla träffar: namn [värde-mönster]" - -msgid "rename section: old-name new-name" -msgstr "byt namn pÃ¥ sektion: gammalt-namn nytt-namn" - -msgid "remove a section: name" -msgstr "ta bort en sektion: namn" - -msgid "list all" -msgstr "visa alla" - -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "använd stränglikhet vid när värden jämförs med â€värde-mönsterâ€" - -msgid "open an editor" -msgstr "öppna textredigeringsprogram" - -msgid "find the color configured: slot [default]" -msgstr "hitta den inställda färgen: slot [default]" - -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "hitta färginställningen: slot [stdout-is-tty]" - msgid "Type" msgstr "Typ" @@ -5105,8 +5113,8 @@ msgstr "värdet är en sökväg (fil- eller katalognamn)" msgid "value is an expiry date" msgstr "värdet är ett utgÃ¥ngsdatum" -msgid "Other" -msgstr "Andra" +msgid "Display options" +msgstr "Visningsflaggor" msgid "terminate values with NUL byte" msgstr "terminera värden med NUL-byte" @@ -5114,9 +5122,6 @@ msgstr "terminera värden med NUL-byte" msgid "show variable names only" msgstr "visa endast variabelnamn" -msgid "respect include directives on lookup" -msgstr "respektera inkluderingsdirektiv vid uppslag" - msgid "show origin of config (file, standard input, blob, command line)" msgstr "visa konfigurationskälla (fil, standard in, blob, kommandorad)" @@ -5125,14 +5130,15 @@ msgstr "" "visa omfÃ¥ng för konfiguration (arbetskatalog, lokalt, globalt, system, " "kommando)" -msgid "value" -msgstr "värde" +msgid "show config keys in addition to their values" +msgstr "visa konfigurationsnycklar tillsammans med deras värden" -msgid "with --get, use default value when missing entry" -msgstr "med --get, använd standardvärde vid saknad post" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "okänt argument för --type, %s" -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "människoläsbar kommentarssträng (# läggs in först efter behov)" +msgid "only one type at a time" +msgstr "endast en typ Ã¥t gÃ¥ngen" #, c-format msgid "wrong number of arguments, should be %d" @@ -5208,46 +5214,72 @@ msgstr "" "konfigurationsutöknignen worktreeConfig har aktiverats. Läsa stycket\n" "â€KONFIGURATIONSFIL†i â€git help worktree†för detaljer" -msgid "--get-color and variable type are incoherent" -msgstr "--get-color och variabeltyp stämmer inte överens" +msgid "Other" +msgstr "Andra" -msgid "only one action at a time" -msgstr "endast en Ã¥tgärd Ã¥t gÃ¥ngen" +msgid "respect include directives on lookup" +msgstr "respektera inkluderingsdirektiv vid uppslag" -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "--name-only gäller bara för --list eller --get-regexp" +#, c-format +msgid "unable to read config file '%s'" +msgstr "kan inte läsa konfigurationsfilen â€%sâ€" -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" -msgstr "" -"--show-origin gäller bara för --get, --get-all, --get-regexp och --list" +msgid "error processing config file(s)" +msgstr "fel vid hantering av konfigurationsfil(er)" -msgid "--default is only applicable to --get" -msgstr "--default gäller bara för --get" +msgid "Filter options" +msgstr "Filterflaggor" -msgid "--comment is only applicable to add/set/replace operations" -msgstr "--comment gäller bara för â€getâ€/â€setâ€/â€replaceâ€-operationerna" +msgid "return all values for multi-valued config options" +msgstr "returnera alla värden för konfigurationsflaggor med flera värden" + +msgid "interpret the name as a regular expression" +msgstr "tolka namnet som reguljärt uttryck" + +msgid "show config with values matching the pattern" +msgstr "via konfiguration med värden som motsvarar mönster" + +msgid "use string equality when comparing values to value pattern" +msgstr "använd stränglikhet vid när värden jämförs med värde-mönster" + +msgid "URL" +msgstr "URL" + +msgid "show config matching the given URL" +msgstr "visa konfiguration som motsvarar given URL" + +msgid "value" +msgstr "värde" + +msgid "use default value when missing entry" +msgstr "använd standardvärde vid saknad post" msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value gäller endast med â€värde-mönsterâ€" -#, c-format -msgid "unable to read config file '%s'" -msgstr "kan inte läsa konfigurationsfilen â€%sâ€" +msgid "--default= cannot be used with --all or --url=" +msgstr "--default= kan inte användas med --all eller --url=" -msgid "error processing config file(s)" -msgstr "fel vid hantering av konfigurationsfil(er)" +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "--url= kan inte användas med --all, --regexp eller --value" -msgid "editing stdin is not supported" -msgstr "redigering av standard in stöds ej" +msgid "Filter" +msgstr "Filter" -msgid "editing blobs is not supported" -msgstr "redigering av blobbar stöds ej" +msgid "replace multi-valued config option with new value" +msgstr "ersätt konfigurationsflagga med flera värden med nytt värde" -#, c-format -msgid "cannot create configuration file %s" -msgstr "kan inte skapa konfigurationsfilen â€%sâ€" +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "människoläsbar kommentarssträng (# läggs in först efter behov)" + +msgid "add a new line without altering any existing values" +msgstr "lägg till ny rad utan att ändra befintliga värden" + +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "--fixed-value gäller endast med --value=<mönster>" + +msgid "--append cannot be used with --value=<pattern>" +msgstr "--append kan inte användas med --value=<mönster>" #, c-format msgid "" @@ -5261,6 +5293,85 @@ msgstr "" msgid "no such section: %s" msgstr "ingen sÃ¥dan sektion: %s" +msgid "editing stdin is not supported" +msgstr "redigering av standard in stöds ej" + +msgid "editing blobs is not supported" +msgstr "redigering av blobbar stöds ej" + +#, c-format +msgid "cannot create configuration file %s" +msgstr "kan inte skapa konfigurationsfilen â€%sâ€" + +msgid "Action" +msgstr "Ã…tgärd" + +msgid "get value: name [<value-pattern>]" +msgstr "hämta värde: namn <värde-mönster>" + +msgid "get all values: key [<value-pattern>]" +msgstr "hämta alla värden: nyckel <värde-mönster>" + +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "hämta värden för reguttr: namn-reguttr <värde-mönster>" + +msgid "get value specific for the URL: section[.var] URL" +msgstr "hämta värde specifikt URL:en: sektion[.var] URL" + +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "ersätt alla motsvarande variabler: namn värde <värde-mönster>" + +msgid "add a new variable: name value" +msgstr "lägg till en ny variabel: namn värde" + +msgid "remove a variable: name [<value-pattern>]" +msgstr "ta bort en variabel: namn <värde-mönster>" + +msgid "remove all matches: name [<value-pattern>]" +msgstr "ta bort alla träffar: namn <värde-mönster>" + +msgid "rename section: old-name new-name" +msgstr "byt namn pÃ¥ sektion: gammalt-namn nytt-namn" + +msgid "remove a section: name" +msgstr "ta bort en sektion: namn" + +msgid "list all" +msgstr "visa alla" + +msgid "open an editor" +msgstr "öppna textredigeringsprogram" + +msgid "find the color configured: slot [<default>]" +msgstr "hitta den inställda färgen: lucka <förval>" + +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "hitta färginställningen: lucka <stdout-är-tty>" + +msgid "with --get, use default value when missing entry" +msgstr "med --get, använd standardvärde vid saknad post" + +msgid "--get-color and variable type are incoherent" +msgstr "--get-color och variabeltyp stämmer inte överens" + +msgid "no action specified" +msgstr "ingen handling angavs" + +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "--name-only gäller bara för --list eller --get-regexp" + +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "" +"--show-origin gäller bara för --get, --get-all, --get-regexp och --list" + +msgid "--default is only applicable to --get" +msgstr "--default gäller bara för --get" + +msgid "--comment is only applicable to add/set/replace operations" +msgstr "--comment gäller bara för â€getâ€/â€setâ€/â€replaceâ€-operationerna" + msgid "print sizes in human readable format" msgstr "skriv storlekar i människoläsbart format" @@ -6079,6 +6190,9 @@ msgstr "konfig" msgid "config key storing a list of repository paths" msgstr "konfigurationsnyckel som innehÃ¥ller en lista över arkivsökvägar" +msgid "keep going even if command fails in a repository" +msgstr "fortsätt även om kommandot misslyckas i ett arkiv" + msgid "missing --config=<config>" msgstr "saknar --config=<konfig>" @@ -7531,8 +7645,11 @@ msgstr "markera serien som N:te försök" msgid "max length of output filename" msgstr "maximal längd för utdatafilnamn" -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "använd [RFC PATCH] istället för [PATCH]" +msgid "rfc" +msgstr "rfc" + +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "lägg till <rfc> (förval â€RFCâ€) före â€PATCHâ€" msgid "cover-from-description-mode" msgstr "cover-from-description-läge" @@ -7793,11 +7910,11 @@ msgstr "" "deduplicate, --eol" msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<nyckel>]\n" " [--symref] [<arkiv> [<mönster>...]]" @@ -7813,8 +7930,11 @@ msgstr "sökväg till git-upload-pack pÃ¥ fjärren" msgid "limit to tags" msgstr "begränsa till taggar" -msgid "limit to heads" -msgstr "begränsa till huvuden" +msgid "limit to branches" +msgstr "begränsa till grenar" + +msgid "deprecated synonym for --branches" +msgstr "förÃ¥ldrad synonym till --branches" msgid "do not show peeled tags" msgstr "visa inte avskalade taggar" @@ -10423,6 +10543,22 @@ msgstr "ingen referenslogg att ta bort angavs" msgid "invalid ref format: %s" msgstr "felaktigt referensformat: %s" +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=<format> [--dry-run]" + +msgid "specify the reference format to convert to" +msgstr "ange referensformatet att konvertera till" + +msgid "perform a non-destructive dry-run" +msgstr "utför ett icke-destruktiv testkörning" + +msgid "missing --ref-format=<format>" +msgstr "saknad --ref-format=<format>" + +#, c-format +msgid "repository already uses '%s' format" +msgstr "arkivet använder redan â€%sâ€-format" + msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" "mirror=<fetch|push>] <name> <url>" @@ -10703,9 +10839,6 @@ msgstr "* fjärr %s" msgid " Fetch URL: %s" msgstr " Hämt-URL: %s" -msgid "(no URL)" -msgstr "(ingen URL)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -10714,6 +10847,9 @@ msgstr "(ingen URL)" msgid " Push URL: %s" msgstr " Sänd-URL: %s" +msgid "(no URL)" +msgstr "(ingen URL)" + #, c-format msgid " HEAD branch: %s" msgstr " HEAD-gren: %s" @@ -10819,10 +10955,6 @@ msgstr "frÃ¥ga sänd-URL:er istället för hämta-URL:er" msgid "return all URLs" msgstr "returnera alla URL:er" -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "ingen URL:er angivna för fjärren â€%sâ€" - msgid "manipulate push URLs" msgstr "manipulera URL:ar för sändning" @@ -11818,12 +11950,12 @@ msgstr "okänd hashningsalgoritm" msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<mönster>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<mönster>...]" msgid "" "git show-ref --verify [-q | --quiet] [-d | --dereference]\n" @@ -11846,11 +11978,11 @@ msgstr "referensen existerar inte" msgid "failed to look up reference" msgstr "misslyckades slÃ¥ upp referensen" -msgid "only show tags (can be combined with heads)" -msgstr "visa endast taggar (kan kombineras med huvuden)" +msgid "only show tags (can be combined with branches)" +msgstr "visa endast taggar (kan kombineras med grenar)" -msgid "only show heads (can be combined with tags)" -msgstr "visa endast huvuden (kan kombineras med taggar)" +msgid "only show branches (can be combined with tags)" +msgstr "visa endast grenar (kan kombineras med taggar)" msgid "check for reference existence without resolving" msgstr "kontrollerar att referensen existerar utan att slÃ¥ upp dem" @@ -12471,14 +12603,14 @@ msgid "refusing to create/use '%s' in another submodule's git dir" msgstr "vägrar skapa/använda â€%s†i en annan undermoduls gitkatalog" #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "misslyckades klona â€%s†till undermodulsökvägen â€%sâ€" - -#, c-format msgid "directory not empty: '%s'" msgstr "katalogen inte tom: â€%sâ€" #, c-format +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "misslyckades klona â€%s†till undermodulsökvägen â€%sâ€" + +#, c-format msgid "could not get submodule directory for '%s'" msgstr "kunde inte fÃ¥ tag i undermodulkatalog för â€%sâ€" @@ -12835,9 +12967,11 @@ msgstr "skäl till uppdateringen" msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" "git tag [-a | -s | -u <nyckel-id>] [-f] [-m <medd> | -F <fil>] [-e]\n" +" [(--trailer <symbol>[(=|:)<värde>])...]\n" " <taggnamn> [<incheckning> | <objekt>]" msgid "git tag -d <tagname>..." @@ -13682,9 +13816,6 @@ msgstr "okänt huvud: %s%s (%d)" msgid "Repository lacks these prerequisite commits:" msgstr "Arkivet saknar dessa nödvändiga incheckningar:" -msgid "need a repository to verify a bundle" -msgstr "behöver ett arkiv för att bekräfta en bunt." - msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -14082,6 +14213,9 @@ msgstr "Ta emot det som sänds till arkivet" msgid "Manage reflog information" msgstr "Hantera referenslogg-information" +msgid "Low-level access to refs" +msgstr "LÃ¥gnivååtkomst till referenser" + msgid "Manage set of tracked repositories" msgstr "Hantera uppsättningen spÃ¥rade arkiv" @@ -14387,6 +14521,14 @@ msgid "commit-graph required commit data chunk missing or corrupted" msgstr "" "incheckningsgrafens nödvändiga incheckningsdatastycke saknas eller är trasigt" +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "" +"inaktivera Bloom-filter för incheckningsgraflager â€%s†pÃ¥ grund av " +"inkompatibla inställningar" + msgid "commit-graph has no base graphs chunk" msgstr "incheckningsgrafen har inga bas-graf-stycken" @@ -14510,6 +14652,14 @@ msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled" msgstr "" "försöker skriva en incheckningsgraf, men â€core.commitGraph†är inaktiverad" +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph." +"changedPathsVersion' (%d) is not supported" +msgstr "" +"försöker skriva en incheckningsgraf, men â€commitGraph." +"changedPathsVersion†(%d) stöds inte" + msgid "too many commits to write graph" msgstr "för mÃ¥nga incheckningar för att skriva graf" @@ -16348,18 +16498,23 @@ msgstr "" msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v | --version] [-h |--help] [-C <sökväg>] [-c <namn>=<värde>]\n" " [--exec-path[=<sökväg>]] [--html-path] [--man-path] [--info-" "path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<sökväg>] [--work-tree=<sökväg>] [--namespace=<namn>]\n" -" [--config-env=<namn>=<miljövar>] <kommando> [<flaggor>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-" +"dir=<sökväg>]\n" +" [--work-tree=<sökväg>] [--namespace=<namn>] [--config-" +"env=<namn>=<miljövar>]\n" +" <kommando> [<flaggor>]" msgid "" "'git help -a' and 'git help -g' list available subcommands and some\n" @@ -16695,14 +16850,14 @@ msgstr "" "Kroken â€%s†ignorerades eftersom den inte är markerad som körbar.\n" "Du kan inaktivera varningen med â€git config advice.ignoredHook falseâ€." +msgid "not a git repository" +msgstr "inte ett git-arkiv" + #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "" "argumentet till --packfile mÃ¥ste vara ett giltigt hashvärde (fick '%s')" -msgid "not a git repository" -msgstr "inte ett git-arkiv" - #, c-format msgid "negative value for http.postBuffer; defaulting to %d" msgstr "http.postBuffer har negativt värde; använder förvalet %d" @@ -16713,6 +16868,9 @@ msgstr "Delegerad styrning stöds inte av cURL < 7.22.0" msgid "Public key pinning not supported with cURL < 7.39.0" msgstr "FastnÃ¥lning av öppen nyckel stöds inte av cURL < 7.39.0" +msgid "Unknown value for http.proactiveauth" +msgstr "Okänt värde för http.proactiveauth" + msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "CURLSSLOPT_NO_REVOKE stöds inte av cURL < 7.44.0" @@ -16728,6 +16886,12 @@ msgstr "Kan inte sätta SSL-bakända till â€%sâ€: cURL byggdes utan SSL-bakän msgid "Could not set SSL backend to '%s': already set" msgstr "Kunde inte sätta SSL-bakända till â€%sâ€: redan valt" +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "vägrar läsa kakor frÃ¥n filen â€-†angiven i http.cookiefile" + +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "ignorerar http.savecookies för tom http.cookiefile" + #, c-format msgid "" "unable to update url base from redirection:\n" @@ -16902,8 +17066,8 @@ msgid "Failed to merge submodule %s (commits not present)" msgstr "Misslyckades slÃ¥ ihop undermodulen %s (incheckningar saknas)" #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" -msgstr "Misslyckades slÃ¥ ihop undermodulen %s (arkivet är trasigt)" +msgid "error: failed to merge submodule %s (repository corrupt)" +msgstr "fel: misslyckades slÃ¥ ihop undermodulen %s (arkivet är trasigt)" #, c-format msgid "Failed to merge submodule %s (commits don't follow merge-base)" @@ -16933,12 +17097,13 @@ msgstr "" "finns:\n" "%s" -msgid "failed to execute internal merge" -msgstr "misslyckades exekvera intern sammanslagning" +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "fel: misslyckades exekvera intern sammanslagning för %s" #, c-format -msgid "unable to add %s to database" -msgstr "kan inte lägga till %s till databasen" +msgid "error: unable to add %s to database" +msgstr "fel: kan inte lägga till %s till databasen" #, c-format msgid "Auto-merging %s" @@ -17031,12 +17196,12 @@ msgstr "" "KONFLIKT (namnbyte/radera): %s namnbytt till %s i %s, men borttagen i %s." #, c-format -msgid "cannot read object %s" -msgstr "kan inte läsa objektet %s" +msgid "error: cannot read object %s" +msgstr "fel: kan inte läsa objektet %s" #, c-format -msgid "object %s is not a blob" -msgstr "objektet %s är inte en blob" +msgid "error: object %s is not a blob" +msgstr "fel: objektet %s är inte en blob" #, c-format msgid "" @@ -17176,6 +17341,10 @@ msgid "do not know what to do with %06o %s '%s'" msgstr "vet inte hur %06o %s â€%s†ska hanteras" #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "Misslyckades slÃ¥ ihop undermodulen %s (arkivet är trasigt)" + +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "Snabbspolar undermodulen %s till följande incheckning:" @@ -17217,6 +17386,13 @@ msgid "Failed to merge submodule %s (multiple merges found)" msgstr "" "Misslyckades slÃ¥ ihop undermodulen %s (flera sammanslagningar hittades)" +msgid "failed to execute internal merge" +msgstr "misslyckades exekvera intern sammanslagning" + +#, c-format +msgid "unable to add %s to database" +msgstr "kan inte lägga till %s till databasen" + #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "Fel: Vägrar förlora ospÃ¥rad fil vid %s; skriver till %s istället." @@ -17312,6 +17488,14 @@ msgstr "" "KONFLIKT (namnbyte/namnbyte): Namnbytt katalog %s→%s i %s. Namnbytt katalog " "%s→%s i %s" +#, c-format +msgid "cannot read object %s" +msgstr "kan inte läsa objektet %s" + +#, c-format +msgid "object %s is not a blob" +msgstr "objektet %s är inte en blob" + msgid "modify" msgstr "ändra" @@ -17395,9 +17579,6 @@ msgstr "kunde inte tolka rad: %s" msgid "malformed line: %s" msgstr "felaktig rad: %s" -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "ignorerar befintlig multi-pack-index; felaktig kontrollsumma" - msgid "could not load pack" msgstr "kunde inte läsa paket{" @@ -17405,6 +17586,9 @@ msgstr "kunde inte läsa paket{" msgid "could not open index for %s" msgstr "kunde inte öppna indexet för %s" +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "ignorerar befintlig multi-pack-index; felaktig kontrollsumma" + msgid "Adding packfiles to multi-pack-index" msgstr "Lägger till paketfiler till multi-pack-index" @@ -18011,6 +18195,17 @@ msgstr "kan inte tolka objektet: %s" msgid "hash mismatch %s" msgstr "hashvärde stämmer inte överens %s" +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "duplicerad post när bitkarteindex skulle skrivas: %s" + +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "försökta lagra icke-vald incheckning: â€%sâ€" + +msgid "too many pseudo-merges" +msgstr "för mÃ¥nga pseudo-sammanslagningar" + msgid "trying to write commit not in index" msgstr "försöker skriva incheckning som inte finns i indexet" @@ -18033,6 +18228,20 @@ msgstr "trasigt bitkarteindex (för kort för att fÃ¥ plats för hash-cache)" msgid "corrupted bitmap index file (too short to fit lookup table)" msgstr "trasigt bitkarteindex (för kort för att fÃ¥ plats för uppslagstabell)" +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "" +"trasig bitkarteindexfil (för kort för att fÃ¥ plats för pseudo-" +"sammanslagningsatbellhuvudet)" + +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "" +"trasig bitkarteindexfil (för kort för att fÃ¥ plats för pseudo-" +"sammanslagningstabell)" + +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "trasig bitkarteindexfil, pseudosammanslagningstabellen är för kort" + #, c-format msgid "duplicate entry in bitmap index: '%s'" msgstr "duplicerad post i bitkarteindex: â€%sâ€" @@ -18123,6 +18332,10 @@ msgid "mismatch in bitmap results" msgstr "bitkarteresultat stämmer inte överens" #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "pseudosammanslaningsindex utenför intervallet (%<PRIu32> ≥ %<PRIuMAX>)" + +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "kunde inte hitta â€%s†i paketet â€%s†pÃ¥ offset %<PRIuMAX>" @@ -18483,6 +18696,10 @@ msgstr "kan inte skapa trÃ¥dad lstat: %s" msgid "unable to parse --pretty format" msgstr "kan inte tolka format för --pretty" +msgid "lazy fetching disabled; some objects may not be available" +msgstr "" +"fördröjd hämtning inaktiverad; nÃ¥gra objekt kanske inte är tillgängliga" + msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "promisor-remote: kan inte grena (fork) av underprocessen för fetch" @@ -18507,6 +18724,71 @@ msgstr "object-info: förväntade â€flush†efter argument" msgid "Removing duplicate objects" msgstr "Tar bort duplicerade objekt" +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "" +"misslyckades läsa reguljärt uttryck för pseudosammanslagning för â€%sâ€: %s" + +#, c-format +msgid "%s must be non-negative, using default" +msgstr "%s mÃ¥ste vara icke-negativt, använder förval" + +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "%s mÃ¥ste vara mellan 0 och 1, använder förval" + +#, c-format +msgid "%s must be positive, using default" +msgstr "%s mÃ¥ste vara positivt, använder förval" + +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "pseudosammanslagningsgruppen â€%s†saknar nödvändigt mönster" + +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "" +"pseudosammanslagningsgruppen â€%s†har instabila tröskelvärden innan de " +"stabila" + +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "" +"reguljärt uttryck för pseudosammanslagning har för mÃ¥nga fÃ¥ngstgrupper " +"(max=%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"läsning utanför intervallet för utökad pseudosammanslagning (%<PRIuMAX> ≥ " +"%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"posten för utökad pseudosammanslagning är för kort (%<PRIuMAX> ≥ %<PRIuMAX>)" + +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "" +"kunde inte hitta pseudosammanslagning för incheckningen %s pÃ¥ offset " +"%<PRIuMAX>" + +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "" +"uppslagning utanför intervallet för utökad pseudosammanslagning (%<PRIu32> ≥ " +"%<PRIu32>)" + +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "läsning utanför intervallet: (%<PRIuMAX> ≥ %<PRIuMAX>)" + +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "kunde inte läsa utökad pseudosammanslagningstabell för incheckning %s" + msgid "could not start `log`" msgstr "kunde inte starta â€logâ€" @@ -19108,11 +19390,18 @@ msgstr "loggen för referensen %s slutade oväntat pÃ¥ %s" msgid "log for %s is empty" msgstr "loggen för %s är tom" +msgid "refusing to force and skip creation of reflog" +msgstr "vägrar att tvinga och hoppa över skapande av reflogg" + #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "vägrar uppdatera referens med trasigt namn â€%sâ€" #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "vägrar uppdatera pseudoreferensen â€%sâ€" + +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "update_ref misslyckades för referensen â€%sâ€: %s" @@ -19143,6 +19432,25 @@ msgid "could not delete references: %s" msgstr "kunde inte ta bort referenser: %s" #, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "Avslutade testkörning av referensmigrering, resultatet hittas i â€%sâ€\n" + +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "kunde ta bort temporär migreringskatalog â€%sâ€" + +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "migrerade referenser hittas vid â€%sâ€" + +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "" +"kan inte läsa referensen â€%sâ€: förväntade symbolisk referens med mÃ¥let â€%sâ€: " +"men är en vanlig referens" + +#, c-format msgid "refname is dangerous: %s" msgstr "refnamnet är farligt: %s" @@ -20289,6 +20597,53 @@ msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s" msgstr "update-ref kräver ett fullständigt referensnamn, t.ex refs/heads/%s" #, c-format +msgid "'%s' does not accept merge commits" +msgstr "â€%s†godtar inte sammanslagningsincheckningar" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"â€pick†tar inte en sammanslagningsincheckning. Om du\n" +"ville spela upp sammanslagningen pÃ¥ nytt använder du\n" +"â€merge -C†pÃ¥ incheckningen." + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"â€reword†tar inte en sammanslagningsincheckning. Om du\n" +"ville spela upp sammanslagningen pÃ¥ nytt och ändra texten\n" +"i incheckningsmeddelandet använder du â€merge -C†pÃ¥\n" +"incheckningen" + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"â€edit†tar inte en sammanslagningsincheckning. Om du\n" +"ville spela upp sammanslagningen pÃ¥ nytt använder du\n" +"â€merge -C†pÃ¥ incheckningen och sedan â€break†för att\n" +"lämna kontrollen tillbaka till dig sÃ¥ att du kan\n" +"använda â€git commit --amend && git rebase --continueâ€." + +msgid "cannot squash merge commit into another commit" +msgstr "" +"kan inte slÃ¥ ihop en sammanslagningsincheckning med en annan incheckning" + +#, c-format msgid "invalid command '%.*s'" msgstr "ogiltigt kommando â€%.*sâ€" @@ -20406,9 +20761,8 @@ msgstr "" msgid "cannot read HEAD" msgstr "kan inte läsa HEAD" -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "kan inte kopiera in â€%s†till â€%sâ€" +msgid "could not write commit message file" +msgstr "kunde inte skriva fil för incheckningsmeddelande" #, c-format msgid "" @@ -20807,6 +21161,18 @@ msgstr "kan inte gÃ¥ tillbaka till arbetskatalogen (cwd)" msgid "failed to stat '%*s%s%s'" msgstr "misslyckades ta status pÃ¥ â€%*ss%s%sâ€" +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"upptäckte tveksamt ägarskap i arkivet i â€%sâ€\n" +"%sFör att lägga till ett undantag för denna katalog, kör:\n" +"\n" +"\tgit config --global --add safe.directory %s" + msgid "Unable to read current working directory" msgstr "Kan inte läsa aktuell arbetskatalog" @@ -20828,18 +21194,6 @@ msgstr "" "Stoppar vid filsystemsgräns (GIT_DISCOVERY_ACROSS_FILESYSTEM är inte satt)." #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"upptäckte tveksamt ägarskap i arkivet i â€%sâ€\n" -"%sFör att lägga till ett undantag för denna katalog, kör:\n" -"\n" -"\tgit config --global --add safe.directory %s" - -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" msgstr "kan inte använda naket arkiv â€%s†(safe.bareRepository är â€%sâ€)" @@ -21141,6 +21495,16 @@ msgid "submodule git dir '%s' is inside git dir '%.*s'" msgstr "undermodul-gitkatalogen â€%s†är inuti gitkatalogen â€%.*sâ€" #, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "" +"förväntade att â€%.*s†i undermodulsökvägen â€%s†inte ska vara en symbolisk " +"länk" + +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "förväntade att undermodulsökvägen â€%s†inte ska vara en symbolisk länk" + +#, c-format msgid "" "relocate_gitdir for submodule '%s' with more than one worktree not supported" msgstr "" @@ -21179,10 +21543,6 @@ msgstr "misslyckades ta status (lstat) pÃ¥ â€%sâ€" msgid "no remote configured to get bundle URIs from" msgstr "ingen fjärr att hämta bunt-URI:er frÃ¥n inställd" -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "fjärren â€%s†har ingen URL konfigurerad" - msgid "could not get the bundle-uri list" msgstr "kunde inte hämta bundle-uri-listan" @@ -22641,24 +23001,24 @@ msgid "Failed to send %s\n" msgstr "Misslyckades sända %s\n" #, perl-format -msgid "Dry-Sent %s\n" -msgstr "Test-Sände %s\n" +msgid "Dry-Sent %s" +msgstr "Test-Sände %s" #, perl-format -msgid "Sent %s\n" -msgstr "Sände %s\n" +msgid "Sent %s" +msgstr "Sände %s" -msgid "Dry-OK. Log says:\n" -msgstr "Test-OK. Loggen säger:\n" +msgid "Dry-OK. Log says:" +msgstr "Test-OK. Loggen säger:" -msgid "OK. Log says:\n" -msgstr "OK. Loggen säger:\n" +msgid "OK. Log says:" +msgstr "OK. Loggen säger:" msgid "Result: " msgstr "Resultat: " -msgid "Result: OK\n" -msgstr "Resultat: OK\n" +msgid "Result: OK" +msgstr "Resultat: OK" #, perl-format msgid "can't open file %s" @@ -96,8 +96,8 @@ msgid "" msgstr "" "Project-Id-Version: Git Turkish Localization Project\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-29 01:09+0300\n" -"PO-Revision-Date: 2024-04-29 01:10+0300\n" +"POT-Creation-Date: 2024-07-19 13:59+0300\n" +"PO-Revision-Date: 2024-07-19 14:00+0300\n" "Last-Translator: Emir SARI <emir_sari@icloud.com>\n" "Language-Team: Turkish (https://github.com/bitigchi/git-po/)\n" "Language: tr\n" @@ -646,6 +646,10 @@ msgstr "" "p - geçerli parçalı yazdır\n" "? - yardımı yazdır\n" +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "Yalnızca bir harf bekleniyordu, '%s' alındı" + msgid "No previous hunk" msgstr "Öncesinde parça yok" @@ -694,9 +698,19 @@ msgstr "%d parçaya bölündü." msgid "Sorry, cannot edit this hunk" msgstr "Üzgünüm, bu parça düzenlenemiyor" +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "Bilinmeyen komut '%s' (yardım için '?')" + msgid "'git apply' failed" msgstr "'git apply' baÅŸarısız oldu" +msgid "No changes." +msgstr "DeÄŸiÅŸiklik yok." + +msgid "Only binary files changed." +msgstr "Yalnızca ikili dosyalar deÄŸiÅŸtirildi." + #, c-format msgid "" "\n" @@ -1545,6 +1559,9 @@ msgstr "pek büyük gitattributes dosyası '%s' dosyası yok sayılıyor" msgid "ignoring overly large gitattributes blob '%s'" msgstr "pek büyük gitattributes ikili nesnesi '%s' yok sayılıyor" +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "depo olmadan --attr-source veya GIT_ATTR_SOURCE kullanılamaz" + msgid "bad --attr-source or GIT_ATTR_SOURCE" msgstr "hatalı --attr-source veya GIT_ATTR_SOURCE" @@ -1862,13 +1879,6 @@ msgstr "%cx '%s' chmod yapılamıyor" msgid "Unstaged changes after refreshing the index:" msgstr "İndeksi yeniledikten sonra hazırlanmamış deÄŸiÅŸiklikler:" -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"add.interactive.useBuiltin ayarı kaldırıldı!\n" -"Ayrıntılar için onun 'git help config' içindeki girdisine bakın." - msgid "could not read the index" msgstr "indeks okunamadı" @@ -1979,7 +1989,7 @@ msgid "adding embedded git repository: %s" msgstr "gömülü git deposu ekleniyor: %s" msgid "Use -f if you really want to add them." -msgstr "Onları gerçekten eklemek istiyorsanız -f kullanın." +msgstr "Onları eklemeyi gerçekten istiyorsanız -f kullanın." msgid "adding files failed" msgstr "dosya ekleme baÅŸarısız" @@ -2310,6 +2320,9 @@ msgstr "yamalama iÅŸlemini iptal et; ancak HEAD'i olduÄŸu yerde bırak" msgid "show the patch being applied" msgstr "uygulanmakta olan yamayı göster" +msgid "try to apply current patch again" +msgstr "yeniden geçerli yamayı uygulamaya çalış" + msgid "record the empty patch as an empty commit" msgstr "boÅŸ yamayı bir boÅŸ iÅŸleme olarak kayıt yaz" @@ -2366,9 +2379,6 @@ msgstr "git apply [<seçenekler>] [<yama>...]" msgid "could not redirect output" msgstr "çıktı yeniden yönlendirilemedi" -msgid "git archive: Remote with no URL" -msgstr "git archive: URL'si olmayan uzak konum" - msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "git archive: ACK/NAK bekleniyordu, floÅŸ paketi alındı" @@ -3261,6 +3271,9 @@ msgstr "Bir demet oluÅŸturmak için bir depo gerekli." msgid "do not show bundle details" msgstr "demet ayrıntılarını gösterme" +msgid "need a repository to verify a bundle" +msgstr "bir demeti doÄŸrulamak için bir depo gerekiyor" + #, c-format msgid "%s is okay\n" msgstr "%s tamam\n" @@ -4272,6 +4285,14 @@ msgid "failed to unlink '%s'" msgstr "'%s' baÄŸlantısı kesilemedi" #, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "sabit baÄŸlantı, '%s' konumunda denetlenemiyor" + +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "sabit baÄŸlantı, '%s' konumundaki kaynaktan farklı" + +#, c-format msgid "failed to create link '%s'" msgstr "'%s' bağı oluÅŸturulamadı" @@ -5104,15 +5125,51 @@ msgstr "" "Diskin dolu olup olmadığını ve kotanızı aşıp aÅŸmadığınızı denetleyin,\n" "sonra kurtarmak için \"git restore --staged :/\" kullanın." -msgid "git config [<options>]" -msgstr "git config [<seçenekler>]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "" +"git config list [<dosya-seçeneÄŸi>] [<görüntüleme-seçeneÄŸi>] [--includes]" -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "tanımlanamayan --type argümanı, %s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [<dosya-seçeneÄŸi>] [<görüntüleme-seçeneÄŸi>] [--includes] [--" +"all] [--regexp=<düzenli-ifade>] [--value=<deÄŸer>] [--fixed-value] [--" +"default=<öntanımlı>] <ad>" -msgid "only one type at a time" -msgstr "bir kerede yalnızca bir tür" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [<dosya-seçeneÄŸi>] [--type=<tür>] [--all] [--value=<deÄŸer>] " +"[--fixed-value] <ad> <deÄŸer>" + +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [<dosya-seçeneÄŸi>] [--all] [--value=<deÄŸer>] [--fixed-" +"value] <ad> <deÄŸer>" + +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "git config rename-section [<dosya-seçeneÄŸi>] <eski-ad> <yeni-ad>" + +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [<dosya-seçeneÄŸi>] <ad>" + +msgid "git config edit [<file-option>]" +msgstr "git config edit [<dosya-seçeneÄŸi>]" + +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "git config [<dosya-seçeneÄŸi>] --get-colorbool <ad> [<stdout-tty>]" + +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [<dosya-seçeneÄŸi>] [--type=<tür>] [--comment=<ileti>] [--all] " +"[--value=<deÄŸer>] [--fixed-value] <ad> <deÄŸer>" msgid "Config file location" msgstr "Yapılandırma dosyası konumu" @@ -5138,54 +5195,6 @@ msgstr "ikili nesne numarası" msgid "read config from given blob object" msgstr "verilen ikili nesneden yapılandırmayı oku" -msgid "Action" -msgstr "Eylem" - -msgid "get value: name [value-pattern]" -msgstr "deÄŸer al: ad [deÄŸer-dizgisi]" - -msgid "get all values: key [value-pattern]" -msgstr "tüm deÄŸerleri al: anahtar [deÄŸer-dizgisi]" - -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "düzenli ifade için deÄŸerleri al: düzenli ifade adı [deÄŸer-dizgisi]" - -msgid "get value specific for the URL: section[.var] URL" -msgstr "URL için özel olan deÄŸeri al: bölüm[.var] URL" - -msgid "replace all matching variables: name value [value-pattern]" -msgstr "tüm eÅŸleÅŸen deÄŸiÅŸkenleri deÄŸiÅŸtir: ad deÄŸer [deÄŸer-dizgisi]" - -msgid "add a new variable: name value" -msgstr "yeni bir deÄŸiÅŸken ekle: ad deÄŸer" - -msgid "remove a variable: name [value-pattern]" -msgstr "bir deÄŸiÅŸken kaldır: ad [deÄŸer-dizgisi]" - -msgid "remove all matches: name [value-pattern]" -msgstr "tüm eÅŸleÅŸmeleri kaldır: ad [deÄŸer-dizgisi]" - -msgid "rename section: old-name new-name" -msgstr "bölümü yeniden adlandır: eski-ad yeni-ad" - -msgid "remove a section: name" -msgstr "bir bölümü kaldır: ad" - -msgid "list all" -msgstr "tümünü listele" - -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "deÄŸerleri 'deÄŸer-dizgisi' ile karşılaÅŸtırırken dizi eÅŸitliÄŸi kullan" - -msgid "open an editor" -msgstr "bir düzenleyici aç" - -msgid "find the color configured: slot [default]" -msgstr "yapılandırılan rengi bul: yuva [öntanımlı]" - -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "renk ayarını bul: yuva [stdout tty]" - msgid "Type" msgstr "Tür" @@ -5213,8 +5222,8 @@ msgstr "deÄŸer bir yol (dosya veya dizin adı)" msgid "value is an expiry date" msgstr "deÄŸer bir son kullanım tarihi" -msgid "Other" -msgstr "DiÄŸer" +msgid "Display options" +msgstr "Seçenekleri görüntüle" msgid "terminate values with NUL byte" msgstr "deÄŸerleri NUL baytı ile sonlandır" @@ -5222,9 +5231,6 @@ msgstr "deÄŸerleri NUL baytı ile sonlandır" msgid "show variable names only" msgstr "yalnızca deÄŸiÅŸken adlarını göster" -msgid "respect include directives on lookup" -msgstr "arama sırasında içerme yönergelerine uy" - msgid "show origin of config (file, standard input, blob, command line)" msgstr "" "yapılandırmanın kökenini göster (dosya, stdin, ikili nesne, komut satırı)" @@ -5234,14 +5240,15 @@ msgstr "" "yapılandırmanın kapsamını göster (çalışma aÄŸacı, yerel, global, sistem, " "komut)" -msgid "value" -msgstr "deÄŸer" +msgid "show config keys in addition to their values" +msgstr "deÄŸerlerine ek olarak yapılandırma anahtarlarını da göster" -msgid "with --get, use default value when missing entry" -msgstr "--get ile girdi verilmemiÅŸse öntanımlı deÄŸeri kullan" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "tanımlanamayan --type argümanı, %s" -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "kiÅŸi tarafından okunabilir yorum satırı (gerekirse önüne # koyulur)" +msgid "only one type at a time" +msgstr "bir kerede yalnızca bir tür" #, c-format msgid "wrong number of arguments, should be %d" @@ -5317,47 +5324,72 @@ msgstr "" "sürece birden çok çalışma aÄŸacı ile birlikte kullanılamaz. Ayrıntılar için\n" "lütfen \"git help worktree\" içindeki \"CONFIGURATION FILE\" bölümünü okuyun" -msgid "--get-color and variable type are incoherent" -msgstr "--get-color ve deÄŸiÅŸken türü tutarsız" +msgid "Other" +msgstr "DiÄŸer" -msgid "only one action at a time" -msgstr "bir kerede yalnızca bir eylem" +msgid "respect include directives on lookup" +msgstr "arama sırasında içerme yönergelerine uy" -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "--name-only yalnızca ÅŸunlara uygulanabilir: --list, --get-regexp" +#, c-format +msgid "unable to read config file '%s'" +msgstr "'%s' yapılandırma dosyası okunamıyor" -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" -msgstr "" -"--show-origin yalnızca ÅŸunlara uygulanabilir: --get, --get-all, --get-regexp " -"ve --list" +msgid "error processing config file(s)" +msgstr "yapılandırma dosyaları iÅŸlenirken hata" -msgid "--default is only applicable to --get" -msgstr "--default yalnızca --get için uygulanabilir" +msgid "Filter options" +msgstr "Süzme seçenekleri" -msgid "--comment is only applicable to add/set/replace operations" -msgstr "--comment yalnızca ekle/ayarla/deÄŸiÅŸtir iÅŸlemlerine uygulanabilir" +msgid "return all values for multi-valued config options" +msgstr "birden çok deÄŸerli yapılandırma seçeneklerinin tüm deÄŸerlerini döndür" + +msgid "interpret the name as a regular expression" +msgstr "adı düzenli ifade olarak yorumla" + +msgid "show config with values matching the pattern" +msgstr "dizgiyle eÅŸleÅŸen deÄŸerleri olan yapılandırmayı göster" + +msgid "use string equality when comparing values to value pattern" +msgstr "deÄŸerleri deÄŸer dizgisiyle karşılaÅŸtırırken dizi eÅŸitliÄŸini kullan" + +msgid "URL" +msgstr "URL" + +msgid "show config matching the given URL" +msgstr "verilen URL ile eÅŸleÅŸen yapılandırmayı göster" + +msgid "value" +msgstr "deÄŸer" + +msgid "use default value when missing entry" +msgstr "girdi eksikse öntanımlı deÄŸeri kullan" msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value yalnızca 'deÄŸer-dizgisi' ile uygulanır" -#, c-format -msgid "unable to read config file '%s'" -msgstr "'%s' yapılandırma dosyası okunamıyor" +msgid "--default= cannot be used with --all or --url=" +msgstr "--default=, --all veya --url= ile kullanılamaz" -msgid "error processing config file(s)" -msgstr "yapılandırma dosyaları iÅŸlenirken hata" +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "--url=; --all, --regexp veya --value ile kullanılamaz" -msgid "editing stdin is not supported" -msgstr "stdin'i düzenleme desteklenmiyor" +msgid "Filter" +msgstr "Süzgeç" -msgid "editing blobs is not supported" -msgstr "ikili nesneleri düzenleme desteklenmiyor" +msgid "replace multi-valued config option with new value" +msgstr "birden çok deÄŸerli yapılandırma seçeneÄŸini yeni deÄŸerle deÄŸiÅŸtir" -#, c-format -msgid "cannot create configuration file %s" -msgstr "%s yapılandırma dosyası oluÅŸturulamıyor" +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "kiÅŸi tarafından okunabilir yorum satırı (gerekirse önüne # koyulur)" + +msgid "add a new line without altering any existing values" +msgstr "var olan herhangi deÄŸeri deÄŸiÅŸtirmeden yeni satır ekle" + +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "--fixed-value, yalnızca --value=<dizgi> ile geçerlidir" + +msgid "--append cannot be used with --value=<pattern>" +msgstr "--append, --value=<dizgi> ile kullanılamaz" #, c-format msgid "" @@ -5372,6 +5404,86 @@ msgstr "" msgid "no such section: %s" msgstr "böyle bir bölüm yok: %s" +msgid "editing stdin is not supported" +msgstr "stdin'i düzenleme desteklenmiyor" + +msgid "editing blobs is not supported" +msgstr "ikili nesneleri düzenleme desteklenmiyor" + +#, c-format +msgid "cannot create configuration file %s" +msgstr "%s yapılandırma dosyası oluÅŸturulamıyor" + +msgid "Action" +msgstr "Eylem" + +msgid "get value: name [<value-pattern>]" +msgstr "deÄŸer al: ad [<deÄŸer-dizgisi>]" + +msgid "get all values: key [<value-pattern>]" +msgstr "tüm deÄŸerleri al: anahtar [<deÄŸer-dizgisi>]" + +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "düzenli ifade için deÄŸerleri al: düzenli ifade adı [<deÄŸer-dizgisi>]" + +msgid "get value specific for the URL: section[.var] URL" +msgstr "URL için özel olan deÄŸeri al: bölüm[.var] URL" + +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "tüm eÅŸleÅŸen deÄŸiÅŸkenleri deÄŸiÅŸtir: ad deÄŸer [<deÄŸer-dizgisi>]" + +msgid "add a new variable: name value" +msgstr "yeni bir deÄŸiÅŸken ekle: ad deÄŸer" + +msgid "remove a variable: name [<value-pattern>]" +msgstr "bir deÄŸiÅŸken kaldır: ad [<deÄŸer-dizgisi>]" + +msgid "remove all matches: name [<value-pattern>]" +msgstr "tüm eÅŸleÅŸmeleri kaldır: ad [<deÄŸer-dizgisi>]" + +msgid "rename section: old-name new-name" +msgstr "bölümü yeniden adlandır: eski-ad yeni-ad" + +msgid "remove a section: name" +msgstr "bir bölümü kaldır: ad" + +msgid "list all" +msgstr "tümünü listele" + +msgid "open an editor" +msgstr "bir düzenleyici aç" + +msgid "find the color configured: slot [<default>]" +msgstr "yapılandırılan rengi bul: yuva [<öntanımlı>]" + +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "renk ayarını bul: yuva [<stdout-tty>]" + +msgid "with --get, use default value when missing entry" +msgstr "--get ile girdi verilmemiÅŸse öntanımlı deÄŸeri kullan" + +msgid "--get-color and variable type are incoherent" +msgstr "--get-color ve deÄŸiÅŸken türü tutarsız" + +msgid "no action specified" +msgstr "belirtilen eylem yok" + +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "--name-only yalnızca ÅŸunlara uygulanabilir: --list, --get-regexp" + +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "" +"--show-origin yalnızca ÅŸunlara uygulanabilir: --get, --get-all, --get-regexp " +"ve --list" + +msgid "--default is only applicable to --get" +msgstr "--default yalnızca --get için uygulanabilir" + +msgid "--comment is only applicable to add/set/replace operations" +msgstr "--comment yalnızca ekle/ayarla/deÄŸiÅŸtir iÅŸlemlerine uygulanabilir" + msgid "print sizes in human readable format" msgstr "yazdırma boyutları kiÅŸi tarafından okunabilir biçimde" @@ -6194,6 +6306,9 @@ msgstr "yapılandırma" msgid "config key storing a list of repository paths" msgstr "bir depo yolları listesi tutan yapılandırma anahtarı" +msgid "keep going even if command fails in a repository" +msgstr "komut depoda baÅŸarısız olsa bile gitmeyi sürdür" + msgid "missing --config=<config>" msgstr "--config=<yapılandırma> eksik" @@ -7645,8 +7760,11 @@ msgstr "diziyi n. deneme olarak imle" msgid "max length of output filename" msgstr "çıktı dosya adının olabilecek en çok uzunluÄŸu" -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "[PATCH] yerine [RFC PATCH] kullan" +msgid "rfc" +msgstr "rfc" + +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "'PATCH' öncesi <rfc> ekle (öntanımlı 'RFC')" msgid "cover-from-description-mode" msgstr "açıklama kipinden kapak sayfası kipi" @@ -7909,11 +8027,12 @@ msgstr "" "kullanılamaz" msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<yürütülebilir>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-" +"pack=<yürütülebilir>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<anahtar>]\n" " [--symref] [<depo> [<dizgiler>...]]" @@ -7929,8 +8048,11 @@ msgstr "uzak konum makinesindeki git-upload-pack yolu" msgid "limit to tags" msgstr "etiketlere kısıtla" -msgid "limit to heads" -msgstr "uç iÅŸlemelere kısıtla" +msgid "limit to branches" +msgstr "dallara kısıtla" + +msgid "deprecated synonym for --branches" +msgstr "--branches için artık kullanılmayan eÅŸanlamlı" msgid "do not show peeled tags" msgstr "soyulmuÅŸ etiketleri gösterme" @@ -10553,6 +10675,22 @@ msgstr "silmek için bir baÅŸvuru günlüğü belirtilmedi" msgid "invalid ref format: %s" msgstr "geçersiz baÅŸvuru biçimi: %s" +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=<biçim> [--dry-run]" + +msgid "specify the reference format to convert to" +msgstr "dönüştürülecek baÅŸvuru biçimini belirt" + +msgid "perform a non-destructive dry-run" +msgstr "yıkıcı olmayan bir deneme gerçekleÅŸtir" + +msgid "missing --ref-format=<format>" +msgstr "--ref-format=<biçim> eksik" + +#, c-format +msgid "repository already uses '%s' format" +msgstr "depo halihazırda '%s' biçimini kullanıyor" + msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" "mirror=<fetch|push>] <name> <url>" @@ -10838,9 +10976,6 @@ msgstr "* uzak konum %s" msgid " Fetch URL: %s" msgstr " URL'yi getir: %s" -msgid "(no URL)" -msgstr "(URL yok)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -10849,6 +10984,9 @@ msgstr "(URL yok)" msgid " Push URL: %s" msgstr " URL'yi it: %s" +msgid "(no URL)" +msgstr "(URL yok)" + #, c-format msgid " HEAD branch: %s" msgstr " HEAD dalı: %s" @@ -10955,10 +11093,6 @@ msgstr "itme URL'lerinden çok getirme URL'lerini sorgula" msgid "return all URLs" msgstr "tüm URL'leri döndür" -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "'%s' uzak konumu için URL yapılandırılmamış" - msgid "manipulate push URLs" msgstr "itme URL'lerini deÄŸiÅŸtir" @@ -11959,12 +12093,12 @@ msgstr "bilinmeyen saÄŸlama algoritması '%s'" msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<dizgi>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<dizgi>...]" msgid "" "git show-ref --verify [-q | --quiet] [-d | --dereference]\n" @@ -11987,11 +12121,11 @@ msgstr "baÅŸvuru yok" msgid "failed to look up reference" msgstr "baÅŸvuru bakılamadı" -msgid "only show tags (can be combined with heads)" -msgstr "yalnızca etiketleri göster (dal uçlarıyla birlikte kullanılabilir)" +msgid "only show tags (can be combined with branches)" +msgstr "yalnızca etiketleri göster (dallarla birlikte kullanılabilir)" -msgid "only show heads (can be combined with tags)" -msgstr "yalnızca dal uçlarını göster (etiketlerle birlikte kullanılabilir)" +msgid "only show branches (can be combined with tags)" +msgstr "yalnızca dalları göster (etiketlerle birlikte kullanılabilir)" msgid "check for reference existence without resolving" msgstr "çözmeden baÅŸvuru varlığını denetle" @@ -12611,14 +12745,14 @@ msgstr "" "baÅŸka bir altmodülün git dizininde '%s' oluÅŸturma/kullanma reddediliyor" #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "'%s' ögesinin '%s' altmodül yoluna klonlanması baÅŸarısız" - -#, c-format msgid "directory not empty: '%s'" msgstr "dizin boÅŸ deÄŸil: '%s'" #, c-format +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "'%s' ögesinin '%s' altmodül yoluna klonlanması baÅŸarısız" + +#, c-format msgid "could not get submodule directory for '%s'" msgstr "'%s' için altmodül dizini alınamadı" @@ -12975,10 +13109,12 @@ msgstr "güncelleme nedeni" msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" "git tag [-a | -s | -u <anahtar-kimliÄŸi>] [-f] [-m <ileti> | -F <dosya>] [-" "e]\n" +" [(--trailer <jeton>[(=|:)<deÄŸer>])...]\n" " <etiket-adı> [<iÅŸleme> | <nesne>]" msgid "git tag -d <tagname>..." @@ -13324,8 +13460,8 @@ msgid "" "core.untrackedCache is set to true; remove or change it, if you really want " "to disable the untracked cache" msgstr "" -"core.untrackedCache 'true' olarak ayarlanmış; izlenmeyen önbelleÄŸi gerçekten " -"devre dışı bırakmayı istiyorsanız bunu kaldırın veya deÄŸiÅŸtirin" +"core.untrackedCache 'true' olarak ayarlanmış; izlenmeyen önbelleÄŸi devre " +"dışı bırakmayı gerçekten istiyorsanız bunu kaldırın veya deÄŸiÅŸtirin" msgid "Untracked cache disabled" msgstr "İzlenmeyen önbellek devre dışı bırakıldı" @@ -13335,7 +13471,7 @@ msgid "" "to enable the untracked cache" msgstr "" "core.untrackedCache 'false' olarak ayarlanmış; izlenmeyen önbelleÄŸi " -"gerçekten etkinleÅŸtirmek istiyorsanız bunu kaldırın veya deÄŸiÅŸtirin" +"etkinleÅŸtirmeyi gerçekten istiyorsanız bunu kaldırın veya deÄŸiÅŸtirin" #, c-format msgid "Untracked cache enabled for '%s'" @@ -13343,8 +13479,8 @@ msgstr "İzlenmeyen önbellek '%s' için etkinleÅŸtirildi" msgid "core.fsmonitor is unset; set it if you really want to enable fsmonitor" msgstr "" -"core.fsmonitor ayarlanmamış; dosya sistemin monitörünü gerçekten " -"etkinleÅŸtirmek istiyorsanız onu ayarlayın" +"core.fsmonitor ayarlanmamış; dosya sistemin monitörünü etkinleÅŸtirmeyi " +"gerçekten istiyorsanız onu ayarlayın" msgid "fsmonitor enabled" msgstr "dosya sistemi monitörü etkin" @@ -13352,8 +13488,8 @@ msgstr "dosya sistemi monitörü etkin" msgid "" "core.fsmonitor is set; remove it if you really want to disable fsmonitor" msgstr "" -"core.fsmonitor ayarlanmış; dosya sistemi monitörünü gerçekten devre dışı " -"bırakmak istiyorsanız onu kaldırın" +"core.fsmonitor ayarlanmış; dosya sistemi monitörünü devre dışı bırakmayı " +"gerçekten istiyorsanız onu kaldırın" msgid "fsmonitor disabled" msgstr "dosya sistemi monitörü devre dışı" @@ -13818,9 +13954,6 @@ msgstr "tanımlanamayan üstbilgi: %s%s (%d)" msgid "Repository lacks these prerequisite commits:" msgstr "Depo aÅŸağıdaki önkoÅŸul iÅŸlemelere iye deÄŸil:" -msgid "need a repository to verify a bundle" -msgstr "bir demeti doÄŸrulamak için bir depo gerekiyor" - msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -14217,6 +14350,9 @@ msgstr "Depoya ne itildiyse al" msgid "Manage reflog information" msgstr "BaÅŸvuru günlüğü bilgisini yönet" +msgid "Low-level access to refs" +msgstr "BaÅŸvurulara alt düzeyden eriÅŸim" + msgid "Manage set of tracked repositories" msgstr "İzlenen depolar setini yönet" @@ -14521,6 +14657,14 @@ msgid "commit-graph required commit data chunk missing or corrupted" msgstr "" "commit-graph'ten gerekli OID çıkış sayısı iri parçası eksik veya hasarlı" +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "" +"uyumsuz ayarlardan dolayı '%s' commit-graph katmanı için olan Bloom " +"süzgeçleri devre dışı bırakılıyor" + msgid "commit-graph has no base graphs chunk" msgstr "commit-graph temel grafiÄŸi iri parçasına iye deÄŸil" @@ -14645,6 +14789,14 @@ msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled" msgstr "" "bir commit-graph yazılmaya çalışılıyor; ancak 'core.commitGraph' devre dışı" +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " +"(%d) is not supported" +msgstr "" +"bir commit-graph yazılmaya çalışılıyor; ancak 'commitGraph." +"changedPathsVersion' (%d) desteklenmiyor" + msgid "too many commits to write graph" msgstr "grafik yazımı için pek fazla iÅŸleme" @@ -16488,17 +16640,21 @@ msgstr "" msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v | --version] [-h | --help] [-C <yol>] [-c <ad>=<deÄŸer>]\n" " [--exec-path[=<yol>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<yol>] [--work-tree=<yol>] [--namespace=<ad>]\n" -" [--config-env=<ad>=<çevre-deÄŸiÅŸkeni>] <komut> [<argümanlar>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<ad>] [--config-env=<ad>=<çevre-" +"deÄŸiÅŸkeni>]\n" +" <komut> [<argümanlar>]" msgid "" "'git help -a' and 'git help -g' list available subcommands and some\n" @@ -16838,13 +16994,13 @@ msgstr "" "'%s' kancası yok sayıldı; çünkü bir yürütülebilir olarak ayarlanmamış.\n" "Bu uyarıyı 'git config advice.ignoredHook false' ile kapatabilirsiniz." +msgid "not a git repository" +msgstr "bir git deposu deÄŸil" + #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "--packfile için argüman geçerli bir saÄŸlama olmalıdır ('%s' alındı)" -msgid "not a git repository" -msgstr "bir git deposu deÄŸil" - #, c-format msgid "negative value for http.postBuffer; defaulting to %d" msgstr "http.postBuffer için negatif deÄŸer; %d olarak varsayılıyor" @@ -16855,6 +17011,9 @@ msgstr "Delegasyon denetimi cURL < 7.22.0 tarafından desteklenmiyor" msgid "Public key pinning not supported with cURL < 7.39.0" msgstr "Ortak anahtar iÄŸnelemesi cURL < 7.39.0 tarafından desteklenmiyor" +msgid "Unknown value for http.proactiveauth" +msgstr "http.proactiveauth için bilinmeyen deÄŸer" + msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "CURLSSLOPT_NO_REVOKE cURL < 7.44.0 tarafından desteklenmiyor" @@ -16871,6 +17030,12 @@ msgstr "" msgid "Could not set SSL backend to '%s': already set" msgstr "SSL arka ucu '%s' olarak ayarlanamadı: Halihazırda ayarlanmış" +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "http.cookiefile '-' konumundan çerezleri okuma reddediliyor" + +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "boÅŸ http.cookiefile için http.savecookies yok sayılıyor" + #, c-format msgid "" "unable to update url base from redirection:\n" @@ -17047,8 +17212,8 @@ msgid "Failed to merge submodule %s (commits not present)" msgstr "%s altmodülü birleÅŸtirilemedi (iÅŸlemeler yok)" #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" -msgstr "%s altmodülü birleÅŸtirilemedi (depo hasarlı)" +msgid "error: failed to merge submodule %s (repository corrupt)" +msgstr "hata: %s altmodülü birleÅŸtirilemedi (depo hasarlı)" #, c-format msgid "Failed to merge submodule %s (commits don't follow merge-base)" @@ -17076,12 +17241,13 @@ msgstr "" "%s altmodülü birleÅŸtirilemedi; ancak birden çok olası birleÅŸtirmeler var:\n" "%s" -msgid "failed to execute internal merge" -msgstr "iç birleÅŸtirme yürütülemedi" +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "hata: %s için iç birleÅŸtirme yürütülemedi" #, c-format -msgid "unable to add %s to database" -msgstr "%s veritabanına eklenemiyor" +msgid "error: unable to add %s to database" +msgstr "hata: %s veritabanına eklenemiyor" #, c-format msgid "Auto-merging %s" @@ -17178,12 +17344,12 @@ msgstr "" "ancak %s içinde silindi." #, c-format -msgid "cannot read object %s" -msgstr "%s nesnesi okunamıyor" +msgid "error: cannot read object %s" +msgstr "hata: %s nesnesi okunamıyor" #, c-format -msgid "object %s is not a blob" -msgstr "%s nesnesi ikili bir nesne deÄŸil" +msgid "error: object %s is not a blob" +msgstr "hata: %s nesnesi ikili bir nesne deÄŸil" #, c-format msgid "" @@ -17322,6 +17488,10 @@ msgid "do not know what to do with %06o %s '%s'" msgstr "ÅŸununla ne yapılacağı bilinmiyor: %06o %s '%s'" #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "%s altmodülü birleÅŸtirilemedi (depo hasarlı)" + +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "%s altmodülü ÅŸu iÅŸlemeye ileri sarılıyor:" @@ -17360,6 +17530,13 @@ msgstr "" msgid "Failed to merge submodule %s (multiple merges found)" msgstr "%s altmodülü birleÅŸtirilemedi (birden çok birleÅŸtirme bulundu)" +msgid "failed to execute internal merge" +msgstr "iç birleÅŸtirme yürütülemedi" + +#, c-format +msgid "unable to add %s to database" +msgstr "%s veritabanına eklenemiyor" + #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "" @@ -17464,6 +17641,14 @@ msgstr "" "ÇAKIÅžMA (y. adlandır/y. adlandır): Dizini %s->%s olarak adlandır (%s " "içinde). Dizini %s->%s olarak adlandır (%s içinde)" +#, c-format +msgid "cannot read object %s" +msgstr "%s nesnesi okunamıyor" + +#, c-format +msgid "object %s is not a blob" +msgstr "%s nesnesi ikili bir nesne deÄŸil" + msgid "modify" msgstr "deÄŸiÅŸtir" @@ -17547,9 +17732,6 @@ msgstr "satır ayrıştırılamadı: %s" msgid "malformed line: %s" msgstr "hatalı oluÅŸturulmuÅŸ satır: %s" -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "var olan multi-pack-index yok sayılıyor; saÄŸlama toplamı uyumsuzluÄŸu" - msgid "could not load pack" msgstr "paket yüklenemedi" @@ -17557,6 +17739,9 @@ msgstr "paket yüklenemedi" msgid "could not open index for %s" msgstr "%s için indeks açılamadı" +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "var olan multi-pack-index yok sayılıyor; saÄŸlama toplamı uyumsuzluÄŸu" + msgid "Adding packfiles to multi-pack-index" msgstr "Paket dosyaları multi-pack-index'e ekleniyor" @@ -18160,6 +18345,17 @@ msgstr "nesne ayrıştırılamıyor: %s" msgid "hash mismatch %s" msgstr "saÄŸlama uyuÅŸmazlığı %s" +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "biteÅŸlem indeksi yazılırken yinelenen girdi: %s" + +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "seçili olmayan iÅŸleme yazılmaya çalışıldı: '%s'" + +msgid "too many pseudo-merges" +msgstr "pek çok yalancı birleÅŸtirme" + msgid "trying to write commit not in index" msgstr "indekste olmayan iÅŸleme yazılmaya çalışılıyor" @@ -18184,6 +18380,20 @@ msgid "corrupted bitmap index file (too short to fit lookup table)" msgstr "" "hasarlı biteÅŸlem indeks dosyası (arama tablosuna sığmak için pek küçük)" +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "" +"hasarlı biteÅŸlem indeks dosyası (yalancı birleÅŸtirme tablo üstbilgisine " +"sığmak için pek kısa)" + +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "" +"hasarlı biteÅŸlem indeks dosyası (yalancı birleÅŸtirme tablosuna sığmak için " +"pek kısa)" + +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "hasarlı biteÅŸlem indeks dosyası, yalancı birleÅŸtirme tablosu pek kısa" + #, c-format msgid "duplicate entry in bitmap index: '%s'" msgstr "biteÅŸlem indeksinde yinelenen girdi: '%s'" @@ -18274,6 +18484,10 @@ msgid "mismatch in bitmap results" msgstr "biteÅŸlem sonuçlarında uyuÅŸmazlık" #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "yalancı birleÅŸtirme indeksi erim dışında (%<PRIu32> >= %<PRIuMAX>)" + +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "öge bulunamadı: '%s'; '%s' paketinde, %<PRIuMAX> ofsetinde" @@ -18635,6 +18849,9 @@ msgstr "iÅŸ parçacıklarına ayrılmış 'lstat' oluÅŸturulamıyor: %s" msgid "unable to parse --pretty format" msgstr "--pretty biçimi ayrıştırılamıyor" +msgid "lazy fetching disabled; some objects may not be available" +msgstr "gerekince getirme devre dışı; bazı nesneler kullanılamayabilir" + msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "promisor-remote: getirme alt süreci çatallanamıyor" @@ -18658,6 +18875,67 @@ msgstr "object-info: argümanlardan sonra floÅŸ bekleniyordu" msgid "Removing duplicate objects" msgstr "YinelenmiÅŸ nesneler kaldırılıyor" +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "%s için yalancı birleÅŸtirme düzenli ifadesi yüklenemedi: '%s'" + +#, c-format +msgid "%s must be non-negative, using default" +msgstr "%s negatif dışı bir deÄŸer olmalı, öntanımlı deÄŸer kullanılıyor" + +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "%s, 0 ve 1 arasında olmalıdır, öntanımlı kullanılıyor" + +#, c-format +msgid "%s must be positive, using default" +msgstr "%s pozitif olmalıdır, öntanımlı kullanılıyor" + +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "yalancı birleÅŸtirme grubu '%s' içinde gerekli dizgi yok" + +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "" +"yalancı birleÅŸtirme gribi '%s' içinde kararlıdan önce kararsız eÅŸik var" + +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "" +"yapılandırmadaki yalancı birleÅŸtirme düzenli ifadesinde pek çok yakalama " +"grubu var (max=%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"geniÅŸletilmiÅŸ yalancı birleÅŸtirme sınırlar dışında okundu (%<PRIuMAX> >= " +"%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"geniÅŸletilmiÅŸ yalancı birleÅŸtirme girdisi pek kısa (%<PRIuMAX> >= %<PRIuMAX>)" + +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "%s iÅŸlemesi için yalancı birleÅŸtirme bulunamadı, %<PRIuMAX> ofsetinde" + +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "" +"geniÅŸletilmiÅŸ yalancı birleÅŸtirme araması sınırlar dışında (%<PRIu32> >= " +"%<PRIu32>)" + +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "sınırlar dışında okundu: (%<PRIuMAX> >= %<PRIuMAX>)" + +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "%s iÅŸlemesi için geniÅŸletilmiÅŸ yalancı birleÅŸtirme tablosu okunamadı" + msgid "could not start `log`" msgstr "'log' baÅŸlatılamadı" @@ -19258,11 +19536,18 @@ msgstr "" msgid "log for %s is empty" msgstr "%s için olan günlük boÅŸ" +msgid "refusing to force and skip creation of reflog" +msgstr "baÅŸvuru günlüğünün oluÅŸturulma/atlanma zorlanması reddediliyor" + #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "hatalı ada iye '%s' baÅŸvurusunu güncelleme reddediliyor" #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "'%s' yalancı baÅŸvurusunun güncellenmesi reddediliyor" + +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "'%s' baÅŸvurusu için update_ref baÅŸarısız oldu: %s" @@ -19293,6 +19578,25 @@ msgid "could not delete references: %s" msgstr "baÅŸvurular silinemedi: %s" #, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "BaÅŸvuruların göç denemesi bitti, sonuç '%s' konumunda bulunabilir\n" + +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "geçici göç dizini '%s' kaldırılamadı" + +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "göç ettirilen baÅŸvurular '%s' konumunda bulunabilir" + +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "" +"'%s' baÅŸvurusu kilitlenemiyor: '%s' hedefiyle bir sembolik baÅŸvuru " +"bekleniyordu; ancak bu normal bir baÅŸvuru" + +#, c-format msgid "refname is dangerous: %s" msgstr "baÅŸvuru adı tehlikeli: %s" @@ -19324,8 +19628,8 @@ msgstr "'%s' baÅŸvurusu kilitlenemiyor: BaÅŸvuruyu okurken hata" msgid "" "multiple updates for '%s' (including one via symref '%s') are not allowed" msgstr "" -"'%s' için birden çok güncellemeye ('%s' sembolik baÄŸlantısı ile olan bir " -"tanesini de içeren) izin verilmiyor" +"'%s' için birden çok güncellemeye ('%s' sembolik bağı ile olan bir tanesini " +"de içeren) izin verilmiyor" #, c-format msgid "cannot lock ref '%s': reference already exists" @@ -19357,7 +19661,7 @@ msgstr "baÅŸvuru adı %s bulunamadı" #, c-format msgid "refname %s is a symbolic ref, copying it is not supported" -msgstr "baÅŸvuru adı %s bir sembolik baÄŸlantı, onu kopyalamak desteklenmiyor" +msgstr "baÅŸvuru adı %s bir sembolik baÄŸ, onu kopyalamak desteklenmiyor" #, c-format msgid "invalid refspec '%s'" @@ -20443,6 +20747,50 @@ msgstr "" "update-ref, tümüyle kalifiye bir baÅŸvuru adı gerektiriyor; örn. refs/heads/%s" #, c-format +msgid "'%s' does not accept merge commits" +msgstr "'%s' birleÅŸtirme iÅŸlemelerini kabul etmiyor" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"'pick', bir birleÅŸtirme iÅŸlemesi almaz. BirleÅŸtirmeyi\n" +"yeniden oynatmak istediyseniz iÅŸlemede 'merge -C' kullanın." + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"'reword', bir birleÅŸtirme iÅŸlemesi almaz. BirleÅŸtirmeyi\n" +"yeniden oynatmak ve iÅŸleme iletisini düzenlemek istediyseniz\n" +"iÅŸlemede 'merge -c' kullanın." + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"'edit', bir birleÅŸtirme iÅŸlemesi almaz. BirleÅŸtirmeyi\n" +"yeniden oynatmak istediyseniz iÅŸlemede 'merge -C' kullanın,sonrasında " +"denetimin size geri verilmesi için 'break'\n" +"yapın; böylece 'git commit --amend && git rebase --continue'\n" +"yapabilirsiniz." + +msgid "cannot squash merge commit into another commit" +msgstr "birleÅŸtirme iÅŸlemesi baÅŸka bir iÅŸlemeye tıkıştırılamaz" + +#, c-format msgid "invalid command '%.*s'" msgstr "geçersiz komut %.*s" @@ -20558,9 +20906,8 @@ msgstr "" msgid "cannot read HEAD" msgstr "HEAD okunamıyor" -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "'%s', '%s' konumuna kopyalanamıyor" +msgid "could not write commit message file" +msgstr "iÅŸleme iletisi dosyası yazılamadı" #, c-format msgid "" @@ -20958,6 +21305,18 @@ msgstr "cwd'ye geri dönülemiyor" msgid "failed to stat '%*s%s%s'" msgstr "'%*s%s%s' bilgileri alınamadı" +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"'%s' konumundaki depoda belirsiz iyelik algılandı\n" +"%sBu dizin için istisna eklemek için ÅŸunu çağırın:\n" +"\n" +"\tgit config --global --add safe.directory %s" + msgid "Unable to read current working directory" msgstr "Åžu anki çalışma dizini okunamıyor" @@ -20979,18 +21338,6 @@ msgstr "" "ayarlanmamış)." #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"'%s' konumundaki depoda belirsiz iyelik algılandı\n" -"%sBu dizin için istisna eklemek için ÅŸunu çağırın:\n" -"\n" -"\tgit config --global --add safe.directory %s" - -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" msgstr "çıplak depo '%s', kullanılamaz (safe.bareRepository '%s')" @@ -21294,6 +21641,15 @@ msgid "submodule git dir '%s' is inside git dir '%.*s'" msgstr "altmodül git dizini '%s', '%.*s' git dizini içinde" #, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "" +"'%.*s' ögesinin bir sembolik baÄŸ olması beklenmiyordu, '%s' altmodül yolunda" + +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "'%s' altmodül yolunun bir sembolik baÄŸ olması beklenmiyordu" + +#, c-format msgid "" "relocate_gitdir for submodule '%s' with more than one worktree not supported" msgstr "" @@ -21331,10 +21687,6 @@ msgstr "'%s', lstat yapılamadı" msgid "no remote configured to get bundle URIs from" msgstr "demet URI'lerini almak için bir uzak konum yapılandırılmamış" -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "'%s' uzak konumunun yapılandırılmış bir URL'si yok" - msgid "could not get the bundle-uri list" msgstr "bundle-uri listesi alınamadı" @@ -22790,24 +23142,24 @@ msgid "Failed to send %s\n" msgstr "%s gönderilemedi\n" #, perl-format -msgid "Dry-Sent %s\n" -msgstr "%s gönderilir gibi yapıldı\n" +msgid "Dry-Sent %s" +msgstr "%s gönderilir gibi yapıldı" #, perl-format -msgid "Sent %s\n" -msgstr "%s gönderildi\n" +msgid "Sent %s" +msgstr "%s gönderildi" -msgid "Dry-OK. Log says:\n" -msgstr "Sınama tamam. Günlük çıktısı:\n" +msgid "Dry-OK. Log says:" +msgstr "Sınama tamam. Günlük çıktısı:" -msgid "OK. Log says:\n" -msgstr "Tamam. Günlük çıktısı:\n" +msgid "OK. Log says:" +msgstr "Tamam. Günlük çıktısı:" msgid "Result: " msgstr "Sonuç: " -msgid "Result: OK\n" -msgstr "Sonuç: Tamam\n" +msgid "Result: OK" +msgstr "Sonuç: Tamam" #, perl-format msgid "can't open file %s" @@ -22880,4 +23232,4 @@ msgstr "%s, yedek sonek '%s' ile atlanıyor.\n" #. TRANSLATORS: please keep "[y|N]" as is. #, perl-format msgid "Do you really want to send %s? [y|N]: " -msgstr "%s ögesini gerçekten göndermek istiyor musunuz? [y|N]: " +msgstr "%s ögesini göndermeyi gerçekten istiyor musunuz? [y|N]: " @@ -6,10 +6,10 @@ # msgid "" msgstr "" -"Project-Id-Version: Git v2.45\n" +"Project-Id-Version: Git v2.46\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-27 09:55-0700\n" -"PO-Revision-Date: 2024-04-15 15:55-0700\n" +"POT-Creation-Date: 2023-04-11 09:55-0700\n" +"PO-Revision-Date: 2024-07-24 08:45-0700\n" "Last-Translator: Arkadii Yakovets <ark@cho.red>\n" "Language-Team: Ukrainian <https://github.com/arkid15r/git-uk-l10n/>\n" "Language: uk\n" @@ -565,6 +565,10 @@ msgstr "" "p - показати поточний шматок\n" "? - показати довідку\n" +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "ОчікувавÑÑ Ð»Ð¸ÑˆÐµ один Ñимвол, отримано \"%s\"" + msgid "No previous hunk" msgstr "Ðемає попереднього шматка" @@ -614,9 +618,19 @@ msgstr "Розщепити на %d шматків." msgid "Sorry, cannot edit this hunk" msgstr "Вибачайте, не можу редагувати цей шматок" +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "Ðевідома команда: \"%s\" (викориÑтовуйте \"?\" Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¸)" + msgid "'git apply' failed" msgstr "\"git apply\" завершивÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾" +msgid "No changes." +msgstr "Ðічого не змінено." + +msgid "Only binary files changed." +msgstr "Змінено лише бінарні файли." + #, c-format msgid "" "\n" @@ -1487,6 +1501,9 @@ msgstr "Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð´Ñ‚Ð¾ великого файлу gitattribu msgid "ignoring overly large gitattributes blob '%s'" msgstr "Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð´Ñ‚Ð¾ великих gitattributes blob \"%s\"" +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "неможливо викориÑтати --attr-source або GIT_ATTR_SOURCE без Ñховища" + msgid "bad --attr-source or GIT_ATTR_SOURCE" msgstr "невірний --attr-source або GIT_ATTR_SOURCE" @@ -1809,13 +1826,6 @@ msgstr "неможливо виконати chmod %cx \"%s\"" msgid "Unstaged changes after refreshing the index:" msgstr "ÐеіндекÑовані зміни піÑÐ»Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑу:" -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"параметр add.interactive.useBuiltin було видалено!\n" -"ДивітьÑÑ Ð·Ð°Ð¿Ð¸Ñ Ñƒ \"git help config\" Ð´Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆ детальної інформації." - msgid "could not read the index" msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ індекÑ" @@ -2258,6 +2268,9 @@ msgstr "перервати латаннÑ, але залишити HEAD на тРmsgid "show the patch being applied" msgstr "показати латку, що заÑтоÑовуєтьÑÑ" +msgid "try to apply current patch again" +msgstr "Ñпробувати заÑтоÑувати поточну латку ще раз" + msgid "record the empty patch as an empty commit" msgstr "запиÑати порожню латку Ñк порожній коміт" @@ -2314,9 +2327,6 @@ msgstr "git apply [<опції>] [<латка>...]" msgid "could not redirect output" msgstr "неможливо перенаправити вивід" -msgid "git archive: Remote with no URL" -msgstr "git archive: віддалене Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð±ÐµÐ· URL" - msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "git archive: очікувалоÑÑŒ ACK/NAK, отримано flush-пакет" @@ -3231,6 +3241,9 @@ msgstr "Ð”Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð°ÐºÑƒÐ½ÐºÐ° потрібне Ñховище msgid "do not show bundle details" msgstr "не показувати деталі пакунка" +msgid "need a repository to verify a bundle" +msgstr "потрібне Ñховище Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ пакунка" + #, c-format msgid "%s is okay\n" msgstr "%s у порÑдку\n" @@ -4262,6 +4275,14 @@ msgid "failed to unlink '%s'" msgstr "не вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ \"%s\"" #, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "неможливо перевірити жорÑтке поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\"" + +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "жорÑтке поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ñ€Ñ–Ð·Ð½ÑєтьÑÑ Ð²Ñ–Ð´ джерела в \"%s\"" + +#, c-format msgid "failed to create link '%s'" msgstr "не вдалоÑÑ Ñтворити поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\"" @@ -5095,15 +5116,50 @@ msgstr "" "новий файл індекÑу. ПереконайтеÑÑ, що диÑк не переповнений Ñ– квота\n" "не перевищена, а потім виконайте \"git restore --staged :/\" Ð´Ð»Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ." -msgid "git config [<options>]" -msgstr "git config [<опції>]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "git config list [<опціÑ-файлу>] [<опціÑ-відображеннÑ>] [--includes]" -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "нерозпізнаний аргумент --type, %s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [<опціÑ-файлу>] [<опціÑ-відображеннÑ>] [--includes] [--all] " +"[--regexp=<регвир>] [--value=<значеннÑ>] [--fixed-value] [--" +"default=<Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ -за-умовчаннÑм>] <назва>" -msgid "only one type at a time" -msgstr "лише один тип за раз" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [<опціÑ-файлу>] [--type=<тип>] [--all] [--value=<значеннÑ>] " +"[--fixed-value] <назва> <значеннÑ>" + +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [<опціÑ-файлу>] [--all] [--value=<значеннÑ>] [--fixed-" +"value] <назва> <значеннÑ>" + +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "git config rename-section [<опціÑ-файлу>] <Ñтара-назва> <нова-назва>" + +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [<опціÑ-файлу>] <назва>" + +msgid "git config edit [<file-option>]" +msgstr "git config edit [<опціÑ-файлу>]" + +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "git config [<опціÑ-файлу>] --get-colorbool <назва> [<stdout-is-tty>]" + +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [<опціÑ-файлу>] [--type=<тип>] [--comment=<допиÑ>] [--all][--" +"value=<значеннÑ>] [--fixed-value] <назва> <значеннÑ>" msgid "Config file location" msgstr "Ð Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ конфігурації" @@ -5129,55 +5185,6 @@ msgstr "blob-id" msgid "read config from given blob object" msgstr "прочитати конфігурацію з наданого blob-обʼєкту" -msgid "Action" -msgstr "ДіÑ" - -msgid "get value: name [value-pattern]" -msgstr "отримати значеннÑ: назва [шаблон-значеннÑ]" - -msgid "get all values: key [value-pattern]" -msgstr "отримати вÑÑ– значеннÑ: ключ [шаблон-значеннÑ]" - -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "отримати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ñ€ÐµÐ³Ð²Ð¸Ñ€Ñƒ: регвир-назви [шаблон-значеннÑ]" - -msgid "get value specific for the URL: section[.var] URL" -msgstr "отримати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ð¾Ñ— URL-адреÑи: розділ[.var] URL-адреÑа" - -msgid "replace all matching variables: name value [value-pattern]" -msgstr "замінити вÑÑ– відповідні змінні: назва Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ [шаблон-значеннÑ]" - -msgid "add a new variable: name value" -msgstr "додати нову змінну: назва значеннÑ" - -msgid "remove a variable: name [value-pattern]" -msgstr "видалити змінну: назва [шаблон-значеннÑ]" - -msgid "remove all matches: name [value-pattern]" -msgstr "видалити вÑÑ– збіги: назва [шаблон-значеннÑ]" - -msgid "rename section: old-name new-name" -msgstr "перейменувати розділ: Ñтара-назва нова-назва" - -msgid "remove a section: name" -msgstr "видалити розділ: назва" - -msgid "list all" -msgstr "показати вÑÑ– змінні" - -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "" -"викориÑтовувати рівніÑть Ñтрок при порівнÑнні значень з \"шаблон-значеннÑм\"" - -msgid "open an editor" -msgstr "відкрити редактор" - -msgid "find the color configured: slot [default]" -msgstr "знайти налаштований колір: Ñлот [за замовчуваннÑм]" - -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "знайти Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð»ÑŒÐ¾Ñ€Ñƒ: slot [stdout-is-tty]" - msgid "Type" msgstr "Тип" @@ -5205,8 +5212,8 @@ msgstr "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÑˆÐ»ÑÑ… (файл або назва директорі msgid "value is an expiry date" msgstr "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ - дата Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії" -msgid "Other" -msgstr "Інше" +msgid "Display options" +msgstr "Опції відображеннÑ" msgid "terminate values with NUL byte" msgstr "завершити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð±Ð°Ð¹Ñ‚Ð¾Ð¼ NUL" @@ -5214,9 +5221,6 @@ msgstr "завершити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð±Ð°Ð¹Ñ‚Ð¾Ð¼ NUL" msgid "show variable names only" msgstr "показувати тільки назви змінних" -msgid "respect include directives on lookup" -msgstr "дотримуватиÑÑŒ директив Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸ пошуку" - msgid "show origin of config (file, standard input, blob, command line)" msgstr "" "показати Ð¿Ð¾Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ— (файл, Ñтандартний ввід, blob, командний " @@ -5227,16 +5231,15 @@ msgstr "" "показати межі дії конфігурації (робоче дерево, локально, глобально, ÑиÑтема, " "команда)" -msgid "value" -msgstr "значеннÑ" +msgid "show config keys in addition to their values" +msgstr "показувати ключі конфігурації на додачу до їхніх значень" -msgid "with --get, use default value when missing entry" -msgstr "" -"з --get викориÑтовувати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм, Ñкщо Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´Ñутній" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "нерозпізнаний аргумент --type, %s" -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "" -"зрозумілий Ð´Ð»Ñ Ð»ÑŽÐ´Ð¸Ð½Ð¸ Ñ€Ñдок ÐºÐ¾Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ñ (# буде додано перед за потребою)" +msgid "only one type at a time" +msgstr "лише один тип за раз" #, c-format msgid "wrong number of arguments, should be %d" @@ -5314,46 +5317,75 @@ msgstr "" "ФÐЙЛ\"\n" "у \"git help worktree\" Ð´Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆ детальної інформації" -msgid "--get-color and variable type are incoherent" -msgstr "--get-color Ñ– тип змінної не узгоджуютьÑÑ" +msgid "Other" +msgstr "Інше" -msgid "only one action at a time" -msgstr "лише одна Ð´Ñ–Ñ Ð·Ð° раз" +msgid "respect include directives on lookup" +msgstr "дотримуватиÑÑŒ директив Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸ пошуку" -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "--name-only заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до --list або --get-regexp" +#, c-format +msgid "unable to read config file '%s'" +msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл конфігурації \"%s\"" -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" +msgid "error processing config file(s)" +msgstr "помилка при обробці файлу(ів) конфігурації" + +msgid "Filter options" +msgstr "Опції фільтрації" + +msgid "return all values for multi-valued config options" +msgstr "повернути вÑÑ– Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð±Ð°Ð³Ð°Ñ‚Ð¾Ð·Ð½Ð°Ñ‡Ð½Ð¸Ñ… параметрів конфігурації" + +msgid "interpret the name as a regular expression" +msgstr "інтерпретувати назву Ñк регулÑрний вираз" + +msgid "show config with values matching the pattern" +msgstr "показати конфіг зі значеннÑми, що відповідають шаблону" + +msgid "use string equality when comparing values to value pattern" msgstr "" -"--show-origin заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до --get, --get-all, --get-regexp та --list" +"викориÑтовувати Ñ€Ñдкову еквівалентніÑть при порівнÑнні з шаблоном значень" -msgid "--default is only applicable to --get" -msgstr "--default заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до --get" +msgid "URL" +msgstr "URL" -msgid "--comment is only applicable to add/set/replace operations" -msgstr "--comment заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до add/set/replace операцій" +msgid "show config matching the given URL" +msgstr "показати конфіг, що відповідає вказаній URL-адреÑÑ–" + +msgid "value" +msgstr "значеннÑ" + +msgid "use default value when missing entry" +msgstr "викориÑтовувати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм, Ñкщо Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´Ñутній" msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ з \"шаблоном-значеннÑ\"" -#, c-format -msgid "unable to read config file '%s'" -msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ файл конфігурації \"%s\"" +msgid "--default= cannot be used with --all or --url=" +msgstr "--default= не можна викориÑтовувати з --all або --url=" -msgid "error processing config file(s)" -msgstr "помилка при обробці файлу(ів) конфігурації" +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "--url= не можна викориÑтовувати з --all, --regexp або --value" -msgid "editing stdin is not supported" -msgstr "Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ stdin не підтримуєтьÑÑ" +msgid "Filter" +msgstr "ФільтраціÑ" -msgid "editing blobs is not supported" -msgstr "Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ blobs не підтримуєтьÑÑ" +msgid "replace multi-valued config option with new value" +msgstr "замінити багатозначний параметр конфігурації новим значеннÑм" -#, c-format -msgid "cannot create configuration file %s" -msgstr "неможливо Ñтворити конфігураційний файл %s" +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "" +"зрозумілий Ð´Ð»Ñ Ð»ÑŽÐ´Ð¸Ð½Ð¸ Ñ€Ñдок ÐºÐ¾Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ñ (# буде додано попереду при " +"необхідноÑті)" + +msgid "add a new line without altering any existing values" +msgstr "додати новий Ñ€Ñдок, не змінюючи жодного з Ñ–Ñнуючих значень" + +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "--fixed-value заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ з --value=<шаблон>" + +msgid "--append cannot be used with --value=<pattern>" +msgstr "--append не можна викориÑтовувати з --value=<шаблон>" #, c-format msgid "" @@ -5367,6 +5399,87 @@ msgstr "" msgid "no such section: %s" msgstr "немає такого розділу: %s" +msgid "editing stdin is not supported" +msgstr "Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ stdin не підтримуєтьÑÑ" + +msgid "editing blobs is not supported" +msgstr "Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ blobs не підтримуєтьÑÑ" + +#, c-format +msgid "cannot create configuration file %s" +msgstr "неможливо Ñтворити конфігураційний файл %s" + +msgid "Action" +msgstr "ДіÑ" + +msgid "get value: name [<value-pattern>]" +msgstr "отримати значеннÑ: назва [шаблон-значеннÑ]" + +msgid "get all values: key [<value-pattern>]" +msgstr "отримати вÑÑ– значеннÑ: ключ [шаблон-значеннÑ]" + +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "отримати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ñ€ÐµÐ³Ð²Ð¸Ñ€Ñƒ: регвир-назви [шаблон-значеннÑ]" + +msgid "get value specific for the URL: section[.var] URL" +msgstr "" +"отримати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ð¾Ñ— URL-адреÑи: розділ[.змінна] URL-адреÑа" + +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "замінити вÑÑ– відповідні змінні: назва Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ [шаблон-значеннÑ]" + +msgid "add a new variable: name value" +msgstr "додати нову змінну: назва значеннÑ" + +msgid "remove a variable: name [<value-pattern>]" +msgstr "видалити змінну: назва [шаблон-значеннÑ]" + +msgid "remove all matches: name [<value-pattern>]" +msgstr "видалити вÑÑ– збіги: назва [шаблон-значеннÑ]" + +msgid "rename section: old-name new-name" +msgstr "перейменувати розділ: Ñтара-назва нова-назва" + +msgid "remove a section: name" +msgstr "видалити розділ: назва" + +msgid "list all" +msgstr "показати вÑÑ– змінні" + +msgid "open an editor" +msgstr "відкрити редактор" + +msgid "find the color configured: slot [<default>]" +msgstr "знайти налаштований колір: Ñлот [<за замовчуваннÑм>]" + +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "знайти Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð»ÑŒÐ¾Ñ€Ñƒ: Ñлот [<stdout-is-tty>]" + +msgid "with --get, use default value when missing entry" +msgstr "" +"з --get викориÑтовувати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм, Ñкщо Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´Ñутній" + +msgid "--get-color and variable type are incoherent" +msgstr "--get-color Ñ– тип змінної не узгоджуютьÑÑ" + +msgid "no action specified" +msgstr "дію не зазначено" + +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "--name-only заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до --list або --get-regexp" + +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "" +"--show-origin заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до --get, --get-all, --get-regexp та --list" + +msgid "--default is only applicable to --get" +msgstr "--default заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до --get" + +msgid "--comment is only applicable to add/set/replace operations" +msgstr "--comment заÑтоÑовуєтьÑÑ Ð»Ð¸ÑˆÐµ до add/set/replace операцій" + msgid "print sizes in human readable format" msgstr "показувати розмір у зручному Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ñ–" @@ -6200,6 +6313,10 @@ msgstr "конфіг" msgid "config key storing a list of repository paths" msgstr "ключ конфігурації, в Ñкому зберігаєтьÑÑ ÑпиÑок шлÑхів до Ñховищ" +msgid "keep going even if command fails in a repository" +msgstr "" +"продовжувати роботу, навіть Ñкщо команда завершилаÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾ в репозиторії" + msgid "missing --config=<config>" msgstr "відÑутній --config=<конфіг>" @@ -7666,8 +7783,11 @@ msgstr "позначити Ñ€Ñд Ñк N-не перекиданнÑ" msgid "max length of output filename" msgstr "макÑимальна довжина назви вихідного файлу" -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "викориÑтати [RFC PATCH] заміÑть [PATCH]" +msgid "rfc" +msgstr "rfc" + +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "додати <rfc> (за замовчуваннÑм \"RFC\") перед \"PATCH\"" msgid "cover-from-description-mode" msgstr "cover-from-description-mode" @@ -7937,11 +8057,12 @@ msgstr "" "deduplicate, --eol" msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<виконавчий-файл>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<виконавчий-" +"файл>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<ключ>]\n" " [--symref] [<Ñховище> [<шаблони>...]]" @@ -7957,8 +8078,11 @@ msgstr "шлÑÑ… до git-upload-pack на віддаленому Ñервері msgid "limit to tags" msgstr "обмежити до тегів" -msgid "limit to heads" -msgstr "обмежити до голів" +msgid "limit to branches" +msgstr "обмежити до гілок" + +msgid "deprecated synonym for --branches" +msgstr "заÑтарілий Ñинонім до --branches" msgid "do not show peeled tags" msgstr "не показувати очищені теги" @@ -10619,6 +10743,22 @@ msgstr "не вказано журнал поÑилань Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð msgid "invalid ref format: %s" msgstr "неприпуÑтимий формат поÑиланнÑ: %s" +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=<формат> [--dry-run]" + +msgid "specify the reference format to convert to" +msgstr "вкажіть формат поÑиланнÑ, в Ñкий потрібно конвертувати" + +msgid "perform a non-destructive dry-run" +msgstr "виконати неруйнівний пробний запуÑк" + +msgid "missing --ref-format=<format>" +msgstr "відÑутній --ref-format=<формат>" + +#, c-format +msgid "repository already uses '%s' format" +msgstr "Ñховище вже викориÑтовує формат \"%s\"" + msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" "mirror=<fetch|push>] <name> <url>" @@ -10907,9 +11047,6 @@ msgstr "* віддалене %s" msgid " Fetch URL: %s" msgstr " URL-адреÑа отриманнÑ: %s" -msgid "(no URL)" -msgstr "(без URL-адреÑи)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -10918,6 +11055,9 @@ msgstr "(без URL-адреÑи)" msgid " Push URL: %s" msgstr " URL-адреÑа надÑиланнÑ: %s" +msgid "(no URL)" +msgstr "(без URL-адреÑи)" + #, c-format msgid " HEAD branch: %s" msgstr " HEAD гілка: %s" @@ -11030,10 +11170,6 @@ msgstr "запитувати URL-адреÑи надÑилань заміÑть msgid "return all URLs" msgstr "повернути вÑÑ– URL-адреÑи" -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "не налаштовано URL-адреÑи Ð´Ð»Ñ Ð²Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð¾Ð³Ð¾ \"%s\"" - msgid "manipulate push URLs" msgstr "маніпулювати URL-адреÑами надÑиланнÑ" @@ -11402,7 +11538,7 @@ msgid "only one pattern can be given with -l" msgstr "тільки один шаблон може бути заданий з -l" msgid "need some commits to replay" -msgstr "потрібні деÑкі комміти Ð´Ð»Ñ Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ" +msgstr "потрібні деÑкі коміти Ð´Ð»Ñ Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ" msgid "--onto and --advance are incompatible" msgstr "--onto та --advance неÑуміÑні" @@ -11468,7 +11604,7 @@ msgid "replaying down to root commit is not supported yet!" msgstr "Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð´Ð¾ кореневого коміту поки що не підтримуєтьÑÑ!" msgid "replaying merge commits is not supported yet!" -msgstr "Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ð¼Ñ–Ñ‚Ñ–Ð² Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ð¾ÐºÐ¸ що не підтримуєтьÑÑ!" +msgstr "Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð² Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ð¾ÐºÐ¸ що не підтримуєтьÑÑ!" msgid "" "git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]" @@ -12047,12 +12183,12 @@ msgstr "Ðевідомий хеш-алгоритм" msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<н>]] [--abbrev[=<н>]] [--tags]\n" -" [--heads] [--] [<шаблон>...]" +" [-s | --hash[=<н>]] [--abbrev[=<н>]] [--branches] [--tags]\n" +" [--] [<шаблон>...]" msgid "" "git show-ref --verify [-q | --quiet] [-d | --dereference]\n" @@ -12075,11 +12211,11 @@ msgstr "поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ðµ Ñ–Ñнує" msgid "failed to look up reference" msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ поÑиланнÑ" -msgid "only show tags (can be combined with heads)" -msgstr "показати тільки теги (можна комбінувати з верхівками)" +msgid "only show tags (can be combined with branches)" +msgstr "показати тільки теги (можна комбінувати з гілками)" -msgid "only show heads (can be combined with tags)" -msgstr "показати тільки верхівки (можна комбінувати з тегами)" +msgid "only show branches (can be combined with tags)" +msgstr "показати тільки гілки (можна комбінувати з тегами)" msgid "check for reference existence without resolving" msgstr "перевірÑти наÑвніÑть поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð±ÐµÐ· розвʼÑзаннÑ" @@ -12714,14 +12850,14 @@ msgstr "" "відмовлено в Ñтворенні/викориÑтанні \"%s\" у git директорії іншого підмодулÑ" #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "не вдалоÑÑ ÐºÐ»Ð¾Ð½ÑƒÐ²Ð°Ñ‚Ð¸ \"%s\" у шлÑÑ… Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ \"%s\"" - -#, c-format msgid "directory not empty: '%s'" msgstr "Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ñ–Ñ Ð½Ðµ порожнÑ: \"%s\"" #, c-format +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "не вдалоÑÑ ÐºÐ»Ð¾Ð½ÑƒÐ²Ð°Ñ‚Ð¸ \"%s\" у шлÑÑ… Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ \"%s\"" + +#, c-format msgid "could not get submodule directory for '%s'" msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ директорію Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð´Ð»Ñ \"%s\"" @@ -13086,14 +13222,16 @@ msgstr "причина оновленнÑ" msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" "git tag [-a | -s | -u <ідентифікатор-ключа>] [-f] [-m <допиÑ> | -F <файл>] [-" "e]\n" +" [(--trailer <токен>[(=|:)<значеннÑ>])...]\n" " <назва-тегу> [<коміт> | <об’єкт>]" msgid "git tag -d <tagname>..." -msgstr "git tag -d <назва-тега>..." +msgstr "git tag -d <назва-тегу>..." msgid "" "git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n" @@ -13948,9 +14086,6 @@ msgstr "нерозпізнаний заголовок: %s%s (%d)" msgid "Repository lacks these prerequisite commits:" msgstr "У Ñховищі не виÑтачає обовʼÑзкових комітів:" -msgid "need a repository to verify a bundle" -msgstr "потрібне Ñховище Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ пакунка" - msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -14353,6 +14488,9 @@ msgstr "Отримати те, що надÑилаєтьÑÑ Ð´Ð¾ Ñховища msgid "Manage reflog information" msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ”ÑŽ журналу поÑилань" +msgid "Low-level access to refs" +msgstr "Ðизькорівневий доÑтуп до поÑилань" + msgid "Manage set of tracked repositories" msgstr "Керувати набором відÑтежуваних Ñховищ" @@ -14364,8 +14502,8 @@ msgstr "Створити, показати, видалити поÑÐ¸Ð»Ð°Ð½Ð½Ñ msgid "EXPERIMENTAL: Replay commits on a new base, works with bare repos too" msgstr "" -"ЕКСПЕРИМЕÐТÐЛЬÐО: Ð’Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ð¼Ñ–Ñ‚Ñ–Ð² на новій базі також працює з " -"порожніми Ñховищами" +"ЕКСПЕРИМЕÐТÐЛЬÐО: Ð’Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð² на новій базі також працює з порожніми " +"Ñховищами" msgid "Generates a summary of pending changes" msgstr "Створює підÑумок змін Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð»Ñду" @@ -14440,7 +14578,7 @@ msgid "Initialize, update or inspect submodules" msgstr "Ініціалізувати, оновити або перевірити підмодулі" msgid "Bidirectional operation between a Subversion repository and Git" -msgstr "Двонаправлена Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð¼Ñ–Ð¶ Subversion Ñховищем та Git" +msgstr "ДвонапрÑмлена Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð¼Ñ–Ð¶ Subversion Ñховищем та Git" msgid "Switch branches" msgstr "Переключити гілки" @@ -14656,6 +14794,14 @@ msgstr "необхідний шматок OID lookup коміт-графа віРmsgid "commit-graph required commit data chunk missing or corrupted" msgstr "необхідний шматок commit data коміт-графа відÑутній або пошкоджений" +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "" +"Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ñ„Ñ–Ð»ÑŒÑ‚Ñ€Ñ–Ð² Блума Ð´Ð»Ñ ÑˆÐ°Ñ€Ñƒ коміт-графа \"%s\" через неÑуміÑніÑть " +"параметрів" + msgid "commit-graph has no base graphs chunk" msgstr "коміт-граф не має шматка базових графів" @@ -14780,6 +14926,14 @@ msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ ÐºÐ¾Ð¼Ñ–Ñ‚-графа" msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled" msgstr "Ñпроба запиÑати коміт-граф, але \"core.commitGraph\" відключено" +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " +"(%d) is not supported" +msgstr "" +"Ñпроба запиÑати коміт-граф, але \"commitGraph.changedPathsVersion\" (%d) не " +"підтримуєтьÑÑ" + msgid "too many commits to write graph" msgstr "занадто багато комітів, щоб запиÑати граф" @@ -16635,17 +16789,21 @@ msgstr "" msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v | --version] [-h | --help] [-C <шлÑÑ…>] [-c <назва>=<значеннÑ>]\n" " [--exec-path[=<шлÑÑ…>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<шлÑÑ…>] [--work-tree=<шлÑÑ…>] [--namespace=<назва>]\n" -"[--config-env=<назва>=<змінна-оточеннÑ>] <команда> [<аргументи>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<шлÑÑ…>]\n" +" [--work-tree=<шлÑÑ…>] [--namespace=<назва>] [--config-" +"env=<шлÑÑ…>=<змінна-оточеннÑ>]\n" +" <команда> [<аргументи>]" msgid "" "'git help -a' and 'git help -g' list available subcommands and some\n" @@ -16988,13 +17146,13 @@ msgstr "" "Ви можете вимкнути це Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð·Ð° допомогою \"git config advice." "ignoredHook false\"." +msgid "not a git repository" +msgstr "не Ñ” git Ñховищем" + #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "аргумент до --packfile має бути коректним хешем (отримано \"%s\")" -msgid "not a git repository" -msgstr "не Ñ” git Ñховищем" - #, c-format msgid "negative value for http.postBuffer; defaulting to %d" msgstr "" @@ -17006,6 +17164,9 @@ msgstr "Контроль Ð´ÐµÐ»ÐµÐ³ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ підтримуєтьÑÑ msgid "Public key pinning not supported with cURL < 7.39.0" msgstr "Ð—Ð°ÐºÑ€Ñ–Ð¿Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸Ñ… ключів не підтримуєтьÑÑ Ð· cURL < 7.39.0" +msgid "Unknown value for http.proactiveauth" +msgstr "Ðевідоме Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ http.proactiveauth" + msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "CURLSSLOPT_NO_REVOKE не підтримуєтьÑÑ Ð· cURL < 7.44.0" @@ -17023,6 +17184,12 @@ msgstr "" msgid "Could not set SSL backend to '%s': already set" msgstr "Ðе вдалоÑÑ Ð²Ñтановити SSL обробник в \"%s\": вже вÑтановлено" +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "відмова від Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ cookies з http.cookiefile \"-\"" + +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ http.savecookies Ð´Ð»Ñ Ð¿Ð¾Ñ€Ð¾Ð¶Ð½ÑŒÐ¾Ð³Ð¾ http.cookiefile" + #, c-format msgid "" "unable to update url base from redirection:\n" @@ -17198,8 +17365,8 @@ msgid "Failed to merge submodule %s (commits not present)" msgstr "Ðе вдалоÑÑ Ð·Ð»Ð¸Ñ‚Ð¸ підмодуль %s (відÑутні коміти)" #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" -msgstr "Ðе вдалоÑÑ Ð¾Ð±Ê¼Ñ”Ð´Ð½Ð°Ñ‚Ð¸ підмодуль %s (Ñховище пошкоджено)" +msgid "error: failed to merge submodule %s (repository corrupt)" +msgstr "помилка: не вдалоÑÑ Ð¾Ð±Ê¼Ñ”Ð´Ð½Ð°Ñ‚Ð¸ підмодуль %s (Ñховище пошкоджено)" #, c-format msgid "Failed to merge submodule %s (commits don't follow merge-base)" @@ -17226,12 +17393,13 @@ msgstr "" "Ðе вдалоÑÑ Ð·Ð»Ð¸Ñ‚Ð¸ підмодуль %s, але Ñ–Ñнує кілька можливих варіантів злиттÑ:\n" "%s" -msgid "failed to execute internal merge" -msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ внутрішнє злиттÑ" +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "помилка: не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ внутрішнє Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ %s" #, c-format -msgid "unable to add %s to database" -msgstr "не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ %s до бази даних" +msgid "error: unable to add %s to database" +msgstr "помилка: не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ %s до бази даних" #, c-format msgid "Auto-merging %s" @@ -17328,12 +17496,12 @@ msgstr "" "в %s." #, c-format -msgid "cannot read object %s" -msgstr "неможливо прочитати обʼєкт %s" +msgid "error: cannot read object %s" +msgstr "помилка: неможливо прочитати обʼєкт %s" #, c-format -msgid "object %s is not a blob" -msgstr "обʼєкт %s не Ñ” blob" +msgid "error: object %s is not a blob" +msgstr "помилка: обʼєкт %s не Ñ” blob" #, c-format msgid "" @@ -17470,6 +17638,10 @@ msgid "do not know what to do with %06o %s '%s'" msgstr "не знаю, що робити з %06o %s \"%s\"" #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "Ðе вдалоÑÑ Ð¾Ð±Ê¼Ñ”Ð´Ð½Ð°Ñ‚Ð¸ підмодуль %s (Ñховище пошкоджено)" + +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "ÐŸÐµÑ€ÐµÐ¼Ð¾Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ %s вперед до наÑтупного коміту:" @@ -17508,6 +17680,13 @@ msgstr "" msgid "Failed to merge submodule %s (multiple merges found)" msgstr "Ðе вдалоÑÑ Ð·Ð»Ð¸Ñ‚Ð¸ підмодуль %s (знайдено більше одного злиттÑ)" +msgid "failed to execute internal merge" +msgstr "не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ внутрішнє злиттÑ" + +#, c-format +msgid "unable to add %s to database" +msgstr "не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ %s до бази даних" + #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "" @@ -17610,6 +17789,14 @@ msgstr "" "КОÐФЛІКТ (перейменовано/перейменовано): перейменовано директорію %s->%s в " "%s. Перейменовано директорію %s->%s в %s" +#, c-format +msgid "cannot read object %s" +msgstr "неможливо прочитати обʼєкт %s" + +#, c-format +msgid "object %s is not a blob" +msgstr "обʼєкт %s не Ñ” blob" + msgid "modify" msgstr "змінити" @@ -17693,10 +17880,6 @@ msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ Ñ€Ñдок: %s" msgid "malformed line: %s" msgstr "невірно Ñформований Ñ€Ñдок: %s" -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "" -"Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ñнуючого multi-pack-index; невідповідніÑть контрольних Ñум" - msgid "could not load pack" msgstr "не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ пакунок" @@ -17704,6 +17887,10 @@ msgstr "не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ пакунок" msgid "could not open index for %s" msgstr "не вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ Ñ–Ð½Ð´ÐµÐºÑ Ð´Ð»Ñ %s" +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "" +"Ñ–Ð³Ð½Ð¾Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ñнуючого multi-pack-index; невідповідніÑть контрольних Ñум" + msgid "Adding packfiles to multi-pack-index" msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ð°ÐºÑƒÐ½ÐºÑ–Ð² до multi-pack-index" @@ -18317,6 +18504,17 @@ msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ обʼєкт: %s" msgid "hash mismatch %s" msgstr "невідповідніÑть хешу %s" +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "дубльований елемент під Ñ‡Ð°Ñ Ð·Ð°Ð¿Ð¸Ñу bitmap індекÑу: \"%s\"" + +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "Ñпроба зберегти невибраний коміт: \"%s\"" + +msgid "too many pseudo-merges" +msgstr "занадто багато пÑевдозлиттÑ" + msgid "trying to write commit not in index" msgstr "Ñпроба запиÑати коміт, Ñкого немає в індекÑÑ–" @@ -18339,8 +18537,21 @@ msgstr "" msgid "corrupted bitmap index file (too short to fit lookup table)" msgstr "" +"пошкоджений файл bitmap індекÑу (занадто малий, щоб вміÑтити таблицю пошуку)" + +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "" +"пошкоджений файл bitmap індекÑу (занадто малий, щоб вміÑтити заголовок " +"таблиці пÑевдозлиттÑ" + +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "" "пошкоджений файл bitmap індекÑу (занадто короткий, щоб вміÑтити таблицю " -"пошуку)" +"пÑевдозлиттÑ)" + +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "пошкоджений файл bitmap індекÑу, Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ Ð¿ÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð½Ð°Ð´Ñ‚Ð¾ мала" #, c-format msgid "duplicate entry in bitmap index: '%s'" @@ -18437,6 +18648,10 @@ msgid "mismatch in bitmap results" msgstr "розбіжніÑть в bitmap результатах" #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "Ñ–Ð½Ð´ÐµÐºÑ Ð¿ÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ð¾Ð·Ð° діапазоном (%<PRIu32> >= %<PRIuMAX>)" + +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ \"%s\" у пакунку \"%s\" зі зміщеннÑм %<PRIuMAX>" @@ -18808,6 +19023,9 @@ msgstr "не вдалоÑÑ Ñтворити потоковий lstat: %s" msgid "unable to parse --pretty format" msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ñ–Ð±Ñ€Ð°Ñ‚Ð¸ --pretty формат" +msgid "lazy fetching disabled; some objects may not be available" +msgstr "лінива вибірка вимкнена; деÑкі обʼєкти можуть бути недоÑтупні" + msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "promisor-remote: не вдалоÑÑ Ñ€Ð¾Ð·Ð³Ð°Ð»ÑƒÐ¶Ð¸Ñ‚Ð¸ Ð¿Ñ–Ð´Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ" @@ -18831,6 +19049,65 @@ msgstr "object-info: очікувавÑÑ flush піÑÐ»Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ñ–Ð²" msgid "Removing duplicate objects" msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð´ÑƒÐ±Ð»Ñ–ÐºÐ°Ñ‚Ñ–Ð² обʼєктів" +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "не вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ регвир пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ %s: \"%s\"" + +#, c-format +msgid "%s must be non-negative, using default" +msgstr "" +"%s має бути невідʼємним значеннÑм, викориÑтано Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм" + +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "" +"%s має бути в діапазоні від 0 до 1, викориÑтано Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм" + +#, c-format +msgid "%s must be positive, using default" +msgstr "%s має бути додатнім, викориÑтано Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм" + +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "у групі пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ \"%s\" відÑутній потрібний шаблон" + +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "група пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ \"%s\" має неÑтабільний поріг перед Ñтабільним" + +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "" +"регвир пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð· конфігурації має забагато груп Ð·Ð°Ñ…Ð¾Ð¿Ð»ÐµÐ½Ð½Ñ " +"(max=%<PRIuMAX>" + +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð·Ð° межами (%<PRIuMAX> >= %<PRIuMAX>) при розширеному пÑевдозлитті" + +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "" +"Ð·Ð°Ð¿Ð¸Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ð¾Ð³Ð¾ пÑÐµÐ²Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð½Ð°Ð´Ñ‚Ð¾ малий (%<PRIuMAX> >= %<PRIuMAX>)" + +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ пÑÐµÐ²Ð¾Ð´Ð¾Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ð° %s зі зміщеннÑм %<PRIuMAX>" + +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "розширене пÑевдозлиттÑ, пошук за межами (%<PRIu32> >= %<PRIu32>)" + +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð·Ð° межами: (%<PRIuMAX> >= %<PRIuMAX>)" + +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "не вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ таблицю розширеного пÑевдо-Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ %s" + msgid "could not start `log`" msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ð¾Ñ‡Ð°Ñ‚Ð¸ \"log\"" @@ -19434,11 +19711,18 @@ msgstr "лог Ð´Ð»Ñ Ð¿Ð¾ÑÐ¸Ð»Ð°Ð½Ð½Ñ %s неÑподівано завершРmsgid "log for %s is empty" msgstr "лог Ð´Ð»Ñ %s порожній" +msgid "refusing to force and skip creation of reflog" +msgstr "відмовлено в примуÑовому пропуÑку ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ€ÐµÑ„Ð»Ð¾Ð³Ñƒ" + #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "відмовлено в оновленні поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð· невірною назвою \"%s\"" #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "відмовлено в оновленні пÑевдопоÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\"" + +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "update_ref завершивÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾ Ð´Ð»Ñ Ð¿Ð¾ÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\": %s" @@ -19469,6 +19753,25 @@ msgid "could not delete references: %s" msgstr "не вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ поÑиланнÑ: %s" #, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "Закінчено пробну міграцію поÑилань, результат можна знайти в \"%s\"\n" + +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "не вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ тимчаÑову директорію міграції \"%s\"" + +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "перенеÑені поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¼Ð¾Ð¶Ð½Ð° знайти в \"%s\"" + +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "" +"неможливо заблокувати поÑÐ¸Ð»Ð°Ð½Ð½Ñ \"%s\": очікувалоÑÑŒ Ñимвольне поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð· " +"призначеннÑм \"%s\", але це звичайне поÑиланнÑ" + +#, c-format msgid "refname is dangerous: %s" msgstr "refname Ñ” небезпечним: %s" @@ -20446,7 +20749,7 @@ msgid "" " git rebase --continue\n" msgstr "" "ви маєте індекÑовані зміни у вашому робочому дереві\n" -"Якщо ці зміни мають бути ÑтиÑнуті у попередній коміт, запуÑтіть:\n" +"Якщо ці зміни мають бути зчавлені у попередній коміт, запуÑтіть:\n" "\n" " git commit --amend %s\n" "\n" @@ -20657,6 +20960,49 @@ msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s" msgstr "update-ref потребує повної назви поÑиланнÑ, наприклад, refs/heads/%s" #, c-format +msgid "'%s' does not accept merge commits" +msgstr "\"%s\" не приймає коміти злиттÑ" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"\"pick\" не приймає коміти злиттÑ. Якщо ви хочете\n" +"відтворити злиттÑ, викориÑтовуйте \"merge -C\" Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ð°." + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"\"reword\" не приймає коміти злиттÑ. Якщо ви хочете\n" +"відтворити Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° змінити текÑÑ‚ допиÑу, викориÑтовуйте\n" +"\"merge -c\" Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ð°." + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"\"edit\" не приймає коміти злиттÑ. Якщо ви хочете\n" +"відтворити злиттÑ, викориÑтовуйте \"merge -C\" Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ð°, а потім\n" +"\"break\" Ð´Ð»Ñ Ð¿Ð¾Ð²ÐµÑ€Ð½ÐµÐ½Ð½Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ, щоб ви могли\n" +"виконати \"git commit --amend && git rebase --continue\"." + +msgid "cannot squash merge commit into another commit" +msgstr "неможливо зчавити коміт Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð² інший коміт" + +#, c-format msgid "invalid command '%.*s'" msgstr "неприпуÑтима команда \"%.*s\"" @@ -20774,9 +21120,8 @@ msgstr "" msgid "cannot read HEAD" msgstr "неможливо прочитати HEAD" -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "не вдалоÑÑ Ñкопіювати \"%s\" в \"%s\"" +msgid "could not write commit message file" +msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати файл допиÑу до коміта" #, c-format msgid "" @@ -21180,6 +21525,18 @@ msgstr "неможливо повернутиÑÑ Ð´Ð¾ поточної робо msgid "failed to stat '%*s%s%s'" msgstr "не вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати \"%*s%s%s\"" +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"виÑвлено Ñумнівне право влаÑноÑті у Ñховищі за адреÑою \"%s\"\n" +"%sЩоб додати винÑток Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— директорії, виконайте:\n" +"\n" +"\tgit config --global --add safe.directory %s" + msgid "Unable to read current working directory" msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ поточну робочу директорію" @@ -21202,18 +21559,6 @@ msgstr "" "вÑтановлено)." #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"виÑвлено Ñумнівне право влаÑноÑті у Ñховищі за адреÑою \"%s\"\n" -"%sЩоб додати винÑток Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— директорії, виконайте:\n" -"\n" -"\tgit config --global --add safe.directory %s" - -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" msgstr "" "неможливо викориÑтати порожнє Ñховище \"%s\" (safe.bareRepository " @@ -21518,7 +21863,17 @@ msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ підмодуль \"%s\"." #, c-format msgid "submodule git dir '%s' is inside git dir '%.*s'" -msgstr "підмодуль git dir \"%s\" знаходитьÑÑ Ð²Ñередині git директорії \"%.*s\"" +msgstr "підмодуль git dir \"%s\" знаходитьÑÑ Ð²Ñередині git директорії \"%*s\"" + +#, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "" +"очікувалоÑÑŒ, що \"%.*s\" у шлÑху Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ \"%s\" не буде Ñимвольним " +"поÑиланнÑм" + +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "очікувалоÑÑŒ, що шлÑÑ… Ð¿Ñ–Ð´Ð¼Ð¾Ð´ÑƒÐ»Ñ \"%s\" не буде Ñимвольним поÑиланнÑм" #, c-format msgid "" @@ -21561,10 +21916,6 @@ msgstr "" "немає налаштованого віддаленого Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ URI пакунків з " "нього" -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "віддалений \"%s\" не має налаштованої URL-адреÑи" - msgid "could not get the bundle-uri list" msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ ÑпиÑок bundle-uri" @@ -23058,24 +23409,24 @@ msgid "Failed to send %s\n" msgstr "Ðе вдалоÑÑ Ð½Ð°Ð´Ñ–Ñлати %s\n" #, perl-format -msgid "Dry-Sent %s\n" -msgstr "Пробно відправлено %s\n" +msgid "Dry-Sent %s" +msgstr "Пробно відправлено %s" #, perl-format -msgid "Sent %s\n" -msgstr "Відправлено %s\n" +msgid "Sent %s" +msgstr "Відправлено %s" -msgid "Dry-OK. Log says:\n" -msgstr "Пробно OK. Журнал каже:\n" +msgid "Dry-OK. Log says:" +msgstr "Пробно OK. Журнал каже:" -msgid "OK. Log says:\n" -msgstr "ОК. Журнал каже:\n" +msgid "OK. Log says:" +msgstr "ОК. Журнал каже:" msgid "Result: " msgstr "Результат: " -msgid "Result: OK\n" -msgstr "Результат: OK\n" +msgid "Result: OK" +msgstr "Результат: OK" #, perl-format msgid "can't open file %s" @@ -2,19 +2,72 @@ # Bản dịch tiếng Việt dà nh cho GIT-CORE. # This file is distributed under the same license as the git-core package. # https://raw.githubusercontent.com/git-l10n/git-po/pot/main/po/git.pot +# --- # Copyright (C) 2012-2022, Translation Project, Vietnamese Team <http://translationproject.org/team/vi.html> # Copyright (C) 2024, VÅ© Tiến Hưng <newcomerminecraft@gmail.com> # Nguyá»…n Thái Ngá»c Duy <pclouds@gmail.com>, 2012. # Äoà n Trần Công Danh <congdanhqx@gmail.com>, 2020. # Trần Ngá»c Quân <vnwildman@gmail.com>, 2012-2022. # VÅ© Tiến Hưng <newcomerminecraft@gmail.com>, 2024. +# --- +# BẢNG THUẬT NGá»® / TERMINOLOGY +# Updated: 2024-07-26, git 2.46 # -msgid "" -msgstr "" -"Project-Id-Version: git 2.45\n" +# Ghi chú: +# - Bảng thuáºt ngữ nà y chưa hoà n thiện. +# - Tuỳ và o ngữ cảnh, bản dịch có thể thay đổi cho phù hợp. +# +# CÃCH VIẾT TẮT +# n. = danh từ +# v. = động từ +# a. = tÃnh từ +# +# +------------------------------------------------------------------+ +# | Thuáºt ngữ / Term | Bản dịch / Translation | +# +------------------------------------------------------------------+ +# | file | táºp tin | +# | folder | thư mục | +# | path | đưá»ng dẫn | +# | error | lá»—i | +# | fatal / fatal error | lá»—i nghiêm trá»ng | +# | warning | cảnh báo | +# | (v.) commit | chuyển giao | +# | (n.) commit | lần chuyển giao | +# | (n.) branch | nhánh | +# | (v.) branch | tạo nhánh | +# | (n.) log | nháºt ký | +# | (v.) log | ghi lại | +# | (n.) ref/refs | tham chiếu | +# | hunk | khúc | +# | index | chỉ mục | +# | (n.) stage | vùng chá» | +# | (v.) stage <...> | đưa <...> và o vùng chá» | +# | (v.) unstage <...> | bá» <...> ra khá»i vùng chá» | +# | revert | hoà n nguyên | +# | add | thêm | +# | restore | phục hồi | +# | (n./v.) change | thay đổi | +# | (v.) update | cáºp nháºt | +# | (v.) track | theo dõi | +# | (v.) untrack | bá» theo dõi | +# | (a.) tracked | được theo dõi | +# | (a.) untracked | không được theo dõi | +# | (v.) parse | hiểu cú pháp | +# | (n.) output | đầu ra, kết quả | +# | (v.) output | in ra, xuất ra | +# | (v.) merge | hoà trá»™n | +# | (v.) rebase | cải tổ | +# | (v.) squash | squash | +# | (v.) amend | tu bổ | +# | | | +# | ... TODO ... | | +# +------------------------------------------------------------------+ +msgid "" +msgstr "" +"Project-Id-Version: git 2.46\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-25 18:57+0000\n" -"PO-Revision-Date: 2024-04-28 14:01+0700\n" +"POT-Creation-Date: 2024-07-21 00:11+0700\n" +"PO-Revision-Date: 2024-07-26 11:31+0700\n" "Last-Translator: VÅ© Tiến Hưng <newcomerminecraft@gmail.com>\n" "Language-Team: Vietnamese <https://github.com/Nekosha/git-po>\n" "Language: vi\n" @@ -44,7 +97,7 @@ msgstr "Cáºp nháºt" #, c-format msgid "could not stage '%s'" -msgstr "không thể đưa '%s' lên bệ phóng" +msgstr "không thể đưa '%s' và o vùng chá»" msgid "could not write index" msgstr "không thể ghi chỉ mục" @@ -113,7 +166,7 @@ msgstr "" msgid "revert staged set of changes back to the HEAD version" msgstr "" -"hoà n nguyên lại táºp hợp các thay đổi đã được đưa lên bệ phóng trở lại phiên " +"hoà n nguyên lại táºp hợp các thay đổi đã được đưa và o vùng chá» trở lại phiên " "bản HEAD" msgid "pick hunks and update selectively" @@ -125,7 +178,7 @@ msgstr "xem khác biệt giữa HEAD và chỉ mục" msgid "add contents of untracked files to the staged set of changes" msgstr "" "thêm ná»™i dung cá»§a các táºp tin chưa được theo dõi và o táºp hợp các thay đổi đã " -"được đưa lên bệ phóng" +"được đưa và o vùng chá»" msgid "Prompt help:" msgstr "Trợ giúp vá» nhắc:" @@ -164,10 +217,10 @@ msgid "What now" msgstr "Giá» thì sao" msgid "staged" -msgstr "đã đưa lên bệ phóng" +msgstr "đã đưa và o vùng chá»" msgid "unstaged" -msgstr "chưa đưa lên bệ phóng" +msgstr "chưa đưa và o vùng chá»" msgid "path" msgstr "đưá»ng-dẫn" @@ -181,26 +234,26 @@ msgstr "Tạm biệt.\n" #, c-format msgid "Stage mode change [y,n,q,a,d%s,?]? " -msgstr "ÄÆ°a lên bệ phóng thay đổi chế độ [y,n,q,a,d%s,?]? " +msgstr "ÄÆ°a và o vùng chá» thay đổi chế độ [y,n,q,a,d%s,?]? " #, c-format msgid "Stage deletion [y,n,q,a,d%s,?]? " -msgstr "ÄÆ°a lên bệ phóng thao tác xoá [y,n,q,a,d%s,?]? " +msgstr "ÄÆ°a và o vùng chá» thao tác xoá [y,n,q,a,d%s,?]? " #, c-format msgid "Stage addition [y,n,q,a,d%s,?]? " -msgstr "ÄÆ°a lên bệ phóng thao tác thêm [y,n,q,a,d%s,?]? " +msgstr "ÄÆ°a và o vùng chá» thao tác thêm [y,n,q,a,d%s,?]? " #, c-format msgid "Stage this hunk [y,n,q,a,d%s,?]? " -msgstr "ÄÆ°a lên bệ phóng khúc nà y [y,n,q,a,d%s,?]? " +msgstr "ÄÆ°a và o vùng chá» khúc nà y [y,n,q,a,d%s,?]? " msgid "" "If the patch applies cleanly, the edited hunk will immediately be marked for " "staging." msgstr "" "Nếu bản vá được áp dụng hoà n toà n, khúc đã sá»a sẽ ngay láºp tức được đánh dấu " -"để chuyển lên bệ phóng." +"để chuyển và o vùng chá»." msgid "" "y - stage this hunk\n" @@ -209,11 +262,11 @@ msgid "" "a - stage this hunk and all later hunks in the file\n" "d - do not stage this hunk or any of the later hunks in the file\n" msgstr "" -"y - đưa lên bệ phóng khúc nà y\n" -"n - đừng đưa lên bệ phóng khúc nà y\n" -"q - thoát; đừng đưa lên bệ phóng khúc nà y hay bất kỳ cái nà o còn lại\n" -"a - đưa lên bệ phóng khúc nà y và tất cả các khúc sau nà y trong táºp tin\n" -"d - đừng đưa lên bệ phóng khúc nà y hay bất kỳ cái nà o còn lại trong táºp tin\n" +"y - đưa và o vùng chá» khúc nà y\n" +"n - đừng đưa và o vùng chá» khúc nà y\n" +"q - thoát; đừng đưa và o vùng chá» khúc nà y hay bất kỳ cái nà o còn lại\n" +"a - đưa và o vùng chá» khúc nà y và tất cả các khúc sau nà y trong táºp tin\n" +"d - đừng đưa và o vùng chá» khúc nà y hay bất kỳ cái nà o còn lại trong táºp tin\n" #, c-format msgid "Stash mode change [y,n,q,a,d%s,?]? " @@ -253,26 +306,26 @@ msgstr "" #, c-format msgid "Unstage mode change [y,n,q,a,d%s,?]? " -msgstr "Bá» ra khá»i bệ phóng thay đổi chế độ [y,n,q,a,d%s,?]? " +msgstr "Bá» ra khá»i vùng chá» thay đổi chế độ [y,n,q,a,d%s,?]? " #, c-format msgid "Unstage deletion [y,n,q,a,d%s,?]? " -msgstr "Bá» ra khá»i bệ phóng thao tác xoá [y,n,q,a,d%s,?]? " +msgstr "Bá» ra khá»i vùng chá» thao tác xoá [y,n,q,a,d%s,?]? " #, c-format msgid "Unstage addition [y,n,q,a,d%s,?]? " -msgstr "Bá» ra khá»i bệ phóng thao tác thêm [y,n,q,a,d%s,?]? " +msgstr "Bá» ra khá»i vùng chá» thao tác thêm [y,n,q,a,d%s,?]? " #, c-format msgid "Unstage this hunk [y,n,q,a,d%s,?]? " -msgstr "Bá» ra khá»i bệ phóng khúc nà y [y,n,q,a,d%s,?]? " +msgstr "Bá» ra khá»i vùng chá» khúc nà y [y,n,q,a,d%s,?]? " msgid "" "If the patch applies cleanly, the edited hunk will immediately be marked for " "unstaging." msgstr "" "Nếu bản vá được áp dụng hoà n toà n, khúc đã sá»a sẽ ngay láºp tức được đánh dấu " -"để bá» ra khá»i bệ phóng." +"để bá» ra khá»i vùng chá»." msgid "" "y - unstage this hunk\n" @@ -281,11 +334,11 @@ msgid "" "a - unstage this hunk and all later hunks in the file\n" "d - do not unstage this hunk or any of the later hunks in the file\n" msgstr "" -"y - đưa ra khá»i bệ phóng khúc nà y\n" -"n - đừng đưa ra khá»i bệ phóng khúc nà y\n" -"q - thoát; đừng đưa ra khá»i bệ phóng khúc nà y hay bất kỳ cái nà o còn lại\n" -"a - đưa ra khá»i bệ phóng khúc nà y và tất cả các khúc sau nà y trong táºp tin\n" -"d - đừng đưa ra khá»i bệ phóng khúc nà y hay bất kỳ cái nà o còn lại trong táºp " +"y - đưa ra khá»i vùng chá» khúc nà y\n" +"n - đừng đưa ra khá»i vùng chá» khúc nà y\n" +"q - thoát; đừng đưa ra khá»i vùng chá» khúc nà y hay bất kỳ cái nà o còn lại\n" +"a - đưa ra khá»i vùng chá» khúc nà y và tất cả các khúc sau nà y trong táºp tin\n" +"d - đừng đưa ra khá»i vùng chá» khúc nà y hay bất kỳ cái nà o còn lại trong táºp " "tin\n" #, c-format @@ -566,6 +619,10 @@ msgstr "" "p - in ra khúc hiện hà nh\n" "? - hiển thị trợ giúp\n" +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "Cần má»™t ký tá»±, nhưng lại có '%s'" + msgid "No previous hunk" msgstr "Không có khúc kế trước" @@ -613,9 +670,19 @@ msgstr "Chia nhá» thà nh %d khúc." msgid "Sorry, cannot edit this hunk" msgstr "Không thể sá»a khúc nà y" +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "không hiểu câu lệnh: '%s' ('?' để hiển thị trợ giúp)" + msgid "'git apply' failed" msgstr "'git apply' gặp lá»—i" +msgid "No changes." +msgstr "Không có thay đổi nà o." + +msgid "Only binary files changed." +msgstr "Chỉ có các táºp tin nhị phân thay đổi." + #, c-format msgid "" "\n" @@ -1462,6 +1529,9 @@ msgstr "bá» qua táºp tin gitattributes quá lá»›n '%s'" msgid "ignoring overly large gitattributes blob '%s'" msgstr "bá» qua blob gitattributes quá lá»›n '%s'" +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "không thể dùng --attr-source hoặc GIT_ATTR_SOURCE mà không có kho chứa" + msgid "bad --attr-source or GIT_ATTR_SOURCE" msgstr "--attr-source hoặc GIT_ATTR_SOURCE sai" @@ -1772,14 +1842,7 @@ msgid "cannot chmod %cx '%s'" msgstr "không thể chmod %cx '%s'" msgid "Unstaged changes after refreshing the index:" -msgstr "ÄÆ°a ra khá»i bệ phóng các thay đổi sau khi là m má»›i lại chỉ mục:" - -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"mục cà i đặt add.interactive.useBuiltin đã không còn!\n" -"Xem mục tin cá»§a nó trong 'git help config' để biết chi tiết." +msgstr "ÄÆ°a ra khá»i vùng chá» các thay đổi sau khi là m má»›i lại chỉ mục:" msgid "could not read the index" msgstr "Không thể Ä‘á»c chỉ mục" @@ -2065,8 +2128,8 @@ msgstr "Thân cá»§a lần chuyển giao là :" #, c-format msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: " msgstr "" -"Ãp dụng? đồng ý [y]/khô[n]g/chỉnh sá»a [e]/hiển thị miếng [v]á/chấp nháºn tất " -"cả [a]: " +"Ãp dụng? đồng ý [y]/không [n]/chỉnh sá»a [e]/hiển thị bản vá [v]/chấp nháºn " +"tất cả [a]: " msgid "unable to write index file" msgstr "không thể ghi táºp tin chỉ mục" @@ -2110,9 +2173,8 @@ msgid "" "already introduced the same changes; you might want to skip this patch." msgstr "" "Không có thay đổi nà o - bạn đã quên sá» dụng lệnh 'git add' à ?\n" -"Nếu ở đây không có gì còn lại stage, tình cá» là có má»™t số thứ khác\n" -"đã sẵn được đưa và o vá»›i cùng ná»™i dung thay đổi; bạn có lẽ muốn bá» qua miếng " -"vá nà y." +"Nếu ở đây không còn gì để đưa và o vùng chá», có lẽ má»™t số ngưá»i khác\n" +"đã thêm các thay đổi trong nà y rồi; bạn có lẽ muốn bá» qua bản vá nà y." msgid "" "You still have unmerged paths in your index.\n" @@ -2121,8 +2183,8 @@ msgid "" "You might run `git rm` on a file to accept \"deleted by them\" for it." msgstr "" "Bạn vẫn có những đưá»ng dẫn chưa hòa trá»™n trong chỉ mục cá»§a bạn.\n" -"Bạn nên 'git add' từng táºp tin vá»›i các xung đột đã được giải quyết để đánh " -"dấu chúng là thế.\n" +"Bạn nên 'git add' những táºp tin đã giải quyết xung đột để đánh dấu chúng là " +"đã xong.\n" "Bạn có lẽ muốn chạy 'git rm' trên má»™t táºp tin để chấp nháºn \"được xóa bởi " "há»\" cho nó." @@ -2222,11 +2284,14 @@ msgstr "huá»· thao tác vá nhưng vẫn giữ HEAD nÆ¡i nó chỉ đến" msgid "show the patch being applied" msgstr "hiển thị bản vá đã được áp dụng rồi" +msgid "try to apply current patch again" +msgstr "thỠáp dụng bản vá hiện hà nh thêm lần nữa" + msgid "record the empty patch as an empty commit" msgstr "ghi lại bản vá trống rá»—ng như là má»™t lần chuyển giao trống" msgid "lie about committer date" -msgstr "nói dối vá» ngà y chuyển giao" +msgstr "là m giả ngà y chuyển giao" msgid "use current timestamp for author date" msgstr "dùng dấu thá»i gian hiện tại cho ngà y tác giả" @@ -2277,9 +2342,6 @@ msgstr "git apply [<các tùy chá»n>] [<miếng-vá>...]" msgid "could not redirect output" msgstr "không thể chuyển hướng đầu ra" -msgid "git archive: Remote with no URL" -msgstr "git archive: Máy chá»§ không có địa chỉ URL" - msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "git archive: cần ACK/NAK, nhưng lại nháºn được gói flush" @@ -2603,7 +2665,7 @@ msgid "force progress reporting" msgstr "ép buá»™c báo cáo tiến độ công việc" msgid "show output score for blame entries" -msgstr "hiển thị kết xuất Ä‘iểm số cho các mục tin 'blame'" +msgstr "hiển thị Ä‘iểm số đầu ra cho các mục tin 'blame'" msgid "show original filename (Default: auto)" msgstr "hiển thị tên táºp tin gốc (Mặc định: auto)" @@ -2881,7 +2943,7 @@ msgid "unset the upstream info" msgstr "bỠđặt thông tin thượng nguồn" msgid "use colored output" -msgstr "tô mà u kết xuất" +msgstr "tô mà u đầu ra" msgid "act on remote-tracking branches" msgstr "thao tác trên nhánh 'remote-tracking'" @@ -3175,6 +3237,9 @@ msgstr "Cần má»™t kho chứa để có thể tạo má»™t bundle." msgid "do not show bundle details" msgstr "không hiển thị chi tiết bundle (bó)" +msgid "need a repository to verify a bundle" +msgstr "cần má»™t kho chứa để thẩm tra má»™t bundle" + #, c-format msgid "%s is okay\n" msgstr "%s tốt\n" @@ -3288,7 +3353,7 @@ msgid "Change or optimize batch output" msgstr "Thay đổi hay tối ưu hóa đầu ra batch" msgid "buffer --batch output" -msgstr "đệm kết xuất --batch" +msgstr "buffer đầu ra --batch" msgid "follow in-tree symlinks" msgstr "theo liên kết má»m trong-cây" @@ -3456,7 +3521,7 @@ msgid "write the content to temporary files" msgstr "ghi ná»™i dung và o táºp tin tạm" msgid "copy out the files from named stage" -msgstr "sao chép ra các táºp tin từ bệ phóng có tên" +msgstr "sao chép ra các táºp tin từ vùng chá» có tên" msgid "git checkout [<options>] <branch>" msgstr "git checkout [<các tùy chá»n>] <nhánh>" @@ -3550,7 +3615,7 @@ msgid "" "cannot continue with staged changes in the following files:\n" "%s" msgstr "" -"không thể tiếp tục vá»›i các thay đổi đã được đưa lên bệ phóng trong các dòng " +"không thể tiếp tục vá»›i các thay đổi đã được đưa và o vùng chá» trong các dòng " "sau:\n" "%s" @@ -3570,7 +3635,7 @@ msgstr "Äặt lại nhánh '%s'\n" #, c-format msgid "Already on '%s'\n" -msgstr "Äã sẵn sà ng trên '%s'\n" +msgstr "Äã sẵn ở trên '%s'\n" #, c-format msgid "Switched to and reset branch '%s'\n" @@ -4177,12 +4242,20 @@ msgid "failed to unlink '%s'" msgstr "gặp lá»—i khi unlink '%s'" #, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "không thể kiểm tra liên kết cứng '%s'" + +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "liên kết cứng '%s' khác vá»›i nguồn" + +#, c-format msgid "failed to create link '%s'" -msgstr "gặp lá»—i khi tạo được liên kết má»m %s" +msgstr "gặp lá»—i khi tạo liên kết má»m %s" #, c-format msgid "failed to copy file to '%s'" -msgstr "gặp lá»—i khi sao chép táºp tin và '%s'" +msgstr "gặp lá»—i khi sao chép táºp tin tá»›i '%s'" #, c-format msgid "failed to iterate over '%s'" @@ -4841,7 +4914,7 @@ msgid "version" msgstr "phiên bản" msgid "machine-readable output" -msgstr "kết xuất dạng máy-có-thể-Ä‘á»c" +msgstr "xuất ra dạng máy-có-thể-Ä‘á»c" msgid "show status in long format (default)" msgstr "hiển thị trạng thái ở định dạng dà i (mặc định)" @@ -4930,15 +5003,14 @@ msgstr "" msgid "use autosquash formatted message to squash specified commit" msgstr "" -"dùng lá»i nhắn có định dạng tá»± động nén để nén lại các lần chuyển giao đã chỉ " -"ra" +"dùng lá»i nhắn có định dạng autosquash để squash các lần chuyển giao đã chỉ ra" msgid "the commit is authored by me now (used with -C/-c/--amend)" msgstr "" "lần chuyển giao nháºn tôi là tác giả (được dùng vá»›i tùy chá»n -C/-c/--amend)" msgid "trailer" -msgstr "bá»™ dò vết" +msgstr "trailer" msgid "add custom trailer(s)" msgstr "thêm Ä‘uôi tá»± chá»n" @@ -5029,15 +5101,51 @@ msgstr "" "có bị đầy quá hay hạn nghạch đĩa (quota) bị vượt quá hay không,\n" "và sau đó \"git restore --staged :/\" để khắc phục." -msgid "git config [<options>]" -msgstr "git config [<các tùy chá»n>]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "git config list [<tuỳ-chá»n>] [<tuỳ-chá»n-hiển-thị>] [--includes]" -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "đối số không được thừa nháºn --type, %s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [<tuỳ-chá»n>] [<tuỳ-chá»n-hiển-thị>] [--includes] [--all] [--" +"regexp=<biểu-thức-chÃnh-quy>] [--value=<giá-trị>] [--fixed-value] [--" +"default=<giá-trị-mặc-định>] <khoá>" -msgid "only one type at a time" -msgstr "chỉ má»™t kiểu má»™t lần" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [<tuỳ-chá»n>] [--type=<kiểu>] [--all] [--value=<giá-trị>] [--" +"fixed-value] <khoá> <giá-trị>" + +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [<tuỳ-chá»n>] [--all] [--value=<giá-trị>] [--fixed-value] " +"<khoá> <giá-trị>" + +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "git config rename-section [<tuỳ-chá»n>] <tên-cÅ©> <tên-má»›i>" + +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [<tuỳ-chá»n>] <tên>" + +msgid "git config edit [<file-option>]" +msgstr "git config edit [<tùy-chá»n>]" + +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "" +"git config [<tuỳ-chá»n>] --get-colorbool <tên> [<stdout-là -tty-hay-không>]" + +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [<tuỳ-chá»n>] [--type=<kiểu>] [--comment=<chú-thÃch>] [--all] " +"[--value=<giá-trị>] [--fixed-value] <khoá> <giá-trị>" msgid "Config file location" msgstr "Vị trà táºp tin cấu hình" @@ -5063,54 +5171,6 @@ msgstr "blob-id" msgid "read config from given blob object" msgstr "Ä‘á»c cấu hình từ đối tượng blob đã cho" -msgid "Action" -msgstr "Hà nh động" - -msgid "get value: name [value-pattern]" -msgstr "lấy giá trị: tên [value-pattern]" - -msgid "get all values: key [value-pattern]" -msgstr "lấy tất cả giá trị: khóa [value-pattern]" - -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "lấy giá trị cho regexp: name-regex [value-pattern]" - -msgid "get value specific for the URL: section[.var] URL" -msgstr "lấy đặc tả giá trị cho URL: phần[.biến] URL" - -msgid "replace all matching variables: name value [value-pattern]" -msgstr "thay thế tất cả các biến khá»›p mẫu: tên giá-trị [value-pattern]" - -msgid "add a new variable: name value" -msgstr "thêm biến má»›i: tên giá-trị" - -msgid "remove a variable: name [value-pattern]" -msgstr "gỡ bá» biến: tên [value-pattern]" - -msgid "remove all matches: name [value-pattern]" -msgstr "gỡ bá» má»i cái khá»›p: tên [value-pattern]" - -msgid "rename section: old-name new-name" -msgstr "đổi tên phần: tên-cÅ© tên-má»›i" - -msgid "remove a section: name" -msgstr "gỡ bá» phần: tên" - -msgid "list all" -msgstr "liệt kê tất" - -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "sá» dụng so sánh bằng chuá»—i khi so sánh các giá trị vá»›i 'value-pattern'" - -msgid "open an editor" -msgstr "mở má»™t trình biên soạn" - -msgid "find the color configured: slot [default]" -msgstr "tìm cấu hình mà u sắc: slot [mặc định]" - -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "tìm các cà i đặt vá» mà u sắc: slot [stdout-là -tty]" - msgid "Type" msgstr "Kiểu" @@ -5138,8 +5198,8 @@ msgstr "giá trị là đưá»ng dẫn (tên táºp tin hay thư mục)" msgid "value is an expiry date" msgstr "giá trị là má»™t ngà y hết hạn" -msgid "Other" -msgstr "Khác" +msgid "Display options" +msgstr "Tuỳ chá»n hiển thị" msgid "terminate values with NUL byte" msgstr "kết thúc giá trị vá»›i byte NUL" @@ -5147,9 +5207,6 @@ msgstr "kết thúc giá trị vá»›i byte NUL" msgid "show variable names only" msgstr "chỉ hiển thị các tên biến" -msgid "respect include directives on lookup" -msgstr "tôn trá»ng kể cà các hướng trong tìm kiếm" - msgid "show origin of config (file, standard input, blob, command line)" msgstr "hiển thị nguồn gốc cá»§a cấu hình (táºp tin, stdin, blob, dòng lệnh)" @@ -5158,14 +5215,15 @@ msgstr "" "hiển thị phạm vi cá»§a cấu hình (cây là m việc, cục bá»™, toà n cầu, hệ thống, " "lệnh)" -msgid "value" -msgstr "giá trị" +msgid "show config keys in addition to their values" +msgstr "hiển thị khoá cùng vói giá trị" -msgid "with --get, use default value when missing entry" -msgstr "vá»›i --get, dùng giá trị mặc định khi thiếu mục tin" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "đối số không được thừa nháºn --type, %s" -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "ghi chú cho ngưá»i Ä‘á»c được (tá»± động thêm # và o trước nếu cần)" +msgid "only one type at a time" +msgstr "chỉ má»™t kiểu má»™t lần" #, c-format msgid "wrong number of arguments, should be %d" @@ -5241,47 +5299,72 @@ msgstr "" "worktreeConfig được báºt. Vui lòng Ä‘á»c phần \"CONFIGURATION FILE\"\n" "trong \"git help worktree\" để biết thêm chi tiết" -msgid "--get-color and variable type are incoherent" -msgstr "--get-color và kiểu biến là không mạch lạc" +msgid "Other" +msgstr "Khác" -msgid "only one action at a time" -msgstr "chỉ má»™t thao tác má»—i lần" +msgid "respect include directives on lookup" +msgstr "tôn trá»ng kể cà các hướng trong tìm kiếm" -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "--name-only chỉ được áp dụng cho --list hoặc --get-regexp" +#, c-format +msgid "unable to read config file '%s'" +msgstr "không thể Ä‘á»c táºp tin cấu hình '%s'" -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" -msgstr "" -"--show-origin chỉ được áp dụng cho --get, --get-all, --get-regexp, hoặc --" -"list" +msgid "error processing config file(s)" +msgstr "gặp lá»—i khi xá» lý các táºp tin cấu hình" -msgid "--default is only applicable to --get" -msgstr "--default chỉ được áp dụng cho --get" +msgid "Filter options" +msgstr "Tùy chá»n lá»c" -msgid "--comment is only applicable to add/set/replace operations" -msgstr "--comment chỉ được áp dụng cho thao tác add/set/replace" +msgid "return all values for multi-valued config options" +msgstr "trả vá» tất cả giá trị cho tuỳ chá»n cấu hình Ä‘a trị" + +msgid "interpret the name as a regular expression" +msgstr "coi khoá là biểu thức chÃnh quy" + +msgid "show config with values matching the pattern" +msgstr "hiển thị giá trị cấu hình khá»›p vá»›i mẫu" + +msgid "use string equality when comparing values to value pattern" +msgstr "sá» dụng so sánh xâu khi so sánh các giá trị vá»›i mẫu" + +msgid "URL" +msgstr "URL" + +msgid "show config matching the given URL" +msgstr "hiển thị giá trị cấu hình khá»›p vá»›i URL" + +msgid "value" +msgstr "giá trị" + +msgid "use default value when missing entry" +msgstr "dùng giá trị mặc định khi không tồn tại" msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value chỉ áp dụng vá»›i 'value-pattern'" -#, c-format -msgid "unable to read config file '%s'" -msgstr "không thể Ä‘á»c táºp tin cấu hình '%s'" +msgid "--default= cannot be used with --all or --url=" +msgstr "--default= không thể được dùng vá»›i --all hay --url" -msgid "error processing config file(s)" -msgstr "gặp lá»—i khi xá» lý các táºp tin cấu hình" +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "--url= không thể được dùng vá»›i --all, --regexp hay --value" -msgid "editing stdin is not supported" -msgstr "sá»a chữa stdin là không được há»— trợ" +msgid "Filter" +msgstr "Bá»™ lá»c" -msgid "editing blobs is not supported" -msgstr "việc sá»a chữa các blob là không được há»— trợ" +msgid "replace multi-valued config option with new value" +msgstr "thay thế tuỳ chá»n cấu hình Ä‘a trị thà nh giá trị" -#, c-format -msgid "cannot create configuration file %s" -msgstr "không thể tạo táºp tin cấu hình '%s'" +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "ghi chú cho ngưá»i Ä‘á»c được (tá»± động thêm # và o trước nếu cần)" + +msgid "add a new line without altering any existing values" +msgstr "thêm dòng má»›i giữ nguyên các giá trị cÅ©" + +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "--fixed-value chỉ áp dụng vá»›i --value=<mẫu>" + +msgid "--append cannot be used with --value=<pattern>" +msgstr "--append không thể được dùng vá»›i --value=<mẫu>" #, c-format msgid "" @@ -5295,6 +5378,86 @@ msgstr "" msgid "no such section: %s" msgstr "không có Ä‘oạn: %s" +msgid "editing stdin is not supported" +msgstr "sá»a chữa stdin là không được há»— trợ" + +msgid "editing blobs is not supported" +msgstr "việc sá»a chữa các blob là không được há»— trợ" + +#, c-format +msgid "cannot create configuration file %s" +msgstr "không thể tạo táºp tin cấu hình '%s'" + +msgid "Action" +msgstr "Hà nh động" + +msgid "get value: name [<value-pattern>]" +msgstr "lấy giá trị: khoá [<mẫu-giá-trị>]" + +msgid "get all values: key [<value-pattern>]" +msgstr "lấy tất cả giá trị: khóa [<mẫu-giá-trị>]" + +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "lấy giá trị cho biểu thức chÃnh quy: regex [<mẫu-giá-trị>]" + +msgid "get value specific for the URL: section[.var] URL" +msgstr "lấy giá trị riêng cho URL: phần[.biến] URL" + +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "thay thế tất cả các biến khá»›p mẫu: tên giá-trị [<mẫu-giá-trị>]" + +msgid "add a new variable: name value" +msgstr "thêm biến má»›i: tên giá-trị" + +msgid "remove a variable: name [<value-pattern>]" +msgstr "gỡ bá» biến: tên [<mẫu-giá-trị>]" + +msgid "remove all matches: name [<value-pattern>]" +msgstr "gỡ bá» má»i biến khá»›p: tên [<mẫu-giá-trị>]" + +msgid "rename section: old-name new-name" +msgstr "đổi tên phần: tên-cÅ© tên-má»›i" + +msgid "remove a section: name" +msgstr "gỡ bá» phần: tên" + +msgid "list all" +msgstr "liệt kê tất" + +msgid "open an editor" +msgstr "mở má»™t trình biên soạn" + +msgid "find the color configured: slot [<default>]" +msgstr "tìm cấu hình mà u sắc: slot [<mặc định>]" + +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "tìm các cà i đặt vá» mà u sắc: slot [<stdout-là -tty-hay-không>]" + +msgid "with --get, use default value when missing entry" +msgstr "vá»›i --get, dùng giá trị mặc định khi thiếu mục tin" + +msgid "--get-color and variable type are incoherent" +msgstr "--get-color và kiểu biến là không mạch lạc" + +msgid "no action specified" +msgstr "chưa chỉ ra hà nh động" + +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "--name-only chỉ được áp dụng cho --list hoặc --get-regexp" + +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "" +"--show-origin chỉ được áp dụng cho --get, --get-all, --get-regexp, hoặc --" +"list" + +msgid "--default is only applicable to --get" +msgstr "--default chỉ được áp dụng cho --get" + +msgid "--comment is only applicable to add/set/replace operations" +msgstr "--comment chỉ được áp dụng cho thao tác add/set/replace" + msgid "print sizes in human readable format" msgstr "hiển thị kÃch cỡ theo định dạng dà nh cho ngưá»i Ä‘á»c" @@ -5637,7 +5800,7 @@ msgid "use the done feature to terminate the stream" msgstr "sá» dụng tÃnh năng done để kết thúc luồng dữ liệu" msgid "skip output of blob data" -msgstr "bá» qua kết xuất cá»§a dữ liệu blob" +msgstr "bá» qua đầu ra cá»§a dữ liệu blob" msgid "refspec" msgstr "refspec" @@ -5646,7 +5809,7 @@ msgid "apply refspec to exported refs" msgstr "áp dụng refspec cho refs đã xuất" msgid "anonymize output" -msgstr "kết xuất anonymize" +msgstr "ẩn danh đầu ra" msgid "from:to" msgstr "từ:đến" @@ -5946,7 +6109,7 @@ msgid "re-fetch without negotiating common commits" msgstr "re-fetch mà không dà n xếp các lần chuyển giao chung" msgid "prepend this to submodule path output" -msgstr "soạn sẵn cái nà y cho kết xuất đưá»ng dẫn mô-Ä‘un-con" +msgstr "soạn sẵn cái nà y cho đầu ra đưá»ng dẫn mô-Ä‘un-con" msgid "" "default for recursive fetching of submodules (lower priority than config " @@ -6038,7 +6201,7 @@ msgid "populate log with at most <n> entries from shortlog" msgstr "gắn nháºt ký vá»›i Ãt nhất <n> mục từ lệnh 'shortlog'" msgid "alias for --log (deprecated)" -msgstr "bà danh cho --log (đã lạc háºu)" +msgstr "đồng nghÄ©a vá»›i --log (đã không còn)" msgid "text" msgstr "văn bản" @@ -6119,6 +6282,9 @@ msgstr "config" msgid "config key storing a list of repository paths" msgstr "khóa cấu hình lưu trữ danh sách đưá»ng dẫn kho lưu trữ" +msgid "keep going even if command fails in a repository" +msgstr "tiếp tục dù có lệnh thất bại trong kho chứa" + msgid "missing --config=<config>" msgstr "thiếu --config=<config>" @@ -6141,7 +6307,7 @@ msgstr "có cảnh báo trong %s %s: %s" #, c-format msgid "broken link from %7s %s" -msgstr "liên kết gãy từ %7s %s" +msgstr "liên kết há»ng từ %7s %s" msgid "wrong object type in link" msgstr "kiểu đối tượng sai trong liên kết" @@ -6151,7 +6317,7 @@ msgid "" "broken link from %7s %s\n" " to %7s %s" msgstr "" -"liên kết gãy từ %7s %s \n" +"liên kết há»ng từ %7s %s \n" " tá»›i %7s %s" msgid "Checking connectivity" @@ -6858,7 +7024,7 @@ msgid "combine patterns specified with -e" msgstr "tổ hợp mẫu được chỉ ra vá»›i tùy chá»n -e" msgid "indicate hit with exit status without output" -msgstr "đưa ra gợi ý vá»›i trạng thái thoát mà không có kết xuất" +msgstr "chỉ ra có khá»›p mẫu hay không vá»›i trạng thái thoát thay vì đầu ra" msgid "show only matches from files that match all patterns" msgstr "chỉ hiển thị những cái khá»›p từ táºp tin mà nó khá»›p toà n bá»™ các mẫu" @@ -7402,7 +7568,7 @@ msgid "invalid --decorate option: %s" msgstr "tùy chá»n --decorate không hợp lệ: %s" msgid "suppress diff output" -msgstr "chặn má»i kết xuất từ diff" +msgstr "chặn má»i đầu ra từ diff" msgid "show source" msgstr "hiển thị mã nguồn" @@ -7435,7 +7601,7 @@ msgstr "-L<vùng>:<táºp tin> không thể được sá» dụng vá»›i đặc tẠ#, c-format msgid "Final output: %d %s\n" -msgstr "Kết xuất cuối cùng: %d %s\n" +msgstr "Äầu ra cuối cùng: %d %s\n" msgid "unable to create temporary object directory" msgstr "không thể tạo thư mục đối tượng tạm thá»i" @@ -7487,7 +7653,7 @@ msgid "git format-patch [<options>] [<since> | <revision-range>]" msgstr "git format-patch [<các tùy chá»n>] [<kể-từ> | <vùng-xem-xét>]" msgid "two output directories?" -msgstr "hai thư mục kết xuất?" +msgstr "hai thư mục đầu ra?" #, c-format msgid "unknown commit %s" @@ -7563,8 +7729,11 @@ msgstr "đánh dấu chuá»—i là lần chạy lại thứ N" msgid "max length of output filename" msgstr "chiá»u dà i tên táºp tin đầu ra tối Ä‘a" -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "dùng [RFC PATCH] thay cho [PATCH]" +msgid "rfc" +msgstr "rfc" + +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "thêm <rfc> (mặc định 'RFC') trước 'PATCH'" msgid "cover-from-description-mode" msgstr "cover-from-description-mode" @@ -7585,7 +7754,7 @@ msgid "don't strip/add [PATCH]" msgstr "không loại bá»/thêm [PATCH]" msgid "don't output binary diffs" -msgstr "không kết xuất diff nhị phân" +msgstr "không xuất diff nhị phân" msgid "output all-zero hash in From header" msgstr "xuất má»i mã băm all-zero trong phần đầu From" @@ -7722,7 +7891,7 @@ msgid "Generating patches" msgstr "Äang tạo các bản vá" msgid "failed to create output files" -msgstr "gặp lá»—i khi tạo các táºp tin kết xuất" +msgstr "gặp lá»—i khi tạo các táºp tin đầu ra" msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]" msgstr "git cherry [-v] [<thượng-nguồn> [<đầu> [<giá»›i-hạn>]]]" @@ -7759,19 +7928,19 @@ msgid "show cached files in the output (default)" msgstr "hiển thị các táºp tin được nhá»› tạm và o đầu ra (mặc định)" msgid "show deleted files in the output" -msgstr "hiển thị các táºp tin đã xóa trong kết xuất" +msgstr "hiển thị các táºp tin đã xóa trong đầu ra" msgid "show modified files in the output" -msgstr "hiển thị các táºp tin đã bị sá»a đổi ra kết xuất" +msgstr "hiển thị các táºp tin đã bị sá»a đổi ra đầu ra" msgid "show other files in the output" -msgstr "hiển thị các táºp tin khác trong kết xuất" +msgstr "hiển thị các táºp tin khác trong đầu ra" msgid "show ignored files in the output" -msgstr "hiển thị các táºp tin bị bá» qua trong kết xuất" +msgstr "hiển thị các táºp tin bị bá» qua trong đầu ra" msgid "show staged contents' object name in the output" -msgstr "hiển thị tên đối tượng cá»§a ná»™i dung được đặt lên bệ phóng ra kết xuất" +msgstr "hiển thị tên đối tượng cá»§a ná»™i dung được đặt và o vùng chá» ra đầu ra" msgid "show files on the filesystem that need to be removed" msgstr "hiển thị các táºp tin trên hệ thống táºp tin mà nó cần được gỡ bá»" @@ -7786,13 +7955,13 @@ msgid "don't show empty directories" msgstr "không hiển thị thư mục rá»—ng" msgid "show unmerged files in the output" -msgstr "hiển thị các táºp tin chưa hòa trá»™n trong kết xuất" +msgstr "hiển thị các táºp tin chưa hòa trá»™n trong đầu ra" msgid "show resolve-undo information" msgstr "hiển thị thông tin resolve-undo" msgid "skip files matching pattern" -msgstr "bá» qua những táºp tin khá»›p vá»›i má»™t mẫu" +msgstr "bá» qua những táºp tin khá»›p vá»›i mẫu" msgid "read exclude patterns from <file>" msgstr "Ä‘á»c mẫu cần loại trừ từ <táºp-tin>" @@ -7804,10 +7973,10 @@ msgid "add the standard git exclusions" msgstr "thêm loại trừ tiêu chuẩn kiểu git" msgid "make the output relative to the project top directory" -msgstr "là m cho kết xuất liên quan đến thư mục ở mức cao nhất (gốc) cá»§a dá»± án" +msgstr "cho kết quả là đưá»ng dẫn tương đối từ thư mục gốc cá»§a dá»± án" msgid "if any <file> is not in the index, treat this as an error" -msgstr "nếu <táºp tin> bất kỳ không ở trong chỉ mục, xá» lý nó như má»™t lá»—i" +msgstr "nếu có bất kỳ <táºp tin> không ở trong chỉ mục, coi nó như má»™t lá»—i" msgid "tree-ish" msgstr "tree-ish" @@ -7833,11 +8002,11 @@ msgstr "" "deduplicate, --eol" msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<kho> [<mẫu>...]]" @@ -7853,8 +8022,11 @@ msgstr "đưá»ng dẫn cá»§a git-upload-pack trên máy chá»§" msgid "limit to tags" msgstr "giá»›i hạn tá»›i các thẻ" -msgid "limit to heads" -msgstr "giá»›i hạn cho các đầu" +msgid "limit to branches" +msgstr "giá»›i hạn tá»›i các nhánh" + +msgid "deprecated synonym for --branches" +msgstr "trước đây là đồng nghÄ©a vá»›i --branches" msgid "do not show peeled tags" msgstr "không hiển thị thẻ bị peel (gá»t bá»)" @@ -8694,7 +8866,7 @@ msgid "Write/edit the notes for the following object:" msgstr "Ghi hay sá»a ghi chú cho đối tượng sau đây:" msgid "could not read 'show' output" -msgstr "không thể Ä‘á»c kết xuất 'show'" +msgstr "không thể Ä‘á»c đầu ra 'show'" #, c-format msgid "failed to finish 'show' for object '%s'" @@ -9171,7 +9343,7 @@ msgid "use threads when searching for best delta matches" msgstr "sá» dụng các tuyến trình khi tìm kiếm cho các mẫu khá»›p delta tốt nhất" msgid "do not create an empty pack output" -msgstr "không thể tạo kết xuất gói trống rá»—ng" +msgstr "không thể tạo đầu ra gói trống rá»—ng" msgid "read revision arguments from standard input" msgstr "Ä‘á»c tham số 'revision' từ stdin" @@ -9300,7 +9472,7 @@ msgid "" "Total %<PRIu32> (delta %<PRIu32>), reused %<PRIu32> (delta %<PRIu32>), pack-" "reused %<PRIu32> (from %<PRIuMAX>)" msgstr "" -"Tổng %<PRIu32> (delta %<PRIu32>), dùng lại %<PRIu32> (delta %<PRIu32>),dùng " +"Tổng %<PRIu32> (delta %<PRIu32>), dùng lại %<PRIu32> (delta %<PRIu32>), dùng " "lại pack %<PRIu32> (trong số %<PRIuMAX>)" msgid "" @@ -9862,10 +10034,10 @@ msgid "passed to 'git log'" msgstr "chuyển cho 'git log'" msgid "only emit output related to the first range" -msgstr "chỉ phát ra kết xuất liên quan đến vùng đầu tiên" +msgstr "chỉ phát ra kết quả liên quan đến vùng đầu tiên" msgid "only emit output related to the second range" -msgstr "chỉ phát ra kết xuất liên quan đến vùng thứ hai" +msgstr "chỉ phát ra kết quả liên quan đến vùng thứ hai" #, c-format msgid "not a revision: '%s'" @@ -10029,7 +10201,7 @@ msgstr "" "không thể tổ hợp các tùy chá»n áp dụng vá»›i các tùy chá»n hòa trá»™n vá»›i nhau" msgid "--empty=ask is deprecated; use '--empty=stop' instead." -msgstr "không cho dùng --empty=ask nữa; hãy thay thế bằng '--empty=stop'." +msgstr "không còn dùng --empty=ask nữa; hãy thay thế bằng '--empty=stop'." #, c-format msgid "" @@ -10499,6 +10671,22 @@ msgstr "chưa chỉ ra reflog để xóa" msgid "invalid ref format: %s" msgstr "định dạng tham chiếu không hợp lệ: %s" +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=<định dạng> [--dry-run]" + +msgid "specify the reference format to convert to" +msgstr "chỉ định định dạng tham chiếu để chuyển đổi sang" + +msgid "perform a non-destructive dry-run" +msgstr "chạy thá» mà không thay đổi gì" + +msgid "missing --ref-format=<format>" +msgstr "thiếu --ref-format=<định dạng>" + +#, c-format +msgid "repository already uses '%s' format" +msgstr "kho đã dùng định dạng '%s'" + msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" "mirror=<fetch|push>] <name> <url>" @@ -10778,9 +10966,6 @@ msgstr "* máy chá»§ %s" msgid " Fetch URL: %s" msgstr " URL để lấy vá»: %s" -msgid "(no URL)" -msgstr "(không có URL)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -10789,6 +10974,9 @@ msgstr "(không có URL)" msgid " Push URL: %s" msgstr " URL để đẩy lên: %s" +msgid "(no URL)" +msgstr "(không có URL)" + #, c-format msgid " HEAD branch: %s" msgstr " Nhánh HEAD: %s" @@ -10891,10 +11079,6 @@ msgstr "truy vấn đẩy URL thay vì lấy" msgid "return all URLs" msgstr "trả vá» má»i URL" -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "không có URL nà o được cấu hình cho nhánh '%s'" - msgid "manipulate push URLs" msgstr "đẩy các 'URL' bằng tay" @@ -11260,7 +11444,7 @@ msgid "--convert-graft-file takes no argument" msgstr "--convert-graft-file không nháºn đối số" msgid "only one pattern can be given with -l" -msgstr "chỉ má»™t mẫu được chỉ ra vá»›i tùy chá»n -l" +msgstr "chỉ được chỉ định má»™t mẫu cùng vá»›i tùy chá»n -l" msgid "need some commits to replay" msgstr "cần các chuyển giao để phát lại" @@ -11422,7 +11606,7 @@ msgstr "Gặp lá»—i khi phân giải '%s' như là má»™t cây (tree) hợp lệ. msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." msgstr "" -"không cho dùng --mixed vá»›i các đưá»ng dẫn nữa; hãy thay thế bằng lệnh 'git " +"không còn dùng --mixed vá»›i các đưá»ng dẫn nữa; hãy thay thế bằng lệnh 'git " "reset -- </các/đưá»ng/dẫn>'." #, c-format @@ -11434,7 +11618,7 @@ msgid "%s reset is not allowed in a bare repository" msgstr "%s reset không được phép trên kho chứa bare" msgid "Unstaged changes after reset:" -msgstr "Những thay đổi được đưa ra khá»i bệ phóng sau khi reset:" +msgstr "Những thay đổi được đưa ra khá»i vùng chá» sau khi reset:" #, c-format msgid "" @@ -11477,7 +11661,7 @@ msgid "stop parsing after the first non-option argument" msgstr "dừng Ä‘á»c sau đối số đầu tiên không có tùy chá»n" msgid "output in stuck long form" -msgstr "kết xuất trong định dạng gáºy dà i" +msgstr "kết quả có định dạng dà i" msgid "premature end of input" msgstr "đầu và o kết thúc bất thưá»ng" @@ -11646,7 +11830,7 @@ msgid_plural "" "the following files have staged content different from both the\n" "file and the HEAD:" msgstr[0] "" -"các táºp tin sau đây có khác biệt ná»™i dung đã đưa lên bệ phóng\n" +"các táºp tin sau đây có khác biệt ná»™i dung đã đưa và o vùng chá»\n" "từ cả táºp tin và cả HEAD:" msgid "" @@ -11751,7 +11935,7 @@ msgid "group by committer rather than author" msgstr "nhóm theo ngưá»i chuyển giao thay vì tác giả" msgid "sort output according to the number of commits per author" -msgstr "sắp xếp kết xuất tuân theo số lượng chuyển giao trên má»—i tác giả" +msgstr "sắp xếp kết quả theo số lượng chuyển giao trên má»—i tác giả" msgid "suppress commit descriptions, only provides commit count" msgstr "chặn má»i mô tả lần chuyển giao, chỉ đưa ra số lượng lần chuyển giao" @@ -11883,12 +12067,12 @@ msgstr "Không hiểu thuáºt toán băm dữ liệu" msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<mẫu>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<mẫu>...]" msgid "" "git show-ref --verify [-q | --quiet] [-d | --dereference]\n" @@ -11911,10 +12095,10 @@ msgstr "tham chiếu không tồn tại" msgid "failed to look up reference" msgstr "gặp lá»—i khi tìm tham chiếu" -msgid "only show tags (can be combined with heads)" -msgstr "chỉ hiển thị thẻ (có thể tổ hợp cùng vá»›i đầu)" +msgid "only show tags (can be combined with branches)" +msgstr "chỉ hiển thị thẻ (có thể tổ hợp cùng vá»›i nhánh)" -msgid "only show heads (can be combined with tags)" +msgid "only show branches (can be combined with tags)" msgstr "chỉ hiển thị đầu (có thể tổ hợp cùng vá»›i thẻ)" msgid "check for reference existence without resolving" @@ -12229,7 +12413,7 @@ msgid "\"git stash store\" requires one <commit> argument" msgstr "\"git stash store\" cần má»™t đối số <lần chuyển giao>" msgid "No staged changes" -msgstr "Không có thay đổi đã được đưa lên bệ phóng" +msgstr "Không có thay đổi đã được đưa và o vùng chá»" msgid "No changes selected" msgstr "Chưa có thay đổi nà o được chá»n" @@ -12247,7 +12431,7 @@ msgid "Cannot save the current worktree state" msgstr "Không thể ghi lại trạng thái cây-là m-việc hiện hà nh" msgid "Cannot save the current staged state" -msgstr "Không thể ghi lại trạng thái bệ phóng hiện hà nh" +msgstr "Không thể ghi lại trạng thái vùng chá» hiện hà nh" msgid "Cannot record working tree state" msgstr "Không thể ghi lại trạng thái cây là m việc hiện hà nh" @@ -12281,7 +12465,7 @@ msgid "keep index" msgstr "giữ nguyên chỉ mục" msgid "stash staged changes only" -msgstr "chỉ tạm cất Ä‘i các thay đổi đã đưa lên bệ phóng" +msgstr "chỉ tạm cất Ä‘i các thay đổi đã đưa và o vùng chá»" msgid "stash in patch mode" msgstr "cất Ä‘i ở chế độ vá" @@ -12344,7 +12528,7 @@ msgstr "" "." msgid "suppress output of entering each submodule command" -msgstr "chặn kết xuất cá»§a từng lệnh mô-Ä‘un-con" +msgstr "chặn đầu ra cá»§a từng lệnh mô-Ä‘un-con" msgid "recurse into nested submodules" msgstr "đệ quy và o trong mô-Ä‘un-con lồng nhau" @@ -12369,7 +12553,7 @@ msgid "Failed to register update mode for submodule path '%s'" msgstr "Gặp lá»—i khi đăng ký chế độ cáºp nháºt cho đưá»ng dẫn mô-Ä‘un-con '%s'" msgid "suppress output for initializing a submodule" -msgstr "chặn kết xuất cá»§a khởi tạo má»™t mô-Ä‘un-con" +msgstr "chặn đầu ra cá»§a khởi tạo má»™t mô-Ä‘un-con" msgid "git submodule init [<options>] [<path>]" msgstr "git submodule init [<các tùy chá»n>] [</đưá»ng/dẫn>]" @@ -12389,7 +12573,7 @@ msgid "failed to recurse into submodule '%s'" msgstr "gặp lá»—i khi đệ quy và o trong mô-Ä‘un-con '%s'" msgid "suppress submodule status output" -msgstr "chặn kết xuất vá» tình trạng mô-Ä‘un-con" +msgstr "chặn đầu ra vá» tình trạng mô-Ä‘un-con" msgid "" "use commit stored in the index instead of the one stored in the submodule " @@ -12458,7 +12642,7 @@ msgid "failed to update remote for submodule '%s'" msgstr "gặp lá»—i khi cáºp nháºt cho mô-Ä‘un-con '%s'" msgid "suppress output of synchronizing submodule url" -msgstr "chặn kết xuất cá»§a url mô-Ä‘un-con đồng bá»™" +msgstr "chặn đầu ra cá»§a url mô-Ä‘un-con đồng bá»™" msgid "git submodule sync [--quiet] [--recursive] [<path>]" msgstr "git submodule sync [--quiet] [--recursive] [</đưá»ng/dẫn>]" @@ -12545,14 +12729,14 @@ msgid "refusing to create/use '%s' in another submodule's git dir" msgstr "từ chối tạo/dùng '%s' trong má»™t thư mục git cá»§a mô Ä‘un con" #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "việc sao '%s' và o đưá»ng dẫn mô-Ä‘un-con '%s' gặp lá»—i" - -#, c-format msgid "directory not empty: '%s'" msgstr "thư mục không trống: '%s'" #, c-format +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "việc sao '%s' và o đưá»ng dẫn mô-Ä‘un-con '%s' gặp lá»—i" + +#, c-format msgid "could not get submodule directory for '%s'" msgstr "không thể lấy thư mục mô-Ä‘un-con cho '%s'" @@ -12902,7 +13086,7 @@ msgid "delete symbolic ref" msgstr "xóa tham chiếu má»m" msgid "shorten ref output" -msgstr "là m ngắn kết xuất ref (tham chiếu)" +msgstr "là m ngắn kết quả ref (tham chiếu)" msgid "recursively dereference (default)" msgstr "chế độ giải tham chiếu đệ quy (mặc định)" @@ -12915,9 +13099,11 @@ msgstr "lý do cáºp nháºt" msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <táºp-tin>] [-e]\n" +" [(--trailer <token>[(=|:)<giá-trị>])...]\n" " <tên-thẻ> [<lần chuyển giao> | <đối tượng> ]" msgid "git tag -d <tagname>..." @@ -13353,7 +13539,7 @@ msgid "print commit contents" msgstr "hiển thị ná»™i dung cá»§a lần chuyển giao" msgid "print raw gpg status output" -msgstr "in kết xuất trạng thái gpg dạng thô" +msgstr "in đầu ra trạng thái gpg dạng thô" msgid "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..." msgstr "git verify-pack [-v | --verbose] [-s | --stat-only] [--] <gói>.idx..." @@ -13764,9 +13950,6 @@ msgstr "phần đầu không được thừa nháºn: %s%s (%d)" msgid "Repository lacks these prerequisite commits:" msgstr "Kho chứa thiếu những lần chuyển giao tiên quyết nà y:" -msgid "need a repository to verify a bundle" -msgstr "cần má»™t kho chứa để thẩm tra má»™t bundle" - msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -14029,7 +14212,7 @@ msgstr "" "Rút trÃch mã số lần chuyển giao từ má»™t kho nén đã được tạo bởi git-archive" msgid "Print lines matching a pattern" -msgstr "In ra những dòng khá»›p vá»›i má»™t mẫu" +msgstr "In ra những dòng khá»›p vá»›i mẫu" msgid "A portable graphical interface to Git" msgstr "Má»™t giao diện đồ há»a khả chuyển cho Git" @@ -14174,6 +14357,9 @@ msgstr "Nháºn cái mà được đẩy và o trong kho" msgid "Manage reflog information" msgstr "Quản lý thông tin reflog" +msgid "Low-level access to refs" +msgstr "Truy cáºp tá»›i tham chiếu ở mức thấp" + msgid "Manage set of tracked repositories" msgstr "Quản lý táºp hợp các kho chứa đã được theo dõi" @@ -14219,16 +14405,16 @@ msgid "Push objects over Git protocol to another repository" msgstr "Äẩy các đối tượng lên thông qua giao thức Git đến kho chứa khác" msgid "Git's i18n setup code for shell scripts" -msgstr "Mã cà i đặt quốc tế hóa cá»§a Git cho văn lệnh hệ vá»" +msgstr "Mã cà i đặt quốc tế hóa cá»§a Git cho shell script" msgid "Common Git shell script setup code" -msgstr "Mã cà i đặt văn lệnh hệ vá» Git chung" +msgstr "Mã cà i đặt shell script Git chung" msgid "Restricted login shell for Git-only SSH access" -msgstr "Hệ vỠđăng nháºp có hạn chế cho truy cáºp SSH chỉ-Git" +msgstr "Shell đăng nháºp có hạn chế cho truy cáºp SSH chỉ-Git" msgid "Summarize 'git log' output" -msgstr "Kết xuất 'git log' dạng tóm tắt" +msgstr "Tóm tắt kết quả 'git log'" msgid "Show various types of objects" msgstr "Hiển thị các kiểu khác nhau cá»§a các đối tượng" @@ -14248,7 +14434,7 @@ msgstr "" "dõi" msgid "Add file contents to the staging area" -msgstr "Thêm ná»™i dung táºp tin và o vùng bệ phóng" +msgstr "Thêm ná»™i dung táºp tin và o vùng vùng chá»" msgid "Stash the changes in a dirty working directory away" msgstr "Tạm cất Ä‘i các thay đổi trong má»™t thư mục là m việc bẩn" @@ -14266,7 +14452,7 @@ msgid "Bidirectional operation between a Subversion repository and Git" msgstr "Thao tác hai hướng giữ hai kho Subversion và Git" msgid "Switch branches" -msgstr "Các nhánh chuyển" +msgstr "Chuyển sang nhánh khác" msgid "Read, modify and delete symbolic refs" msgstr "Äá»c, sá»a và xóa tham chiếu má»m" @@ -14335,7 +14521,7 @@ msgid "Git for CVS users" msgstr "Git dà nh cho những ngưá»i dùng CVS" msgid "Tweaking diff output" -msgstr "Chỉnh kết xuất diff" +msgstr "Tinh chỉnh đầu ra diff" msgid "A useful minimum set of commands for Everyday Git" msgstr "Táºp hợp lệnh hữu dụng tối thiểu để dùng Git hà ng ngà y" @@ -14478,6 +14664,14 @@ msgstr "đồ-thị-chuyển-giao thiếu chunk OID lookup cần thiết hoặc msgid "commit-graph required commit data chunk missing or corrupted" msgstr "đồ-thị-chuyển-giao thiếu chunk commit data cần thiết hoặc bị há»ng" +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "" +"vô hiệu hoá bá»™ lá»c Bloom cho đồ thị chuyển giao '%s' do tuỳ chá»n không tương " +"thÃch" + msgid "commit-graph has no base graphs chunk" msgstr "đồ thị chuyển giao không có chunk đồ thị cÆ¡ sở" @@ -14604,8 +14798,15 @@ msgstr "Äang hòa trá»™n đồ-thị-chuyển-giao" msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled" msgstr "" -"cố gắng để ghi má»™t đồ thị các lần chuyển giao, nhưng 'core.commitGraph' bị " -"vô hiệu hóa" +"Ä‘ang thá» ghi đồ thị chuyển giao, nhưng 'core.commitGraph' bị vô hiệu hóa" + +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " +"(%d) is not supported" +msgstr "" +"Ä‘ang thá» ghi đồ thị chuyển giao, nhưng 'commitGraph.changedPathsVersion' " +"(%d) không được há»— trợ" msgid "too many commits to write graph" msgstr "có quá nhiá»u lần chuyển giao để ghi đồ thị" @@ -15765,7 +15966,7 @@ msgid "bad --word-diff argument: %s" msgstr "đối số --word-diff sai: %s" msgid "Diff output format options" -msgstr "Các tùy chá»n định dạng khi xuất các khác biệt" +msgstr "Các tùy chá»n định dạng kết quả khác biệt" msgid "generate patch" msgstr "tạo bản vá" @@ -15789,14 +15990,14 @@ msgid "machine friendly --stat" msgstr "--stat thuáºn tiện cho máy Ä‘á»c" msgid "output only the last line of --stat" -msgstr "chỉ xuất những dòng cuối cá»§a --stat" +msgstr "chỉ in ra những dòng cuối cá»§a --stat" msgid "<param1>,<param2>..." msgstr "<tham_số_1>,<tham_số_2>..." msgid "" "output the distribution of relative amount of changes for each sub-directory" -msgstr "đầu ra phân phối cá»§a số lượng thay đổi tương đối cho má»—i thư mục con" +msgstr "in ra phân phối số lượng thay đổi tương đối cho má»—i thư mục con" msgid "synonym for --dirstat=cumulative" msgstr "đồng nghÄ©a vá»›i --dirstat=cumulative" @@ -15845,7 +16046,7 @@ msgid "generate compact summary in diffstat" msgstr "tạo tổng hợp xúc tÃch trong diffstat" msgid "output a binary diff that can be applied" -msgstr "xuất ra má»™t khác biệt dạng nhị phân cái mà có thể được áp dụng" +msgstr "in ra má»™t khác biệt dạng nhị phân có thể được áp dụng" msgid "show full pre- and post-image object names on the \"index\" lines" msgstr "" @@ -15882,7 +16083,7 @@ msgid "show the given destination prefix instead of \"b/\"" msgstr "hiển thị tiá»n tố Ä‘Ãch đã cho thay cho \"b/\"" msgid "prepend an additional prefix to every line of output" -msgstr "treo và o trước má»™t tiá»n tố bổ sung cho má»—i dòng kết xuất" +msgstr "thêm và o trước má»™t tiá»n tố bổ sung cho má»—i dòng đầu ra" msgid "do not show any source or destination prefix" msgstr "đừng hiển thị bất kỳ tiá»n tố nguồn hay Ä‘Ãch" @@ -16023,7 +16224,7 @@ msgid "exit with 1 if there were differences, 0 otherwise" msgstr "thoát vá»›i mã 1 nếu không có khác biệt gì, 0 nếu ngược lại" msgid "disable all output of the program" -msgstr "tắt má»i kết xuất cá»§a chương trình" +msgstr "tắt má»i đầu ra cá»§a chương trình" msgid "allow an external diff helper to be executed" msgstr "cho phép má»™ helper xuất khác biệt ở bên ngoà i được phép thá»±c thi" @@ -16075,7 +16276,7 @@ msgid "treat <string> in -S as extended POSIX regular expression" msgstr "coi <chuá»—i> trong -S là biểu thức chÃnh quy POSIX mở rá»™ng" msgid "control the order in which files appear in the output" -msgstr "Ä‘iá»u khiển thứ tá»± xuất hiện các táºp tin trong đầu ra" +msgstr "Ä‘iá»u khiển thứ tá»± xuất hiện các táºp tin trong kết quả" msgid "<path>" msgstr "<đưá»ng-dẫn>" @@ -16084,7 +16285,7 @@ msgid "show the change in the specified path first" msgstr "hiển thị các thay đổi trong đưá»ng dẫn đã cho ở đầu" msgid "skip the output to the specified path" -msgstr "bá» qua đầu ra vá»›i đưá»ng dẫn đã cho" +msgstr "bá» qua kết quả vá»›i đưá»ng dẫn đã cho" msgid "<object-id>" msgstr "<mã-số-đối-tượng>" @@ -16284,7 +16485,7 @@ msgid "fetch-pack: unable to fork off %s" msgstr "fetch-pack: không thể rẽ nhánh %s" msgid "fetch-pack: invalid index-pack output" -msgstr "fetch-pack: kết xuất index-pack không hợp lệ" +msgstr "fetch-pack: đầu ra index-pack không hợp lệ" #, c-format msgid "%s failed" @@ -16441,19 +16642,23 @@ msgstr "" msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v | --version] [-h | --help] [-C </đưá»ng/dẫn/>] [-c <tên>=<giá trị>]\n" " [--exec-path[=</đưá»ng/dẫn/>]] [--html-path] [--man-path] [--info-" "path]\n" -" [-p | --paginate | -P --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=</đưá»ng/dẫn/>] [--work-tree=</đưá»ng/dẫn/>] [--" -"namespace=<tên>]\n" -" [--config-env=<tên>=<envvar>] <lệnh> [<các tham số>]" +" [-p | --paginate | -P --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=</đưá»ng/" +"dẫn/>]\n" +" [--work-tree=</đưá»ng/dẫn/>] [--namespace=<tên>] [--config-" +"env=<tên>=<envvar>]\n" +" <lệnh> [<các tham số>]" msgid "" "'git help -a' and 'git help -g' list available subcommands and some\n" @@ -16780,16 +16985,16 @@ msgid "" "The '%s' hook was ignored because it's not set as executable.\n" "You can disable this warning with `git config advice.ignoredHook false`." msgstr "" -"Móc '%s' bị bá» qua bởi vì nó không thể đặt là thá»±c thi được.\n" +"Móc '%s' bị bá» qua bởi vì nó không có cá» thá»±c thi được.\n" "Bạn có thể tắt cảnh báo nà y bằng 'git config advice.ignoredHook false'." +msgid "not a git repository" +msgstr "không phải là kho git" + #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "tham số cho --packfile phải là má»™t giá trị băm hợp lệ (có '%s')" -msgid "not a git repository" -msgstr "không phải là kho git" - #, c-format msgid "negative value for http.postBuffer; defaulting to %d" msgstr "giá trị âm cho http.postBuffer; đặt thà nh mặc định là %d" @@ -16800,6 +17005,9 @@ msgstr "Äiá»u khiển giao quyá»n không được há»— trợ vá»›i cURL < 7.2 msgid "Public key pinning not supported with cURL < 7.39.0" msgstr "Chốt khóa công không được há»— trợ vá»›i cURL < 7.39.0" +msgid "Unknown value for http.proactiveauth" +msgstr "không hiểu giá trị cho http.proactiveauth" + msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "CURLSSLOPT_NO_REVOKE không được há»— trợ vá»›i cURL < 7.44.0" @@ -16819,6 +17027,12 @@ msgstr "" msgid "Could not set SSL backend to '%s': already set" msgstr "Không thể đặt ứng dụng chạy sau SSL cho '%s': đã đặt rồi" +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "từ chối Ä‘á»c cookie từ http.cookiefile '-'" + +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "bá» qua tuỳ chá»n http.savecookies vì http.cookiefile để trống" + #, c-format msgid "" "unable to update url base from redirection:\n" @@ -16992,8 +17206,8 @@ msgid "Failed to merge submodule %s (commits not present)" msgstr "Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con %s (lần chuyển giao không hiện diện)" #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" -msgstr "Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con %s (kho chứa há»ng)" +msgid "error: failed to merge submodule %s (repository corrupt)" +msgstr "lá»—i: gặp lá»—i khi hòa trá»™n mô-Ä‘un-con %s (kho chứa há»ng)" #, c-format msgid "Failed to merge submodule %s (commits don't follow merge-base)" @@ -17022,12 +17236,13 @@ msgstr "" "Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con %s, nhưng có nhiá»u cách giải quyết:\n" "%s" -msgid "failed to execute internal merge" -msgstr "Gặp lá»—i khi thá»±c hiện trá»™n ná»™i bá»™" +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "lá»—i: Gặp lá»—i khi thá»±c hiện trá»™n ná»™i bá»™ %s" #, c-format -msgid "unable to add %s to database" -msgstr "Không thể thêm %s và o cÆ¡ sở dữ liệu" +msgid "error: unable to add %s to database" +msgstr "lá»—i: không thể thêm %s và o cÆ¡ sở dữ liệu" #, c-format msgid "Auto-merging %s" @@ -17120,20 +17335,20 @@ msgstr "" "XUNG ÄỘT (đổi-tên/xóa): Äổi tên %s->%s trong %s, nhưng lại bị xóa trong %s." #, c-format -msgid "cannot read object %s" -msgstr "không thể Ä‘á»c đối tượng %s" +msgid "error: cannot read object %s" +msgstr "lá»—i: không thể Ä‘á»c đối tượng %s" #, c-format -msgid "object %s is not a blob" -msgstr "đối tượng %s không phải là má»™t blob" +msgid "error: object %s is not a blob" +msgstr "lá»—i: đối tượng %s không phải là má»™t blob" #, c-format msgid "" "CONFLICT (file/directory): directory in the way of %s from %s; moving it to " "%s instead." msgstr "" -"XUNG ÄỘT (táºp tin/thư mục): thư mục theo cách cá»§a %s từ %s; thay và o đó, di " -"chuyển nó đến %s." +"XUNG ÄỘT (táºp tin/thư mục): thư mục khác nằm trên %s từ %s; thay và o đó sẽ " +"di chuyển nó đến %s." #, c-format msgid "" @@ -17141,15 +17356,15 @@ msgid "" "of them so each can be recorded somewhere." msgstr "" "XUNG ÄỘT (các kiểu riêng biệt): %s có các kiểu khác nhau ở má»—i bên; đã đổi " -"tên cả hai trong số chúng để má»—i cái có thể được ghi lại ở đâu đó." +"tên cả hai để có thể ghi lại cả hai." #, c-format msgid "" "CONFLICT (distinct types): %s had different types on each side; renamed one " "of them so each can be recorded somewhere." msgstr "" -"XUNG ÄỘT (các kiểu riêng biệt): %s có các loại khác nhau ở má»—i bên; đã đổi " -"tên má»™t trong số chúng để má»—i cái có thể được ghi lại ở đâu đó." +"XUNG ÄỘT (các kiểu riêng biệt): %s có các kiểu khác nhau ở má»—i bên; đã đổi " +"tên má»™t trong số chúng để có thể ghi lại cả hai." msgid "content" msgstr "ná»™i dung" @@ -17262,6 +17477,10 @@ msgid "do not know what to do with %06o %s '%s'" msgstr "không hiểu phải là m gì vá»›i %06o %s '%s'" #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con %s (kho chứa há»ng)" + +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "Chuyển-tiếp-nhanh mô-Ä‘un-con '%s' đến lần chuyển giao sau đây:" @@ -17302,6 +17521,13 @@ msgstr "" msgid "Failed to merge submodule %s (multiple merges found)" msgstr "Gặp lá»—i khi hòa trá»™n mô-Ä‘un-con '%s' (thấy nhiá»u hòa trá»™n Ä‘a trùng)" +msgid "failed to execute internal merge" +msgstr "Gặp lá»—i khi thá»±c hiện trá»™n ná»™i bá»™" + +#, c-format +msgid "unable to add %s to database" +msgstr "Không thể thêm %s và o cÆ¡ sở dữ liệu" + #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "" @@ -17405,6 +17631,14 @@ msgstr "" "XUNG ÄỘT (đổi-tên/đổi-tên): Äổi tên thư mục %s->%s trong %s. Äổi tên thư mục " "%s->%s trong %s" +#, c-format +msgid "cannot read object %s" +msgstr "không thể Ä‘á»c đối tượng %s" + +#, c-format +msgid "object %s is not a blob" +msgstr "đối tượng %s không phải là má»™t blob" + msgid "modify" msgstr "sá»a đổi" @@ -17488,9 +17722,6 @@ msgstr "không hiểu cú pháp dòng: %s" msgid "malformed line: %s" msgstr "dòng sai quy cách: %s" -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "bá» qua multi-pack-index sẵn có; tổng kiểm không khá»›p" - msgid "could not load pack" msgstr "không thể tải gói" @@ -17498,6 +17729,9 @@ msgstr "không thể tải gói" msgid "could not open index for %s" msgstr "không thể mở chỉ mục cho %s" +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "bá» qua multi-pack-index sẵn có; tổng kiểm không khá»›p" + msgid "Adding packfiles to multi-pack-index" msgstr "Äang thêm táºp tin gói từ multi-pack-index" @@ -18103,6 +18337,17 @@ msgstr "không thể Ä‘á»c đối tượng: '%s'" msgid "hash mismatch %s" msgstr "mã băm không khá»›p %s" +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "đối tượng trùng lặp khi ghi chỉ mục bitmap: %s" + +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "đã cố ghi lần chuyển giao không được chá»n: '%s'" + +msgid "too many pseudo-merges" +msgstr "có quá nhiá»u lần pseudo-merge" + msgid "trying to write commit not in index" msgstr "đã thá» ghi lần chuyển giao nằm ngoà i chỉ mục" @@ -18125,6 +18370,17 @@ msgstr "táºp tin chỉ mục bitmap bị há»ng (quá ngắn để chứa bá»™ msgid "corrupted bitmap index file (too short to fit lookup table)" msgstr "táºp tin chỉ mục bitmap bị há»ng (quá ngắn để chứa bảng tìm kiếm)" +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "" +"táºp tin chỉ mục bitmap bị há»ng (quá ngắn để chứa đỠmục bảng pseudo-merge)" + +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "táºp tin chỉ mục bitmap bị há»ng (quá ngắn để chứa bảng pseudo-merge)" + +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "táºp tin chỉ mục bitmap bị há»ng, bảng pseudo-merge quá ngắn" + #, c-format msgid "duplicate entry in bitmap index: '%s'" msgstr "đối tượng trùng lặp trong bitmap: '%s'" @@ -18215,6 +18471,10 @@ msgid "mismatch in bitmap results" msgstr "kết quả bitmap không khá»›p" #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "chỉ mục pseudo-merge vượt ngoà i phạm vi (%<PRIu32> >= %<PRIuMAX>)" + +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "không thể tìm thấy '%s' trong gói '%s' tại vị trà %<PRIuMAX>" @@ -18579,6 +18839,9 @@ msgstr "không thể tạo tiến trình lstat: %s" msgid "unable to parse --pretty format" msgstr "không thể Ä‘á»c định dạng --pretty" +msgid "lazy fetching disabled; some objects may not be available" +msgstr "vô hiệu lazy fetching; má»™t số đối tượng sẽ không có sẵn" + msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "promisor-remote: không thể rẽ nhánh tuyến trình con fetch" @@ -18602,6 +18865,62 @@ msgstr "object-info: cần đẩy dữ liệu lên đĩa sau các tham số" msgid "Removing duplicate objects" msgstr "Äang gỡ các đối tượng trùng lặp" +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "gặp lá»—i khi Ä‘á»c biểu thức chÃnh quy pseudo-merge cho %s: '%s'" + +#, c-format +msgid "%s must be non-negative, using default" +msgstr "%s phải không âm, dùng mặc định thay thế" + +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "%s nên giữa 0 và 1, dùng mặc định thay thế" + +#, c-format +msgid "%s must be positive, using default" +msgstr "%s phải dương, dùng mặc định thay thế" + +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "nhóm pseudo-merge '%s' thiếu mẫu bắt buá»™c" + +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "nhóm pseudo-merge '%s' có unstable threshold trước stable" + +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "" +"biểu thức chÃnh quy pseudo-merge từ cấu hình có quá nhiá»u nhóm chá»n (tối " +"Ä‘a=%<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "extended pseudo-merge Ä‘á»c ngoà i biên (%<PRIuMAX> >= %<PRIuMAX>)" + +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "mục extended pseudo-merge quá ngắn (%<PRIuMAX> >= %<PRIuMAX>)" + +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "" +"không thể tìm pseudo-merge cho lần chuyển giao %s tại vị trà %<PRIuMAX>" + +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "extended pseudo-merge lookup vượt ngoà i biên (%<PRIu32> >= %<PRIu32>)" + +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "Ä‘á»c ngoà i biên (%<PRIuMAX> >= %<PRIuMAX>)" + +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "không thể Ä‘á»c bảng extended pseudo-merge cho lần chuyển giao %s" + msgid "could not start `log`" msgstr "không thể khởi chạy `log`" @@ -18844,7 +19163,7 @@ msgstr "" " chỉ giữ ghi chú cá»§a lần chuyển giao nà y; -c giống như -C " "nhưng\n" " mở trình biên soạn\n" -"x, exec <commit> = chạy lệnh (phần còn lại cá»§a dòng) dùng hệ vá»\n" +"x, exec <commit> = chạy lệnh (phần còn lại cá»§a dòng) dùng shell\n" "b, break = dừng tại đây (tiếp tục cải tổ sau nà y bằng 'git rebase --" "continue')\n" "d, drop <commit> = xóa bá» lần chuyển giao\n" @@ -19206,11 +19525,18 @@ msgstr "nháºt ký cho tham chiếu %s kết thúc bất ngá» trên %s" msgid "log for %s is empty" msgstr "nháºt ký cho %s trống rá»—ng" +msgid "refusing to force and skip creation of reflog" +msgstr "từ chối bá» qua việc tạo log tham chiếu" + #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "từ chối cáºp nháºt tham chiếu vá»›i tên sai '%s'" #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "từ chối cáºp nháºt tham chiếu ảo '%s'" + +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "update_ref bị lá»—i cho ref '%s': %s" @@ -19241,6 +19567,25 @@ msgid "could not delete references: %s" msgstr "không thể xóa bá» tham chiếu: %s" #, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "Äã hoà n thà nh thá» chạy di cư tham chiếu, kết quả tại '%s'\n" + +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "không thể xoá thư mục tạm thá»i '%s'" + +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "ydam chiếu đã di cư tại '%s'" + +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "" +"không thể lock tham chiếu '%s': cần tham chiếu má»m tá»›i '%s': nhưng lại là " +"tham chiếu thưá»ng" + +#, c-format msgid "refname is dangerous: %s" msgstr "tên tham chiếu không an toà n: %s" @@ -19599,7 +19944,7 @@ msgstr "không thể tìm thấy tham chiếu máy chá»§ %s" #, c-format msgid "* Ignoring funny ref '%s' locally" -msgstr "* Äang bá» qua tham chiếu thú vị ná»™i bá»™ '%s'" +msgstr "* Äang bá» qua tham chiếu ná»™i bá»™ '%s'" #, c-format msgid "Your branch is based on '%s', but the upstream is gone.\n" @@ -20062,9 +20407,9 @@ msgid "" "To abort and get back to the state before \"git rebase\", run \"git rebase --" "abort\"." msgstr "" -"Giải quyết vấn đỠnà y thá»§ công, hãy Ä‘anh dấu chúng đã được giải quyết bằng\n" -"hãy chạy lệnh \"git add/rm <các_táºp tin_xung_đột>\", sau đó chạy \"git " -"rebase --continue\".\n" +"Hãy giải quyết vấn đỠnà y bằng tay, đánh dấu chúng đã được giải quyết bằng\n" +"lệnh \"git add/rm <các_táºp tin_xung_đột>\", sau đó chạy \"git rebase --" +"continue\".\n" "Bạn có thể bá» qua bản vá, chạy \"git rebase --skip\".\n" "Äể huá»· bá» và quay trở lại trạng thái trước \"git rebase\", chạy \"git rebase " "--abort\"." @@ -20183,7 +20528,7 @@ msgid "" "\n" " git rebase --continue\n" msgstr "" -"bạn có các thay đổi so vá»›i trong bệ phóng trong thư mục là m việc cá»§a bạn.\n" +"bạn có các thay đổi so vá»›i trong vùng chá» trong thư mục là m việc cá»§a bạn.\n" "Nếu các thay đổi nà y là muốn squash và o lần chuyển giao kế trước, chạy:\n" "\n" " git commit --amend %s\n" @@ -20397,6 +20742,47 @@ msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s" msgstr "update-ref yêu cầu tên tham chiếu đầy đủ v.d. refs/heads/%s" #, c-format +msgid "'%s' does not accept merge commits" +msgstr "'%s' không nháºn đối số lần chuyển giao hoà trá»™n" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"'pick' không cho phép dùng lần chuyển giao hoà trá»™n. Nếu như cần phát lại\n" +"lần hoà trá»™n, hà y dùng 'merge -C'." + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"'reword' không cho phép dùng lần chuyển giao hoà trá»™n. Nếu như cần phát lại\n" +"lần hoà trá»™n và sá»a ná»™i dung, hãy dùng 'merge -c'." + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"'pick' không cho phép dùng lần chuyển giao hoà trá»™n. Nếu như cần phát lại\n" +"lần hoà trá»™n, hà y dùng 'merge -C', sau đó 'break' để dùng lệnh\n" +"'git commit --amend && git rebase --continue'." + +msgid "cannot squash merge commit into another commit" +msgstr "không thể squash lần chuyển giao hoà trá»™n và o lần chuyển giao khác" + +#, c-format msgid "invalid command '%.*s'" msgstr "lệnh không hợp lệ '%.*s'" @@ -20512,9 +20898,8 @@ msgstr "" msgid "cannot read HEAD" msgstr "không thể Ä‘á»c HEAD" -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "không thể sao chép '%s' sang '%s'" +msgid "could not write commit message file" +msgstr "không thể ghi táºp tin chú thÃch lần chuyển giao" #, c-format msgid "" @@ -20744,7 +21129,7 @@ msgid "Successfully rebased and updated %s.\n" msgstr "Cà i tổ và cáºp nháºt %s má»™t cách thà nh công.\n" msgid "cannot rebase: You have unstaged changes." -msgstr "không thể cải tổ: Bạn có các thay đổi chưa được đưa lên bệ phóng." +msgstr "không thể cải tổ: Bạn có các thay đổi chưa được đưa và o vùng chá»." msgid "cannot amend non-existing commit" msgstr "không thể tu sá»a lần chuyển giao không tồn tại" @@ -20774,7 +21159,7 @@ msgid "could not remove CHERRY_PICK_HEAD" msgstr "không thể xóa bá» CHERRY_PICK_HEAD" msgid "could not commit staged changes." -msgstr "không thể chuyển giao các thay đổi đã đưa lên bệ phóng." +msgstr "không thể chuyển giao các thay đổi đã đưa và o vùng chá»." #, c-format msgid "%s: can't cherry-pick a %s" @@ -20915,6 +21300,18 @@ msgstr "không thể quay lại thư mục là m việc hiện hà nh" msgid "failed to stat '%*s%s%s'" msgstr "gặp lá»—i khi stat'%*s%s%s'" +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"kho lưu trữ '%s' thuá»™c sở hữu cá»§a ngưá»i khác\n" +"%sÄể thêm ngoại lệ cho thư mục nà y, hãy gá»i:\n" +"\n" +"\tgit config --global --add safe.directory %s" + msgid "Unable to read current working directory" msgstr "Không thể Ä‘á»c thư mục là m việc hiện hà nh" @@ -20937,18 +21334,6 @@ msgstr "" "được đặt)." #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"kho lưu trữ '%s' thuá»™c sở hữu cá»§a ngưá»i khác\n" -"%sÄể thêm ngoại lệ cho thư mục nà y, hãy gá»i:\n" -"\n" -"\tgit config --global --add safe.directory %s" - -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" msgstr "không thể dùng kho chứa bare '%s' (safe.bareRepository là '%s')" @@ -21249,6 +21634,15 @@ msgid "submodule git dir '%s' is inside git dir '%.*s'" msgstr "thư mục git mô Ä‘un con '%s' là bên trong git DIR '%.*s'" #, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "" +"cần '%.*s' trong đưá»ng dẫn tá»›i mô-Ä‘un-con '%s' không phải là liên kết má»m" + +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "cần đưá»ng dẫn tá»›i mô-Ä‘un-con '%s' không phải là liên kết má»m" + +#, c-format msgid "" "relocate_gitdir for submodule '%s' with more than one worktree not supported" msgstr "" @@ -21287,10 +21681,6 @@ msgstr "gặp lá»—i khi lstat '%s'" msgid "no remote configured to get bundle URIs from" msgstr "không có máy chá»§ để lấy URI bundle" -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "máy chá»§ '%s' không có cấu hình URL" - msgid "could not get the bundle-uri list" msgstr "không thể lấy vá» danh sách bundle-uri" @@ -21915,7 +22305,7 @@ msgid "error: unable to format message: %s\n" msgstr "lá»—i: không thể định dạng thông Ä‘iệp: %s\n" msgid "usage: " -msgstr "cách dùng: %s" +msgstr "cách dùng: " msgid "fatal: " msgstr "lá»—i nghiêm trá»ng: " @@ -22033,7 +22423,7 @@ msgid "Unmerged paths:" msgstr "Những đưá»ng dẫn chưa được hòa trá»™n:" msgid " (use \"git restore --staged <file>...\" to unstage)" -msgstr " (dùng \"git restore --staged <táºp-tin>...\" để bá» ra khá»i bệ phóng)" +msgstr " (dùng \"git restore --staged <táºp-tin>...\" để bá» ra khá»i vùng chá»)" #, c-format msgid " (use \"git restore --source=%s --staged <file>...\" to unstage)" @@ -22042,7 +22432,7 @@ msgstr "" "phóng)" msgid " (use \"git rm --cached <file>...\" to unstage)" -msgstr " (dùng \"git rm --cached <táºp-tin>...\" để bá» ra khá»i bệ phóng)" +msgstr " (dùng \"git rm --cached <táºp-tin>...\" để bá» ra khá»i vùng chá»)" msgid " (use \"git add <file>...\" to mark resolution)" msgstr " (dùng \"git add <táºp-tin>...\" để đánh dấu là muốn thêm)" @@ -22057,7 +22447,7 @@ msgid "Changes to be committed:" msgstr "Những thay đổi sẽ được chuyển giao:" msgid "Changes not staged for commit:" -msgstr "Các thay đổi chưa được đặt lên bệ phóng để chuyển giao:" +msgstr "Các thay đổi chưa được đặt và o vùng chỠđể chuyển giao:" msgid " (use \"git add <file>...\" to update what will be committed)" msgstr "" @@ -22465,7 +22855,7 @@ msgstr "đứng trước " #. TRANSLATORS: the action is e.g. "pull with rebase" #, c-format msgid "cannot %s: You have unstaged changes." -msgstr "không thể %s: Bạn có các thay đổi chưa được đưa lên bệ phóng." +msgstr "không thể %s: Bạn có các thay đổi chưa được đưa và o vùng chá»." msgid "additionally, your index contains uncommitted changes." msgstr "ngoà i ra, chỉ mục cá»§a bạn có chứa các thay đổi chưa được chuyển giao." @@ -22526,11 +22916,11 @@ msgstr "" msgid "Cannot rewrite branches: You have unstaged changes." msgstr "" -"Không thể ghi lại các nhánh: Bạn có các thay đổi chưa được đưa lên bệ phóng." +"Không thể ghi lại các nhánh: Bạn có các thay đổi chưa được đưa và o vùng chá»." #, sh-format msgid "Cannot $action: You have unstaged changes." -msgstr "Không thể $action: Bạn có các thay đổi chưa được đưa lên bệ phóng." +msgstr "Không thể $action: Bạn có các thay đổi chưa được đưa và o vùng chá»." #, sh-format msgid "Cannot $action: Your index contains uncommitted changes." @@ -22751,7 +23141,7 @@ msgstr "" #. translation. The program will only accept English input #. at this point. msgid "Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): " -msgstr "Gá»i email nà y chứ? ([y]có|[n]không|[e]sá»a|[q]thoát|[a]tất): " +msgstr "Gá»i email nà y chứ? ([y]có|[n]không|[e]sá»a|[q]thoát|[a]tất cả): " msgid "Send this email reply required" msgstr "Hãy trả lá»i yêu cầu gá»i email" @@ -22776,24 +23166,24 @@ msgid "Failed to send %s\n" msgstr "Gặp lá»—i khi gá»i %s\n" #, perl-format -msgid "Dry-Sent %s\n" -msgstr "Thá» gá»i %s\n" +msgid "Dry-Sent %s" +msgstr "Thá» gá»i %s" #, perl-format -msgid "Sent %s\n" -msgstr "Gá»i %s\n" +msgid "Sent %s" +msgstr "Gá»i %s" -msgid "Dry-OK. Log says:\n" -msgstr "Thá» gá»i OK. Nháºt ký ghi lại:\n" +msgid "Dry-OK. Log says:" +msgstr "Thá» gá»i OK. Nháºt ký ghi lại:" -msgid "OK. Log says:\n" -msgstr "OK. Nháºt ký ghi lại:\n" +msgid "OK. Log says:" +msgstr "OK. Nháºt ký ghi lại:" msgid "Result: " msgstr "Kết quả: " -msgid "Result: OK\n" -msgstr "Kết quả: OK\n" +msgid "Result: OK" +msgstr "Kết quả: OK" #, perl-format msgid "can't open file %s" diff --git a/po/zh_CN.po b/po/zh_CN.po index 4838c19b0b..91b8b79de8 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -154,8 +154,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-28 19:59+0800\n" -"PO-Revision-Date: 2024-04-28 20:31+0800\n" +"POT-Creation-Date: 2024-07-27 22:28+0800\n" +"PO-Revision-Date: 2024-07-28 19:52+0800\n" "Last-Translator: Teng Long <dyroneteng@gmail.com>\n" "Language-Team: GitHub <https://github.com/dyrone/git/>\n" "Language: zh_CN\n" @@ -252,12 +252,12 @@ msgstr[1] "å¢žåŠ äº† %d 个路径\n" msgid "ignoring unmerged: %s" msgstr "忽略未åˆå…¥çš„:%s" -#: add-interactive.c add-patch.c +#: add-interactive.c #, c-format msgid "Only binary files changed.\n" msgstr "åªæœ‰äºŒè¿›åˆ¶æ–‡ä»¶è¢«ä¿®æ”¹ã€‚\n" -#: add-interactive.c add-patch.c +#: add-interactive.c #, c-format msgid "No changes.\n" msgstr "没有修改。\n" @@ -799,6 +799,11 @@ msgstr "" "? - 显示帮助\n" #: add-patch.c +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "é¢„æœŸåªæœ‰ä¸€ä¸ªå—æ¯ï¼Œå¾—到 '%s'" + +#: add-patch.c msgid "No previous hunk" msgstr "没有å‰ä¸€ä¸ªå—" @@ -861,9 +866,22 @@ msgid "Sorry, cannot edit this hunk" msgstr "对ä¸èµ·ï¼Œä¸èƒ½ç¼–辑这个å—" #: add-patch.c +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "未知命令 '%s'(使用 '?' 寻求帮助)" + +#: add-patch.c msgid "'git apply' failed" msgstr "'git apply' 失败" +#: add-patch.c +msgid "No changes." +msgstr "没有修改。" + +#: add-patch.c +msgid "Only binary files changed." +msgstr "åªæœ‰äºŒè¿›åˆ¶æ–‡ä»¶è¢«ä¿®æ”¹ã€‚" + #: advice.c #, c-format msgid "" @@ -1036,7 +1054,7 @@ msgid "unclosed quote" msgstr "未关é—的引å·" #: alias.c builtin/cat-file.c builtin/notes.c builtin/prune-packed.c -#: builtin/receive-pack.c builtin/tag.c t/helper/test-pkt-line.c +#: builtin/receive-pack.c builtin/refs.c builtin/tag.c t/helper/test-pkt-line.c msgid "too many arguments" msgstr "å¤ªå¤šå‚æ•°" @@ -1918,6 +1936,10 @@ msgid "ignoring overly large gitattributes blob '%s'" msgstr "忽略过大的 gitattributes æ•°æ®å¯¹è±¡ '%s'" #: attr.c +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "æ— æ³•åœ¨æ²¡æœ‰å˜å‚¨åº“的情况下使用 --attr-source 或 GIT_ATTR_SOURCE" + +#: attr.c msgid "bad --attr-source or GIT_ATTR_SOURCE" msgstr "错误的 --attr-source 或 GIT_ATTR_SOURCE" @@ -2278,14 +2300,6 @@ msgid "Unstaged changes after refreshing the index:" msgstr "刷新索引之åŽå°šæœªè¢«æš‚å˜çš„å˜æ›´ï¼š" #: builtin/add.c -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"设置 add.interactive.useBuiltin å·²ç»è¢«ç§»é™¤ï¼\n" -"查看 'git help config' ä¸çš„相关æ¡ç›®ä»¥èŽ·å–æ›´å¤šä¿¡æ¯ã€‚" - -#: builtin/add.c msgid "could not read the index" msgstr "ä¸èƒ½è¯»å–索引" @@ -2720,7 +2734,7 @@ msgid "" "Not rewinding to ORIG_HEAD" msgstr "您好åƒåœ¨ä¸Šä¸€æ¬¡ 'am' 失败åŽç§»åŠ¨äº† HEAD。未回退至 ORIG_HEAD" -#: builtin/am.c builtin/bisect.c worktree.c +#: builtin/am.c builtin/bisect.c builtin/tag.c worktree.c #, c-format msgid "failed to read '%s'" msgstr "æ— æ³•è¯»å– '%s'" @@ -2798,8 +2812,8 @@ msgstr "n" #: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c #: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c -#: builtin/ls-files.c builtin/ls-tree.c builtin/replace.c builtin/tag.c -#: builtin/verify-tag.c +#: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c +#: builtin/tag.c builtin/verify-tag.c msgid "format" msgstr "æ ¼å¼" @@ -2836,6 +2850,10 @@ msgid "show the patch being applied" msgstr "显示æ£åœ¨åº”用的补ä¸" #: builtin/am.c +msgid "try to apply current patch again" +msgstr "å°è¯•冿¬¡åº”用当å‰è¡¥ä¸" + +#: builtin/am.c msgid "record the empty patch as an empty commit" msgstr "把空补ä¸è®°å½•为空æäº¤" @@ -2907,10 +2925,6 @@ msgid "could not redirect output" msgstr "ä¸èƒ½é‡å®šå‘输出" #: builtin/archive.c -msgid "git archive: Remote with no URL" -msgstr "git archive:未æä¾›è¿œç¨‹ URL" - -#: builtin/archive.c msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "git archive:期望是 ACK/NAK,å´å¾—到 flush 包" @@ -4024,6 +4038,10 @@ msgstr "需è¦ä¸€ä¸ªä»“库æ¥åˆ›å»ºå½’档包。" msgid "do not show bundle details" msgstr "䏿˜¾ç¤ºå½’档包的细节" +#: builtin/bundle.c bundle.c +msgid "need a repository to verify a bundle" +msgstr "需è¦ä¸€ä¸ªä»“åº“æ¥æ ¡éªŒä¸€ä¸ªå½’档包" + #: builtin/bundle.c #, c-format msgid "%s is okay\n" @@ -5064,9 +5082,9 @@ msgstr "äº¤äº’å¼æ¸…除" msgid "remove whole directories" msgstr "åˆ é™¤æ•´ä¸ªç›®å½•" -#: builtin/clean.c builtin/describe.c builtin/grep.c builtin/log.c -#: builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c builtin/show-ref.c -#: ref-filter.h +#: builtin/clean.c builtin/config.c builtin/describe.c builtin/grep.c +#: builtin/log.c builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c +#: builtin/show-ref.c ref-filter.h msgid "pattern" msgstr "模å¼" @@ -5284,6 +5302,16 @@ msgstr "æ— æ³•åˆ é™¤ '%s'" #: builtin/clone.c #, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "æ— æ³•æ£€æŸ¥ '%s' 处的硬链接" + +#: builtin/clone.c +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "硬链接与 '%s' 处的æºä¸åŒ" + +#: builtin/clone.c +#, c-format msgid "failed to create link '%s'" msgstr "æ— æ³•åˆ›å»ºé“¾æŽ¥ '%s'" @@ -5358,7 +5386,7 @@ msgstr "å¤ªå¤šå‚æ•°ã€‚" msgid "You must specify a repository to clone." msgstr "您必须指定一个仓库æ¥å…‹éš†ã€‚" -#: builtin/clone.c builtin/init-db.c setup.c +#: builtin/clone.c builtin/init-db.c builtin/refs.c setup.c #, c-format msgid "unknown ref storage format '%s'" msgstr "未知的引用å˜å‚¨æ ¼å¼ '%s'" @@ -5967,7 +5995,7 @@ msgstr "%sæäº¤è€…:%.*s <%.*s>" msgid "Cannot read index" msgstr "æ— æ³•è¯»å–索引" -#: builtin/commit.c +#: builtin/commit.c builtin/tag.c msgid "unable to pass trailers to --trailers" msgstr "æ— æ³•å°†å°¾æ³¨ä¼ é€’ç»™ --trailers" @@ -6177,11 +6205,11 @@ msgstr "ä½¿ç”¨è‡ªåŠ¨æŒ¤åŽ‹æ ¼å¼çš„æäº¤è¯´æ˜Žç”¨ä»¥æŒ¤åŽ‹è‡³æŒ‡å®šçš„æäº¤" msgid "the commit is authored by me now (used with -C/-c/--amend)" msgstr "现在将该æäº¤çš„作者改为我(和 -C/-c/--amend 傿•°å…±ç”¨ï¼‰" -#: builtin/commit.c builtin/interpret-trailers.c +#: builtin/commit.c builtin/interpret-trailers.c builtin/tag.c msgid "trailer" msgstr "尾注" -#: builtin/commit.c +#: builtin/commit.c builtin/tag.c msgid "add custom trailer(s)" msgstr "æ·»åŠ è‡ªå®šä¹‰å°¾æ³¨" @@ -6293,17 +6321,57 @@ msgstr "" "ç£ç›˜é…é¢å·²è€—å°½ï¼Œç„¶åŽæ‰§è¡Œ \"git restore --staged :/\" æ¢å¤ã€‚" #: builtin/config.c -msgid "git config [<options>]" -msgstr "git config [<选项>]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "git config list [<文件选项>] [<显示选项>] [--includes]" #: builtin/config.c -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "未能识别的 --type 傿•°ï¼Œ%s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [<文件选项>] [<显示选项>] [--includes] [--all] [--regexp=<æ£åˆ™" +"表达å¼>] [--value=<值>] [--fixed-value] [--default=<默认值>] <åç§°>" #: builtin/config.c -msgid "only one type at a time" -msgstr "一次åªèƒ½ä¸€ä¸ªç±»åž‹" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [<文件选项>] [--type=<类型>] [--all] [--value=<值>] [--fixed-" +"value] <åç§°> <值>" + +#: builtin/config.c +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [<文件选项>] [--all] [--value=<值>] [--fixed-value] <åç§°> <" +"值>" + +#: builtin/config.c +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "git config rename-section [<文件选项>] <æ—§åç§°> <æ–°åç§°>" + +#: builtin/config.c +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [<文件选项>] <åç§°>" + +#: builtin/config.c +msgid "git config edit [<file-option>]" +msgstr "git config edit [<文件选项>]" + +#: builtin/config.c +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "git config [<文件选项>] --get-colorbool <åç§°> [<æ ‡å‡†è¾“å‡ºä¸ºtty>]" + +#: builtin/config.c +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [<文件选项>] [--type=<类型>] [--comment=<消æ¯>] [--all] [--" +"value=<值>] [--fixed-value] <åç§°> <值>" #: builtin/config.c msgid "Config file location" @@ -6338,70 +6406,6 @@ msgid "read config from given blob object" msgstr "从给定的数æ®å¯¹è±¡è¯»å–é…ç½®" #: builtin/config.c -msgid "Action" -msgstr "æ“作" - -#: builtin/config.c -msgid "get value: name [value-pattern]" -msgstr "获å–值:åç§° [值模å¼]" - -#: builtin/config.c -msgid "get all values: key [value-pattern]" -msgstr "获得所有的值:键 [值模å¼]" - -#: builtin/config.c -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "æ ¹æ®æ£åˆ™è¡¨è¾¾å¼èŽ·å¾—å€¼ï¼šåç§°æ£åˆ™ [值模å¼]" - -#: builtin/config.c -msgid "get value specific for the URL: section[.var] URL" -msgstr "获得 URL å–值:section[.var] URL" - -#: builtin/config.c -msgid "replace all matching variables: name value [value-pattern]" -msgstr "æ›¿æ¢æ‰€æœ‰åŒ¹é…çš„å˜é‡ï¼šåç§° 值 [值模å¼]" - -#: builtin/config.c -msgid "add a new variable: name value" -msgstr "æ·»åŠ ä¸€ä¸ªæ–°çš„å˜é‡ï¼šåç§° 值" - -#: builtin/config.c -msgid "remove a variable: name [value-pattern]" -msgstr "åˆ é™¤ä¸€ä¸ªå˜é‡ï¼šåç§° [值模å¼]" - -#: builtin/config.c -msgid "remove all matches: name [value-pattern]" -msgstr "åˆ é™¤æ‰€æœ‰åŒ¹é…项:åç§° [值模å¼]" - -#: builtin/config.c -msgid "rename section: old-name new-name" -msgstr "é‡å‘½åå°èŠ‚ï¼šold-name new-name" - -#: builtin/config.c -msgid "remove a section: name" -msgstr "åˆ é™¤ä¸€ä¸ªå°èŠ‚ï¼šname" - -#: builtin/config.c -msgid "list all" -msgstr "列出所有" - -#: builtin/config.c -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "在比较值与 '值模å¼' 时,使用å—符串å—颿¯”较" - -#: builtin/config.c -msgid "open an editor" -msgstr "打开一个编辑器" - -#: builtin/config.c -msgid "find the color configured: slot [default]" -msgstr "获得é…置的颜色:é…ç½® [默认]" - -#: builtin/config.c -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "获得颜色设置:é…ç½® [stdout-is-tty]" - -#: builtin/config.c msgid "Type" msgstr "类型" @@ -6438,8 +6442,8 @@ msgid "value is an expiry date" msgstr "值是一个到期日期" #: builtin/config.c -msgid "Other" -msgstr "其它" +msgid "Display options" +msgstr "显示选项" #: builtin/config.c msgid "terminate values with NUL byte" @@ -6450,10 +6454,6 @@ msgid "show variable names only" msgstr "åªæ˜¾ç¤ºå˜é‡å" #: builtin/config.c -msgid "respect include directives on lookup" -msgstr "查询时å‚ç…§ include 指令递归查找" - -#: builtin/config.c msgid "show origin of config (file, standard input, blob, command line)" msgstr "显示é…ç½®çš„æ¥æºï¼ˆæ–‡ä»¶ã€æ ‡å‡†è¾“å…¥ã€æ•°æ®å¯¹è±¡ï¼Œæˆ–命令行)" @@ -6462,16 +6462,17 @@ msgid "show scope of config (worktree, local, global, system, command)" msgstr "显示é…ç½®çš„ä½œç”¨åŸŸï¼ˆå·¥ä½œåŒºã€æœ¬åœ°ã€å…¨å±€ã€ç³»ç»Ÿã€å‘½ä»¤ï¼‰" #: builtin/config.c -msgid "value" -msgstr "å–值" +msgid "show config keys in addition to their values" +msgstr "显示é…置键åŠå…¶å€¼" #: builtin/config.c -msgid "with --get, use default value when missing entry" -msgstr "使用 --get 傿•°ï¼Œå½“缺少设置时使用默认值" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "未能识别的 --type 傿•°ï¼Œ%s" #: builtin/config.c -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "人类å¯è¯»çš„æ³¨é‡Šå—符串(# å°†æ ¹æ®éœ€è¦æ·»åŠ åˆ°å‰é¢ï¼‰" +msgid "only one type at a time" +msgstr "一次åªèƒ½ä¸€ä¸ªç±»åž‹" #: builtin/config.c #, c-format @@ -6564,56 +6565,93 @@ msgstr "" "详情请阅读“git help worktreeâ€çš„“CONFIGURATION FILEâ€å°èŠ‚" #: builtin/config.c -msgid "--get-color and variable type are incoherent" -msgstr "--get-color å’Œå˜é‡ç±»åž‹ä¸å…¼å®¹" +msgid "Other" +msgstr "其它" #: builtin/config.c -msgid "only one action at a time" -msgstr "一次åªèƒ½æœ‰ä¸€ä¸ªåŠ¨ä½œ" +msgid "respect include directives on lookup" +msgstr "查询时å‚ç…§ include 指令递归查找" #: builtin/config.c -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "--name-only 仅适用于 --list 或 --get-regexp" +#, c-format +msgid "unable to read config file '%s'" +msgstr "æ— æ³•è¯»å–é…置文件 '%s'" #: builtin/config.c -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" -msgstr "--show-origin 仅适用于 --getã€--get-allã€--get-regexp å’Œ --list" +msgid "error processing config file(s)" +msgstr "处ç†é…置文件出错" #: builtin/config.c -msgid "--default is only applicable to --get" -msgstr "--default 仅适用于 --get" +msgid "Filter options" +msgstr "过滤选项" #: builtin/config.c -msgid "--comment is only applicable to add/set/replace operations" -msgstr "--comment 仅适用于 add/set/replace æ“作" +msgid "return all values for multi-valued config options" +msgstr "返回多值é…置选项的所有值" + +#: builtin/config.c +msgid "interpret the name as a regular expression" +msgstr "å°†å称解释为æ£åˆ™è¡¨è¾¾å¼" + +#: builtin/config.c +msgid "show config with values matching the pattern" +msgstr "显示值与模å¼åŒ¹é…çš„é…ç½®" + +#: builtin/config.c +msgid "use string equality when comparing values to value pattern" +msgstr "在将值与值模å¼è¿›è¡Œæ¯”较时使用å—ç¬¦ä¸²ç›¸ç‰æ€§" + +#: builtin/config.c +msgid "URL" +msgstr "URL" + +#: builtin/config.c +msgid "show config matching the given URL" +msgstr "显示与给定 URL 匹é…çš„é…ç½®" + +#: builtin/config.c +msgid "value" +msgstr "值" + +#: builtin/config.c +msgid "use default value when missing entry" +msgstr "缺少æ¡ç›®æ—¶ä½¿ç”¨é»˜è®¤å€¼" #: builtin/config.c msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value 仅适用于有 '值模å¼'" #: builtin/config.c -#, c-format -msgid "unable to read config file '%s'" -msgstr "æ— æ³•è¯»å–é…置文件 '%s'" +msgid "--default= cannot be used with --all or --url=" +msgstr "--default= ä¸èƒ½ä¸Ž --all 或 --url= 一起使用" #: builtin/config.c -msgid "error processing config file(s)" -msgstr "处ç†é…置文件出错" +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "--url= ä¸èƒ½ä¸Ž --allã€--regexp 或 --value 一起使用" #: builtin/config.c -msgid "editing stdin is not supported" -msgstr "䏿”¯æŒç¼–è¾‘æ ‡å‡†è¾“å…¥" +msgid "Filter" +msgstr "过滤器" #: builtin/config.c -msgid "editing blobs is not supported" -msgstr "䏿”¯æŒç¼–辑数æ®å¯¹è±¡" +msgid "replace multi-valued config option with new value" +msgstr "将多值é…置选项替æ¢ä¸ºæ–°å€¼" #: builtin/config.c -#, c-format -msgid "cannot create configuration file %s" -msgstr "ä¸èƒ½åˆ›å»ºé…置文件 %s" +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "人类å¯è¯»çš„æ³¨é‡Šå—符串(# å°†æ ¹æ®éœ€è¦æ·»åŠ åˆ°å‰é¢ï¼‰" + +#: builtin/config.c +msgid "add a new line without altering any existing values" +msgstr "æ·»åŠ æ–°è¡Œè€Œä¸æ›´æ”¹ä»»ä½•现有值" + +#: builtin/config.c +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "--fixed-value åªèƒ½ä¸Ž --value=<模å¼> é…åˆä½¿ç”¨" + +#: builtin/config.c +msgid "--append cannot be used with --value=<pattern>" +msgstr "--append ä¸èƒ½ä¸Ž --value=<模å¼> 一起使用" #: builtin/config.c #, c-format @@ -6629,6 +6667,109 @@ msgstr "" msgid "no such section: %s" msgstr "æ— æ¤å°èŠ‚ï¼š%s" +#: builtin/config.c +msgid "editing stdin is not supported" +msgstr "䏿”¯æŒç¼–è¾‘æ ‡å‡†è¾“å…¥" + +#: builtin/config.c +msgid "editing blobs is not supported" +msgstr "䏿”¯æŒç¼–辑数æ®å¯¹è±¡" + +#: builtin/config.c +#, c-format +msgid "cannot create configuration file %s" +msgstr "ä¸èƒ½åˆ›å»ºé…置文件 %s" + +#: builtin/config.c +msgid "Action" +msgstr "æ“作" + +#: builtin/config.c +msgid "get value: name [<value-pattern>]" +msgstr "获å–值:name [<值模å¼>]" + +#: builtin/config.c +msgid "get all values: key [<value-pattern>]" +msgstr "èŽ·å–æ‰€æœ‰å€¼ï¼škey [<值模å¼>]" + +#: builtin/config.c +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "èŽ·å–æ£åˆ™è¡¨è¾¾å¼çš„值:name-regex [<值模å¼>]" + +#: builtin/config.c +msgid "get value specific for the URL: section[.var] URL" +msgstr "获得 URL å–值:section[.var] URL" + +#: builtin/config.c +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "æ›¿æ¢æ‰€æœ‰åŒ¹é…çš„å˜é‡ï¼šname value [<值模å¼>]" + +#: builtin/config.c +msgid "add a new variable: name value" +msgstr "æ·»åŠ ä¸€ä¸ªæ–°çš„å˜é‡ï¼šåç§° 值" + +#: builtin/config.c +msgid "remove a variable: name [<value-pattern>]" +msgstr "åˆ é™¤ä¸€ä¸ªå˜é‡ï¼šåç§° [<值模å¼>]" + +#: builtin/config.c +msgid "remove all matches: name [<value-pattern>]" +msgstr "åˆ é™¤æ‰€æœ‰åŒ¹é…项:åç§° [<值模å¼>]" + +#: builtin/config.c +msgid "rename section: old-name new-name" +msgstr "é‡å‘½åå°èŠ‚ï¼šold-name new-name" + +#: builtin/config.c +msgid "remove a section: name" +msgstr "åˆ é™¤ä¸€ä¸ªå°èŠ‚ï¼šname" + +#: builtin/config.c +msgid "list all" +msgstr "列出所有" + +#: builtin/config.c +msgid "open an editor" +msgstr "打开编辑器" + +#: builtin/config.c +msgid "find the color configured: slot [<default>]" +msgstr "找到é…置的颜色:slot [<默认>]" + +#: builtin/config.c +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "找到颜色设置:slot [<stdout-is-tty>]" + +#: builtin/config.c +msgid "with --get, use default value when missing entry" +msgstr "使用 --get 傿•°ï¼Œå½“缺少设置时使用默认值" + +#: builtin/config.c +msgid "--get-color and variable type are incoherent" +msgstr "--get-color å’Œå˜é‡ç±»åž‹ä¸å…¼å®¹" + +#: builtin/config.c +msgid "no action specified" +msgstr "未指定任何æ“作" + +#: builtin/config.c +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "--name-only 仅适用于 --list 或 --get-regexp" + +#: builtin/config.c +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "--show-origin 仅适用于 --getã€--get-allã€--get-regexp å’Œ --list" + +#: builtin/config.c +msgid "--default is only applicable to --get" +msgstr "--default 仅适用于 --get" + +#: builtin/config.c +msgid "--comment is only applicable to add/set/replace operations" +msgstr "--comment 仅适用于 add/set/replace æ“作" + #: builtin/count-objects.c msgid "print sizes in human readable format" msgstr "以用户å¯è¯»çš„æ ¼å¼æ˜¾ç¤ºå¤§å°" @@ -7655,6 +7796,10 @@ msgid "config key storing a list of repository paths" msgstr "å˜å‚¨ç€ä»“库路径列表的é…置项键å" #: builtin/for-each-repo.c +msgid "keep going even if command fails in a repository" +msgstr "å³ä½¿å˜å‚¨åº“ä¸çš„命令失败,ä»ç»§ç»æ‰§è¡Œ" + +#: builtin/for-each-repo.c msgid "missing --config=<config>" msgstr "缺少 --config=<é…ç½®>" @@ -9489,8 +9634,12 @@ msgid "max length of output filename" msgstr "输出文件å的最大长度" #: builtin/log.c -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "使用 [RFC PATCH] 代替 [PATCH]" +msgid "rfc" +msgstr "RFC" + +#: builtin/log.c +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "在 'PATCH' 之剿·»åŠ <RFC> (默认为 'RFC')" #: builtin/log.c msgid "cover-from-description-mode" @@ -9834,11 +9983,11 @@ msgstr "" #: builtin/ls-remote.c msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<坿‰§è¡Œæ–‡ä»¶>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<坿‰§è¡Œæ–‡ä»¶>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<é”®>]\n" " [--symref] [<仓库> [<模å¼>...]]" @@ -9859,9 +10008,13 @@ msgid "limit to tags" msgstr "ä»…é™äºŽæ ‡ç¾" #: builtin/ls-remote.c -msgid "limit to heads" +msgid "limit to branches" msgstr "ä»…é™äºŽåˆ†æ”¯" +#: builtin/ls-remote.c builtin/show-ref.c +msgid "deprecated synonym for --branches" +msgstr "已弃用的 --branches åŒä¹‰è¯" + #: builtin/ls-remote.c msgid "do not show peeled tags" msgstr "䏿˜¾ç¤ºå·²è§£æžçš„æ ‡ç¾" @@ -13048,6 +13201,27 @@ msgstr "未指定è¦åˆ 除的引用日志" msgid "invalid ref format: %s" msgstr "æ— æ•ˆçš„å¼•ç”¨æ ¼å¼ï¼š%s" +#: builtin/refs.c +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=<æ ¼å¼> [--dry-run]" + +#: builtin/refs.c +msgid "specify the reference format to convert to" +msgstr "指定è¦è½¬æ¢çš„å¼•ç”¨æ ¼å¼" + +#: builtin/refs.c +msgid "perform a non-destructive dry-run" +msgstr "进行éžç ´å性的试è¿è¡Œï¼ˆdry-run)" + +#: builtin/refs.c +msgid "missing --ref-format=<format>" +msgstr "缺少 --ref-format=<æ ¼å¼>" + +#: builtin/refs.c +#, c-format +msgid "repository already uses '%s' format" +msgstr "仓库已使用 '%s' æ ¼å¼" + #: builtin/remote.c msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" @@ -13392,10 +13566,6 @@ msgstr "* 远程 %s" msgid " Fetch URL: %s" msgstr " 获å–地å€ï¼š%s" -#: builtin/remote.c -msgid "(no URL)" -msgstr "(æ— URL)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -13406,6 +13576,10 @@ msgid " Push URL: %s" msgstr " 推é€åœ°å€ï¼š%s" #: builtin/remote.c +msgid "(no URL)" +msgstr "(æ— URL)" + +#: builtin/remote.c #, c-format msgid " HEAD branch: %s" msgstr " HEAD 分支:%s" @@ -13542,11 +13716,6 @@ msgid "return all URLs" msgstr "返回所有 URL 地å€" #: builtin/remote.c -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "没有给远程仓库 '%s' 设定 URL" - -#: builtin/remote.c msgid "manipulate push URLs" msgstr "æ“ä½œæŽ¨é€ URLS" @@ -14793,12 +14962,12 @@ msgstr "未知的哈希算法" #: builtin/show-ref.c msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<模å¼>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<模å¼>...]" #: builtin/show-ref.c msgid "" @@ -14827,12 +14996,12 @@ msgid "failed to look up reference" msgstr "æ— æ³•æ‰¾åˆ°å¼•ç”¨" #: builtin/show-ref.c -msgid "only show tags (can be combined with heads)" -msgstr "åªæ˜¾ç¤ºæ ‡ç¾ï¼ˆå¯ä»¥å’Œå¤´å…±ç”¨ï¼‰" +msgid "only show tags (can be combined with branches)" +msgstr "ä»…æ˜¾ç¤ºæ ‡ç¾ï¼ˆå¯ä¸Žåˆ†æ”¯ç»„åˆä½¿ç”¨ï¼‰" #: builtin/show-ref.c -msgid "only show heads (can be combined with tags)" -msgstr "åªæ˜¾ç¤ºå¤´ï¼ˆå¯ä»¥å’Œæ ‡ç¾å…±ç”¨ï¼‰" +msgid "only show branches (can be combined with tags)" +msgstr "仅显示分支(å¯ä»¥å’Œæ ‡ç¾ç»„åˆä½¿ç”¨ï¼‰" #: builtin/show-ref.c msgid "check for reference existence without resolving" @@ -15579,20 +15748,20 @@ msgstr "ä¸èƒ½è¯†åˆ« submodule.alternateErrorStrategy çš„å–值 '%s'" msgid "Value '%s' for submodule.alternateLocation is not recognized" msgstr "ä¸èƒ½è¯†åˆ« submodule.alternateLocation çš„å–值 '%s'" -#: builtin/submodule--helper.c +#: builtin/submodule--helper.c submodule.c #, c-format msgid "refusing to create/use '%s' in another submodule's git dir" msgstr "æ‹’ç»åœ¨å¦ä¸€ä¸ªå模组的 git 目录ä¸åˆ›å»º/使用 '%s'" #: builtin/submodule--helper.c #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "æ— æ³•å…‹éš† '%s' åˆ°åæ¨¡ç»„路径 '%s'" +msgid "directory not empty: '%s'" +msgstr "目录éžç©ºï¼š'%s'" #: builtin/submodule--helper.c #, c-format -msgid "directory not empty: '%s'" -msgstr "目录éžç©ºï¼š'%s'" +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "æ— æ³•å…‹éš† '%s' åˆ°åæ¨¡ç»„路径 '%s'" #: builtin/submodule--helper.c #, c-format @@ -16033,9 +16202,11 @@ msgstr "æ›´æ–°çš„åŽŸå› " #: builtin/tag.c msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" -"git tag [-a | -s | -u <ç§é’¥ ID>] [-f] [-m <消æ¯> | -F <文件>] [-e]\n" +"git tag [-a | -s | -u <ç§é’¥ id>] [-f] [-m <消æ¯> | -F <文件>] [-e]\n" +" [(--trailer <令牌>[(=|:)<值>])...]\n" " <æ ‡ç¾å> [<æäº¤> | <对象>]" #: builtin/tag.c @@ -17080,10 +17251,6 @@ msgid "Repository lacks these prerequisite commits:" msgstr "仓库ä¸ç¼ºå°‘这些必备的æäº¤ï¼š" #: bundle.c -msgid "need a repository to verify a bundle" -msgstr "需è¦ä¸€ä¸ªä»“åº“æ¥æ ¡éªŒä¸€ä¸ªå½’档包" - -#: bundle.c msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -17604,6 +17771,10 @@ msgid "Manage reflog information" msgstr "ç®¡ç† reflog ä¿¡æ¯" #: command-list.h +msgid "Low-level access to refs" +msgstr "对引用的低级访问" + +#: command-list.h msgid "Manage set of tracked repositories" msgstr "管ç†å·²è·Ÿè¸ªä»“库" @@ -18000,6 +18171,13 @@ msgid "commit-graph required commit data chunk missing or corrupted" msgstr "æäº¤å›¾æ‰€éœ€çš„æäº¤æ•°æ®å—缺失或æŸå" #: commit-graph.c +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "由于ä¸å…¼å®¹çš„设置,æ£åœ¨ç¦ç”¨æäº¤å›¾å±‚ '%s' 的布隆过滤器" + +#: commit-graph.c msgid "commit-graph has no base graphs chunk" msgstr "æäº¤å›¾æ²¡æœ‰åŸºç¡€å›¾å½¢å—" @@ -18159,6 +18337,13 @@ msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled" msgstr "æ£å°è¯•写æäº¤å›¾ï¼Œä½†æ˜¯ 'core.commitGraph' 被ç¦ç”¨" #: commit-graph.c +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph.changedPathsVersion' " +"(%d) is not supported" +msgstr "å°è¯•写入æäº¤å›¾ï¼Œä½†ä¸æ”¯æŒ 'commitGraph.changedPathsVersion' (%d)" + +#: commit-graph.c msgid "too many commits to write graph" msgstr "æäº¤å¤ªå¤šä¸èƒ½ç”»å›¾" @@ -20418,16 +20603,19 @@ msgstr "å› ä¸ºç¼ºå°‘ Unix å¥—æŽ¥å—æ”¯æŒï¼Œå¥—接å—目录 '%s' 与 fsmonitor ä msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v | --version] [-h | --help] [-C <路径>] [-c <åç§°>=<å–值>]\n" " [--exec-path[=<路径>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<路径>] [--work-tree=<路径>] [--namespace=<åç§°>]\n" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [\"--" +"no-lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<路径>]\n" +" [--work-tree=<路径>] [--namespace=<åç§°>]\n" " [--config-env=<åç§°>=<环境å˜é‡>] <命令> [<傿•°>]" #: git.c @@ -20834,14 +21022,14 @@ msgstr "" "é…ç½® `git config advice.ignoredHook false` æ¥å…³é—è¿™æ¡è¦å‘Šã€‚" #: http-fetch.c +msgid "not a git repository" +msgstr "䏿˜¯ git 仓库" + +#: http-fetch.c #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "--packfile çš„å‚æ•°å¿…须是有效的哈希值(得到 '%s')" -#: http-fetch.c -msgid "not a git repository" -msgstr "䏿˜¯ git 仓库" - #: http.c #, c-format msgid "negative value for http.postBuffer; defaulting to %d" @@ -20856,6 +21044,10 @@ msgid "Public key pinning not supported with cURL < 7.39.0" msgstr "䏿”¯æŒå…¬é’¥æ–‡ä»¶é”å®šï¼Œå› ä¸º cURL < 7.39.0" #: http.c +msgid "Unknown value for http.proactiveauth" +msgstr "http.proactiveauth 为未知å–值" + +#: http.c msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "䏿”¯æŒ CURLSSLOPT_NO_REVOKEï¼Œå› ä¸º cURL < 7.44.0" @@ -20875,6 +21067,14 @@ msgid "Could not set SSL backend to '%s': already set" msgstr "æ— æ³•å°† SSL åŽç«¯è®¾ç½®ä¸º '%s':已ç»è®¾ç½®" #: http.c +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "æ‹’ç»ä»Ž http.cookiefile '-' è¯»å– cookies" + +#: http.c +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "å› ä¸º http.cookiefile 为空,忽略 http.savecookies" + +#: http.c #, c-format msgid "" "unable to update url base from redirection:\n" @@ -21080,10 +21280,10 @@ msgstr "æ— æ³•åˆå¹¶å模组 %s (没有åˆå¹¶åŸºçº¿ï¼‰" msgid "Failed to merge submodule %s (commits not present)" msgstr "æ— æ³•åˆå¹¶å模组 %s(æäº¤ä¸å˜åœ¨ï¼‰" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" -msgstr "æ— æ³•åˆå¹¶å模组 %s(仓库æŸå)" +msgid "error: failed to merge submodule %s (repository corrupt)" +msgstr "é”™è¯¯ï¼šæ— æ³•åˆå¹¶å模组 %s(仓库æŸå)" #: merge-ort.c merge-recursive.c #, c-format @@ -21115,14 +21315,15 @@ msgstr "" "æ— æ³•åˆå¹¶å模组 %s,但是å˜åœ¨å¤šä¸ªå¯èƒ½çš„åˆå¹¶ï¼š\n" "%s" -#: merge-ort.c merge-recursive.c -msgid "failed to execute internal merge" -msgstr "æ— æ³•æ‰§è¡Œå†…éƒ¨åˆå¹¶" +#: merge-ort.c +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "é”™è¯¯ï¼šæ— æ³•ä¸º %s 执行内部åˆå¹¶" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "unable to add %s to database" -msgstr "ä¸èƒ½æ·»åŠ %s 至对象库" +msgid "error: unable to add %s to database" +msgstr "错误:ä¸èƒ½æ·»åŠ %s 至对象库" #: merge-ort.c merge-recursive.c #, c-format @@ -21220,15 +21421,15 @@ msgstr "" msgid "CONFLICT (rename/delete): %s renamed to %s in %s, but deleted in %s." msgstr "冲çªï¼ˆé‡å‘½å/åˆ é™¤ï¼‰ï¼š%1$s 在 %3$s ä¸é‡å‘½å为 %2$s,但在 %4$s ä¸åˆ 除。" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "cannot read object %s" -msgstr "ä¸èƒ½è¯»å–对象 %s" +msgid "error: cannot read object %s" +msgstr "错误:ä¸èƒ½è¯»å–对象 %s" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "object %s is not a blob" -msgstr "对象 %s 䏿˜¯ä¸€ä¸ªæ•°æ®å¯¹è±¡" +msgid "error: object %s is not a blob" +msgstr "错误:对象 %s 䏿˜¯ä¸€ä¸ªæ•°æ®å¯¹è±¡" #: merge-ort.c #, c-format @@ -21384,6 +21585,11 @@ msgstr "ä¸çŸ¥é“å¦‚ä½•å¤„ç† %06o %s '%s'" #: merge-recursive.c #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "æ— æ³•åˆå¹¶å模组 %s(仓库æŸå)" + +#: merge-recursive.c +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "忍¡ç»„ %s 快进到如下æäº¤ï¼š" @@ -21428,6 +21634,15 @@ msgid "Failed to merge submodule %s (multiple merges found)" msgstr "æ— æ³•åˆå¹¶å模组 %s (å‘现多个åˆå¹¶ï¼‰" #: merge-recursive.c +msgid "failed to execute internal merge" +msgstr "æ— æ³•æ‰§è¡Œå†…éƒ¨åˆå¹¶" + +#: merge-recursive.c +#, c-format +msgid "unable to add %s to database" +msgstr "ä¸èƒ½æ·»åŠ %s 至对象库" + +#: merge-recursive.c #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "错误:拒ç»ä¸¢å¤±æœªè·Ÿè¸ªæ–‡ä»¶ '%s',而是写入 %s。" @@ -21541,6 +21756,16 @@ msgstr "" "%4$s->%5$s" #: merge-recursive.c +#, c-format +msgid "cannot read object %s" +msgstr "ä¸èƒ½è¯»å–对象 %s" + +#: merge-recursive.c +#, c-format +msgid "object %s is not a blob" +msgstr "对象 %s 䏿˜¯ä¸€ä¸ªæ•°æ®å¯¹è±¡" + +#: merge-recursive.c msgid "modify" msgstr "修改" @@ -21645,10 +21870,6 @@ msgid "malformed line: %s" msgstr "æ ¼å¼é”™è¯¯çš„行:%s" #: midx-write.c -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "忽略已å˜åœ¨çš„å¤šåŒ…ç´¢å¼•ï¼Œæ ¡éªŒç ä¸åŒ¹é…" - -#: midx-write.c msgid "could not load pack" msgstr "ä¸èƒ½è½½å…¥åŒ…" @@ -21658,6 +21879,10 @@ msgid "could not open index for %s" msgstr "ä¸èƒ½æ‰“å¼€ %s 的索引" #: midx-write.c +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "忽略已å˜åœ¨çš„å¤šåŒ…ç´¢å¼•ï¼Œæ ¡éªŒç ä¸åŒ¹é…" + +#: midx-write.c msgid "Adding packfiles to multi-pack-index" msgstr "æ·»åŠ åŒ…æ–‡ä»¶åˆ°å¤šåŒ…ç´¢å¼•" @@ -22394,6 +22619,20 @@ msgid "hash mismatch %s" msgstr "哈希值与 %s ä¸åŒ¹é…" #: pack-bitmap-write.c +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "写入ä½å›¾ç´¢å¼•æ—¶å˜åœ¨é‡å¤æ¡ç›®ï¼š'%s'" + +#: pack-bitmap-write.c +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "å°è¯•å˜å‚¨æœªé€‰å®šçš„æäº¤ï¼š'%s'" + +#: pack-bitmap-write.c +msgid "too many pseudo-merges" +msgstr "太多伪åˆå¹¶" + +#: pack-bitmap-write.c msgid "trying to write commit not in index" msgstr "å°è¯•写入未在索引ä¸çš„æäº¤" @@ -22423,6 +22662,19 @@ msgid "corrupted bitmap index file (too short to fit lookup table)" msgstr "æŸåçš„ä½å›¾ç´¢å¼•(太å°ï¼Œå®¹ä¸ä¸‹æŸ¥è¯¢è¡¨ï¼‰" #: pack-bitmap.c +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "æŸåçš„ä½å›¾ç´¢å¼•文件(太çŸè€Œæ— 法容纳伪åˆå¹¶è¡¨å¤´ï¼‰" + +#: pack-bitmap.c +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "æŸåçš„ä½å›¾ç´¢å¼•(太çŸè€Œæ— 法容纳伪åˆå¹¶è¡¨ï¼‰" + +#: pack-bitmap.c +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "æŸåçš„ä½å›¾ç´¢å¼•,伪åˆå¹¶è¡¨è¿‡çŸ" + +#: pack-bitmap.c #, c-format msgid "duplicate entry in bitmap index: '%s'" msgstr "ä½å›¾ç´¢å¼•ä¸çš„é‡å¤æ¡ç›®ï¼š'%s'" @@ -22537,6 +22789,11 @@ msgstr "ä½å›¾ç»“æžœä¸ä¸€è‡´" #: pack-bitmap.c #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "伪åˆå¹¶ç´¢å¼•超出范围 (%<PRIu32> >= %<PRIuMAX>)" + +#: pack-bitmap.c +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "æ— æ³•åœ¨åŒ… '%2$s' åç§» %3$<PRIuMAX> 䏿‰¾åˆ° '%1$s'" @@ -22988,6 +23245,10 @@ msgid "unable to parse --pretty format" msgstr "ä¸èƒ½è§£æž --pretty æ ¼å¼" #: promisor-remote.c +msgid "lazy fetching disabled; some objects may not be available" +msgstr "ç¦ç”¨å»¶è¿ŸèŽ·å–,æŸäº›å¯¹è±¡å¯èƒ½ä¸å¯ç”¨" + +#: promisor-remote.c msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "promisor-remoteï¼šæ— æ³•æ´¾ç”Ÿ fetch å进程" @@ -23017,6 +23278,72 @@ msgstr "object-infoï¼šåœ¨å‚æ•°ä¹‹åŽåº”有一个 flush" msgid "Removing duplicate objects" msgstr "æ£åœ¨åˆ 除é‡å¤å¯¹è±¡" +#: pseudo-merge.c +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "æœªèƒ½åŠ è½½ %s 的伪åˆå¹¶æ£åˆ™è¡¨è¾¾å¼ï¼š'%s'" + +#: pseudo-merge.c +#, c-format +msgid "%s must be non-negative, using default" +msgstr "%s 必须为éžè´Ÿæ•´æ•°ï¼Œä½¿ç”¨é»˜è®¤å€¼" + +#: pseudo-merge.c +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "%s 必须介于 0 到 1 之间,使用默认值" + +#: pseudo-merge.c +#, c-format +msgid "%s must be positive, using default" +msgstr "%s å¿…é¡»ä¸ºæ£æ•°ï¼Œä½¿ç”¨é»˜è®¤å€¼" + +#: pseudo-merge.c +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "伪åˆå¹¶ç»„ '%s' 缺少所需的模å¼" + +#: pseudo-merge.c +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "伪åˆå¹¶ç»„ '%s' åœ¨ç¨³å®šé˜ˆå€¼ä¹‹å‰æœ‰ä¸ç¨³å®šé˜ˆå€¼" + +#: pseudo-merge.c +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "æ¥è‡ª config 的伪åˆå¹¶æ£åˆ™è¡¨è¾¾å¼æœ‰å¤ªå¤šçš„æ•èŽ·ç»„ï¼ˆæœ€å¤š %<PRIuMAX> 个)" + +#: pseudo-merge.c +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "扩展伪åˆå¹¶è¯»å–越界 (%<PRIuMAX> >= %<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "扩展伪åˆå¹¶æ¡ç›®å¤ªçŸï¼ˆ%<PRIuMAX> >= %<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "æ— æ³•åœ¨æäº¤ %1$s çš„åç§» %2$<PRIuMAX> 䏿‰¾åˆ°ä¼ªåˆå¹¶" + +#: pseudo-merge.c +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "扩展伪åˆå¹¶æŸ¥æ‰¾è¶Šç•Œ (%<PRIu32> >= %<PRIu32>)" + +#: pseudo-merge.c +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "越界读å–:(%<PRIuMAX> >= %<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "æ— æ³•è¯»å–æäº¤ %s 的扩展伪åˆå¹¶è¡¨" + #: range-diff.c msgid "could not start `log`" msgstr "ä¸èƒ½å¯åЍ `log`" @@ -23726,12 +24053,21 @@ msgid "log for %s is empty" msgstr "%s 的日志为空" #: refs.c +msgid "refusing to force and skip creation of reflog" +msgstr "æ‹’ç»æ—¢å¼ºåˆ¶åˆè·³è¿‡åˆ›å»ºå¼•用日志" + +#: refs.c #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "æ‹’ç»æ›´æ–°æœ‰é”™è¯¯åç§° '%s' 的引用" #: refs.c #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "æ‹’ç»æ›´æ–°ä¼ªå¼•用 '%s'" + +#: refs.c +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "对引用 '%s' 执行 update_ref 失败:%s" @@ -23768,6 +24104,27 @@ msgstr "æ— æ³•åˆ é™¤å¼•ç”¨ %s:%s" msgid "could not delete references: %s" msgstr "æ— æ³•åˆ é™¤å¼•ç”¨ï¼š%s" +#: refs.c +#, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "å·²å®Œæˆ refs 的试è¿è¡Œè¿ç§»ï¼Œç»“æžœå¯åœ¨ '%s' 处找到\n" + +#: refs.c +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "æ— æ³•åˆ é™¤ä¸´æ—¶è¿ç§»ç›®å½• '%s'" + +#: refs.c +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "è¿ç§»çš„引用å¯ä»¥åœ¨ '%s' 处找到" + +#: refs/files-backend.c refs/reftable-backend.c +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "æ— æ³•é”定引用 '%s'ï¼šé¢„æœŸç›®æ ‡ä¸º '%s' 的符å·å¼•用:但是是普通引用" + #: refs/reftable-backend.c #, c-format msgid "refname is dangerous: %s" @@ -25159,6 +25516,53 @@ msgstr "update-ref 需è¦ä¸€ä¸ªå®Œæ•´çš„引用å,例如:refs/heads/%s" #: sequencer.c #, c-format +msgid "'%s' does not accept merge commits" +msgstr "'%s' 䏿ޥå—åˆå¹¶æäº¤" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +#: sequencer.c +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"'pick' 䏿ޥå—åˆå¹¶æäº¤ã€‚如果您想è¦é‡æ”¾åˆå¹¶ï¼Œ\n" +"请在æäº¤ä¸Šä½¿ç”¨ 'merge -C'。" + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +#: sequencer.c +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"'reword' 䏿ޥå—åˆå¹¶æäº¤ã€‚å¦‚æžœæ‚¨æƒ³é‡æ”¾åˆå¹¶å¹¶é‡å†™æäº¤æ¶ˆæ¯ï¼Œ\n" +"请在æäº¤ä¸Šä½¿ç”¨ 'merge -c'" + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +#: sequencer.c +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"'editâ€' 䏿ޥå—åˆå¹¶æäº¤ã€‚如果您想è¦é‡æ”¾åˆå¹¶ï¼Œ\n" +"请在æäº¤ä¸Šä½¿ç”¨ 'merge -C',然åŽä½¿ç”¨ 'break'\n" +"将控制æƒäº¤è¿˜ç»™æ‚¨ï¼Œä»¥ä¾¿æ‚¨å¯ä»¥æ‰§è¡Œ\n" +"'git commit --amend && git rebase --continue'。" + +#: sequencer.c +msgid "cannot squash merge commit into another commit" +msgstr "æ— æ³•å°†åˆå¹¶æäº¤åŽ‹ç¼©åˆ°å¦ä¸€ä¸ªæäº¤ä¸" + +#: sequencer.c +#, c-format msgid "invalid command '%.*s'" msgstr "æ— æ•ˆå‘½ä»¤ '%.*s'" @@ -25307,9 +25711,8 @@ msgid "cannot read HEAD" msgstr "ä¸èƒ½è¯»å– HEAD" #: sequencer.c -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "æ— æ³•æ‹·è´ '%s' 至 '%s'" +msgid "could not write commit message file" +msgstr "æ— æ³•å†™å…¥æäº¤è¯´æ˜Žæ–‡ä»¶" #: sequencer.c #, c-format @@ -25788,6 +26191,19 @@ msgid "failed to stat '%*s%s%s'" msgstr "æ— æ³•èŽ·å– '%*s%s%s' 状æ€ï¼ˆstat)" #: setup.c +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"在 '%s' 检测到å¯ç–‘的仓库所有æƒ\n" +"%sè¦ä¸ºæœ¬ä»“库创建特例,请è¿è¡Œï¼š\n" +"\n" +"\tgit config --global --add safe.directory %s" + +#: setup.c msgid "Unable to read current working directory" msgstr "ä¸èƒ½è¯»å–当å‰å·¥ä½œç›®å½•" @@ -25812,19 +26228,6 @@ msgstr "" #: setup.c #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"在 '%s' 检测到å¯ç–‘的仓库所有æƒ\n" -"%sè¦ä¸ºæœ¬ä»“库创建特例,请è¿è¡Œï¼š\n" -"\n" -"\tgit config --global --add safe.directory %s" - -#: setup.c -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" msgstr "æ— æ³•ä½¿ç”¨çº¯ä»“åº“ '%s' (safe.bareRepository 为 '%s')" @@ -26189,6 +26592,16 @@ msgstr "忍¡ç»„ git 目录 '%s' ä½äºŽ git 目录 '%.*s' ä¸" #: submodule.c #, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "æœŸæœ›åæ¨¡ç»„的父目录 '%.*s' 䏿˜¯ä¸€ä¸ªç¬¦å·é“¾æŽ¥ï¼Œå模组路径为 '%s'" + +#: submodule.c +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "é¢„æœŸåæ¨¡ç»„路径 '%s' 䏿˜¯ç¬¦å·é“¾æŽ¥" + +#: submodule.c +#, c-format msgid "" "relocate_gitdir for submodule '%s' with more than one worktree not supported" msgstr "䏿”¯æŒå¯¹æœ‰å¤šä¸ªå·¥ä½œåŒºçš„忍¡ç»„ '%s' 执行 relocate_gitdir" @@ -26233,11 +26646,6 @@ msgid "no remote configured to get bundle URIs from" msgstr "没有远程被设置为å¯ä»¥èŽ·å–归档包 URI" #: t/helper/test-bundle-uri.c -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "远程 '%s' 没有设置 URL" - -#: t/helper/test-bundle-uri.c msgid "could not get the bundle-uri list" msgstr "æ— æ³•èŽ·å– bundle-uri 列表" @@ -28025,29 +28433,29 @@ msgstr "æ— æ³•å‘é€ %s\n" #: git-send-email.perl #, perl-format -msgid "Dry-Sent %s\n" -msgstr "æ¼”ä¹ å‘é€ %s\n" +msgid "Dry-Sent %s" +msgstr "æ¼”ä¹ å‘é€ %s" #: git-send-email.perl #, perl-format -msgid "Sent %s\n" -msgstr "æ£å‘é€ %s\n" +msgid "Sent %s" +msgstr "å·²å‘é€ %s" #: git-send-email.perl -msgid "Dry-OK. Log says:\n" -msgstr "æ¼”ä¹ æˆåŠŸã€‚æ—¥å¿—è¯´ï¼š\n" +msgid "Dry-OK. Log says:" +msgstr "æ¼”ä¹ æˆåŠŸã€‚æ—¥å¿—è¯´ï¼š" #: git-send-email.perl -msgid "OK. Log says:\n" -msgstr "OK。日志说:\n" +msgid "OK. Log says:" +msgstr "æˆåŠŸã€‚æ—¥å¿—è¯´ï¼š" #: git-send-email.perl msgid "Result: " msgstr "结果:" #: git-send-email.perl -msgid "Result: OK\n" -msgstr "结果:OK\n" +msgid "Result: OK" +msgstr "结果:æˆåŠŸ" #: git-send-email.perl #, perl-format diff --git a/po/zh_TW.po b/po/zh_TW.po index f554381a7a..abf7157a99 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -21,14 +21,17 @@ # # Yi-Jyun Pan <pan93412@gmail.com>, 2021, 2022, 2023, 2024. # Kaiyang Wu <self@origincode.me>, 2022. -# lumynou5 <lumynou5.tw@gmail.com>, 2023, 2024. +# Lumynous <lumynou5.tw@gmail.com>, 2023, 2024. # Kisaragi Hiu <mail@kisaragi-hiu.com>, 2024. +# Ngoo Ka-iu <willy04wu69@gmail.com>, 2024. +# Nightfeather Chen <slat@nightfeather.me>, 2024. +# hms5232 <hms5232@hhming.moe>, 2024. msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2024-04-28 18:52+0800\n" -"PO-Revision-Date: 2024-04-28 18:44+0800\n" +"POT-Creation-Date: 2024-07-19 15:00+0800\n" +"PO-Revision-Date: 2024-07-24 08:21+0000\n" "Last-Translator: Yi-Jyun Pan <pan93412@gmail.com>\n" "Language-Team: Chinese (Traditional) <http://weblate.slat.org/projects/git-" "po/git-cli/zh_Hant/>\n" @@ -37,7 +40,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 3.4.2\n" +"X-Generator: Weblate 5.6.2\n" "X-ZhConverter: ç¹åŒ–姬 dict-f4bc617e-r910 @ 2019/11/16 20:23:12 | https://" "zhconvert.org\n" @@ -69,7 +72,7 @@ msgstr "æ›´æ–°" #: add-interactive.c #, c-format msgid "could not stage '%s'" -msgstr "ç„¡æ³•æš«å˜ â€œ%sâ€" +msgstr "無法暫å˜ã€Œ%sã€" #: add-interactive.c builtin/stash.c reset.c sequencer.c msgid "could not write index" @@ -89,7 +92,7 @@ msgstr "註:ç¾å·²ä¸å†è¿½è¹¤ %s。\n" #: add-interactive.c apply.c builtin/checkout.c builtin/reset.c #, c-format msgid "make_cache_entry failed for path '%s'" -msgstr "å° â€œ%s†路徑執行 make_cache_entry 失敗" +msgstr "å°ã€Œ%sã€è·¯å¾‘執行 make_cache_entry 失敗" #: add-interactive.c msgid "Revert" @@ -125,12 +128,12 @@ msgstr[0] "å·²åŠ å…¥ %d 個路徑\n" msgid "ignoring unmerged: %s" msgstr "忽略未åˆä½µé …目:%s" -#: add-interactive.c add-patch.c +#: add-interactive.c #, c-format msgid "Only binary files changed.\n" msgstr "åªæœ‰äºŒé€²ä½æª”案更動了。\n" -#: add-interactive.c add-patch.c +#: add-interactive.c #, c-format msgid "No changes.\n" msgstr "沒有更動。\n" @@ -543,7 +546,7 @@ msgstr "" #: add-patch.c #, c-format msgid "could not parse hunk header '%.*s'" -msgstr "無法解æžå€å¡Šæ¨™é “%.*sâ€" +msgstr "無法解æžå€å¡Šæ¨™é 「%.*sã€" #: add-patch.c msgid "could not parse diff" @@ -556,7 +559,7 @@ msgstr "無法解æžä¸Šè‰²éŽçš„差異" #: add-patch.c #, c-format msgid "failed to run '%s'" -msgstr "無法執行 “%sâ€" +msgstr "無法執行「%sã€" #: add-patch.c msgid "mismatched output from interactive.diffFilter" @@ -625,7 +628,7 @@ msgstr "無法解æžå€å¡Šæ¨™é " #: add-patch.c msgid "'git apply --cached' failed" -msgstr "“git apply --cached†失敗" +msgstr "「git apply --cachedã€å¤±æ•—" #. TRANSLATORS: do not translate [y/n] #. The program will only accept that input at this point. @@ -636,7 +639,7 @@ msgstr "“git apply --cached†失敗" #: add-patch.c msgid "" "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? " -msgstr "未套用您編輯的å€å¡Šã€‚是å¦é‡æ–°ç·¨è¼¯ï¼ˆè¼¸å…¥ “noâ€ æ¨æ£„ï¼ï¼‰ [y/n]? " +msgstr "未套用您編輯的å€å¡Šã€‚是å¦é‡æ–°ç·¨è¼¯ï¼ˆè¼¸å…¥ã€Œnoã€æ¨æ£„ï¼ï¼‰ [y/n]? " #: add-patch.c msgid "The selected hunks do not apply to the index!" @@ -675,6 +678,11 @@ msgstr "" "? - 顯示說明\n" #: add-patch.c +#, c-format +msgid "Only one letter is expected, got '%s'" +msgstr "é æœŸæ”¶åˆ°ä¸€å€‹å—æ¯ï¼Œå»æ”¶åˆ°ã€Œ%sã€" + +#: add-patch.c msgid "No previous hunk" msgstr "沒有上一個å€å¡Š" @@ -697,7 +705,7 @@ msgstr "跳轉到哪個å€å¡Š? " #: add-patch.c #, c-format msgid "Invalid number: '%s'" -msgstr "無效數å—:“%sâ€" +msgstr "無效數å—:「%sã€" #: add-patch.c #, c-format @@ -736,8 +744,21 @@ msgid "Sorry, cannot edit this hunk" msgstr "å°ä¸èµ·ï¼Œç„¡æ³•編輯這個å€å¡Š" #: add-patch.c +#, c-format +msgid "Unknown command '%s' (use '?' for help)" +msgstr "未知命令「%sã€ï¼ˆä½¿ç”¨ã€Œ?ã€ç²å–幫助)" + +#: add-patch.c msgid "'git apply' failed" -msgstr "“git apply†失敗" +msgstr "「git applyã€å¤±æ•—" + +#: add-patch.c +msgid "No changes." +msgstr "沒有更動。" + +#: add-patch.c +msgid "Only binary files changed." +msgstr "åªæœ‰äºŒé€²ä½æª”案更動了。" #: advice.c #, c-format @@ -746,7 +767,7 @@ msgid "" "Disable this message with \"git config advice.%s false\"" msgstr "" "\n" -"請使用 “git config advice.%s false†åœç”¨æ¤è¨Šæ¯" +"請使用「git config advice.%s falseã€åœç”¨æ¤è¨Šæ¯" #: advice.c #, c-format @@ -782,7 +803,7 @@ msgid "" "Fix them up in the work tree, and then use 'git add/rm <file>'\n" "as appropriate to mark resolution and make a commit." msgstr "" -"請在工作å€ä¿®æ£æª”案,然後視情æ³ä½¿ç”¨ “git add/rm <file>â€\n" +"請在工作å€ä¿®æ£æª”案,然後視情æ³ä½¿ç”¨ã€Œgit add/rm <file>ã€\n" "命令標記解決方案並æäº¤ã€‚" #: advice.c @@ -866,7 +887,7 @@ msgid "" "false\n" "\n" msgstr "" -"註:切æ›è‡³ “%sâ€ã€‚\n" +"註:切æ›è‡³ã€Œ%sã€ã€‚\n" "\n" "您æ£è™•於「分離 HEADã€ç‹€æ…‹ã€‚您å¯ä»¥æª¢è¦–ã€é€²è¡Œå¯¦é©—性修改並æäº¤ï¼Œ\n" "而且您å¯ä»¥åœ¨åˆ‡å›žåˆ†æ”¯æ™‚ï¼Œæ¨æ£„在æ¤ç‹€æ…‹ä¸‹æ‰€åšçš„æäº¤\n" @@ -901,8 +922,8 @@ msgid "" "* Use \"git sparse-checkout reapply\" to apply the sparsity rules" msgstr "" "è‹¥è¦æ›´æ£é€™äº›è·¯å¾‘的稀ç–狀態,請:\n" -"* 使用 “git add --sparse <路徑†更新索引\n" -"* 使用 “git sparse-checkout reapply†套用稀ç–è¦å‰‡" +"* 使用「git add --sparse <路徑>ã€æ›´æ–°ç´¢å¼•\n" +"* 使用「git sparse-checkout reapplyã€å¥—用稀ç–è¦å‰‡" #: alias.c msgid "cmdline ends with \\" @@ -913,19 +934,19 @@ msgid "unclosed quote" msgstr "未閉åˆçš„引號" #: alias.c builtin/cat-file.c builtin/notes.c builtin/prune-packed.c -#: builtin/receive-pack.c builtin/tag.c t/helper/test-pkt-line.c +#: builtin/receive-pack.c builtin/refs.c builtin/tag.c t/helper/test-pkt-line.c msgid "too many arguments" msgstr "引數éŽå¤š" #: apply.c #, c-format msgid "unrecognized whitespace option '%s'" -msgstr "空白å—å…ƒé¸é … “%s†無法è˜åˆ¥" +msgstr "空白å—å…ƒé¸é …「%sã€ç„¡æ³•è˜åˆ¥" #: apply.c #, c-format msgid "unrecognized whitespace ignore option '%s'" -msgstr "空白å—元忽略é¸é … “%s†無法è˜åˆ¥" +msgstr "空白å—元忽略é¸é …「%sã€ç„¡æ³•è˜åˆ¥" #: apply.c archive.c builtin/add.c builtin/branch.c builtin/checkout-index.c #: builtin/checkout.c builtin/clean.c builtin/clone.c builtin/commit.c @@ -939,12 +960,12 @@ msgstr "空白å—元忽略é¸é … “%s†無法è˜åˆ¥" #: range-diff.c revision.c #, c-format msgid "options '%s' and '%s' cannot be used together" -msgstr "ç„¡æ³•åŒæ™‚使用 “%s†和 “%s†é¸é …" +msgstr "ç„¡æ³•åŒæ™‚使用「%sã€å’Œã€Œ%sã€é¸é …" #: apply.c #, c-format msgid "'%s' outside a repository" -msgstr "“%s†在版本庫之外" +msgstr "「%sã€åœ¨ç‰ˆæœ¬åº«ä¹‹å¤–" #: apply.c msgid "failed to read patch" @@ -1080,7 +1101,7 @@ msgstr "ç„¡æ³•é–‹å•Ÿæˆ–è®€å– %s" #: apply.c #, c-format msgid "invalid start of line: '%c'" -msgstr "無效的列首å—元:“%câ€" +msgstr "無效的列首å—元:「%cã€" #: apply.c #, c-format @@ -1105,43 +1126,43 @@ msgstr "" #: apply.c #, c-format msgid "missing binary patch data for '%s'" -msgstr "缺少 “%s†的二進ä½ä¿®è£œæª”資料" +msgstr "缺少「%sã€çš„二進ä½ä¿®è£œæª”資料" #: apply.c #, c-format msgid "cannot reverse-apply a binary patch without the reverse hunk to '%s'" -msgstr "無法åå‘套用一個缺少至 “%s†的åå‘資料å€å¡Šçš„二進ä½ä¿®è£œæª”" +msgstr "無法åå‘套用一個缺少至「%sã€çš„åå‘資料å€å¡Šçš„二進ä½ä¿®è£œæª”" #: apply.c #, c-format msgid "cannot apply binary patch to '%s' without full index line" -msgstr "無法在 “%s†上套用沒有完整索引列的二進ä½ä¿®è£œæª”" +msgstr "無法在「%sã€ä¸Šå¥—用沒有完整索引列的二進ä½ä¿®è£œæª”" #: apply.c #, c-format msgid "" "the patch applies to '%s' (%s), which does not match the current contents." -msgstr "修補檔è¦å¥—用到 “%sâ€ï¼ˆ%s),但與目å‰å…§å®¹ä¸ç¬¦ã€‚" +msgstr "修補檔è¦å¥—用到「%sã€ï¼ˆ%s),但與目å‰å…§å®¹ä¸ç¬¦ã€‚" #: apply.c #, c-format msgid "the patch applies to an empty '%s' but it is not empty" -msgstr "修補檔è¦å¥—用至空檔案 “%sâ€ï¼Œä½†å…¶éžç©ºæª”案" +msgstr "修補檔è¦å¥—用至空檔案「%sã€ï¼Œä½†å…¶éžç©ºæª”案" #: apply.c #, c-format msgid "the necessary postimage %s for '%s' cannot be read" -msgstr "ç„¡æ³•è®€å– â€œ%2$sâ€ å¿…é ˆçš„ç›®æ¨™æª”æ¡ˆ %1$s" +msgstr "無法讀å–「%2$sã€å¿…é ˆçš„ç›®æ¨™æª”æ¡ˆ %1$s" #: apply.c #, c-format msgid "binary patch does not apply to '%s'" -msgstr "二進ä½ä¿®è£œæª”未套用到 “%sâ€" +msgstr "二進ä½ä¿®è£œæª”未套用到「%sã€" #: apply.c #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" -msgstr "修補 “%s†的二進ä½ä¿®è£œæª”ï¼Œç”¢ç”Ÿäº†ä¸æ£ç¢ºçš„çµæžœï¼ˆé 期 %s,å»ç‚º %s)" +msgstr "修補「%sã€çš„二進ä½ä¿®è£œæª”ï¼Œç”¢ç”Ÿäº†ä¸æ£ç¢ºçš„çµæžœï¼ˆé 期 %s,å»ç‚º %s)" #: apply.c #, c-format @@ -1161,7 +1182,7 @@ msgstr "ç„¡æ³•è®€å– %s" #: apply.c #, c-format msgid "reading from '%s' beyond a symbolic link" -msgstr "讀å–符號連çµèƒŒå¾Œçš„ “%sâ€" +msgstr "讀å–符號連çµèƒŒå¾Œçš„「%sã€" #: apply.c #, c-format @@ -1190,7 +1211,7 @@ msgstr "æ£åœ¨é€²è¡Œä¸‰æ–¹åˆä½µâ€¦â€¦\n" #: apply.c #, c-format msgid "cannot read the current contents of '%s'" -msgstr "ç„¡æ³•è®€å– â€œ%s†目å‰çš„內容" +msgstr "無法讀å–「%sã€ç›®å‰çš„內容" #: apply.c #, c-format @@ -1200,12 +1221,12 @@ msgstr "無法進行三方åˆä½µâ€¦â€¦\n" #: apply.c #, c-format msgid "Applied patch to '%s' with conflicts.\n" -msgstr "å·²å¥—ç”¨å° â€œ%s†的修補檔,但有è¡çªã€‚\n" +msgstr "已套用å°ã€Œ%sã€çš„修補檔,但有è¡çªã€‚\n" #: apply.c #, c-format msgid "Applied patch to '%s' cleanly.\n" -msgstr "å·²å®Œå…¨å¥—ç”¨å° â€œ%s†的修補檔。\n" +msgstr "已完全套用å°ã€Œ%sã€çš„修補檔。\n" #: apply.c #, c-format @@ -1229,7 +1250,7 @@ msgstr "%s 的類型是 %oï¼Œé æœŸæ˜¯ %o" #: apply.c read-cache.c #, c-format msgid "invalid path '%s'" -msgstr "路徑 “%s†無效" +msgstr "路徑「%sã€ç„¡æ•ˆ" #: apply.c #, c-format @@ -1254,7 +1275,7 @@ msgstr "%2$s 的新模å¼ï¼ˆ%1$o)和 %4$s 的舊模å¼ï¼ˆ%3$o)ä¸ç¬¦" #: apply.c #, c-format msgid "affected file '%s' is beyond a symbolic link" -msgstr "å—影響的檔案 “%s†在符號連çµå¾Œ" +msgstr "å—影響的檔案「%sã€åœ¨ç¬¦è™Ÿé€£çµå¾Œ" #: apply.c #, c-format @@ -1304,7 +1325,7 @@ msgstr "修補 %s 忍¡çµ„的修補檔æå£ž" #: apply.c #, c-format msgid "unable to stat newly created file '%s'" -msgstr "無法å°å‰›å»ºç«‹çš„æª”案 “%s†執行 stat" +msgstr "無法å°å‰›å»ºç«‹çš„æª”案「%sã€åŸ·è¡Œ stat" #: apply.c #, c-format @@ -1319,17 +1340,17 @@ msgstr "無法為 %s åŠ å…¥å¿«å–é …ç›®" #: apply.c builtin/bisect.c builtin/gc.c #, c-format msgid "failed to write to '%s'" -msgstr "無法寫入 “%sâ€" +msgstr "無法寫入「%sã€" #: apply.c #, c-format msgid "closing file '%s'" -msgstr "關閉檔案 “%sâ€" +msgstr "關閉檔案「%sã€" #: apply.c #, c-format msgid "unable to write file '%s' mode %o" -msgstr "ç„¡æ³•ä»¥æ¨¡å¼ %2$o 寫入 “%1$s†檔案" +msgstr "ç„¡æ³•ä»¥æ¨¡å¼ %2$o 寫入「%1$sã€æª”案" #: apply.c #, c-format @@ -1354,7 +1375,7 @@ msgstr "無法開啟 %s" #: apply.c rerere.c #, c-format msgid "cannot unlink '%s'" -msgstr "無法刪除 “%sâ€" +msgstr "無法刪除「%sã€" #: apply.c #, c-format @@ -1369,11 +1390,11 @@ msgstr "拒絕第 #%d 個å€å¡Šã€‚" #: apply.c #, c-format msgid "Skipped patch '%s'." -msgstr "ç•¥éŽä¿®è£œæª” “%sâ€ã€‚" +msgstr "ç•¥éŽä¿®è£œæª”「%sã€ã€‚" #: apply.c msgid "No valid patches in input (allow with \"--allow-empty\")" -msgstr "輸入沒有有效的修補檔內容(傳入 “--allow-empty†å…許æ¤è¡Œç‚ºï¼‰" +msgstr "輸入沒有有效的修補檔內容(傳入「--allow-emptyã€å…許æ¤è¡Œç‚ºï¼‰" #: apply.c t/helper/test-cache-tree.c msgid "unable to read index file" @@ -1382,7 +1403,7 @@ msgstr "無法讀å–索引檔案" #: apply.c #, c-format msgid "can't open patch '%s': %s" -msgstr "無法開啟修補檔 “%sâ€ï¼š%s" +msgstr "無法開啟修補檔「%sã€ï¼š%s" #: apply.c #, c-format @@ -1545,7 +1566,7 @@ msgstr "壓縮錯誤 (%d)" #: archive-tar.c #, c-format msgid "unable to start '%s' filter" -msgstr "無法啟動 “%sâ€ éŽæ¿¾å™¨" +msgstr "無法啟動「%sã€éŽæ¿¾å™¨" #: archive-tar.c msgid "unable to redirect descriptor" @@ -1554,7 +1575,7 @@ msgstr "ç„¡æ³•é‡æ–°å°Žå‘æè¿°å…ƒ" #: archive-tar.c #, c-format msgid "'%s' filter reported error" -msgstr "“%sâ€ éŽæ¿¾å™¨å›žå ±éŒ¯èª¤" +msgstr "「%sã€éŽæ¿¾å™¨å›žå ±éŒ¯èª¤" #: archive-zip.c #, c-format @@ -1588,17 +1609,17 @@ msgstr "git archive --remote <repo> [--exec <cmd>] --list" #: archive.c builtin/gc.c builtin/notes.c builtin/tag.c #, c-format msgid "cannot read '%s'" -msgstr "ç„¡æ³•è®€å– â€œ%sâ€" +msgstr "無法讀å–「%sã€" #: archive.c #, c-format msgid "pathspec '%s' matches files outside the current directory" -msgstr "符åˆè·¯å¾‘è¦æ ¼ “%s†的檔案在目å‰ç›®éŒ„之外" +msgstr "符åˆè·¯å¾‘è¦æ ¼ã€Œ%sã€çš„æª”案在目å‰ç›®éŒ„之外" #: archive.c builtin/add.c builtin/rm.c #, c-format msgid "pathspec '%s' did not match any files" -msgstr "è·¯å¾‘è¦æ ¼ “%s†未符åˆä»»ä½•檔案" +msgstr "è·¯å¾‘è¦æ ¼ã€Œ%sã€æœªç¬¦åˆä»»ä½•檔案" #: archive.c #, c-format @@ -1628,17 +1649,17 @@ msgstr "䏿˜¯ä¸€èˆ¬æª”案:%s" #: archive.c #, c-format msgid "unclosed quote: '%s'" -msgstr "未閉åˆçš„引號:“%sâ€" +msgstr "未閉åˆçš„引號:「%sã€" #: archive.c #, c-format msgid "missing colon: '%s'" -msgstr "缺少冒號:“%sâ€" +msgstr "缺少冒號:「%sã€" #: archive.c #, c-format msgid "empty file name: '%s'" -msgstr "檔案å稱空白:“%sâ€" +msgstr "檔案å稱空白:「%sã€" #: archive.c msgid "fmt" @@ -1725,7 +1746,7 @@ msgstr "éžé 期é¸é … --remote" #: revision.c #, c-format msgid "the option '%s' requires '%s'" -msgstr "“%s†é¸é …éœ€è¦ â€œ%sâ€" +msgstr "「%sã€é¸é …需è¦ã€Œ%sã€" #: archive.c msgid "Unexpected option --output" @@ -1734,17 +1755,17 @@ msgstr "éžé 期é¸é … --output" #: archive.c #, c-format msgid "extra command line parameter '%s'" -msgstr "å¤šå‡ºå‘½ä»¤åˆ—åƒæ•¸ “%sâ€" +msgstr "å¤šå‡ºå‘½ä»¤åˆ—åƒæ•¸ã€Œ%sã€" #: archive.c #, c-format msgid "Unknown archive format '%s'" -msgstr "å°å˜æ ¼å¼ “%s†未知" +msgstr "å°å˜æ ¼å¼ã€Œ%sã€æœªçŸ¥" #: archive.c #, c-format msgid "Argument not supported for format '%s': -%d" -msgstr "å¼•æ•¸ä¸æ”¯æ´ “%sâ€ æ ¼å¼ï¼š-%d" +msgstr "å¼•æ•¸ä¸æ”¯æ´ã€Œ%sã€æ ¼å¼ï¼š-%d" #: attr.c #, c-format @@ -1771,22 +1792,26 @@ msgid "" "Use '\\!' for literal leading exclamation." msgstr "" "git attributes 會忽略å呿¨¡å¼\n" -"ç•¶å—串確定è¦ä»¥é©šå˜†è™Ÿé–‹å§‹æ™‚,請使用 “\\!â€ã€‚" +"ç•¶å—串確定è¦ä»¥é©šå˜†è™Ÿé–‹å§‹æ™‚,請使用「\\!ã€ã€‚" #: attr.c #, c-format msgid "cannot fstat gitattributes file '%s'" -msgstr "無法 fstat gitattributes 檔案 “%sâ€" +msgstr "無法 fstat gitattributes 檔案「%sã€" #: attr.c #, c-format msgid "ignoring overly large gitattributes file '%s'" -msgstr "忽略éŽå¤§çš„ gitattributes 檔案 “%sâ€" +msgstr "忽略éŽå¤§çš„ gitattributes 檔案「%sã€" #: attr.c #, c-format msgid "ignoring overly large gitattributes blob '%s'" -msgstr "忽略éŽå¤§çš„ gitattributes 資料物件 “%sâ€" +msgstr "忽略éŽå¤§çš„ gitattributes 資料物件「%sã€" + +#: attr.c +msgid "cannot use --attr-source or GIT_ATTR_SOURCE without repo" +msgstr "沒有版本庫無法使用 --attr-source 或 GIT_ATTR_SOURCE" #: attr.c msgid "bad --attr-source or GIT_ATTR_SOURCE" @@ -1795,18 +1820,18 @@ msgstr "無效的 --attr-source 或 GIT_ATTR_SOURCE" #: attr.c read-cache.c #, c-format msgid "unable to stat '%s'" -msgstr "ç„¡æ³•å° %s 執行 stat" +msgstr "無法統計「%sã€" #: bisect.c builtin/cat-file.c builtin/index-pack.c builtin/notes.c #: builtin/pack-objects.c combine-diff.c rerere.c #, c-format msgid "unable to read %s" -msgstr "ä¸èƒ½è®€ %s" +msgstr "ç„¡æ³•è®€å– %s" #: bisect.c #, c-format msgid "Badly quoted content in file '%s': %s" -msgstr "檔案 “%s†包å«ç„¡æ•ˆçš„引用內容:%s" +msgstr "檔案「%sã€åŒ…å«ç„¡æ•ˆçš„引用內容:%s" #: bisect.c #, c-format @@ -1843,7 +1868,7 @@ msgid "" "This means the first '%s' commit is between %s and [%s].\n" msgstr "" "åˆä½µåŸºç¤Ž %s 是 %s。\n" -"這æ„味著第一個 “%s†æäº¤ä½æ–¼ %s å’Œ [%s] 之間。\n" +"這æ„味著第一個「%sã€æäº¤ä½æ–¼ %s å’Œ [%s] 之間。\n" #: bisect.c #, c-format @@ -1880,17 +1905,17 @@ msgstr "需è¦ä¸€å€‹ %s 修訂版" #: bisect.c #, c-format msgid "could not create file '%s'" -msgstr "無法建立 “%s†檔案" +msgstr "無法建立「%sã€æª”案" #: bisect.c builtin/notes.c #, c-format msgid "unable to start 'show' for object '%s'" -msgstr "ä¸èƒ½ç‚ºç‰©ä»¶ '%s' é–‹å§‹ 'show'" +msgstr "無法為物件「%sã€é–‹å§‹ã€Œshowã€" #: bisect.c builtin/merge.c #, c-format msgid "could not read file '%s'" -msgstr "ç„¡æ³•è®€å– â€œ%s†檔案" +msgstr "無法讀å–「%sã€æª”案" #: bisect.c msgid "reading bisect refs failed" @@ -1963,22 +1988,22 @@ msgstr "請求é‡å®šåŸºåº•時,無法繼承多個引用的上游追蹤è¨å®š" #: branch.c #, c-format msgid "not setting branch '%s' as its own upstream" -msgstr "未將 “%s†分支è¨ç‚ºå…¶è‡ªå·±çš„上游" +msgstr "未將「%sã€åˆ†æ”¯è¨ç‚ºå…¶è‡ªå·±çš„上游" #: branch.c #, c-format msgid "branch '%s' set up to track '%s' by rebasing." -msgstr "已藉由é‡è¨‚基底,將 “%s†分支è¨å®šç‚ºè¿½è¹¤ “%sâ€ã€‚" +msgstr "已藉由é‡è¨‚基底,將「%sã€åˆ†æ”¯è¨å®šç‚ºè¿½è¹¤ã€Œ%sã€ã€‚" #: branch.c #, c-format msgid "branch '%s' set up to track '%s'." -msgstr "已將 “%s†分支è¨å®šç‚ºè¿½è¹¤ “%sâ€ã€‚" +msgstr "已將「%sã€åˆ†æ”¯è¨å®šç‚ºè¿½è¹¤ã€Œ%sã€ã€‚" #: branch.c #, c-format msgid "branch '%s' set up to track:" -msgstr "“%s†分支已è¨å®šè¿½è¹¤ï¼š" +msgstr "「%sã€åˆ†æ”¯å·²è¨å®šè¿½è¹¤ï¼š" #: branch.c msgid "unable to write upstream branch configuration" @@ -1997,17 +2022,17 @@ msgstr "" #: branch.c #, c-format msgid "asked to inherit tracking from '%s', but no remote is set" -msgstr "請求繼承 “%s†的追蹤è¨å®šï¼Œä½†æœªè¨å®šé 端" +msgstr "請求繼承「%sã€çš„追蹤è¨å®šï¼Œä½†æœªè¨å®šé 端" #: branch.c #, c-format msgid "asked to inherit tracking from '%s', but no merge configuration is set" -msgstr "請求繼承 “%s†的追蹤è¨å®šï¼Œä½†æœªè¨å®šåˆä½µè¨å®š" +msgstr "請求繼承「%sã€çš„追蹤è¨å®šï¼Œä½†æœªè¨å®šåˆä½µè¨å®š" #: branch.c #, c-format msgid "not tracking: ambiguous information for ref '%s'" -msgstr "未追蹤:“%s†引用有æ§ç¾©" +msgstr "未追蹤:「%sã€å¼•用有æ§ç¾©" # è¯è€…:為ä¿è‰åœ¨è¼¸å‡ºä¸å°é½Šï¼Œæ³¨æ„調整å¥ä¸ç©ºæ ¼ï¼ #. #-#-#-#-# branch.c.po #-#-#-#-# @@ -2042,7 +2067,7 @@ msgid "" "tracking namespaces." msgstr "" "有多個é 端的抓å–å¼•ç”¨è¦æ ¼ï¼Œæ˜ 射到\n" -"é 端追蹤引用 “%sâ€ çš„è¦æ ¼ï¼š\n" +"é 端追蹤引用「%sã€çš„è¦æ ¼ï¼š\n" "%s\n" "這通常是è¨å®šéŒ¯èª¤ã€‚\n" "\n" @@ -2052,7 +2077,7 @@ msgstr "" #: branch.c #, c-format msgid "'%s' is not a valid branch name" -msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„分支å稱" +msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆçš„分支å稱" #: branch.c builtin/branch.c msgid "See `man git check-ref-format`" @@ -2061,22 +2086,22 @@ msgstr "è«‹åƒé–±ã€Œman git check-ref-formatã€" #: branch.c #, c-format msgid "a branch named '%s' already exists" -msgstr "已有åŒå “%s†分支" +msgstr "已有åŒå「%sã€åˆ†æ”¯" #: branch.c #, c-format msgid "cannot force update the branch '%s' used by worktree at '%s'" -msgstr "ç„¡æ³•å¼·åˆ¶æ›´æ–°è¢«ä½æ–¼ “%2$s†的工作å€ä½¿ç”¨çš„ “%1$s†分支" +msgstr "ç„¡æ³•å¼·åˆ¶æ›´æ–°è¢«ä½æ–¼ã€Œ%2$sã€çš„工作å€ä½¿ç”¨çš„分支「%1$sã€" #: branch.c #, c-format msgid "cannot set up tracking information; starting point '%s' is not a branch" -msgstr "無法è¨å®šè¿½è¹¤è³‡è¨Šï¼šèµ·å§‹é»ž “%sâ€ ä¸æ˜¯åˆ†æ”¯" +msgstr "無法è¨å®šè¿½è¹¤è³‡è¨Šï¼šèµ·å§‹é»žã€Œ%sã€ä¸æ˜¯åˆ†æ”¯" #: branch.c #, c-format msgid "the requested upstream branch '%s' does not exist" -msgstr "請求的上游分支 “%s†ä¸å˜åœ¨" +msgstr "請求的上游分支「%sã€ä¸å˜åœ¨" #: branch.c msgid "" @@ -2100,22 +2125,22 @@ msgstr "" #: branch.c builtin/replace.c #, c-format msgid "not a valid object name: '%s'" -msgstr "物件å稱無效:“%sâ€" +msgstr "物件å稱無效:「%sã€" #: branch.c #, c-format msgid "ambiguous object name: '%s'" -msgstr "物件å稱有æ§ç¾©ï¼šâ€œ%sâ€" +msgstr "物件å稱有æ§ç¾©ï¼šã€Œ%sã€" #: branch.c #, c-format msgid "not a valid branch point: '%s'" -msgstr "分支點無效:“%sâ€" +msgstr "分支點無效:「%sã€" #: branch.c #, c-format msgid "submodule '%s': unable to find submodule" -msgstr "“%sâ€ åæ¨¡çµ„:找ä¸åˆ°å模組" +msgstr "「%sã€å模組:找ä¸åˆ°å模組" #: branch.c #, c-format @@ -2123,18 +2148,18 @@ msgid "" "You may try updating the submodules using 'git checkout --no-recurse-" "submodules %s && git submodule update --init'" msgstr "" -"您å¯ä»¥ä½¿ç”¨ “git checkout --no-recurse-submodules %s && git submodule update " -"--initâ€ å‘½ä»¤å˜—è©¦æ›´æ–°åæ¨¡çµ„" +"您å¯ä»¥ä½¿ç”¨ã€Œgit checkout --no-recurse-submodules %s && git submodule update " +"--initã€å‘½ä»¤å˜—è©¦æ›´æ–°åæ¨¡çµ„" #: branch.c #, c-format msgid "submodule '%s': cannot create branch '%s'" -msgstr "“%sâ€ åæ¨¡çµ„:無法建立 “%s†分支" +msgstr "「%sã€å模組:無法建立「%sã€åˆ†æ”¯" #: branch.c #, c-format msgid "'%s' is already used by worktree at '%s'" -msgstr "“%sâ€ å·²è¢«ä½æ–¼ “%s†的工作å€ä½¿ç”¨" +msgstr "「%sã€å·²è¢«ä½æ–¼ã€Œ%sã€çš„工作å€ä½¿ç”¨" #: builtin/add.c msgid "git add [<options>] [--] <pathspec>..." @@ -2150,14 +2175,6 @@ msgid "Unstaged changes after refreshing the index:" msgstr "釿–°æ•´ç†ç´¢å¼•之後,尚未被暫å˜çš„æ›´å‹•:" #: builtin/add.c -msgid "" -"the add.interactive.useBuiltin setting has been removed!\n" -"See its entry in 'git help config' for details." -msgstr "" -"add.interactive.useBuiltin è¨å®šå·²è¢«ç§»é™¤ï¼\n" -"深入了解請åƒé–± “git help config†ä¸çš„å°æ‡‰æ¢ç›®ã€‚" - -#: builtin/add.c msgid "could not read the index" msgstr "無法讀å–索引" @@ -2168,7 +2185,7 @@ msgstr "編輯修補檔失敗" #: builtin/add.c read-cache.c #, c-format msgid "could not stat '%s'" -msgstr "ä¸èƒ½å° '%s' å‘¼å« stat" +msgstr "無法統計「%sã€" #: builtin/add.c msgid "empty patch. aborted" @@ -2177,7 +2194,7 @@ msgstr "ä¿®è£œæª”ç©ºç™½ã€‚ä¸æ¢" #: builtin/add.c #, c-format msgid "could not apply '%s'" -msgstr "無法套用 “%sâ€" +msgstr "無法套用「%sã€" #: builtin/add.c msgid "The following paths are ignored by one of your .gitignore files:\n" @@ -2284,7 +2301,7 @@ msgstr "" "\n" "\tgit rm --cached %s\n" "\n" -"åƒè¦‹ “git help submodule†深入了解。" +"åƒè¦‹ã€Œgit help submoduleã€æ·±å…¥äº†è§£ã€‚" #: builtin/add.c #, c-format @@ -2293,7 +2310,7 @@ msgstr "æ£åœ¨åŠ å…¥åµŒå…¥å¼ git 版本庫:%s" #: builtin/add.c msgid "Use -f if you really want to add them." -msgstr "如果您確定想è¦åŠ å…¥ä»–å€‘ï¼Œè«‹ä½¿ç”¨ã€Œ-fã€ã€‚" +msgstr "如果您確定想è¦åŠ å…¥å®ƒå€‘ï¼Œè«‹ä½¿ç”¨ -f。" #: builtin/add.c msgid "adding files failed" @@ -2302,13 +2319,13 @@ msgstr "åŠ å…¥æª”æ¡ˆå¤±æ•—" #: builtin/add.c #, c-format msgid "--chmod param '%s' must be either -x or +x" -msgstr "--chmod çš„åƒæ•¸ “%sâ€ å¿…é ˆæ˜¯ -x 或 +x" +msgstr "--chmod çš„åƒæ•¸ã€Œ%sã€å¿…é ˆæ˜¯ -x 或 +x" #: builtin/add.c builtin/checkout.c builtin/commit.c builtin/reset.c #: builtin/rm.c builtin/stash.c #, c-format msgid "'%s' and pathspec arguments cannot be used together" -msgstr "“%sâ€ å’Œè·¯å¾‘è¦æ ¼å¼•數ä¸å¾—åŒæ™‚使用" +msgstr "「%sã€å’Œè·¯å¾‘è¦æ ¼å¼•數ä¸å¾—åŒæ™‚使用" #: builtin/add.c #, c-format @@ -2334,19 +2351,19 @@ msgstr "無法寫入新的索引檔案" #: builtin/am.c builtin/mailinfo.c mailinfo.c #, c-format msgid "bad action '%s' for '%s'" -msgstr "“%sâ€ å‹•ä½œå° â€œ%s†無效" +msgstr "「%sã€å‹•作å°ã€Œ%sã€ç„¡æ•ˆ" #: builtin/am.c builtin/blame.c builtin/fetch.c builtin/pack-objects.c #: builtin/pull.c builtin/revert.c config.c diff-merges.c gpg-interface.c #: ls-refs.c parallel-checkout.c sequencer.c setup.c #, c-format msgid "invalid value for '%s': '%s'" -msgstr "“%s†的值無效:“%sâ€" +msgstr "「%sã€çš„值無效:「%sã€" #: builtin/am.c builtin/commit.c builtin/merge.c sequencer.c #, c-format msgid "could not read '%s'" -msgstr "ç„¡æ³•è®€å– â€œ%sâ€" +msgstr "無法讀å–「%sã€" #: builtin/am.c msgid "could not parse author script" @@ -2360,17 +2377,17 @@ msgstr "ç„¡æ³•è§£æž %s" #: builtin/am.c #, c-format msgid "'%s' was deleted by the applypatch-msg hook" -msgstr "“%s†被 applypatch-msg 掛鉤刪除" +msgstr "「%sã€è¢« applypatch-msg 掛鉤刪除" #: builtin/am.c #, c-format msgid "Malformed input line: '%s'." -msgstr "æ ¼å¼éŒ¯èª¤çš„輸入列:“%sâ€ã€‚" +msgstr "æ ¼å¼éŒ¯èª¤çš„輸入列:「%sã€ã€‚" #: builtin/am.c #, c-format msgid "Failed to copy notes from '%s' to '%s'" -msgstr "從 “%s†拷è²è¨»è§£åˆ° “%s†失敗" +msgstr "從「%sã€æ‹·è²è¨»è§£åˆ°ã€Œ%sã€å¤±æ•—" #: builtin/am.c msgid "fseek failed" @@ -2379,17 +2396,17 @@ msgstr "fseek 失敗" #: builtin/am.c builtin/rebase.c sequencer.c wrapper.c #, c-format msgid "could not open '%s' for reading" -msgstr "無法開啟 “%s†進行讀å–" +msgstr "無法開啟「%sã€é€²è¡Œè®€å–" #: builtin/am.c builtin/rebase.c editor.c sequencer.c wrapper.c #, c-format msgid "could not open '%s' for writing" -msgstr "無法開啟 “%s†進行寫入" +msgstr "無法開啟「%sã€é€²è¡Œå¯«å…¥" #: builtin/am.c #, c-format msgid "could not parse patch '%s'" -msgstr "無法解æžä¿®è£œæª” “%sâ€" +msgstr "無法解æžä¿®è£œæª”「%sã€" #: builtin/am.c msgid "Only one StGIT patch series can be applied at once" @@ -2414,7 +2431,7 @@ msgstr "ä¿®è£œæª”æ ¼å¼åµæ¸¬å¤±æ•—。" #: builtin/am.c builtin/clone.c #, c-format msgid "failed to create directory '%s'" -msgstr "無法建立目錄 “%sâ€" +msgstr "無法建立目錄「%sã€" #: builtin/am.c msgid "Failed to split patches." @@ -2439,7 +2456,7 @@ msgstr "è‹¥è¦å°‡ç©ºç™½ä¿®è£œæª”錄入為空白æäº¤ï¼Œè«‹åŸ·è¡Œã€Œ%s --allow-e #: builtin/am.c #, c-format msgid "To restore the original branch and stop patching, run \"%s --abort\"." -msgstr "è‹¥è¦é‚„åŽŸè‡³åŽŸå§‹åˆ†æ”¯ï¼Œä¸¦åœæ¢ä¿®è£œå‹•作,請執行 “%s --abortâ€ã€‚" +msgstr "è‹¥è¦é‚„åŽŸè‡³åŽŸå§‹åˆ†æ”¯ï¼Œä¸¦åœæ¢ä¿®è£œå‹•作,請執行「%s --abortã€ã€‚" #: builtin/am.c msgid "Patch sent with format=flowed; space at the end of lines might be lost." @@ -2554,7 +2571,7 @@ msgstr "在 %s %.*s 處修補失敗" #: builtin/am.c msgid "Use 'git am --show-current-patch=diff' to see the failed patch" -msgstr "使用 “git am --show-current-patch=diff†命令檢視失敗的修補檔" +msgstr "使用「git am --show-current-patch=diffã€å‘½ä»¤æª¢è¦–失敗的修補檔" #: builtin/am.c msgid "No changes - recorded it as an empty commit." @@ -2566,7 +2583,7 @@ msgid "" "If there is nothing left to stage, chances are that something else\n" "already introduced the same changes; you might want to skip this patch." msgstr "" -"沒有變更:是å¦å¿˜è¨˜åŸ·è¡Œ “git addâ€ï¼Ÿ\n" +"沒有變更:是å¦å¿˜è¨˜åŸ·è¡Œã€Œgit addã€ï¼Ÿ\n" "å¦‚æžœæ²’æœ‰å…¶ä»–è¦æ–°å¢žåˆ°æš«å˜å€çš„,則很å¯èƒ½æ˜¯å…¶å®ƒæäº¤\n" "已經引入了相åŒçš„變更。您也許想è¦ç•¥éŽé€™å€‹ä¿®è£œæª”。" @@ -2584,7 +2601,7 @@ msgstr "" #: builtin/am.c builtin/reset.c #, c-format msgid "Could not parse object '%s'." -msgstr "ç„¡æ³•è§£æž â€œ%s†物件。" +msgstr "無法解æžã€Œ%sã€ç‰©ä»¶ã€‚" #: builtin/am.c msgid "failed to clean index" @@ -2595,13 +2612,13 @@ msgid "" "You seem to have moved HEAD since the last 'am' failure.\n" "Not rewinding to ORIG_HEAD" msgstr "" -"您似乎在上一次 “am†失敗後移動了 HEAD。\n" +"您似乎在上一次「amã€å¤±æ•—後移動了 HEAD。\n" "未倒轉回 ORIG_HEAD" -#: builtin/am.c builtin/bisect.c worktree.c +#: builtin/am.c builtin/bisect.c builtin/tag.c worktree.c #, c-format msgid "failed to read '%s'" -msgstr "ç„¡æ³•è®€å– â€œ%sâ€" +msgstr "無法讀å–「%sã€" #: builtin/am.c msgid "git am [<options>] [(<mbox> | <Maildir>)...]" @@ -2676,8 +2693,8 @@ msgstr "n" #: builtin/am.c builtin/branch.c builtin/bugreport.c builtin/cat-file.c #: builtin/clone.c builtin/diagnose.c builtin/for-each-ref.c builtin/init-db.c -#: builtin/ls-files.c builtin/ls-tree.c builtin/replace.c builtin/tag.c -#: builtin/verify-tag.c +#: builtin/ls-files.c builtin/ls-tree.c builtin/refs.c builtin/replace.c +#: builtin/tag.c builtin/verify-tag.c msgid "format" msgstr "format" @@ -2714,6 +2731,10 @@ msgid "show the patch being applied" msgstr "顯示æ£åœ¨å¥—用的修補檔" #: builtin/am.c +msgid "try to apply current patch again" +msgstr "冿¬¡å˜—試套用目å‰ä¿®è£œæª”" + +#: builtin/am.c msgid "record the empty patch as an empty commit" msgstr "將空白修補檔錄入為空白æäº¤" @@ -2766,7 +2787,7 @@ msgid "" "Use \"git am --abort\" to remove it." msgstr "" "發ç¾å¤±æ•£çš„ %s 目錄。\n" -"使用 “git am --abort†移除。" +"使用「git am --abortã€ç§»é™¤ã€‚" #: builtin/am.c msgid "Resolve operation not in progress, we are not resuming." @@ -2785,10 +2806,6 @@ msgid "could not redirect output" msgstr "ç„¡æ³•é‡æ–°å°Žå‘輸出" #: builtin/archive.c -msgid "git archive: Remote with no URL" -msgstr "git archive: 未æä¾›é 端 URL" - -#: builtin/archive.c msgid "git archive: expected ACK/NAK, got a flush packet" msgstr "git archiveï¼šé æœŸæ˜¯ ACK/NAKï¼Œå»æ”¶åˆ° flush å°åŒ…" @@ -2836,32 +2853,32 @@ msgstr "git bisect run <cmd> [<arg>...]" #: builtin/bisect.c #, c-format msgid "cannot open file '%s' in mode '%s'" -msgstr "無法以 “%2$s†模å¼é–‹å•Ÿ “%1$s†檔案" +msgstr "無法以「%2$sã€æ¨¡å¼é–‹å•Ÿã€Œ%1$sã€æª”案" #: builtin/bisect.c #, c-format msgid "could not write to file '%s'" -msgstr "無法寫入 “%s†檔案" +msgstr "無法寫入「%sã€æª”案" #: builtin/bisect.c #, c-format msgid "cannot open file '%s' for reading" -msgstr "無法開啟 “%s†檔案進行讀å–" +msgstr "無法開啟「%sã€æª”案進行讀å–" #: builtin/bisect.c #, c-format msgid "'%s' is not a valid term" -msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆè¡“語" +msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆè¡“語" #: builtin/bisect.c #, c-format msgid "can't use the builtin command '%s' as a term" -msgstr "ä¸èƒ½å°‡å…§å»ºå‘½ä»¤ “%s†當作術語使用" +msgstr "ä¸èƒ½å°‡å…§å»ºå‘½ä»¤ã€Œ%sã€ç•¶ä½œè¡“語使用" #: builtin/bisect.c #, c-format msgid "can't change the meaning of the term '%s'" -msgstr "ä¸èƒ½è®Šæ›´è¡“語 “%s†的å«ç¾©" +msgstr "ä¸èƒ½è®Šæ›´è¡“語「%sã€çš„å«ç¾©" #: builtin/bisect.c msgid "please use two different terms" @@ -2875,13 +2892,13 @@ msgstr "我們沒有在二分æœå°‹ã€‚\n" #: builtin/bisect.c #, c-format msgid "'%s' is not a valid commit" -msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„æäº¤" +msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆçš„æäº¤" #: builtin/bisect.c #, c-format msgid "" "could not check out original HEAD '%s'. Try 'git bisect reset <commit>'." -msgstr "ä¸èƒ½ç°½å‡ºåŽŸå§‹ HEAD “%sâ€ã€‚請嘗試 “git bisect reset <commit>â€ã€‚" +msgstr "ä¸èƒ½ç°½å‡ºåŽŸå§‹ HEAD「%sã€ã€‚請嘗試「git bisect reset <commit>ã€ã€‚" #: builtin/bisect.c #, c-format @@ -2891,12 +2908,12 @@ msgstr "bisect_write 引數無效:%s" #: builtin/bisect.c #, c-format msgid "couldn't get the oid of the rev '%s'" -msgstr "無法å–得修訂版 “%s†的物件 ID" +msgstr "無法å–得修訂版「%sã€çš„物件 ID" #: builtin/bisect.c #, c-format msgid "couldn't open the file '%s'" -msgstr "無法開啟檔案 “%sâ€" +msgstr "無法開啟檔案「%sã€" #: builtin/bisect.c #, c-format @@ -2910,7 +2927,7 @@ msgid "" "You can use \"git bisect %s\" and \"git bisect %s\" for that." msgstr "" "需指定至少一個 %s 和一個 %s 修訂版。\n" -"ç‚ºæ¤æ‚¨å¯ä»¥ç”¨ “git bisect %s†和 “git bisect %sâ€ã€‚" +"ç‚ºæ¤æ‚¨å¯ä»¥ç”¨ã€Œgit bisect %sã€å’Œã€Œgit bisect %sã€ã€‚" #: builtin/bisect.c #, c-format @@ -2919,9 +2936,9 @@ msgid "" "You then need to give me at least one %s and %s revision.\n" "You can use \"git bisect %s\" and \"git bisect %s\" for that." msgstr "" -"è¦é–‹å§‹ï¼Œè«‹åŸ·è¡Œ “git bisect startâ€ã€‚\n" +"è¦é–‹å§‹ï¼Œè«‹åŸ·è¡Œã€Œgit bisect startã€ã€‚\n" "接著æä¾›è‡³å°‘一個 %s 和一個 %s 修訂版。\n" -"ç‚ºæ¤æ‚¨å¯ä»¥ç”¨ “git bisect %s†和 “git bisect %sâ€ã€‚" +"ç‚ºæ¤æ‚¨å¯ä»¥ç”¨ã€Œgit bisect %sã€å’Œã€Œgit bisect %sã€ã€‚" #: builtin/bisect.c #, c-format @@ -2970,7 +2987,7 @@ msgid "" "invalid argument %s for 'git bisect terms'.\n" "Supported options are: --term-good|--term-old and --term-bad|--term-new." msgstr "" -"傳入 “git bisect terms†的 %s 引數無效。\n" +"傳入「git bisect termsã€çš„ %s 引數無效。\n" "支æ´çš„é¸é …有:--term-good|--term-old å’Œ --term-bad|--term-new。" #: builtin/bisect.c @@ -2980,21 +2997,21 @@ msgstr "ä¿®è¨‚ç‰ˆéæ·è¨å®šå¤±æ•—\n" #: builtin/bisect.c #, c-format msgid "could not open '%s' for appending" -msgstr "無法開啟 “%sâ€ é€²è¡Œé™„åŠ " +msgstr "無法開啟「%sã€é€²è¡Œé™„åŠ " #: builtin/bisect.c msgid "'' is not a valid term" -msgstr "“ â€ ä¸æ˜¯æœ‰æ•ˆè¡“語" +msgstr "「 ã€ä¸æ˜¯æœ‰æ•ˆè¡“語" #: builtin/bisect.c #, c-format msgid "unrecognized option: '%s'" -msgstr "無法è˜åˆ¥é¸é …:“%sâ€" +msgstr "無法è˜åˆ¥é¸é …:「%sã€" #: builtin/bisect.c #, c-format msgid "'%s' does not appear to be a valid revision" -msgstr "“%sâ€ ä¼¼ä¹Žä¸æ˜¯æœ‰æ•ˆä¿®è¨‚版" +msgstr "「%sã€ä¼¼ä¹Žä¸æ˜¯æœ‰æ•ˆä¿®è¨‚版" #: builtin/bisect.c msgid "bad HEAD - I need a HEAD" @@ -3003,7 +3020,7 @@ msgstr "HEAD 無效 — 需è¦ä¸€å€‹ HEAD" #: builtin/bisect.c #, c-format msgid "checking out '%s' failed. Try 'git bisect start <valid-branch>'." -msgstr "簽出 “%s†失敗。請嘗試 “git bisect start <valid-branch>â€ã€‚" +msgstr "簽出「%sã€å¤±æ•—。請嘗試「git bisect start <valid-branch>ã€ã€‚" #: builtin/bisect.c msgid "bad HEAD - strange symbolic ref" @@ -3012,11 +3029,11 @@ msgstr "HEAD 無效 — 異常符號引用" #: builtin/bisect.c #, c-format msgid "invalid ref: '%s'" -msgstr "引用無效:“%sâ€" +msgstr "引用無效:「%sã€" #: builtin/bisect.c msgid "You need to start by \"git bisect start\"\n" -msgstr "è¦é–‹å§‹ï¼Œè«‹åŸ·è¡Œ “git bisect startâ€\n" +msgstr "è¦é–‹å§‹ï¼Œè«‹åŸ·è¡Œã€Œgit bisect startã€\n" # è¯è€…ï¼šè«‹ç¶æŒå¥å°¾ç©ºæ ¼ #. TRANSLATORS: Make sure to include [Y] and [n] in your @@ -3034,7 +3051,7 @@ msgstr "è¦å‘¼å« `--bisect-state`,請傳入一個以上的引數" #: builtin/bisect.c #, c-format msgid "'git bisect %s' can take only one argument." -msgstr "“git bisect %s†åªå–一個引數。" +msgstr "「git bisect %sã€åªå–一個引數。" #: builtin/bisect.c #, c-format @@ -3087,7 +3104,7 @@ msgstr "二分æœå°‹åŸ·è¡Œå¤±æ•—:%2$s å›žå‚³çš„çµæŸä»£ç¢¼ %1$d å°æ–¼ 0 或å #: builtin/bisect.c #, c-format msgid "cannot open file '%s' for writing" -msgstr "無法開啟 “%s†檔案進行寫入" +msgstr "無法開啟「%sã€æª”案進行寫入" #: builtin/bisect.c msgid "bisect run cannot continue any more" @@ -3104,22 +3121,22 @@ msgstr "二分æœå°‹ç™¼ç¾åˆ°ç¬¬ä¸€å€‹æœ‰å•題的æäº¤" #: builtin/bisect.c #, c-format msgid "bisect run failed: 'git bisect %s' exited with error code %d" -msgstr "二分æœå°‹åŸ·è¡Œå¤±æ•—:“git bisect %s†以錯誤碼 %d 離開" +msgstr "二分æœå°‹åŸ·è¡Œå¤±æ•—:「git bisect %sã€ä»¥éŒ¯èª¤ç¢¼ %d 離開" #: builtin/bisect.c #, c-format msgid "'%s' requires either no argument or a commit" -msgstr "“%s†ä¸éœ€è¦å¼•數,或者得傳入一個æäº¤" +msgstr "「%sã€ä¸éœ€è¦å¼•數,或者得傳入一個æäº¤" #: builtin/bisect.c #, c-format msgid "'%s' requires 0 or 1 argument" -msgstr "“%sâ€ éœ€è¦ 0 或 1 個引數" +msgstr "「%sã€éœ€è¦ 0 或 1 個引數" #: builtin/bisect.c #, c-format msgid "'%s' requires 0 arguments" -msgstr "“%s†ä¸éœ€å¼•數" +msgstr "「%sã€ä¸éœ€å¼•數" #: builtin/bisect.c msgid "no logfile given" @@ -3128,7 +3145,7 @@ msgstr "未æä¾›æ—¥èªŒæª”案" #: builtin/bisect.c #, c-format msgid "'%s' failed: no command provided." -msgstr "“%s†失敗:沒有æä¾›å‘½ä»¤ã€‚" +msgstr "「%sã€å¤±æ•—:沒有æä¾›å‘½ä»¤ã€‚" #: builtin/bisect.c msgid "need a command" @@ -3137,7 +3154,7 @@ msgstr "éœ€è¦æä¾›å‘½ä»¤" #: builtin/bisect.c builtin/cat-file.c #, c-format msgid "unknown command: '%s'" -msgstr "未知命令:“%sâ€" +msgstr "未知命令:「%sã€" #: builtin/blame.c msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>" @@ -3352,8 +3369,8 @@ msgid "" "deleting branch '%s' that has been merged to\n" " '%s', but not yet merged to HEAD" msgstr "" -"å°‡è¦åˆªé™¤çš„ “%s†分支已經被åˆä½µåˆ°\n" -" “%sâ€ï¼Œä½†å°šæœªåˆä½µåˆ° HEAD" +"å°‡è¦åˆªé™¤çš„分支「%sã€å·²ç¶“被åˆä½µåˆ°\n" +" 「%sã€ï¼Œä½†å°šæœªåˆä½µåˆ° HEAD" # è¯è€…ï¼šä¿æŒåŽŸæ›è¡Œæ ¼å¼ï¼Œåœ¨è¼¸å‡ºæ™‚ %s 的替代內容會讓å—串變長 #: builtin/branch.c @@ -3362,23 +3379,23 @@ msgid "" "not deleting branch '%s' that is not yet merged to\n" " '%s', even though it is merged to HEAD" msgstr "" -"並未刪除分支 “%sâ€ï¼Œ 雖然已經åˆä½µåˆ° HEAD,\n" -" å»å°šæœªè¢«åˆä½µè‡³ “%s†分支" +"並未刪除分支「%sã€ï¼Œé›–然已經åˆä½µåˆ° HEAD,\n" +" å»å°šæœªè¢«åˆä½µè‡³ã€Œ%sã€åˆ†æ”¯" #: builtin/branch.c #, c-format msgid "couldn't look up commit object for '%s'" -msgstr "無法查詢 “%s†指å‘çš„æäº¤ç‰©ä»¶" +msgstr "無法查詢「%sã€æŒ‡å‘çš„æäº¤ç‰©ä»¶" #: builtin/branch.c #, c-format msgid "the branch '%s' is not fully merged" -msgstr "分支 “%s†沒有完全åˆä½µ" +msgstr "分支「%sã€æ²’有完全åˆä½µ" #: builtin/branch.c #, c-format msgid "If you are sure you want to delete it, run 'git branch -D %s'" -msgstr "如果確定è¦åˆªé™¤å®ƒï¼Œè«‹åŸ·è¡Œ “git branch -D %sâ€" +msgstr "如果確定è¦åˆªé™¤å®ƒï¼Œè«‹åŸ·è¡Œã€Œgit branch -D %sã€" #: builtin/branch.c msgid "update of config-file failed" @@ -3391,12 +3408,12 @@ msgstr "ä¸èƒ½å°‡ -a å’Œ -d åŒæ™‚使用" #: builtin/branch.c #, c-format msgid "cannot delete branch '%s' used by worktree at '%s'" -msgstr "ç„¡æ³•åˆªé™¤è¢«ä½æ–¼ “%2$s†的工作å€ä½¿ç”¨çš„ “%1$s†分支" +msgstr "ç„¡æ³•åˆªé™¤è¢«ä½æ–¼ã€Œ%2$sã€çš„工作å€ä½¿ç”¨çš„分支「%1$sã€" #: builtin/branch.c #, c-format msgid "remote-tracking branch '%s' not found" -msgstr "找ä¸åˆ° “%s†é 端追蹤分支" +msgstr "找ä¸åˆ°é 端追蹤分支「%sã€" #: builtin/branch.c #, c-format @@ -3404,13 +3421,13 @@ msgid "" "branch '%s' not found.\n" "Did you forget --remote?" msgstr "" -"找ä¸åˆ° “%s†分支。\n" -"您å¯èƒ½è¦åŠ ä¸Š --remote?" +"找ä¸åˆ°åˆ†æ”¯ã€Œ%sã€ã€‚\n" +"您å¯èƒ½æƒ³åŠ ä¸Š --remote?" #: builtin/branch.c #, c-format msgid "branch '%s' not found" -msgstr "找ä¸åˆ° “%s†分支" +msgstr "找ä¸åˆ°åˆ†æ”¯ã€Œ%sã€" #: builtin/branch.c #, c-format @@ -3428,42 +3445,42 @@ msgstr "ç„¡æ³•è§£æžæ ¼å¼åŒ–å—串" #: builtin/branch.c msgid "could not resolve HEAD" -msgstr "ç„¡æ³•è§£æž HEAD 指é‡" +msgstr "ç„¡æ³•è§£æž HEAD 指標" #: builtin/branch.c #, c-format msgid "HEAD (%s) points outside of refs/heads/" -msgstr "HEAD æŒ‡é‡ (%s) æŒ‡å‘ refs/heads/ 之外" +msgstr "HEAD 指標 (%s) æŒ‡å‘ refs/heads/ 之外" #: builtin/branch.c #, c-format msgid "branch %s is being rebased at %s" -msgstr "%s 分支æ£åœ¨é‡å®šåŸºåº•至 %s" +msgstr "分支 %s æ£åœ¨é‡å®šåŸºåº•至 %s" #: builtin/branch.c #, c-format msgid "branch %s is being bisected at %s" -msgstr "%s åˆ†æ”¯æ£æ–¼ %s 進行二分æœå°‹" +msgstr "分支 %s æ£æ–¼ %s 進行二分æœå°‹" #: builtin/branch.c #, c-format msgid "HEAD of working tree %s is not updated" -msgstr "%s 工作å€çš„ HEAD æŒ‡é‡æœªè¢«æ›´æ–°" +msgstr "%s 工作å€çš„ HEAD 指標未被更新" #: builtin/branch.c #, c-format msgid "invalid branch name: '%s'" -msgstr "分支å稱無效:“%sâ€" +msgstr "分支å稱無效:「%sã€" #: builtin/branch.c #, c-format msgid "no commit on branch '%s' yet" -msgstr "分支 “%s†尚無æäº¤" +msgstr "分支「%sã€å°šç„¡æäº¤" #: builtin/branch.c #, c-format msgid "no branch named '%s'" -msgstr "沒有å為 “%s†的分支" +msgstr "沒有å為「%sã€çš„分支" #: builtin/branch.c msgid "branch rename failed" @@ -3476,17 +3493,17 @@ msgstr "分支拷è²å¤±æ•—" #: builtin/branch.c #, c-format msgid "created a copy of a misnamed branch '%s'" -msgstr "已為誤命åçš„ “%s†分支建立拷è²" +msgstr "已為誤命å的分支「%sã€å»ºç«‹æ‹·è²" #: builtin/branch.c #, c-format msgid "renamed a misnamed branch '%s' away" -msgstr "已更改誤命åçš„ “%s†分支的å稱" +msgstr "已更改誤命å的分支「%sã€çš„å稱" #: builtin/branch.c #, c-format msgid "branch renamed to %s, but HEAD is not updated" -msgstr "åˆ†æ”¯å·²é‡æ–°å‘½å為 %s,但 HEAD 指é‡å°šæœªæ›´æ–°" +msgstr "åˆ†æ”¯å·²é‡æ–°å‘½å為 %s,但 HEAD 指標尚未更新" #: builtin/branch.c msgid "branch is renamed, but update of config-file failed" @@ -3581,7 +3598,7 @@ msgstr "å³ä½¿ç›®æ¨™å·²å˜åœ¨ï¼Œä»ç§»å‹•æˆ–é‡æ–°å‘½å分支" #: builtin/branch.c builtin/for-each-ref.c builtin/tag.c msgid "do not output a newline after empty formatted refs" -msgstr "åœ¨æ ¼å¼åŒ–å¼•ç”¨çµæžœç‚ºç©ºä¹‹å¾Œï¼Œä¸è¦è¼¸å‡ºæ›åˆ—符號" +msgstr "åœ¨æ ¼å¼åŒ–çµæžœç‚ºç©ºçš„引用之後,ä¸è¦è¼¸å‡ºæ›åˆ—符號" #: builtin/branch.c msgid "copy a branch and its reflog" @@ -3650,7 +3667,7 @@ msgstr "無法將 HEAD è§£æžç‚ºæœ‰æ•ˆå¼•用" #: builtin/branch.c builtin/clone.c msgid "HEAD not found below refs/heads!" -msgstr "HEAD 指é‡ä¸åœ¨ /refs/heads ä¸ï¼" +msgstr "HEAD 指標ä¸åœ¨ /refs/heads ä¸ï¼" #: builtin/branch.c msgid "" @@ -3669,7 +3686,7 @@ msgstr "å¿…é ˆæä¾›åˆ†æ”¯å稱" #: builtin/branch.c msgid "cannot give description to detached HEAD" -msgstr "無法å‘分離 HEAD æŒ‡é‡æä¾›æè¿°" +msgstr "無法å‘分離 HEAD 指標æä¾›æè¿°" #: builtin/branch.c msgid "cannot edit description of more than one branch" @@ -3704,12 +3721,12 @@ msgstr "無法將 HEAD 的上游è¨ç‚º %s:其未指å‘任何分支" #: builtin/branch.c #, c-format msgid "no such branch '%s'" -msgstr "ç„¡ “%s†分支" +msgstr "無「%sã€åˆ†æ”¯" #: builtin/branch.c #, c-format msgid "branch '%s' does not exist" -msgstr "沒有 “%s†分支" +msgstr "沒有「%sã€åˆ†æ”¯" #: builtin/branch.c msgid "too many arguments to unset upstream" @@ -3722,21 +3739,22 @@ msgstr "ç„¡æ³•å–æ¶ˆè¨å®š HEAD 的上游:其未指å‘任何分支" #: builtin/branch.c #, c-format msgid "branch '%s' has no upstream information" -msgstr "分支 “%s†沒有上游資訊" +msgstr "分支「%sã€æ²’有上游資訊" #: builtin/branch.c msgid "" "the -a, and -r, options to 'git branch' do not take a branch name.\n" "Did you mean to use: -a|-r --list <pattern>?" msgstr "" -"“git branch†的 -a å’Œ -r é¸é …ä¸å–分支å稱。\n" +"「git branchã€çš„ -a å’Œ -r é¸é …ä¸å–分支å稱。\n" "您是想使用:-a|-r --list <pattern> 嗎?" #: builtin/branch.c msgid "" "the '--set-upstream' option is no longer supported. Please use '--track' or " "'--set-upstream-to' instead" -msgstr "ä¸å†æ”¯æ´é¸é … “--set-upstreamâ€ã€‚請改用 “--track†或 “--set-upstream-toâ€" +msgstr "" +"ä¸å†æ”¯æ´é¸é …「--set-upstreamã€ã€‚請改用「--trackã€æˆ–「--set-upstream-toã€" #: builtin/bugreport.c msgid "git version:\n" @@ -3745,7 +3763,7 @@ msgstr "git 版本:\n" #: builtin/bugreport.c #, c-format msgid "uname() failed with error '%s' (%d)\n" -msgstr "uname() 失敗,錯誤:“%s†(%d)\n" +msgstr "uname() 失敗,錯誤:「%sã€(%d)\n" #: builtin/bugreport.c msgid "compiler info: " @@ -3811,7 +3829,7 @@ msgstr "mode" #: builtin/bugreport.c msgid "" "create an additional zip archive of detailed diagnostics (default 'stats')" -msgstr "å¦å¤–建立有詳細診斷資訊的 ZIP å°å˜æª”(é è¨å€¼ “statsâ€ï¼‰" +msgstr "å¦å¤–建立有詳細診斷資訊的 ZIP å°å˜æª”(é è¨å€¼ã€Œstatsã€ï¼‰" #: builtin/bugreport.c msgid "specify a destination for the bugreport file(s)" @@ -3824,12 +3842,12 @@ msgstr "指定用於檔åçš„ strftime æ ¼å¼å¾Œç¶´" #: builtin/bugreport.c #, c-format msgid "unknown argument `%s'" -msgstr "未知引數 “%sâ€" +msgstr "未知引數「%sã€" #: builtin/bugreport.c builtin/diagnose.c #, c-format msgid "could not create leading directories for '%s'" -msgstr "無法建立 “%s†的å‰ç½®ç›®éŒ„" +msgstr "無法建立「%sã€çš„å‰ç½®ç›®éŒ„" #: builtin/bugreport.c builtin/diagnose.c #, c-format @@ -3852,7 +3870,7 @@ msgstr "無法寫入 %s" #: builtin/bugreport.c #, c-format msgid "Created new report at '%s'.\n" -msgstr "已在 “%sâ€ å»ºç«‹æ–°å ±å‘Šã€‚\n" +msgstr "已在「%sã€å»ºç«‹æ–°å ±å‘Šã€‚\n" #: builtin/bundle.c msgid "" @@ -3906,6 +3924,10 @@ msgstr "需è¦ç‰ˆæœ¬åº«ä¾†å»ºç«‹å¥—件包。" msgid "do not show bundle details" msgstr "ä¸é¡¯ç¤ºå¥—件包的詳細資訊" +#: builtin/bundle.c bundle.c +msgid "need a repository to verify a bundle" +msgstr "需è¦ç‰ˆæœ¬åº«é©—è‰å¥—件包" + #: builtin/bundle.c #, c-format msgid "%s is okay\n" @@ -3922,7 +3944,7 @@ msgstr "æ£åœ¨æ‹†åˆ†ç‰©ä»¶" #: builtin/cat-file.c merge-recursive.c #, c-format msgid "cannot read object %s '%s'" -msgstr "無法讀å–物件 %s “%sâ€" +msgstr "無法讀å–物件 %s「%sã€" #: builtin/cat-file.c msgid "flush is only for --buffer mode" @@ -3935,7 +3957,7 @@ msgstr "è¼¸å…¥ä¸æ²’有命令" #: builtin/cat-file.c #, c-format msgid "whitespace before command: '%s'" -msgstr "命令剿œ‰ç©ºæ ¼ï¼šâ€œ%sâ€" +msgstr "命令剿œ‰ç©ºæ ¼ï¼šã€Œ%sã€" #: builtin/cat-file.c #, c-format @@ -4001,7 +4023,8 @@ msgstr "輸出 [æå£žçš„] ([broken]) 物件屬性" #: builtin/cat-file.c msgid "show object type (one of 'blob', 'tree', 'commit', 'tag', ...)" -msgstr "顯示物件類型(å¯ä»¥æ˜¯ “blobâ€ã€â€œtreeâ€ã€â€œcommitâ€ã€â€œtag†ç‰å…¶ä¸ä¸€å€‹ï¼‰" +msgstr "" +"顯示物件類型(å¯ä»¥æ˜¯ã€Œblobã€ã€ã€Œtreeã€ã€ã€Œcommitã€ã€ã€Œtagã€ç‰å…¶ä¸ä¸€å€‹ï¼‰" #: builtin/cat-file.c msgid "show object size" @@ -4079,12 +4102,12 @@ msgstr "blob|tree" #: builtin/cat-file.c msgid "use a <path> for (--textconv | --filters); Not with 'batch'" -msgstr "請在 (--textconv | --filters) 使用 <path>ï¼Œè€Œéž â€œbatchâ€" +msgstr "請在 (--textconv | --filters) 使用 <path>,而éžã€Œbatchã€" #: builtin/cat-file.c #, c-format msgid "'%s=<%s>' needs '%s' or '%s'" -msgstr "“%s=<%s>â€ éœ€è¦ â€œ%s†或 “%sâ€" +msgstr "「%s=<%s>ã€éœ€è¦ã€Œ%sã€æˆ–「%sã€" #: builtin/cat-file.c msgid "path|tree-ish" @@ -4093,12 +4116,12 @@ msgstr "path|tree-ish" #: builtin/cat-file.c #, c-format msgid "'%s' requires a batch mode" -msgstr "“%sâ€ éœ€è¦æ‰¹æ¬¡è™•ç†æ¨¡å¼" +msgstr "「%sã€éœ€è¦æ‰¹æ¬¡è™•ç†æ¨¡å¼" #: builtin/cat-file.c #, c-format msgid "'-%c' is incompatible with batch mode" -msgstr "“-%câ€ èˆ‡æ‰¹æ¬¡è™•ç†æ¨¡å¼ä¸ç›¸å®¹" +msgstr "「-%cã€èˆ‡æ‰¹æ¬¡è™•ç†æ¨¡å¼ä¸ç›¸å®¹" #: builtin/cat-file.c msgid "batch modes take no arguments" @@ -4107,12 +4130,12 @@ msgstr "æ‰¹æ¬¡è™•ç†æ¨¡å¼ä¸å–引數" #: builtin/cat-file.c #, c-format msgid "<rev> required with '%s'" -msgstr "“%sâ€ éœ€è¦ <rev>" +msgstr "「%sã€éœ€è¦ <rev>" #: builtin/cat-file.c #, c-format msgid "<object> required with '-%c'" -msgstr "“-%câ€ éœ€è¦ <object>" +msgstr "「-%cã€éœ€è¦ <object>" #: builtin/cat-file.c #, c-format @@ -4286,32 +4309,32 @@ msgstr "git restore [<options>] [--source=<branch>] <file>..." #: builtin/checkout.c #, c-format msgid "path '%s' does not have our version" -msgstr "“%s†路徑沒有我們的版本" +msgstr "「%sã€è·¯å¾‘沒有我們的版本" #: builtin/checkout.c #, c-format msgid "path '%s' does not have their version" -msgstr "“%s†路徑沒有他們的版本" +msgstr "「%sã€è·¯å¾‘沒有他們的版本" #: builtin/checkout.c #, c-format msgid "path '%s' does not have all necessary versions" -msgstr "“%sâ€ è·¯å¾‘æ²’æœ‰æ‰€æœ‰å¿…é ˆçš„ç‰ˆæœ¬" +msgstr "「%sã€è·¯å¾‘æ²’æœ‰æ‰€æœ‰å¿…é ˆçš„ç‰ˆæœ¬" #: builtin/checkout.c #, c-format msgid "path '%s' does not have necessary versions" -msgstr "“%sâ€ è·¯å¾‘æ²’æœ‰å¿…é ˆçš„ç‰ˆæœ¬" +msgstr "「%sã€è·¯å¾‘æ²’æœ‰å¿…é ˆçš„ç‰ˆæœ¬" #: builtin/checkout.c #, c-format msgid "path '%s': cannot merge" -msgstr "path “%sâ€ï¼šç„¡æ³•åˆä½µ" +msgstr "path「%sã€ï¼šç„¡æ³•åˆä½µ" #: builtin/checkout.c #, c-format msgid "Unable to add merge result for '%s'" -msgstr "無法為 “%sâ€ åŠ ä¸Šåˆä½µçµæžœ" +msgstr "無法為「%sã€åŠ ä¸Šåˆä½µçµæžœ" #: builtin/checkout.c #, c-format @@ -4334,37 +4357,37 @@ msgstr[0] "å·²å¾žç´¢å¼•å€æ›´æ–° %d 個路徑" #: builtin/checkout.c #, c-format msgid "'%s' cannot be used with updating paths" -msgstr "無法在更新路徑時使用 “%sâ€" +msgstr "無法在更新路徑時使用「%sã€" #: builtin/checkout.c #, c-format msgid "Cannot update paths and switch to branch '%s' at the same time." -msgstr "ç„¡æ³•åŒæ™‚更新路徑和切æ›è‡³ “%s†分支。" +msgstr "ç„¡æ³•åŒæ™‚更新路徑和切æ›è‡³ã€Œ%sã€åˆ†æ”¯ã€‚" #: builtin/checkout.c #, c-format msgid "neither '%s' or '%s' is specified" -msgstr "“%s†或 “%s†皆未指定" +msgstr "「%sã€æˆ–「%sã€çš†æœªæŒ‡å®š" #: builtin/checkout.c #, c-format msgid "'%s' must be used when '%s' is not specified" -msgstr "未指定 “%2$sâ€ æ™‚ï¼Œå¿…é ˆä½¿ç”¨ “%1$sâ€" +msgstr "未指定「%2$sã€æ™‚ï¼Œå¿…é ˆä½¿ç”¨ã€Œ%1$sã€" #: builtin/checkout.c #, c-format msgid "'%s' or '%s' cannot be used with %s" -msgstr "“%s†或 “%s†無法與 %s 一起使用" +msgstr "「%sã€æˆ–「%sã€ç„¡æ³•與 %s 一起使用" #: builtin/checkout.c #, c-format msgid "'%s', '%s', or '%s' cannot be used when checking out of a tree" -msgstr "“%sâ€ã€â€œ%s†或 “%s†無法在簽出樹狀物件時使用" +msgstr "「%sã€ã€ã€Œ%sã€æˆ–「%sã€ç„¡æ³•在簽出樹狀物件時使用" #: builtin/checkout.c #, c-format msgid "path '%s' is unmerged" -msgstr "路徑 “%s†未åˆä½µ" +msgstr "路徑「%sã€æœªåˆä½µ" #: builtin/checkout.c builtin/grep.c builtin/merge-tree.c builtin/reset.c #: merge-ort.c reset.c sequencer.c tree-walk.c @@ -4388,7 +4411,7 @@ msgstr "" #: builtin/checkout.c #, c-format msgid "Can not do reflog for '%s': %s\n" -msgstr "ç„¡æ³•å° â€œ%s†執行 reflog 動作:%s\n" +msgstr "無法å°ã€Œ%sã€åŸ·è¡Œ reflog 動作:%s\n" #: builtin/checkout.c msgid "HEAD is now at" @@ -4401,27 +4424,27 @@ msgstr "無法更新 HEAD" #: builtin/checkout.c #, c-format msgid "Reset branch '%s'\n" -msgstr "é‡è¨åˆ†æ”¯ “%sâ€\n" +msgstr "é‡è¨åˆ†æ”¯ã€Œ%sã€\n" #: builtin/checkout.c #, c-format msgid "Already on '%s'\n" -msgstr "å·²ç¶“ä½æ–¼ “%sâ€\n" +msgstr "å·²ç¶“ä½æ–¼ã€Œ%sã€\n" #: builtin/checkout.c #, c-format msgid "Switched to and reset branch '%s'\n" -msgstr "已切æ›ä¸¦é‡è¨åˆ†æ”¯ “%sâ€\n" +msgstr "已切æ›ä¸¦é‡è¨åˆ†æ”¯ã€Œ%sã€\n" #: builtin/checkout.c #, c-format msgid "Switched to a new branch '%s'\n" -msgstr "已切æ›è‡³æ–°åˆ†æ”¯ “%sâ€\n" +msgstr "已切æ›è‡³æ–°åˆ†æ”¯ã€Œ%sã€\n" #: builtin/checkout.c #, c-format msgid "Switched to branch '%s'\n" -msgstr "已切æ›è‡³åˆ†æ”¯ “%sâ€\n" +msgstr "已切æ›è‡³åˆ†æ”¯ã€Œ%sã€\n" # è¯è€…ï¼šè«‹ç¶æŒå‰å°Žç©ºæ ¼ #: builtin/checkout.c @@ -4474,7 +4497,7 @@ msgstr "åœ¨ä¿®è¨‚ç‰ˆéæ·æ™‚é‡åˆ°å…§éƒ¨éŒ¯èª¤" #: builtin/checkout.c msgid "Previous HEAD position was" -msgstr "之å‰çš„ HEAD 指é‡ä½ç½®åœ¨" +msgstr "之å‰çš„ HEAD 指標ä½ç½®åœ¨" #: builtin/checkout.c msgid "You are on a branch yet to be born" @@ -4486,7 +4509,7 @@ msgid "" "'%s' could be both a local file and a tracking branch.\n" "Please use -- (and optionally --no-guess) to disambiguate" msgstr "" -"“%s†既å¯ä»¥æ˜¯æœ¬æ©Ÿæª”案,也å¯ä»¥æ˜¯è¿½è¹¤åˆ†æ”¯ã€‚\n" +"「%sã€æ—¢å¯ä»¥æ˜¯æœ¬æ©Ÿæª”案,也å¯ä»¥æ˜¯è¿½è¹¤åˆ†æ”¯ã€‚\n" "請使用 --(和å¯é¸çš„ --no-guess)來消除æ§ç¾©" #: builtin/checkout.c @@ -4500,19 +4523,19 @@ msgid "" "one remote, e.g. the 'origin' remote, consider setting\n" "checkout.defaultRemote=origin in your config." msgstr "" -"如果您想è¦ç°½å‡ºé 端追蹤分支,例如 “originâ€ï¼Œ\n" +"如果您想è¦ç°½å‡ºé 端追蹤分支,例如「originã€ï¼Œ\n" "您å¯ä»¥ä½¿ç”¨ --track é¸é …寫出全å:\n" "\n" " git checkout --track origin/<name>\n" "\n" "如果您平時比較想è¦ä½¿ç”¨æ¨¡ç³Šçš„ç°¡çŸåˆ†æ”¯å稱 <name>,\n" -"而ä¸å¤ªæƒ³å¯«å¦‚ “origin†的é 端版本庫å稱,\n" +"而ä¸å¤ªæƒ³å¯«å¦‚「originã€çš„é 端版本庫å稱,\n" "å¯ä»¥åœ¨çµ„æ…‹ä¸è¨å®š checkout.defaultRemote=origin。" #: builtin/checkout.c #, c-format msgid "'%s' matched multiple (%d) remote tracking branches" -msgstr "“%s†符åˆå¤šå€‹ (%d) é 端追蹤分支" +msgstr "「%sã€ç¬¦åˆå¤šå€‹ (%d) é 端追蹤分支" #: builtin/checkout.c msgid "only one reference expected" @@ -4536,27 +4559,27 @@ msgstr "å¼•ç”¨ä¸æ˜¯æ¨¹ç‹€ç‰©ä»¶ï¼š%s" #: builtin/checkout.c #, c-format msgid "a branch is expected, got tag '%s'" -msgstr "é æœŸæ”¶åˆ°åˆ†æ”¯ï¼Œå»æ”¶åˆ°æ¨™ç±¤ “%sâ€" +msgstr "é æœŸæ”¶åˆ°åˆ†æ”¯ï¼Œå»æ”¶åˆ°æ¨™ç±¤ã€Œ%sã€" #: builtin/checkout.c #, c-format msgid "a branch is expected, got remote branch '%s'" -msgstr "é æœŸæ”¶åˆ°åˆ†æ”¯ï¼Œå»æ”¶åˆ°é 端分支 “%sâ€" +msgstr "é æœŸæ”¶åˆ°åˆ†æ”¯ï¼Œå»æ”¶åˆ°é 端分支「%sã€" #: builtin/checkout.c #, c-format msgid "a branch is expected, got '%s'" -msgstr "é æœŸæ”¶åˆ°åˆ†æ”¯ï¼Œå»æ”¶åˆ° “%sâ€" +msgstr "é æœŸæ”¶åˆ°åˆ†æ”¯ï¼Œå»æ”¶åˆ°ã€Œ%sã€" #: builtin/checkout.c #, c-format msgid "a branch is expected, got commit '%s'" -msgstr "é æœŸæ”¶åˆ°åˆ†æ”¯ï¼Œå»æ”¶åˆ°æäº¤ “%sâ€" +msgstr "é æœŸæ”¶åˆ°åˆ†æ”¯ï¼Œå»æ”¶åˆ°æäº¤ã€Œ%sã€" #: builtin/checkout.c msgid "" "If you want to detach HEAD at the commit, try again with the --detach option." -msgstr "若您想è¦åœ¨æ¤æäº¤åˆ†é›¢ HEAD 指é‡ï¼Œè«‹å‚³å…¥ --detach é¸é …é‡è©¦ã€‚" +msgstr "若您想è¦åœ¨æ¤æäº¤åˆ†é›¢ HEAD 指標,請傳入 --detach é¸é …é‡è©¦ã€‚" #: builtin/checkout.c msgid "" @@ -4564,7 +4587,7 @@ msgid "" "Consider \"git merge --quit\" or \"git worktree add\"." msgstr "" "無法在åˆä½µæ™‚切æ›åˆ†æ”¯\n" -"請試試 “git merge --quit†或 “git worktree addâ€ã€‚" +"請試試「git merge --quitã€æˆ–「git worktree addã€ã€‚" #: builtin/checkout.c msgid "" @@ -4572,7 +4595,7 @@ msgid "" "Consider \"git am --quit\" or \"git worktree add\"." msgstr "" "無法在 am 工作階段期間時切æ›åˆ†æ”¯\n" -"請試試 “git am --quit†或 “git worktree addâ€ã€‚" +"請試試「git am --quitã€æˆ–「git worktree addã€ã€‚" #: builtin/checkout.c msgid "" @@ -4580,7 +4603,7 @@ msgid "" "Consider \"git rebase --quit\" or \"git worktree add\"." msgstr "" "無法在é‡å®šåŸºåº•時切æ›åˆ†æ”¯\n" -"請試試 “git rebase --quit†或 “git worktree addâ€ã€‚" +"請試試「git rebase --quitã€æˆ–「git worktree addã€ã€‚" #: builtin/checkout.c msgid "" @@ -4588,7 +4611,7 @@ msgid "" "Consider \"git cherry-pick --quit\" or \"git worktree add\"." msgstr "" "無法在æ€é¸æ™‚切æ›åˆ†æ”¯\n" -"請試試 “git cherry-pick --quit†或 “git worktree addâ€ã€‚" +"請試試「git cherry-pick --quitã€æˆ–「git worktree addã€ã€‚" #: builtin/checkout.c msgid "" @@ -4596,7 +4619,7 @@ msgid "" "Consider \"git revert --quit\" or \"git worktree add\"." msgstr "" "無法在還原時切æ›åˆ†æ”¯\n" -"請試試 “git revert --quit†或 “git worktree addâ€ã€‚" +"請試試「git revert --quitã€æˆ–「git worktree addã€ã€‚" #: builtin/checkout.c msgid "you are switching branch while bisecting" @@ -4609,22 +4632,22 @@ msgstr "路徑ä¸èƒ½èˆ‡åˆ‡æ›åˆ†æ”¯åŒæ™‚使用" #: builtin/checkout.c #, c-format msgid "'%s' cannot be used with switching branches" -msgstr "“%s†ä¸èƒ½èˆ‡åˆ‡æ›åˆ†æ”¯åŒæ™‚使用" +msgstr "「%sã€ä¸èƒ½èˆ‡åˆ‡æ›åˆ†æ”¯åŒæ™‚使用" #: builtin/checkout.c #, c-format msgid "'%s' cannot be used with '%s'" -msgstr "“%s†ä¸èƒ½èˆ‡ “%sâ€ åŒæ™‚使用" +msgstr "「%sã€ä¸èƒ½èˆ‡ã€Œ%sã€åŒæ™‚使用" #: builtin/checkout.c #, c-format msgid "'%s' cannot take <start-point>" -msgstr "“%s†ä¸å– <start-point>" +msgstr "「%sã€ä¸å– <start-point>" #: builtin/checkout.c #, c-format msgid "Cannot switch branch to a non-commit '%s'" -msgstr "無法將分支切æ›è‡³éžæäº¤é …ç›® “%sâ€" +msgstr "無法將分支切æ›è‡³éžæäº¤é …目「%sã€" #: builtin/checkout.c msgid "missing branch or commit argument" @@ -4649,7 +4672,7 @@ msgstr "è¡çªè¼¸å‡ºé¢¨æ ¼ï¼ˆmergeã€diff3 或 zdiff3)" #: builtin/checkout.c builtin/worktree.c msgid "detach HEAD at named commit" -msgstr "自指定æäº¤åˆ†é›¢ HEAD 指é‡" +msgstr "自指定æäº¤åˆ†é›¢ HEAD 指標" #: builtin/checkout.c msgid "force checkout (throw away local modifications)" @@ -4686,7 +4709,7 @@ msgstr "å°è·¯å¾‘è¦æ ¼ä¸åšç¨€ç–簽出的é™åˆ¶" #: builtin/checkout.c #, c-format msgid "options '-%c', '-%c', and '%s' cannot be used together" -msgstr "“-%câ€ã€â€œ-%c†和 “%s†é¸é …ä¸å¾—åŒæ™‚使用" +msgstr "「-%cã€ã€ã€Œ-%cã€å’Œã€Œ%sã€é¸é …ä¸å¾—åŒæ™‚使用" #: builtin/checkout.c msgid "--track needs a branch name" @@ -4709,12 +4732,12 @@ msgstr "ç„¡æ•ˆçš„è·¯å¾‘è¦æ ¼" #: builtin/checkout.c #, c-format msgid "'%s' is not a commit and a branch '%s' cannot be created from it" -msgstr "“%sâ€ ä¸æ˜¯æäº¤ï¼Œå› æ¤ä¸èƒ½ä»¥é€™ç‚ºåŸºç¤Žå»ºç«‹ “%s†分支" +msgstr "「%sã€ä¸æ˜¯æäº¤ï¼Œå› æ¤ä¸èƒ½ä»¥é€™ç‚ºåŸºç¤Žå»ºç«‹ã€Œ%sã€åˆ†æ”¯" #: builtin/checkout.c #, c-format msgid "git checkout: --detach does not take a path argument '%s'" -msgstr "git checkout:--detach ä¸å–路徑引數 “%sâ€" +msgstr "git checkout:--detach ä¸å–路徑引數「%sã€" #: builtin/checkout.c msgid "" @@ -4747,7 +4770,7 @@ msgstr "為新分支建立引用日誌" #: builtin/checkout.c msgid "second guess 'git checkout <no-such-branch>' (default)" -msgstr "二次猜測 “git checkout <ç„¡æ¤åˆ†æ”¯>â€ï¼ˆé è¨å€¼ï¼‰" +msgstr "二次猜測「git checkout <ç„¡æ¤åˆ†æ”¯>ã€ï¼ˆé è¨å€¼ï¼‰" #: builtin/checkout.c msgid "use overlay mode (default)" @@ -4763,7 +4786,7 @@ msgstr "建立/é‡è¨ä¸¦åˆ‡æ›è‡³æŒ‡å®šåˆ†æ”¯" #: builtin/checkout.c msgid "second guess 'git switch <no-such-branch>'" -msgstr "二次猜測 “git switch <ç„¡æ¤åˆ†æ”¯>â€" +msgstr "二次猜測「git switch <ç„¡æ¤åˆ†æ”¯>ã€" #: builtin/checkout.c msgid "throw away local modifications" @@ -4907,7 +4930,7 @@ msgstr "" "clean - 開始清ç†\n" "filter by pattern - é€éŽç¯„本排除è¦åˆªé™¤çš„æ¢ç›®\n" "select by numbers - é€éŽæ•¸å—鏿“‡è¦åˆªé™¤çš„æ¢ç›®\n" -"ask each - é‡å°åˆªé™¤é€ä¸€è©¢å•ï¼ˆå°±åƒ â€œrm -iâ€ï¼‰\n" +"ask each - é‡å°åˆªé™¤é€ä¸€è©¢å•(就åƒã€Œrm -iã€ï¼‰\n" "quit - åœæ¢åˆªé™¤ä¸¦é›¢é–‹\n" "help - 顯示本輔助說明\n" "? - 顯示如何在æç¤ºä¸‹é¸æ“‡çš„å”助" @@ -4937,9 +4960,9 @@ msgstr "äº’å‹•å¼æ¸…除" msgid "remove whole directories" msgstr "移除整個目錄" -#: builtin/clean.c builtin/describe.c builtin/grep.c builtin/log.c -#: builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c builtin/show-ref.c -#: ref-filter.h +#: builtin/clean.c builtin/config.c builtin/describe.c builtin/grep.c +#: builtin/log.c builtin/ls-files.c builtin/name-rev.c builtin/pack-refs.c +#: builtin/show-ref.c ref-filter.h msgid "pattern" msgstr "pattern" @@ -5027,7 +5050,7 @@ msgstr "name" #: builtin/clone.c msgid "use <name> instead of 'origin' to track upstream" -msgstr "使用 <name> è€Œä¸æ˜¯ “origin†追蹤上游" +msgstr "使用 <name> è€Œä¸æ˜¯ã€Œoriginã€è¿½è¹¤ä¸Šæ¸¸" #: builtin/clone.c msgid "checkout <branch> instead of the remote's HEAD" @@ -5138,7 +5161,7 @@ msgstr "%s å˜åœ¨ä¸”䏿˜¯ä¸€å€‹ç›®éŒ„" #: builtin/clone.c #, c-format msgid "'%s' is a symlink, refusing to clone with --local" -msgstr "“%s†是個符號連çµï¼Œæ•…ä¸èƒ½ä½¿ç”¨ --local 複製" +msgstr "「%sã€æ˜¯å€‹ç¬¦è™Ÿé€£çµï¼Œæ•…ä¸èƒ½ä½¿ç”¨ --local 複製" #: builtin/clone.c #, c-format @@ -5153,7 +5176,17 @@ msgstr "「%sã€ç¬¦è™Ÿé€£çµå·²å˜åœ¨ï¼Œæ‹’絕使用 --local 複製" #: builtin/clone.c compat/precompose_utf8.c #, c-format msgid "failed to unlink '%s'" -msgstr "無法刪除 “%sâ€" +msgstr "無法刪除「%sã€" + +#: builtin/clone.c +#, c-format +msgid "hardlink cannot be checked at '%s'" +msgstr "ç„¡æ³•æª¢æŸ¥ä½æ–¼ã€Œ%sã€çš„硬連çµ" + +#: builtin/clone.c +#, c-format +msgid "hardlink different from source at '%s'" +msgstr "硬連çµèˆ‡ä½æ–¼ '%s' 的來æºä¸åŒ" #: builtin/clone.c #, c-format @@ -5231,10 +5264,10 @@ msgstr "å¤ªå¤šåƒæ•¸ã€‚" msgid "You must specify a repository to clone." msgstr "æ‚¨å¿…é ˆæŒ‡å®šè¦è¤‡è£½çš„版本庫。" -#: builtin/clone.c builtin/init-db.c setup.c +#: builtin/clone.c builtin/init-db.c builtin/refs.c setup.c #, c-format msgid "unknown ref storage format '%s'" -msgstr "æœªçŸ¥çš„å¼•ç”¨å„²å˜æ ¼å¼ “%sâ€" +msgstr "æœªçŸ¥çš„å¼•ç”¨å„²å˜æ ¼å¼ã€Œ%sã€" #: builtin/clone.c #, c-format @@ -5331,7 +5364,7 @@ msgstr "無法åˆå§‹åŒ–版本庫,略éŽå¥—件包 URI" #: builtin/clone.c #, c-format msgid "failed to fetch objects from bundle URI '%s'" -msgstr "無法從套件包 URL “%s†抓å–物件" +msgstr "無法從套件包 URL「%sã€æŠ“å–物件" #: builtin/clone.c msgid "failed to fetch advertised bundles" @@ -5391,7 +5424,7 @@ msgstr "--command å¿…é ˆæ˜¯ç¬¬ä¸€å€‹åƒæ•¸" msgid "" "git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]" msgstr "" -"git commit-graph verify [--object-dir <目錄>] [--shallow] [--[no-]progress]" +"git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]" #: builtin/commit-graph.c msgid "" @@ -5415,21 +5448,21 @@ msgstr "目錄" #: builtin/commit-graph.c msgid "the object directory to store the graph" -msgstr "儲å˜åœ–形的物件目錄" +msgstr "儲å˜åœ–的物件目錄" #: builtin/commit-graph.c msgid "if the commit-graph is split, only verify the tip file" -msgstr "如果æäº¤åœ–形被分割,åªé©—è‰é 一個檔案" +msgstr "如果æäº¤åœ–被分割,åªé©—è‰é 一個檔案" #: builtin/commit-graph.c #, c-format msgid "Could not open commit-graph '%s'" -msgstr "無法開啟æäº¤åœ–å½¢ '%s'" +msgstr "無法開啟æäº¤åœ–「%sã€" #: builtin/commit-graph.c #, c-format msgid "could not open commit-graph chain '%s'" -msgstr "無法開啟æäº¤åœ–éˆ â€œ%sâ€" +msgstr "無法開啟æäº¤åœ–éˆã€Œ%sã€" #: builtin/commit-graph.c #, c-format @@ -5465,7 +5498,7 @@ msgstr "從標準輸入ä¸çš„æäº¤é–‹å§‹æŽƒæ" #: builtin/commit-graph.c msgid "include all commits already in the commit-graph file" -msgstr "åŒ…å« commit-graph 檔案ä¸å·²æœ‰æ‰€æœ‰æäº¤" +msgstr "åŒ…å«æäº¤åœ–æª”æ¡ˆä¸æ‰€æœ‰å·²æœ‰çš„æäº¤" #: builtin/commit-graph.c msgid "enable computation for changed paths" @@ -5473,15 +5506,15 @@ msgstr "啟用已變更路徑的計算" #: builtin/commit-graph.c msgid "allow writing an incremental commit-graph file" -msgstr "å…è¨±å¯«ä¸€å€‹å¢žé‡æäº¤åœ–å½¢æª”æ¡ˆ" +msgstr "å…è¨±å¯«ä¸€å€‹å¢žé‡æäº¤åœ–æª”æ¡ˆ" #: builtin/commit-graph.c msgid "maximum number of commits in a non-base split commit-graph" -msgstr "在éžåŸºæœ¬åˆ†å‰²æäº¤åœ–å½¢ä¸çš„æœ€å¤§æäº¤æ•¸" +msgstr "在éžåŸºç¤Žåˆ†å‰²æäº¤åœ–ä¸çš„æœ€å¤§æäº¤æ•¸" #: builtin/commit-graph.c msgid "maximum ratio between two levels of a split commit-graph" -msgstr "一個分割æäº¤åœ–形的兩個級別之間的最大比率" +msgstr "一個分割æäº¤åœ–的兩個級別之間的最大比率" #: builtin/commit-graph.c msgid "only expire files older than a given date-time" @@ -5719,7 +5752,7 @@ msgstr "ç„¡æ³•é¸æ“‡ä¸€å€‹æœªè¢«ç›®å‰æäº¤èªªæ˜Žä½¿ç”¨çš„備註å—å…ƒ" #: builtin/commit.c #, c-format msgid "could not lookup commit '%s'" -msgstr "無法查詢æäº¤ “%sâ€" +msgstr "無法查詢æäº¤ã€Œ%sã€" #: builtin/commit.c builtin/shortlog.c #, c-format @@ -5845,7 +5878,7 @@ msgstr "%sæäº¤è€…:%.*s <%.*s>" msgid "Cannot read index" msgstr "無法讀å–索引" -#: builtin/commit.c +#: builtin/commit.c builtin/tag.c msgid "unable to pass trailers to --trailers" msgstr "無法將尾部署å傳éžè‡³ --trailers" @@ -6056,11 +6089,11 @@ msgstr "使用 autosquash æ ¼å¼çš„æäº¤èªªæ˜Žç”¨ä»¥å£“縮至指定的æäº¤" msgid "the commit is authored by me now (used with -C/-c/--amend)" msgstr "ç¾åœ¨å°‡è©²æäº¤çš„作者改為我(和 -C/-c/--amend åƒæ•¸å…±ç”¨ï¼‰" -#: builtin/commit.c builtin/interpret-trailers.c +#: builtin/commit.c builtin/interpret-trailers.c builtin/tag.c msgid "trailer" msgstr "尾部署å" -#: builtin/commit.c +#: builtin/commit.c builtin/tag.c msgid "add custom trailer(s)" msgstr "åŠ å…¥è‡ªè¨‚å°¾éƒ¨ç½²å" @@ -6169,20 +6202,60 @@ msgid "" "not exceeded, and then \"git restore --staged :/\" to recover." msgstr "" "版本庫已更新,但無法寫入新的索引檔案。請檢查ç£ç¢Ÿæ˜¯å¦\n" -"已滿或ç£ç¢Ÿé…é¡å·²è€—盡,然後執行 “git restore --staged :/†復原。" +"已滿或ç£ç¢Ÿé…é¡å·²è€—盡,然後執行「git restore --staged :/ã€å¾©åŽŸã€‚" #: builtin/config.c -msgid "git config [<options>]" -msgstr "git config [<é¸é …>]" +msgid "git config list [<file-option>] [<display-option>] [--includes]" +msgstr "git config list [<檔案é¸é …>] [<顯示é¸é …>] [--includes]" #: builtin/config.c -#, c-format -msgid "unrecognized --type argument, %s" -msgstr "無法è˜åˆ¥çš„ --type åƒæ•¸ï¼Œ%s" +msgid "" +"git config get [<file-option>] [<display-option>] [--includes] [--all] [--" +"regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] " +"<name>" +msgstr "" +"git config get [<檔案é¸é …>] [<顯示é¸é …>] [--includes] [--all] [--regexp=<常è¦" +"表示å¼>] [--value=<值>] [--fixed-value] [--default=<é è¨å€¼>] <å稱>" #: builtin/config.c -msgid "only one type at a time" -msgstr "一次åªèƒ½ä¸€å€‹é¡žåž‹" +msgid "" +"git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--" +"fixed-value] <name> <value>" +msgstr "" +"git config set [<檔案é¸é …>] [--type=<類型>] [--all] [--value=<值>] [--fixed-" +"value] <å稱> <值>" + +#: builtin/config.c +msgid "" +"git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] " +"<name> <value>" +msgstr "" +"git config unset [<檔案é¸é …>] [--all] [--value=<值>] [--fixed-value] <å稱> <" +"值>" + +#: builtin/config.c +msgid "git config rename-section [<file-option>] <old-name> <new-name>" +msgstr "git config rename-section [<檔案é¸é …>] <舊å稱> <æ–°å稱>" + +#: builtin/config.c +msgid "git config remove-section [<file-option>] <name>" +msgstr "git config remove-section [<檔案é¸é …>] <å稱>" + +#: builtin/config.c +msgid "git config edit [<file-option>]" +msgstr "git config edit [<檔案é¸é …>]" + +#: builtin/config.c +msgid "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" +msgstr "git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]" + +#: builtin/config.c +msgid "" +"git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] " +"[--value=<value>] [--fixed-value] <name> <value>" +msgstr "" +"git config set [<檔案é¸é …>] [--type=<類型>] [--comment=<備註>] [--all] [--" +"value=<值>] [--fixed-value] <å稱> <值>" #: builtin/config.c msgid "Config file location" @@ -6217,70 +6290,6 @@ msgid "read config from given blob object" msgstr "從æä¾›çš„資料物件讀å–è¨å®š" #: builtin/config.c -msgid "Action" -msgstr "動作" - -#: builtin/config.c -msgid "get value: name [value-pattern]" -msgstr "å–得值:name [value-pattern]" - -#: builtin/config.c -msgid "get all values: key [value-pattern]" -msgstr "å–得所有值:key [value-pattern]" - -#: builtin/config.c -msgid "get values for regexp: name-regex [value-pattern]" -msgstr "æ ¹æ“šå¸¸è¦è¡¨ç¤ºå¼å–得值:name-regex [value-pattern]" - -#: builtin/config.c -msgid "get value specific for the URL: section[.var] URL" -msgstr "ç²å¾— URL å–值:section[.var] URL" - -#: builtin/config.c -msgid "replace all matching variables: name value [value-pattern]" -msgstr "å–代所有符åˆçš„變數:name value [value-pattern]" - -#: builtin/config.c -msgid "add a new variable: name value" -msgstr "新增一個新的變數:name value" - -#: builtin/config.c -msgid "remove a variable: name [value-pattern]" -msgstr "移除一個變數:name [value-pattern]" - -#: builtin/config.c -msgid "remove all matches: name [value-pattern]" -msgstr "移除所有符åˆé …目:name [value-pattern]" - -#: builtin/config.c -msgid "rename section: old-name new-name" -msgstr "釿–°å‘½åå°ç¯€ï¼šold-name new-name" - -#: builtin/config.c -msgid "remove a section: name" -msgstr "刪除一個å°ç¯€ï¼šname" - -#: builtin/config.c -msgid "list all" -msgstr "全部列出" - -#: builtin/config.c -msgid "use string equality when comparing values to 'value-pattern'" -msgstr "比較「value-patternã€çš„值時,使用å—ä¸²ç›¸ç‰æ¯”較" - -#: builtin/config.c -msgid "open an editor" -msgstr "開啟一個編輯器" - -#: builtin/config.c -msgid "find the color configured: slot [default]" -msgstr "ç²å¾—è¨å®šçš„é¡è‰²ï¼šè¨å®š [é è¨å€¼]" - -#: builtin/config.c -msgid "find the color setting: slot [stdout-is-tty]" -msgstr "ç²å¾—é¡è‰²è¨å®šï¼šè¨å®š [stdout-is-tty]" - -#: builtin/config.c msgid "Type" msgstr "類型" @@ -6317,8 +6326,8 @@ msgid "value is an expiry date" msgstr "值是一個到期日期" #: builtin/config.c -msgid "Other" -msgstr "其它" +msgid "Display options" +msgstr "顯示é¸é …" #: builtin/config.c msgid "terminate values with NUL byte" @@ -6329,10 +6338,6 @@ msgid "show variable names only" msgstr "åªé¡¯ç¤ºè®Šæ•¸å" #: builtin/config.c -msgid "respect include directives on lookup" -msgstr "查詢時引用 include 指令éžè¿´å°‹æ‰¾" - -#: builtin/config.c msgid "show origin of config (file, standard input, blob, command line)" msgstr "顯示è¨å®šçš„來æºï¼ˆæª”æ¡ˆã€æ¨™æº–輸入ã€è³‡æ–™ç‰©ä»¶ï¼Œæˆ–命令列)" @@ -6343,16 +6348,17 @@ msgstr "" "令 command)" #: builtin/config.c -msgid "value" -msgstr "å–值" +msgid "show config keys in addition to their values" +msgstr "除了顯示組態值,é¡å¤–顯示其éµå" #: builtin/config.c -msgid "with --get, use default value when missing entry" -msgstr "使用 --get ä½†æœªæŒ‡å®šåƒæ•¸æ™‚所使用的é è¨å€¼" +#, c-format +msgid "unrecognized --type argument, %s" +msgstr "無法è˜åˆ¥çš„ --type åƒæ•¸ï¼Œ%s" #: builtin/config.c -msgid "human-readable comment string (# will be prepended as needed)" -msgstr "人類å¯è®€çš„備註å—串(將按需æ’å…¥ # è‡³å‰æ–¹ï¼‰" +msgid "only one type at a time" +msgstr "一次åªèƒ½ä¸€å€‹é¡žåž‹" #: builtin/config.c #, c-format @@ -6445,56 +6451,93 @@ msgstr "" "詳情請閱讀「git help worktreeã€çš„「CONFIGURATION FILEã€å°ç¯€" #: builtin/config.c -msgid "--get-color and variable type are incoherent" -msgstr "--get-color 和變數類型ä¸ç›¸å®¹" +msgid "Other" +msgstr "其它" #: builtin/config.c -msgid "only one action at a time" -msgstr "一次åªèƒ½æœ‰ä¸€å€‹å‹•作" +msgid "respect include directives on lookup" +msgstr "查詢時引用 include 指令éžè¿´å°‹æ‰¾" #: builtin/config.c -msgid "--name-only is only applicable to --list or --get-regexp" -msgstr "--name-only 僅é©ç”¨æ–¼ --list 或 --get-regexp" +#, c-format +msgid "unable to read config file '%s'" +msgstr "無法讀å–è¨å®šæª”案 '%s'" #: builtin/config.c -msgid "" -"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" -"list" -msgstr "--show-origin 僅é©ç”¨æ–¼ --getã€--get-allã€--get-regexp å’Œ --list" +msgid "error processing config file(s)" +msgstr "處ç†è¨å®šæª”案發生錯誤" #: builtin/config.c -msgid "--default is only applicable to --get" -msgstr "--default 僅é©ç”¨æ–¼ --get" +msgid "Filter options" +msgstr "éŽæ¿¾é¸é …" #: builtin/config.c -msgid "--comment is only applicable to add/set/replace operations" -msgstr "--comment åªèƒ½ç”¨æ–¼åŠ å…¥ã€è¨å®šå’Œå–代動作" +msgid "return all values for multi-valued config options" +msgstr "å›žå‚³æœ‰å¤šé …å€¼ä¹‹çµ„æ…‹é¸é …的所有值" + +#: builtin/config.c +msgid "interpret the name as a regular expression" +msgstr "å°‡å稱當作常è¦è¡¨ç¤ºå¼è§£è®€" + +#: builtin/config.c +msgid "show config with values matching the pattern" +msgstr "é¡¯ç¤ºå€¼ç¬¦åˆæ¨¡å¼çš„組態" + +#: builtin/config.c +msgid "use string equality when comparing values to value pattern" +msgstr "使用å—ä¸²ç›¸ç‰æ¯”較值和模å¼" + +#: builtin/config.c +msgid "URL" +msgstr "URL" + +#: builtin/config.c +msgid "show config matching the given URL" +msgstr "é¡¯ç¤ºç¬¦åˆæä¾› URL 的組態" + +#: builtin/config.c +msgid "value" +msgstr "å–值" + +#: builtin/config.c +msgid "use default value when missing entry" +msgstr "æœªæŒ‡å®šåƒæ•¸æ™‚所使用的é è¨å€¼" #: builtin/config.c msgid "--fixed-value only applies with 'value-pattern'" msgstr "--fixed-value 僅套用至 'value-pattern'" #: builtin/config.c -#, c-format -msgid "unable to read config file '%s'" -msgstr "無法讀å–è¨å®šæª”案 '%s'" +msgid "--default= cannot be used with --all or --url=" +msgstr "--default= 無法和 --all 或 --url= 一起使用" #: builtin/config.c -msgid "error processing config file(s)" -msgstr "處ç†è¨å®šæª”案發生錯誤" +msgid "--url= cannot be used with --all, --regexp or --value" +msgstr "--url= 無法和 --allã€--regexpã€--value 一起使用" #: builtin/config.c -msgid "editing stdin is not supported" -msgstr "䏿”¯æ´ç·¨è¼¯æ¨™æº–輸入" +msgid "Filter" +msgstr "éŽæ¿¾å™¨" #: builtin/config.c -msgid "editing blobs is not supported" -msgstr "䏿”¯æ´ç·¨è¼¯è³‡æ–™ç‰©ä»¶" +msgid "replace multi-valued config option with new value" +msgstr "以新值å–ä»£æœ‰å¤šé …å€¼çš„çµ„æ…‹é¸é …" #: builtin/config.c -#, c-format -msgid "cannot create configuration file %s" -msgstr "ä¸èƒ½å»ºç«‹è¨å®šæª”案 %s" +msgid "human-readable comment string (# will be prepended as needed)" +msgstr "人類å¯è®€çš„備註å—串(將按需æ’å…¥ # è‡³å‰æ–¹ï¼‰" + +#: builtin/config.c +msgid "add a new line without altering any existing values" +msgstr "åœ¨ä¸æ›´å‹•ä»»ä½•ç¾æœ‰å€¼çš„æƒ…æ³ä¸‹æ–°å¢žä¸€è¡Œ" + +#: builtin/config.c +msgid "--fixed-value only applies with --value=<pattern>" +msgstr "--fixed-value 僅套用至 --value=<模å¼>" + +#: builtin/config.c +msgid "--append cannot be used with --value=<pattern>" +msgstr "--append 無法和 --value=<模å¼> 一起使用" #: builtin/config.c #, c-format @@ -6510,6 +6553,109 @@ msgstr "" msgid "no such section: %s" msgstr "ç„¡æ¤å°ç¯€ï¼š%s" +#: builtin/config.c +msgid "editing stdin is not supported" +msgstr "䏿”¯æ´ç·¨è¼¯æ¨™æº–輸入" + +#: builtin/config.c +msgid "editing blobs is not supported" +msgstr "䏿”¯æ´ç·¨è¼¯è³‡æ–™ç‰©ä»¶" + +#: builtin/config.c +#, c-format +msgid "cannot create configuration file %s" +msgstr "ä¸èƒ½å»ºç«‹è¨å®šæª”案 %s" + +#: builtin/config.c +msgid "Action" +msgstr "動作" + +#: builtin/config.c +msgid "get value: name [<value-pattern>]" +msgstr "å–得值:name [<value-pattern>]" + +#: builtin/config.c +msgid "get all values: key [<value-pattern>]" +msgstr "å–得所有值:key [<value-pattern>]" + +#: builtin/config.c +msgid "get values for regexp: name-regex [<value-pattern>]" +msgstr "æ ¹æ“šå¸¸è¦è¡¨ç¤ºå¼å–得值:name-regex [<value-pattern>]" + +#: builtin/config.c +msgid "get value specific for the URL: section[.var] URL" +msgstr "ç²å¾— URL å–值:section[.var] URL" + +#: builtin/config.c +msgid "replace all matching variables: name value [<value-pattern>]" +msgstr "å–代所有符åˆçš„變數:name value [<value-pattern>]" + +#: builtin/config.c +msgid "add a new variable: name value" +msgstr "新增一個新的變數:name value" + +#: builtin/config.c +msgid "remove a variable: name [<value-pattern>]" +msgstr "移除一個變數:name [<value-pattern>]" + +#: builtin/config.c +msgid "remove all matches: name [<value-pattern>]" +msgstr "移除所有符åˆé …目:name [<value-pattern>]" + +#: builtin/config.c +msgid "rename section: old-name new-name" +msgstr "釿–°å‘½åå°ç¯€ï¼šold-name new-name" + +#: builtin/config.c +msgid "remove a section: name" +msgstr "刪除一個å°ç¯€ï¼šname" + +#: builtin/config.c +msgid "list all" +msgstr "全部列出" + +#: builtin/config.c +msgid "open an editor" +msgstr "開啟一個編輯器" + +#: builtin/config.c +msgid "find the color configured: slot [<default>]" +msgstr "ç²å¾—è¨å®šçš„é¡è‰²ï¼šè¨å®š [<é è¨å€¼>]" + +#: builtin/config.c +msgid "find the color setting: slot [<stdout-is-tty>]" +msgstr "ç²å¾—é¡è‰²è¨å®šï¼šè¨å®š [<stdout-is-tty>]" + +#: builtin/config.c +msgid "with --get, use default value when missing entry" +msgstr "使用 --get ä½†æœªæŒ‡å®šåƒæ•¸æ™‚所使用的é è¨å€¼" + +#: builtin/config.c +msgid "--get-color and variable type are incoherent" +msgstr "--get-color 和變數類型ä¸ç›¸å®¹" + +#: builtin/config.c +msgid "no action specified" +msgstr "未指定動作" + +#: builtin/config.c +msgid "--name-only is only applicable to --list or --get-regexp" +msgstr "--name-only 僅é©ç”¨æ–¼ --list 或 --get-regexp" + +#: builtin/config.c +msgid "" +"--show-origin is only applicable to --get, --get-all, --get-regexp, and --" +"list" +msgstr "--show-origin 僅é©ç”¨æ–¼ --getã€--get-allã€--get-regexp å’Œ --list" + +#: builtin/config.c +msgid "--default is only applicable to --get" +msgstr "--default 僅é©ç”¨æ–¼ --get" + +#: builtin/config.c +msgid "--comment is only applicable to add/set/replace operations" +msgstr "--comment åªèƒ½ç”¨æ–¼åŠ å…¥ã€è¨å®šå’Œå–代動作" + #: builtin/count-objects.c msgid "print sizes in human readable format" msgstr "以使用者å¯è®€çš„æ ¼å¼é¡¯ç¤ºå¤§å°" @@ -6694,11 +6840,11 @@ msgstr "標記" #: builtin/describe.c msgid "append <mark> on dirty working tree (default: \"-dirty\")" -msgstr "å°æ–¼é«’工作å€ï¼Œè¿½åŠ <標記>(é è¨å€¼ï¼šâ€-dirty\")" +msgstr "å°æ–¼é«’工作å€ï¼Œè¿½åŠ <標記>(é è¨å€¼ï¼šã€-dirty\")" #: builtin/describe.c msgid "append <mark> on broken working tree (default: \"-broken\")" -msgstr "å°æ–¼æå£žçš„工作å€ï¼Œè¿½åŠ <標記>(é è¨å€¼ï¼šâ€-broken\")" +msgstr "å°æ–¼æå£žçš„工作å€ï¼Œè¿½åŠ <標記>(é è¨å€¼ï¼šã€-broken\")" #: builtin/describe.c msgid "No names found, cannot describe anything." @@ -7363,7 +7509,7 @@ msgstr "在所有更新分支上檢查強制更新" #: builtin/fetch.c msgid "write the commit-graph after fetching" -msgstr "抓å–後寫入分支圖" +msgstr "抓å–後寫入æäº¤åœ–" #: builtin/fetch.c msgid "accept refspecs from stdin" @@ -7539,6 +7685,10 @@ msgid "config key storing a list of repository paths" msgstr "儲å˜ç‰ˆæœ¬åº«è·¯å¾‘清單的è¨å®šéµ" #: builtin/for-each-repo.c +msgid "keep going even if command fails in a repository" +msgstr "命令在版本庫ä¸å¤±æ•—時ä»ç¹¼çºŒåŸ·è¡Œ" + +#: builtin/for-each-repo.c msgid "missing --config=<config>" msgstr "缺少 --config=<è¨å®š>" @@ -7753,12 +7903,12 @@ msgstr "%s:%s çš„ resolve-undo ä¸çš„ sha1 指標無效" #: builtin/fsck.c #, c-format msgid "unable to load rev-index for pack '%s'" -msgstr "ç„¡æ³•è®€å– â€œ%s†å°è£çš„修訂版索引 (rev-index)" +msgstr "無法讀å–「%sã€å°è£çš„修訂版索引 (rev-index)" #: builtin/fsck.c #, c-format msgid "invalid rev-index for pack '%s'" -msgstr "“%s†å°è£çš„修訂版索引 (rev-index) 無效" +msgstr "「%sã€å°è£çš„修訂版索引 (rev-index) 無效" #: builtin/fsck.c msgid "" @@ -8065,7 +8215,7 @@ msgstr "無法è˜åˆ¥çš„ --schedule 引數 '%s'" #: builtin/gc.c msgid "failed to write commit-graph" -msgstr "無法寫入æäº¤åœ–å½¢" +msgstr "無法寫入æäº¤åœ–" #: builtin/gc.c msgid "failed to prefetch remotes" @@ -8192,7 +8342,7 @@ msgstr "無法啟動 schtasks" #: builtin/gc.c msgid "failed to run 'crontab -l'; your system might not support 'cron'" -msgstr "無法執行 “crontab -lâ€ï¼›æ‚¨çš„系統å¯èƒ½ä¸æ”¯æ´ “cronâ€" +msgstr "無法執行「crontab -lã€ï¼›æ‚¨çš„系統å¯èƒ½ä¸æ”¯æ´ã€Œcronã€" #: builtin/gc.c msgid "failed to create crontab temporary file" @@ -8204,11 +8354,11 @@ msgstr "ç„¡æ³•é–‹å•Ÿæš«å˜æª”" #: builtin/gc.c msgid "failed to run 'crontab'; your system might not support 'cron'" -msgstr "無法執行 “crontabâ€ï¼›æ‚¨çš„系統å¯èƒ½ä¸æ”¯æ´ “cronâ€" +msgstr "無法執行「crontabã€ï¼›æ‚¨çš„系統å¯èƒ½ä¸æ”¯æ´ã€Œcronã€" #: builtin/gc.c msgid "'crontab' died" -msgstr "“crontabâ€ çµæŸé‹ä½œ" +msgstr "「crontabã€çµæŸé‹ä½œ" #: builtin/gc.c builtin/worktree.c #, c-format @@ -9135,7 +9285,7 @@ msgstr "--only-trailers --only-input --unfold 的別å" #: builtin/interpret-trailers.c msgid "do not treat \"---\" as the end of input" -msgstr "ä¸è¦æŠŠ “---†當作輸入çµå°¾" +msgstr "ä¸è¦æŠŠã€Œ---ã€ç•¶ä½œè¼¸å…¥çµå°¾" #: builtin/interpret-trailers.c msgid "trailer(s) to add" @@ -9250,7 +9400,7 @@ msgstr "䏿˜¯ä¸€å€‹ç¯„åœ" #: builtin/log.c #, c-format msgid "unable to read branch description file '%s'" -msgstr "無法讀å–分支æè¿°æª” “%sâ€" +msgstr "無法讀å–分支æè¿°æª”「%sã€" #: builtin/log.c msgid "cover letter needs email format" @@ -9367,8 +9517,12 @@ msgid "max length of output filename" msgstr "輸出檔å的最大長度" #: builtin/log.c -msgid "use [RFC PATCH] instead of [PATCH]" -msgstr "使用 [RFC PATCH] 代替 [PATCH]" +msgid "rfc" +msgstr "rfc" + +#: builtin/log.c +msgid "add <rfc> (default 'RFC') before 'PATCH'" +msgstr "在「PATCHã€å‰å† 上 <rfc>(é è¨ç‚ºã€ŒRFCã€ï¼‰" #: builtin/log.c msgid "cover-from-description-mode" @@ -9711,11 +9865,11 @@ msgstr "" #: builtin/ls-remote.c msgid "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" msgstr "" -"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n" +"git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n" " [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n" " [--symref] [<repository> [<patterns>...]]" @@ -9736,9 +9890,13 @@ msgid "limit to tags" msgstr "åƒ…é™æ–¼æ¨™ç±¤" #: builtin/ls-remote.c -msgid "limit to heads" +msgid "limit to branches" msgstr "åƒ…é™æ–¼åˆ†æ”¯" +#: builtin/ls-remote.c builtin/show-ref.c +msgid "deprecated synonym for --branches" +msgstr "--branches 已棄用的åŒç¾©è©ž" + #: builtin/ls-remote.c msgid "do not show peeled tags" msgstr "ä¸é¡¯ç¤ºå·²è§£æžçš„æ¨™ç±¤" @@ -9963,7 +10121,7 @@ msgstr "為 檔案1/åˆå§‹æª”案/檔案2 è¨å®šæ¨™ç±¤" #: builtin/merge-file.c #, c-format msgid "object '%s' does not exist" -msgstr "物件 “%s†ä¸å˜åœ¨" +msgstr "物件「%sã€ä¸å˜åœ¨" #: builtin/merge-file.c msgid "Could not write object file" @@ -11215,7 +11373,7 @@ msgstr "ä¸ä¸€è‡´çš„差異計數" #: builtin/pack-objects.c #, c-format msgid "invalid pack.allowPackReuse value: '%s'" -msgstr "無效的 pack.allowPackReuse 值:“%sâ€" +msgstr "無效的 pack.allowPackReuse 值:「%sã€" #: builtin/pack-objects.c #, c-format @@ -11223,8 +11381,8 @@ msgid "" "value of uploadpack.blobpackfileuri must be of the form '<object-hash> <pack-" "hash> <uri>' (got '%s')" msgstr "" -"uploadpack.blobpackfileuri çš„å€¼æ ¼å¼å¿…é ˆç‚º '<object-hash> <pack-hash> <uri>' " -"(收到 '%s')" +"uploadpack.blobpackfileuri çš„å€¼æ ¼å¼å¿…é ˆç‚º '<object-hash> <pack-hash> " +"<uri>' (收到 '%s')" #: builtin/pack-objects.c #, c-format @@ -11860,7 +12018,7 @@ msgid "" "To choose either option permanently, see push.default in 'git help config'.\n" msgstr "" "\n" -"è‹¥è¦æ°¸ä¹…鏿“‡æŸå€‹é¸é …,請åƒé–± “git help config†ä¸çš„ push.default。\n" +"è‹¥è¦æ°¸ä¹…鏿“‡æŸå€‹é¸é …,請åƒé–±ã€Œgit help configã€ä¸çš„ push.default。\n" #: builtin/push.c msgid "" @@ -11871,8 +12029,8 @@ msgid "" msgstr "" "\n" "è‹¥è¦é¿å…在å稱與本機分支ä¸åŒæ™‚自動è¨å®šä¸Šæ¸¸åˆ†æ”¯ï¼Œ\n" -"è«‹åƒé–± “git help configâ€ ä¸ branch.autoSetupMerge çš„\n" -"“simple†é¸é …。\n" +"è«‹åƒé–±ã€Œgit help configã€ä¸ branch.autoSetupMerge çš„\n" +"「simpleã€é¸é …。\n" #: builtin/push.c #, c-format @@ -11919,8 +12077,8 @@ msgid "" "upstream, see 'push.autoSetupRemote' in 'git help config'.\n" msgstr "" "\n" -"è‹¥è¦ä½¿æ²’有追蹤上游的分支自動é…置,請åƒé–± “git help config†ä¸çš„\n" -"“push.autoSetupRemoteâ€ã€‚\n" +"è‹¥è¦ä½¿æ²’有追蹤上游的分支自動é…置,請åƒé–±ã€Œgit help configã€ä¸çš„\n" +"「push.autoSetupRemoteã€ã€‚\n" #: builtin/push.c #, c-format @@ -11965,8 +12123,8 @@ msgid "" "See the 'Note about fast-forwards' in 'git push --help' for details." msgstr "" "æ›´æ–°è¢«æ‹’çµ•ï¼Œå› ç‚ºæ‚¨ç›®å‰åˆ†æ”¯çš„æœ€æ–°æäº¤è½å¾Œæ–¼å…¶å°æ‡‰çš„é 端分支。\n" -"å¦‚æžœæ‚¨æƒ³è¦æ•´åˆé ç«¯æ›´å‹•ï¼Œè«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ “git pullâ€ã€‚詳見\n" -"“git push --help†ä¸çš„〈Note about fast-forwards〉å°ç¯€ã€‚" +"å¦‚æžœæ‚¨æƒ³è¦æ•´åˆé ç«¯æ›´å‹•ï¼Œè«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ã€Œgit pullã€ã€‚詳見\n" +"「git push --helpã€ä¸çš„〈Note about fast-forwards〉å°ç¯€ã€‚" #: builtin/push.c msgid "" @@ -11976,8 +12134,8 @@ msgid "" "See the 'Note about fast-forwards' in 'git push --help' for details." msgstr "" "æ›´æ–°è¢«æ‹’çµ•ï¼Œå› ç‚ºæŽ¨é€çš„æŸåˆ†æ”¯çš„æœ€æ–°æäº¤è½å¾Œæ–¼å…¶å°æ‡‰çš„é 端分支。\n" -"å¦‚æžœæ‚¨æƒ³è¦æ•´åˆé ç«¯æ›´å‹•ï¼Œè«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ “git pullâ€ã€‚詳見\n" -"“git push --help†ä¸çš„〈Note about fast-forwards〉å°ç¯€ã€‚" +"å¦‚æžœæ‚¨æƒ³è¦æ•´åˆé ç«¯æ›´å‹•ï¼Œè«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ã€Œgit pullã€ã€‚詳見\n" +"「git push --helpã€ä¸çš„〈Note about fast-forwards〉å°ç¯€ã€‚" #: builtin/push.c msgid "" @@ -11989,7 +12147,7 @@ msgid "" msgstr "" "æ›´æ–°è¢«æ‹’çµ•ï¼Œå› ç‚ºé ç«¯åŒ…å«æ‚¨æœ¬æ©Ÿæ²’有的æäº¤ã€‚é€™é€šå¸¸æ˜¯å› ç‚º\n" "å¦ä¸€å€‹ç‰ˆæœ¬åº«æœ‰æŽ¨é€æ›´å‹•到åŒå€‹å¼•ç”¨ã€‚å¦‚æžœæ‚¨æƒ³è¦æ•´åˆé 端更動,\n" -"è«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ “git pullâ€ã€‚詳見 “git push --help†ä¸çš„\n" +"è«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ã€Œgit pullã€ã€‚詳見「git push --helpã€ä¸çš„\n" "〈Note about fast-forwards〉å°ç¯€ã€‚" #: builtin/push.c @@ -12013,8 +12171,8 @@ msgid "" "See the 'Note about fast-forwards' in 'git push --help' for details." msgstr "" "æ›´æ–°è¢«æ‹’çµ•ï¼Œå› ç‚ºé 端追蹤分支的最新æäº¤è‡ªä¸Šæ¬¡ç°½å‡ºå¾Œæœ‰æ”¹è®Šã€‚\n" -"å¦‚æžœæ‚¨æƒ³è¦æ•´åˆé ç«¯æ›´å‹•ï¼Œè«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ “git pullâ€ã€‚\n" -"詳見 “git push --help†ä¸çš„〈Note about fast-forwards〉å°ç¯€ã€‚" +"å¦‚æžœæ‚¨æƒ³è¦æ•´åˆé ç«¯æ›´å‹•ï¼Œè«‹åœ¨å†æ¬¡æŽ¨é€å‰ä½¿ç”¨ã€Œgit pullã€ã€‚\n" +"詳見「git push --helpã€ä¸çš„〈Note about fast-forwards〉å°ç¯€ã€‚" #: builtin/push.c #, c-format @@ -12607,8 +12765,8 @@ msgid "" "which is no longer supported; use 'merges' instead" msgstr "" "--preserve-merges 已被 --rebase-merges å–代\n" -"註:您的 `pull.rebase` è¨å®šå¯èƒ½ä¹Ÿè¢«è¨å®šç‚ºä¸å—支æ´çš„ “preserveâ€ï¼›\n" -"請改用 “mergesâ€" +"註:您的 `pull.rebase` è¨å®šå¯èƒ½ä¹Ÿè¢«è¨å®šç‚ºä¸å—支æ´çš„「preserveã€ï¼›\n" +"請改用「mergesã€" #: builtin/rebase.c msgid "no rebase in progress" @@ -12928,6 +13086,27 @@ msgstr "未指定è¦åˆªé™¤çš„引用日誌" msgid "invalid ref format: %s" msgstr "ç„¡æ•ˆçš„å¼•ç”¨æ ¼å¼ï¼š%s" +#: builtin/refs.c +msgid "git refs migrate --ref-format=<format> [--dry-run]" +msgstr "git refs migrate --ref-format=<æ ¼å¼> [--dry-run]" + +#: builtin/refs.c +msgid "specify the reference format to convert to" +msgstr "指定è¦è½‰æ›æˆçš„å¼•ç”¨æ ¼å¼" + +#: builtin/refs.c +msgid "perform a non-destructive dry-run" +msgstr "進行éžç ´å£žæ€§çš„試執行" + +#: builtin/refs.c +msgid "missing --ref-format=<format>" +msgstr "缺少 --ref-format=<æ ¼å¼>" + +#: builtin/refs.c +#, c-format +msgid "repository already uses '%s' format" +msgstr "版本庫已經使用 '%s' æ ¼å¼" + #: builtin/remote.c msgid "" "git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--" @@ -13273,10 +13452,6 @@ msgstr "* é 端 %s" msgid " Fetch URL: %s" msgstr " å–å¾—ä½å€ï¼š%s" -#: builtin/remote.c -msgid "(no URL)" -msgstr "(ç„¡ URL)" - #. TRANSLATORS: the colon ':' should align #. with the one in " Fetch URL: %s" #. translation. @@ -13287,6 +13462,10 @@ msgid " Push URL: %s" msgstr " 推é€ä½å€ï¼š%s" #: builtin/remote.c +msgid "(no URL)" +msgstr "(ç„¡ URL)" + +#: builtin/remote.c #, c-format msgid " HEAD branch: %s" msgstr " HEAD 分支:%s" @@ -13421,11 +13600,6 @@ msgid "return all URLs" msgstr "返回所有 URL ä½å€" #: builtin/remote.c -#, c-format -msgid "no URLs configured for remote '%s'" -msgstr "沒有給é 端版本庫 '%s' è¨å®š URL" - -#: builtin/remote.c msgid "manipulate push URLs" msgstr "å‹•ä½œæŽ¨é€ URLS" @@ -13632,7 +13806,7 @@ msgstr "ä¸èƒ½åˆªé™¤çå“版本庫ä¸çš„å°åŒ…" #: builtin/repack.c #, c-format msgid "option '%s' can only be used along with '%s'" -msgstr "“%s†é¸é …åªèƒ½èˆ‡ “%s†一起使用" +msgstr "「%sã€é¸é …åªèƒ½èˆ‡ã€Œ%sã€ä¸€èµ·ä½¿ç”¨" #: builtin/repack.c msgid "Nothing new to pack." @@ -13646,7 +13820,7 @@ msgstr "ç„¡æ³•å°‡åŒ…é‡æ–°å‘½å為「%sã€" #: builtin/repack.c #, c-format msgid "pack-objects did not write a '%s' file for pack %s-%s" -msgstr "pack-objects 沒有為 %2$s-%3$s 套件包寫入 “%1$s†檔案" +msgstr "pack-objects 沒有為 %2$s-%3$s 套件包寫入「%1$sã€æª”案" #: builtin/repack.c sequencer.c #, c-format @@ -13955,7 +14129,7 @@ msgstr "å¿…é ˆå‚³å…¥ --onto 或 --advance é¸é …" msgid "" "some rev walking options will be overridden as '%s' bit in 'struct rev_info' " "will be forced" -msgstr "å°‡è¦†å¯«éƒ¨åˆ†ä¿®è¨‚ç‰ˆéæ·é¸é …,強制使用 “struct rev_info†的 “%s†ä½å…ƒ" +msgstr "å°‡è¦†å¯«éƒ¨åˆ†ä¿®è¨‚ç‰ˆéæ·é¸é …,強制使用「struct rev_infoã€çš„「%sã€ä½å…ƒ" #: builtin/replay.c msgid "error preparing revisions" @@ -14345,7 +14519,7 @@ msgstr "已棄用:請改用 --empty=keep" #: builtin/revert.c msgid "use the 'reference' format to refer to commits" -msgstr "請使用 “referenceâ€ æ ¼å¼åƒè€ƒæäº¤" +msgstr "請使用「referenceã€æ ¼å¼åƒè€ƒæäº¤" #: builtin/revert.c msgid "revert failed" @@ -14669,12 +14843,12 @@ msgstr "未知的雜湊算法" #: builtin/show-ref.c msgid "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" msgstr "" "git show-ref [--head] [-d | --dereference]\n" -" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n" -" [--heads] [--] [<pattern>...]" +" [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n" +" [--] [<pattern>...]" #: builtin/show-ref.c msgid "" @@ -14703,12 +14877,12 @@ msgid "failed to look up reference" msgstr "無法查詢引用" #: builtin/show-ref.c -msgid "only show tags (can be combined with heads)" -msgstr "åªé¡¯ç¤ºæ¨™ç±¤ï¼ˆå¯ä»¥å’Œé 共用)" +msgid "only show tags (can be combined with branches)" +msgstr "åªé¡¯ç¤ºæ¨™ç±¤ï¼ˆå¯ä»¥å’Œåˆ†æ”¯å…±ç”¨ï¼‰" #: builtin/show-ref.c -msgid "only show heads (can be combined with tags)" -msgstr "åªé¡¯ç¤ºé (å¯ä»¥å’Œæ¨™ç±¤å…±ç”¨ï¼‰" +msgid "only show branches (can be combined with tags)" +msgstr "åªé¡¯ç¤ºåˆ†æ”¯ï¼ˆå¯ä»¥å’Œæ¨™ç±¤å…±ç”¨ï¼‰" #: builtin/show-ref.c msgid "check for reference existence without resolving" @@ -15440,7 +15614,7 @@ msgstr "" #: builtin/submodule--helper.c #, c-format msgid "could not get a repository handle for gitdir '%s'" -msgstr "無法å–å¾— gitdir “%s†的版本庫控點" +msgstr "無法å–å¾— gitdir「%sã€çš„版本庫控點" #: builtin/submodule--helper.c #, c-format @@ -15457,20 +15631,20 @@ msgstr "ä¸èƒ½è˜åˆ¥ submodule.alternateErrorStrategy çš„å–值 '%s'" msgid "Value '%s' for submodule.alternateLocation is not recognized" msgstr "ä¸èƒ½è˜åˆ¥ submodule.alternateLocation çš„å–值 '%s'" -#: builtin/submodule--helper.c +#: builtin/submodule--helper.c submodule.c #, c-format msgid "refusing to create/use '%s' in another submodule's git dir" msgstr "æ‹’çµ•åœ¨å…¶ä»–åæ¨¡çµ„çš„ git 路徑建立ï¼ä½¿ç”¨ã€Œ%sã€" #: builtin/submodule--helper.c #, c-format -msgid "clone of '%s' into submodule path '%s' failed" -msgstr "無法複製 '%s' åˆ°åæ¨¡çµ„路徑 '%s'" +msgid "directory not empty: '%s'" +msgstr "ç›®éŒ„ä¸æ˜¯ç©ºçš„:「%sã€" #: builtin/submodule--helper.c #, c-format -msgid "directory not empty: '%s'" -msgstr "ç›®éŒ„ä¸æ˜¯ç©ºçš„:「%sã€" +msgid "clone of '%s' into submodule path '%s' failed" +msgstr "無法複製 '%s' åˆ°åæ¨¡çµ„路徑 '%s'" #: builtin/submodule--helper.c #, c-format @@ -15542,7 +15716,7 @@ msgstr "ç•¥éŽå模組 '%s'" #: builtin/submodule--helper.c #, c-format msgid "cannot clone submodule '%s' without a URL" -msgstr "無法在沒有網å€çš„æƒ…æ³ä¸‹è¤‡è£½ “%sâ€ åæ¨¡çµ„" +msgstr "無法在沒有網å€çš„æƒ…æ³ä¸‹è¤‡è£½ã€Œ%sã€å模組" #: builtin/submodule--helper.c #, c-format @@ -15660,15 +15834,15 @@ msgstr "ä¸å¾žé 端站å°å–得新物件" #: builtin/submodule--helper.c msgid "use the 'checkout' update strategy (default)" -msgstr "使用 “checkout†更新ç–略(é è¨å€¼ï¼‰" +msgstr "使用「checkoutã€æ›´æ–°ç–略(é è¨å€¼ï¼‰" #: builtin/submodule--helper.c msgid "use the 'merge' update strategy" -msgstr "使用 “merge†更新ç–ç•¥" +msgstr "使用「mergeã€æ›´æ–°ç–ç•¥" #: builtin/submodule--helper.c msgid "use the 'rebase' update strategy" -msgstr "使用 “rebase†更新ç–ç•¥" +msgstr "使用「rebaseã€æ›´æ–°ç–ç•¥" #: builtin/submodule--helper.c msgid "create a shallow clone truncated to the specified number of revisions" @@ -15911,9 +16085,11 @@ msgstr "æ›´æ–°çš„åŽŸå› " #: builtin/tag.c msgid "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" msgstr "" "git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n" +" [(--trailer <token>[(=|:)<value>])...]\n" " <tagname> [<commit> | <object>]" #: builtin/tag.c @@ -16081,7 +16257,7 @@ msgstr "åªåˆ—å°æŒ‡å‘該物件的標籤" #: builtin/tag.c msgid "could not start 'git column'" -msgstr "無法啟動 “git columnâ€" +msgstr "無法啟動「git columnã€" #: builtin/tag.c #, c-format @@ -16511,7 +16687,7 @@ msgstr "git worktree unlock <worktree>" #: builtin/worktree.c msgid "No possible source branch, inferring '--orphan'" -msgstr "沒有å¯èƒ½çš„來æºåˆ†æ”¯ï¼ŒæŽ¨æ¸¬ç‚º “--orphanâ€" +msgstr "沒有å¯èƒ½çš„來æºåˆ†æ”¯ï¼ŒæŽ¨æ¸¬ç‚ºã€Œ--orphanã€" #: builtin/worktree.c #, c-format @@ -16646,8 +16822,8 @@ msgid "" "HEAD contents: '%s'" msgstr "" "HEAD 指å‘無效(或å¤ç«‹ï¼‰å¼•用。\n" -"HEAD 路徑:“%sâ€\n" -"HEAD 內容:“%sâ€" +"HEAD 路徑:「%sã€\n" +"HEAD 內容:「%sã€" #: builtin/worktree.c msgid "" @@ -16655,7 +16831,7 @@ msgid "" "present, stopping; use 'add -f' to override or fetch a remote first" msgstr "" "å³ä½¿æœ‰æä¾›ä¸€å€‹é 端,å»ä¸å˜åœ¨æœ¬æ©Ÿæˆ–é 端引用,\n" -"æ•…åœæ¢ã€‚使用 “add -f†先覆蓋或抓å–é 端" +"æ•…åœæ¢ã€‚使用「add -fã€å…ˆè¦†è“‹æˆ–抓å–é 端" #: builtin/worktree.c msgid "checkout <branch> even if already checked out in other worktree" @@ -16866,12 +17042,12 @@ msgstr "core.fsyncMethod = batch 䏿”¯æ´æœ¬å¹³å°" #: bundle-uri.c #, c-format msgid "could not parse bundle list key %s with value '%s'" -msgstr "無法解æžå¥—ä»¶åŒ…æ¸…å–®éµ %s 的值 “%sâ€" +msgstr "無法解æžå¥—ä»¶åŒ…æ¸…å–®éµ %s 的值「%sã€" #: bundle-uri.c #, c-format msgid "bundle list at '%s' has no mode" -msgstr "使–¼ “%s†的套件包清單沒有模å¼" +msgstr "使–¼ã€Œ%sã€çš„套件包清單沒有模å¼" #: bundle-uri.c msgid "failed to create temporary file" @@ -16884,7 +17060,7 @@ msgstr "功能ä¸è¶³" #: bundle-uri.c #, c-format msgid "file downloaded from '%s' is not a bundle" -msgstr "從 “%sâ€ ä¸‹è¼‰çš„æª”æ¡ˆä¸æ˜¯å¥—件包" +msgstr "從「%sã€ä¸‹è¼‰çš„æª”æ¡ˆä¸æ˜¯å¥—件包" #: bundle-uri.c msgid "failed to store maximum creation token" @@ -16893,7 +17069,7 @@ msgstr "ç„¡æ³•å„²å˜æœ€å¤§çš„建立權æ–" #: bundle-uri.c #, c-format msgid "unrecognized bundle mode from URI '%s'" -msgstr "無法è˜åˆ¥å¾ž URI “%s†å–回的套件包模å¼" +msgstr "無法è˜åˆ¥å¾ž URI「%sã€å–回的套件包模å¼" #: bundle-uri.c #, c-format @@ -16903,17 +17079,17 @@ msgstr "超出套件包 URI éžè¿´é™åˆ¶ (%d)" #: bundle-uri.c #, c-format msgid "failed to download bundle from URI '%s'" -msgstr "無法從 “%s†URI 下載套件包" +msgstr "無法從「%sã€URI 下載套件包" #: bundle-uri.c #, c-format msgid "file at URI '%s' is not a bundle or bundle list" -msgstr "使–¼ URI “%sâ€ çš„æª”æ¡ˆä¸æ˜¯å¥—件包或套件包清單" +msgstr "使–¼ URI「%sã€çš„æª”æ¡ˆä¸æ˜¯å¥—件包或套件包清單" #: bundle-uri.c #, c-format msgid "bundle-uri: unexpected argument: '%s'" -msgstr "bundle-uri: éžé 期的引數:“%sâ€" +msgstr "bundle-uri: éžé 期的引數:「%sã€" #: bundle-uri.c msgid "bundle-uri: expected flush after arguments" @@ -16925,7 +17101,7 @@ msgstr "bundle-uri: 收到空白列" #: bundle-uri.c msgid "bundle-uri: line is not of the form 'key=value'" -msgstr "bundle-uri: åˆ—çš„æ ¼å¼ä¸æ˜¯ “key=valueâ€" +msgstr "bundle-uri: åˆ—çš„æ ¼å¼ä¸æ˜¯ã€Œkey=valueã€" #: bundle-uri.c msgid "bundle-uri: line has empty key or value" @@ -16944,7 +17120,7 @@ msgstr "未知功能「%sã€" #: bundle.c #, c-format msgid "'%s' does not look like a v2 or v3 bundle file" -msgstr "“%s†ä¸åƒæ˜¯ä¸€å€‹ v2 或 v3 版本的套件包檔案" +msgstr "「%sã€ä¸åƒæ˜¯ä¸€å€‹ v2 或 v3 版本的套件包檔案" #: bundle.c #, c-format @@ -16956,10 +17132,6 @@ msgid "Repository lacks these prerequisite commits:" msgstr "版本庫ä¸ç¼ºå°‘這些必備的æäº¤ï¼š" #: bundle.c -msgid "need a repository to verify a bundle" -msgstr "需è¦ç‰ˆæœ¬åº«é©—è‰å¥—件包" - -#: bundle.c msgid "" "some prerequisite commits exist in the object store, but are not connected " "to the repository's history" @@ -17478,6 +17650,10 @@ msgid "Manage reflog information" msgstr "ç®¡ç† reflog 訊æ¯" #: command-list.h +msgid "Low-level access to refs" +msgstr "å°å¼•用的低階å˜å–" + +#: command-list.h msgid "Manage set of tracked repositories" msgstr "管ç†å·²è¿½è¹¤ç‰ˆæœ¬åº«" @@ -17572,7 +17748,7 @@ msgstr "將工作å€é™ç¸®è‡³åªåŒ…å«è¿½è¹¤æª”案的å集" #: command-list.h msgid "Add file contents to the staging area" -msgstr "將檔案內容新增到索引" +msgstr "將檔案內容新增到暫å˜å€" #: command-list.h msgid "Stash the changes in a dirty working directory away" @@ -17720,7 +17896,7 @@ msgstr "Git å°åŒ…æ ¼å¼" #: command-list.h msgid "Git cryptographic signature formats" -msgstr "Git 密碼編è¯ç°½ç« æ ¼å¼" +msgstr "Git 數ä½ç°½ç« æ ¼å¼" #: command-list.h msgid "A Git Glossary" @@ -17808,104 +17984,111 @@ msgstr "用來管ç†å¤§åž‹ Git 版本庫的工具" #: commit-graph.c msgid "commit-graph file is too small" -msgstr "æäº¤åœ–形檔案太å°" +msgstr "æäº¤åœ–檔案太å°" #: commit-graph.c msgid "commit-graph oid fanout chunk is wrong size" -msgstr "æäº¤åœ–å½¢ OID 扇出å€å¡Šå¤§å°æœ‰èª¤" +msgstr "æäº¤åœ– OID 扇出å€å¡Šå¤§å°æœ‰èª¤" #: commit-graph.c msgid "commit-graph fanout values out of order" -msgstr "æäº¤åœ–形扇出的數值失åº" +msgstr "æäº¤åœ–扇出的數值失åº" #: commit-graph.c msgid "commit-graph OID lookup chunk is the wrong size" -msgstr "æäº¤åœ–å½¢ OID 查詢å€å¡Šçš„大尿œ‰èª¤" +msgstr "æäº¤åœ– OID 查詢å€å¡Šçš„大尿œ‰èª¤" #: commit-graph.c msgid "commit-graph commit data chunk is wrong size" -msgstr "æäº¤åœ–形的æäº¤è³‡æ–™å€å¡Šå¤§å°æœ‰èª¤" +msgstr "æäº¤åœ–çš„æäº¤è³‡æ–™å€å¡Šå¤§å°æœ‰èª¤" #: commit-graph.c msgid "commit-graph generations chunk is wrong size" -msgstr "æäº¤åœ–形的世代å€å¡Šå¤§å°æœ‰èª¤" +msgstr "æäº¤åœ–的世代å€å¡Šå¤§å°æœ‰èª¤" #: commit-graph.c msgid "commit-graph changed-path index chunk is too small" -msgstr "æäº¤åœ–形的更動路徑索引å€å¡ŠéŽå°" +msgstr "æäº¤åœ–的更動路徑索引å€å¡ŠéŽå°" #: commit-graph.c #, c-format msgid "" "ignoring too-small changed-path chunk (%<PRIuMAX> < %<PRIuMAX>) in commit-" "graph file" -msgstr "忽略æäº¤åœ–形檔案ä¸éŽå°çš„æ›´å‹•路徑å€å¡Š (%<PRIuMAX> < %<PRIuMAX>)" +msgstr "忽略æäº¤åœ–檔案ä¸éŽå°çš„æ›´å‹•路徑å€å¡Šï¼ˆ%<PRIuMAX> < %<PRIuMAX>)" #: commit-graph.c #, c-format msgid "commit-graph signature %X does not match signature %X" -msgstr "æäº¤åœ–形簽å %X 和簽å %X ä¸ç¬¦åˆ" +msgstr "æäº¤åœ–ç°½ç« %X å’Œç°½ç« %X ä¸ç¬¦" #: commit-graph.c #, c-format msgid "commit-graph version %X does not match version %X" -msgstr "æäº¤åœ–形版本 %X 和版本 %X ä¸ç¬¦åˆ" +msgstr "æäº¤åœ–版本 %X 和版本 %X ä¸ç¬¦" #: commit-graph.c #, c-format msgid "commit-graph hash version %X does not match version %X" -msgstr "æäº¤åœ–形雜湊版本 %X 和版本 %X ä¸ç¬¦åˆ" +msgstr "æäº¤åœ–雜湊版本 %X 和版本 %X ä¸ç¬¦" #: commit-graph.c #, c-format msgid "commit-graph file is too small to hold %u chunks" -msgstr "æäº¤åœ–形檔案ä¸å¤ 放置 %u 個å€å¡Š" +msgstr "æäº¤åœ–檔案ä¸å¤ 放置 %u 個å€å¡Š" #: commit-graph.c msgid "commit-graph required OID fanout chunk missing or corrupted" -msgstr "æäº¤åœ–形需è¦çš„ OID 扇出å€å¡Šéºå¤±æˆ–æå£ž" +msgstr "æäº¤åœ–需è¦çš„ OID 扇出å€å¡Šéºå¤±æˆ–æå£ž" #: commit-graph.c msgid "commit-graph required OID lookup chunk missing or corrupted" -msgstr "æäº¤åœ–形需è¦çš„ OID 查詢å€å¡Šéºå¤±æˆ–æå£ž" +msgstr "æäº¤åœ–需è¦çš„ OID 查詢å€å¡Šéºå¤±æˆ–æå£ž" #: commit-graph.c msgid "commit-graph required commit data chunk missing or corrupted" -msgstr "æäº¤åœ–形需è¦çš„æäº¤è³‡æ–™å€å¡Šéºå¤±æˆ–æå£ž" +msgstr "æäº¤åœ–需è¦çš„æäº¤è³‡æ–™å€å¡Šéºå¤±æˆ–æå£ž" + +#: commit-graph.c +#, c-format +msgid "" +"disabling Bloom filters for commit-graph layer '%s' due to incompatible " +"settings" +msgstr "由於ä¸ç›¸å®¹çš„è¨å®šï¼Œåœç”¨æäº¤åœ–層 '%s' çš„å¸ƒéš†éŽæ¿¾å™¨" #: commit-graph.c msgid "commit-graph has no base graphs chunk" -msgstr "æäº¤åœ–形沒有基礎圖形å€å¡Š" +msgstr "æäº¤åœ–沒有基礎圖å€å¡Š" #: commit-graph.c msgid "commit-graph base graphs chunk is too small" -msgstr "æäº¤åœ–形的基礎圖形å€å¡ŠéŽå°" +msgstr "æäº¤åœ–的基礎圖å€å¡ŠéŽå°" #: commit-graph.c msgid "commit-graph chain does not match" -msgstr "æäº¤åœ–å½¢éˆä¸ç¬¦åˆ" +msgstr "æäº¤åœ–éˆä¸ç¬¦" #: commit-graph.c #, c-format msgid "commit count in base graph too high: %<PRIuMAX>" -msgstr "基礎圖 (base graph) ä¸çš„æäº¤æ•¸éŽå¤šï¼š%<PRIuMAX>" +msgstr "基礎圖ä¸çš„æäº¤æ•¸éŽå¤šï¼š%<PRIuMAX>" #: commit-graph.c msgid "commit-graph chain file too small" -msgstr "æäº¤åœ–å½¢éˆæª”案éŽå°" +msgstr "æäº¤åœ–éˆæª”案éŽå°" #: commit-graph.c #, c-format msgid "invalid commit-graph chain: line '%s' not a hash" -msgstr "無效的æäº¤åœ–å½¢éˆï¼šã€Œ%sã€åˆ—䏿˜¯é›œæ¹Šå€¼" +msgstr "無效的æäº¤åœ–éˆï¼šã€Œ%sã€åˆ—䏿˜¯é›œæ¹Šå€¼" #: commit-graph.c msgid "unable to find all commit-graph files" -msgstr "無法找到所有æäº¤åœ–形檔案" +msgstr "無法找到所有æäº¤åœ–檔案" #: commit-graph.c msgid "invalid commit position. commit-graph is likely corrupt" -msgstr "無效的æäº¤ä½ç½®ã€‚æäº¤åœ–å½¢å¯èƒ½å·²æå£ž" +msgstr "無效的æäº¤ä½ç½®ã€‚æäº¤åœ–å¯èƒ½å·²æå£ž" #: commit-graph.c #, c-format @@ -17914,15 +18097,15 @@ msgstr "無法找到æäº¤ %s" #: commit-graph.c msgid "commit-graph requires overflow generation data but has none" -msgstr "æäº¤åœ–éœ€è¦æ¯”ç›®å‰æ›´å¤šçš„世代資料,但沒有相關資料" +msgstr "缺少æäº¤åœ–需è¦çš„æº¢ä½ä¸–代資料" #: commit-graph.c msgid "commit-graph overflow generation data is too small" -msgstr "æäº¤åœ–形的溢出世代資料éŽå°" +msgstr "æäº¤åœ–的溢ä½ä¸–代資料éŽå°" #: commit-graph.c msgid "commit-graph extra-edges pointer out of bounds" -msgstr "æäº¤åœ–形的延伸邊界指é‡è¶…出範åœ" +msgstr "æäº¤åœ–é¡å¤–的邊指標超出範åœ" #: commit-graph.c msgid "Loading known commits in commit graph" @@ -17930,7 +18113,7 @@ msgstr "æ£åœ¨è¼‰å…¥æäº¤åœ–ä¸çš„已知æäº¤" #: commit-graph.c msgid "Expanding reachable commits in commit graph" -msgstr "æ£åœ¨å±•é–‹æäº¤åœ–ä¸çš„å¯ä»¥å–å¾—çš„æäº¤" +msgstr "æ£åœ¨å±•é–‹æäº¤åœ–ä¸çš„å¯è§¸åŠæäº¤" #: commit-graph.c msgid "Clearing commit marks in commit graph" @@ -17938,11 +18121,11 @@ msgstr "æ£åœ¨æ¸…除æäº¤åœ–ä¸çš„æäº¤æ¨™è¨˜" #: commit-graph.c msgid "Computing commit graph topological levels" -msgstr "æ£åœ¨è¨ˆç®—æäº¤åœ–拓樸級別" +msgstr "æ£åœ¨è¨ˆç®—æäº¤åœ–的拓樸層級" #: commit-graph.c msgid "Computing commit graph generation numbers" -msgstr "æ£åœ¨è¨ˆç®—æäº¤åœ–世代數å—" +msgstr "æ£åœ¨è¨ˆç®—æäº¤åœ–的世代數" #: commit-graph.c msgid "Computing commit changed paths Bloom filters" @@ -17970,7 +18153,7 @@ msgstr "為 %s 開啟索引發生錯誤" #: commit-graph.c msgid "Finding commits for commit graph among packed objects" -msgstr "æ£åœ¨æ‰“包物件ä¸å°‹æ‰¾æäº¤åœ–çš„æäº¤" +msgstr "æ£åœ¨å¾žæ‰“包物件ä¸å°‹æ‰¾æäº¤åœ–çš„æäº¤" #: commit-graph.c msgid "Finding extra edges in commit graph" @@ -17978,11 +18161,11 @@ msgstr "æ£åœ¨å°‹æ‰¾æäº¤åœ–ä¸é¡å¤–的邊" #: commit-graph.c msgid "failed to write correct number of base graph ids" -msgstr "無法寫入æ£ç¢ºæ•¸é‡çš„基礎圖形 ID" +msgstr "無法寫入æ£ç¢ºæ•¸é‡çš„基礎圖 ID" #: commit-graph.c msgid "unable to create temporary graph layer" -msgstr "無法建立暫時的圖形層" +msgstr "無法建立暫時性圖層" #: commit-graph.c #, c-format @@ -17997,25 +18180,25 @@ msgstr[0] "æ£åœ¨ç”¨ %d æ¥å¯«å‡ºæäº¤åœ–" #: commit-graph.c msgid "unable to open commit-graph chain file" -msgstr "無法開啟æäº¤åœ–å½¢éˆæª”案" +msgstr "無法開啟æäº¤åœ–éˆæª”案" #: commit-graph.c msgid "failed to rename base commit-graph file" -msgstr "ç„¡æ³•é‡æ–°å‘½å基礎æäº¤åœ–形檔案" +msgstr "ç„¡æ³•é‡æ–°å‘½å基礎æäº¤åœ–檔案" #: commit-graph.c msgid "failed to rename temporary commit-graph file" -msgstr "ç„¡æ³•é‡æ–°å‘½å暫時æäº¤åœ–形檔案" +msgstr "ç„¡æ³•é‡æ–°å‘½å暫時性æäº¤åœ–檔案" #: commit-graph.c #, c-format msgid "cannot merge graphs with %<PRIuMAX>, %<PRIuMAX> commits" -msgstr "無法將圖與 %<PRIuMAX>, %<PRIuMAX> 個æäº¤é€²è¡Œåˆä½µ" +msgstr "無法åˆä½µåœ–,兩者分別有 %<PRIuMAX>ã€%<PRIuMAX> 個æäº¤" #: commit-graph.c #, c-format msgid "cannot merge graph %s, too many commits: %<PRIuMAX>" -msgstr "無法åˆä½µ %s 圖,太多æäº¤ï¼š%<PRIuMAX>" +msgstr "無法åˆä½µåœ– %s,太多æäº¤ï¼š%<PRIuMAX>" #: commit-graph.c msgid "Scanning merged commits" @@ -18023,15 +18206,22 @@ msgstr "æ£åœ¨æŽƒæåˆä½µæäº¤" #: commit-graph.c msgid "Merging commit-graph" -msgstr "æ£åœ¨åˆä½µæäº¤åœ–å½¢" +msgstr "æ£åœ¨åˆä½µæäº¤åœ–" #: commit-graph.c msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled" -msgstr "嘗試寫入æäº¤åœ–形,但 “core.commitGraph†已被åœç”¨" +msgstr "嘗試寫入æäº¤åœ–,但「core.commitGraphã€å·²åœç”¨" + +#: commit-graph.c +#, c-format +msgid "" +"attempting to write a commit-graph, but 'commitGraph." +"changedPathsVersion' (%d) is not supported" +msgstr "嘗試寫入æäº¤åœ–ï¼Œä½†ä¸æ”¯æ´ã€ŒcommitGraph.changedPathsVersionã€ï¼ˆ%d)" #: commit-graph.c msgid "too many commits to write graph" -msgstr "æäº¤å¤ªå¤šä¸èƒ½ç•«åœ–" +msgstr "æäº¤éŽå¤šç„¡æ³•畫圖" #: commit-graph.c msgid "the commit-graph file has incorrect checksum and is likely corrupt" @@ -18040,59 +18230,59 @@ msgstr "æäº¤åœ–檔案的總和檢查碼錯誤,å¯èƒ½å·²ç¶“æå£ž" #: commit-graph.c #, c-format msgid "commit-graph has incorrect OID order: %s then %s" -msgstr "æäº¤åœ–形的物件 ID é †åºä¸æ£ç¢ºï¼š%s 然後 %s" +msgstr "æäº¤åœ–的物件 ID é †åºä¸æ£ç¢ºï¼š%s 然後 %s" #: commit-graph.c #, c-format msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u" -msgstr "æäº¤åœ–å½¢æœ‰ä¸æ£ç¢ºçš„æ‰‡å‡ºå€¼ï¼šfanout[%d] = %u != %u" +msgstr "æäº¤åœ–æœ‰ä¸æ£ç¢ºçš„æ‰‡å‡ºå€¼ï¼šfanout[%d] = %u != %u" #: commit-graph.c #, c-format msgid "failed to parse commit %s from commit-graph" -msgstr "無法從æäº¤åœ–å½¢ä¸è§£æžæäº¤ %s" +msgstr "無法從æäº¤åœ–ä¸è§£æžæäº¤ %s" #: commit-graph.c #, c-format msgid "failed to parse commit %s from object database for commit-graph" -msgstr "無法從æäº¤åœ–形的物件庫ä¸è§£æžæäº¤ %s" +msgstr "無法從æäº¤åœ–的物件資料庫ä¸è§£æžæäº¤ %s" #: commit-graph.c #, c-format msgid "root tree OID for commit %s in commit-graph is %s != %s" -msgstr "æäº¤åœ–å½¢ä¸çš„æäº¤ %s çš„æ ¹æ¨¹ç‹€ç‰©ä»¶ ID 是 %s != %s" +msgstr "æäº¤åœ–ä¸çš„æäº¤ %s çš„æ ¹æ¨¹ç‹€ç‰©ä»¶ ID 是 %s != %s" #: commit-graph.c #, c-format msgid "commit-graph parent list for commit %s is too long" -msgstr "æäº¤ %s çš„æäº¤åœ–形父æäº¤åˆ—表太長了" +msgstr "æäº¤ %s çš„æäº¤åœ–上級清單éŽé•·" #: commit-graph.c #, c-format msgid "commit-graph parent for %s is %s != %s" -msgstr "%s çš„æäº¤åœ–形父æäº¤æ˜¯ %s != %s" +msgstr "%s çš„æäº¤åœ–上級是 %s != %s" #: commit-graph.c #, c-format msgid "commit-graph parent list for commit %s terminates early" -msgstr "æäº¤ %s çš„æäº¤åœ–形父æäº¤åˆ—è¡¨éŽæ—©çµ‚æ¢" +msgstr "æäº¤ %s çš„æäº¤åœ–ä¸Šç´šæ¸…å–®éŽæ—©çµ‚æ¢" #: commit-graph.c #, c-format msgid "commit-graph generation for commit %s is %<PRIuMAX> < %<PRIuMAX>" -msgstr "æäº¤ %s çš„æäº¤åœ–形處於 %<PRIuMAX> < %<PRIuMAX> 世代" +msgstr "æäº¤ %s 使–¼ %<PRIuMAX> < %<PRIuMAX> æäº¤åœ–世代" #: commit-graph.c #, c-format msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>" -msgstr "æäº¤åœ–å½¢ä¸æäº¤ %s çš„æäº¤æ—¥æœŸæ˜¯ %<PRIuMAX> != %<PRIuMAX>" +msgstr "æäº¤åœ–ä¸çš„æäº¤ %s æäº¤æ—¥æœŸæ˜¯ %<PRIuMAX> != %<PRIuMAX>" #: commit-graph.c #, c-format msgid "" "commit-graph has both zero and non-zero generations (e.g., commits '%s' and " "'%s')" -msgstr "æäº¤åœ–å½¢ä¸åŒ…å« 0 å’Œéž 0 兩個世代號(例如 “%s†和 “%s†æäº¤ï¼‰" +msgstr "æäº¤åœ–ä¸åŒ…å« 0 å’Œéž 0 兩個世代數(例如æäº¤ã€Œ%sã€å’Œã€Œ%sã€ï¼‰" #: commit-graph.c msgid "Verifying commits in commit graph" @@ -18131,7 +18321,7 @@ msgstr "" #: commit.c #, c-format msgid "commit %s exists in commit-graph but not in the object database" -msgstr "%s æäº¤åœ¨æäº¤åœ–å½¢ä¸ï¼Œä½†ä¸åœ¨ç‰©ä»¶è³‡æ–™åº«ä¸" +msgstr "%s æäº¤åœ¨æäº¤åœ–ä¸ï¼Œä½†ä¸åœ¨ç‰©ä»¶è³‡æ–™åº«ä¸" #: commit.c #, c-format @@ -18174,37 +18364,37 @@ msgstr "沒有å¯ç”¨çš„ libc 資訊\n" #: compat/disk.h #, c-format msgid "could not determine free disk size for '%s'" -msgstr "無法判斷 “%s†的剩餘ç£ç¢Ÿå¤§å°" +msgstr "無法判斷「%sã€çš„剩餘ç£ç¢Ÿå¤§å°" #: compat/disk.h #, c-format msgid "could not get info for '%s'" -msgstr "無法å–å¾— “%s†的資訊" +msgstr "無法å–得「%sã€çš„資訊" #: compat/fsmonitor/fsm-health-win32.c #, c-format msgid "[GLE %ld] health thread could not open '%ls'" -msgstr "[GLE %ld] å¥åº·ç›£è½åŸ·è¡Œç·’無法開啟 “%lsâ€" +msgstr "[GLE %ld] å¥åº·ç›£è½åŸ·è¡Œç·’無法開啟「%lsã€" #: compat/fsmonitor/fsm-health-win32.c #, c-format msgid "[GLE %ld] health thread getting BHFI for '%ls'" -msgstr "[GLE %ld] å¥åº·ç›£è½åŸ·è¡Œç·’å–å¾— “%ls†的 BHFI" +msgstr "[GLE %ld] å¥åº·ç›£è½åŸ·è¡Œç·’å–得「%lsã€çš„ BHFI" #: compat/fsmonitor/fsm-health-win32.c compat/fsmonitor/fsm-listen-win32.c #, c-format msgid "could not convert to wide characters: '%s'" -msgstr "無法轉æ›è‡³è¼ƒå¯¬å—元:“%sâ€" +msgstr "無法轉æ›è‡³è¼ƒå¯¬å—元:「%sã€" #: compat/fsmonitor/fsm-health-win32.c #, c-format msgid "BHFI changed '%ls'" -msgstr "BHFI 更改了 “%lsâ€" +msgstr "BHFI 更改了「%lsã€" #: compat/fsmonitor/fsm-health-win32.c #, c-format msgid "unhandled case in 'has_worktree_moved': %d" -msgstr "“has_worktree_movedâ€ ä¸æœ‰æœªè™•置的情æ³ï¼š%d" +msgstr "「has_worktree_movedã€ä¸æœ‰æœªè™•置的情æ³ï¼š%d" #: compat/fsmonitor/fsm-health-win32.c #, c-format @@ -18232,22 +18422,22 @@ msgstr "[GLE %ld] 無法將路徑轉æ›ç‚º UTF-8:「%.*lsã€" #: compat/fsmonitor/fsm-listen-win32.c #, c-format msgid "[GLE %ld] could not watch '%s'" -msgstr "[GLE %ld] ç„¡æ³•ç›£è½ â€œ%sâ€" +msgstr "[GLE %ld] 無法監è½ã€Œ%sã€" #: compat/fsmonitor/fsm-listen-win32.c #, c-format msgid "[GLE %ld] could not get longname of '%s'" -msgstr "[GLE %ld] 無法å–å¾— “%s†的 longname" +msgstr "[GLE %ld] 無法å–得「%sã€çš„ longname" #: compat/fsmonitor/fsm-listen-win32.c #, c-format msgid "ReadDirectoryChangedW failed on '%s' [GLE %ld]" -msgstr "在 “%sâ€ ä¸Šå‘¼å« ReadDirectoryChangedW 失敗 [GLE %ld]" +msgstr "在「%sã€ä¸Šå‘¼å« ReadDirectoryChangedW 失敗 [GLE %ld]" #: compat/fsmonitor/fsm-listen-win32.c #, c-format msgid "GetOverlappedResult failed on '%s' [GLE %ld]" -msgstr "在 “%sâ€ ä¸Šå‘¼å« GetOverlappedResult 失敗 [GLE %ld]" +msgstr "在「%sã€ä¸Šå‘¼å« GetOverlappedResult 失敗 [GLE %ld]" #: compat/fsmonitor/fsm-listen-win32.c #, c-format @@ -18292,7 +18482,7 @@ msgstr "無法複製 SID (%ld)" #: compat/mingw.c #, c-format msgid "failed to get owner for '%s' (%ld)" -msgstr "無法å–å¾— “%s†的所有者 (%ld)" +msgstr "無法å–得「%sã€çš„æ‰€æœ‰è€… (%ld)" #: compat/obstack.c msgid "memory exhausted" @@ -18381,7 +18571,7 @@ msgstr "ç„¡æ³•è®€å– IPC 回應" #: compat/simple-ipc/ipc-unix-socket.c #, c-format msgid "could not start accept_thread '%s'" -msgstr "無法啟動 accept_thread “%sâ€" +msgstr "無法啟動 accept_thread「%sã€" #: compat/simple-ipc/ipc-unix-socket.c #, c-format @@ -18391,26 +18581,26 @@ msgstr "無法啟動「%sã€çš„ worker[0]" #: compat/simple-ipc/ipc-win32.c #, c-format msgid "ConnectNamedPipe failed for '%s' (%lu)" -msgstr "å° â€œ%s†進行 ConnectNamedPipe 失敗 (%lu)" +msgstr "å°ã€Œ%sã€é€²è¡Œ ConnectNamedPipe 失敗 (%lu)" #: compat/simple-ipc/ipc-win32.c #, c-format msgid "could not create fd from pipe for '%s'" -msgstr "無法為 “%s†從管é“建立 fd" +msgstr "無法為「%sã€å¾žç®¡é“建立 fd" #: compat/simple-ipc/ipc-win32.c #, c-format msgid "could not start thread[0] for '%s'" -msgstr "無法為 “%s†啟動 thread[0]" +msgstr "無法為「%sã€å•Ÿå‹• thread[0]" #: compat/simple-ipc/ipc-win32.c #, c-format msgid "wait for hEvent failed for '%s'" -msgstr "ç‰å¾… “%s†的 hEvent 失敗" +msgstr "ç‰å¾…「%sã€çš„ hEvent 失敗" #: compat/terminal.c msgid "cannot resume in the background, please use 'fg' to resume" -msgstr "無法在背景繼續;請使用 “fg†繼續" +msgstr "無法在背景繼續;請使用「fgã€ç¹¼çºŒ" #: compat/terminal.c msgid "cannot restore terminal settings" @@ -18602,7 +18792,7 @@ msgstr "%s 變數的值無效" #: config.c #, c-format msgid "ignoring unknown core.fsync component '%s'" -msgstr "忽略未知的 core.fsync 組件「%sã€" +msgstr "忽略未知的 core.fsync 元件「%sã€" #: config.c #, c-format @@ -18778,7 +18968,7 @@ msgstr "無效的å°ç¯€å稱:%s" #: config.c #, c-format msgid "refusing to work with overly long line in '%s' on line %<PRIuMAX>" -msgstr "å› ç‚ºç¬¬ %2$<PRIuMAX> åˆ—ä¸ â€œ%1$s†的文å—列太長,故拒絕é‹ä½œ" +msgstr "å› ç‚ºç¬¬ %2$<PRIuMAX> 列ä¸ã€Œ%1$sã€çš„æ–‡å—列太長,故拒絕é‹ä½œ" #: config.c #, c-format @@ -18992,7 +19182,7 @@ msgstr "%s ä¸çš„ CRLF 將被 LF å–代" msgid "" "in the working copy of '%s', CRLF will be replaced by LF the next time Git " "touches it" -msgstr "在 “%s†的工作複本ä¸ï¼Œä¸‹æ¬¡ Git 接觸到時會用 LF å–代 CRLF" +msgstr "在「%sã€çš„工作複本ä¸ï¼Œä¸‹æ¬¡ Git 接觸到時會用 LF å–代 CRLF" #: convert.c #, c-format @@ -19004,7 +19194,7 @@ msgstr "檔案 %s ä¸çš„ LF 將被 CRLF å–代" msgid "" "in the working copy of '%s', LF will be replaced by CRLF the next time Git " "touches it" -msgstr "在 “%s†的工作複本ä¸ï¼Œä¸‹æ¬¡ Git 接觸到時會用 CRLF å–代 LF" +msgstr "在「%sã€çš„工作複本ä¸ï¼Œä¸‹æ¬¡ Git 接觸到時會用 CRLF å–代 LF" #: convert.c #, c-format @@ -19225,7 +19415,7 @@ msgstr "ä¸èƒ½é–‹å•Ÿç›®éŒ„ '%s'" #: diagnose.c #, c-format msgid "skipping '%s', which is neither file nor directory" -msgstr "ç•¥éŽ â€œ%sâ€ï¼Œå…¶éžæª”案或目錄" +msgstr "ç•¥éŽã€Œ%sã€ï¼Œå…¶éžæª”案或目錄" #: diagnose.c msgid "could not duplicate stdout" @@ -19523,7 +19713,7 @@ msgstr "使用æä¾›çš„æª”案å長度生æˆå·®ç•°çµ±è¨ˆ" #: diff.c msgid "generate diffstat with a given graph width" -msgstr "使用æä¾›çš„圖形長度生æˆå·®ç•°çµ±è¨ˆ" +msgstr "產出é™åˆ¶ç‚ºæä¾›çš„寬度的差異統計圖形" #: diff.c msgid "<count>" @@ -20159,7 +20349,7 @@ msgstr "é æœŸ '%s',得到 '%s'" #: fetch-pack.c #, c-format msgid "expected '%s'" -msgstr "é æœŸ “%sâ€" +msgstr "é æœŸã€Œ%sã€" #: fetch-pack.c #, c-format @@ -20251,45 +20441,49 @@ msgstr "無法將「%sã€å‘½ä»¤å‚³é€åˆ° fsmonitor--daemon" #: fsmonitor-settings.c #, c-format msgid "bare repository '%s' is incompatible with fsmonitor" -msgstr "純版本庫 “%s†與 fsmonitor ä¸ç›¸å®¹" +msgstr "純版本庫「%sã€èˆ‡ fsmonitor ä¸ç›¸å®¹" #: fsmonitor-settings.c #, c-format msgid "repository '%s' is incompatible with fsmonitor due to errors" -msgstr "版本庫 “%sâ€ å› éŒ¯èª¤è€Œèˆ‡ fsmonitor ä¸ç›¸å®¹" +msgstr "版本庫「%sã€å› 錯誤而與 fsmonitor ä¸ç›¸å®¹" #: fsmonitor-settings.c #, c-format msgid "remote repository '%s' is incompatible with fsmonitor" -msgstr "é 端版本庫 “%s†與 fsmonitor ä¸ç›¸å®¹" +msgstr "é 端版本庫「%sã€èˆ‡ fsmonitor ä¸ç›¸å®¹" #: fsmonitor-settings.c #, c-format msgid "virtual repository '%s' is incompatible with fsmonitor" -msgstr "虛擬版本庫 “%s†與 fsmonitor ä¸ç›¸å®¹" +msgstr "虛擬版本庫「%sã€èˆ‡ fsmonitor ä¸ç›¸å®¹" #: fsmonitor-settings.c #, c-format msgid "" "socket directory '%s' is incompatible with fsmonitor due to lack of Unix " "sockets support" -msgstr "通訊端 “%sâ€ å› ç¼ºå°‘ Unix 通訊端支æ´ï¼Œè€Œèˆ‡ fsmonitor ä¸ç›¸å®¹" +msgstr "通訊端「%sã€å› 缺少 Unix 通訊端支æ´ï¼Œè€Œèˆ‡ fsmonitor ä¸ç›¸å®¹" #: git.c msgid "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" msgstr "" "git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n" " [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--" -"bare]\n" -" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n" -" [--config-env=<name>=<envvar>] <command> [<args>]" +" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-" +"lazy-fetch]\n" +" [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]\n" +" [--work-tree=<path>] [--namespace=<name>] [--config-" +"env=<name>=<envvar>]\n" +" <command> [<args>]" #: git.c msgid "" @@ -20493,7 +20687,7 @@ msgstr "無法從「%sã€è®€å– SSH ç°½å資料緩è¡å€" #: graph.c #, c-format msgid "ignored invalid color '%.*s' in log.graphColors" -msgstr "已忽略 log.graphColors ä¸ç„¡æ•ˆçš„ “%.*s†色彩" +msgstr "已忽略 log.graphColors ä¸ç„¡æ•ˆçš„「%.*sã€è‰²å½©" #: grep.c msgid "" @@ -20689,14 +20883,14 @@ msgstr "" "è¨å®š `git config advice.ignoredHook false` 來關閉這æ¢è¦å‘Šã€‚" #: http-fetch.c +msgid "not a git repository" +msgstr "䏿˜¯ä¸€å€‹ git 版本庫" + +#: http-fetch.c #, c-format msgid "argument to --packfile must be a valid hash (got '%s')" msgstr "傳入 --packfile çš„åƒæ•¸å¿…é ˆæ˜¯æœ‰æ•ˆçš„é›œæ¹Š (收到 '%s')" -#: http-fetch.c -msgid "not a git repository" -msgstr "䏿˜¯ä¸€å€‹ git 版本庫" - #: http.c #, c-format msgid "negative value for http.postBuffer; defaulting to %d" @@ -20711,6 +20905,10 @@ msgid "Public key pinning not supported with cURL < 7.39.0" msgstr "䏿”¯æ´å…¬é‘°æª”æ¡ˆéŽ–å®šï¼Œå› ç‚º cURL < 7.39.0" #: http.c +msgid "Unknown value for http.proactiveauth" +msgstr "http.proactiveauth 的值未知" + +#: http.c msgid "CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0" msgstr "䏿”¯æ´ CURLSSLOPT_NO_REVOKEï¼Œå› ç‚º cURL < 7.44.0" @@ -20730,6 +20928,14 @@ msgid "Could not set SSL backend to '%s': already set" msgstr "無法將 SSL 後端è¨å®šç‚º '%s':已經è¨å®š" #: http.c +msgid "refusing to read cookies from http.cookiefile '-'" +msgstr "ä¸å…許從 http.cookiefile çš„è¨å®šå€¼ã€Œ-ã€è™•è®€å– cookie" + +#: http.c +msgid "ignoring http.savecookies for empty http.cookiefile" +msgstr "http.cookiefile 空白,忽略 http.savecookies" + +#: http.c #, c-format msgid "" "unable to update url base from redirection:\n" @@ -20813,7 +21019,7 @@ msgstr "sparse:path éŽæ¿¾å™¨æ”¯æ´å·²è¢«åˆªé™¤" #: list-objects-filter-options.c #, c-format msgid "'%s' for 'object:type=<type>' is not a valid object type" -msgstr "“object:type=<type>†的 “%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„ç‰©ä»¶æ ¼å¼" +msgstr "「object:type=<type>ã€çš„「%sã€ä¸æ˜¯æœ‰æ•ˆçš„ç‰©ä»¶æ ¼å¼" #: list-objects-filter-options.c #, c-format @@ -20937,10 +21143,10 @@ msgstr "無法åˆä½µ %s 忍¡çµ„(沒有åˆä½µåŸºåº•)" msgid "Failed to merge submodule %s (commits not present)" msgstr "無法åˆä½µå模組 %s(æäº¤ä¸å˜åœ¨ï¼‰" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "Failed to merge submodule %s (repository corrupt)" -msgstr "無法åˆä½µå模組 %s (版本庫æå£žï¼‰" +msgid "error: failed to merge submodule %s (repository corrupt)" +msgstr "錯誤:無法åˆä½µå模組 %s (版本庫æå£žï¼‰" #: merge-ort.c merge-recursive.c #, c-format @@ -20972,14 +21178,15 @@ msgstr "" "無法åˆä½µ %s 忍¡çµ„,但有找到幾個å¯è¡Œçš„åˆä½µæ–¹æ¡ˆï¼š\n" "%s" -#: merge-ort.c merge-recursive.c -msgid "failed to execute internal merge" -msgstr "無法執行內部åˆä½µ" +#: merge-ort.c +#, c-format +msgid "error: failed to execute internal merge for %s" +msgstr "éŒ¯èª¤ï¼šç„¡æ³•å° %s 執行內部åˆä½µ" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "unable to add %s to database" -msgstr "無法將 %s åŠ é€²è³‡æ–™åº«" +msgid "error: unable to add %s to database" +msgstr "錯誤:無法將 %s åŠ é€²è³‡æ–™åº«" #: merge-ort.c merge-recursive.c #, c-format @@ -21079,15 +21286,15 @@ msgid "CONFLICT (rename/delete): %s renamed to %s in %s, but deleted in %s." msgstr "" "è¡çªï¼ˆé‡æ–°å‘½å/刪除):%1$s 已釿–°å‘½å為 %3$s ä¸çš„ %2$s å»åœ¨ %4$s ä¸è¢«åˆªé™¤ã€‚" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "cannot read object %s" -msgstr "ä¸èƒ½è®€å–物件 %s" +msgid "error: cannot read object %s" +msgstr "錯誤:無法讀å–物件 %s" -#: merge-ort.c merge-recursive.c +#: merge-ort.c #, c-format -msgid "object %s is not a blob" -msgstr "物件 %s 䏿˜¯ä¸€å€‹è³‡æ–™ç‰©ä»¶" +msgid "error: object %s is not a blob" +msgstr "錯誤:物件 %s 䏿˜¯ä¸€å€‹è³‡æ–™ç‰©ä»¶" #: merge-ort.c #, c-format @@ -21243,6 +21450,11 @@ msgstr "ä¸çŸ¥é“å¦‚ä½•è™•ç† %06o %s '%s'" #: merge-recursive.c #, c-format +msgid "Failed to merge submodule %s (repository corrupt)" +msgstr "無法åˆä½µå模組 %s (版本庫æå£žï¼‰" + +#: merge-recursive.c +#, c-format msgid "Fast-forwarding submodule %s to the following commit:" msgstr "忍¡çµ„ %s 快轉到如下æäº¤ï¼š" @@ -21287,6 +21499,15 @@ msgid "Failed to merge submodule %s (multiple merges found)" msgstr "無法åˆä½µå模組 %s (發ç¾å¤šå€‹åˆä½µï¼‰" #: merge-recursive.c +msgid "failed to execute internal merge" +msgstr "無法執行內部åˆä½µ" + +#: merge-recursive.c +#, c-format +msgid "unable to add %s to database" +msgstr "無法將 %s åŠ é€²è³‡æ–™åº«" + +#: merge-recursive.c #, c-format msgid "Error: Refusing to lose untracked file at %s; writing to %s instead." msgstr "錯誤:拒絕éºå¤±æœªè¿½è¹¤æª”案 '%s',而是寫入 %s。" @@ -21401,6 +21622,16 @@ msgstr "" "命å目錄 %4$s->%5$s" #: merge-recursive.c +#, c-format +msgid "cannot read object %s" +msgstr "ä¸èƒ½è®€å–物件 %s" + +#: merge-recursive.c +#, c-format +msgid "object %s is not a blob" +msgstr "物件 %s 䏿˜¯ä¸€å€‹è³‡æ–™ç‰©ä»¶" + +#: merge-recursive.c msgid "modify" msgstr "修改" @@ -21504,10 +21735,6 @@ msgid "malformed line: %s" msgstr "æ©«åˆ—æ ¼å¼éŒ¯èª¤ï¼š%s" #: midx-write.c -msgid "ignoring existing multi-pack-index; checksum mismatch" -msgstr "å¿½ç•¥ç¾æœ‰çš„多包索引:總和檢查碼ä¸ç¬¦" - -#: midx-write.c msgid "could not load pack" msgstr "無法載入包" @@ -21517,6 +21744,10 @@ msgid "could not open index for %s" msgstr "無法開啟 %s 的索引" #: midx-write.c +msgid "ignoring existing multi-pack-index; checksum mismatch" +msgstr "å¿½ç•¥ç¾æœ‰çš„多包索引:總和檢查碼ä¸ç¬¦" + +#: midx-write.c msgid "Adding packfiles to multi-pack-index" msgstr "æ£åœ¨æ–°å¢ž packfile 至多包索引" @@ -22254,6 +22485,20 @@ msgid "hash mismatch %s" msgstr "雜湊值與 %s ä¸ç¬¦åˆ" #: pack-bitmap-write.c +#, c-format +msgid "duplicate entry when writing bitmap index: %s" +msgstr "寫入ä½åœ–ç´¢å¼•ä¸æ™‚發ç¾é‡è¤‡é …目:%s" + +#: pack-bitmap-write.c +#, c-format +msgid "attempted to store non-selected commit: '%s'" +msgstr "å˜—è©¦å„²å˜æœªé¸å–çš„æäº¤ï¼šã€Œ%sã€" + +#: pack-bitmap-write.c +msgid "too many pseudo-merges" +msgstr "å½åˆä½µéŽå¤š" + +#: pack-bitmap-write.c msgid "trying to write commit not in index" msgstr "嘗試寫入ä¸åœ¨ç´¢å¼•çš„æäº¤" @@ -22272,7 +22517,7 @@ msgstr "ä½åœ–索引檔案æå£žï¼ˆæ¨™é 錯誤)" #: pack-bitmap.c #, c-format msgid "unsupported version '%d' for bitmap index file" -msgstr "ä½åœ–索引檔案的版本 “%dâ€ ä¸æ”¯æ´" +msgstr "ä½åœ–索引檔案的版本「%dã€ä¸æ”¯æ´" #: pack-bitmap.c msgid "corrupted bitmap index file (too short to fit hash cache)" @@ -22283,6 +22528,19 @@ msgid "corrupted bitmap index file (too short to fit lookup table)" msgstr "ä½åœ–索引檔案æå£žï¼ˆä¸å¤ 長,無法置入查詢表)" #: pack-bitmap.c +msgid "" +"corrupted bitmap index file (too short to fit pseudo-merge table header)" +msgstr "ä½åœ–索引檔案æå£žï¼ˆä¸å¤ 長,無法置入å½åˆä½µè¡¨æ¨™é )" + +#: pack-bitmap.c +msgid "corrupted bitmap index file (too short to fit pseudo-merge table)" +msgstr "ä½åœ–索引檔案æå£žï¼ˆä¸å¤ 長,無法置入å½åˆä½µè¡¨ï¼‰" + +#: pack-bitmap.c +msgid "corrupted bitmap index file, pseudo-merge table too short" +msgstr "ä½åœ–索引檔案æå£žï¼Œå½åˆä½µè¡¨å¤ªçŸ" + +#: pack-bitmap.c #, c-format msgid "duplicate entry in bitmap index: '%s'" msgstr "ä½åœ–ç´¢å¼•ä¸æœ‰é‡è¤‡é …目:「%sã€" @@ -22347,7 +22605,7 @@ msgstr "ä½åœ–查詢表æå£žï¼šæäº¤ç´¢å¼• %u 超出範åœ" #: pack-bitmap.c #, c-format msgid "corrupt ewah bitmap: truncated header for bitmap of commit \"%s\"" -msgstr "ewah ä½åœ–æå£žï¼šæäº¤ “%s†之ä½åœ–的標é éæˆªæ–·" +msgstr "ewah ä½åœ–æå£žï¼šæäº¤ã€Œ%sã€ä¹‹ä½åœ–的標é éæˆªæ–·" #: pack-bitmap.c #, c-format @@ -22397,6 +22655,11 @@ msgstr "ä½åœ–çµæžœä¸æœ‰ä¸ç¬¦é …ç›®" #: pack-bitmap.c #, c-format +msgid "pseudo-merge index out of range (%<PRIu32> >= %<PRIuMAX>)" +msgstr "å½åˆä½µç´¢å¼•超出範åœï¼ˆ%<PRIu32> >= %<PRIuMAX>)" + +#: pack-bitmap.c +#, c-format msgid "could not find '%s' in pack '%s' at offset %<PRIuMAX>" msgstr "在「%2$sã€å°åŒ…,ä½ç§» %3$<PRIuMAX> 的地方找ä¸åˆ°ã€Œ%1$sã€" @@ -22408,7 +22671,7 @@ msgstr "無法å–得「%sã€çš„ç£ç¢Ÿç”¨é‡" #: pack-bitmap.c #, c-format msgid "bitmap file '%s' has invalid checksum" -msgstr "“%s†ä½åœ–檔案的總和檢查碼無效" +msgstr "「%sã€ä½åœ–檔案的總和檢查碼無效" #: pack-mtimes.c #, c-format @@ -22751,7 +23014,7 @@ msgstr "%s:'literal' å’Œ 'glob' ä¸ç›¸å®¹" #: pathspec.c #, c-format msgid "'%s' is outside the directory tree" -msgstr "“%s†在目錄樹之外" +msgstr "「%sã€åœ¨ç›®éŒ„樹之外" #: pathspec.c #, c-format @@ -22848,6 +23111,10 @@ msgid "unable to parse --pretty format" msgstr "ä¸èƒ½è§£æž --pretty æ ¼å¼" #: promisor-remote.c +msgid "lazy fetching disabled; some objects may not be available" +msgstr "延後抓å–已被åœç”¨ï¼›æŸäº›ç‰©ä»¶å¯èƒ½ç„¡æ³•使用" + +#: promisor-remote.c msgid "promisor-remote: unable to fork off fetch subprocess" msgstr "promisor-remote: 無法 fork fetch å處ç†ç¨‹åº" @@ -22877,6 +23144,72 @@ msgstr "object-infoï¼šå¼•æ•¸å¾Œé æœŸè¦æœ‰ flush" msgid "Removing duplicate objects" msgstr "æ£åœ¨åˆªé™¤é‡è¤‡ç‰©ä»¶" +#: pseudo-merge.c +#, c-format +msgid "failed to load pseudo-merge regex for %s: '%s'" +msgstr "未能載入 %s çš„å½åˆä½µå¸¸è¦è¡¨ç¤ºå¼ï¼š%s" + +#: pseudo-merge.c +#, c-format +msgid "%s must be non-negative, using default" +msgstr "%s é ˆç‚ºéžè² 數,將採用é è¨å€¼" + +#: pseudo-merge.c +#, c-format +msgid "%s must be between 0 and 1, using default" +msgstr "%s é ˆä»‹æ–¼ 0 到 1 之間,將採用é è¨å€¼" + +#: pseudo-merge.c +#, c-format +msgid "%s must be positive, using default" +msgstr "%s é ˆç‚ºæ£æ•¸ï¼Œå°‡æŽ¡ç”¨é è¨å€¼" + +#: pseudo-merge.c +#, c-format +msgid "pseudo-merge group '%s' missing required pattern" +msgstr "å½åˆä½µç¾¤çµ„「%sã€ç¼ºå°‘å¿…é ˆçš„æ¨¡å¼" + +#: pseudo-merge.c +#, c-format +msgid "pseudo-merge group '%s' has unstable threshold before stable one" +msgstr "å½åˆä½µç¾¤çµ„「%sã€çš„éžç©©å®šé–¾å€¼ä½æ–¼ç©©å®šè€…之å‰" + +#: pseudo-merge.c +#, c-format +msgid "" +"pseudo-merge regex from config has too many capture groups (max=%<PRIuMAX>)" +msgstr "來自組態的å½åˆä½µå¸¸è¦è¡¨ç¤ºå¼åŒ…å«å¤ªå¤šçš„æ“·å–群組(最多 %<PRIuMAX> 個)" + +#: pseudo-merge.c +#, c-format +msgid "extended pseudo-merge read out-of-bounds (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "延伸å½åˆä½µè®€å–超出範åœï¼ˆ%<PRIuMAX> >= %<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "extended pseudo-merge entry is too short (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "延伸å½åˆä½µé …ç›®éŽçŸï¼ˆ%<PRIuMAX> >= %<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "could not find pseudo-merge for commit %s at offset %<PRIuMAX>" +msgstr "無法在åç§» %2$<PRIuMAX> 處找到æäº¤ %1$s çš„å½åˆä½µ" + +#: pseudo-merge.c +#, c-format +msgid "extended pseudo-merge lookup out-of-bounds (%<PRIu32> >= %<PRIu32>)" +msgstr "延伸å½åˆä½µæŸ¥è©¢è¶…出範åœï¼ˆ%<PRIu32> >= %<PRIu32>)" + +#: pseudo-merge.c +#, c-format +msgid "out-of-bounds read: (%<PRIuMAX> >= %<PRIuMAX>)" +msgstr "讀å–超出範åœï¼šï¼ˆ%<PRIuMAX> >= %<PRIuMAX>)" + +#: pseudo-merge.c +#, c-format +msgid "could not read extended pseudo-merge table for commit %s" +msgstr "ç„¡æ³•è®€å–æäº¤ %s 的延伸å½åˆä½µè¡¨" + #: range-diff.c msgid "could not start `log`" msgstr "ä¸èƒ½å•Ÿå‹• `log`" @@ -22914,7 +23247,7 @@ msgstr "ä¸èƒ½è§£æž '%s' 的日誌" #: reachable.c #, c-format msgid "invalid extra cruft tip: '%s'" -msgstr "無效的é¡å¤–廢棄æäº¤ä¿®è¨‚版:“%sâ€" +msgstr "無效的é¡å¤–廢棄æäº¤ä¿®è¨‚版:「%sã€" #: reachable.c msgid "unable to enumerate additional recent objects" @@ -23106,7 +23439,7 @@ msgstr "éžé 期的 diff 狀態 %c" #: read-cache.c #, c-format msgid "remove '%s'\n" -msgstr "移除 “%sâ€\n" +msgstr "移除「%sã€\n" #: rebase-interactive.c msgid "" @@ -23156,11 +23489,11 @@ msgstr "" "r, reword <æäº¤> = 使用æäº¤ï¼Œä½†ç·¨è¼¯æäº¤èªªæ˜Ž\n" "e, edit <æäº¤> = 使用æäº¤ï¼Œä½†ä¸ç›´æŽ¥ä¿®è£œ (amend) \n" "s, squash <æäº¤> = 使用æäº¤ï¼Œä½†èžåˆè‡³ä¸Šå€‹æäº¤\n" -"f, fixup [-C | -c] <æäº¤> = è·Ÿ “squash†相似,但除éžå‚³å…¥ -C,\n" +"f, fixup [-C | -c] <æäº¤> = 跟「squashã€ç›¸ä¼¼ï¼Œä½†é™¤éžå‚³å…¥ -C,\n" " å¦å‰‡åªä¿ç•™ä¸Šä¸€å€‹æäº¤çš„æ—¥èªŒè¨Šæ¯ã€‚傳入 -C 表示åªä¿ç•™é€™å€‹\n" " æäº¤çš„訊æ¯ï¼›å‚³å…¥ -c 與 -C 功能相åŒï¼Œä½†æœƒé–‹å•Ÿç·¨è¼¯å™¨\n" "x, exec <命令> = 使用 shell 執行命令(這一列的剩餘部分)\n" -"b, break = 在æ¤åœæ¢ï¼ˆä½¿ç”¨ “git rebase --continue†繼續é‡å®šåŸºåº•)\n" +"b, break = 在æ¤åœæ¢ï¼ˆä½¿ç”¨ã€Œgit rebase --continueã€ç¹¼çºŒé‡å®šåŸºåº•)\n" "d, drop <æäº¤> = 移除æäº¤\n" "l, label <標籤> = ç‚ºç›®å‰ HEAD 打上指定åå—æ¨™ç±¤\n" "t, reset <標籤> = é‡è¨ HEAD 到指定標籤\n" @@ -23432,7 +23765,7 @@ msgstr "--format=%.*s ä¸èƒ½å’Œ --pythonã€--shellã€--tcl 一起使用" #: ref-filter.c msgid "failed to run 'describe'" -msgstr "無法執行 “describeâ€" +msgstr "無法執行「describeã€" #: ref-filter.c #, c-format @@ -23550,8 +23883,8 @@ msgstr "" "\n" "\tgit config --global init.defaultBranch <name>\n" "\n" -"除了 “master†外,常用的分支å稱有 “mainâ€, “trunk†以åŠ\n" -"“developmentâ€ã€‚剛建立的分支å¯ä»¥ç”¨é€™å€‹å‘½ä»¤é‡æ–°å‘½å:\n" +"除了「masterã€å¤–,常用的分支å稱有「mainã€,「trunkã€ä»¥åŠ\n" +"「developmentã€ã€‚剛建立的分支å¯ä»¥ç”¨é€™å€‹å‘½ä»¤é‡æ–°å‘½å:\n" "\n" "\tgit branch -m <name>\n" @@ -23586,12 +23919,21 @@ msgid "log for %s is empty" msgstr "%s 的日誌為空" #: refs.c +msgid "refusing to force and skip creation of reflog" +msgstr "拒絕強制並略éŽå»ºç«‹å¼•用日誌" + +#: refs.c #, c-format msgid "refusing to update ref with bad name '%s'" msgstr "拒絕更新有錯誤å稱 '%s' 的引用" #: refs.c #, c-format +msgid "refusing to update pseudoref '%s'" +msgstr "拒絕更新å½å¼•用「%sã€" + +#: refs.c +#, c-format msgid "update_ref failed for ref '%s': %s" msgstr "å°å¼•用 '%s' 執行 update_ref 失敗:%s" @@ -23628,6 +23970,27 @@ msgstr "無法刪除引用 %s:%s" msgid "could not delete references: %s" msgstr "無法刪除引用:%s" +#: refs.c +#, c-format +msgid "Finished dry-run migration of refs, the result can be found at '%s'\n" +msgstr "完æˆå¼•用移轉的測試執行,å¯ä»¥åœ¨ã€Œ%sã€æ‰¾åˆ°çµæžœ\n" + +#: refs.c +#, c-format +msgid "could not remove temporary migration directory '%s'" +msgstr "無法移除暫時性é·ç§»ç›®éŒ„「%sã€" + +#: refs.c +#, c-format +msgid "migrated refs can be found at '%s'" +msgstr "å¯ä»¥åœ¨ã€Œ%sã€æ‰¾åˆ°å·²é·ç§»çš„引用" + +#: refs/files-backend.c refs/reftable-backend.c +#, c-format +msgid "" +"cannot lock ref '%s': expected symref with target '%s': but is a regular ref" +msgstr "無法鎖定引用「%sã€ï¼šé 期是指å‘「%sã€çš„符號引用,但這個是一般引用" + #: refs/reftable-backend.c #, c-format msgid "refname is dangerous: %s" @@ -23839,7 +24202,7 @@ msgstr "å”å®šéŒ¯èª¤ï¼šé æœŸæ˜¯ã€Œ<URL> <路徑>ã€ï¼Œä½†ç¼ºå°‘空白" #: remote-curl.c #, c-format msgid "failed to download file at URL '%s'" -msgstr "ç„¡æ³•ä¸‹è¼‰ä½æ–¼ URL “%s†的檔案" +msgstr "ç„¡æ³•ä¸‹è¼‰ä½æ–¼ URL「%sã€çš„æª”案" #: remote-curl.c msgid "git-http-push failed" @@ -23878,12 +24241,12 @@ msgstr "æä¾›äº†ä¸€å€‹ä»¥ä¸Šçš„ uploadpack,使用第一個" #: remote.c #, c-format msgid "unrecognized value transfer.credentialsInUrl: '%s'" -msgstr "數值 transfer.credentialsInUrl 無法è˜åˆ¥ï¼šâ€œ%sâ€" +msgstr "數值 transfer.credentialsInUrl 無法è˜åˆ¥ï¼šã€Œ%sã€" #: remote.c #, c-format msgid "URL '%s' uses plaintext credentials" -msgstr "URL “%s†使用明文憑è‰" +msgstr "URL「%sã€ä½¿ç”¨æ˜Žæ–‡æ†‘è‰" #: remote.c #, c-format @@ -24124,7 +24487,7 @@ msgstr[0] "" #: remote.c msgid "" " (use \"git pull\" if you want to integrate the remote branch with yours)\n" -msgstr " (使用 “git pull†來將é 端分支整åˆé€²æ‚¨çš„分支)\n" +msgstr " (使用「git pullã€ä¾†å°‡é 端分支整åˆé€²æ‚¨çš„分支)\n" #: remote.c #, c-format @@ -24197,7 +24560,7 @@ msgstr "使用之å‰çš„解決方案解決 '%s'。" #: rerere.c #, c-format msgid "cannot unlink stray '%s'" -msgstr "無法刪除失散檔案 “%sâ€" +msgstr "無法刪除失散檔案「%sã€" #: rerere.c #, c-format @@ -24280,7 +24643,7 @@ msgstr "--unpacked=<packfile> å·²ä¸å—支æ´" #: revision.c #, c-format msgid "invalid option '%s' in --stdin mode" -msgstr "在 --stdin 模å¼ä¸‹ï¼Œâ€œ%s†é¸é …無效" +msgstr "在 --stdin 模å¼ä¸‹ï¼Œã€Œ%sã€é¸é …無效" #: revision.c msgid "your current branch appears to be broken" @@ -24394,7 +24757,7 @@ msgstr "åªä¸‹è¼‰æœƒç°½å‡ºçš„分支ä¸ä»‹è³‡æ–™" #: scalar.c msgid "create repository within 'src' directory" -msgstr "在 “src†目錄建立版本庫" +msgstr "在「srcã€ç›®éŒ„建立版本庫" #: scalar.c msgid "" @@ -24464,27 +24827,27 @@ msgstr "--all 或 <enlistment> 但ä¸èƒ½å‚³å…¥å…©è€…" #: scalar.c #, c-format msgid "could not remove stale scalar.repo '%s'" -msgstr "ç„¡æ³•ç§»é™¤éŽæ™‚çš„ scalar.repo “%sâ€" +msgstr "ç„¡æ³•ç§»é™¤éŽæ™‚çš„ scalar.repo「%sã€" #: scalar.c #, c-format msgid "removed stale scalar.repo '%s'" -msgstr "å·²ç§»é™¤éŽæ™‚çš„ scalar.repo “%sâ€" +msgstr "å·²ç§»é™¤éŽæ™‚çš„ scalar.repo「%sã€" #: scalar.c #, c-format msgid "repository at '%s' has different owner" -msgstr "使–¼ “%s†的版本庫有ä¸åŒçš„æ“æœ‰è€…" +msgstr "使–¼ã€Œ%sã€çš„版本庫有ä¸åŒçš„æ“æœ‰è€…" #: scalar.c #, c-format msgid "repository at '%s' has a format issue" -msgstr "使–¼ “%sâ€ çš„ç‰ˆæœ¬åº«æœ‰æ ¼å¼å•題" +msgstr "使–¼ã€Œ%sã€çš„ç‰ˆæœ¬åº«æœ‰æ ¼å¼å•題" #: scalar.c #, c-format msgid "repository not found in '%s'" -msgstr "版本庫ä¸åœ¨ “%sâ€" +msgstr "版本庫ä¸åœ¨ã€Œ%sã€" #: scalar.c #, c-format @@ -25008,12 +25371,12 @@ msgstr "git %sï¼šç„¡æ³•é‡æ–°æ•´ç†ç´¢å¼•" #: sequencer.c #, c-format msgid "'%s' is not a valid label" -msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„æ¨™ç±¤" +msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆçš„æ¨™ç±¤" #: sequencer.c #, c-format msgid "'%s' is not a valid refname" -msgstr "“%sâ€ ä¸æ˜¯æœ‰æ•ˆçš„引用å稱" +msgstr "「%sã€ä¸æ˜¯æœ‰æ•ˆçš„引用å稱" #: sequencer.c #, c-format @@ -25022,8 +25385,56 @@ msgstr "update-ref 需è¦å®Œå…¨é™å®šçš„引用å稱,比如:refs/heads/%s" #: sequencer.c #, c-format +msgid "'%s' does not accept merge commits" +msgstr "「%sã€ä¸æŽ¥å—åˆä½µæäº¤" + +#. TRANSLATORS: 'pick' and 'merge -C' should not be +#. translated. +#. +#: sequencer.c +msgid "" +"'pick' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit." +msgstr "" +"ä¸èƒ½ä½¿ç”¨ã€Œpickã€é¸æ“‡ä¸€å€‹åˆä½µæäº¤ã€‚\n" +"å¦‚æžœä½ æƒ³è¦é‡æ”¾é€™å€‹åˆä½µï¼Œè«‹å°é€™å€‹æäº¤ä½¿ç”¨ã€Œmerge -Cã€ã€‚" + +#. TRANSLATORS: 'reword' and 'merge -c' should not be +#. translated. +#. +#: sequencer.c +msgid "" +"'reword' does not take a merge commit. If you wanted to\n" +"replay the merge and reword the commit message, use\n" +"'merge -c' on the commit" +msgstr "" +"「rewordã€ä¸¦ç„¡æ³•使用åˆä½µæäº¤ä½œç‚ºåƒæ•¸ã€‚\n" +"å¦‚æžœä½ å¸Œæœ›åˆä½µä¸¦æ”¹å¯«æäº¤è¨Šæ¯ï¼Œ\n" +"è«‹å°é€™å€‹æäº¤ä½¿ç”¨ã€Œmerge -cã€" + +#. TRANSLATORS: 'edit', 'merge -C' and 'break' should +#. not be translated. +#. +#: sequencer.c +msgid "" +"'edit' does not take a merge commit. If you wanted to\n" +"replay the merge, use 'merge -C' on the commit, and then\n" +"'break' to give the control back to you so that you can\n" +"do 'git commit --amend && git rebase --continue'." +msgstr "" +"「editã€ä¸¦ç„¡æ³•使用åˆä½µæäº¤ä½œç‚ºåƒæ•¸ã€‚\n" +"å¦‚æžœä½ å¸Œæœ›é‡æ”¾é€™å€‹åˆä½µï¼Œè«‹å°é€™å€‹æäº¤ä½¿ç”¨ã€Œmerge -Cã€ï¼Œ\n" +"並使用「breakã€å–回控制權,\n" +"這樣æ‰èƒ½åŸ·è¡Œã€Œgit commit --amend && git rebase --continueã€ã€‚" + +#: sequencer.c +msgid "cannot squash merge commit into another commit" +msgstr "無法將一個åˆä½µæäº¤å£“æ‰é€²å…¶ä»–æäº¤" + +#: sequencer.c +#, c-format msgid "invalid command '%.*s'" -msgstr "無效的命令 “%.*sâ€" +msgstr "無效的命令「%.*sã€" #: sequencer.c #, c-format @@ -25170,9 +25581,8 @@ msgid "cannot read HEAD" msgstr "ä¸èƒ½è®€å– HEAD" #: sequencer.c -#, c-format -msgid "unable to copy '%s' to '%s'" -msgstr "無法複製 '%s' 至 '%s'" +msgid "could not write commit message file" +msgstr "無法寫入æäº¤è¨Šæ¯æª”案" #: sequencer.c #, c-format @@ -25299,7 +25709,7 @@ msgstr "åˆä½µï¼šç„¡æ³•寫入新索引檔案" #, c-format msgid "" "another 'rebase' process appears to be running; '%s.lock' already exists" -msgstr "似乎有å¦ä¸€å€‹ “rebaseâ€ ç¨‹åºæ£åœ¨é€²è¡Œï¼›â€œ%s.lock†已經å˜åœ¨" +msgstr "似乎有å¦ä¸€å€‹ã€Œrebaseã€ç¨‹åºæ£åœ¨é€²è¡Œï¼›ã€Œ%s.lockã€å·²ç¶“å˜åœ¨" #: sequencer.c #, c-format @@ -25650,6 +26060,19 @@ msgid "failed to stat '%*s%s%s'" msgstr "å–å¾— '%*s%s%s' 狀態(stat)失敗" #: setup.c +#, c-format +msgid "" +"detected dubious ownership in repository at '%s'\n" +"%sTo add an exception for this directory, call:\n" +"\n" +"\tgit config --global --add safe.directory %s" +msgstr "" +"åœ¨ä½æ–¼ã€Œ%sã€çš„ç‰ˆæœ¬åº«åµæ¸¬åˆ°å¯ç–‘所有權\n" +"%sè‹¥è¦æ”¾è¡Œæœ¬ç›®éŒ„,請呼å«ï¼š\n" +"\n" +"\tgit config --global --add safe.directory %s" + +#: setup.c msgid "Unable to read current working directory" msgstr "ä¸èƒ½è®€å–ç›®å‰å·¥ä½œç›®éŒ„" @@ -25674,21 +26097,8 @@ msgstr "" #: setup.c #, c-format -msgid "" -"detected dubious ownership in repository at '%s'\n" -"%sTo add an exception for this directory, call:\n" -"\n" -"\tgit config --global --add safe.directory %s" -msgstr "" -"åœ¨ä½æ–¼ã€Œ%sã€çš„ç‰ˆæœ¬åº«åµæ¸¬åˆ°å¯ç–‘所有權\n" -"%sè‹¥è¦æ”¾è¡Œæœ¬ç›®éŒ„,請呼å«ï¼š\n" -"\n" -"\tgit config --global --add safe.directory %s" - -#: setup.c -#, c-format msgid "cannot use bare repository '%s' (safe.bareRepository is '%s')" -msgstr "無法使用 “%s†純版本庫(safe.bareRepository 是 “%sâ€ï¼‰" +msgstr "無法使用「%sã€ç´”版本庫(safe.bareRepository 是「%sã€ï¼‰" #: setup.c #, c-format @@ -26049,6 +26459,16 @@ msgstr "「%sã€å模組 git 目錄在「%.*sã€git 路徑ä¸" #: submodule.c #, c-format +msgid "expected '%.*s' in submodule path '%s' not to be a symbolic link" +msgstr "é æœŸã€Œ%.*sã€ï¼ˆä½æ–¼å模組路徑「%sã€ï¼‰ä¸æ˜¯è±¡å¾µå¼é€£çµ" + +#: submodule.c +#, c-format +msgid "expected submodule path '%s' not to be a symbolic link" +msgstr "é æœŸå模組路徑「%sã€ä¸æ˜¯è±¡å¾µå¼é€£çµ" + +#: submodule.c +#, c-format msgid "" "relocate_gitdir for submodule '%s' with more than one worktree not supported" msgstr "䏿”¯æ´å°æœ‰å¤šå€‹å·¥ä½œå€çš„忍¡çµ„ '%s' 執行 relocate_gitdir" @@ -26086,18 +26506,13 @@ msgstr "ls-tree 返回未知返回值 %d" #: symlinks.c #, c-format msgid "failed to lstat '%s'" -msgstr "無法 lstat “%sâ€" +msgstr "無法 lstat「%sã€" #: t/helper/test-bundle-uri.c msgid "no remote configured to get bundle URIs from" msgstr "沒有è¨å®šå¯ä»¥ç”¨ä¾†å–得套件包 URIs çš„é 端" #: t/helper/test-bundle-uri.c -#, c-format -msgid "remote '%s' has no configured URL" -msgstr "“%s†é 端未è¨å®š URL" - -#: t/helper/test-bundle-uri.c msgid "could not get the bundle-uri list" msgstr "無法å–å¾— bundle-uri 清單" @@ -27439,7 +27854,7 @@ msgstr "列舉未追蹤檔案花費 %.2f 秒。" #: wt-status.c msgid "See 'git help status' for information on how to improve this." -msgstr "è«‹åƒé–± “git help status†深入了解如何改善。" +msgstr "è«‹åƒé–±ã€Œgit help statusã€æ·±å…¥äº†è§£å¦‚何改善。" #: wt-status.c #, c-format @@ -27885,29 +28300,29 @@ msgstr "ç„¡æ³•å‚³é€ %s\n" #: git-send-email.perl #, perl-format -msgid "Dry-Sent %s\n" -msgstr "æ¸¬è©¦åŸ·è¡Œå‚³é€ %s\n" +msgid "Dry-Sent %s" +msgstr "è©¦åŸ·è¡Œå‚³é€ %s" #: git-send-email.perl #, perl-format -msgid "Sent %s\n" -msgstr "æ£å‚³é€ %s\n" +msgid "Sent %s" +msgstr "æ£å‚³é€ %s" #: git-send-email.perl -msgid "Dry-OK. Log says:\n" -msgstr "測試執行æˆåŠŸã€‚æ—¥èªŒèªªï¼š\n" +msgid "Dry-OK. Log says:" +msgstr "試執行æˆåŠŸã€‚æ—¥èªŒèªªï¼š" #: git-send-email.perl -msgid "OK. Log says:\n" -msgstr "OK。日誌說:\n" +msgid "OK. Log says:" +msgstr "OK。日誌說:" #: git-send-email.perl msgid "Result: " msgstr "çµæžœï¼š " #: git-send-email.perl -msgid "Result: OK\n" -msgstr "çµæžœï¼šOK\n" +msgid "Result: OK" +msgstr "çµæžœï¼šOK" #: git-send-email.perl #, perl-format @@ -27942,7 +28357,7 @@ msgstr "(%s) ä¸èƒ½åŸ·è¡Œ '%s'" #: git-send-email.perl #, perl-format msgid "(%s) Malformed output from '%s'" -msgstr "(%s) 從 “%sâ€ è®€åˆ°æ ¼å¼éŒ¯èª¤çš„輸出" +msgstr "(%s) 從「%sã€è®€åˆ°æ ¼å¼éŒ¯èª¤çš„輸出" #: git-send-email.perl #, perl-format @@ -27998,6 +28413,34 @@ msgstr "ç•¥éŽ %s å«å‚™ä»½å¾Œç¶´ '%s'。\n" msgid "Do you really want to send %s? [y|N]: " msgstr "您真的è¦å‚³é€ %s?[y|N]: " +#~ msgid "" +#~ "the add.interactive.useBuiltin setting has been removed!\n" +#~ "See its entry in 'git help config' for details." +#~ msgstr "" +#~ "add.interactive.useBuiltin è¨å®šå·²è¢«ç§»é™¤ï¼\n" +#~ "深入了解請åƒé–± “git help config†ä¸çš„å°æ‡‰æ¢ç›®ã€‚" + +#~ msgid "git archive: Remote with no URL" +#~ msgstr "git archive: 未æä¾›é 端 URL" + +#~ msgid "only one action at a time" +#~ msgstr "一次åªèƒ½æœ‰ä¸€å€‹å‹•作" + +#~ msgid "use [RFC PATCH] instead of [PATCH]" +#~ msgstr "使用 [RFC PATCH] 代替 [PATCH]" + +#, c-format +#~ msgid "no URLs configured for remote '%s'" +#~ msgstr "沒有給é 端版本庫 '%s' è¨å®š URL" + +#, c-format +#~ msgid "unable to copy '%s' to '%s'" +#~ msgstr "無法複製 '%s' 至 '%s'" + +#, c-format +#~ msgid "remote '%s' has no configured URL" +#~ msgstr "“%s†é 端未è¨å®š URL" + #, c-format #~ msgid "truncating .rej filename to %.*s.rej" #~ msgstr "æ£åœ¨å°‡ .rej 檔案å稱截çŸç‚º %.*s.rej" @@ -28045,9 +28488,6 @@ msgstr "您真的è¦å‚³é€ %s?[y|N]: " #~ msgid "core.commentChar should only be one ASCII character" #~ msgstr "core.commentChar 應該是一個 ASCII å—å…ƒ" -#~ msgid "-x and -X cannot be used together" -#~ msgstr "-x å’Œ -X ä¸èƒ½åŒæ™‚使用" - #~ msgid "" #~ "--bundle-uri is incompatible with --depth, --shallow-since, and --shallow-" #~ "exclude" @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "commit.h" @@ -1325,7 +1327,7 @@ int format_set_trailers_options(struct process_trailer_options *opts, static size_t parse_describe_args(const char *start, struct strvec *args) { struct { - char *name; + const char *name; enum { DESCRIBE_ARG_BOOL, DESCRIBE_ARG_INTEGER, @@ -1584,8 +1586,8 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ case 'D': { const struct decoration_options opts = { - .prefix = "", - .suffix = "" + .prefix = (char *) "", + .suffix = (char *) "", }; format_decorations(sb, commit, c->auto_color, &opts); diff --git a/progress.c b/progress.c index c83cb60bf1..0d44c18edc 100644 --- a/progress.c +++ b/progress.c @@ -9,6 +9,8 @@ */ #define GIT_TEST_PROGRESS_ONLY +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "pager.h" #include "progress.h" diff --git a/promisor-remote.c b/promisor-remote.c index 2ca7c2ae48..317e1b127f 100644 --- a/promisor-remote.c +++ b/promisor-remote.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "hex.h" diff --git a/protocol-caps.c b/protocol-caps.c index 75f4cbb0a7..855f279c2f 100644 --- a/protocol-caps.c +++ b/protocol-caps.c @@ -3,10 +3,11 @@ #include "gettext.h" #include "hex.h" #include "pkt-line.h" -#include "hash-ll.h" +#include "hash.h" #include "hex.h" #include "object.h" #include "object-store-ll.h" +#include "repository.h" #include "string-list.h" #include "strbuf.h" @@ -52,7 +53,7 @@ static void send_info(struct repository *r, struct packet_writer *writer, struct object_id oid; unsigned long object_size; - if (get_oid_hex(oid_str, &oid) < 0) { + if (get_oid_hex_algop(oid_str, &oid, r->hash_algo) < 0) { packet_writer_error( writer, "object-info: protocol error, expected to get oid, not '%s'", diff --git a/pseudo-merge.c b/pseudo-merge.c new file mode 100644 index 0000000000..f0fde13c47 --- /dev/null +++ b/pseudo-merge.c @@ -0,0 +1,759 @@ +#define USE_THE_REPOSITORY_VARIABLE + +#include "git-compat-util.h" +#include "pseudo-merge.h" +#include "date.h" +#include "oid-array.h" +#include "strbuf.h" +#include "config.h" +#include "string-list.h" +#include "refs.h" +#include "pack-bitmap.h" +#include "commit.h" +#include "alloc.h" +#include "progress.h" +#include "hex.h" + +#define DEFAULT_PSEUDO_MERGE_DECAY 1.0 +#define DEFAULT_PSEUDO_MERGE_MAX_MERGES 64 +#define DEFAULT_PSEUDO_MERGE_SAMPLE_RATE 1 +#define DEFAULT_PSEUDO_MERGE_THRESHOLD approxidate("1.week.ago") +#define DEFAULT_PSEUDO_MERGE_STABLE_THRESHOLD approxidate("1.month.ago") +#define DEFAULT_PSEUDO_MERGE_STABLE_SIZE 512 + +static double gitexp(double base, int exp) +{ + double result = 1; + while (1) { + if (exp % 2) + result *= base; + exp >>= 1; + if (!exp) + break; + base *= base; + } + return result; +} + +static uint32_t pseudo_merge_group_size(const struct pseudo_merge_group *group, + const struct pseudo_merge_matches *matches, + uint32_t i) +{ + double C = 0.0f; + uint32_t n; + + /* + * The size of pseudo-merge groups decays according to a power series, + * which looks like: + * + * f(n) = C * n^-k + * + * , where 'n' is the n-th pseudo-merge group, 'f(n)' is its size, 'k' + * is the decay rate, and 'C' is a scaling value. + * + * The value of C depends on the number of groups, decay rate, and total + * number of commits. It is computed such that if there are M and N + * total groups and commits, respectively, that: + * + * N = f(0) + f(1) + ... f(M-1) + * + * Rearranging to isolate C, we get: + * + * N = \sum_{n=1}^M C / n^k + * + * N / C = \sum_{n=1}^M n^-k + * + * C = N / \sum_{n=1}^M n^-k + * + * For example, if we have a decay rate of 'k' being equal to 1.5, 'N' + * total commits equal to 10,000, and 'M' being equal to 6 groups, then + * the (rounded) group sizes are: + * + * { 5469, 1934, 1053, 684, 489, 372 } + * + * increasing the number of total groups, say to 10, scales the group + * sizes appropriately: + * + * { 5012, 1772, 964, 626, 448, 341, 271, 221, 186, 158 } + */ + for (n = 0; n < group->max_merges; n++) + C += 1.0 / gitexp(n + 1, group->decay); + C = matches->unstable_nr / C; + + return (uint32_t)((C / gitexp(i + 1, group->decay)) + 0.5); +} + +static void pseudo_merge_group_init(struct pseudo_merge_group *group) +{ + memset(group, 0, sizeof(struct pseudo_merge_group)); + + strmap_init_with_options(&group->matches, NULL, 0); + + group->decay = DEFAULT_PSEUDO_MERGE_DECAY; + group->max_merges = DEFAULT_PSEUDO_MERGE_MAX_MERGES; + group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE; + group->threshold = DEFAULT_PSEUDO_MERGE_THRESHOLD; + group->stable_threshold = DEFAULT_PSEUDO_MERGE_STABLE_THRESHOLD; + group->stable_size = DEFAULT_PSEUDO_MERGE_STABLE_SIZE; +} + +static int pseudo_merge_config(const char *var, const char *value, + const struct config_context *ctx, + void *cb_data) +{ + struct string_list *list = cb_data; + struct string_list_item *item; + struct pseudo_merge_group *group; + struct strbuf buf = STRBUF_INIT; + const char *sub, *key; + size_t sub_len; + int ret = 0; + + if (parse_config_key(var, "bitmappseudomerge", &sub, &sub_len, &key)) + goto done; + + if (!sub_len) + goto done; + + strbuf_add(&buf, sub, sub_len); + + item = string_list_lookup(list, buf.buf); + if (!item) { + item = string_list_insert(list, buf.buf); + + item->util = xmalloc(sizeof(struct pseudo_merge_group)); + pseudo_merge_group_init(item->util); + } + + group = item->util; + + if (!strcmp(key, "pattern")) { + struct strbuf re = STRBUF_INIT; + + free(group->pattern); + if (*value != '^') + strbuf_addch(&re, '^'); + strbuf_addstr(&re, value); + + group->pattern = xcalloc(1, sizeof(regex_t)); + if (regcomp(group->pattern, re.buf, REG_EXTENDED)) + die(_("failed to load pseudo-merge regex for %s: '%s'"), + sub, re.buf); + + strbuf_release(&re); + } else if (!strcmp(key, "decay")) { + group->decay = git_config_double(var, value, ctx->kvi); + if (group->decay < 0) { + warning(_("%s must be non-negative, using default"), var); + group->decay = DEFAULT_PSEUDO_MERGE_DECAY; + } + } else if (!strcmp(key, "samplerate")) { + group->sample_rate = git_config_double(var, value, ctx->kvi); + if (!(0 <= group->sample_rate && group->sample_rate <= 1)) { + warning(_("%s must be between 0 and 1, using default"), var); + group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE; + } + } else if (!strcmp(key, "threshold")) { + if (git_config_expiry_date(&group->threshold, var, value)) { + ret = -1; + goto done; + } + } else if (!strcmp(key, "maxmerges")) { + group->max_merges = git_config_int(var, value, ctx->kvi); + if (group->max_merges < 0) { + warning(_("%s must be non-negative, using default"), var); + group->max_merges = DEFAULT_PSEUDO_MERGE_MAX_MERGES; + } + } else if (!strcmp(key, "stablethreshold")) { + if (git_config_expiry_date(&group->stable_threshold, var, value)) { + ret = -1; + goto done; + } + } else if (!strcmp(key, "stablesize")) { + group->stable_size = git_config_int(var, value, ctx->kvi); + if (group->stable_size <= 0) { + warning(_("%s must be positive, using default"), var); + group->stable_size = DEFAULT_PSEUDO_MERGE_STABLE_SIZE; + } + } + +done: + strbuf_release(&buf); + + return ret; +} + +void load_pseudo_merges_from_config(struct string_list *list) +{ + struct string_list_item *item; + + git_config(pseudo_merge_config, list); + + for_each_string_list_item(item, list) { + struct pseudo_merge_group *group = item->util; + if (!group->pattern) + die(_("pseudo-merge group '%s' missing required pattern"), + item->string); + if (group->threshold < group->stable_threshold) + die(_("pseudo-merge group '%s' has unstable threshold " + "before stable one"), item->string); + } +} + +static int find_pseudo_merge_group_for_ref(const char *refname, + const struct object_id *oid, + int flags UNUSED, + void *_data) +{ + struct bitmap_writer *writer = _data; + struct object_id peeled; + struct commit *c; + uint32_t i; + int has_bitmap; + + if (!peel_iterated_oid(the_repository, oid, &peeled)) + oid = &peeled; + + c = lookup_commit(the_repository, oid); + if (!c) + return 0; + + has_bitmap = bitmap_writer_has_bitmapped_object_id(writer, oid); + + for (i = 0; i < writer->pseudo_merge_groups.nr; i++) { + struct pseudo_merge_group *group; + struct pseudo_merge_matches *matches; + struct strbuf group_name = STRBUF_INIT; + regmatch_t captures[16]; + size_t j; + + group = writer->pseudo_merge_groups.items[i].util; + if (regexec(group->pattern, refname, ARRAY_SIZE(captures), + captures, 0)) + continue; + + if (captures[ARRAY_SIZE(captures) - 1].rm_so != -1) + warning(_("pseudo-merge regex from config has too many capture " + "groups (max=%"PRIuMAX")"), + (uintmax_t)ARRAY_SIZE(captures) - 2); + + for (j = !!group->pattern->re_nsub; j < ARRAY_SIZE(captures); j++) { + regmatch_t *match = &captures[j]; + if (match->rm_so == -1) + continue; + + if (group_name.len) + strbuf_addch(&group_name, '-'); + + strbuf_add(&group_name, refname + match->rm_so, + match->rm_eo - match->rm_so); + } + + matches = strmap_get(&group->matches, group_name.buf); + if (!matches) { + matches = xcalloc(1, sizeof(*matches)); + strmap_put(&group->matches, strbuf_detach(&group_name, NULL), + matches); + } + + if (c->date <= group->stable_threshold) { + ALLOC_GROW(matches->stable, matches->stable_nr + 1, + matches->stable_alloc); + matches->stable[matches->stable_nr++] = c; + } else if (c->date <= group->threshold && !has_bitmap) { + ALLOC_GROW(matches->unstable, matches->unstable_nr + 1, + matches->unstable_alloc); + matches->unstable[matches->unstable_nr++] = c; + } + + strbuf_release(&group_name); + } + + return 0; +} + +static struct commit *push_pseudo_merge(struct pseudo_merge_group *group) +{ + struct commit *merge; + + ALLOC_GROW(group->merges, group->merges_nr + 1, group->merges_alloc); + + merge = alloc_commit_node(the_repository); + merge->object.parsed = 1; + merge->object.flags |= BITMAP_PSEUDO_MERGE; + + group->merges[group->merges_nr++] = merge; + + return merge; +} + +static struct pseudo_merge_commit_idx *pseudo_merge_idx(kh_oid_map_t *pseudo_merge_commits, + const struct object_id *oid) + +{ + struct pseudo_merge_commit_idx *pmc; + int hash_ret; + khiter_t hash_pos = kh_put_oid_map(pseudo_merge_commits, *oid, + &hash_ret); + + if (hash_ret) { + CALLOC_ARRAY(pmc, 1); + kh_value(pseudo_merge_commits, hash_pos) = pmc; + } else { + pmc = kh_value(pseudo_merge_commits, hash_pos); + } + + return pmc; +} + +#define MIN_PSEUDO_MERGE_SIZE 8 + +static void select_pseudo_merges_1(struct bitmap_writer *writer, + struct pseudo_merge_group *group, + struct pseudo_merge_matches *matches) +{ + uint32_t i, j; + uint32_t stable_merges_nr; + + if (!matches->stable_nr && !matches->unstable_nr) + return; /* all tips in this group already have bitmaps */ + + stable_merges_nr = matches->stable_nr / group->stable_size; + if (matches->stable_nr % group->stable_size) + stable_merges_nr++; + + /* make stable_merges_nr pseudo merges for stable commits */ + for (i = 0, j = 0; i < stable_merges_nr; i++) { + struct commit *merge; + struct commit_list **p; + + merge = push_pseudo_merge(group); + p = &merge->parents; + + /* + * For each pseudo-merge created above, add parents to the + * allocated commit node from the stable set of commits + * (un-bitmapped, newer than the stable threshold). + */ + do { + struct commit *c; + struct pseudo_merge_commit_idx *pmc; + + if (j >= matches->stable_nr) + break; + + c = matches->stable[j++]; + /* + * Here and below, make sure that we keep our mapping of + * commits -> pseudo-merge(s) which include the key'd + * commit up-to-date. + */ + pmc = pseudo_merge_idx(writer->pseudo_merge_commits, + &c->object.oid); + + ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc); + + pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr; + p = commit_list_append(c, p); + } while (j % group->stable_size); + + bitmap_writer_push_commit(writer, merge, 1); + writer->pseudo_merges_nr++; + } + + /* make up to group->max_merges pseudo merges for unstable commits */ + for (i = 0, j = 0; i < group->max_merges; i++) { + struct commit *merge; + struct commit_list **p; + uint32_t size, end; + + merge = push_pseudo_merge(group); + p = &merge->parents; + + size = pseudo_merge_group_size(group, matches, i); + end = size < MIN_PSEUDO_MERGE_SIZE ? matches->unstable_nr : j + size; + + /* + * For each pseudo-merge commit created above, add parents to + * the allocated commit node from the unstable set of commits + * (newer than the stable threshold). + * + * Account for the sample rate, since not every candidate from + * the set of stable commits will be included as a pseudo-merge + * parent. + */ + for (; j < end && j < matches->unstable_nr; j++) { + struct commit *c = matches->unstable[j]; + struct pseudo_merge_commit_idx *pmc; + + if (j % (uint32_t)(1.0 / group->sample_rate)) + continue; + + pmc = pseudo_merge_idx(writer->pseudo_merge_commits, + &c->object.oid); + + ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc); + + pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr; + p = commit_list_append(c, p); + } + + bitmap_writer_push_commit(writer, merge, 1); + writer->pseudo_merges_nr++; + if (end >= matches->unstable_nr) + break; + } +} + +static int commit_date_cmp(const void *va, const void *vb) +{ + timestamp_t a = (*(const struct commit **)va)->date; + timestamp_t b = (*(const struct commit **)vb)->date; + + if (a < b) + return -1; + else if (a > b) + return 1; + return 0; +} + +static void sort_pseudo_merge_matches(struct pseudo_merge_matches *matches) +{ + QSORT(matches->stable, matches->stable_nr, commit_date_cmp); + QSORT(matches->unstable, matches->unstable_nr, commit_date_cmp); +} + +void select_pseudo_merges(struct bitmap_writer *writer, + struct commit **commits, size_t commits_nr) +{ + struct progress *progress = NULL; + uint32_t i; + + if (!writer->pseudo_merge_groups.nr) + return; + + if (writer->show_progress) + progress = start_progress("Selecting pseudo-merge commits", + writer->pseudo_merge_groups.nr); + + refs_for_each_ref(get_main_ref_store(the_repository), + find_pseudo_merge_group_for_ref, writer); + + for (i = 0; i < writer->pseudo_merge_groups.nr; i++) { + struct pseudo_merge_group *group; + struct hashmap_iter iter; + struct strmap_entry *e; + + group = writer->pseudo_merge_groups.items[i].util; + strmap_for_each_entry(&group->matches, &iter, e) { + struct pseudo_merge_matches *matches = e->value; + + sort_pseudo_merge_matches(matches); + + select_pseudo_merges_1(writer, group, matches); + } + + display_progress(progress, i + 1); + } + + stop_progress(&progress); +} + +void free_pseudo_merge_map(struct pseudo_merge_map *pm) +{ + uint32_t i; + for (i = 0; i < pm->nr; i++) { + ewah_pool_free(pm->v[i].commits); + ewah_pool_free(pm->v[i].bitmap); + } + free(pm->v); +} + +struct pseudo_merge_commit_ext { + uint32_t nr; + const unsigned char *ptr; +}; + +static int pseudo_merge_ext_at(const struct pseudo_merge_map *pm, + struct pseudo_merge_commit_ext *ext, size_t at) +{ + if (at >= pm->map_size) + return error(_("extended pseudo-merge read out-of-bounds " + "(%"PRIuMAX" >= %"PRIuMAX")"), + (uintmax_t)at, (uintmax_t)pm->map_size); + if (at + 4 >= pm->map_size) + return error(_("extended pseudo-merge entry is too short " + "(%"PRIuMAX" >= %"PRIuMAX")"), + (uintmax_t)(at + 4), (uintmax_t)pm->map_size); + + ext->nr = get_be32(pm->map + at); + ext->ptr = pm->map + at + sizeof(uint32_t); + + return 0; +} + +struct ewah_bitmap *pseudo_merge_bitmap(const struct pseudo_merge_map *pm, + struct pseudo_merge *merge) +{ + if (!merge->loaded_commits) + BUG("cannot use unloaded pseudo-merge bitmap"); + + if (!merge->loaded_bitmap) { + size_t at = merge->bitmap_at; + + merge->bitmap = read_bitmap(pm->map, pm->map_size, &at); + merge->loaded_bitmap = 1; + } + + return merge->bitmap; +} + +struct pseudo_merge *use_pseudo_merge(const struct pseudo_merge_map *pm, + struct pseudo_merge *merge) +{ + if (!merge->loaded_commits) { + size_t pos = merge->at; + + merge->commits = read_bitmap(pm->map, pm->map_size, &pos); + merge->bitmap_at = pos; + merge->loaded_commits = 1; + } + return merge; +} + +static struct pseudo_merge *pseudo_merge_at(const struct pseudo_merge_map *pm, + struct object_id *oid, + size_t want) +{ + size_t lo = 0; + size_t hi = pm->nr; + + while (lo < hi) { + size_t mi = lo + (hi - lo) / 2; + size_t got = pm->v[mi].at; + + if (got == want) + return use_pseudo_merge(pm, &pm->v[mi]); + else if (got < want) + hi = mi; + else + lo = mi + 1; + } + + warning(_("could not find pseudo-merge for commit %s at offset %"PRIuMAX), + oid_to_hex(oid), (uintmax_t)want); + + return NULL; +} + +struct pseudo_merge_commit { + uint32_t commit_pos; + uint64_t pseudo_merge_ofs; +}; + +#define PSEUDO_MERGE_COMMIT_RAWSZ (sizeof(uint32_t)+sizeof(uint64_t)) + +static void read_pseudo_merge_commit_at(struct pseudo_merge_commit *merge, + const unsigned char *at) +{ + merge->commit_pos = get_be32(at); + merge->pseudo_merge_ofs = get_be64(at + sizeof(uint32_t)); +} + +static int nth_pseudo_merge_ext(const struct pseudo_merge_map *pm, + struct pseudo_merge_commit_ext *ext, + struct pseudo_merge_commit *merge, + uint32_t n) +{ + size_t ofs; + + if (n >= ext->nr) + return error(_("extended pseudo-merge lookup out-of-bounds " + "(%"PRIu32" >= %"PRIu32")"), n, ext->nr); + + ofs = get_be64(ext->ptr + st_mult(n, sizeof(uint64_t))); + if (ofs >= pm->map_size) + return error(_("out-of-bounds read: (%"PRIuMAX" >= %"PRIuMAX")"), + (uintmax_t)ofs, (uintmax_t)pm->map_size); + + read_pseudo_merge_commit_at(merge, pm->map + ofs); + + return 0; +} + +static unsigned apply_pseudo_merge(const struct pseudo_merge_map *pm, + struct pseudo_merge *merge, + struct bitmap *result, + struct bitmap *roots) +{ + if (merge->satisfied) + return 0; + + if (!ewah_bitmap_is_subset(merge->commits, roots ? roots : result)) + return 0; + + bitmap_or_ewah(result, pseudo_merge_bitmap(pm, merge)); + if (roots) + bitmap_or_ewah(roots, pseudo_merge_bitmap(pm, merge)); + merge->satisfied = 1; + + return 1; +} + +static int pseudo_merge_commit_cmp(const void *va, const void *vb) +{ + struct pseudo_merge_commit merge; + uint32_t key = *(uint32_t*)va; + + read_pseudo_merge_commit_at(&merge, vb); + + if (key < merge.commit_pos) + return -1; + if (key > merge.commit_pos) + return 1; + return 0; +} + +static struct pseudo_merge_commit *find_pseudo_merge(const struct pseudo_merge_map *pm, + uint32_t pos) +{ + if (!pm->commits_nr) + return NULL; + + return bsearch(&pos, pm->commits, pm->commits_nr, + PSEUDO_MERGE_COMMIT_RAWSZ, pseudo_merge_commit_cmp); +} + +int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm, + struct bitmap *result, + struct commit *commit, uint32_t commit_pos) +{ + struct pseudo_merge *merge; + struct pseudo_merge_commit *merge_commit; + int ret = 0; + + merge_commit = find_pseudo_merge(pm, commit_pos); + if (!merge_commit) + return 0; + + if (merge_commit->pseudo_merge_ofs & ((uint64_t)1<<63)) { + struct pseudo_merge_commit_ext ext = { 0 }; + off_t ofs = merge_commit->pseudo_merge_ofs & ~((uint64_t)1<<63); + uint32_t i; + + if (pseudo_merge_ext_at(pm, &ext, ofs) < -1) { + warning(_("could not read extended pseudo-merge table " + "for commit %s"), + oid_to_hex(&commit->object.oid)); + return ret; + } + + for (i = 0; i < ext.nr; i++) { + if (nth_pseudo_merge_ext(pm, &ext, merge_commit, i) < 0) + return ret; + + merge = pseudo_merge_at(pm, &commit->object.oid, + merge_commit->pseudo_merge_ofs); + + if (!merge) + return ret; + + if (apply_pseudo_merge(pm, merge, result, NULL)) + ret++; + } + } else { + merge = pseudo_merge_at(pm, &commit->object.oid, + merge_commit->pseudo_merge_ofs); + + if (!merge) + return ret; + + if (apply_pseudo_merge(pm, merge, result, NULL)) + ret++; + } + + if (ret) + cascade_pseudo_merges(pm, result, NULL); + + return ret; +} + +int cascade_pseudo_merges(const struct pseudo_merge_map *pm, + struct bitmap *result, + struct bitmap *roots) +{ + unsigned any_satisfied; + int ret = 0; + + do { + struct pseudo_merge *merge; + uint32_t i; + + any_satisfied = 0; + + for (i = 0; i < pm->nr; i++) { + merge = use_pseudo_merge(pm, &pm->v[i]); + if (apply_pseudo_merge(pm, merge, result, roots)) { + any_satisfied |= 1; + ret++; + } + } + } while (any_satisfied); + + return ret; +} + +struct pseudo_merge *pseudo_merge_for_parents(const struct pseudo_merge_map *pm, + struct bitmap *parents) +{ + struct pseudo_merge *match = NULL; + size_t i; + + if (!pm->nr) + return NULL; + + /* + * NOTE: this loop is quadratic in the worst-case (where no + * matching pseudo-merge bitmaps are found), but in practice + * this is OK for a few reasons: + * + * - Rejecting pseudo-merge bitmaps that do not match the + * given commit is done quickly (i.e. `bitmap_equals_ewah()` + * returns early when we know the two bitmaps aren't equal. + * + * - Already matched pseudo-merge bitmaps (which we track with + * the `->satisfied` bit here) are skipped as potential + * candidates. + * + * - The number of pseudo-merges should be small (in the + * hundreds for most repositories). + * + * If in the future this semi-quadratic behavior does become a + * problem, another approach would be to keep track of which + * pseudo-merges are still "viable" after enumerating the + * pseudo-merge commit's parents: + * + * - A pseudo-merge bitmap becomes non-viable when the bit(s) + * corresponding to one or more parent(s) of the given + * commit are not set in a candidate pseudo-merge's commits + * bitmap. + * + * - After processing all bits, enumerate the remaining set of + * viable pseudo-merge bitmaps, and check that their + * popcount() matches the number of parents in the given + * commit. + */ + for (i = 0; i < pm->nr; i++) { + struct pseudo_merge *candidate = use_pseudo_merge(pm, &pm->v[i]); + if (!candidate || candidate->satisfied) + continue; + if (!bitmap_equals_ewah(parents, candidate->commits)) + continue; + + match = candidate; + match->satisfied = 1; + break; + } + + return match; +} diff --git a/pseudo-merge.h b/pseudo-merge.h new file mode 100644 index 0000000000..2aca01d056 --- /dev/null +++ b/pseudo-merge.h @@ -0,0 +1,216 @@ +#ifndef PSEUDO_MERGE_H +#define PSEUDO_MERGE_H + +#include "git-compat-util.h" +#include "strmap.h" +#include "khash.h" +#include "ewah/ewok.h" + +struct commit; +struct string_list; +struct bitmap_index; +struct bitmap_writer; + +/* + * A pseudo-merge group tracks the set of non-bitmapped reference tips + * that match the given pattern. + * + * Within those matches, they are further segmented by separating + * consecutive capture groups with '-' dash character capture groups + * with '-' dash characters. + * + * Those groups are then ordered by committer date and partitioned + * into individual pseudo-merge(s) according to the decay, max_merges, + * sample_rate, and threshold parameters. + */ +struct pseudo_merge_group { + regex_t *pattern; + + /* capture group(s) -> struct pseudo_merge_matches */ + struct strmap matches; + + /* + * The individual pseudo-merge(s) that are generated from the + * above array of matches, partitioned according to the below + * parameters. + */ + struct commit **merges; + size_t merges_nr; + size_t merges_alloc; + + /* + * Pseudo-merge grouping parameters. See git-config(1) for + * more information. + */ + double decay; + int max_merges; + double sample_rate; + int stable_size; + timestamp_t threshold; + timestamp_t stable_threshold; +}; + +struct pseudo_merge_matches { + struct commit **stable; + struct commit **unstable; + size_t stable_nr, stable_alloc; + size_t unstable_nr, unstable_alloc; +}; + +/* + * Read the repository's configuration: + * + * - bitmapPseudoMerge.<name>.pattern + * - bitmapPseudoMerge.<name>.decay + * - bitmapPseudoMerge.<name>.sampleRate + * - bitmapPseudoMerge.<name>.threshold + * - bitmapPseudoMerge.<name>.maxMerges + * - bitmapPseudoMerge.<name>.stableThreshold + * - bitmapPseudoMerge.<name>.stableSize + * + * and populates the given `list` with pseudo-merge groups. String + * entry keys are the pseudo-merge group names, and the values are + * pointers to the pseudo_merge_group structure itself. + */ +void load_pseudo_merges_from_config(struct string_list *list); + +/* + * A pseudo-merge commit index (pseudo_merge_commit_idx) maps a + * particular (non-pseudo-merge) commit to the list of pseudo-merge(s) + * it appears in. + */ +struct pseudo_merge_commit_idx { + uint32_t *pseudo_merge; + size_t nr, alloc; +}; + +/* + * Selects pseudo-merges from a list of commits, populating the given + * string_list of pseudo-merge groups. + * + * Populates the pseudo_merge_commits map with a commit_idx + * corresponding to each commit in the list. Counts the total number + * of pseudo-merges generated. + * + * Optionally shows a progress meter. + */ +void select_pseudo_merges(struct bitmap_writer *writer, + struct commit **commits, size_t commits_nr); + +/* + * Represents a serialized view of a file containing pseudo-merge(s) + * (see Documentation/technical/bitmap-format.txt for a specification + * of the format). + */ +struct pseudo_merge_map { + /* + * An array of pseudo-merge(s), lazily loaded from the .bitmap + * file. + */ + struct pseudo_merge *v; + size_t nr; + size_t commits_nr; + + /* + * Pointers into a memory-mapped view of the .bitmap file: + * + * - map: the beginning of the .bitmap file + * - commits: the beginning of the pseudo-merge commit index + * - map_size: the size of the .bitmap file + */ + const unsigned char *map; + const unsigned char *commits; + + size_t map_size; +}; + +/* + * An individual pseudo-merge, storing a pair of lazily-loaded + * bitmaps: + * + * - commits: the set of commit(s) that are part of the pseudo-merge + * - bitmap: the set of object(s) reachable from the above set of + * commits. + * + * The `at` and `bitmap_at` fields are used to store the locations of + * each of the above bitmaps in the .bitmap file. + */ +struct pseudo_merge { + struct ewah_bitmap *commits; + struct ewah_bitmap *bitmap; + + off_t at; + off_t bitmap_at; + + /* + * `satisfied` indicates whether the given pseudo-merge has been + * used. + * + * `loaded_commits` and `loaded_bitmap` indicate whether the + * respective bitmaps have been loaded and read from the + * .bitmap file. + */ + unsigned satisfied : 1, + loaded_commits : 1, + loaded_bitmap : 1; +}; + +/* + * Frees the given pseudo-merge map, releasing any memory held by (a) + * parsed EWAH bitmaps, or (b) the array of pseudo-merges itself. Does + * not free the memory-mapped view of the .bitmap file. + */ +void free_pseudo_merge_map(struct pseudo_merge_map *pm); + +/* + * Loads the bitmap corresponding to the given pseudo-merge from the + * map, if it has not already been loaded. + */ +struct ewah_bitmap *pseudo_merge_bitmap(const struct pseudo_merge_map *pm, + struct pseudo_merge *merge); + +/* + * Loads the pseudo-merge and its commits bitmap from the given + * pseudo-merge map, if it has not already been loaded. + */ +struct pseudo_merge *use_pseudo_merge(const struct pseudo_merge_map *pm, + struct pseudo_merge *merge); + +/* + * Applies pseudo-merge(s) containing the given commit to the bitmap + * "result". + * + * If any pseudo-merge(s) were satisfied, returns the number + * satisfied, otherwise returns 0. If any were satisfied, the + * remaining unsatisfied pseudo-merges are cascaded (see below). + */ +int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm, + struct bitmap *result, + struct commit *commit, uint32_t commit_pos); + +/* + * Applies pseudo-merge(s) which are satisfied according to the + * current bitmap in result (or roots, see below). If any + * pseudo-merges were satisfied, repeat the process over unsatisfied + * pseudo-merge commits until no more pseudo-merges are satisfied. + * + * Result is the bitmap to which the pseudo-merge(s) are applied. + * Roots (if given) is a bitmap of the traversal tip(s) for either + * side of a reachability traversal. + * + * Roots may given instead of a populated results bitmap at the + * beginning of a traversal on either side where the reachability + * closure over tips is not yet known. + */ +int cascade_pseudo_merges(const struct pseudo_merge_map *pm, + struct bitmap *result, + struct bitmap *roots); + +/* + * Returns a pseudo-merge which contains the exact set of commits + * listed in the "parents" bitamp, or NULL if none could be found. + */ +struct pseudo_merge *pseudo_merge_for_parents(const struct pseudo_merge_map *pm, + struct bitmap *parents); + +#endif diff --git a/range-diff.c b/range-diff.c index c45b6d849c..5f01605550 100644 --- a/range-diff.c +++ b/range-diff.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "gettext.h" diff --git a/reachable.c b/reachable.c index 1224b30008..46613a6bb6 100644 --- a/reachable.c +++ b/reachable.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "hex.h" diff --git a/read-cache-ll.h b/read-cache-ll.h index 09414afd04..e0e39607ef 100644 --- a/read-cache-ll.h +++ b/read-cache-ll.h @@ -1,7 +1,7 @@ #ifndef READ_CACHE_LL_H #define READ_CACHE_LL_H -#include "hash-ll.h" +#include "hash.h" #include "hashmap.h" #include "statinfo.h" diff --git a/read-cache.c b/read-cache.c index 447109aa76..1f67bb755b 100644 --- a/read-cache.c +++ b/read-cache.c @@ -3,6 +3,9 @@ * * Copyright (C) Linus Torvalds, 2005 */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "bulk-checkin.h" #include "config.h" @@ -337,7 +340,7 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st) /* Racily smudged entry? */ if (!ce->ce_stat_data.sd_size) { - if (!is_empty_blob_sha1(ce->oid.hash)) + if (!is_empty_blob_oid(&ce->oid, the_repository->hash_algo)) changed |= DATA_CHANGED; } @@ -1728,14 +1731,14 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size) end = (unsigned char *)hdr + size; start = end - the_hash_algo->rawsz; - oidread(&oid, start); + oidread(&oid, start, the_repository->hash_algo); if (oideq(&oid, null_oid())) return 0; the_hash_algo->init_fn(&c); the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz); the_hash_algo->final_fn(hash, &c); - if (!hasheq(hash, start)) + if (!hasheq(hash, start, the_repository->hash_algo)) return error(_("bad index file sha1 signature")); return 0; } @@ -1876,7 +1879,8 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool, ce->ce_flags = flags & ~CE_NAMEMASK; ce->ce_namelen = len; ce->index = 0; - oidread(&ce->oid, (const unsigned char *)ondisk + offsetof(struct ondisk_cache_entry, data)); + oidread(&ce->oid, (const unsigned char *)ondisk + offsetof(struct ondisk_cache_entry, data), + the_repository->hash_algo); if (expand_name_field) { if (copy_len) @@ -2249,7 +2253,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) if (verify_hdr(hdr, mmap_size) < 0) goto unmap; - oidread(&istate->oid, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz); + oidread(&istate->oid, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz, + the_repository->hash_algo); istate->version = ntohl(hdr->hdr_version); istate->cache_nr = ntohl(hdr->hdr_entries); istate->cache_alloc = alloc_nr(istate->cache_nr); @@ -2641,7 +2646,7 @@ static void copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk, ondisk->uid = htonl(ce->ce_stat_data.sd_uid); ondisk->gid = htonl(ce->ce_stat_data.sd_gid); ondisk->size = htonl(ce->ce_stat_data.sd_size); - hashcpy(ondisk->data, ce->oid.hash); + hashcpy(ondisk->data, ce->oid.hash, the_repository->hash_algo); flags = ce->ce_flags & ~CE_NAMEMASK; flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce)); @@ -2730,7 +2735,7 @@ static int verify_index_from(const struct index_state *istate, const char *path) if (n != the_hash_algo->rawsz) goto out; - if (!hasheq(istate->oid.hash, hash)) + if (!hasheq(istate->oid.hash, hash, the_repository->hash_algo)) goto out; close(fd); @@ -2958,7 +2963,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, if (err) { free(ieot); - return err; + goto cleanup; } offset = hashfile_total(f); @@ -2987,8 +2992,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, hashwrite(f, sb.buf, sb.len); strbuf_release(&sb); free(ieot); - if (err) - return -1; + /* + * NEEDSWORK: write_index_ext_header() never returns a failure, + * and this part may want to be simplified. + */ + if (err) { + err = -1; + goto cleanup; + } } if (write_extensions & WRITE_SPLIT_INDEX_EXTENSION && @@ -3003,8 +3014,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, sb.len) < 0; hashwrite(f, sb.buf, sb.len); strbuf_release(&sb); - if (err) - return -1; + /* + * NEEDSWORK: write_link_extension() never returns a failure, + * and this part may want to be simplified. + */ + if (err) { + err = -1; + goto cleanup; + } } if (write_extensions & WRITE_CACHE_TREE_EXTENSION && !drop_cache_tree && istate->cache_tree) { @@ -3014,8 +3031,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, err = write_index_ext_header(f, eoie_c, CACHE_EXT_TREE, sb.len) < 0; hashwrite(f, sb.buf, sb.len); strbuf_release(&sb); - if (err) - return -1; + /* + * NEEDSWORK: write_index_ext_header() never returns a failure, + * and this part may want to be simplified. + */ + if (err) { + err = -1; + goto cleanup; + } } if (write_extensions & WRITE_RESOLVE_UNDO_EXTENSION && istate->resolve_undo) { @@ -3026,8 +3049,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, sb.len) < 0; hashwrite(f, sb.buf, sb.len); strbuf_release(&sb); - if (err) - return -1; + /* + * NEEDSWORK: write_index_ext_header() never returns a failure, + * and this part may want to be simplified. + */ + if (err) { + err = -1; + goto cleanup; + } } if (write_extensions & WRITE_UNTRACKED_CACHE_EXTENSION && istate->untracked) { @@ -3038,8 +3067,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, sb.len) < 0; hashwrite(f, sb.buf, sb.len); strbuf_release(&sb); - if (err) - return -1; + /* + * NEEDSWORK: write_index_ext_header() never returns a failure, + * and this part may want to be simplified. + */ + if (err) { + err = -1; + goto cleanup; + } } if (write_extensions & WRITE_FSMONITOR_EXTENSION && istate->fsmonitor_last_update) { @@ -3049,12 +3084,25 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, err = write_index_ext_header(f, eoie_c, CACHE_EXT_FSMONITOR, sb.len) < 0; hashwrite(f, sb.buf, sb.len); strbuf_release(&sb); - if (err) - return -1; + /* + * NEEDSWORK: write_index_ext_header() never returns a failure, + * and this part may want to be simplified. + */ + if (err) { + err = -1; + goto cleanup; + } } if (istate->sparse_index) { - if (write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0) - return -1; + err = write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0); + /* + * NEEDSWORK: write_index_ext_header() never returns a failure, + * and this part may want to be simplified. + */ + if (err) { + err = -1; + goto cleanup; + } } /* @@ -3070,8 +3118,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, err = write_index_ext_header(f, NULL, CACHE_EXT_ENDOFINDEXENTRIES, sb.len) < 0; hashwrite(f, sb.buf, sb.len); strbuf_release(&sb); - if (err) - return -1; + /* + * NEEDSWORK: write_index_ext_header() never returns a failure, + * and this part may want to be simplified. + */ + if (err) { + err = -1; + goto cleanup; + } } csum_fsync_flag = 0; @@ -3080,13 +3134,16 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, finalize_hashfile(f, istate->oid.hash, FSYNC_COMPONENT_INDEX, CSUM_HASH_IN_STREAM | csum_fsync_flag); + f = NULL; if (close_tempfile_gently(tempfile)) { - error(_("could not close '%s'"), get_tempfile_path(tempfile)); - return -1; + err = error(_("could not close '%s'"), get_tempfile_path(tempfile)); + goto cleanup; + } + if (stat(get_tempfile_path(tempfile), &st)) { + err = error_errno(_("could not stat '%s'"), get_tempfile_path(tempfile)); + goto cleanup; } - if (stat(get_tempfile_path(tempfile), &st)) - return -1; istate->timestamp.sec = (unsigned int)st.st_mtime; istate->timestamp.nsec = ST_MTIME_NSEC(st); trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed); @@ -3101,6 +3158,11 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, istate->cache_nr); return 0; + +cleanup: + if (f) + discard_hashfile(f); + return err; } void set_alternate_index_output(const char *name) @@ -3603,7 +3665,7 @@ static size_t read_eoie_extension(const char *mmap, size_t mmap_size) src_offset += extsize; } the_hash_algo->final_fn(hash, &c); - if (!hasheq(hash, (const unsigned char *)index)) + if (!hasheq(hash, (const unsigned char *)index, the_repository->hash_algo)) return 0; /* Validate that the extension offsets returned us back to the eoie extension. */ diff --git a/rebase-interactive.c b/rebase-interactive.c index c343e16fcd..cbeb864147 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "commit.h" #include "editor.h" @@ -101,9 +103,10 @@ void append_todo_help(int command_count, strbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_str); } -int edit_todo_list(struct repository *r, struct todo_list *todo_list, - struct todo_list *new_todo, const char *shortrevisions, - const char *shortonto, unsigned flags) +int edit_todo_list(struct repository *r, struct replay_opts *opts, + struct todo_list *todo_list, struct todo_list *new_todo, + const char *shortrevisions, const char *shortonto, + unsigned flags) { const char *todo_file = rebase_path_todo(), *todo_backup = rebase_path_todo_backup(); @@ -114,7 +117,9 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list, * it. If there is an error, we do not return, because the user * might want to fix it in the first place. */ if (!initial) - incorrect = todo_list_parse_insn_buffer(r, todo_list->buf.buf, todo_list) | + incorrect = todo_list_parse_insn_buffer(r, opts, + todo_list->buf.buf, + todo_list) | file_exists(rebase_path_dropped()); if (todo_list_write_to_file(r, todo_list, todo_file, shortrevisions, shortonto, @@ -134,13 +139,13 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list, if (initial && new_todo->buf.len == 0) return -3; - if (todo_list_parse_insn_buffer(r, new_todo->buf.buf, new_todo)) { + if (todo_list_parse_insn_buffer(r, opts, new_todo->buf.buf, new_todo)) { fprintf(stderr, _(edit_todo_list_advice)); return -4; } if (incorrect) { - if (todo_list_check_against_backup(r, new_todo)) { + if (todo_list_check_against_backup(r, opts, new_todo)) { write_file(rebase_path_dropped(), "%s", ""); return -4; } @@ -228,13 +233,15 @@ leave_check: return res; } -int todo_list_check_against_backup(struct repository *r, struct todo_list *todo_list) +int todo_list_check_against_backup(struct repository *r, + struct replay_opts *opts, + struct todo_list *todo_list) { struct todo_list backup = TODO_LIST_INIT; int res = 0; if (strbuf_read_file(&backup.buf, rebase_path_todo_backup(), 0) > 0) { - todo_list_parse_insn_buffer(r, backup.buf.buf, &backup); + todo_list_parse_insn_buffer(r, opts, backup.buf.buf, &backup); res = todo_list_check(&backup, todo_list); } diff --git a/rebase-interactive.h b/rebase-interactive.h index 7239c60f79..8e5b181b33 100644 --- a/rebase-interactive.h +++ b/rebase-interactive.h @@ -3,17 +3,20 @@ struct strbuf; struct repository; +struct replay_opts; struct todo_list; void append_todo_help(int command_count, const char *shortrevisions, const char *shortonto, struct strbuf *buf); -int edit_todo_list(struct repository *r, struct todo_list *todo_list, - struct todo_list *new_todo, const char *shortrevisions, - const char *shortonto, unsigned flags); +int edit_todo_list(struct repository *r, struct replay_opts *opts, + struct todo_list *todo_list, struct todo_list *new_todo, + const char *shortrevisions, const char *shortonto, + unsigned flags); int todo_list_check(struct todo_list *old_todo, struct todo_list *new_todo); int todo_list_check_against_backup(struct repository *r, + struct replay_opts *opts, struct todo_list *todo_list); #endif diff --git a/ref-filter.c b/ref-filter.c index f7fb0c7e0e..54880a2497 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "gettext.h" @@ -1626,6 +1628,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam timestamp = parse_timestamp(eoemail + 2, &zone, 10); if (timestamp == TIME_MAX) goto bad; + errno = 0; tz = strtol(zone, NULL, 10); if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE) goto bad; diff --git a/reflog-walk.c b/reflog-walk.c index 5f09552c5c..c7070b13b0 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "commit.h" #include "refs.h" @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "object-store-ll.h" @@ -330,7 +332,8 @@ void reflog_expiry_prepare(const char *refname, if (!cb->cmd.expire_unreachable || is_head(refname)) { cb->unreachable_expire_kind = UE_HEAD; } else { - commit = lookup_commit(the_repository, oid); + commit = lookup_commit_reference_gently(the_repository, + oid, 1); if (commit && is_null_oid(&commit->object.oid)) commit = NULL; cb->unreachable_expire_kind = commit ? UE_NORMAL : UE_ALWAYS; @@ -37,14 +37,15 @@ static const struct ref_storage_be *refs_backends[] = { [REF_STORAGE_FORMAT_REFTABLE] = &refs_be_reftable, }; -static const struct ref_storage_be *find_ref_storage_backend(unsigned int ref_storage_format) +static const struct ref_storage_be *find_ref_storage_backend( + enum ref_storage_format ref_storage_format) { if (ref_storage_format < ARRAY_SIZE(refs_backends)) return refs_backends[ref_storage_format]; return NULL; } -unsigned int ref_storage_format_by_name(const char *name) +enum ref_storage_format ref_storage_format_by_name(const char *name) { for (unsigned int i = 0; i < ARRAY_SIZE(refs_backends); i++) if (refs_backends[i] && !strcmp(refs_backends[i]->name, name)) @@ -52,7 +53,7 @@ unsigned int ref_storage_format_by_name(const char *name) return REF_STORAGE_FORMAT_UNKNOWN; } -const char *ref_storage_format_to_name(unsigned int ref_storage_format) +const char *ref_storage_format_to_name(enum ref_storage_format ref_storage_format) { const struct ref_storage_be *be = find_ref_storage_backend(ref_storage_format); if (!be) @@ -158,7 +159,7 @@ void update_ref_namespace(enum ref_namespace namespace, char *ref) { struct ref_namespace_info *info = &ref_namespace[namespace]; if (info->ref_updated) - free(info->ref); + free((char *)info->ref); info->ref = ref; info->ref_updated = 1; } @@ -913,7 +914,7 @@ int refs_delete_ref(struct ref_store *refs, const char *msg, transaction = ref_store_transaction_begin(refs, &err); if (!transaction || ref_transaction_delete(transaction, refname, old_oid, - flags, msg, &err) || + NULL, flags, msg, &err) || ref_transaction_commit(transaction, &err)) { error("%s", err.buf); ref_transaction_free(transaction); @@ -1193,6 +1194,12 @@ int ref_transaction_update(struct ref_transaction *transaction, { assert(err); + if ((flags & REF_FORCE_CREATE_REFLOG) && + (flags & REF_SKIP_CREATE_REFLOG)) { + strbuf_addstr(err, _("refusing to force and skip creation of reflog")); + return -1; + } + if (!(flags & REF_SKIP_REFNAME_VERIFICATION) && ((new_oid && !is_null_oid(new_oid)) ? check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : @@ -1231,43 +1238,57 @@ int ref_transaction_update(struct ref_transaction *transaction, int ref_transaction_create(struct ref_transaction *transaction, const char *refname, const struct object_id *new_oid, + const char *new_target, unsigned int flags, const char *msg, struct strbuf *err) { - if (!new_oid || is_null_oid(new_oid)) { - strbuf_addf(err, "'%s' has a null OID", refname); + if (new_oid && new_target) + BUG("create called with both new_oid and new_target set"); + if ((!new_oid || is_null_oid(new_oid)) && !new_target) { + strbuf_addf(err, "'%s' has neither a valid OID nor a target", refname); return 1; } return ref_transaction_update(transaction, refname, new_oid, - null_oid(), NULL, NULL, flags, + null_oid(), new_target, NULL, flags, msg, err); } int ref_transaction_delete(struct ref_transaction *transaction, const char *refname, const struct object_id *old_oid, - unsigned int flags, const char *msg, + const char *old_target, + unsigned int flags, + const char *msg, struct strbuf *err) { if (old_oid && is_null_oid(old_oid)) BUG("delete called with old_oid set to zeros"); + if (old_oid && old_target) + BUG("delete called with both old_oid and old_target set"); + if (old_target && !(flags & REF_NO_DEREF)) + BUG("delete cannot operate on symrefs with deref mode"); return ref_transaction_update(transaction, refname, null_oid(), old_oid, - NULL, NULL, flags, + NULL, old_target, flags, msg, err); } int ref_transaction_verify(struct ref_transaction *transaction, const char *refname, const struct object_id *old_oid, + const char *old_target, unsigned int flags, struct strbuf *err) { - if (!old_oid) - BUG("verify called with old_oid set to NULL"); + if (!old_target && !old_oid) + BUG("verify called with old_oid and old_target set to NULL"); + if (old_oid && old_target) + BUG("verify called with both old_oid and old_target set"); + if (old_target && !(flags & REF_NO_DEREF)) + BUG("verify cannot operate on symrefs with deref mode"); return ref_transaction_update(transaction, refname, NULL, old_oid, - NULL, NULL, + NULL, old_target, flags, NULL, err); } @@ -1731,8 +1752,8 @@ static int refs_read_special_head(struct ref_store *ref_store, goto done; } - result = parse_loose_ref_contents(content.buf, oid, referent, type, - failure_errno); + result = parse_loose_ref_contents(ref_store->repo->hash_algo, content.buf, + oid, referent, type, failure_errno); done: strbuf_release(&full_path); @@ -1815,7 +1836,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, failure_errno != ENOTDIR) return NULL; - oidclr(oid); + oidclr(oid, refs->repo->hash_algo); if (*flags & REF_BAD_NAME) *flags |= REF_ISBROKEN; return refname; @@ -1825,7 +1846,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, if (!(read_flags & REF_ISSYMREF)) { if (*flags & REF_BAD_NAME) { - oidclr(oid); + oidclr(oid, refs->repo->hash_algo); *flags |= REF_ISBROKEN; } return refname; @@ -1833,7 +1854,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, refname = sb_refname.buf; if (resolve_flags & RESOLVE_REF_NO_RECURSE) { - oidclr(oid); + oidclr(oid, refs->repo->hash_algo); return refname; } if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { @@ -1854,6 +1875,11 @@ int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *e return refs->be->create_on_disk(refs, flags, err); } +int ref_store_remove_on_disk(struct ref_store *refs, struct strbuf *err) +{ + return refs->be->remove_on_disk(refs, err); +} + int repo_resolve_gitlink_ref(struct repository *r, const char *submodule, const char *refname, struct object_id *oid) @@ -1890,16 +1916,17 @@ static struct ref_store *lookup_ref_store_map(struct strmap *map, /* * Create, record, and return a ref_store instance for the specified - * gitdir. + * gitdir using the given ref storage format. */ static struct ref_store *ref_store_init(struct repository *repo, + enum ref_storage_format format, const char *gitdir, unsigned int flags) { const struct ref_storage_be *be; struct ref_store *refs; - be = find_ref_storage_backend(repo->ref_storage_format); + be = find_ref_storage_backend(format); if (!be) BUG("reference backend is unknown"); @@ -1921,7 +1948,8 @@ struct ref_store *get_main_ref_store(struct repository *r) if (!r->gitdir) BUG("attempting to get main_ref_store outside of repository"); - r->refs_private = ref_store_init(r, r->gitdir, REF_STORE_ALL_CAPS); + r->refs_private = ref_store_init(r, r->ref_storage_format, + r->gitdir, REF_STORE_ALL_CAPS); r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private); return r->refs_private; } @@ -1981,7 +2009,8 @@ struct ref_store *repo_get_submodule_ref_store(struct repository *repo, free(subrepo); goto done; } - refs = ref_store_init(subrepo, submodule_sb.buf, + refs = ref_store_init(subrepo, repo->ref_storage_format, + submodule_sb.buf, REF_STORE_READ | REF_STORE_ODB); register_ref_store_map(&repo->submodule_ref_stores, "submodule", refs, submodule); @@ -2010,12 +2039,12 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt) struct strbuf common_path = STRBUF_INIT; strbuf_git_common_path(&common_path, wt->repo, "worktrees/%s", wt->id); - refs = ref_store_init(wt->repo, common_path.buf, - REF_STORE_ALL_CAPS); + refs = ref_store_init(wt->repo, wt->repo->ref_storage_format, + common_path.buf, REF_STORE_ALL_CAPS); strbuf_release(&common_path); } else { - refs = ref_store_init(wt->repo, wt->repo->commondir, - REF_STORE_ALL_CAPS); + refs = ref_store_init(wt->repo, wt->repo->ref_storage_format, + wt->repo->commondir, REF_STORE_ALL_CAPS); } if (refs) @@ -2470,7 +2499,7 @@ int refs_delete_refs(struct ref_store *refs, const char *logmsg, for_each_string_list_item(item, refnames) { ret = ref_transaction_delete(transaction, item->string, - NULL, flags, msg, &err); + NULL, NULL, flags, msg, &err); if (ret) { warning(_("could not delete reference %s: %s"), item->string, err.buf); @@ -2555,3 +2584,332 @@ int ref_update_check_old_target(const char *referent, struct ref_update *update, referent, update->old_target); return -1; } + +struct migration_data { + struct ref_store *old_refs; + struct ref_transaction *transaction; + struct strbuf *errbuf; +}; + +static int migrate_one_ref(const char *refname, const struct object_id *oid, + int flags, void *cb_data) +{ + struct migration_data *data = cb_data; + struct strbuf symref_target = STRBUF_INIT; + int ret; + + if (flags & REF_ISSYMREF) { + ret = refs_read_symbolic_ref(data->old_refs, refname, &symref_target); + if (ret < 0) + goto done; + + ret = ref_transaction_update(data->transaction, refname, NULL, null_oid(), + symref_target.buf, NULL, + REF_SKIP_CREATE_REFLOG | REF_NO_DEREF, NULL, data->errbuf); + if (ret < 0) + goto done; + } else { + ret = ref_transaction_create(data->transaction, refname, oid, NULL, + REF_SKIP_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION, + NULL, data->errbuf); + if (ret < 0) + goto done; + } + +done: + strbuf_release(&symref_target); + return ret; +} + +static int move_files(const char *from_path, const char *to_path, struct strbuf *errbuf) +{ + struct strbuf from_buf = STRBUF_INIT, to_buf = STRBUF_INIT; + size_t from_len, to_len; + DIR *from_dir; + int ret; + + from_dir = opendir(from_path); + if (!from_dir) { + strbuf_addf(errbuf, "could not open source directory '%s': %s", + from_path, strerror(errno)); + ret = -1; + goto done; + } + + strbuf_addstr(&from_buf, from_path); + strbuf_complete(&from_buf, '/'); + from_len = from_buf.len; + + strbuf_addstr(&to_buf, to_path); + strbuf_complete(&to_buf, '/'); + to_len = to_buf.len; + + while (1) { + struct dirent *ent; + + errno = 0; + ent = readdir(from_dir); + if (!ent) + break; + + if (!strcmp(ent->d_name, ".") || + !strcmp(ent->d_name, "..")) + continue; + + strbuf_setlen(&from_buf, from_len); + strbuf_addstr(&from_buf, ent->d_name); + + strbuf_setlen(&to_buf, to_len); + strbuf_addstr(&to_buf, ent->d_name); + + ret = rename(from_buf.buf, to_buf.buf); + if (ret < 0) { + strbuf_addf(errbuf, "could not link file '%s' to '%s': %s", + from_buf.buf, to_buf.buf, strerror(errno)); + goto done; + } + } + + if (errno) { + strbuf_addf(errbuf, "could not read entry from directory '%s': %s", + from_path, strerror(errno)); + ret = -1; + goto done; + } + + ret = 0; + +done: + strbuf_release(&from_buf); + strbuf_release(&to_buf); + if (from_dir) + closedir(from_dir); + return ret; +} + +static int count_reflogs(const char *reflog UNUSED, void *payload) +{ + size_t *reflog_count = payload; + (*reflog_count)++; + return 0; +} + +static int has_worktrees(void) +{ + struct worktree **worktrees = get_worktrees(); + int ret = 0; + size_t i; + + for (i = 0; worktrees[i]; i++) { + if (is_main_worktree(worktrees[i])) + continue; + ret = 1; + } + + free_worktrees(worktrees); + return ret; +} + +int repo_migrate_ref_storage_format(struct repository *repo, + enum ref_storage_format format, + unsigned int flags, + struct strbuf *errbuf) +{ + struct ref_store *old_refs = NULL, *new_refs = NULL; + struct ref_transaction *transaction = NULL; + struct strbuf new_gitdir = STRBUF_INIT; + struct migration_data data; + size_t reflog_count = 0; + int did_migrate_refs = 0; + int ret; + + if (repo->ref_storage_format == format) { + strbuf_addstr(errbuf, "current and new ref storage format are equal"); + ret = -1; + goto done; + } + + old_refs = get_main_ref_store(repo); + + /* + * We do not have any interfaces that would allow us to write many + * reflog entries. Once we have them we can remove this restriction. + */ + if (refs_for_each_reflog(old_refs, count_reflogs, &reflog_count) < 0) { + strbuf_addstr(errbuf, "cannot count reflogs"); + ret = -1; + goto done; + } + if (reflog_count) { + strbuf_addstr(errbuf, "migrating reflogs is not supported yet"); + ret = -1; + goto done; + } + + /* + * Worktrees complicate the migration because every worktree has a + * separate ref storage. While it should be feasible to implement, this + * is pushed out to a future iteration. + * + * TODO: we should really be passing the caller-provided repository to + * `has_worktrees()`, but our worktree subsystem doesn't yet support + * that. + */ + if (has_worktrees()) { + strbuf_addstr(errbuf, "migrating repositories with worktrees is not supported yet"); + ret = -1; + goto done; + } + + /* + * The overall logic looks like this: + * + * 1. Set up a new temporary directory and initialize it with the new + * format. This is where all refs will be migrated into. + * + * 2. Enumerate all refs and write them into the new ref storage. + * This operation is safe as we do not yet modify the main + * repository. + * + * 3. If we're in dry-run mode then we are done and can hand over the + * directory to the caller for inspection. If not, we now start + * with the destructive part. + * + * 4. Delete the old ref storage from disk. As we have a copy of refs + * in the new ref storage it's okay(ish) if we now get interrupted + * as there is an equivalent copy of all refs available. + * + * 5. Move the new ref storage files into place. + * + * 6. Change the repository format to the new ref format. + */ + strbuf_addf(&new_gitdir, "%s/%s", old_refs->gitdir, "ref_migration.XXXXXX"); + if (!mkdtemp(new_gitdir.buf)) { + strbuf_addf(errbuf, "cannot create migration directory: %s", + strerror(errno)); + ret = -1; + goto done; + } + + new_refs = ref_store_init(repo, format, new_gitdir.buf, + REF_STORE_ALL_CAPS); + ret = ref_store_create_on_disk(new_refs, 0, errbuf); + if (ret < 0) + goto done; + + transaction = ref_store_transaction_begin(new_refs, errbuf); + if (!transaction) + goto done; + + data.old_refs = old_refs; + data.transaction = transaction; + data.errbuf = errbuf; + + /* + * We need to use the internal `do_for_each_ref()` here so that we can + * also include broken refs and symrefs. These would otherwise be + * skipped silently. + * + * Ideally, we would do this call while locking the old ref storage + * such that there cannot be any concurrent modifications. We do not + * have the infra for that though, and the "files" backend does not + * allow for a central lock due to its design. It's thus on the user to + * ensure that there are no concurrent writes. + */ + ret = do_for_each_ref(old_refs, "", NULL, migrate_one_ref, 0, + DO_FOR_EACH_INCLUDE_ROOT_REFS | DO_FOR_EACH_INCLUDE_BROKEN, + &data); + if (ret < 0) + goto done; + + /* + * TODO: we might want to migrate to `initial_ref_transaction_commit()` + * here, which is more efficient for the files backend because it would + * write new refs into the packed-refs file directly. At this point, + * the files backend doesn't handle pseudo-refs and symrefs correctly + * though, so this requires some more work. + */ + ret = ref_transaction_commit(transaction, errbuf); + if (ret < 0) + goto done; + did_migrate_refs = 1; + + if (flags & REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN) { + printf(_("Finished dry-run migration of refs, " + "the result can be found at '%s'\n"), new_gitdir.buf); + ret = 0; + goto done; + } + + /* + * Release the new ref store such that any potentially-open files will + * be closed. This is required for platforms like Cygwin, where + * renaming an open file results in EPERM. + */ + ref_store_release(new_refs); + FREE_AND_NULL(new_refs); + + /* + * Until now we were in the non-destructive phase, where we only + * populated the new ref store. From hereon though we are about + * to get hands by deleting the old ref store and then moving + * the new one into place. + * + * Assuming that there were no concurrent writes, the new ref + * store should have all information. So if we fail from hereon + * we may be in an in-between state, but it would still be able + * to recover by manually moving remaining files from the + * temporary migration directory into place. + */ + ret = ref_store_remove_on_disk(old_refs, errbuf); + if (ret < 0) + goto done; + + ret = move_files(new_gitdir.buf, old_refs->gitdir, errbuf); + if (ret < 0) + goto done; + + if (rmdir(new_gitdir.buf) < 0) + warning_errno(_("could not remove temporary migration directory '%s'"), + new_gitdir.buf); + + /* + * We have migrated the repository, so we now need to adjust the + * repository format so that clients will use the new ref store. + * We also need to swap out the repository's main ref store. + */ + initialize_repository_version(hash_algo_by_ptr(repo->hash_algo), format, 1); + + /* + * Unset the old ref store and release it. `get_main_ref_store()` will + * make sure to lazily re-initialize the repository's ref store with + * the new format. + */ + ref_store_release(old_refs); + FREE_AND_NULL(old_refs); + repo->refs_private = NULL; + + ret = 0; + +done: + if (ret && did_migrate_refs) { + strbuf_complete(errbuf, '\n'); + strbuf_addf(errbuf, _("migrated refs can be found at '%s'"), + new_gitdir.buf); + } + + if (new_refs) { + ref_store_release(new_refs); + free(new_refs); + } + ref_transaction_free(transaction); + strbuf_release(&new_gitdir); + return ret; +} + +int ref_update_expects_existing_old_ref(struct ref_update *update) +{ + return (update->flags & REF_HAVE_OLD) && + (!is_null_oid(&update->old_oid) || update->old_target); +} + @@ -2,17 +2,17 @@ #define REFS_H #include "commit.h" +#include "repository.h" struct object_id; struct ref_store; -struct repository; struct strbuf; struct string_list; struct string_list_item; struct worktree; -unsigned int ref_storage_format_by_name(const char *name); -const char *ref_storage_format_to_name(unsigned int ref_storage_format); +enum ref_storage_format ref_storage_format_by_name(const char *name); +const char *ref_storage_format_to_name(enum ref_storage_format ref_storage_format); /* * Resolve a reference, recursively following symbolic refererences. @@ -124,6 +124,11 @@ int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *e void ref_store_release(struct ref_store *ref_store); /* + * Remove the ref store from disk. This deletes all associated data. + */ +int ref_store_remove_on_disk(struct ref_store *refs, struct strbuf *err); + +/* * Return the peeled value of the oid currently being iterated via * for_each_ref(), etc. This is equivalent to calling: * @@ -654,12 +659,18 @@ struct ref_transaction *ref_store_transaction_begin(struct ref_store *refs, #define REF_SKIP_REFNAME_VERIFICATION (1 << 11) /* + * Skip creation of a reflog entry, even if it would have otherwise been + * created. + */ +#define REF_SKIP_CREATE_REFLOG (1 << 12) + +/* * Bitmask of all of the flags that are allowed to be passed in to * ref_transaction_update() and friends: */ #define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \ (REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \ - REF_SKIP_REFNAME_VERIFICATION) + REF_SKIP_REFNAME_VERIFICATION | REF_SKIP_CREATE_REFLOG) /* * Add a reference update to transaction. `new_oid` is the value that @@ -700,6 +711,7 @@ int ref_transaction_update(struct ref_transaction *transaction, int ref_transaction_create(struct ref_transaction *transaction, const char *refname, const struct object_id *new_oid, + const char *new_target, unsigned int flags, const char *msg, struct strbuf *err); @@ -714,7 +726,9 @@ int ref_transaction_create(struct ref_transaction *transaction, int ref_transaction_delete(struct ref_transaction *transaction, const char *refname, const struct object_id *old_oid, - unsigned int flags, const char *msg, + const char *old_target, + unsigned int flags, + const char *msg, struct strbuf *err); /* @@ -728,6 +742,7 @@ int ref_transaction_delete(struct ref_transaction *transaction, int ref_transaction_verify(struct ref_transaction *transaction, const char *refname, const struct object_id *old_oid, + const char *old_target, unsigned int flags, struct strbuf *err); @@ -968,7 +983,7 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt); */ struct ref_namespace_info { - char *ref; + const char *ref; enum decoration_type decoration; /* @@ -1054,210 +1069,21 @@ int is_root_ref(const char *refname); int is_pseudo_ref(const char *refname); /* - * The following functions have been removed in Git v2.45 in favor of functions - * that receive a `ref_store` as parameter. The intent of this section is - * merely to help patch authors of in-flight series to have a reference what - * they should be migrating to. The section will be removed in Git v2.46. + * The following flags can be passed to `repo_migrate_ref_storage_format()`: + * + * - REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN: perform a dry-run migration + * without touching the main repository. The result will be written into a + * temporary ref storage directory. */ -#if 0 -static char *resolve_refdup(const char *refname, int resolve_flags, - struct object_id *oid, int *flags) -{ - return refs_resolve_refdup(get_main_ref_store(the_repository), - refname, resolve_flags, - oid, flags); -} - -static int read_ref_full(const char *refname, int resolve_flags, - struct object_id *oid, int *flags) -{ - return refs_read_ref_full(get_main_ref_store(the_repository), refname, - resolve_flags, oid, flags); -} - -static int read_ref(const char *refname, struct object_id *oid) -{ - return refs_read_ref(get_main_ref_store(the_repository), refname, oid); -} - -static int ref_exists(const char *refname) -{ - return refs_ref_exists(get_main_ref_store(the_repository), refname); -} - -static int for_each_tag_ref(each_ref_fn fn, void *cb_data) -{ - return refs_for_each_tag_ref(get_main_ref_store(the_repository), fn, cb_data); -} - -static int for_each_branch_ref(each_ref_fn fn, void *cb_data) -{ - return refs_for_each_branch_ref(get_main_ref_store(the_repository), fn, cb_data); -} - -static int for_each_remote_ref(each_ref_fn fn, void *cb_data) -{ - return refs_for_each_remote_ref(get_main_ref_store(the_repository), fn, cb_data); -} - -static int head_ref_namespaced(each_ref_fn fn, void *cb_data) -{ - return refs_head_ref_namespaced(get_main_ref_store(the_repository), - fn, cb_data); -} - -static int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, - const char *prefix, void *cb_data) -{ - return refs_for_each_glob_ref_in(get_main_ref_store(the_repository), - fn, pattern, prefix, cb_data); -} - -static int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data) -{ - return refs_for_each_glob_ref(get_main_ref_store(the_repository), - fn, pattern, cb_data); -} - -static int delete_ref(const char *msg, const char *refname, - const struct object_id *old_oid, unsigned int flags) -{ - return refs_delete_ref(get_main_ref_store(the_repository), msg, refname, - old_oid, flags); -} - -static struct ref_transaction *ref_transaction_begin(struct strbuf *err) -{ - return ref_store_transaction_begin(get_main_ref_store(the_repository), err); -} - -static int update_ref(const char *msg, const char *refname, - const struct object_id *new_oid, - const struct object_id *old_oid, - unsigned int flags, enum action_on_err onerr) -{ - return refs_update_ref(get_main_ref_store(the_repository), msg, refname, new_oid, - old_oid, flags, onerr); -} - -static char *shorten_unambiguous_ref(const char *refname, int strict) -{ - return refs_shorten_unambiguous_ref(get_main_ref_store(the_repository), - refname, strict); -} - -static int head_ref(each_ref_fn fn, void *cb_data) -{ - return refs_head_ref(get_main_ref_store(the_repository), fn, cb_data); -} - -static int for_each_ref(each_ref_fn fn, void *cb_data) -{ - return refs_for_each_ref(get_main_ref_store(the_repository), fn, cb_data); -} - -static int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data) -{ - return refs_for_each_ref_in(get_main_ref_store(the_repository), prefix, fn, cb_data); -} - -static int for_each_fullref_in(const char *prefix, - const char **exclude_patterns, - each_ref_fn fn, void *cb_data) -{ - return refs_for_each_fullref_in(get_main_ref_store(the_repository), - prefix, exclude_patterns, fn, cb_data); -} - -static int for_each_namespaced_ref(const char **exclude_patterns, - each_ref_fn fn, void *cb_data) -{ - return refs_for_each_namespaced_ref(get_main_ref_store(the_repository), - exclude_patterns, fn, cb_data); -} - -static int for_each_rawref(each_ref_fn fn, void *cb_data) -{ - return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data); -} - -static const char *resolve_ref_unsafe(const char *refname, int resolve_flags, - struct object_id *oid, int *flags) -{ - return refs_resolve_ref_unsafe(get_main_ref_store(the_repository), refname, - resolve_flags, oid, flags); -} - -static int create_symref(const char *ref_target, const char *refs_heads_master, - const char *logmsg) -{ - return refs_create_symref(get_main_ref_store(the_repository), ref_target, - refs_heads_master, logmsg); -} - -static int for_each_reflog(each_reflog_fn fn, void *cb_data) -{ - return refs_for_each_reflog(get_main_ref_store(the_repository), fn, cb_data); -} - -static int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, - void *cb_data) -{ - return refs_for_each_reflog_ent_reverse(get_main_ref_store(the_repository), - refname, fn, cb_data); -} - -static int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, - void *cb_data) -{ - return refs_for_each_reflog_ent(get_main_ref_store(the_repository), refname, - fn, cb_data); -} - -static int reflog_exists(const char *refname) -{ - return refs_reflog_exists(get_main_ref_store(the_repository), refname); -} - -static int safe_create_reflog(const char *refname, struct strbuf *err) -{ - return refs_create_reflog(get_main_ref_store(the_repository), refname, - err); -} - -static int delete_reflog(const char *refname) -{ - return refs_delete_reflog(get_main_ref_store(the_repository), refname); -} +#define REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN (1 << 0) -static int reflog_expire(const char *refname, - unsigned int flags, - reflog_expiry_prepare_fn prepare_fn, - reflog_expiry_should_prune_fn should_prune_fn, - reflog_expiry_cleanup_fn cleanup_fn, - void *policy_cb_data) -{ - return refs_reflog_expire(get_main_ref_store(the_repository), - refname, flags, - prepare_fn, should_prune_fn, - cleanup_fn, policy_cb_data); -} - -static int delete_refs(const char *msg, struct string_list *refnames, - unsigned int flags) -{ - return refs_delete_refs(get_main_ref_store(the_repository), msg, refnames, flags); -} - -static int rename_ref(const char *oldref, const char *newref, const char *logmsg) -{ - return refs_rename_ref(get_main_ref_store(the_repository), oldref, newref, logmsg); -} - -static int copy_existing_ref(const char *oldref, const char *newref, const char *logmsg) -{ - return refs_copy_existing_ref(get_main_ref_store(the_repository), oldref, newref, logmsg); -} -#endif +/* + * Migrate the ref storage format used by the repository to the + * specified one. + */ +int repo_migrate_ref_storage_format(struct repository *repo, + enum ref_storage_format format, + unsigned int flags, + struct strbuf *err); #endif /* REFS_H */ diff --git a/refs/files-backend.c b/refs/files-backend.c index 324c59b096..c73f95ecf2 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -246,7 +246,7 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs, if (!refs_resolve_ref_unsafe(&refs->base, refname, RESOLVE_REF_READING, &oid, &flag)) { - oidclr(&oid); + oidclr(&oid, refs->base.repo->hash_algo); flag |= REF_ISBROKEN; } else if (is_null_oid(&oid)) { /* @@ -263,7 +263,7 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs, if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { if (!refname_is_safe(refname)) die("loose refname is dangerous: %s", refname); - oidclr(&oid); + oidclr(&oid, refs->base.repo->hash_algo); flag |= REF_BAD_NAME | REF_ISBROKEN; } add_entry_to_dir(dir, create_ref_entry(refname, &oid, flag)); @@ -323,19 +323,15 @@ static void loose_fill_ref_dir(struct ref_store *ref_store, add_per_worktree_entries_to_dir(dir, dirname); } -/* - * Add pseudorefs to the ref dir by parsing the directory for any files - * which follow the pseudoref syntax. - */ -static void add_pseudoref_and_head_entries(struct ref_store *ref_store, - struct ref_dir *dir, - const char *dirname) +static int for_each_root_ref(struct files_ref_store *refs, + int (*cb)(const char *refname, void *cb_data), + void *cb_data) { - struct files_ref_store *refs = - files_downcast(ref_store, REF_STORE_READ, "fill_ref_dir"); struct strbuf path = STRBUF_INIT, refname = STRBUF_INIT; + const char *dirname = refs->loose->root->name; struct dirent *de; size_t dirnamelen; + int ret; DIR *d; files_ref_path(refs, &path, dirname); @@ -343,7 +339,7 @@ static void add_pseudoref_and_head_entries(struct ref_store *ref_store, d = opendir(path.buf); if (!d) { strbuf_release(&path); - return; + return -1; } strbuf_addstr(&refname, dirname); @@ -359,14 +355,49 @@ static void add_pseudoref_and_head_entries(struct ref_store *ref_store, strbuf_addstr(&refname, de->d_name); dtype = get_dtype(de, &path, 1); - if (dtype == DT_REG && is_root_ref(de->d_name)) - loose_fill_ref_dir_regular_file(refs, refname.buf, dir); + if (dtype == DT_REG && is_root_ref(de->d_name)) { + ret = cb(refname.buf, cb_data); + if (ret) + goto done; + } strbuf_setlen(&refname, dirnamelen); } + + ret = 0; + +done: strbuf_release(&refname); strbuf_release(&path); closedir(d); + return ret; +} + +struct fill_root_ref_data { + struct files_ref_store *refs; + struct ref_dir *dir; +}; + +static int fill_root_ref(const char *refname, void *cb_data) +{ + struct fill_root_ref_data *data = cb_data; + loose_fill_ref_dir_regular_file(data->refs, refname, data->dir); + return 0; +} + +/* + * Add root refs to the ref dir by parsing the directory for any files which + * follow the root ref syntax. + */ +static void add_root_refs(struct files_ref_store *refs, + struct ref_dir *dir) +{ + struct fill_root_ref_data data = { + .refs = refs, + .dir = dir, + }; + + for_each_root_ref(refs, fill_root_ref, &data); } static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs, @@ -388,8 +419,7 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs, dir = get_ref_dir(refs->loose->root); if (flags & DO_FOR_EACH_INCLUDE_ROOT_REFS) - add_pseudoref_and_head_entries(dir->cache->ref_store, dir, - refs->loose->root->name); + add_root_refs(refs, dir); /* * Add an incomplete entry for "refs/" (to be filled @@ -520,7 +550,8 @@ stat_ref: strbuf_rtrim(&sb_contents); buf = sb_contents.buf; - ret = parse_loose_ref_contents(buf, oid, referent, type, &myerr); + ret = parse_loose_ref_contents(ref_store->repo->hash_algo, buf, + oid, referent, type, &myerr); out: if (ret && !myerr) @@ -554,7 +585,8 @@ static int files_read_symbolic_ref(struct ref_store *ref_store, const char *refn return !(type & REF_ISSYMREF); } -int parse_loose_ref_contents(const char *buf, struct object_id *oid, +int parse_loose_ref_contents(const struct git_hash_algo *algop, + const char *buf, struct object_id *oid, struct strbuf *referent, unsigned int *type, int *failure_errno) { @@ -572,7 +604,7 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid, /* * FETCH_HEAD has additional data after the sha. */ - if (parse_oid_hex(buf, oid, &p) || + if (parse_oid_hex_algop(buf, oid, &p, algop) || (*p != '\0' && !isspace(*p))) { *type |= REF_ISBROKEN; *failure_errno = EINVAL; @@ -1120,7 +1152,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, if (!refs_resolve_ref_unsafe(&refs->base, lock->ref_name, 0, &lock->old_oid, NULL)) - oidclr(&lock->old_oid); + oidclr(&lock->old_oid, refs->base.repo->hash_algo); goto out; error_return: @@ -1752,6 +1784,9 @@ static int files_log_ref_write(struct files_ref_store *refs, { int logfd, result; + if (flags & REF_SKIP_CREATE_REFLOG) + return 0; + if (log_all_ref_updates == LOG_REFS_UNSET) log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL; @@ -1963,7 +1998,8 @@ static int files_delete_reflog(struct ref_store *ref_store, return ret; } -static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *cb_data) +static int show_one_reflog_ent(struct files_ref_store *refs, struct strbuf *sb, + each_reflog_ent_fn fn, void *cb_data) { struct object_id ooid, noid; char *email_end, *message; @@ -1973,8 +2009,8 @@ static int show_one_reflog_ent(struct strbuf *sb, each_reflog_ent_fn fn, void *c /* old SP new SP name <email> SP time TAB msg LF */ if (!sb->len || sb->buf[sb->len - 1] != '\n' || - parse_oid_hex(p, &ooid, &p) || *p++ != ' ' || - parse_oid_hex(p, &noid, &p) || *p++ != ' ' || + parse_oid_hex_algop(p, &ooid, &p, refs->base.repo->hash_algo) || *p++ != ' ' || + parse_oid_hex_algop(p, &noid, &p, refs->base.repo->hash_algo) || *p++ != ' ' || !(email_end = strchr(p, '>')) || email_end[1] != ' ' || !(timestamp = parse_timestamp(email_end + 2, &message, 10)) || @@ -2073,7 +2109,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store, strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1)); scanp = bp; endp = bp + 1; - ret = show_one_reflog_ent(&sb, fn, cb_data); + ret = show_one_reflog_ent(refs, &sb, fn, cb_data); strbuf_reset(&sb); if (ret) break; @@ -2085,7 +2121,7 @@ static int files_for_each_reflog_ent_reverse(struct ref_store *ref_store, * Process it, and we can end the loop. */ strbuf_splice(&sb, 0, 0, buf, endp - buf); - ret = show_one_reflog_ent(&sb, fn, cb_data); + ret = show_one_reflog_ent(refs, &sb, fn, cb_data); strbuf_reset(&sb); break; } @@ -2135,7 +2171,7 @@ static int files_for_each_reflog_ent(struct ref_store *ref_store, return -1; while (!ret && !strbuf_getwholeline(&sb, logfp, '\n')) - ret = show_one_reflog_ent(&sb, fn, cb_data); + ret = show_one_reflog_ent(refs, &sb, fn, cb_data); fclose(logfp); strbuf_release(&sb); return ret; @@ -2253,6 +2289,7 @@ static int split_head_update(struct ref_update *update, struct ref_update *new_update; if ((update->flags & REF_LOG_ONLY) || + (update->flags & REF_SKIP_CREATE_REFLOG) || (update->flags & REF_IS_PRUNING) || (update->flags & REF_UPDATE_VIA_HEAD)) return 0; @@ -2423,8 +2460,7 @@ static int lock_ref_for_update(struct files_ref_store *refs, struct strbuf *err) { struct strbuf referent = STRBUF_INIT; - int mustexist = (update->flags & REF_HAVE_OLD) && - !is_null_oid(&update->old_oid); + int mustexist = ref_update_expects_existing_old_ref(update); int ret = 0; struct ref_lock *lock; @@ -2503,14 +2539,16 @@ static int lock_ref_for_update(struct files_ref_store *refs, /* * Even if the ref is a regular ref, if `old_target` is set, we - * check the referent value. Ideally `old_target` should only - * be set for symrefs, but we're strict about its usage. + * fail with an error. */ if (update->old_target) { - if (ref_update_check_old_target(referent.buf, update, err)) { - ret = TRANSACTION_GENERIC_ERROR; - goto out; - } + strbuf_addf(err, _("cannot lock ref '%s': " + "expected symref with target '%s': " + "but is a regular ref"), + ref_update_original_update_refname(update), + update->old_target); + ret = TRANSACTION_GENERIC_ERROR; + goto out; } else if (check_old_oid(update, &lock->old_oid, err)) { ret = TRANSACTION_GENERIC_ERROR; goto out; @@ -3310,11 +3348,73 @@ static int files_ref_store_create_on_disk(struct ref_store *ref_store, return 0; } +struct remove_one_root_ref_data { + const char *gitdir; + struct strbuf *err; +}; + +static int remove_one_root_ref(const char *refname, + void *cb_data) +{ + struct remove_one_root_ref_data *data = cb_data; + struct strbuf buf = STRBUF_INIT; + int ret = 0; + + strbuf_addf(&buf, "%s/%s", data->gitdir, refname); + + ret = unlink(buf.buf); + if (ret < 0) + strbuf_addf(data->err, "could not delete %s: %s\n", + refname, strerror(errno)); + + strbuf_release(&buf); + return ret; +} + +static int files_ref_store_remove_on_disk(struct ref_store *ref_store, + struct strbuf *err) +{ + struct files_ref_store *refs = + files_downcast(ref_store, REF_STORE_WRITE, "remove"); + struct remove_one_root_ref_data data = { + .gitdir = refs->base.gitdir, + .err = err, + }; + struct strbuf sb = STRBUF_INIT; + int ret = 0; + + strbuf_addf(&sb, "%s/refs", refs->base.gitdir); + if (remove_dir_recursively(&sb, 0) < 0) { + strbuf_addf(err, "could not delete refs: %s", + strerror(errno)); + ret = -1; + } + strbuf_reset(&sb); + + strbuf_addf(&sb, "%s/logs", refs->base.gitdir); + if (remove_dir_recursively(&sb, 0) < 0) { + strbuf_addf(err, "could not delete logs: %s", + strerror(errno)); + ret = -1; + } + strbuf_reset(&sb); + + if (for_each_root_ref(refs, remove_one_root_ref, &data) < 0) + ret = -1; + + if (ref_store_remove_on_disk(refs->packed_ref_store, err) < 0) + ret = -1; + + strbuf_release(&sb); + return ret; +} + struct ref_storage_be refs_be_files = { .name = "files", .init = files_ref_store_init, .release = files_ref_store_release, .create_on_disk = files_ref_store_create_on_disk, + .remove_on_disk = files_ref_store_remove_on_disk, .transaction_prepare = files_transaction_prepare, .transaction_finish = files_transaction_finish, diff --git a/refs/packed-backend.c b/refs/packed-backend.c index 2789fd92f5..89976aa359 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -1,5 +1,6 @@ #include "../git-compat-util.h" #include "../config.h" +#include "../dir.h" #include "../gettext.h" #include "../hash.h" #include "../hex.h" @@ -791,7 +792,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store, const char *refname, return -1; } - if (get_oid_hex(rec, oid)) + if (get_oid_hex_algop(rec, oid, ref_store->repo->hash_algo)) die_invalid_line(refs->path, rec, snapshot->eof - rec); *type = REF_ISPACKED; @@ -876,7 +877,7 @@ static int next_record(struct packed_ref_iterator *iter) p = iter->pos; if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 2 || - parse_oid_hex(p, &iter->oid, &p) || + parse_oid_hex_algop(p, &iter->oid, &p, iter->repo->hash_algo) || !isspace(*p++)) die_invalid_line(iter->snapshot->refs->path, iter->pos, iter->eof - iter->pos); @@ -893,7 +894,7 @@ static int next_record(struct packed_ref_iterator *iter) if (!refname_is_safe(iter->base.refname)) die("packed refname is dangerous: %s", iter->base.refname); - oidclr(&iter->oid); + oidclr(&iter->oid, iter->repo->hash_algo); iter->base.flags |= REF_BAD_NAME | REF_ISBROKEN; } if (iter->snapshot->peeled == PEELED_FULLY || @@ -906,7 +907,7 @@ static int next_record(struct packed_ref_iterator *iter) if (iter->pos < iter->eof && *iter->pos == '^') { p = iter->pos + 1; if (iter->eof - p < snapshot_hexsz(iter->snapshot) + 1 || - parse_oid_hex(p, &iter->peeled, &p) || + parse_oid_hex_algop(p, &iter->peeled, &p, iter->repo->hash_algo) || *p++ != '\n') die_invalid_line(iter->snapshot->refs->path, iter->pos, iter->eof - iter->pos); @@ -918,13 +919,13 @@ static int next_record(struct packed_ref_iterator *iter) * we suppress it if the reference is broken: */ if ((iter->base.flags & REF_ISBROKEN)) { - oidclr(&iter->peeled); + oidclr(&iter->peeled, iter->repo->hash_algo); iter->base.flags &= ~REF_KNOWS_PEELED; } else { iter->base.flags |= REF_KNOWS_PEELED; } } else { - oidclr(&iter->peeled); + oidclr(&iter->peeled, iter->repo->hash_algo); } return ITER_OK; @@ -1266,6 +1267,19 @@ static int packed_ref_store_create_on_disk(struct ref_store *ref_store UNUSED, return 0; } +static int packed_ref_store_remove_on_disk(struct ref_store *ref_store, + struct strbuf *err) +{ + struct packed_ref_store *refs = packed_downcast(ref_store, 0, "remove"); + + if (remove_path(refs->path) < 0) { + strbuf_addstr(err, "could not delete packed-refs"); + return -1; + } + + return 0; +} + /* * Write the packed refs from the current snapshot to the packed-refs * tempfile, incorporating any changes from `updates`. `updates` must @@ -1724,6 +1738,7 @@ struct ref_storage_be refs_be_packed = { .init = packed_ref_store_init, .release = packed_ref_store_release, .create_on_disk = packed_ref_store_create_on_disk, + .remove_on_disk = packed_ref_store_remove_on_disk, .transaction_prepare = packed_transaction_prepare, .transaction_finish = packed_transaction_finish, diff --git a/refs/ref-cache.c b/refs/ref-cache.c index b6c53fc8ed..4ce519bbc8 100644 --- a/refs/ref-cache.c +++ b/refs/ref-cache.c @@ -71,6 +71,8 @@ static void free_ref_entry(struct ref_entry *entry) void free_ref_cache(struct ref_cache *cache) { + if (!cache) + return; free_ref_entry(cache->root); free(cache); } diff --git a/refs/ref-cache.h b/refs/ref-cache.h index 95c76e27c8..31ebe24f6c 100644 --- a/refs/ref-cache.h +++ b/refs/ref-cache.h @@ -1,7 +1,7 @@ #ifndef REFS_REF_CACHE_H #define REFS_REF_CACHE_H -#include "hash-ll.h" +#include "hash.h" struct ref_dir; struct ref_store; diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 33749fbd83..309b382284 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -517,6 +517,12 @@ typedef int ref_store_create_on_disk_fn(struct ref_store *refs, int flags, struct strbuf *err); +/* + * Remove the reference store from disk. + */ +typedef int ref_store_remove_on_disk_fn(struct ref_store *refs, + struct strbuf *err); + typedef int ref_transaction_prepare_fn(struct ref_store *refs, struct ref_transaction *transaction, struct strbuf *err); @@ -649,6 +655,7 @@ struct ref_storage_be { ref_store_init_fn *init; ref_store_release_fn *release; ref_store_create_on_disk_fn *create_on_disk; + ref_store_remove_on_disk_fn *remove_on_disk; ref_transaction_prepare_fn *transaction_prepare; ref_transaction_finish_fn *transaction_finish; @@ -698,7 +705,8 @@ struct ref_store { * Parse contents of a loose ref file. *failure_errno maybe be set to EINVAL for * invalid contents. */ -int parse_loose_ref_contents(const char *buf, struct object_id *oid, +int parse_loose_ref_contents(const struct git_hash_algo *algop, + const char *buf, struct object_id *oid, struct strbuf *referent, unsigned int *type, int *failure_errno); @@ -735,4 +743,10 @@ int ref_update_has_null_new_value(struct ref_update *update); int ref_update_check_old_target(const char *referent, struct ref_update *update, struct strbuf *err); +/* + * Check if the ref must exist, this means that the old_oid or + * old_target is non NULL. + */ +int ref_update_expects_existing_old_ref(struct ref_update *update); + #endif /* REFS_REFS_INTERNAL_H */ diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 438b5c478b..bf4446afd3 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -2,6 +2,7 @@ #include "../abspath.h" #include "../chdir-notify.h" #include "../config.h" +#include "../dir.h" #include "../environment.h" #include "../gettext.h" #include "../hash.h" @@ -198,7 +199,8 @@ static void fill_reftable_log_record(struct reftable_log_record *log, const stru log->value.update.tz_offset = sign * atoi(tz_begin); } -static int read_ref_without_reload(struct reftable_stack *stack, +static int read_ref_without_reload(struct reftable_ref_store *refs, + struct reftable_stack *stack, const char *refname, struct object_id *oid, struct strbuf *referent, @@ -216,7 +218,8 @@ static int read_ref_without_reload(struct reftable_stack *stack, strbuf_addstr(referent, ref.value.symref); *type |= REF_ISSYMREF; } else if (reftable_ref_record_val1(&ref)) { - oidread(oid, reftable_ref_record_val1(&ref)); + oidread(oid, reftable_ref_record_val1(&ref), + refs->base.repo->hash_algo); } else { /* We got a tombstone, which should not happen. */ BUG("unhandled reference value type %d", ref.value_type); @@ -383,6 +386,56 @@ static int reftable_be_create_on_disk(struct ref_store *ref_store, return 0; } +static int reftable_be_remove_on_disk(struct ref_store *ref_store, + struct strbuf *err) +{ + struct reftable_ref_store *refs = + reftable_be_downcast(ref_store, REF_STORE_WRITE, "remove"); + struct strbuf sb = STRBUF_INIT; + int ret = 0; + + /* + * Release the ref store such that all stacks are closed. This is + * required so that the "tables.list" file is not open anymore, which + * would otherwise make it impossible to remove the file on Windows. + */ + reftable_be_release(ref_store); + + strbuf_addf(&sb, "%s/reftable", refs->base.gitdir); + if (remove_dir_recursively(&sb, 0) < 0) { + strbuf_addf(err, "could not delete reftables: %s", + strerror(errno)); + ret = -1; + } + strbuf_reset(&sb); + + strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir); + if (unlink(sb.buf) < 0) { + strbuf_addf(err, "could not delete stub HEAD: %s", + strerror(errno)); + ret = -1; + } + strbuf_reset(&sb); + + strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir); + if (unlink(sb.buf) < 0) { + strbuf_addf(err, "could not delete stub heads: %s", + strerror(errno)); + ret = -1; + } + strbuf_reset(&sb); + + strbuf_addf(&sb, "%s/refs", refs->base.gitdir); + if (rmdir(sb.buf) < 0) { + strbuf_addf(err, "could not delete refs directory: %s", + strerror(errno)); + ret = -1; + } + + strbuf_release(&sb); + return ret; +} + struct reftable_ref_iterator { struct ref_iterator base; struct reftable_ref_store *refs; @@ -432,15 +485,17 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator) switch (iter->ref.value_type) { case REFTABLE_REF_VAL1: - oidread(&iter->oid, iter->ref.value.val1); + oidread(&iter->oid, iter->ref.value.val1, + refs->base.repo->hash_algo); break; case REFTABLE_REF_VAL2: - oidread(&iter->oid, iter->ref.value.val2.value); + oidread(&iter->oid, iter->ref.value.val2.value, + refs->base.repo->hash_algo); break; case REFTABLE_REF_SYMREF: if (!refs_resolve_ref_unsafe(&iter->refs->base, iter->ref.refname, RESOLVE_REF_READING, &iter->oid, &flags)) - oidclr(&iter->oid); + oidclr(&iter->oid, refs->base.repo->hash_algo); break; default: BUG("unhandled reference value type %d", iter->ref.value_type); @@ -452,7 +507,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator) if (check_refname_format(iter->ref.refname, REFNAME_ALLOW_ONELEVEL)) { if (!refname_is_safe(iter->ref.refname)) die(_("refname is dangerous: %s"), iter->ref.refname); - oidclr(&iter->oid); + oidclr(&iter->oid, refs->base.repo->hash_algo); flags |= REF_BAD_NAME | REF_ISBROKEN; } @@ -494,7 +549,8 @@ static int reftable_ref_iterator_peel(struct ref_iterator *ref_iterator, (struct reftable_ref_iterator *)ref_iterator; if (iter->ref.value_type == REFTABLE_REF_VAL2) { - oidread(peeled, iter->ref.value.val2.target_value); + oidread(peeled, iter->ref.value.val2.target_value, + iter->refs->base.repo->hash_algo); return 0; } @@ -602,7 +658,7 @@ static int reftable_be_read_raw_ref(struct ref_store *ref_store, if (ret) return ret; - ret = read_ref_without_reload(stack, refname, oid, referent, type); + ret = read_ref_without_reload(refs, stack, refname, oid, referent, type); if (ret < 0) return ret; if (ret > 0) { @@ -811,8 +867,8 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, goto done; } - ret = read_ref_without_reload(stack_for(refs, "HEAD", NULL), "HEAD", &head_oid, - &head_referent, &head_type); + ret = read_ref_without_reload(refs, stack_for(refs, "HEAD", NULL), "HEAD", + &head_oid, &head_referent, &head_type); if (ret < 0) goto done; ret = 0; @@ -879,11 +935,11 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, string_list_insert(&affected_refnames, new_update->refname); } - ret = read_ref_without_reload(stack, rewritten_ref, + ret = read_ref_without_reload(refs, stack, rewritten_ref, ¤t_oid, &referent, &u->type); if (ret < 0) goto done; - if (ret > 0 && (!(u->flags & REF_HAVE_OLD) || is_null_oid(&u->old_oid))) { + if (ret > 0 && !ref_update_expects_existing_old_ref(u)) { /* * The reference does not exist, and we either have no * old object ID or expect the reference to not exist. @@ -954,8 +1010,9 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, */ new_update = ref_transaction_add_update( transaction, referent.buf, new_flags, - &u->new_oid, &u->old_oid, u->new_target, - u->old_target, u->msg); + u->new_target ? NULL : &u->new_oid, + u->old_target ? NULL : &u->old_oid, + u->new_target, u->old_target, u->msg); new_update->parent_update = u; @@ -987,6 +1044,16 @@ static int reftable_be_transaction_prepare(struct ref_store *ref_store, * backend returns, which keeps our tests happy. */ if (u->old_target) { + if (!(u->type & REF_ISSYMREF)) { + strbuf_addf(err, _("cannot lock ref '%s': " + "expected symref with target '%s': " + "but is a regular ref"), + ref_update_original_update_refname(u), + u->old_target); + ret = -1; + goto done; + } + if (ref_update_check_old_target(referent.buf, u, err)) { ret = -1; goto done; @@ -1141,7 +1208,8 @@ static int write_transaction_table(struct reftable_writer *writer, void *cb_data if (ret) goto done; - } else if (u->flags & REF_HAVE_NEW && + } else if (!(u->flags & REF_SKIP_CREATE_REFLOG) && + (u->flags & REF_HAVE_NEW) && (u->flags & REF_FORCE_CREATE_REFLOG || should_write_log(&arg->refs->base, u->refname))) { struct reftable_log_record *log; @@ -1398,10 +1466,10 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) * old reference. */ refs[0] = old_ref; - refs[0].refname = (char *)arg->newname; + refs[0].refname = xstrdup(arg->newname); refs[0].update_index = creation_ts; if (arg->delete_old) { - refs[1].refname = (char *)arg->oldname; + refs[1].refname = xstrdup(arg->oldname); refs[1].value_type = REFTABLE_REF_DELETION; refs[1].update_index = deletion_ts; } @@ -1424,14 +1492,15 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) ALLOC_GROW(logs, logs_nr + 1, logs_alloc); memset(&logs[logs_nr], 0, sizeof(logs[logs_nr])); fill_reftable_log_record(&logs[logs_nr], &committer_ident); - logs[logs_nr].refname = (char *)arg->newname; + logs[logs_nr].refname = xstrdup(arg->newname); logs[logs_nr].update_index = deletion_ts; logs[logs_nr].value.update.message = xstrndup(arg->logmsg, arg->refs->write_options.block_size / 2); memcpy(logs[logs_nr].value.update.old_hash, old_ref.value.val1, GIT_MAX_RAWSZ); logs_nr++; - ret = read_ref_without_reload(arg->stack, "HEAD", &head_oid, &head_referent, &head_type); + ret = read_ref_without_reload(arg->refs, arg->stack, "HEAD", &head_oid, + &head_referent, &head_type); if (ret < 0) goto done; append_head_reflog = (head_type & REF_ISSYMREF) && !strcmp(head_referent.buf, arg->oldname); @@ -1445,7 +1514,13 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) if (append_head_reflog) { ALLOC_GROW(logs, logs_nr + 1, logs_alloc); logs[logs_nr] = logs[logs_nr - 1]; - logs[logs_nr].refname = "HEAD"; + logs[logs_nr].refname = xstrdup("HEAD"); + logs[logs_nr].value.update.name = + xstrdup(logs[logs_nr].value.update.name); + logs[logs_nr].value.update.email = + xstrdup(logs[logs_nr].value.update.email); + logs[logs_nr].value.update.message = + xstrdup(logs[logs_nr].value.update.message); logs_nr++; } } @@ -1456,7 +1531,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) ALLOC_GROW(logs, logs_nr + 1, logs_alloc); memset(&logs[logs_nr], 0, sizeof(logs[logs_nr])); fill_reftable_log_record(&logs[logs_nr], &committer_ident); - logs[logs_nr].refname = (char *)arg->newname; + logs[logs_nr].refname = xstrdup(arg->newname); logs[logs_nr].update_index = creation_ts; logs[logs_nr].value.update.message = xstrndup(arg->logmsg, arg->refs->write_options.block_size / 2); @@ -1489,7 +1564,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) */ ALLOC_GROW(logs, logs_nr + 1, logs_alloc); logs[logs_nr] = old_log; - logs[logs_nr].refname = (char *)arg->newname; + logs[logs_nr].refname = xstrdup(arg->newname); logs_nr++; /* @@ -1498,7 +1573,7 @@ static int write_copy_table(struct reftable_writer *writer, void *cb_data) if (arg->delete_old) { ALLOC_GROW(logs, logs_nr + 1, logs_alloc); memset(&logs[logs_nr], 0, sizeof(logs[logs_nr])); - logs[logs_nr].refname = (char *)arg->oldname; + logs[logs_nr].refname = xstrdup(arg->oldname); logs[logs_nr].value_type = REFTABLE_LOG_DELETION; logs[logs_nr].update_index = old_log.update_index; logs_nr++; @@ -1521,13 +1596,11 @@ done: reftable_iterator_destroy(&it); string_list_clear(&skip, 0); strbuf_release(&errbuf); - for (i = 0; i < logs_nr; i++) { - if (!strcmp(logs[i].refname, "HEAD")) - continue; - logs[i].refname = NULL; + for (i = 0; i < logs_nr; i++) reftable_log_record_release(&logs[i]); - } free(logs); + for (i = 0; i < ARRAY_SIZE(refs); i++) + reftable_ref_record_release(&refs[i]); reftable_ref_record_release(&old_ref); reftable_log_record_release(&old_log); return ret; @@ -1717,15 +1790,16 @@ static struct ref_iterator *reftable_be_reflog_iterator_begin(struct ref_store * ref_iterator_select, NULL); } -static int yield_log_record(struct reftable_log_record *log, +static int yield_log_record(struct reftable_ref_store *refs, + struct reftable_log_record *log, each_reflog_ent_fn fn, void *cb_data) { struct object_id old_oid, new_oid; const char *full_committer; - oidread(&old_oid, log->value.update.old_hash); - oidread(&new_oid, log->value.update.new_hash); + oidread(&old_oid, log->value.update.old_hash, refs->base.repo->hash_algo); + oidread(&new_oid, log->value.update.new_hash, refs->base.repo->hash_algo); /* * When both the old object ID and the new object ID are null @@ -1768,7 +1842,7 @@ static int reftable_be_for_each_reflog_ent_reverse(struct ref_store *ref_store, break; } - ret = yield_log_record(&log, fn, cb_data); + ret = yield_log_record(refs, &log, fn, cb_data); if (ret) break; } @@ -1813,7 +1887,7 @@ static int reftable_be_for_each_reflog_ent(struct ref_store *ref_store, } for (i = logs_nr; i--;) { - ret = yield_log_record(&logs[i], fn, cb_data); + ret = yield_log_record(refs, &logs[i], fn, cb_data); if (ret) goto done; } @@ -2126,7 +2200,8 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, if (ret < 0) goto done; if (reftable_ref_record_val1(&ref_record)) - oidread(&oid, reftable_ref_record_val1(&ref_record)); + oidread(&oid, reftable_ref_record_val1(&ref_record), + ref_store->repo->hash_algo); prepare_fn(refname, &oid, policy_cb_data); while (1) { @@ -2141,8 +2216,10 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, break; } - oidread(&old_oid, log.value.update.old_hash); - oidread(&new_oid, log.value.update.new_hash); + oidread(&old_oid, log.value.update.old_hash, + ref_store->repo->hash_algo); + oidread(&new_oid, log.value.update.new_hash, + ref_store->repo->hash_algo); /* * Skip over the reflog existence marker. We will add it back @@ -2173,8 +2250,10 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, struct object_id old_oid, new_oid; *dest = logs[i]; - oidread(&old_oid, logs[i].value.update.old_hash); - oidread(&new_oid, logs[i].value.update.new_hash); + oidread(&old_oid, logs[i].value.update.old_hash, + ref_store->repo->hash_algo); + oidread(&new_oid, logs[i].value.update.new_hash, + ref_store->repo->hash_algo); if (should_prune_fn(&old_oid, &new_oid, logs[i].value.update.email, (timestamp_t)logs[i].value.update.time, @@ -2191,7 +2270,7 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store, if (flags & EXPIRE_REFLOGS_UPDATE_REF && last_hash && reftable_ref_record_val1(&ref_record)) - oidread(&arg.update_oid, last_hash); + oidread(&arg.update_oid, last_hash, ref_store->repo->hash_algo); arg.refs = refs; arg.records = rewritten; @@ -2230,6 +2309,7 @@ struct ref_storage_be refs_be_reftable = { .init = reftable_be_init, .release = reftable_be_release, .create_on_disk = reftable_be_create_on_disk, + .remove_on_disk = reftable_be_remove_on_disk, .transaction_prepare = reftable_be_transaction_prepare, .transaction_finish = reftable_be_transaction_finish, @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "hash.h" @@ -7,19 +9,6 @@ #include "refspec.h" #include "strbuf.h" -static struct refspec_item s_tag_refspec = { - .force = 0, - .pattern = 1, - .matching = 0, - .exact_sha1 = 0, - .negative = 0, - .src = "refs/tags/*", - .dst = "refs/tags/*", -}; - -/* See TAG_REFSPEC for the string version */ -const struct refspec_item *tag_refspec = &s_tag_refspec; - /* * Parses the provided refspec 'refspec' and populates the refspec_item 'item'. * Returns 1 if successful and 0 if the refspec is invalid. @@ -2,7 +2,6 @@ #define REFSPEC_H #define TAG_REFSPEC "refs/tags/*:refs/tags/*" -extern const struct refspec_item *tag_refspec; /** * A struct refspec_item holds the parsed interpretation of a refspec. If it diff --git a/reftable/basics.c b/reftable/basics.c index fea711db7e..0058619ca6 100644 --- a/reftable/basics.c +++ b/reftable/basics.c @@ -67,9 +67,9 @@ void free_names(char **a) reftable_free(a); } -size_t names_length(char **names) +size_t names_length(const char **names) { - char **p = names; + const char **p = names; while (*p) p++; return p - names; @@ -102,15 +102,12 @@ void parse_names(char *buf, int size, char ***namesp) *namesp = names; } -int names_equal(char **a, char **b) +int names_equal(const char **a, const char **b) { - int i = 0; - for (; a[i] && b[i]; i++) { - if (strcmp(a[i], b[i])) { + size_t i = 0; + for (; a[i] && b[i]; i++) + if (strcmp(a[i], b[i])) return 0; - } - } - return a[i] == b[i]; } diff --git a/reftable/basics.h b/reftable/basics.h index 523ecd5307..c8fec68d4e 100644 --- a/reftable/basics.h +++ b/reftable/basics.h @@ -42,10 +42,10 @@ void free_names(char **a); void parse_names(char *buf, int size, char ***namesp); /* compares two NULL-terminated arrays of strings. */ -int names_equal(char **a, char **b); +int names_equal(const char **a, const char **b); /* returns the array size of a NULL-terminated array of strings. */ -size_t names_length(char **names); +size_t names_length(const char **names); /* Allocation routines; they invoke the functions set through * reftable_set_alloc() */ diff --git a/reftable/basics_test.c b/reftable/basics_test.c deleted file mode 100644 index 997c4d9e01..0000000000 --- a/reftable/basics_test.c +++ /dev/null @@ -1,105 +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 "system.h" - -#include "basics.h" -#include "test_framework.h" -#include "reftable-tests.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 test_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}, - }; - size_t i = 0; - - for (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); - EXPECT(idx == testcases[i].expected_idx); - } -} - -static void test_names_length(void) -{ - char *a[] = { "a", "b", NULL }; - EXPECT(names_length(a) == 2); -} - -static void test_parse_names_normal(void) -{ - char in[] = "a\nb\n"; - char **out = NULL; - parse_names(in, strlen(in), &out); - EXPECT(!strcmp(out[0], "a")); - EXPECT(!strcmp(out[1], "b")); - EXPECT(!out[2]); - free_names(out); -} - -static void test_parse_names_drop_empty(void) -{ - char in[] = "a\n\n"; - char **out = NULL; - parse_names(in, strlen(in), &out); - EXPECT(!strcmp(out[0], "a")); - EXPECT(!out[1]); - free_names(out); -} - -static void test_common_prefix(void) -{ - struct strbuf s1 = STRBUF_INIT; - struct strbuf s2 = STRBUF_INIT; - strbuf_addstr(&s1, "abcdef"); - strbuf_addstr(&s2, "abc"); - EXPECT(common_prefix_size(&s1, &s2) == 3); - strbuf_release(&s1); - strbuf_release(&s2); -} - -int basics_test_main(int argc, const char *argv[]) -{ - RUN_TEST(test_common_prefix); - RUN_TEST(test_parse_names_normal); - RUN_TEST(test_parse_names_drop_empty); - RUN_TEST(test_binsearch); - RUN_TEST(test_names_length); - return 0; -} diff --git a/reftable/block_test.c b/reftable/block_test.c index 26a9cfbc83..90aecd5a7c 100644 --- a/reftable/block_test.c +++ b/reftable/block_test.c @@ -42,7 +42,7 @@ static void test_block_read_write(void) block_writer_init(&bw, BLOCK_TYPE_REF, block.data, block_size, header_off, hash_size(GIT_SHA1_FORMAT_ID)); - rec.u.ref.refname = ""; + rec.u.ref.refname = (char *) ""; rec.u.ref.value_type = REFTABLE_REF_DELETION; n = block_writer_add(&bw, &rec); EXPECT(n == REFTABLE_API_ERROR); diff --git a/reftable/dump.c b/reftable/dump.c index 41abbb8ecf..dd65d9e8bb 100644 --- a/reftable/dump.c +++ b/reftable/dump.c @@ -7,7 +7,7 @@ https://developers.google.com/open-source/licenses/bsd */ #include "git-compat-util.h" -#include "hash-ll.h" +#include "hash.h" #include "reftable-blocksource.h" #include "reftable-error.h" diff --git a/reftable/merged.c b/reftable/merged.c index 0da9dba265..6adce44f4b 100644 --- a/reftable/merged.c +++ b/reftable/merged.c @@ -225,19 +225,11 @@ int reftable_new_merged_table(struct reftable_merged_table **dest, return 0; } -/* clears the list of subtable, without affecting the readers themselves. */ -void merged_table_release(struct reftable_merged_table *mt) -{ - FREE_AND_NULL(mt->stack); - mt->stack_len = 0; -} - void reftable_merged_table_free(struct reftable_merged_table *mt) { - if (!mt) { + if (!mt) return; - } - merged_table_release(mt); + FREE_AND_NULL(mt->stack); reftable_free(mt); } diff --git a/reftable/merged.h b/reftable/merged.h index a10469f58e..2efe571da6 100644 --- a/reftable/merged.h +++ b/reftable/merged.h @@ -24,8 +24,6 @@ struct reftable_merged_table { uint64_t max; }; -void merged_table_release(struct reftable_merged_table *mt); - struct reftable_iterator; void merged_table_init_iter(struct reftable_merged_table *mt, diff --git a/reftable/pq.c b/reftable/pq.c index 7fb45d8c60..2b5b7d1c0e 100644 --- a/reftable/pq.c +++ b/reftable/pq.c @@ -22,27 +22,21 @@ int pq_less(struct pq_entry *a, struct pq_entry *b) struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq) { - int i = 0; + size_t i = 0; struct pq_entry e = pq->heap[0]; pq->heap[0] = pq->heap[pq->len - 1]; pq->len--; - i = 0; while (i < pq->len) { - int min = i; - int j = 2 * i + 1; - int k = 2 * i + 2; - if (j < pq->len && pq_less(&pq->heap[j], &pq->heap[i])) { + size_t min = i; + size_t j = 2 * i + 1; + size_t k = 2 * i + 2; + if (j < pq->len && pq_less(&pq->heap[j], &pq->heap[i])) min = j; - } - if (k < pq->len && pq_less(&pq->heap[k], &pq->heap[min])) { + if (k < pq->len && pq_less(&pq->heap[k], &pq->heap[min])) min = k; - } - - if (min == i) { + if (min == i) break; - } - SWAP(pq->heap[i], pq->heap[min]); i = min; } @@ -52,20 +46,17 @@ struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq) void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e) { - int i = 0; + size_t i = 0; REFTABLE_ALLOC_GROW(pq->heap, pq->len + 1, pq->cap); pq->heap[pq->len++] = *e; i = pq->len - 1; while (i > 0) { - int j = (i - 1) / 2; - if (pq_less(&pq->heap[j], &pq->heap[i])) { + size_t j = (i - 1) / 2; + if (pq_less(&pq->heap[j], &pq->heap[i])) break; - } - SWAP(pq->heap[j], pq->heap[i]); - i = j; } } diff --git a/reftable/pq.h b/reftable/pq.h index f796c23179..707bd26767 100644 --- a/reftable/pq.h +++ b/reftable/pq.h @@ -22,7 +22,6 @@ struct merged_iter_pqueue { size_t cap; }; -void merged_iter_pqueue_check(struct merged_iter_pqueue pq); struct pq_entry merged_iter_pqueue_remove(struct merged_iter_pqueue *pq); void merged_iter_pqueue_add(struct merged_iter_pqueue *pq, const struct pq_entry *e); void merged_iter_pqueue_release(struct merged_iter_pqueue *pq); diff --git a/reftable/pq_test.c b/reftable/pq_test.c deleted file mode 100644 index b7d3c80cc7..0000000000 --- a/reftable/pq_test.c +++ /dev/null @@ -1,74 +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 "system.h" - -#include "basics.h" -#include "constants.h" -#include "pq.h" -#include "record.h" -#include "reftable-tests.h" -#include "test_framework.h" - -void merged_iter_pqueue_check(struct merged_iter_pqueue pq) -{ - int i; - for (i = 1; i < pq.len; i++) { - int parent = (i - 1) / 2; - - EXPECT(pq_less(&pq.heap[parent], &pq.heap[i])); - } -} - -static void test_pq(void) -{ - struct merged_iter_pqueue pq = { NULL }; - struct reftable_record recs[54]; - int N = ARRAY_SIZE(recs) - 1, i; - char *last = NULL; - - for (i = 0; i < N; i++) { - struct strbuf refname = STRBUF_INIT; - strbuf_addf(&refname, "%02d", i); - - reftable_record_init(&recs[i], BLOCK_TYPE_REF); - recs[i].u.ref.refname = strbuf_detach(&refname, NULL); - } - - i = 1; - do { - struct pq_entry e = { - .rec = &recs[i], - }; - - merged_iter_pqueue_add(&pq, &e); - merged_iter_pqueue_check(pq); - - i = (i * 7) % N; - } while (i != 1); - - while (!merged_iter_pqueue_is_empty(pq)) { - struct pq_entry e = merged_iter_pqueue_remove(&pq); - merged_iter_pqueue_check(pq); - - EXPECT(reftable_record_type(e.rec) == BLOCK_TYPE_REF); - if (last) - EXPECT(strcmp(last, e.rec->u.ref.refname) < 0); - last = e.rec->u.ref.refname; - } - - for (i = 0; i < N; i++) - reftable_record_release(&recs[i]); - merged_iter_pqueue_release(&pq); -} - -int pq_test_main(int argc, const char *argv[]) -{ - RUN_TEST(test_pq); - return 0; -} diff --git a/reftable/readwrite_test.c b/reftable/readwrite_test.c index d99543bbd6..f411abfe9c 100644 --- a/reftable/readwrite_test.c +++ b/reftable/readwrite_test.c @@ -86,7 +86,7 @@ static void write_table(char ***names, struct strbuf *buf, int N, log.update_index = update_index; log.value_type = REFTABLE_LOG_UPDATE; set_test_hash(log.value.update.new_hash, i); - log.value.update.message = "message"; + log.value.update.message = (char *) "message"; n = reftable_writer_add_log(w, &log); EXPECT(n == 0); @@ -118,15 +118,15 @@ static void test_log_buffer_size(void) int err; int i; struct reftable_log_record - log = { .refname = "refs/heads/master", + log = { .refname = (char *) "refs/heads/master", .update_index = 0xa, .value_type = REFTABLE_LOG_UPDATE, .value = { .update = { - .name = "Han-Wen Nienhuys", - .email = "hanwen@google.com", + .name = (char *) "Han-Wen Nienhuys", + .email = (char *) "hanwen@google.com", .tz_offset = 100, .time = 0x5e430672, - .message = "commit: 9\n", + .message = (char *) "commit: 9\n", } } }; struct reftable_writer *w = reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); @@ -156,15 +156,15 @@ static void test_log_overflow(void) }; int err; struct reftable_log_record log = { - .refname = "refs/heads/master", + .refname = (char *) "refs/heads/master", .update_index = 0xa, .value_type = REFTABLE_LOG_UPDATE, .value = { .update = { .old_hash = { 1 }, .new_hash = { 2 }, - .name = "Han-Wen Nienhuys", - .email = "hanwen@google.com", + .name = (char *) "Han-Wen Nienhuys", + .email = (char *) "hanwen@google.com", .tz_offset = 100, .time = 0x5e430672, .message = msg, @@ -297,14 +297,14 @@ static void test_log_zlib_corruption(void) char message[100] = { 0 }; int err, i, n; struct reftable_log_record log = { - .refname = "refname", + .refname = (char *) "refname", .value_type = REFTABLE_LOG_UPDATE, .value = { .update = { .new_hash = { 1 }, .old_hash = { 2 }, - .name = "My Name", - .email = "myname@invalid", + .name = (char *) "My Name", + .email = (char *) "myname@invalid", .message = message, }, }, @@ -739,7 +739,7 @@ static void test_write_empty_key(void) struct reftable_writer *w = reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); struct reftable_ref_record ref = { - .refname = "", + .refname = (char *) "", .update_index = 1, .value_type = REFTABLE_REF_DELETION, }; @@ -763,18 +763,18 @@ static void test_write_key_order(void) reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); struct reftable_ref_record refs[2] = { { - .refname = "b", + .refname = (char *) "b", .update_index = 1, .value_type = REFTABLE_REF_SYMREF, .value = { - .symref = "target", + .symref = (char *) "target", }, }, { - .refname = "a", + .refname = (char *) "a", .update_index = 1, .value_type = REFTABLE_REF_SYMREF, .value = { - .symref = "target", + .symref = (char *) "target", }, } }; diff --git a/reftable/record.c b/reftable/record.c index 5506f3e913..a2cba5ef74 100644 --- a/reftable/record.c +++ b/reftable/record.c @@ -116,7 +116,7 @@ static int decode_string(struct strbuf *dest, struct string_view in) return start_len - in.len; } -static int encode_string(char *str, struct string_view s) +static int encode_string(const char *str, struct string_view s) { struct string_view start = s; int l = strlen(str); @@ -969,9 +969,9 @@ done: return REFTABLE_FORMAT_ERROR; } -static int null_streq(char *a, char *b) +static int null_streq(const char *a, const char *b) { - char *empty = ""; + const char *empty = ""; if (!a) a = empty; diff --git a/reftable/record_test.c b/reftable/record_test.c deleted file mode 100644 index c158ee79ff..0000000000 --- a/reftable/record_test.c +++ /dev/null @@ -1,419 +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 "record.h" - -#include "system.h" -#include "basics.h" -#include "constants.h" -#include "test_framework.h" -#include "reftable-tests.h" - -static void test_copy(struct reftable_record *rec) -{ - struct reftable_record copy; - uint8_t typ; - - typ = reftable_record_type(rec); - reftable_record_init(©, typ); - reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); - /* do it twice to catch memory leaks */ - reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); - EXPECT(reftable_record_equal(rec, ©, GIT_SHA1_RAWSZ)); - - puts("testing print coverage:\n"); - reftable_record_print(©, GIT_SHA1_RAWSZ); - - reftable_record_release(©); -} - -static void test_varint_roundtrip(void) -{ - uint64_t inputs[] = { 0, - 1, - 27, - 127, - 128, - 257, - 4096, - ((uint64_t)1 << 63), - ((uint64_t)1 << 63) + ((uint64_t)1 << 63) - 1 }; - int i = 0; - for (i = 0; i < ARRAY_SIZE(inputs); i++) { - uint8_t dest[10]; - - struct string_view out = { - .buf = dest, - .len = sizeof(dest), - }; - uint64_t in = inputs[i]; - int n = put_var_int(&out, in); - uint64_t got = 0; - - EXPECT(n > 0); - out.len = n; - n = get_var_int(&got, &out); - EXPECT(n > 0); - - EXPECT(got == in); - } -} - -static void test_common_prefix(void) -{ - struct { - const char *a, *b; - int want; - } cases[] = { - { "abc", "ab", 2 }, - { "", "abc", 0 }, - { "abc", "abd", 2 }, - { "abc", "pqr", 0 }, - }; - - int i = 0; - for (i = 0; i < ARRAY_SIZE(cases); i++) { - struct strbuf a = STRBUF_INIT; - struct strbuf b = STRBUF_INIT; - strbuf_addstr(&a, cases[i].a); - strbuf_addstr(&b, cases[i].b); - EXPECT(common_prefix_size(&a, &b) == cases[i].want); - - strbuf_release(&a); - strbuf_release(&b); - } -} - -static void set_hash(uint8_t *h, int j) -{ - int i = 0; - for (i = 0; i < hash_size(GIT_SHA1_FORMAT_ID); i++) { - h[i] = (j >> i) & 0xff; - } -} - -static void test_reftable_ref_record_roundtrip(void) -{ - struct strbuf scratch = STRBUF_INIT; - int i = 0; - - for (i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) { - struct reftable_record in = { - .type = BLOCK_TYPE_REF, - }; - struct reftable_record out = { .type = BLOCK_TYPE_REF }; - struct strbuf key = STRBUF_INIT; - uint8_t buffer[1024] = { 0 }; - struct string_view dest = { - .buf = buffer, - .len = sizeof(buffer), - }; - int n, m; - - in.u.ref.value_type = i; - switch (i) { - case REFTABLE_REF_DELETION: - break; - case REFTABLE_REF_VAL1: - set_hash(in.u.ref.value.val1, 1); - break; - case REFTABLE_REF_VAL2: - set_hash(in.u.ref.value.val2.value, 1); - set_hash(in.u.ref.value.val2.target_value, 2); - break; - case REFTABLE_REF_SYMREF: - in.u.ref.value.symref = xstrdup("target"); - break; - } - in.u.ref.refname = xstrdup("refs/heads/master"); - - test_copy(&in); - - EXPECT(reftable_record_val_type(&in) == i); - - reftable_record_key(&in, &key); - n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); - EXPECT(n > 0); - - /* decode into a non-zero reftable_record to test for leaks. */ - m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ, &scratch); - EXPECT(n == m); - - EXPECT(reftable_ref_record_equal(&in.u.ref, &out.u.ref, - GIT_SHA1_RAWSZ)); - reftable_record_release(&in); - - strbuf_release(&key); - reftable_record_release(&out); - } - - strbuf_release(&scratch); -} - -static void test_reftable_log_record_equal(void) -{ - struct reftable_log_record in[2] = { - { - .refname = xstrdup("refs/heads/master"), - .update_index = 42, - }, - { - .refname = xstrdup("refs/heads/master"), - .update_index = 22, - } - }; - - EXPECT(!reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); - in[1].update_index = in[0].update_index; - EXPECT(reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); - reftable_log_record_release(&in[0]); - reftable_log_record_release(&in[1]); -} - -static void test_reftable_log_record_roundtrip(void) -{ - int i; - struct reftable_log_record in[] = { - { - .refname = xstrdup("refs/heads/master"), - .update_index = 42, - .value_type = REFTABLE_LOG_UPDATE, - .value = { - .update = { - .name = xstrdup("han-wen"), - .email = xstrdup("hanwen@google.com"), - .message = xstrdup("test"), - .time = 1577123507, - .tz_offset = 100, - }, - } - }, - { - .refname = xstrdup("refs/heads/master"), - .update_index = 22, - .value_type = REFTABLE_LOG_DELETION, - }, - { - .refname = xstrdup("branch"), - .update_index = 33, - .value_type = REFTABLE_LOG_UPDATE, - } - }; - struct strbuf scratch = STRBUF_INIT; - - set_test_hash(in[0].value.update.new_hash, 1); - set_test_hash(in[0].value.update.old_hash, 2); - set_test_hash(in[2].value.update.new_hash, 3); - set_test_hash(in[2].value.update.old_hash, 4); - for (i = 0; i < ARRAY_SIZE(in); i++) { - struct reftable_record rec = { .type = BLOCK_TYPE_LOG }; - struct strbuf key = STRBUF_INIT; - uint8_t buffer[1024] = { 0 }; - struct string_view dest = { - .buf = buffer, - .len = sizeof(buffer), - }; - /* populate out, to check for leaks. */ - struct reftable_record out = { - .type = BLOCK_TYPE_LOG, - .u.log = { - .refname = xstrdup("old name"), - .value_type = REFTABLE_LOG_UPDATE, - .value = { - .update = { - .name = xstrdup("old name"), - .email = xstrdup("old@email"), - .message = xstrdup("old message"), - }, - }, - }, - }; - int n, m, valtype; - - rec.u.log = in[i]; - - test_copy(&rec); - - reftable_record_key(&rec, &key); - - n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ); - EXPECT(n >= 0); - valtype = reftable_record_val_type(&rec); - m = reftable_record_decode(&out, key, valtype, dest, - GIT_SHA1_RAWSZ, &scratch); - EXPECT(n == m); - - EXPECT(reftable_log_record_equal(&in[i], &out.u.log, - GIT_SHA1_RAWSZ)); - reftable_log_record_release(&in[i]); - strbuf_release(&key); - reftable_record_release(&out); - } - - strbuf_release(&scratch); -} - -static void test_u24_roundtrip(void) -{ - uint32_t in = 0x112233; - uint8_t dest[3]; - uint32_t out; - put_be24(dest, in); - out = get_be24(dest); - EXPECT(in == out); -} - -static void test_key_roundtrip(void) -{ - uint8_t buffer[1024] = { 0 }; - struct string_view dest = { - .buf = buffer, - .len = sizeof(buffer), - }; - struct strbuf last_key = STRBUF_INIT; - struct strbuf key = STRBUF_INIT; - struct strbuf roundtrip = STRBUF_INIT; - int restart; - uint8_t extra; - int n, m; - uint8_t rt_extra; - - strbuf_addstr(&last_key, "refs/heads/master"); - strbuf_addstr(&key, "refs/tags/bla"); - extra = 6; - n = reftable_encode_key(&restart, dest, last_key, key, extra); - EXPECT(!restart); - EXPECT(n > 0); - - strbuf_addstr(&roundtrip, "refs/heads/master"); - m = reftable_decode_key(&roundtrip, &rt_extra, dest); - EXPECT(n == m); - EXPECT(0 == strbuf_cmp(&key, &roundtrip)); - EXPECT(rt_extra == extra); - - strbuf_release(&last_key); - strbuf_release(&key); - strbuf_release(&roundtrip); -} - -static void test_reftable_obj_record_roundtrip(void) -{ - uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 }; - uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 }; - struct reftable_obj_record recs[3] = { - { - .hash_prefix = testHash1, - .hash_prefix_len = 5, - .offsets = till9, - .offset_len = 3, - }, - { - .hash_prefix = testHash1, - .hash_prefix_len = 5, - .offsets = till9, - .offset_len = 9, - }, - { - .hash_prefix = testHash1, - .hash_prefix_len = 5, - }, - }; - struct strbuf scratch = STRBUF_INIT; - int i = 0; - - for (i = 0; i < ARRAY_SIZE(recs); i++) { - uint8_t buffer[1024] = { 0 }; - struct string_view dest = { - .buf = buffer, - .len = sizeof(buffer), - }; - struct reftable_record in = { - .type = BLOCK_TYPE_OBJ, - .u = { - .obj = recs[i], - }, - }; - struct strbuf key = STRBUF_INIT; - struct reftable_record out = { .type = BLOCK_TYPE_OBJ }; - int n, m; - uint8_t extra; - - test_copy(&in); - reftable_record_key(&in, &key); - n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); - EXPECT(n > 0); - extra = reftable_record_val_type(&in); - m = reftable_record_decode(&out, key, extra, dest, - GIT_SHA1_RAWSZ, &scratch); - EXPECT(n == m); - - EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); - strbuf_release(&key); - reftable_record_release(&out); - } - - strbuf_release(&scratch); -} - -static void test_reftable_index_record_roundtrip(void) -{ - struct reftable_record in = { - .type = BLOCK_TYPE_INDEX, - .u.idx = { - .offset = 42, - .last_key = STRBUF_INIT, - }, - }; - uint8_t buffer[1024] = { 0 }; - struct string_view dest = { - .buf = buffer, - .len = sizeof(buffer), - }; - struct strbuf scratch = STRBUF_INIT; - struct strbuf key = STRBUF_INIT; - struct reftable_record out = { - .type = BLOCK_TYPE_INDEX, - .u.idx = { .last_key = STRBUF_INIT }, - }; - int n, m; - uint8_t extra; - - strbuf_addstr(&in.u.idx.last_key, "refs/heads/master"); - reftable_record_key(&in, &key); - test_copy(&in); - - EXPECT(0 == strbuf_cmp(&key, &in.u.idx.last_key)); - n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); - EXPECT(n > 0); - - extra = reftable_record_val_type(&in); - m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ, - &scratch); - EXPECT(m == n); - - EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); - - reftable_record_release(&out); - strbuf_release(&key); - strbuf_release(&scratch); - strbuf_release(&in.u.idx.last_key); -} - -int record_test_main(int argc, const char *argv[]) -{ - RUN_TEST(test_reftable_log_record_equal); - RUN_TEST(test_reftable_log_record_roundtrip); - RUN_TEST(test_reftable_ref_record_roundtrip); - RUN_TEST(test_varint_roundtrip); - RUN_TEST(test_key_roundtrip); - RUN_TEST(test_common_prefix); - RUN_TEST(test_reftable_obj_record_roundtrip); - RUN_TEST(test_reftable_index_record_roundtrip); - RUN_TEST(test_u24_roundtrip); - return 0; -} diff --git a/reftable/reftable-record.h b/reftable/reftable-record.h index 2a2943cd13..ff486eb1f7 100644 --- a/reftable/reftable-record.h +++ b/reftable/reftable-record.h @@ -9,7 +9,7 @@ https://developers.google.com/open-source/licenses/bsd #ifndef REFTABLE_RECORD_H #define REFTABLE_RECORD_H -#include "hash-ll.h" +#include "hash.h" #include <stdint.h> /* diff --git a/reftable/reftable-tests.h b/reftable/reftable-tests.h index d0abcc51e2..4b666810af 100644 --- a/reftable/reftable-tests.h +++ b/reftable/reftable-tests.h @@ -11,8 +11,6 @@ https://developers.google.com/open-source/licenses/bsd int basics_test_main(int argc, const char **argv); int block_test_main(int argc, const char **argv); -int merged_test_main(int argc, const char **argv); -int pq_test_main(int argc, const char **argv); int record_test_main(int argc, const char **argv); int readwrite_test_main(int argc, const char **argv); int stack_test_main(int argc, const char **argv); diff --git a/reftable/stack.c b/reftable/stack.c index 98ac9cf9f9..737591125e 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -221,7 +221,8 @@ static struct reftable_reader **stack_copy_readers(struct reftable_stack *st, return cur; } -static int reftable_stack_reload_once(struct reftable_stack *st, char **names, +static int reftable_stack_reload_once(struct reftable_stack *st, + const char **names, int reuse_open) { size_t cur_len = !st->merged ? 0 : st->merged->stack_len; @@ -239,7 +240,7 @@ static int reftable_stack_reload_once(struct reftable_stack *st, char **names, while (*names) { struct reftable_reader *rd = NULL; - char *name = *names++; + const char *name = *names++; /* this is linear; we assume compaction keeps the number of tables under control so this is not quadratic. */ @@ -278,10 +279,8 @@ static int reftable_stack_reload_once(struct reftable_stack *st, char **names, new_tables = NULL; st->readers_len = new_readers_len; - if (st->merged) { - merged_table_release(st->merged); + if (st->merged) reftable_merged_table_free(st->merged); - } if (st->readers) { reftable_free(st->readers); } @@ -371,7 +370,7 @@ static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st, goto out; } - err = reftable_stack_reload_once(st, names, reuse_open); + err = reftable_stack_reload_once(st, (const char **) names, reuse_open); if (!err) break; if (err != REFTABLE_NOT_EXIST_ERROR) @@ -385,7 +384,8 @@ static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st, err = read_lines(st->list_file, &names_after); if (err < 0) goto out; - if (names_equal(names_after, names)) { + if (names_equal((const char **) names_after, + (const char **) names)) { err = REFTABLE_NOT_EXIST_ERROR; goto out; } @@ -987,10 +987,8 @@ static int stack_write_compact(struct reftable_stack *st, done: reftable_iterator_destroy(&it); - if (mt) { - merged_table_release(mt); + if (mt) reftable_merged_table_free(mt); - } reftable_ref_record_release(&ref); reftable_log_record_release(&log); st->stats.entries_written += entries; diff --git a/reftable/stack_test.c b/reftable/stack_test.c index 0f7b1453e6..e3c11e6a6e 100644 --- a/reftable/stack_test.c +++ b/reftable/stack_test.c @@ -83,7 +83,7 @@ static void test_read_file(void) char out[1024] = "line1\n\nline2\nline3"; int n, err; char **names = NULL; - char *want[] = { "line1", "line2", "line3" }; + const char *want[] = { "line1", "line2", "line3" }; int i = 0; EXPECT(fd > 0); @@ -102,29 +102,6 @@ static void test_read_file(void) (void) remove(fn); } -static void test_parse_names(void) -{ - char buf[] = "line\n"; - char **names = NULL; - parse_names(buf, strlen(buf), &names); - - EXPECT(NULL != names[0]); - EXPECT(0 == strcmp(names[0], "line")); - EXPECT(NULL == names[1]); - free_names(names); -} - -static void test_names_equal(void) -{ - char *a[] = { "a", "b", "c", NULL }; - char *b[] = { "a", "b", "d", NULL }; - char *c[] = { "a", "b", NULL }; - - EXPECT(names_equal(a, a)); - EXPECT(!names_equal(a, b)); - EXPECT(!names_equal(a, c)); -} - static int write_test_ref(struct reftable_writer *wr, void *arg) { struct reftable_ref_record *ref = arg; @@ -156,10 +133,10 @@ static void test_reftable_stack_add_one(void) struct reftable_stack *st = NULL; int err; struct reftable_ref_record ref = { - .refname = "HEAD", + .refname = (char *) "HEAD", .update_index = 1, .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; struct reftable_ref_record dest = { NULL }; struct stat stat_result = { 0 }; @@ -216,16 +193,16 @@ static void test_reftable_stack_uptodate(void) int err; struct reftable_ref_record ref1 = { - .refname = "HEAD", + .refname = (char *) "HEAD", .update_index = 1, .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; struct reftable_ref_record ref2 = { - .refname = "branch2", + .refname = (char *) "branch2", .update_index = 2, .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; @@ -263,10 +240,10 @@ static void test_reftable_stack_transaction_api(void) struct reftable_addition *add = NULL; struct reftable_ref_record ref = { - .refname = "HEAD", + .refname = (char *) "HEAD", .update_index = 1, .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; struct reftable_ref_record dest = { NULL }; @@ -311,7 +288,7 @@ static void test_reftable_stack_transaction_api_performs_auto_compaction(void) struct reftable_ref_record ref = { .update_index = reftable_stack_next_update_index(st), .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; char name[100]; @@ -354,7 +331,7 @@ static void test_reftable_stack_transaction_api_performs_auto_compaction(void) static void test_reftable_stack_auto_compaction_fails_gracefully(void) { struct reftable_ref_record ref = { - .refname = "refs/heads/master", + .refname = (char *) "refs/heads/master", .update_index = 1, .value_type = REFTABLE_REF_VAL1, .value.val1 = {0x01}, @@ -406,16 +383,16 @@ static void test_reftable_stack_update_index_check(void) struct reftable_stack *st = NULL; int err; struct reftable_ref_record ref1 = { - .refname = "name1", + .refname = (char *) "name1", .update_index = 1, .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; struct reftable_ref_record ref2 = { - .refname = "name2", + .refname = (char *) "name2", .update_index = 1, .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; err = reftable_new_stack(&st, dir, &opts); @@ -557,7 +534,7 @@ static void test_reftable_stack_log_normalize(void) struct reftable_stack *st = NULL; char *dir = get_tmp_dir(__LINE__); struct reftable_log_record input = { - .refname = "branch", + .refname = (char *) "branch", .update_index = 1, .value_type = REFTABLE_LOG_UPDATE, .value = { @@ -578,11 +555,11 @@ static void test_reftable_stack_log_normalize(void) err = reftable_new_stack(&st, dir, &opts); EXPECT_ERR(err); - input.value.update.message = "one\ntwo"; + input.value.update.message = (char *) "one\ntwo"; err = reftable_stack_add(st, &write_test_log, &arg); EXPECT(err == REFTABLE_API_ERROR); - input.value.update.message = "one"; + input.value.update.message = (char *) "one"; err = reftable_stack_add(st, &write_test_log, &arg); EXPECT_ERR(err); @@ -590,7 +567,7 @@ static void test_reftable_stack_log_normalize(void) EXPECT_ERR(err); EXPECT(0 == strcmp(dest.value.update.message, "one\n")); - input.value.update.message = "two\n"; + input.value.update.message = (char *) "two\n"; arg.update_index = 2; err = reftable_stack_add(st, &write_test_log, &arg); EXPECT_ERR(err); @@ -690,9 +667,9 @@ static void test_reftable_stack_hash_id(void) int err; struct reftable_ref_record ref = { - .refname = "master", + .refname = (char *) "master", .value_type = REFTABLE_REF_SYMREF, - .value.symref = "target", + .value.symref = (char *) "target", .update_index = 1, }; struct reftable_write_options opts32 = { .hash_id = GIT_SHA256_FORMAT_ID }; @@ -867,7 +844,7 @@ static void test_reftable_stack_auto_compaction(void) .refname = name, .update_index = reftable_stack_next_update_index(st), .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; snprintf(name, sizeof(name), "branch%04d", i); @@ -901,7 +878,7 @@ static void test_reftable_stack_add_performs_auto_compaction(void) struct reftable_ref_record ref = { .update_index = reftable_stack_next_update_index(st), .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; /* @@ -951,7 +928,7 @@ static void test_reftable_stack_compaction_concurrent(void) .refname = name, .update_index = reftable_stack_next_update_index(st1), .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; snprintf(name, sizeof(name), "branch%04d", i); @@ -1000,7 +977,7 @@ static void test_reftable_stack_compaction_concurrent_clean(void) .refname = name, .update_index = reftable_stack_next_update_index(st1), .value_type = REFTABLE_REF_SYMREF, - .value.symref = "master", + .value.symref = (char *) "master", }; snprintf(name, sizeof(name), "branch%04d", i); @@ -1034,8 +1011,6 @@ static void test_reftable_stack_compaction_concurrent_clean(void) int stack_test_main(int argc, const char *argv[]) { RUN_TEST(test_empty_add); - RUN_TEST(test_names_equal); - RUN_TEST(test_parse_names); RUN_TEST(test_read_file); RUN_TEST(test_reflog_expire); RUN_TEST(test_reftable_stack_add); diff --git a/reftable/system.h b/reftable/system.h index 5d8b6dede5..d0cabd5d17 100644 --- a/reftable/system.h +++ b/reftable/system.h @@ -15,7 +15,7 @@ https://developers.google.com/open-source/licenses/bsd #include "lockfile.h" #include "strbuf.h" #include "tempfile.h" -#include "hash-ll.h" /* hash ID, sizes.*/ +#include "hash.h" /* hash ID, sizes.*/ #include "dir.h" /* remove_dir_recursively, for tests.*/ int hash_size(uint32_t id); diff --git a/remote-curl.c b/remote-curl.c index 6008d7e87c..4adcf25ed6 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "git-curl-compat.h" #include "config.h" @@ -58,9 +60,9 @@ struct options { static struct options options; static struct string_list cas_options = STRING_LIST_INIT_DUP; -static int set_option(const char *name, const char *value) +static int set_option(const char *name, size_t namelen, const char *value) { - if (!strcmp(name, "verbosity")) { + if (!strncmp(name, "verbosity", namelen)) { char *end; int v = strtol(value, &end, 10); if (value == end || *end) @@ -68,7 +70,7 @@ static int set_option(const char *name, const char *value) options.verbosity = v; return 0; } - else if (!strcmp(name, "progress")) { + else if (!strncmp(name, "progress", namelen)) { if (!strcmp(value, "true")) options.progress = 1; else if (!strcmp(value, "false")) @@ -77,7 +79,7 @@ static int set_option(const char *name, const char *value) return -1; return 0; } - else if (!strcmp(name, "depth")) { + else if (!strncmp(name, "depth", namelen)) { char *end; unsigned long v = strtoul(value, &end, 10); if (value == end || *end) @@ -85,15 +87,15 @@ static int set_option(const char *name, const char *value) options.depth = v; return 0; } - else if (!strcmp(name, "deepen-since")) { + else if (!strncmp(name, "deepen-since", namelen)) { options.deepen_since = xstrdup(value); return 0; } - else if (!strcmp(name, "deepen-not")) { + else if (!strncmp(name, "deepen-not", namelen)) { string_list_append(&options.deepen_not, value); return 0; } - else if (!strcmp(name, "deepen-relative")) { + else if (!strncmp(name, "deepen-relative", namelen)) { if (!strcmp(value, "true")) options.deepen_relative = 1; else if (!strcmp(value, "false")) @@ -102,7 +104,7 @@ static int set_option(const char *name, const char *value) return -1; return 0; } - else if (!strcmp(name, "followtags")) { + else if (!strncmp(name, "followtags", namelen)) { if (!strcmp(value, "true")) options.followtags = 1; else if (!strcmp(value, "false")) @@ -111,7 +113,7 @@ static int set_option(const char *name, const char *value) return -1; return 0; } - else if (!strcmp(name, "dry-run")) { + else if (!strncmp(name, "dry-run", namelen)) { if (!strcmp(value, "true")) options.dry_run = 1; else if (!strcmp(value, "false")) @@ -120,7 +122,7 @@ static int set_option(const char *name, const char *value) return -1; return 0; } - else if (!strcmp(name, "check-connectivity")) { + else if (!strncmp(name, "check-connectivity", namelen)) { if (!strcmp(value, "true")) options.check_self_contained_and_connected = 1; else if (!strcmp(value, "false")) @@ -129,7 +131,7 @@ static int set_option(const char *name, const char *value) return -1; return 0; } - else if (!strcmp(name, "cas")) { + else if (!strncmp(name, "cas", namelen)) { struct strbuf val = STRBUF_INIT; strbuf_addstr(&val, "--force-with-lease="); if (*value != '"') @@ -139,7 +141,7 @@ static int set_option(const char *name, const char *value) string_list_append(&cas_options, val.buf); strbuf_release(&val); return 0; - } else if (!strcmp(name, TRANS_OPT_FORCE_IF_INCLUDES)) { + } else if (!strncmp(name, TRANS_OPT_FORCE_IF_INCLUDES, namelen)) { if (!strcmp(value, "true")) options.force_if_includes = 1; else if (!strcmp(value, "false")) @@ -147,7 +149,7 @@ static int set_option(const char *name, const char *value) else return -1; return 0; - } else if (!strcmp(name, "cloning")) { + } else if (!strncmp(name, "cloning", namelen)) { if (!strcmp(value, "true")) options.cloning = 1; else if (!strcmp(value, "false")) @@ -155,7 +157,7 @@ static int set_option(const char *name, const char *value) else return -1; return 0; - } else if (!strcmp(name, "update-shallow")) { + } else if (!strncmp(name, "update-shallow", namelen)) { if (!strcmp(value, "true")) options.update_shallow = 1; else if (!strcmp(value, "false")) @@ -163,7 +165,7 @@ static int set_option(const char *name, const char *value) else return -1; return 0; - } else if (!strcmp(name, "pushcert")) { + } else if (!strncmp(name, "pushcert", namelen)) { if (!strcmp(value, "true")) options.push_cert = SEND_PACK_PUSH_CERT_ALWAYS; else if (!strcmp(value, "false")) @@ -173,7 +175,7 @@ static int set_option(const char *name, const char *value) else return -1; return 0; - } else if (!strcmp(name, "atomic")) { + } else if (!strncmp(name, "atomic", namelen)) { if (!strcmp(value, "true")) options.atomic = 1; else if (!strcmp(value, "false")) @@ -181,7 +183,7 @@ static int set_option(const char *name, const char *value) else return -1; return 0; - } else if (!strcmp(name, "push-option")) { + } else if (!strncmp(name, "push-option", namelen)) { if (*value != '"') string_list_append(&options.push_options, value); else { @@ -192,7 +194,7 @@ static int set_option(const char *name, const char *value) strbuf_detach(&unquoted, NULL)); } return 0; - } else if (!strcmp(name, "family")) { + } else if (!strncmp(name, "family", namelen)) { if (!strcmp(value, "ipv4")) git_curl_ipresolve = CURL_IPRESOLVE_V4; else if (!strcmp(value, "ipv6")) @@ -202,16 +204,16 @@ static int set_option(const char *name, const char *value) else return -1; return 0; - } else if (!strcmp(name, "from-promisor")) { + } else if (!strncmp(name, "from-promisor", namelen)) { options.from_promisor = 1; return 0; - } else if (!strcmp(name, "refetch")) { + } else if (!strncmp(name, "refetch", namelen)) { options.refetch = 1; return 0; - } else if (!strcmp(name, "filter")) { + } else if (!strncmp(name, "filter", namelen)) { options.filter = xstrdup(value); return 0; - } else if (!strcmp(name, "object-format")) { + } else if (!strncmp(name, "object-format", namelen)) { options.object_format = 1; if (strcmp(value, "true")) die(_("unknown value for object-format: %s"), value); @@ -1574,7 +1576,7 @@ int cmd_main(int argc, const char **argv) if (argc > 2) { end_url_with_slash(&url, argv[2]); } else { - end_url_with_slash(&url, remote->url[0]); + end_url_with_slash(&url, remote->url.v[0]); } http_init(remote, url.buf, 0); @@ -1605,15 +1607,16 @@ int cmd_main(int argc, const char **argv) parse_push(&buf); } else if (skip_prefix(buf.buf, "option ", &arg)) { - char *value = strchr(arg, ' '); + const char *value = strchrnul(arg, ' '); + size_t arglen = value - arg; int result; - if (value) - *value++ = '\0'; + if (*value) + value++; /* skip over SP */ else value = "true"; - result = set_option(arg, value); + result = set_option(arg, arglen, value); if (!result) printf("ok\n"); else if (result < 0) @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "config.h" @@ -32,10 +34,10 @@ struct counted_string { static int valid_remote(const struct remote *remote) { - return (!!remote->url) || (!!remote->foreign_vcs); + return !!remote->url.nr; } -static const char *alias_url(const char *url, struct rewrites *r) +static char *alias_url(const char *url, struct rewrites *r) { int i, j; struct counted_string *longest; @@ -56,36 +58,43 @@ static const char *alias_url(const char *url, struct rewrites *r) } } if (!longest) - return url; + return NULL; return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len); } static void add_url(struct remote *remote, const char *url) { - ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); - remote->url[remote->url_nr++] = url; + if (*url) + strvec_push(&remote->url, url); + else + strvec_clear(&remote->url); } static void add_pushurl(struct remote *remote, const char *pushurl) { - ALLOC_GROW(remote->pushurl, remote->pushurl_nr + 1, remote->pushurl_alloc); - remote->pushurl[remote->pushurl_nr++] = pushurl; + if (*pushurl) + strvec_push(&remote->pushurl, pushurl); + else + strvec_clear(&remote->pushurl); } static void add_pushurl_alias(struct remote_state *remote_state, struct remote *remote, const char *url) { - const char *pushurl = alias_url(url, &remote_state->rewrites_push); - if (pushurl != url) - add_pushurl(remote, pushurl); + char *alias = alias_url(url, &remote_state->rewrites_push); + if (alias) + add_pushurl(remote, alias); + free(alias); } static void add_url_alias(struct remote_state *remote_state, struct remote *remote, const char *url) { - add_url(remote, alias_url(url, &remote_state->rewrites)); + char *alias = alias_url(url, &remote_state->rewrites); + add_url(remote, alias ? alias : url); add_pushurl_alias(remote_state, remote, url); + free(alias); } struct remotes_hash_key { @@ -147,18 +156,12 @@ static struct remote *make_remote(struct remote_state *remote_state, static void remote_clear(struct remote *remote) { - int i; - free((char *)remote->name); free((char *)remote->foreign_vcs); - for (i = 0; i < remote->url_nr; i++) - free((char *)remote->url[i]); - FREE_AND_NULL(remote->url); + strvec_clear(&remote->url); + strvec_clear(&remote->pushurl); - for (i = 0; i < remote->pushurl_nr; i++) - free((char *)remote->pushurl[i]); - FREE_AND_NULL(remote->pushurl); free((char *)remote->receivepack); free((char *)remote->uploadpack); FREE_AND_NULL(remote->http_proxy); @@ -292,7 +295,7 @@ static void read_remotes_file(struct remote_state *remote_state, if (skip_prefix(buf.buf, "URL:", &v)) add_url_alias(remote_state, remote, - xstrdup(skip_spaces(v))); + skip_spaces(v)); else if (skip_prefix(buf.buf, "Push:", &v)) refspec_append(&remote->push, skip_spaces(v)); else if (skip_prefix(buf.buf, "Pull:", &v)) @@ -335,7 +338,7 @@ static void read_branches_file(struct remote_state *remote_state, else frag = to_free = repo_default_branch_name(the_repository, 0); - add_url_alias(remote_state, remote, strbuf_detach(&buf, NULL)); + add_url_alias(remote_state, remote, buf.buf); refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s", frag, remote->name); @@ -346,6 +349,7 @@ static void read_branches_file(struct remote_state *remote_state, refspec_appendf(&remote->push, "HEAD:refs/heads/%s", frag); remote->fetch_tags = 1; /* always auto-follow */ + strbuf_release(&buf); free(to_free); } @@ -430,15 +434,13 @@ static int handle_config(const char *key, const char *value, else if (!strcmp(subkey, "prunetags")) remote->prune_tags = git_config_bool(key, value); else if (!strcmp(subkey, "url")) { - char *v; - if (git_config_string(&v, key, value)) - return -1; - add_url(remote, v); + if (!value) + return config_error_nonbool(key); + add_url(remote, value); } else if (!strcmp(subkey, "pushurl")) { - char *v; - if (git_config_string(&v, key, value)) - return -1; - add_pushurl(remote, v); + if (!value) + return config_error_nonbool(key); + add_pushurl(remote, value); } else if (!strcmp(subkey, "push")) { char *v; if (git_config_string(&v, key, value)) @@ -491,20 +493,25 @@ static void alias_all_urls(struct remote_state *remote_state) int add_pushurl_aliases; if (!remote_state->remotes[i]) continue; - for (j = 0; j < remote_state->remotes[i]->pushurl_nr; j++) { - remote_state->remotes[i]->pushurl[j] = - alias_url(remote_state->remotes[i]->pushurl[j], - &remote_state->rewrites); + for (j = 0; j < remote_state->remotes[i]->pushurl.nr; j++) { + char *alias = alias_url(remote_state->remotes[i]->pushurl.v[j], + &remote_state->rewrites); + if (alias) + strvec_replace(&remote_state->remotes[i]->pushurl, + j, alias); } - add_pushurl_aliases = remote_state->remotes[i]->pushurl_nr == 0; - for (j = 0; j < remote_state->remotes[i]->url_nr; j++) { + add_pushurl_aliases = remote_state->remotes[i]->pushurl.nr == 0; + for (j = 0; j < remote_state->remotes[i]->url.nr; j++) { + char *alias; if (add_pushurl_aliases) add_pushurl_alias( remote_state, remote_state->remotes[i], - remote_state->remotes[i]->url[j]); - remote_state->remotes[i]->url[j] = - alias_url(remote_state->remotes[i]->url[j], + remote_state->remotes[i]->url.v[j]); + alias = alias_url(remote_state->remotes[i]->url.v[j], &remote_state->rewrites); + if (alias) + strvec_replace(&remote_state->remotes[i]->url, + j, alias); } } } @@ -644,10 +651,10 @@ static void validate_remote_url(struct remote *remote) else die(_("unrecognized value transfer.credentialsInUrl: '%s'"), value); - for (i = 0; i < remote->url_nr; i++) { + for (i = 0; i < remote->url.nr; i++) { struct url_info url_info = { 0 }; - if (!url_normalize(remote->url[i], &url_info) || + if (!url_normalize(remote->url.v[i], &url_info) || !url_info.passwd_off) goto loop_cleanup; @@ -821,13 +828,18 @@ struct ref *ref_remove_duplicates(struct ref *ref_map) int remote_has_url(struct remote *remote, const char *url) { int i; - for (i = 0; i < remote->url_nr; i++) { - if (!strcmp(remote->url[i], url)) + for (i = 0; i < remote->url.nr; i++) { + if (!strcmp(remote->url.v[i], url)) return 1; } return 0; } +struct strvec *push_url_of_remote(struct remote *remote) +{ + return remote->pushurl.nr ? &remote->pushurl : &remote->url; +} + static int match_name_with_pattern(const char *key, const char *name, const char *value, char **result) { @@ -1164,7 +1176,7 @@ static void tail_link_ref(struct ref *ref, struct ref ***tail) static struct ref *alloc_delete_ref(void) { struct ref *ref = alloc_ref("(delete)"); - oidclr(&ref->new_oid); + oidclr(&ref->new_oid, the_repository->hash_algo); return ref; } @@ -2531,7 +2543,7 @@ static int parse_push_cas_option(struct push_cas_option *cas, const char *arg, i if (!*colon) entry->use_tracking = 1; else if (!colon[1]) - oidclr(&entry->expect); + oidclr(&entry->expect, the_repository->hash_algo); else if (repo_get_oid(the_repository, colon + 1, &entry->expect)) return error(_("cannot parse expected object name '%s'"), colon + 1); @@ -2733,7 +2745,7 @@ static void apply_cas(struct push_cas_option *cas, else if (remote_tracking(remote, ref->name, &ref->old_oid_expect, &ref->tracking_ref)) - oidclr(&ref->old_oid_expect); + oidclr(&ref->old_oid_expect, the_repository->hash_algo); else ref->check_reachable = cas->use_force_if_includes; return; @@ -2747,7 +2759,7 @@ static void apply_cas(struct push_cas_option *cas, if (remote_tracking(remote, ref->name, &ref->old_oid_expect, &ref->tracking_ref)) - oidclr(&ref->old_oid_expect); + oidclr(&ref->old_oid_expect, the_repository->hash_algo); else ref->check_reachable = cas->use_force_if_includes; } @@ -1,9 +1,10 @@ #ifndef REMOTE_H #define REMOTE_H -#include "hash-ll.h" +#include "hash.h" #include "hashmap.h" #include "refspec.h" +#include "strvec.h" struct option; struct transport_ls_refs_options; @@ -68,16 +69,9 @@ struct remote { char *foreign_vcs; /* An array of all of the url_nr URLs configured for the remote */ - const char **url; - - int url_nr; - int url_alloc; - + struct strvec url; /* An array of all of the pushurl_nr push URLs configured for the remote */ - const char **pushurl; - - int pushurl_nr; - int pushurl_alloc; + struct strvec pushurl; struct refspec push; @@ -129,6 +123,7 @@ typedef int each_remote_fn(struct remote *remote, void *priv); int for_each_remote(each_remote_fn fn, void *priv); int remote_has_url(struct remote *remote, const char *url); +struct strvec *push_url_of_remote(struct remote *remote); struct ref_push_report { const char *ref_name; @@ -200,7 +195,7 @@ struct ref { }; #define REF_NORMAL (1u << 0) -#define REF_HEADS (1u << 1) +#define REF_BRANCHES (1u << 1) #define REF_TAGS (1u << 2) struct ref *find_ref_by_name(const struct ref *list, const char *name); diff --git a/replace-object.c b/replace-object.c index 73f5acbcd9..59252d565e 100644 --- a/replace-object.c +++ b/replace-object.c @@ -20,7 +20,7 @@ static int register_replace_ref(const char *refname, const char *hash = slash ? slash + 1 : refname; struct replace_object *repl_obj = xmalloc(sizeof(*repl_obj)); - if (get_oid_hex(hash, &repl_obj->original.oid)) { + if (get_oid_hex_algop(hash, &repl_obj->original.oid, r->hash_algo)) { free(repl_obj); warning(_("bad replace ref name: %s"), refname); return 0; diff --git a/repo-settings.c b/repo-settings.c index a0b590bc6c..2b4e68731b 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -23,6 +23,7 @@ void prepare_repo_settings(struct repository *r) int value; const char *strval; int manyfiles; + int read_changed_paths; if (!r->gitdir) BUG("Cannot add settings for uninitialized repository"); @@ -54,7 +55,10 @@ void prepare_repo_settings(struct repository *r) /* Commit graph config or default, does not cascade (simple) */ repo_cfg_bool(r, "core.commitgraph", &r->settings.core_commit_graph, 1); repo_cfg_int(r, "commitgraph.generationversion", &r->settings.commit_graph_generation_version, 2); - repo_cfg_bool(r, "commitgraph.readchangedpaths", &r->settings.commit_graph_read_changed_paths, 1); + repo_cfg_bool(r, "commitgraph.readchangedpaths", &read_changed_paths, 1); + repo_cfg_int(r, "commitgraph.changedpathsversion", + &r->settings.commit_graph_changed_paths_version, + read_changed_paths ? -1 : 0); repo_cfg_bool(r, "gc.writecommitgraph", &r->settings.gc_write_commit_graph, 1); repo_cfg_bool(r, "fetch.writecommitgraph", &r->settings.fetch_write_commit_graph, 0); diff --git a/repository.c b/repository.c index deb68625e0..9825a30899 100644 --- a/repository.c +++ b/repository.c @@ -16,6 +16,14 @@ #include "promisor-remote.h" #include "refs.h" +/* + * We do not define `USE_THE_REPOSITORY_VARIABLE` in this file because we do + * not want to rely on functions that implicitly use `the_repository`. This + * means that the `extern` declaration of `the_repository` isn't visible here, + * which makes sparse unhappy. We thus declare it here. + */ +extern struct repository *the_repository; + /* The main repository */ static struct repository the_repo; struct repository *the_repository = &the_repo; @@ -148,7 +156,8 @@ void repo_set_compat_hash_algo(struct repository *repo, int algo) repo_read_loose_object_map(repo); } -void repo_set_ref_storage_format(struct repository *repo, unsigned int format) +void repo_set_ref_storage_format(struct repository *repo, + enum ref_storage_format format) { repo->ref_storage_format = format; } diff --git a/repository.h b/repository.h index 4bd8969005..af6ea0a62c 100644 --- a/repository.h +++ b/repository.h @@ -26,16 +26,18 @@ enum fetch_negotiation_setting { FETCH_NEGOTIATION_NOOP, }; -#define REF_STORAGE_FORMAT_UNKNOWN 0 -#define REF_STORAGE_FORMAT_FILES 1 -#define REF_STORAGE_FORMAT_REFTABLE 2 +enum ref_storage_format { + REF_STORAGE_FORMAT_UNKNOWN, + REF_STORAGE_FORMAT_FILES, + REF_STORAGE_FORMAT_REFTABLE, +}; struct repo_settings { int initialized; int core_commit_graph; int commit_graph_generation_version; - int commit_graph_read_changed_paths; + int commit_graph_changed_paths_version; int gc_write_commit_graph; int fetch_write_commit_graph; int command_requires_full_index; @@ -181,7 +183,7 @@ struct repository { const struct git_hash_algo *compat_hash_algo; /* Repository's reference storage format, as serialized on disk. */ - unsigned int ref_storage_format; + enum ref_storage_format ref_storage_format; /* A unique-id for tracing purposes. */ int trace2_repo_id; @@ -200,7 +202,9 @@ struct repository { unsigned different_commondir:1; }; +#ifdef USE_THE_REPOSITORY_VARIABLE extern struct repository *the_repository; +#endif /* * Define a custom repository layout. Any field can be NULL, which @@ -220,7 +224,8 @@ void repo_set_gitdir(struct repository *repo, const char *root, void repo_set_worktree(struct repository *repo, const char *path); void repo_set_hash_algo(struct repository *repo, int algo); void repo_set_compat_hash_algo(struct repository *repo, int compat_algo); -void repo_set_ref_storage_format(struct repository *repo, unsigned int format); +void repo_set_ref_storage_format(struct repository *repo, + enum ref_storage_format format); void initialize_repository(struct repository *repo); RESULT_MUST_BE_USED int repo_init(struct repository *r, const char *gitdir, const char *worktree); @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "config.h" @@ -849,6 +851,8 @@ static int do_plain_rerere(struct repository *r, if (update.nr) update_paths(r, &update); + string_list_clear(&conflict, 0); + string_list_clear(&update, 0); return write_rr(rr, fd); } @@ -912,6 +916,7 @@ int repo_rerere(struct repository *r, int flags) return 0; status = do_plain_rerere(r, &merge_rr, fd); free_rerere_dirs(); + string_list_clear(&merge_rr, 1); return status; } @@ -1102,7 +1107,7 @@ fail_exit: int rerere_forget(struct repository *r, struct pathspec *pathspec) { - int i, fd; + int i, fd, ret; struct string_list conflict = STRING_LIST_INIT_DUP; struct string_list merge_rr = STRING_LIST_INIT_DUP; @@ -1127,7 +1132,12 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec) continue; rerere_forget_one_path(r->index, it->string, &merge_rr); } - return write_rr(&merge_rr, fd); + + ret = write_rr(&merge_rr, fd); + + string_list_clear(&conflict, 0); + string_list_clear(&merge_rr, 1); + return ret; } /* @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "cache-tree.h" #include "gettext.h" @@ -1,7 +1,7 @@ #ifndef RESET_H #define RESET_H -#include "hash-ll.h" +#include "hash.h" #include "repository.h" #define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION" diff --git a/resolve-undo.c b/resolve-undo.c index cd02dc9928..8c9911affb 100644 --- a/resolve-undo.c +++ b/resolve-undo.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "dir.h" #include "hash.h" @@ -93,7 +95,8 @@ struct string_list *resolve_undo_read(const char *data, unsigned long size) continue; if (size < rawsz) goto error; - oidread(&ui->oid[i], (const unsigned char *)data); + oidread(&ui->oid[i], (const unsigned char *)data, + the_repository->hash_algo); size -= rawsz; data += rawsz; } diff --git a/resolve-undo.h b/resolve-undo.h index f3f8462751..89a3227262 100644 --- a/resolve-undo.h +++ b/resolve-undo.h @@ -6,7 +6,7 @@ struct index_state; struct pathspec; struct string_list; -#include "hash-ll.h" +#include "hash.h" struct resolve_undo_info { unsigned int mode[3]; diff --git a/revision.c b/revision.c index 7ddf0f151a..1c0192f522 100644 --- a/revision.c +++ b/revision.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "environment.h" @@ -29,6 +31,7 @@ #include "bisect.h" #include "packfile.h" #include "worktree.h" +#include "path.h" #include "read-cache.h" #include "setup.h" #include "sparse-index.h" @@ -844,17 +847,28 @@ static int rev_compare_tree(struct rev_info *revs, return tree_difference; } -static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit) +static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit, + int nth_parent) { struct tree *t1 = repo_get_commit_tree(the_repository, commit); + int bloom_ret = -1; if (!t1) return 0; + if (!nth_parent && revs->bloom_keys_nr) { + bloom_ret = check_maybe_different_in_bloom_filter(revs, commit); + if (!bloom_ret) + return 1; + } + tree_difference = REV_TREE_SAME; revs->pruning.flags.has_changes = 0; diff_tree_oid(NULL, &t1->object.oid, "", &revs->pruning); + if (bloom_ret == 1 && tree_difference == REV_TREE_SAME) + count_bloom_filter_false_positive++; + return tree_difference == REV_TREE_SAME; } @@ -892,7 +906,7 @@ static int compact_treesame(struct rev_info *revs, struct commit *commit, unsign if (nth_parent != 0) die("compact_treesame %u", nth_parent); old_same = !!(commit->object.flags & TREESAME); - if (rev_same_tree_as_empty(revs, commit)) + if (rev_same_tree_as_empty(revs, commit, nth_parent)) commit->object.flags |= TREESAME; else commit->object.flags &= ~TREESAME; @@ -988,7 +1002,14 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) return; if (!commit->parents) { - if (rev_same_tree_as_empty(revs, commit)) + /* + * Pretend as if we are comparing ourselves to the + * (non-existent) first parent of this commit object. Even + * though no such parent exists, its changed-path Bloom filter + * (if one exists) is relative to the empty tree, using Bloom + * filters is allowed here. + */ + if (rev_same_tree_as_empty(revs, commit, 0)) commit->object.flags |= TREESAME; return; } @@ -1069,7 +1090,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) case REV_TREE_NEW: if (revs->remove_empty_trees && - rev_same_tree_as_empty(revs, p)) { + rev_same_tree_as_empty(revs, p, nth_parent)) { /* We are adding all the specified * paths from this parent, so the * history beyond this parent is not @@ -2130,30 +2151,26 @@ static int handle_dotdot(const char *arg, struct rev_info *revs, int flags, int cant_be_filename) { - struct object_context a_oc, b_oc; + struct object_context a_oc = {0}, b_oc = {0}; char *dotdot = strstr(arg, ".."); int ret; if (!dotdot) return -1; - memset(&a_oc, 0, sizeof(a_oc)); - memset(&b_oc, 0, sizeof(b_oc)); - *dotdot = '\0'; ret = handle_dotdot_1(arg, dotdot, revs, flags, cant_be_filename, &a_oc, &b_oc); *dotdot = '.'; - free(a_oc.path); - free(b_oc.path); - + object_context_release(&a_oc); + object_context_release(&b_oc); return ret; } static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt) { - struct object_context oc; + struct object_context oc = {0}; char *mark; struct object *object; struct object_id oid; @@ -2161,6 +2178,7 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl const char *arg = arg_; int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME; unsigned get_sha1_flags = GET_OID_RECORD_PATH; + int ret; flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM; @@ -2169,17 +2187,22 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl * Just ".."? That is not a range but the * pathspec for the parent directory. */ - return -1; + ret = -1; + goto out; } - if (!handle_dotdot(arg, revs, flags, revarg_opt)) - return 0; + if (!handle_dotdot(arg, revs, flags, revarg_opt)) { + ret = 0; + goto out; + } mark = strstr(arg, "^@"); if (mark && !mark[2]) { *mark = 0; - if (add_parents_only(revs, arg, flags, 0)) - return 0; + if (add_parents_only(revs, arg, flags, 0)) { + ret = 0; + goto out; + } *mark = '^'; } mark = strstr(arg, "^!"); @@ -2194,8 +2217,10 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl if (mark[2]) { if (strtol_i(mark + 2, 10, &exclude_parent) || - exclude_parent < 1) - return -1; + exclude_parent < 1) { + ret = -1; + goto out; + } } *mark = 0; @@ -2217,17 +2242,25 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl * should error out if we can't even get an oid, as * `--missing=print` should be able to report missing oids. */ - if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc)) - return revs->ignore_missing ? 0 : -1; + if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc)) { + ret = revs->ignore_missing ? 0 : -1; + goto out; + } if (!cant_be_filename) verify_non_filename(revs->prefix, arg); object = get_reference(revs, arg, &oid, flags ^ local_flags); - if (!object) - return (revs->ignore_missing || revs->do_not_die_on_missing_objects) ? 0 : -1; + if (!object) { + ret = (revs->ignore_missing || revs->do_not_die_on_missing_objects) ? 0 : -1; + goto out; + } add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags); add_pending_object_with_path(revs, object, arg, oc.mode, oc.path); - free(oc.path); - return 0; + + ret = 0; + +out: + object_context_release(&oc); + return ret; } int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt) @@ -2650,10 +2683,11 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--invert-grep")) { revs->grep_filter.no_body_match = 1; } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) { + free(git_log_output_encoding); if (strcmp(optarg, "none")) git_log_output_encoding = xstrdup(optarg); else - git_log_output_encoding = ""; + git_log_output_encoding = xstrdup(""); return argcount; } else if (!strcmp(arg, "--reverse")) { revs->reverse ^= 1; @@ -3062,6 +3096,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s diagnose_missing_default(revs->def); object = get_reference(revs, revs->def, &oid, 0); add_pending_object_with_mode(revs, object, revs->def, oc.mode); + object_context_release(&oc); } /* Did the user ask for any diff output? Run the diff! */ @@ -3168,6 +3203,7 @@ void release_revisions(struct rev_info *revs) { free_commit_list(revs->commits); free_commit_list(revs->ancestry_path_bottoms); + release_display_notes(&revs->notes_opt); object_array_clear(&revs->pending); object_array_clear(&revs->boundary_commits); release_revisions_cmdline(&revs->cmdline); @@ -3177,7 +3213,7 @@ void release_revisions(struct rev_info *revs) release_revisions_mailmap(revs->mailmap); free_grep_patterns(&revs->grep_filter); graph_clear(revs->graph); - /* TODO (need to handle "no_free"): diff_free(&revs->diffopt) */ + diff_free(&revs->diffopt); diff_free(&revs->pruning); reflog_walk_info_release(revs->reflog_info); release_revisions_topo_walk_info(revs->topo_walk_info); @@ -4430,6 +4466,7 @@ struct commit *get_revision(struct rev_info *revs) reversed = NULL; while ((c = get_revision_internal(revs))) commit_list_insert(c, &reversed); + free_commit_list(revs->commits); revs->commits = reversed; revs->reverse = 0; revs->reverse_output_stage = 1; diff --git a/run-command.c b/run-command.c index 31b20123d8..45ba544932 100644 --- a/run-command.c +++ b/run-command.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "run-command.h" #include "environment.h" @@ -272,17 +274,24 @@ int sane_execvp(const char *file, char * const argv[]) return -1; } +char *git_shell_path(void) +{ +#ifndef GIT_WINDOWS_NATIVE + return xstrdup(SHELL_PATH); +#else + char *p = locate_in_PATH("sh"); + convert_slashes(p); + return p; +#endif +} + static const char **prepare_shell_cmd(struct strvec *out, const char **argv) { if (!argv[0]) BUG("shell command is empty"); if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) { -#ifndef GIT_WINDOWS_NATIVE - strvec_push(out, SHELL_PATH); -#else - strvec_push(out, "sh"); -#endif + strvec_push_nodup(out, git_shell_path()); strvec_push(out, "-c"); /* @@ -663,7 +672,7 @@ int start_command(struct child_process *cmd) int need_in, need_out, need_err; int fdin[2], fdout[2], fderr[2]; int failed_errno; - char *str; + const char *str; /* * In case of errors we must keep the promise to close FDs @@ -1756,7 +1765,8 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts) if (do_trace2) trace2_region_enter_printf(tr2_category, tr2_label, NULL, - "max:%d", opts->processes); + "max:%"PRIuMAX, + (uintmax_t)opts->processes); pp_init(&pp, opts, &pp_sig); while (1) { diff --git a/run-command.h b/run-command.h index 55f6631a2a..03e7222d8b 100644 --- a/run-command.h +++ b/run-command.h @@ -196,6 +196,11 @@ int is_executable(const char *name); int exists_in_PATH(const char *command); /** + * Return the path that is used to execute Unix shell command-lines. + */ +char *git_shell_path(void); + +/** * Start a sub-process. Takes a pointer to a `struct child_process` * that specifies the details and returns pipe FDs (if requested). * See below for details. @@ -2,6 +2,8 @@ * The Scalar command-line interface. */ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "gettext.h" @@ -70,6 +72,7 @@ static void setup_enlistment_directory(int argc, const char **argv, strbuf_release(&path); } +LAST_ARG_MUST_BE_NULL static int run_git(const char *arg, ...) { struct child_process cmd = CHILD_PROCESS_INIT; @@ -288,6 +291,7 @@ static int unregister_dir(void) } /* printf-style interface, expects `<key>=<value>` argument */ +__attribute__((format (printf, 1, 2))) static int set_config(const char *fmt, ...) { struct strbuf buf = STRBUF_INIT; diff --git a/send-pack.c b/send-pack.c index 37f59d4f66..fa2f5eec17 100644 --- a/send-pack.c +++ b/send-pack.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "commit.h" @@ -259,7 +261,7 @@ static int receive_status(struct packet_reader *reader, struct ref *refs) if (p) hint->remote_status = xstrdup(p); else - hint->remote_status = "failed"; + hint->remote_status = xstrdup("failed"); } else { hint->status = REF_STATUS_OK; hint->remote_status = xstrdup_or_null(p); @@ -425,17 +427,26 @@ static void get_commons_through_negotiation(const char *url, struct child_process child = CHILD_PROCESS_INIT; const struct ref *ref; int len = the_hash_algo->hexsz + 1; /* hash + NL */ + int nr_negotiation_tip = 0; child.git_cmd = 1; child.no_stdin = 1; child.out = -1; strvec_pushl(&child.args, "fetch", "--negotiate-only", NULL); for (ref = remote_refs; ref; ref = ref->next) { - if (!is_null_oid(&ref->new_oid)) - strvec_pushf(&child.args, "--negotiation-tip=%s", oid_to_hex(&ref->new_oid)); + if (!is_null_oid(&ref->new_oid)) { + strvec_pushf(&child.args, "--negotiation-tip=%s", + oid_to_hex(&ref->new_oid)); + nr_negotiation_tip++; + } } strvec_push(&child.args, url); + if (!nr_negotiation_tip) { + child_process_clear(&child); + return; + } + if (start_command(&child)) die(_("send-pack: unable to fork off fetch subprocess")); diff --git a/sequencer.c b/sequencer.c index 30513e87bf..0291920f0b 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "advice.h" @@ -760,7 +762,7 @@ static int do_recursive_merge(struct repository *r, repo_read_index(r); - init_merge_options(&o, r); + init_ui_merge_options(&o, r); o.ancestor = base ? base_label : "(empty tree)"; o.branch1 = "HEAD"; o.branch2 = next ? next_label : "(empty tree)"; @@ -1711,6 +1713,7 @@ static int try_to_commit(struct repository *r, out: free_commit_extra_headers(extra); + free_commit_list(parents); strbuf_release(&err); strbuf_release(&commit_msg); free(amend_author); @@ -2263,7 +2266,7 @@ static int do_pick_commit(struct repository *r, unborn = 1; } else if (unborn) oidcpy(&head, the_hash_algo->empty_tree); - if (index_differs_from(r, unborn ? empty_tree_oid_hex() : "HEAD", + if (index_differs_from(r, unborn ? empty_tree_oid_hex(the_repository->hash_algo) : "HEAD", NULL, 0)) return error_dirty_index(r, opts); } @@ -2626,8 +2629,63 @@ static int check_label_or_ref_arg(enum todo_command command, const char *arg) return 0; } -static int parse_insn_line(struct repository *r, struct todo_item *item, - const char *buf, const char *bol, char *eol) +static int check_merge_commit_insn(enum todo_command command) +{ + switch(command) { + case TODO_PICK: + error(_("'%s' does not accept merge commits"), + todo_command_info[command].str); + advise_if_enabled(ADVICE_REBASE_TODO_ERROR, _( + /* + * TRANSLATORS: 'pick' and 'merge -C' should not be + * translated. + */ + "'pick' does not take a merge commit. If you wanted to\n" + "replay the merge, use 'merge -C' on the commit.")); + return -1; + + case TODO_REWORD: + error(_("'%s' does not accept merge commits"), + todo_command_info[command].str); + advise_if_enabled(ADVICE_REBASE_TODO_ERROR, _( + /* + * TRANSLATORS: 'reword' and 'merge -c' should not be + * translated. + */ + "'reword' does not take a merge commit. If you wanted to\n" + "replay the merge and reword the commit message, use\n" + "'merge -c' on the commit")); + return -1; + + case TODO_EDIT: + error(_("'%s' does not accept merge commits"), + todo_command_info[command].str); + advise_if_enabled(ADVICE_REBASE_TODO_ERROR, _( + /* + * TRANSLATORS: 'edit', 'merge -C' and 'break' should + * not be translated. + */ + "'edit' does not take a merge commit. If you wanted to\n" + "replay the merge, use 'merge -C' on the commit, and then\n" + "'break' to give the control back to you so that you can\n" + "do 'git commit --amend && git rebase --continue'.")); + return -1; + + case TODO_FIXUP: + case TODO_SQUASH: + return error(_("cannot squash merge commit into another commit")); + + case TODO_MERGE: + return 0; + + default: + BUG("unexpected todo_command"); + } +} + +static int parse_insn_line(struct repository *r, struct replay_opts *opts, + struct todo_item *item, const char *buf, + const char *bol, char *eol) { struct object_id commit_oid; char *end_of_object_name; @@ -2731,7 +2789,12 @@ static int parse_insn_line(struct repository *r, struct todo_item *item, return status; item->commit = lookup_commit_reference(r, &commit_oid); - return item->commit ? 0 : -1; + if (!item->commit) + return -1; + if (is_rebase_i(opts) && + item->commit->parents && item->commit->parents->next) + return check_merge_commit_insn(item->command); + return 0; } int sequencer_get_last_command(struct repository *r UNUSED, enum replay_action *action) @@ -2761,8 +2824,8 @@ int sequencer_get_last_command(struct repository *r UNUSED, enum replay_action * return ret; } -int todo_list_parse_insn_buffer(struct repository *r, char *buf, - struct todo_list *todo_list) +int todo_list_parse_insn_buffer(struct repository *r, struct replay_opts *opts, + char *buf, struct todo_list *todo_list) { struct todo_item *item; char *p = buf, *next_p; @@ -2780,7 +2843,7 @@ int todo_list_parse_insn_buffer(struct repository *r, char *buf, item = append_new_todo(todo_list); item->offset_in_buf = p - todo_list->buf.buf; - if (parse_insn_line(r, item, buf, p, eol)) { + if (parse_insn_line(r, opts, item, buf, p, eol)) { res = error(_("invalid line %d: %.*s"), i, (int)(eol - p), p); item->command = TODO_COMMENT + 1; @@ -2930,7 +2993,7 @@ static int read_populate_todo(struct repository *r, if (strbuf_read_file_or_whine(&todo_list->buf, todo_file) < 0) return -1; - res = todo_list_parse_insn_buffer(r, todo_list->buf.buf, todo_list); + res = todo_list_parse_insn_buffer(r, opts, todo_list->buf.buf, todo_list); if (res) { if (is_rebase_i(opts)) return error(_("please fix this using " @@ -2960,7 +3023,7 @@ static int read_populate_todo(struct repository *r, struct todo_list done = TODO_LIST_INIT; if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 && - !todo_list_parse_insn_buffer(r, done.buf.buf, &done)) + !todo_list_parse_insn_buffer(r, opts, done.buf.buf, &done)) todo_list->done_nr = count_commands(&done); else todo_list->done_nr = 0; @@ -3334,12 +3397,12 @@ static int rollback_is_safe(void) strbuf_release(&sb); } else if (errno == ENOENT) - oidclr(&expected_head); + oidclr(&expected_head, the_repository->hash_algo); else die_errno(_("could not read '%s'"), git_path_abort_safety_file()); if (repo_get_oid(the_repository, "HEAD", &actual_head)) - oidclr(&actual_head); + oidclr(&actual_head, the_repository->hash_algo); return oideq(&actual_head, &expected_head); } @@ -4246,7 +4309,7 @@ static int do_merge(struct repository *r, bases = reverse_commit_list(bases); repo_read_index(r); - init_merge_options(&o, r); + init_ui_merge_options(&o, r); o.branch1 = "HEAD"; o.branch2 = ref_name.buf; o.buffer_output = 2; @@ -4314,6 +4377,7 @@ leave_merge: strbuf_release(&ref_name); rollback_lock_file(&lock); free_commit_list(to_merge); + free_commit_list(bases); return ret; } @@ -5145,33 +5209,47 @@ static int commit_staged_changes(struct repository *r, struct replay_ctx *ctx = opts->ctx; unsigned int flags = ALLOW_EMPTY | EDIT_MSG; unsigned int final_fixup = 0, is_clean; + struct strbuf rev = STRBUF_INIT; + int ret; - if (has_unstaged_changes(r, 1)) - return error(_("cannot rebase: You have unstaged changes.")); + if (has_unstaged_changes(r, 1)) { + ret = error(_("cannot rebase: You have unstaged changes.")); + goto out; + } is_clean = !has_uncommitted_changes(r, 0); if (!is_clean && !file_exists(rebase_path_message())) { const char *gpg_opt = gpg_sign_opt_quoted(opts); - - return error(_(staged_changes_advice), gpg_opt, gpg_opt); + ret = error(_(staged_changes_advice), gpg_opt, gpg_opt); + goto out; } + if (file_exists(rebase_path_amend())) { - struct strbuf rev = STRBUF_INIT; struct object_id head, to_amend; - if (repo_get_oid(r, "HEAD", &head)) - return error(_("cannot amend non-existing commit")); - if (!read_oneliner(&rev, rebase_path_amend(), 0)) - return error(_("invalid file: '%s'"), rebase_path_amend()); - if (get_oid_hex(rev.buf, &to_amend)) - return error(_("invalid contents: '%s'"), - rebase_path_amend()); - if (!is_clean && !oideq(&head, &to_amend)) - return error(_("\nYou have uncommitted changes in your " - "working tree. Please, commit them\n" - "first and then run 'git rebase " - "--continue' again.")); + if (repo_get_oid(r, "HEAD", &head)) { + ret = error(_("cannot amend non-existing commit")); + goto out; + } + + if (!read_oneliner(&rev, rebase_path_amend(), 0)) { + ret = error(_("invalid file: '%s'"), rebase_path_amend()); + goto out; + } + + if (get_oid_hex(rev.buf, &to_amend)) { + ret = error(_("invalid contents: '%s'"), + rebase_path_amend()); + goto out; + } + if (!is_clean && !oideq(&head, &to_amend)) { + ret = error(_("\nYou have uncommitted changes in your " + "working tree. Please, commit them\n" + "first and then run 'git rebase " + "--continue' again.")); + goto out; + } /* * When skipping a failed fixup/squash, we need to edit the * commit message, the current fixup list and count, and if it @@ -5203,9 +5281,11 @@ static int commit_staged_changes(struct repository *r, len--; strbuf_setlen(&ctx->current_fixups, len); if (write_message(p, len, rebase_path_current_fixups(), - 0) < 0) - return error(_("could not write file: '%s'"), - rebase_path_current_fixups()); + 0) < 0) { + ret = error(_("could not write file: '%s'"), + rebase_path_current_fixups()); + goto out; + } /* * If a fixup/squash in a fixup/squash chain failed, the @@ -5235,35 +5315,38 @@ static int commit_staged_changes(struct repository *r, * We need to update the squash message to skip * the latest commit message. */ - int res = 0; struct commit *commit; const char *msg; const char *path = rebase_path_squash_msg(); const char *encoding = get_commit_output_encoding(); - if (parse_head(r, &commit)) - return error(_("could not parse HEAD")); + if (parse_head(r, &commit)) { + ret = error(_("could not parse HEAD")); + goto out; + } p = repo_logmsg_reencode(r, commit, NULL, encoding); if (!p) { - res = error(_("could not parse commit %s"), + ret = error(_("could not parse commit %s"), oid_to_hex(&commit->object.oid)); goto unuse_commit_buffer; } find_commit_subject(p, &msg); if (write_message(msg, strlen(msg), path, 0)) { - res = error(_("could not write file: " + ret = error(_("could not write file: " "'%s'"), path); goto unuse_commit_buffer; } + + ret = 0; + unuse_commit_buffer: repo_unuse_commit_buffer(r, commit, p); - if (res) - return res; + if (ret) + goto out; } } - strbuf_release(&rev); flags |= AMEND_MSG; } @@ -5271,18 +5354,29 @@ static int commit_staged_changes(struct repository *r, if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") && refs_delete_ref(get_main_ref_store(r), "", - "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF)) - return error(_("could not remove CHERRY_PICK_HEAD")); - if (unlink(git_path_merge_msg(r)) && errno != ENOENT) - return error_errno(_("could not remove '%s'"), - git_path_merge_msg(r)); - if (!final_fixup) - return 0; + "CHERRY_PICK_HEAD", NULL, REF_NO_DEREF)) { + ret = error(_("could not remove CHERRY_PICK_HEAD")); + goto out; + } + + if (unlink(git_path_merge_msg(r)) && errno != ENOENT) { + ret = error_errno(_("could not remove '%s'"), + git_path_merge_msg(r)); + goto out; + } + + if (!final_fixup) { + ret = 0; + goto out; + } } if (run_git_commit(final_fixup ? NULL : rebase_path_message(), - opts, flags)) - return error(_("could not commit staged changes.")); + opts, flags)) { + ret = error(_("could not commit staged changes.")); + goto out; + } + unlink(rebase_path_amend()); unlink(git_path_merge_head(r)); refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE", @@ -5300,7 +5394,12 @@ static int commit_staged_changes(struct repository *r, strbuf_reset(&ctx->current_fixups); ctx->current_fixup_count = 0; } - return 0; + + ret = 0; + +out: + strbuf_release(&rev); + return ret; } int sequencer_continue(struct repository *r, struct replay_opts *opts) @@ -5319,7 +5418,8 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts) goto release_todo_list; if (file_exists(rebase_path_dropped())) { - if ((res = todo_list_check_against_backup(r, &todo_list))) + if ((res = todo_list_check_against_backup(r, opts, + &todo_list))) goto release_todo_list; unlink(rebase_path_dropped()); @@ -5915,6 +6015,9 @@ static int make_script_with_merges(struct pretty_print_context *pp, strbuf_release(&oneline); strbuf_release(&buf); + oidset_clear(&interesting); + oidset_clear(&child_seen); + oidset_clear(&shown); oidmap_free(&commit2todo, 1); oidmap_free(&state.commit2label, 1); hashmap_clear_and_free(&state.labels, struct labels_entry, entry); @@ -6363,7 +6466,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla return error(_("nothing to do")); } - res = edit_todo_list(r, todo_list, &new_todo, shortrevisions, + res = edit_todo_list(r, opts, todo_list, &new_todo, shortrevisions, shortonto, flags); if (res == -1) return -1; @@ -6391,7 +6494,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla strbuf_release(&buf2); /* Nothing is done yet, and we're reparsing, so let's reset the count */ new_todo.total_nr = 0; - if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) < 0) + if (todo_list_parse_insn_buffer(r, opts, new_todo.buf.buf, &new_todo) < 0) BUG("invalid todo list after expanding IDs:\n%s", new_todo.buf.buf); diff --git a/sequencer.h b/sequencer.h index a309ddd712..304ba4b4d3 100644 --- a/sequencer.h +++ b/sequencer.h @@ -136,8 +136,8 @@ struct todo_list { .buf = STRBUF_INIT, \ } -int todo_list_parse_insn_buffer(struct repository *r, char *buf, - struct todo_list *todo_list); +int todo_list_parse_insn_buffer(struct repository *r, struct replay_opts *opts, + char *buf, struct todo_list *todo_list); int todo_list_write_to_file(struct repository *r, struct todo_list *todo_list, const char *file, const char *shortrevisions, const char *shortonto, int num, unsigned flags); @@ -1,7 +1,9 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "repository.h" #include "config.h" -#include "hash-ll.h" +#include "hash.h" #include "pkt-line.h" #include "version.h" #include "ls-refs.h" diff --git a/server-info.c b/server-info.c index 6feaa457c5..f61296a60d 100644 --- a/server-info.c +++ b/server-info.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "dir.h" #include "environment.h" @@ -13,6 +15,7 @@ #include "object-store-ll.h" #include "server-info.h" #include "strbuf.h" +#include "tempfile.h" struct update_info_ctx { FILE *cur_fp; @@ -75,9 +78,8 @@ static int update_info_file(char *path, int force) { char *tmp = mkpathdup("%s_XXXXXX", path); + struct tempfile *f = NULL; int ret = -1; - int fd = -1; - FILE *to_close; struct update_info_ctx uic = { .cur_fp = NULL, .old_fp = NULL, @@ -86,13 +88,12 @@ static int update_info_file(char *path, }; safe_create_leading_directories(path); - fd = git_mkstemp_mode(tmp, 0666); - if (fd < 0) + f = mks_tempfile_m(tmp, 0666); + if (!f) goto out; - to_close = uic.cur_fp = fdopen(fd, "w"); + uic.cur_fp = fdopen_tempfile(f, "w"); if (!uic.cur_fp) goto out; - fd = -1; /* no problem on ENOENT and old_fp == NULL, it's stale, now */ if (!force) @@ -121,27 +122,22 @@ static int update_info_file(char *path, } uic.cur_fp = NULL; - if (fclose(to_close)) - goto out; if (uic_is_stale(&uic)) { - if (adjust_shared_perm(tmp) < 0) + if (adjust_shared_perm(get_tempfile_path(f)) < 0) goto out; - if (rename(tmp, path) < 0) + if (rename_tempfile(&f, path) < 0) goto out; } else { - unlink(tmp); + delete_tempfile(&f); } ret = 0; out: if (ret) { error_errno("unable to update %s", path); - if (uic.cur_fp) - fclose(uic.cur_fp); - else if (fd >= 0) - close(fd); - unlink(tmp); + if (f) + delete_tempfile(&f); } free(tmp); if (uic.old_fp) @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "copy.h" @@ -49,7 +51,7 @@ static int abspath_part_inside_repo(char *path) size_t wtlen; char *path0; int off; - const char *work_tree = get_git_work_tree(); + const char *work_tree = precompose_string_if_needed(get_git_work_tree()); struct strbuf realpath = STRBUF_INIT; if (!work_tree) @@ -1230,13 +1232,20 @@ static int safe_directory_cb(const char *key, const char *value, } else if (!strcmp(value, "*")) { data->is_safe = 1; } else { - char *interpolated = NULL; - - if (!git_config_pathname(&interpolated, key, value) && - !fspathcmp(data->path, interpolated ? interpolated : value)) - data->is_safe = 1; - - free(interpolated); + char *allowed = NULL; + + if (!git_config_pathname(&allowed, key, value)) { + const char *check = allowed ? allowed : value; + if (ends_with(check, "/*")) { + size_t len = strlen(check); + if (!fspathncmp(check, data->path, len - 1)) + data->is_safe = 1; + } else if (!fspathcmp(data->path, check)) { + data->is_safe = 1; + } + } + if (allowed != value) + free(allowed); } return 0; @@ -2050,7 +2059,7 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree) } void initialize_repository_version(int hash_algo, - unsigned int ref_storage_format, + enum ref_storage_format ref_storage_format, int reinit) { char repo_version_string[10]; @@ -2081,6 +2090,8 @@ void initialize_repository_version(int hash_algo, if (ref_storage_format != REF_STORAGE_FORMAT_FILES) git_config_set("extensions.refstorage", ref_storage_format_to_name(ref_storage_format)); + else if (reinit) + git_config_set_gently("extensions.refstorage", NULL); } static int is_reinit(void) @@ -2095,7 +2106,7 @@ static int is_reinit(void) return ret; } -void create_reference_database(unsigned int ref_storage_format, +void create_reference_database(enum ref_storage_format ref_storage_format, const char *initial_branch, int quiet) { struct strbuf err = STRBUF_INIT; @@ -2294,7 +2305,7 @@ static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash } static void validate_ref_storage_format(struct repository_format *repo_fmt, - unsigned int format) + enum ref_storage_format format) { const char *name = getenv("GIT_DEFAULT_REF_FORMAT"); @@ -2314,7 +2325,7 @@ static void validate_ref_storage_format(struct repository_format *repo_fmt, int init_db(const char *git_dir, const char *real_git_dir, const char *template_dir, int hash, - unsigned int ref_storage_format, + enum ref_storage_format ref_storage_format, const char *initial_branch, int init_shared_repository, unsigned int flags) { @@ -1,6 +1,7 @@ #ifndef SETUP_H #define SETUP_H +#include "refs.h" #include "string-list.h" int is_inside_git_dir(void); @@ -128,7 +129,7 @@ struct repository_format { int is_bare; int hash_algo; int compat_hash_algo; - unsigned int ref_storage_format; + enum ref_storage_format ref_storage_format; int sparse_index; char *work_tree; struct string_list unknown_extensions; @@ -192,13 +193,13 @@ const char *get_template_dir(const char *option_template); int init_db(const char *git_dir, const char *real_git_dir, const char *template_dir, int hash_algo, - unsigned int ref_storage_format, + enum ref_storage_format ref_storage_format, const char *initial_branch, int init_shared_repository, unsigned int flags); void initialize_repository_version(int hash_algo, - unsigned int ref_storage_format, + enum ref_storage_format ref_storage_format, int reinit); -void create_reference_database(unsigned int ref_storage_format, +void create_reference_database(enum ref_storage_format ref_storage_format, const char *initial_branch, int quiet); /* @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "hex.h" #include "repository.h" diff --git a/sparse-index.c b/sparse-index.c index e48e40cae7..9958656ded 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -12,6 +12,22 @@ #include "config.h" #include "dir.h" #include "fsmonitor-ll.h" +#include "advice.h" + +/** + * This global is used by expand_index() to determine if we should give the + * advice for advice.sparseIndexExpanded when expanding a sparse index to a full + * one. However, this is sometimes done on purpose, such as in the sparse-checkout + * builtin, even when index.sparse=false. This may be disabled in + * convert_to_sparse(). + */ +static int give_advice_on_expansion = 1; +#define ADVICE_MSG \ + "The sparse index is expanding to a full index, a slow operation.\n" \ + "Your working directory likely has contents that are outside of\n" \ + "your sparse-checkout patterns. Use 'git sparse-checkout list' to\n" \ + "see your sparse-checkout definition and compare it to your working\n" \ + "directory contents. Running 'git clean' may assist in this cleanup." struct modify_index_context { struct index_state *write; @@ -184,6 +200,12 @@ int convert_to_sparse(struct index_state *istate, int flags) return 0; /* + * If we are purposefully collapsing a full index, then don't give + * advice when it is expanded later. + */ + give_advice_on_expansion = 0; + + /* * NEEDSWORK: If we have unmerged entries, then stay full. * Unmerged entries prevent the cache-tree extension from working. */ @@ -328,6 +350,12 @@ void expand_index(struct index_state *istate, struct pattern_list *pl) pl = NULL; } + if (!pl && give_advice_on_expansion) { + give_advice_on_expansion = 0; + advise_if_enabled(ADVICE_SPARSE_INDEX_EXPANDED, + _(ADVICE_MSG)); + } + /* * A NULL pattern set indicates we are expanding a full index, so * we use a special region name that indicates the full expansion. @@ -439,96 +467,208 @@ void ensure_correct_sparsity(struct index_state *istate) ensure_full_index(istate); } -static int path_found(const char *path, const char **dirname, size_t *dir_len, - int *dir_found) +struct path_found_data { + /** + * The path stored in 'dir', if non-empty, corresponds to the most- + * recent path that we checked where: + * + * 1. The path should be a directory, according to the index. + * 2. The path does not exist. + * 3. The parent path _does_ exist. (This may be the root of the + * working directory.) + */ + struct strbuf dir; + size_t lstat_count; +}; + +#define PATH_FOUND_DATA_INIT { \ + .dir = STRBUF_INIT \ +} + +static void clear_path_found_data(struct path_found_data *data) +{ + strbuf_release(&data->dir); +} + +/** + * Return the length of the longest common substring that ends in a + * slash ('/') to indicate the longest common parent directory. Returns + * zero if no common directory exists. + */ +static size_t max_common_dir_prefix(const char *path1, const char *path2) +{ + size_t common_prefix = 0; + for (size_t i = 0; path1[i] && path2[i]; i++) { + if (path1[i] != path2[i]) + break; + + /* + * If they agree at a directory separator, then add one + * to make sure it is included in the common prefix string. + */ + if (path1[i] == '/') + common_prefix = i + 1; + } + + return common_prefix; +} + +static int path_found(const char *path, struct path_found_data *data) { struct stat st; - char *newdir; - char *tmp; + size_t common_prefix; /* - * If dirname corresponds to a directory that doesn't exist, and this - * path starts with dirname, then path can't exist. + * If data->dir is non-empty, then it contains a path that doesn't + * exist, including an ending slash ('/'). If it is a prefix of 'path', + * then we can return 0. */ - if (!*dir_found && !memcmp(path, *dirname, *dir_len)) + if (data->dir.len && !memcmp(path, data->dir.buf, data->dir.len)) return 0; /* - * If path itself exists, return 1. + * Otherwise, we must check if the current path exists. If it does, then + * return 1. The cached directory will be skipped until we come across + * a missing path again. */ + data->lstat_count++; if (!lstat(path, &st)) return 1; /* - * Otherwise, path does not exist so we'll return 0...but we'll first - * determine some info about its parent directory so we can avoid - * lstat calls for future cache entries. + * At this point, we know that 'path' doesn't exist, and we know that + * the parent directory of 'data->dir' does exist. Let's set 'data->dir' + * to be the top-most non-existing directory of 'path'. If the first + * parent of 'path' exists, then we will act as though 'path' + * corresponds to a directory (by adding a slash). */ - newdir = strrchr(path, '/'); - if (!newdir) - return 0; /* Didn't find a parent dir; just return 0 now. */ + common_prefix = max_common_dir_prefix(path, data->dir.buf); /* - * If path starts with directory (which we already lstat'ed and found), - * then no need to lstat parent directory again. + * At this point, 'path' and 'data->dir' have a common existing parent + * directory given by path[0..common_prefix] (which could have length 0). + * We "grow" the data->dir buffer by checking for existing directories + * along 'path'. */ - if (*dir_found && *dirname && memcmp(path, *dirname, *dir_len)) - return 0; - /* Free previous dirname, and cache path's dirname */ - *dirname = path; - *dir_len = newdir - path + 1; + strbuf_setlen(&data->dir, common_prefix); + while (1) { + /* Find the next directory in 'path'. */ + const char *rest = path + data->dir.len; + const char *next_slash = strchr(rest, '/'); + + /* + * If there are no more slashes, then 'path' doesn't contain a + * non-existent _parent_ directory. Set 'data->dir' to be equal + * to 'path' plus an additional slash, so it can be used for + * caching in the future. The filename of 'path' is considered + * a non-existent directory. + * + * Note: if "{path}/" exists as a directory, then it will never + * appear as a prefix of other callers to this method, assuming + * the context from the clear_skip_worktree... methods. If this + * method is reused, then this must be reconsidered. + */ + if (!next_slash) { + strbuf_addstr(&data->dir, rest); + strbuf_addch(&data->dir, '/'); + break; + } - tmp = xstrndup(path, *dir_len); - *dir_found = !lstat(tmp, &st); - free(tmp); + /* + * Now that we have a slash, let's grow 'data->dir' to include + * this slash, then test if we should stop. + */ + strbuf_add(&data->dir, rest, next_slash - rest + 1); + /* If the parent dir doesn't exist, then stop here. */ + data->lstat_count++; + if (lstat(data->dir.buf, &st)) + return 0; + } + + /* + * At this point, 'data->dir' is equal to 'path' plus a slash character, + * and the parent directory of 'path' definitely exists. Moreover, we + * know that 'path' doesn't exist, or we would have returned 1 earlier. + */ return 0; } -void clear_skip_worktree_from_present_files(struct index_state *istate) +static int clear_skip_worktree_from_present_files_sparse(struct index_state *istate) { - const char *last_dirname = NULL; - size_t dir_len = 0; - int dir_found = 1; + struct path_found_data data = PATH_FOUND_DATA_INIT; - int i; - int path_count[2] = {0, 0}; - int restarted = 0; - - if (!core_apply_sparse_checkout || - sparse_expect_files_outside_of_patterns) - return; + int path_count = 0; + int to_restart = 0; - trace2_region_enter("index", "clear_skip_worktree_from_present_files", + trace2_region_enter("index", "clear_skip_worktree_from_present_files_sparse", istate->repo); -restart: - for (i = 0; i < istate->cache_nr; i++) { + for (int i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce = istate->cache[i]; if (ce_skip_worktree(ce)) { - path_count[restarted]++; - if (path_found(ce->name, &last_dirname, &dir_len, &dir_found)) { + path_count++; + if (path_found(ce->name, &data)) { if (S_ISSPARSEDIR(ce->ce_mode)) { - if (restarted) - BUG("ensure-full-index did not fully flatten?"); - ensure_full_index(istate); - restarted = 1; - goto restart; + to_restart = 1; + break; } ce->ce_flags &= ~CE_SKIP_WORKTREE; } } } - if (path_count[0]) - trace2_data_intmax("index", istate->repo, - "sparse_path_count", path_count[0]); - if (restarted) - trace2_data_intmax("index", istate->repo, - "sparse_path_count_full", path_count[1]); - trace2_region_leave("index", "clear_skip_worktree_from_present_files", + trace2_data_intmax("index", istate->repo, + "sparse_path_count", path_count); + trace2_data_intmax("index", istate->repo, + "sparse_lstat_count", data.lstat_count); + trace2_region_leave("index", "clear_skip_worktree_from_present_files_sparse", istate->repo); + clear_path_found_data(&data); + return to_restart; +} + +static void clear_skip_worktree_from_present_files_full(struct index_state *istate) +{ + struct path_found_data data = PATH_FOUND_DATA_INIT; + + int path_count = 0; + + trace2_region_enter("index", "clear_skip_worktree_from_present_files_full", + istate->repo); + for (int i = 0; i < istate->cache_nr; i++) { + struct cache_entry *ce = istate->cache[i]; + + if (S_ISSPARSEDIR(ce->ce_mode)) + BUG("ensure-full-index did not fully flatten?"); + + if (ce_skip_worktree(ce)) { + path_count++; + if (path_found(ce->name, &data)) + ce->ce_flags &= ~CE_SKIP_WORKTREE; + } + } + + trace2_data_intmax("index", istate->repo, + "full_path_count", path_count); + trace2_data_intmax("index", istate->repo, + "full_lstat_count", data.lstat_count); + trace2_region_leave("index", "clear_skip_worktree_from_present_files_full", + istate->repo); + clear_path_found_data(&data); +} + +void clear_skip_worktree_from_present_files(struct index_state *istate) +{ + if (!core_apply_sparse_checkout || + sparse_expect_files_outside_of_patterns) + return; + + if (clear_skip_worktree_from_present_files_sparse(istate)) { + ensure_full_index(istate); + clear_skip_worktree_from_present_files_full(istate); + } } /* diff --git a/split-index.c b/split-index.c index 8c38687c04..120c8190b1 100644 --- a/split-index.c +++ b/split-index.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "hash.h" @@ -29,7 +31,7 @@ int read_link_extension(struct index_state *istate, if (sz < the_hash_algo->rawsz) return error("corrupt link extension (too short)"); si = init_split_index(istate); - oidread(&si->base_oid, data); + oidread(&si->base_oid, data, the_repository->hash_algo); data += the_hash_algo->rawsz; sz -= the_hash_algo->rawsz; if (!sz) diff --git a/split-index.h b/split-index.h index 15a29cd08c..1a153f47ba 100644 --- a/split-index.h +++ b/split-index.h @@ -1,7 +1,7 @@ #ifndef SPLIT_INDEX_H #define SPLIT_INDEX_H -#include "hash-ll.h" +#include "hash.h" struct index_state; struct strbuf; @@ -313,6 +313,15 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len) strbuf_setlen(sb, sb->len + len); } +void strbuf_addstrings(struct strbuf *sb, const char *s, size_t n) +{ + size_t len = strlen(s); + + strbuf_grow(sb, st_mult(len, n)); + for (size_t i = 0; i < n; i++) + strbuf_add(sb, s, len); +} + void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) { strbuf_grow(sb, sb2->len); @@ -311,6 +311,11 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s) } /** + * Add a NUL-terminated string the specified number of times to the buffer. + */ +void strbuf_addstrings(struct strbuf *sb, const char *s, size_t n); + +/** * Copy the contents of another buffer at the end of the current one. */ void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2); diff --git a/streaming.c b/streaming.c index 10adf625b2..38839511af 100644 --- a/streaming.c +++ b/streaming.c @@ -1,6 +1,9 @@ /* * Copyright (c) 2011, Google Inc. */ + +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "convert.h" #include "environment.h" @@ -10,7 +10,7 @@ void strvec_init(struct strvec *array) memcpy(array, &blank, sizeof(*array)); } -static void strvec_push_nodup(struct strvec *array, const char *value) +void strvec_push_nodup(struct strvec *array, char *value) { if (array->v == empty_strvec) array->v = NULL; @@ -46,6 +46,9 @@ void strvec_init(struct strvec *); /* Push a copy of a string onto the end of the array. */ const char *strvec_push(struct strvec *, const char *); +/* Push an allocated string onto the end of the array, taking ownership. */ +void strvec_push_nodup(struct strvec *array, char *value); + /** * Format a string and push it onto the end of the array. This is a * convenience wrapper combining `strbuf_addf` and `strvec_push`. diff --git a/submodule-config.c b/submodule-config.c index ec45ea67b9..9b0bb0b9f4 100644 --- a/submodule-config.c +++ b/submodule-config.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "dir.h" #include "environment.h" @@ -682,7 +684,7 @@ static int gitmodule_oid_from_commit(const struct object_id *treeish_name, int ret = 0; if (is_null_oid(treeish_name)) { - oidclr(gitmodules_oid); + oidclr(gitmodules_oid, the_repository->hash_algo); return 1; } diff --git a/submodule.c b/submodule.c index 759cf1e1cd..ab99a30253 100644 --- a/submodule.c +++ b/submodule.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "repository.h" @@ -2119,7 +2121,7 @@ static void submodule_reset_index(const char *path, const char *super_prefix) strvec_pushf(&cp.args, "--super-prefix=%s%s/", (super_prefix ? super_prefix : ""), path); - strvec_push(&cp.args, empty_tree_oid_hex()); + strvec_push(&cp.args, empty_tree_oid_hex(the_repository->hash_algo)); if (run_command(&cp)) die(_("could not reset submodule index")); @@ -2229,9 +2231,9 @@ int submodule_move_head(const char *path, const char *super_prefix, strvec_push(&cp.args, "-m"); if (!(flags & SUBMODULE_MOVE_HEAD_FORCE)) - strvec_push(&cp.args, old_head ? old_head : empty_tree_oid_hex()); + strvec_push(&cp.args, old_head ? old_head : empty_tree_oid_hex(the_repository->hash_algo)); - strvec_push(&cp.args, new_head ? new_head : empty_tree_oid_hex()); + strvec_push(&cp.args, new_head ? new_head : empty_tree_oid_hex(the_repository->hash_algo)); if (run_command(&cp)) { ret = error(_("Submodule '%s' could not be updated."), path); diff --git a/t/.gitattributes b/t/.gitattributes index b9cea1795d..7664c6e027 100644 --- a/t/.gitattributes +++ b/t/.gitattributes @@ -1,5 +1,5 @@ t[0-9][0-9][0-9][0-9]/* -whitespace -/chainlint/*.expect eol=lf +/chainlint/*.expect eol=lf -whitespace /t0110/url-* binary /t3206/* eol=lf /t3900/*.txt eol=lf diff --git a/t/Makefile b/t/Makefile index b2eb9f770b..4c30e7c06f 100644 --- a/t/Makefile +++ b/t/Makefile @@ -108,20 +108,8 @@ clean-chainlint: check-chainlint: @mkdir -p '$(CHAINLINTTMP_SQ)' && \ - for i in $(CHAINLINTTESTS); do \ - echo "test_expect_success '$$i' '" && \ - sed -e '/^# LINT: /d' chainlint/$$i.test && \ - echo "'"; \ - done >'$(CHAINLINTTMP_SQ)'/tests && \ - { \ - echo "# chainlint: $(CHAINLINTTMP_SQ)/tests" && \ - for i in $(CHAINLINTTESTS); do \ - echo "# chainlint: $$i" && \ - cat chainlint/$$i.expect; \ - done \ - } >'$(CHAINLINTTMP_SQ)'/expect && \ - $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests | \ - sed -e 's/^[1-9][0-9]* //' >'$(CHAINLINTTMP_SQ)'/actual && \ + '$(PERL_PATH_SQ)' chainlint-cat.pl '$(CHAINLINTTMP_SQ)' $(CHAINLINTTESTS) && \ + { $(CHAINLINT) --emit-all '$(CHAINLINTTMP_SQ)'/tests >'$(CHAINLINTTMP_SQ)'/actual || true; } && \ diff -u '$(CHAINLINTTMP_SQ)'/expect '$(CHAINLINTTMP_SQ)'/actual test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \ @@ -382,33 +382,9 @@ mapping between "TEST_PASSES_SANITIZE_LEAK=true" and those tests that pass under "SANITIZE=leak". This is especially useful when testing a series that fixes various memory leaks with "git rebase -x". -GIT_TEST_SANITIZE_LEAK_LOG=true will log memory leaks to -"test-results/$TEST_NAME.leak/trace.*" files. The logs include a -"dedup_token" (see +"ASAN_OPTIONS=help=1 ./git") and other options to -make logs +machine-readable. - -With GIT_TEST_SANITIZE_LEAK_LOG=true we'll look at the leak logs -before exiting and exit on failure if the logs showed that we had a -memory leak, even if the test itself would have otherwise passed. This -allows us to catch e.g. missing &&-chaining. This is especially useful -when combined with "GIT_TEST_PASSING_SANITIZE_LEAK", see below. - GIT_TEST_PASSING_SANITIZE_LEAK=check when combined with "--immediate" will run to completion faster, and result in the same failing -tests. The only practical reason to run -GIT_TEST_PASSING_SANITIZE_LEAK=check without "--immediate" is to -combine it with "GIT_TEST_SANITIZE_LEAK_LOG=true". If we stop at the -first failing test case our leak logs won't show subsequent leaks we -might have run into. - -GIT_TEST_PASSING_SANITIZE_LEAK=(true|check) will not catch all memory -leaks unless combined with GIT_TEST_SANITIZE_LEAK_LOG=true. Some tests -run "git" (or "test-tool" etc.) without properly checking the exit -code, or git will invoke itself and fail to ferry the abort() exit -code to the original caller. When the two modes are combined we'll -look at the "test-results/$TEST_NAME.leak/trace.*" files at the end of -the test run to see if had memory leaks which the test itself didn't -catch. +tests. GIT_TEST_PROTOCOL_VERSION=<n>, when set, makes 'protocol.version' default to n. @@ -906,6 +882,14 @@ see test-lib-functions.sh for the full list and their options. 'git-write-tree should be able to write an empty tree.' \ 'tree=$(git-write-tree)' + If <script> is `-` (a single dash), then the script to run is read + from stdin. This lets you more easily use single quotes within the + script by using a here-doc. For example: + + test_expect_success 'output contains expected string' - <<\EOT + grep "this string has 'quotes' in it" output + EOT + If you supply three parameters the first will be taken to be a prerequisite; see the test_set_prereq and test_have_prereq documentation below: diff --git a/t/chainlint-cat.pl b/t/chainlint-cat.pl new file mode 100644 index 0000000000..388f6e1e41 --- /dev/null +++ b/t/chainlint-cat.pl @@ -0,0 +1,29 @@ +#!/usr/bin/env perl + +my $outdir = shift; +open(my $tests, '>', "$outdir/tests") + or die "unable to open $outdir/tests: $!"; +open(my $expect, '>', "$outdir/expect") + or die "unable to open $outdir/expect: $!"; + +print $expect "# chainlint: $outdir/tests\n"; + +my $offset = 0; +for my $script (@ARGV) { + print $expect "# chainlint: $script\n"; + + open(my $expect_in, '<', "chainlint/$script.expect") + or die "unable to open chainlint/$script.expect: $!"; + while (<$expect_in>) { + s/^\d+/$& + $offset/e; + print $expect $_; + } + + open(my $test_in, '<', "chainlint/$script.test") + or die "unable to open chainlint/$script.test: $!"; + while (<$test_in>) { + /^# LINT: / and next; + print $tests $_; + $offset++; + } +} diff --git a/t/chainlint.pl b/t/chainlint.pl index 1bbd985b78..5361f23b1d 100755 --- a/t/chainlint.pl +++ b/t/chainlint.pl @@ -174,6 +174,10 @@ sub swallow_heredocs { $$b =~ /(?:\G|\n)$indent\Q$$tag[0]\E(?:\n|\z)/gc; if (pos($$b) > $start) { my $body = substr($$b, $start, pos($$b) - $start); + $self->{parser}->{heredocs}->{$$tag[0]} = { + content => substr($body, 0, length($body) - length($&)), + start_line => $self->{lineno}, + }; $self->{lineno} += () = $body =~ /\n/sg; next; } @@ -232,7 +236,8 @@ sub new { my $self = bless { buff => [], stop => [], - output => [] + output => [], + heredocs => {}, } => $class; $self->{lexer} = Lexer->new($self, $s); return $self; @@ -616,14 +621,21 @@ sub unwrap { sub check_test { my $self = shift @_; - my ($title, $body) = map(unwrap, @_); + my $title = unwrap(shift @_); + my $body = shift @_; + my $lineno = $body->[3]; + $body = unwrap($body); + if ($body eq '-') { + my $herebody = shift @_; + $body = $herebody->{content}; + $lineno = $herebody->{start_line}; + } $self->{ntests}++; my $parser = TestParser->new(\$body); my @tokens = $parser->parse(); my $problems = $parser->{problems}; return unless $emit_all || @$problems; my $c = main::fd_colors(1); - my $lineno = $_[1]->[3]; my $start = 0; my $checked = ''; for (sort {$a->[1]->[2] <=> $b->[1]->[2]} @$problems) { @@ -649,8 +661,13 @@ sub parse_cmd { return @tokens unless @tokens && $tokens[0]->[0] =~ /^test_expect_(?:success|failure)$/; my $n = $#tokens; $n-- while $n >= 0 && $tokens[$n]->[0] =~ /^(?:[;&\n|]|&&|\|\|)$/; - $self->check_test($tokens[1], $tokens[2]) if $n == 2; # title body - $self->check_test($tokens[2], $tokens[3]) if $n > 2; # prereq title body + my $herebody; + if ($n >= 2 && $tokens[$n-1]->[0] eq '-' && $tokens[$n]->[0] =~ /^<<-?(.+)$/) { + $herebody = $self->{heredocs}->{$1}; + $n--; + } + $self->check_test($tokens[1], $tokens[2], $herebody) if $n == 2; # title body + $self->check_test($tokens[2], $tokens[3], $herebody) if $n > 2; # prereq title body return @tokens; } @@ -762,7 +779,7 @@ sub check_script { while (my $path = $next_script->()) { $nscripts++; my $fh; - unless (open($fh, "<", $path)) { + unless (open($fh, "<:unix:crlf", $path)) { $emit->("?!ERR?! $path: $!\n"); next; } @@ -806,8 +823,10 @@ unless (@scripts) { show_stats($start_time, \@stats) if $show_stats; exit; } +$jobs = @scripts if @scripts < $jobs; -unless ($Config{useithreads} && eval { +unless ($jobs > 1 && + $Config{useithreads} && eval { require threads; threads->import(); require Thread::Queue; Thread::Queue->import(); 1; diff --git a/t/chainlint/arithmetic-expansion.expect b/t/chainlint/arithmetic-expansion.expect index 46ee1046af..338ecd5861 100644 --- a/t/chainlint/arithmetic-expansion.expect +++ b/t/chainlint/arithmetic-expansion.expect @@ -1,9 +1,9 @@ -( - foo && - bar=$((42 + 1)) && - baz -) && -( - bar=$((42 + 1)) ?!AMP?! - baz -) +2 ( +3 foo && +4 bar=$((42 + 1)) && +5 baz +6 ) && +7 ( +8 bar=$((42 + 1)) ?!AMP?! +9 baz +10 ) diff --git a/t/chainlint/arithmetic-expansion.test b/t/chainlint/arithmetic-expansion.test index 16206960d8..7b4c5c9a41 100644 --- a/t/chainlint/arithmetic-expansion.test +++ b/t/chainlint/arithmetic-expansion.test @@ -1,3 +1,4 @@ +test_expect_success 'arithmetic-expansion' ' ( foo && # LINT: closing ")" of $((...)) not misinterpreted as subshell-closing ")" @@ -9,3 +10,4 @@ bar=$((42 + 1)) baz ) +' diff --git a/t/chainlint/bash-array.expect b/t/chainlint/bash-array.expect index 4c34eaee45..435dc8bdc8 100644 --- a/t/chainlint/bash-array.expect +++ b/t/chainlint/bash-array.expect @@ -1,10 +1,10 @@ -( - foo && - bar=(gumbo stumbo wumbo) && - baz -) && -( - foo && - bar=${#bar[@]} && - baz -) +2 ( +3 foo && +4 bar=(gumbo stumbo wumbo) && +5 baz +6 ) && +7 ( +8 foo && +9 bar=${#bar[@]} && +10 baz +11 ) diff --git a/t/chainlint/bash-array.test b/t/chainlint/bash-array.test index 92bbb777b8..4ca977d299 100644 --- a/t/chainlint/bash-array.test +++ b/t/chainlint/bash-array.test @@ -1,3 +1,4 @@ +test_expect_success 'bash-array' ' ( foo && # LINT: ")" in Bash array assignment not misinterpreted as subshell-closing ")" @@ -10,3 +11,4 @@ bar=${#bar[@]} && baz ) +' diff --git a/t/chainlint/blank-line-before-esac.expect b/t/chainlint/blank-line-before-esac.expect index 056e03003d..b88ba919eb 100644 --- a/t/chainlint/blank-line-before-esac.expect +++ b/t/chainlint/blank-line-before-esac.expect @@ -1,18 +1,18 @@ -test_done () { - case "$test_failure" in - 0) - test_at_end_hook_ - - exit 0 ;; - - *) - if test $test_external_has_tap -eq 0 - then - say_color error "# failed $test_failure among $msg" - say "1..$test_count" - fi - - exit 1 ;; - - esac -} +2 test_done () { +3 case "$test_failure" in +4 0) +5 test_at_end_hook_ +6 +7 exit 0 ;; +8 +9 *) +10 if test $test_external_has_tap -eq 0 +11 then +12 say_color error "# failed $test_failure among $msg" +13 say "1..$test_count" +14 fi +15 +16 exit 1 ;; +17 +18 esac +19 } diff --git a/t/chainlint/blank-line-before-esac.test b/t/chainlint/blank-line-before-esac.test index cecccad19f..51f02ea0c5 100644 --- a/t/chainlint/blank-line-before-esac.test +++ b/t/chainlint/blank-line-before-esac.test @@ -1,3 +1,4 @@ +test_expect_success 'blank-line-before-esac' ' # LINT: blank line before "esac" test_done () { case "$test_failure" in @@ -17,3 +18,4 @@ test_done () { esac } +' diff --git a/t/chainlint/blank-line.expect b/t/chainlint/blank-line.expect index b47827d749..6ae39dd174 100644 --- a/t/chainlint/blank-line.expect +++ b/t/chainlint/blank-line.expect @@ -1,8 +1,8 @@ -( - - nothing && - - something - - -) +2 ( +3 +4 nothing && +5 +6 something +7 +8 +9 ) diff --git a/t/chainlint/blank-line.test b/t/chainlint/blank-line.test index 0fdf15b3e1..6f29a491de 100644 --- a/t/chainlint/blank-line.test +++ b/t/chainlint/blank-line.test @@ -1,3 +1,4 @@ +test_expect_success 'blank-line' ' ( nothing && @@ -8,3 +9,4 @@ ) +' diff --git a/t/chainlint/block-comment.expect b/t/chainlint/block-comment.expect index df2beea888..7926936c18 100644 --- a/t/chainlint/block-comment.expect +++ b/t/chainlint/block-comment.expect @@ -1,8 +1,8 @@ -( - { - # show a - echo a && - # show b - echo b - } -) +2 ( +3 { +4 # show a +5 echo a && +6 # show b +7 echo b +8 } +9 ) diff --git a/t/chainlint/block-comment.test b/t/chainlint/block-comment.test index df2beea888..934ef4113a 100644 --- a/t/chainlint/block-comment.test +++ b/t/chainlint/block-comment.test @@ -1,3 +1,4 @@ +test_expect_success 'block-comment' ' ( { # show a @@ -6,3 +7,4 @@ echo b } ) +' diff --git a/t/chainlint/block.expect b/t/chainlint/block.expect index 1c87326364..b62e3d58c3 100644 --- a/t/chainlint/block.expect +++ b/t/chainlint/block.expect @@ -1,23 +1,23 @@ -( - foo && - { - echo a ?!AMP?! - echo b - } && - bar && - { - echo c - } ?!AMP?! - baz -) && - -{ - echo a; ?!AMP?! echo b -} && -{ echo a; ?!AMP?! echo b; } && - -{ - echo "${var}9" && - echo "done" -} && -finis +2 ( +3 foo && +4 { +5 echo a ?!AMP?! +6 echo b +7 } && +8 bar && +9 { +10 echo c +11 } ?!AMP?! +12 baz +13 ) && +14 +15 { +16 echo a; ?!AMP?! echo b +17 } && +18 { echo a; ?!AMP?! echo b; } && +19 +20 { +21 echo "${var}9" && +22 echo "done" +23 } && +24 finis diff --git a/t/chainlint/block.test b/t/chainlint/block.test index 4ab69a4afc..a1b6b4dd32 100644 --- a/t/chainlint/block.test +++ b/t/chainlint/block.test @@ -1,3 +1,4 @@ +test_expect_success 'block' ' ( # LINT: missing "&&" after first "echo" foo && @@ -25,3 +26,4 @@ echo "done" } && finis +' diff --git a/t/chainlint/broken-chain.expect b/t/chainlint/broken-chain.expect index cfb58fb6b9..9a1838736f 100644 --- a/t/chainlint/broken-chain.expect +++ b/t/chainlint/broken-chain.expect @@ -1,6 +1,6 @@ -( - foo && - bar ?!AMP?! - baz && - wop -) +2 ( +3 foo && +4 bar ?!AMP?! +5 baz && +6 wop +7 ) diff --git a/t/chainlint/broken-chain.test b/t/chainlint/broken-chain.test index 2a44aa73b7..1966499ef9 100644 --- a/t/chainlint/broken-chain.test +++ b/t/chainlint/broken-chain.test @@ -1,3 +1,4 @@ +test_expect_success 'broken-chain' ' ( foo && # LINT: missing "&&" from "bar" @@ -6,3 +7,4 @@ # LINT: final statement before closing ")" legitimately lacks "&&" wop ) +' diff --git a/t/chainlint/case-comment.expect b/t/chainlint/case-comment.expect index 641c157b98..2442dd5f25 100644 --- a/t/chainlint/case-comment.expect +++ b/t/chainlint/case-comment.expect @@ -1,11 +1,11 @@ -( - case "$x" in - # found foo - x) foo ;; - # found other - *) - # treat it as bar - bar - ;; - esac -) +2 ( +3 case "$x" in +4 # found foo +5 x) foo ;; +6 # found other +7 *) +8 # treat it as bar +9 bar +10 ;; +11 esac +12 ) diff --git a/t/chainlint/case-comment.test b/t/chainlint/case-comment.test index 641c157b98..3f31ae9010 100644 --- a/t/chainlint/case-comment.test +++ b/t/chainlint/case-comment.test @@ -1,3 +1,4 @@ +test_expect_success 'case-comment' ' ( case "$x" in # found foo @@ -9,3 +10,4 @@ ;; esac ) +' diff --git a/t/chainlint/case.expect b/t/chainlint/case.expect index 31f280d8ce..c04c61ff36 100644 --- a/t/chainlint/case.expect +++ b/t/chainlint/case.expect @@ -1,19 +1,19 @@ -( - case "$x" in - x) foo ;; - *) bar ;; - esac && - foobar -) && -( - case "$x" in - x) foo ;; - *) bar ;; - esac ?!AMP?! - foobar -) && -( - case "$x" in 1) true;; esac && - case "$y" in 2) false;; esac ?!AMP?! - foobar -) +2 ( +3 case "$x" in +4 x) foo ;; +5 *) bar ;; +6 esac && +7 foobar +8 ) && +9 ( +10 case "$x" in +11 x) foo ;; +12 *) bar ;; +13 esac ?!AMP?! +14 foobar +15 ) && +16 ( +17 case "$x" in 1) true;; esac && +18 case "$y" in 2) false;; esac ?!AMP?! +19 foobar +20 ) diff --git a/t/chainlint/case.test b/t/chainlint/case.test index 4cb086bf87..bea21fee4f 100644 --- a/t/chainlint/case.test +++ b/t/chainlint/case.test @@ -1,3 +1,4 @@ +test_expect_success 'case' ' ( # LINT: "...)" arms in "case" not misinterpreted as subshell-closing ")" case "$x" in @@ -21,3 +22,4 @@ case "$y" in 2) false;; esac foobar ) +' diff --git a/t/chainlint/chain-break-background.expect b/t/chainlint/chain-break-background.expect index 20d0bb5333..d06deadae7 100644 --- a/t/chainlint/chain-break-background.expect +++ b/t/chainlint/chain-break-background.expect @@ -1,9 +1,9 @@ -JGIT_DAEMON_PID= && -git init --bare empty.git && ->empty.git/git-daemon-export-ok && -mkfifo jgit_daemon_output && -{ - jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output & - JGIT_DAEMON_PID=$! -} && -test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git +2 JGIT_DAEMON_PID= && +3 git init --bare empty.git && +4 >empty.git/git-daemon-export-ok && +5 mkfifo jgit_daemon_output && +6 { +7 jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output & +8 JGIT_DAEMON_PID=$! +9 } && +10 test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git diff --git a/t/chainlint/chain-break-background.test b/t/chainlint/chain-break-background.test index e10f656b05..c68e1b04d5 100644 --- a/t/chainlint/chain-break-background.test +++ b/t/chainlint/chain-break-background.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-background' ' JGIT_DAEMON_PID= && git init --bare empty.git && >empty.git/git-daemon-export-ok && @@ -8,3 +9,4 @@ mkfifo jgit_daemon_output && JGIT_DAEMON_PID=$! } && test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git +' diff --git a/t/chainlint/chain-break-continue.expect b/t/chainlint/chain-break-continue.expect index 47a3457710..4bb60aae25 100644 --- a/t/chainlint/chain-break-continue.expect +++ b/t/chainlint/chain-break-continue.expect @@ -1,12 +1,12 @@ -git ls-tree --name-only -r refs/notes/many_notes | -while read path -do - test "$path" = "foobar/non-note.txt" && continue - test "$path" = "deadbeef" && continue - test "$path" = "de/adbeef" && continue - - if test $(expr length "$path") -ne $hexsz - then - return 1 - fi -done +2 git ls-tree --name-only -r refs/notes/many_notes | +3 while read path +4 do +5 test "$path" = "foobar/non-note.txt" && continue +6 test "$path" = "deadbeef" && continue +7 test "$path" = "de/adbeef" && continue +8 +9 if test $(expr length "$path") -ne $hexsz +10 then +11 return 1 +12 fi +13 done diff --git a/t/chainlint/chain-break-continue.test b/t/chainlint/chain-break-continue.test index f0af71d8bd..de8119b204 100644 --- a/t/chainlint/chain-break-continue.test +++ b/t/chainlint/chain-break-continue.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-continue' ' git ls-tree --name-only -r refs/notes/many_notes | while read path do @@ -11,3 +12,4 @@ do return 1 fi done +' diff --git a/t/chainlint/chain-break-false.expect b/t/chainlint/chain-break-false.expect index 989766fb85..4f815f8e14 100644 --- a/t/chainlint/chain-break-false.expect +++ b/t/chainlint/chain-break-false.expect @@ -1,9 +1,9 @@ -if condition not satisified -then - echo it did not work... - echo failed! - false -else - echo it went okay ?!AMP?! - congratulate user -fi +2 if condition not satisified +3 then +4 echo it did not work... +5 echo failed! +6 false +7 else +8 echo it went okay ?!AMP?! +9 congratulate user +10 fi diff --git a/t/chainlint/chain-break-false.test b/t/chainlint/chain-break-false.test index a5aaff8c8a..f78ad911fc 100644 --- a/t/chainlint/chain-break-false.test +++ b/t/chainlint/chain-break-false.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-false' ' # LINT: broken &&-chain okay if explicit "false" signals failure if condition not satisified then @@ -8,3 +9,4 @@ else echo it went okay congratulate user fi +' diff --git a/t/chainlint/chain-break-return-exit.expect b/t/chainlint/chain-break-return-exit.expect index 4cd18e2edf..ba0ec51aa0 100644 --- a/t/chainlint/chain-break-return-exit.expect +++ b/t/chainlint/chain-break-return-exit.expect @@ -1,19 +1,19 @@ -case "$(git ls-files)" in -one) echo pass one ;; -*) echo bad one; return 1 ;; -esac && -( - case "$(git ls-files)" in - two) echo pass two ;; - *) echo bad two; exit 1 ;; - esac -) && -case "$(git ls-files)" in -dir/two"$LF"one) echo pass both ;; -*) echo bad; return 1 ;; -esac && - -for i in 1 2 3 4 ; do - git checkout main -b $i || return $? - test_commit $i $i $i tag$i || return $? -done +2 case "$(git ls-files)" in +3 one) echo pass one ;; +4 *) echo bad one; return 1 ;; +5 esac && +6 ( +7 case "$(git ls-files)" in +8 two) echo pass two ;; +9 *) echo bad two; exit 1 ;; +10 esac +11 ) && +12 case "$(git ls-files)" in +13 dir/two"$LF"one) echo pass both ;; +14 *) echo bad; return 1 ;; +15 esac && +16 +17 for i in 1 2 3 4 ; do +18 git checkout main -b $i || return $? +19 test_commit $i $i $i tag$i || return $? +20 done diff --git a/t/chainlint/chain-break-return-exit.test b/t/chainlint/chain-break-return-exit.test index 46542edf88..b6f519bb4d 100644 --- a/t/chainlint/chain-break-return-exit.test +++ b/t/chainlint/chain-break-return-exit.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-return-exit' ' case "$(git ls-files)" in one) echo pass one ;; # LINT: broken &&-chain okay if explicit "return 1" signals failuire @@ -21,3 +22,4 @@ for i in 1 2 3 4 ; do git checkout main -b $i || return $? test_commit $i $i $i tag$i || return $? done +' diff --git a/t/chainlint/chain-break-status.expect b/t/chainlint/chain-break-status.expect index e6b3b2193e..23c0caa7d8 100644 --- a/t/chainlint/chain-break-status.expect +++ b/t/chainlint/chain-break-status.expect @@ -1,9 +1,9 @@ -OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && -test_match_signal 13 "$OUT" && - -{ test-tool sigchain >actual; ret=$?; } && -{ - test_match_signal 15 "$ret" || - test "$ret" = 3 -} && -test_cmp expect actual +2 OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && +3 test_match_signal 13 "$OUT" && +4 +5 { test-tool sigchain >actual; ret=$?; } && +6 { +7 test_match_signal 15 "$ret" || +8 test "$ret" = 3 +9 } && +10 test_cmp expect actual diff --git a/t/chainlint/chain-break-status.test b/t/chainlint/chain-break-status.test index a6602a7b99..d9fee190d9 100644 --- a/t/chainlint/chain-break-status.test +++ b/t/chainlint/chain-break-status.test @@ -1,3 +1,4 @@ +test_expect_success 'chain-break-status' ' # LINT: broken &&-chain okay if next command handles "$?" explicitly OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && test_match_signal 13 "$OUT" && @@ -9,3 +10,4 @@ test_match_signal 13 "$OUT" && test "$ret" = 3 } && test_cmp expect actual +' diff --git a/t/chainlint/chained-block.expect b/t/chainlint/chained-block.expect index 574cdceb07..a546b714a6 100644 --- a/t/chainlint/chained-block.expect +++ b/t/chainlint/chained-block.expect @@ -1,9 +1,9 @@ -echo nobody home && { - test the doohicky ?!AMP?! - right now -} && - -GIT_EXTERNAL_DIFF=echo git diff | { - read path oldfile oldhex oldmode newfile newhex newmode && - test "z$oh" = "z$oldhex" -} +2 echo nobody home && { +3 test the doohicky ?!AMP?! +4 right now +5 } && +6 +7 GIT_EXTERNAL_DIFF=echo git diff | { +8 read path oldfile oldhex oldmode newfile newhex newmode && +9 test "z$oh" = "z$oldhex" +10 } diff --git a/t/chainlint/chained-block.test b/t/chainlint/chained-block.test index 86f81ece63..71ef1d0b7f 100644 --- a/t/chainlint/chained-block.test +++ b/t/chainlint/chained-block.test @@ -1,3 +1,4 @@ +test_expect_success 'chained-block' ' # LINT: start of block chained to preceding command echo nobody home && { test the doohicky @@ -9,3 +10,4 @@ GIT_EXTERNAL_DIFF=echo git diff | { read path oldfile oldhex oldmode newfile newhex newmode && test "z$oh" = "z$oldhex" } +' diff --git a/t/chainlint/chained-subshell.expect b/t/chainlint/chained-subshell.expect index 83810ea7ec..f78b268291 100644 --- a/t/chainlint/chained-subshell.expect +++ b/t/chainlint/chained-subshell.expect @@ -1,10 +1,10 @@ -mkdir sub && ( - cd sub && - foo the bar ?!AMP?! - nuff said -) && - -cut "-d " -f actual | (read s1 s2 s3 && -test -f $s1 ?!AMP?! -test $(cat $s2) = tree2path1 && -test $(cat $s3) = tree3path1) +2 mkdir sub && ( +3 cd sub && +4 foo the bar ?!AMP?! +5 nuff said +6 ) && +7 +8 cut "-d " -f actual | (read s1 s2 s3 && +9 test -f $s1 ?!AMP?! +10 test $(cat $s2) = tree2path1 && +11 test $(cat $s3) = tree3path1) diff --git a/t/chainlint/chained-subshell.test b/t/chainlint/chained-subshell.test index 4ff6ddd8cb..1f11f65398 100644 --- a/t/chainlint/chained-subshell.test +++ b/t/chainlint/chained-subshell.test @@ -1,3 +1,4 @@ +test_expect_success 'chained-subshell' ' # LINT: start of subshell chained to preceding command mkdir sub && ( cd sub && @@ -11,3 +12,4 @@ test -f $s1 test $(cat $s2) = tree2path1 && # LINT: closing subshell ")" correctly detected on same line as "$(...)" test $(cat $s3) = tree3path1) +' diff --git a/t/chainlint/close-nested-and-parent-together.expect b/t/chainlint/close-nested-and-parent-together.expect index 72d482f76d..4167e54a59 100644 --- a/t/chainlint/close-nested-and-parent-together.expect +++ b/t/chainlint/close-nested-and-parent-together.expect @@ -1,3 +1,3 @@ -(cd foo && - (bar && - baz)) +2 (cd foo && +3 (bar && +4 baz)) diff --git a/t/chainlint/close-nested-and-parent-together.test b/t/chainlint/close-nested-and-parent-together.test index 72d482f76d..56b28b186b 100644 --- a/t/chainlint/close-nested-and-parent-together.test +++ b/t/chainlint/close-nested-and-parent-together.test @@ -1,3 +1,5 @@ +test_expect_success 'close-nested-and-parent-together' ' (cd foo && (bar && baz)) +' diff --git a/t/chainlint/close-subshell.expect b/t/chainlint/close-subshell.expect index 2192a2870a..a272cfe72e 100644 --- a/t/chainlint/close-subshell.expect +++ b/t/chainlint/close-subshell.expect @@ -1,26 +1,26 @@ -( - foo -) && -( - bar -) >out && -( - baz -) 2>err && -( - boo -) <input && -( - bip -) | wuzzle && -( - bop -) | fazz \ - fozz && -( - bup -) | -fuzzle && -( - yop -) +2 ( +3 foo +4 ) && +5 ( +6 bar +7 ) >out && +8 ( +9 baz +10 ) 2>err && +11 ( +12 boo +13 ) <input && +14 ( +15 bip +16 ) | wuzzle && +17 ( +18 bop +19 ) | fazz \ +20 fozz && +21 ( +22 bup +23 ) | +24 fuzzle && +25 ( +26 yop +27 ) diff --git a/t/chainlint/close-subshell.test b/t/chainlint/close-subshell.test index 508ca447fd..b99f80569d 100644 --- a/t/chainlint/close-subshell.test +++ b/t/chainlint/close-subshell.test @@ -1,3 +1,4 @@ +test_expect_success 'close-subshell' ' # LINT: closing ")" with various decorations ("&&", ">", "|", etc.) ( foo @@ -25,3 +26,4 @@ fuzzle && ( yop ) +' diff --git a/t/chainlint/command-substitution-subsubshell.expect b/t/chainlint/command-substitution-subsubshell.expect index ec42f2c30c..f2a9312dc8 100644 --- a/t/chainlint/command-substitution-subsubshell.expect +++ b/t/chainlint/command-substitution-subsubshell.expect @@ -1,2 +1,2 @@ -OUT=$( ((large_git 1>&3) | :) 3>&1 ) && -test_match_signal 13 "$OUT" +2 OUT=$( ((large_git 1>&3) | :) 3>&1 ) && +3 test_match_signal 13 "$OUT" diff --git a/t/chainlint/command-substitution-subsubshell.test b/t/chainlint/command-substitution-subsubshell.test index 321de2951c..4ea772d60a 100644 --- a/t/chainlint/command-substitution-subsubshell.test +++ b/t/chainlint/command-substitution-subsubshell.test @@ -1,3 +1,5 @@ +test_expect_success 'command-substitution-subsubshell' ' # LINT: subshell nested in subshell nested in command substitution OUT=$( ((large_git 1>&3) | :) 3>&1 ) && test_match_signal 13 "$OUT" +' diff --git a/t/chainlint/command-substitution.expect b/t/chainlint/command-substitution.expect index c72e4df9e7..5e31b36db6 100644 --- a/t/chainlint/command-substitution.expect +++ b/t/chainlint/command-substitution.expect @@ -1,9 +1,9 @@ -( - foo && - bar=$(gobble) && - baz -) && -( - bar=$(gobble blocks) ?!AMP?! - baz -) +2 ( +3 foo && +4 bar=$(gobble) && +5 baz +6 ) && +7 ( +8 bar=$(gobble blocks) ?!AMP?! +9 baz +10 ) diff --git a/t/chainlint/command-substitution.test b/t/chainlint/command-substitution.test index 3bbb002a4c..494d671e80 100644 --- a/t/chainlint/command-substitution.test +++ b/t/chainlint/command-substitution.test @@ -1,3 +1,4 @@ +test_expect_success 'command-substitution' ' ( foo && # LINT: closing ")" of $(...) not misinterpreted as subshell-closing ")" @@ -9,3 +10,4 @@ bar=$(gobble blocks) baz ) +' diff --git a/t/chainlint/comment.expect b/t/chainlint/comment.expect index a68f1f9d7c..584098d6ba 100644 --- a/t/chainlint/comment.expect +++ b/t/chainlint/comment.expect @@ -1,8 +1,8 @@ -( - # comment 1 - nothing && - # comment 2 - something - # comment 3 - # comment 4 -) +2 ( +3 # comment 1 +4 nothing && +5 # comment 2 +6 something +7 # comment 3 +8 # comment 4 +9 ) diff --git a/t/chainlint/comment.test b/t/chainlint/comment.test index 113c0c466f..c488beac0d 100644 --- a/t/chainlint/comment.test +++ b/t/chainlint/comment.test @@ -1,3 +1,4 @@ +test_expect_success 'comment' ' ( # LINT: swallow comment lines # comment 1 @@ -9,3 +10,4 @@ # comment 3 # comment 4 ) +' diff --git a/t/chainlint/complex-if-in-cuddled-loop.expect b/t/chainlint/complex-if-in-cuddled-loop.expect index dac2d0fd1d..3a740103db 100644 --- a/t/chainlint/complex-if-in-cuddled-loop.expect +++ b/t/chainlint/complex-if-in-cuddled-loop.expect @@ -1,9 +1,9 @@ -(for i in a b c; do - if test "$(echo $(waffle bat))" = "eleventeen" && - test "$x" = "$y"; then - : - else - echo >file - fi ?!LOOP?! - done) && -test ! -f file +2 (for i in a b c; do +3 if test "$(echo $(waffle bat))" = "eleventeen" && +4 test "$x" = "$y"; then +5 : +6 else +7 echo >file +8 fi ?!LOOP?! +9 done) && +10 test ! -f file diff --git a/t/chainlint/complex-if-in-cuddled-loop.test b/t/chainlint/complex-if-in-cuddled-loop.test index 5efeda58b2..f98ae4c42d 100644 --- a/t/chainlint/complex-if-in-cuddled-loop.test +++ b/t/chainlint/complex-if-in-cuddled-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'complex-if-in-cuddled-loop' ' # LINT: "for" loop cuddled with "(" and ")" and nested "if" with complex # LINT: multi-line condition; indented with spaces, not tabs (for i in a b c; do @@ -9,3 +10,4 @@ fi done) && test ! -f file +' diff --git a/t/chainlint/cuddled-if-then-else.expect b/t/chainlint/cuddled-if-then-else.expect index 1d8ed58c49..72da8794cb 100644 --- a/t/chainlint/cuddled-if-then-else.expect +++ b/t/chainlint/cuddled-if-then-else.expect @@ -1,6 +1,6 @@ -(if test -z ""; then - echo empty - else - echo bizzy - fi) && -echo foobar +2 (if test -z ""; then +3 echo empty +4 else +5 echo bizzy +6 fi) && +7 echo foobar diff --git a/t/chainlint/cuddled-if-then-else.test b/t/chainlint/cuddled-if-then-else.test index 7c53f4efe3..b1b42e1aac 100644 --- a/t/chainlint/cuddled-if-then-else.test +++ b/t/chainlint/cuddled-if-then-else.test @@ -1,3 +1,4 @@ +test_expect_success 'cuddled-if-then-else' ' # LINT: "if" cuddled with "(" and ")"; indented with spaces, not tabs (if test -z ""; then echo empty @@ -5,3 +6,4 @@ echo bizzy fi) && echo foobar +' diff --git a/t/chainlint/cuddled-loop.expect b/t/chainlint/cuddled-loop.expect index 9cf260708e..c38585c756 100644 --- a/t/chainlint/cuddled-loop.expect +++ b/t/chainlint/cuddled-loop.expect @@ -1,4 +1,4 @@ -( while read x - do foobar bop || exit 1 - done <file ) && -outside subshell +2 ( while read x +3 do foobar bop || exit 1 +4 done <file ) && +5 outside subshell diff --git a/t/chainlint/cuddled-loop.test b/t/chainlint/cuddled-loop.test index 3c2a62f751..6fccb6ac22 100644 --- a/t/chainlint/cuddled-loop.test +++ b/t/chainlint/cuddled-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'cuddled-loop' ' # LINT: "while" loop cuddled with "(" and ")", with embedded (allowed) # LINT: "|| exit {n}" to exit loop early, and using redirection "<" to feed # LINT: loop; indented with spaces, not tabs @@ -5,3 +6,4 @@ do foobar bop || exit 1 done <file ) && outside subshell +' diff --git a/t/chainlint/cuddled.expect b/t/chainlint/cuddled.expect index c3e0be4047..b06d638311 100644 --- a/t/chainlint/cuddled.expect +++ b/t/chainlint/cuddled.expect @@ -1,17 +1,17 @@ -(cd foo && - bar -) && - -(cd foo ?!AMP?! - bar -) && - -( - cd foo && - bar) && - -(cd foo && - bar) && - -(cd foo ?!AMP?! - bar) +2 (cd foo && +3 bar +4 ) && +5 +6 (cd foo ?!AMP?! +7 bar +8 ) && +9 +10 ( +11 cd foo && +12 bar) && +13 +14 (cd foo && +15 bar) && +16 +17 (cd foo ?!AMP?! +18 bar) diff --git a/t/chainlint/cuddled.test b/t/chainlint/cuddled.test index 257b5b5eed..5a6ef7a4a6 100644 --- a/t/chainlint/cuddled.test +++ b/t/chainlint/cuddled.test @@ -1,3 +1,4 @@ +test_expect_success 'cuddled' ' # LINT: first subshell statement cuddled with opening "(" (cd foo && bar @@ -20,3 +21,4 @@ # LINT: same with missing "&&" (cd foo bar) +' diff --git a/t/chainlint/double-here-doc.expect b/t/chainlint/double-here-doc.expect index cd584a4357..48c04ecd58 100644 --- a/t/chainlint/double-here-doc.expect +++ b/t/chainlint/double-here-doc.expect @@ -1,12 +1,12 @@ -run_sub_test_lib_test_err run-inv-range-start \ - "--run invalid range start" \ - --run="a-5" <<-\EOF && -test_expect_success "passing test #1" "true" -test_done -EOF -check_sub_test_lib_test_err run-inv-range-start \ - <<-\EOF_OUT 3<<-EOF_ERR -> FATAL: Unexpected exit with code 1 -EOF_OUT -> error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ} -EOF_ERR +2 run_sub_test_lib_test_err run-inv-range-start \ +3 "--run invalid range start" \ +4 --run="a-5" <<-\EOF && +5 test_expect_success "passing test #1" "true" +6 test_done +7 EOF +8 check_sub_test_lib_test_err run-inv-range-start \ +9 <<-\EOF_OUT 3<<-EOF_ERR +10 > FATAL: Unexpected exit with code 1 +11 EOF_OUT +12 > error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ} +13 EOF_ERR diff --git a/t/chainlint/double-here-doc.test b/t/chainlint/double-here-doc.test index cd584a4357..1b69b7a651 100644 --- a/t/chainlint/double-here-doc.test +++ b/t/chainlint/double-here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'double-here-doc' ' run_sub_test_lib_test_err run-inv-range-start \ "--run invalid range start" \ --run="a-5" <<-\EOF && @@ -10,3 +11,4 @@ check_sub_test_lib_test_err run-inv-range-start \ EOF_OUT > error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ} EOF_ERR +' diff --git a/t/chainlint/dqstring-line-splice.expect b/t/chainlint/dqstring-line-splice.expect index 37eab80738..2ca1c92cd6 100644 --- a/t/chainlint/dqstring-line-splice.expect +++ b/t/chainlint/dqstring-line-splice.expect @@ -1,5 +1,5 @@ - -echo 'fatal: reword option of --fixup is mutually exclusive with' '--patch/--interactive/--all/--include/--only' >expect && -test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual && -test_cmp expect actual - +2 +3 echo 'fatal: reword option of --fixup is mutually exclusive with' '--patch/--interactive/--all/--include/--only' >expect && +4 test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual && +5 test_cmp expect actual +6 diff --git a/t/chainlint/dqstring-line-splice.test b/t/chainlint/dqstring-line-splice.test index b40714439f..f6aa637be8 100644 --- a/t/chainlint/dqstring-line-splice.test +++ b/t/chainlint/dqstring-line-splice.test @@ -1,3 +1,4 @@ +test_expect_success 'dqstring-line-splice' ' # LINT: line-splice within DQ-string '" echo 'fatal: reword option of --fixup is mutually exclusive with'\ @@ -5,3 +6,4 @@ echo 'fatal: reword option of --fixup is mutually exclusive with'\ test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual && test_cmp expect actual "' +' diff --git a/t/chainlint/dqstring-no-interpolate.expect b/t/chainlint/dqstring-no-interpolate.expect index 087eda15e4..c9f75849c5 100644 --- a/t/chainlint/dqstring-no-interpolate.expect +++ b/t/chainlint/dqstring-no-interpolate.expect @@ -1,12 +1,12 @@ -grep "^ ! [rejected][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out && - -grep "^\.git$" output.txt && - - -( - cd client$version && - GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. $(cat ../input) -) >output && - cut -d ' ' -f 2 <output | sort >actual && - test_cmp expect actual - +2 grep "^ ! [rejected][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out && +3 +4 grep "^\.git$" output.txt && +5 +6 +7 ( +8 cd client$version && +9 GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. $(cat ../input) +10 ) >output && +11 cut -d ' ' -f 2 <output | sort >actual && +12 test_cmp expect actual +13 diff --git a/t/chainlint/dqstring-no-interpolate.test b/t/chainlint/dqstring-no-interpolate.test index d2f4219cbb..7ae079b558 100644 --- a/t/chainlint/dqstring-no-interpolate.test +++ b/t/chainlint/dqstring-no-interpolate.test @@ -1,3 +1,4 @@ +test_expect_success 'dqstring-no-interpolate' ' # LINT: regex dollar-sign eol anchor in double-quoted string not special grep "^ ! \[rejected\][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out && @@ -13,3 +14,4 @@ grep "^\\.git\$" output.txt && cut -d ' ' -f 2 <output | sort >actual && test_cmp expect actual "' +' diff --git a/t/chainlint/empty-here-doc.expect b/t/chainlint/empty-here-doc.expect index 8507721192..54b33f823a 100644 --- a/t/chainlint/empty-here-doc.expect +++ b/t/chainlint/empty-here-doc.expect @@ -1,4 +1,4 @@ -git ls-tree $tree path >current && -cat >expected <<\EOF && -EOF -test_output +2 git ls-tree $tree path >current && +3 cat >expected <<\EOF && +4 EOF +5 test_output diff --git a/t/chainlint/empty-here-doc.test b/t/chainlint/empty-here-doc.test index 24fc165de3..8b7ab6eb5f 100644 --- a/t/chainlint/empty-here-doc.test +++ b/t/chainlint/empty-here-doc.test @@ -1,5 +1,7 @@ +test_expect_success 'empty-here-doc' ' git ls-tree $tree path >current && # LINT: empty here-doc cat >expected <<\EOF && EOF test_output +' diff --git a/t/chainlint/exclamation.expect b/t/chainlint/exclamation.expect index 765a35bb4c..078744b61b 100644 --- a/t/chainlint/exclamation.expect +++ b/t/chainlint/exclamation.expect @@ -1,4 +1,4 @@ -if ! condition; then echo nope; else yep; fi && -test_prerequisite !MINGW && -mail uucp!address && -echo !whatever! +2 if ! condition; then echo nope; else yep; fi && +3 test_prerequisite !MINGW && +4 mail uucp!address && +5 echo !whatever! diff --git a/t/chainlint/exclamation.test b/t/chainlint/exclamation.test index 323595b5bd..796de21b7c 100644 --- a/t/chainlint/exclamation.test +++ b/t/chainlint/exclamation.test @@ -1,3 +1,4 @@ +test_expect_success 'exclamation' ' # LINT: "! word" is two tokens if ! condition; then echo nope; else yep; fi && # LINT: "!word" is single token, not two tokens "!" and "word" @@ -6,3 +7,4 @@ test_prerequisite !MINGW && mail uucp!address && # LINT: "!word!" is single token, not three tokens "!", "word", and "!" echo !whatever! +' diff --git a/t/chainlint/exit-loop.expect b/t/chainlint/exit-loop.expect index f76aa60466..407278094c 100644 --- a/t/chainlint/exit-loop.expect +++ b/t/chainlint/exit-loop.expect @@ -1,24 +1,24 @@ -( - for i in a b c - do - foo || exit 1 - bar && - baz - done -) && -( - while true - do - foo || exit 1 - bar && - baz - done -) && -( - i=0 && - while test $i -lt 10 - do - echo $i || exit - i=$(($i + 1)) - done -) +2 ( +3 for i in a b c +4 do +5 foo || exit 1 +6 bar && +7 baz +8 done +9 ) && +10 ( +11 while true +12 do +13 foo || exit 1 +14 bar && +15 baz +16 done +17 ) && +18 ( +19 i=0 && +20 while test $i -lt 10 +21 do +22 echo $i || exit +23 i=$(($i + 1)) +24 done +25 ) diff --git a/t/chainlint/exit-loop.test b/t/chainlint/exit-loop.test index 2f038207e1..7e8b68b465 100644 --- a/t/chainlint/exit-loop.test +++ b/t/chainlint/exit-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'exit-loop' ' ( for i in a b c do @@ -25,3 +26,4 @@ i=$(($i + 1)) done ) +' diff --git a/t/chainlint/exit-subshell.expect b/t/chainlint/exit-subshell.expect index da80339f78..793db12453 100644 --- a/t/chainlint/exit-subshell.expect +++ b/t/chainlint/exit-subshell.expect @@ -1,5 +1,5 @@ -( - foo || exit 1 - bar && - baz -) +2 ( +3 foo || exit 1 +4 bar && +5 baz +6 ) diff --git a/t/chainlint/exit-subshell.test b/t/chainlint/exit-subshell.test index 4e6ab69b88..05dff55cd7 100644 --- a/t/chainlint/exit-subshell.test +++ b/t/chainlint/exit-subshell.test @@ -1,6 +1,8 @@ +test_expect_success 'exit-subshell' ' ( # LINT: "|| exit {n}" valid subshell escape without hurting &&-chain foo || exit 1 bar && baz ) +' diff --git a/t/chainlint/for-loop-abbreviated.expect b/t/chainlint/for-loop-abbreviated.expect index 02c0d15cca..5574831976 100644 --- a/t/chainlint/for-loop-abbreviated.expect +++ b/t/chainlint/for-loop-abbreviated.expect @@ -1,5 +1,5 @@ -for it -do - path=$(expr "$it" : ([^:]*)) && - git update-index --add "$path" || exit -done +2 for it +3 do +4 path=$(expr "$it" : ([^:]*)) && +5 git update-index --add "$path" || exit +6 done diff --git a/t/chainlint/for-loop-abbreviated.test b/t/chainlint/for-loop-abbreviated.test index 1084eccb89..1dd14f2a44 100644 --- a/t/chainlint/for-loop-abbreviated.test +++ b/t/chainlint/for-loop-abbreviated.test @@ -1,6 +1,8 @@ +test_expect_success 'for-loop-abbreviated' ' # LINT: for-loop lacking optional "in [word...]" before "do" for it do path=$(expr "$it" : '\([^:]*\)') && git update-index --add "$path" || exit done +' diff --git a/t/chainlint/for-loop.expect b/t/chainlint/for-loop.expect index d2237f1e38..908aeedf96 100644 --- a/t/chainlint/for-loop.expect +++ b/t/chainlint/for-loop.expect @@ -1,14 +1,14 @@ -( - for i in a b c - do - echo $i ?!AMP?! - cat <<-\EOF ?!LOOP?! - bar - EOF - done ?!AMP?! - - for i in a b c; do - echo $i && - cat $i ?!LOOP?! - done -) +2 ( +3 for i in a b c +4 do +5 echo $i ?!AMP?! +6 cat <<-\EOF ?!LOOP?! +7 bar +8 EOF +9 done ?!AMP?! +10 +11 for i in a b c; do +12 echo $i && +13 cat $i ?!LOOP?! +14 done +15 ) diff --git a/t/chainlint/for-loop.test b/t/chainlint/for-loop.test index 6cb3428158..6f2489eb19 100644 --- a/t/chainlint/for-loop.test +++ b/t/chainlint/for-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'for-loop' ' ( # LINT: "for", "do", "done" do not need "&&" for i in a b c @@ -17,3 +18,4 @@ cat $i done ) +' diff --git a/t/chainlint/function.expect b/t/chainlint/function.expect index dd7c997a3c..c226246b25 100644 --- a/t/chainlint/function.expect +++ b/t/chainlint/function.expect @@ -1,11 +1,11 @@ -sha1_file() { - echo "$*" | sed "s#..#.git/objects/&/#" -} && - -remove_object() { - file=$(sha1_file "$*") && - test -e "$file" ?!AMP?! - rm -f "$file" -} ?!AMP?! - -sha1_file arg && remove_object arg +2 sha1_file() { +3 echo "$*" | sed "s#..#.git/objects/&/#" +4 } && +5 +6 remove_object() { +7 file=$(sha1_file "$*") && +8 test -e "$file" ?!AMP?! +9 rm -f "$file" +10 } ?!AMP?! +11 +12 sha1_file arg && remove_object arg diff --git a/t/chainlint/function.test b/t/chainlint/function.test index 5ee59562c9..763fcf3f87 100644 --- a/t/chainlint/function.test +++ b/t/chainlint/function.test @@ -1,3 +1,4 @@ +test_expect_success 'function' ' # LINT: "()" in function definition not mistaken for subshell sha1_file() { echo "$*" | sed "s#..#.git/objects/&/#" @@ -11,3 +12,4 @@ remove_object() { } sha1_file arg && remove_object arg +' diff --git a/t/chainlint/here-doc-body-indent.expect b/t/chainlint/here-doc-body-indent.expect new file mode 100644 index 0000000000..4323acc93d --- /dev/null +++ b/t/chainlint/here-doc-body-indent.expect @@ -0,0 +1,2 @@ +2 echo "we should find this" ?!AMP?! +3 echo "even though our heredoc has its indent stripped" diff --git a/t/chainlint/here-doc-body-indent.test b/t/chainlint/here-doc-body-indent.test new file mode 100644 index 0000000000..39ff970ef3 --- /dev/null +++ b/t/chainlint/here-doc-body-indent.test @@ -0,0 +1,4 @@ +test_expect_success 'here-doc-body-indent' - <<-\EOT + echo "we should find this" + echo "even though our heredoc has its indent stripped" +EOT diff --git a/t/chainlint/here-doc-body-pathological.expect b/t/chainlint/here-doc-body-pathological.expect new file mode 100644 index 0000000000..a93a1fa3aa --- /dev/null +++ b/t/chainlint/here-doc-body-pathological.expect @@ -0,0 +1,7 @@ +2 echo "outer here-doc does not allow indented end-tag" ?!AMP?! +3 cat >file <<-\EOF && +4 but this inner here-doc +5 does allow indented EOF +6 EOF +7 echo "missing chain after" ?!AMP?! +8 echo "but this line is OK because it's the end" diff --git a/t/chainlint/here-doc-body-pathological.test b/t/chainlint/here-doc-body-pathological.test new file mode 100644 index 0000000000..7d2daa44f9 --- /dev/null +++ b/t/chainlint/here-doc-body-pathological.test @@ -0,0 +1,9 @@ +test_expect_success 'here-doc-body-pathological' - <<\EOF + echo "outer here-doc does not allow indented end-tag" + cat >file <<-\EOF && + but this inner here-doc + does allow indented EOF + EOF + echo "missing chain after" + echo "but this line is OK because it's the end" +EOF diff --git a/t/chainlint/here-doc-body.expect b/t/chainlint/here-doc-body.expect new file mode 100644 index 0000000000..ddf1c412af --- /dev/null +++ b/t/chainlint/here-doc-body.expect @@ -0,0 +1,7 @@ +2 echo "missing chain before" ?!AMP?! +3 cat >file <<-\EOF && +4 inside inner here-doc +5 these are not shell commands +6 EOF +7 echo "missing chain after" ?!AMP?! +8 echo "but this line is OK because it's the end" diff --git a/t/chainlint/here-doc-body.test b/t/chainlint/here-doc-body.test new file mode 100644 index 0000000000..989ac2f4e1 --- /dev/null +++ b/t/chainlint/here-doc-body.test @@ -0,0 +1,9 @@ +test_expect_success 'here-doc-body' - <<\EOT + echo "missing chain before" + cat >file <<-\EOF && + inside inner here-doc + these are not shell commands + EOF + echo "missing chain after" + echo "but this line is OK because it's the end" +EOT diff --git a/t/chainlint/here-doc-close-subshell.expect b/t/chainlint/here-doc-close-subshell.expect index 7d9c2b5607..965813f463 100644 --- a/t/chainlint/here-doc-close-subshell.expect +++ b/t/chainlint/here-doc-close-subshell.expect @@ -1,4 +1,4 @@ -( - cat <<-\INPUT) - fizz - INPUT +2 ( +3 cat <<-\INPUT) +4 fizz +5 INPUT diff --git a/t/chainlint/here-doc-close-subshell.test b/t/chainlint/here-doc-close-subshell.test index b857ff5467..2458f3323b 100644 --- a/t/chainlint/here-doc-close-subshell.test +++ b/t/chainlint/here-doc-close-subshell.test @@ -1,5 +1,7 @@ +test_expect_success 'here-doc-close-subshell' ' ( # LINT: line contains here-doc and closes nested subshell cat <<-\INPUT) fizz INPUT +' diff --git a/t/chainlint/here-doc-double.expect b/t/chainlint/here-doc-double.expect new file mode 100644 index 0000000000..20dba4b452 --- /dev/null +++ b/t/chainlint/here-doc-double.expect @@ -0,0 +1,2 @@ +8 echo "actual test commands" ?!AMP?! +9 echo "that should be checked" diff --git a/t/chainlint/here-doc-double.test b/t/chainlint/here-doc-double.test new file mode 100644 index 0000000000..777389f0d9 --- /dev/null +++ b/t/chainlint/here-doc-double.test @@ -0,0 +1,10 @@ +# This is obviously a ridiculous thing to do, but we should be able +# to handle two here-docs on the same line, and attribute them +# correctly. +test_expect_success "$(cat <<END_OF_PREREQS)" 'here-doc-double' - <<\EOT +SOME +PREREQS +END_OF_PREREQS + echo "actual test commands" + echo "that should be checked" +EOT diff --git a/t/chainlint/here-doc-indent-operator.expect b/t/chainlint/here-doc-indent-operator.expect index f92a7ce999..277a11202d 100644 --- a/t/chainlint/here-doc-indent-operator.expect +++ b/t/chainlint/here-doc-indent-operator.expect @@ -1,11 +1,11 @@ -cat >expect <<- EOF && -header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 -num_commits: $1 -chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data -EOF - -cat >expect << -EOF ?!AMP?! -this is not indented --EOF - -cleanup +2 cat >expect <<- EOF && +3 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 +4 num_commits: $1 +5 chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data +6 EOF +7 +8 cat >expect << -EOF ?!AMP?! +9 this is not indented +10 -EOF +11 +12 cleanup diff --git a/t/chainlint/here-doc-indent-operator.test b/t/chainlint/here-doc-indent-operator.test index c8a6f18eb4..a2656f47c1 100644 --- a/t/chainlint/here-doc-indent-operator.test +++ b/t/chainlint/here-doc-indent-operator.test @@ -1,3 +1,4 @@ +test_expect_success 'here-doc-indent-operator' ' # LINT: whitespace between operator "<<-" and tag legal cat >expect <<- EOF && header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 @@ -11,3 +12,4 @@ this is not indented -EOF cleanup +' diff --git a/t/chainlint/here-doc-multi-line-command-subst.expect b/t/chainlint/here-doc-multi-line-command-subst.expect index b7364c82c8..41b55f6437 100644 --- a/t/chainlint/here-doc-multi-line-command-subst.expect +++ b/t/chainlint/here-doc-multi-line-command-subst.expect @@ -1,8 +1,8 @@ -( - x=$(bobble <<-\END && - fossil - vegetable - END - wiffle) ?!AMP?! - echo $x -) +2 ( +3 x=$(bobble <<-\END && +4 fossil +5 vegetable +6 END +7 wiffle) ?!AMP?! +8 echo $x +9 ) diff --git a/t/chainlint/here-doc-multi-line-command-subst.test b/t/chainlint/here-doc-multi-line-command-subst.test index 899bc5de8b..8710a8c483 100644 --- a/t/chainlint/here-doc-multi-line-command-subst.test +++ b/t/chainlint/here-doc-multi-line-command-subst.test @@ -1,3 +1,4 @@ +test_expect_success 'here-doc-multi-line-command-subst' ' ( # LINT: line contains here-doc and opens multi-line $(...) x=$(bobble <<-\END && @@ -7,3 +8,4 @@ wiffle) echo $x ) +' diff --git a/t/chainlint/here-doc-multi-line-string.expect b/t/chainlint/here-doc-multi-line-string.expect index 6c13bdcbfb..c71828589e 100644 --- a/t/chainlint/here-doc-multi-line-string.expect +++ b/t/chainlint/here-doc-multi-line-string.expect @@ -1,7 +1,7 @@ -( - cat <<-\TXT && echo "multi-line - string" ?!AMP?! - fizzle - TXT - bap -) +2 ( +3 cat <<-\TXT && echo "multi-line +4 string" ?!AMP?! +5 fizzle +6 TXT +7 bap +8 ) diff --git a/t/chainlint/here-doc-multi-line-string.test b/t/chainlint/here-doc-multi-line-string.test index a53edbcc8d..2f496002fd 100644 --- a/t/chainlint/here-doc-multi-line-string.test +++ b/t/chainlint/here-doc-multi-line-string.test @@ -1,3 +1,4 @@ +test_expect_success 'here-doc-multi-line-string' ' ( # LINT: line contains here-doc and opens multi-line string cat <<-\TXT && echo "multi-line @@ -6,3 +7,4 @@ TXT bap ) +' diff --git a/t/chainlint/here-doc.expect b/t/chainlint/here-doc.expect index 91b961242a..2c382dd8eb 100644 --- a/t/chainlint/here-doc.expect +++ b/t/chainlint/here-doc.expect @@ -1,25 +1,25 @@ -boodle wobba \ - gorgo snoot \ - wafta snurb <<EOF && -quoth the raven, -nevermore... -EOF - -cat <<-Arbitrary_Tag_42 >foo && -snoz -boz -woz -Arbitrary_Tag_42 - -cat <<"zump" >boo && -snoz -boz -woz -zump - -horticulture <<\EOF -gomez -morticia -wednesday -pugsly -EOF +2 boodle wobba \ +3 gorgo snoot \ +4 wafta snurb <<EOF && +5 quoth the raven, +6 nevermore... +7 EOF +8 +9 cat <<-Arbitrary_Tag_42 >foo && +10 snoz +11 boz +12 woz +13 Arbitrary_Tag_42 +14 +15 cat <<"zump" >boo && +16 snoz +17 boz +18 woz +19 zump +20 +21 horticulture <<\EOF +22 gomez +23 morticia +24 wednesday +25 pugsly +26 EOF diff --git a/t/chainlint/here-doc.test b/t/chainlint/here-doc.test index 3f5f92cad3..c91b695319 100644 --- a/t/chainlint/here-doc.test +++ b/t/chainlint/here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'here-doc' ' # LINT: stitch together incomplete \-ending lines # LINT: swallow here-doc to avoid false positives in content boodle wobba \ @@ -28,3 +29,4 @@ morticia wednesday pugsly EOF +' diff --git a/t/chainlint/if-condition-split.expect b/t/chainlint/if-condition-split.expect index ee745ef8d7..9daf3d294a 100644 --- a/t/chainlint/if-condition-split.expect +++ b/t/chainlint/if-condition-split.expect @@ -1,7 +1,7 @@ -if bob && - marcia || - kevin -then - echo "nomads" ?!AMP?! - echo "for sure" -fi +2 if bob && +3 marcia || +4 kevin +5 then +6 echo "nomads" ?!AMP?! +7 echo "for sure" +8 fi diff --git a/t/chainlint/if-condition-split.test b/t/chainlint/if-condition-split.test index 240daa9fd5..9a3b3ed04a 100644 --- a/t/chainlint/if-condition-split.test +++ b/t/chainlint/if-condition-split.test @@ -1,3 +1,4 @@ +test_expect_success 'if-condition-split' ' # LINT: "if" condition split across multiple lines at "&&" or "||" if bob && marcia || @@ -6,3 +7,4 @@ then echo "nomads" echo "for sure" fi +' diff --git a/t/chainlint/if-in-loop.expect b/t/chainlint/if-in-loop.expect index d6514ae749..ff8c60dbdb 100644 --- a/t/chainlint/if-in-loop.expect +++ b/t/chainlint/if-in-loop.expect @@ -1,12 +1,12 @@ -( - for i in a b c - do - if false - then - echo "err" - exit 1 - fi ?!AMP?! - foo - done ?!AMP?! - bar -) +2 ( +3 for i in a b c +4 do +5 if false +6 then +7 echo "err" +8 exit 1 +9 fi ?!AMP?! +10 foo +11 done ?!AMP?! +12 bar +13 ) diff --git a/t/chainlint/if-in-loop.test b/t/chainlint/if-in-loop.test index 90c23976fe..5be9d1cfa5 100644 --- a/t/chainlint/if-in-loop.test +++ b/t/chainlint/if-in-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'if-in-loop' ' ( for i in a b c do @@ -13,3 +14,4 @@ done bar ) +' diff --git a/t/chainlint/if-then-else.expect b/t/chainlint/if-then-else.expect index cbaaf857d4..965d7e41a2 100644 --- a/t/chainlint/if-then-else.expect +++ b/t/chainlint/if-then-else.expect @@ -1,22 +1,22 @@ -( - if test -n "" - then - echo very ?!AMP?! - echo empty - elif test -z "" - then - echo foo - else - echo foo && - cat <<-\EOF - bar - EOF - fi ?!AMP?! - echo poodle -) && -( - if test -n ""; then - echo very && - echo empty - fi -) +2 ( +3 if test -n "" +4 then +5 echo very ?!AMP?! +6 echo empty +7 elif test -z "" +8 then +9 echo foo +10 else +11 echo foo && +12 cat <<-\EOF +13 bar +14 EOF +15 fi ?!AMP?! +16 echo poodle +17 ) && +18 ( +19 if test -n ""; then +20 echo very && +21 echo empty +22 fi +23 ) diff --git a/t/chainlint/if-then-else.test b/t/chainlint/if-then-else.test index 2055336c2b..6582a7f440 100644 --- a/t/chainlint/if-then-else.test +++ b/t/chainlint/if-then-else.test @@ -1,3 +1,4 @@ +test_expect_success 'if-then-else' ' ( # LINT: "if", "then", "elif", "else", "fi" do not need "&&" if test -n "" @@ -27,3 +28,4 @@ echo empty fi ) +' diff --git a/t/chainlint/incomplete-line.expect b/t/chainlint/incomplete-line.expect index 134d3a14f5..b15e00b901 100644 --- a/t/chainlint/incomplete-line.expect +++ b/t/chainlint/incomplete-line.expect @@ -1,10 +1,10 @@ -line 1 \ -line 2 \ -line 3 \ -line 4 && -( - line 5 \ - line 6 \ - line 7 \ - line 8 -) +2 line 1 \ +3 line 2 \ +4 line 3 \ +5 line 4 && +6 ( +7 line 5 \ +8 line 6 \ +9 line 7 \ +10 line 8 +11 ) diff --git a/t/chainlint/incomplete-line.test b/t/chainlint/incomplete-line.test index d856658083..74a93021eb 100644 --- a/t/chainlint/incomplete-line.test +++ b/t/chainlint/incomplete-line.test @@ -1,3 +1,4 @@ +test_expect_success 'incomplete-line' ' # LINT: stitch together all incomplete \-ending lines line 1 \ line 2 \ @@ -10,3 +11,4 @@ line 4 && line 7 \ line 8 ) +' diff --git a/t/chainlint/inline-comment.expect b/t/chainlint/inline-comment.expect index 6bad218530..0285c0b22c 100644 --- a/t/chainlint/inline-comment.expect +++ b/t/chainlint/inline-comment.expect @@ -1,8 +1,8 @@ -( - foobar && # comment 1 - barfoo ?!AMP?! # wrong position for && - flibble "not a # comment" -) && - -(cd foo && - flibble "not a # comment") +2 ( +3 foobar && # comment 1 +4 barfoo ?!AMP?! # wrong position for && +5 flibble "not a # comment" +6 ) && +7 +8 (cd foo && +9 flibble "not a # comment") diff --git a/t/chainlint/inline-comment.test b/t/chainlint/inline-comment.test index 8f26856e77..4fbbf1058a 100644 --- a/t/chainlint/inline-comment.test +++ b/t/chainlint/inline-comment.test @@ -1,3 +1,4 @@ +test_expect_success 'inline-comment' ' ( # LINT: swallow inline comment (leaving command intact) foobar && # comment 1 @@ -10,3 +11,4 @@ # LINT: "#" in string in cuddled subshell not misinterpreted as comment (cd foo && flibble "not a # comment") +' diff --git a/t/chainlint/loop-detect-failure.expect b/t/chainlint/loop-detect-failure.expect index a66025c39d..40c06f0d53 100644 --- a/t/chainlint/loop-detect-failure.expect +++ b/t/chainlint/loop-detect-failure.expect @@ -1,15 +1,15 @@ -git init r1 && -for n in 1 2 3 4 5 -do - echo "This is file: $n" > r1/file.$n && - git -C r1 add file.$n && - git -C r1 commit -m "$n" || return 1 -done && - -git init r2 && -for n in 1000 10000 -do - printf "%"$n"s" X > r2/large.$n && - git -C r2 add large.$n && - git -C r2 commit -m "$n" ?!LOOP?! -done +2 git init r1 && +3 for n in 1 2 3 4 5 +4 do +5 echo "This is file: $n" > r1/file.$n && +6 git -C r1 add file.$n && +7 git -C r1 commit -m "$n" || return 1 +8 done && +9 +10 git init r2 && +11 for n in 1000 10000 +12 do +13 printf "%"$n"s" X > r2/large.$n && +14 git -C r2 add large.$n && +15 git -C r2 commit -m "$n" ?!LOOP?! +16 done diff --git a/t/chainlint/loop-detect-failure.test b/t/chainlint/loop-detect-failure.test index b9791cc802..44673aa394 100644 --- a/t/chainlint/loop-detect-failure.test +++ b/t/chainlint/loop-detect-failure.test @@ -1,3 +1,4 @@ +test_expect_success 'loop-detect-failure' ' git init r1 && # LINT: loop handles failure explicitly with "|| return 1" for n in 1 2 3 4 5 @@ -15,3 +16,4 @@ do git -C r2 add large.$n && git -C r2 commit -m "$n" done +' diff --git a/t/chainlint/loop-detect-status.expect b/t/chainlint/loop-detect-status.expect index 7ce3a34806..0f180b08de 100644 --- a/t/chainlint/loop-detect-status.expect +++ b/t/chainlint/loop-detect-status.expect @@ -1,18 +1,18 @@ -(while test $i -le $blobcount - do - printf "Generating blob $i/$blobcount\r" >&2 && - printf "blob\nmark :$i\ndata $blobsize\n" && - #test-tool genrandom $i $blobsize && - printf "%-${blobsize}s" $i && - echo "M 100644 :$i $i" >> commit && - i=$(($i+1)) || - echo $? > exit-status - done && - echo "commit refs/heads/main" && - echo "author A U Thor <author@email.com> 123456789 +0000" && - echo "committer C O Mitter <committer@email.com> 123456789 +0000" && - echo "data 5" && - echo ">2gb" && - cat commit) | -git fast-import --big-file-threshold=2 && -test ! -f exit-status +2 (while test $i -le $blobcount +3 do +4 printf "Generating blob $i/$blobcount\r" >&2 && +5 printf "blob\nmark :$i\ndata $blobsize\n" && +6 #test-tool genrandom $i $blobsize && +7 printf "%-${blobsize}s" $i && +8 echo "M 100644 :$i $i" >> commit && +9 i=$(($i+1)) || +10 echo $? > exit-status +11 done && +12 echo "commit refs/heads/main" && +13 echo "author A U Thor <author@email.com> 123456789 +0000" && +14 echo "committer C O Mitter <committer@email.com> 123456789 +0000" && +15 echo "data 5" && +16 echo ">2gb" && +17 cat commit) | +18 git fast-import --big-file-threshold=2 && +19 test ! -f exit-status diff --git a/t/chainlint/loop-detect-status.test b/t/chainlint/loop-detect-status.test index 1c6c23cfc9..8b639be073 100644 --- a/t/chainlint/loop-detect-status.test +++ b/t/chainlint/loop-detect-status.test @@ -1,3 +1,4 @@ +test_expect_success 'loop-detect-status' ' # LINT: "$?" handled explicitly within loop body (while test $i -le $blobcount do @@ -17,3 +18,4 @@ cat commit) | git fast-import --big-file-threshold=2 && test ! -f exit-status +' diff --git a/t/chainlint/loop-in-if.expect b/t/chainlint/loop-in-if.expect index 6c5d6e5b24..4e8c67c914 100644 --- a/t/chainlint/loop-in-if.expect +++ b/t/chainlint/loop-in-if.expect @@ -1,12 +1,12 @@ -( - if true - then - while true - do - echo "pop" ?!AMP?! - echo "glup" ?!LOOP?! - done ?!AMP?! - foo - fi ?!AMP?! - bar -) +2 ( +3 if true +4 then +5 while true +6 do +7 echo "pop" ?!AMP?! +8 echo "glup" ?!LOOP?! +9 done ?!AMP?! +10 foo +11 fi ?!AMP?! +12 bar +13 ) diff --git a/t/chainlint/loop-in-if.test b/t/chainlint/loop-in-if.test index dfcc3f98fb..b0d0d393cf 100644 --- a/t/chainlint/loop-in-if.test +++ b/t/chainlint/loop-in-if.test @@ -1,3 +1,4 @@ +test_expect_success 'loop-in-if' ' ( if true then @@ -13,3 +14,4 @@ fi bar ) +' diff --git a/t/chainlint/loop-upstream-pipe.expect b/t/chainlint/loop-upstream-pipe.expect index 0b82ecc4b9..bef82479ca 100644 --- a/t/chainlint/loop-upstream-pipe.expect +++ b/t/chainlint/loop-upstream-pipe.expect @@ -1,10 +1,10 @@ -( - git rev-list --objects --no-object-names base..loose | - while read oid - do - path="$objdir/$(test_oid_to_path "$oid")" && - printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" || - echo "object list generation failed for $oid" - done | - sort -k1 -) >expect && +2 ( +3 git rev-list --objects --no-object-names base..loose | +4 while read oid +5 do +6 path="$objdir/$(test_oid_to_path "$oid")" && +7 printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" || +8 echo "object list generation failed for $oid" +9 done | +10 sort -k1 +11 ) >expect && diff --git a/t/chainlint/loop-upstream-pipe.test b/t/chainlint/loop-upstream-pipe.test index efb77da897..8415a4db27 100644 --- a/t/chainlint/loop-upstream-pipe.test +++ b/t/chainlint/loop-upstream-pipe.test @@ -1,3 +1,4 @@ +test_expect_success 'loop-upstream-pipe' ' ( git rev-list --objects --no-object-names base..loose | while read oid @@ -9,3 +10,4 @@ done | sort -k1 ) >expect && +' diff --git a/t/chainlint/multi-line-nested-command-substitution.expect b/t/chainlint/multi-line-nested-command-substitution.expect index 300058341b..ad27e43e05 100644 --- a/t/chainlint/multi-line-nested-command-substitution.expect +++ b/t/chainlint/multi-line-nested-command-substitution.expect @@ -1,18 +1,18 @@ -( - foo && - x=$( - echo bar | - cat - ) && - echo ok -) | -sort && -( - bar && - x=$(echo bar | - cat - ) && - y=$(echo baz | - fip) && - echo fail -) +2 ( +3 foo && +4 x=$( +5 echo bar | +6 cat +7 ) && +8 echo ok +9 ) | +10 sort && +11 ( +12 bar && +13 x=$(echo bar | +14 cat +15 ) && +16 y=$(echo baz | +17 fip) && +18 echo fail +19 ) diff --git a/t/chainlint/multi-line-nested-command-substitution.test b/t/chainlint/multi-line-nested-command-substitution.test index 300058341b..e811c63f2b 100644 --- a/t/chainlint/multi-line-nested-command-substitution.test +++ b/t/chainlint/multi-line-nested-command-substitution.test @@ -1,3 +1,4 @@ +test_expect_success 'multi-line-nested-command-substitution' ' ( foo && x=$( @@ -16,3 +17,4 @@ sort && fip) && echo fail ) +' diff --git a/t/chainlint/multi-line-string.expect b/t/chainlint/multi-line-string.expect index 27ff95218e..62c54e3a5e 100644 --- a/t/chainlint/multi-line-string.expect +++ b/t/chainlint/multi-line-string.expect @@ -1,14 +1,14 @@ -( - x="line 1 - line 2 - line 3" && - y="line 1 - line2" ?!AMP?! - foobar -) && -( - echo "xyz" "abc - def - ghi" && - barfoo -) +2 ( +3 x="line 1 +4 line 2 +5 line 3" && +6 y="line 1 +7 line2" ?!AMP?! +8 foobar +9 ) && +10 ( +11 echo "xyz" "abc +12 def +13 ghi" && +14 barfoo +15 ) diff --git a/t/chainlint/multi-line-string.test b/t/chainlint/multi-line-string.test index 4a0af2107d..7b5048d2ea 100644 --- a/t/chainlint/multi-line-string.test +++ b/t/chainlint/multi-line-string.test @@ -1,3 +1,4 @@ +test_expect_success 'multi-line-string' ' ( x="line 1 line 2 @@ -13,3 +14,4 @@ ghi" && barfoo ) +' diff --git a/t/chainlint/negated-one-liner.expect b/t/chainlint/negated-one-liner.expect index ad4c2d949e..a6ce52a1da 100644 --- a/t/chainlint/negated-one-liner.expect +++ b/t/chainlint/negated-one-liner.expect @@ -1,5 +1,5 @@ -! (foo && bar) && -! (foo && bar) >baz && - -! (foo; ?!AMP?! bar) && -! (foo; ?!AMP?! bar) >baz +2 ! (foo && bar) && +3 ! (foo && bar) >baz && +4 +5 ! (foo; ?!AMP?! bar) && +6 ! (foo; ?!AMP?! bar) >baz diff --git a/t/chainlint/negated-one-liner.test b/t/chainlint/negated-one-liner.test index c9598e9153..30f4cc5a9b 100644 --- a/t/chainlint/negated-one-liner.test +++ b/t/chainlint/negated-one-liner.test @@ -1,3 +1,4 @@ +test_expect_success 'negated-one-liner' ' # LINT: top-level one-liner subshell ! (foo && bar) && ! (foo && bar) >baz && @@ -5,3 +6,4 @@ # LINT: top-level one-liner subshell missing internal "&&" ! (foo; bar) && ! (foo; bar) >baz +' diff --git a/t/chainlint/nested-cuddled-subshell.expect b/t/chainlint/nested-cuddled-subshell.expect index 3836049cc4..0191c9c294 100644 --- a/t/chainlint/nested-cuddled-subshell.expect +++ b/t/chainlint/nested-cuddled-subshell.expect @@ -1,25 +1,25 @@ -( - (cd foo && - bar - ) && - - (cd foo && - bar - ) ?!AMP?! - - ( - cd foo && - bar) && - - ( - cd foo && - bar) ?!AMP?! - - (cd foo && - bar) && - - (cd foo && - bar) ?!AMP?! - - foobar -) +2 ( +3 (cd foo && +4 bar +5 ) && +6 +7 (cd foo && +8 bar +9 ) ?!AMP?! +10 +11 ( +12 cd foo && +13 bar) && +14 +15 ( +16 cd foo && +17 bar) ?!AMP?! +18 +19 (cd foo && +20 bar) && +21 +22 (cd foo && +23 bar) ?!AMP?! +24 +25 foobar +26 ) diff --git a/t/chainlint/nested-cuddled-subshell.test b/t/chainlint/nested-cuddled-subshell.test index 8fd656c7b5..31e92d3be4 100644 --- a/t/chainlint/nested-cuddled-subshell.test +++ b/t/chainlint/nested-cuddled-subshell.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-cuddled-subshell' ' ( # LINT: opening "(" cuddled with first nested subshell statement (cd foo && @@ -29,3 +30,4 @@ foobar ) +' diff --git a/t/chainlint/nested-here-doc.expect b/t/chainlint/nested-here-doc.expect index 29b3832a98..70d9b68dc9 100644 --- a/t/chainlint/nested-here-doc.expect +++ b/t/chainlint/nested-here-doc.expect @@ -1,30 +1,30 @@ -cat <<ARBITRARY >foop && -naddle -fub <<EOF - nozzle - noodle -EOF -formp -ARBITRARY - -( - cat <<-\INPUT_END && - fish are mice - but geese go slow - data <<EOF - perl is lerp - and nothing else - EOF - toink - INPUT_END - - cat <<-\EOT ?!AMP?! - text goes here - data <<EOF - data goes here - EOF - more test here - EOT - - foobar -) +2 cat <<ARBITRARY >foop && +3 naddle +4 fub <<EOF +5 nozzle +6 noodle +7 EOF +8 formp +9 ARBITRARY +10 +11 ( +12 cat <<-\INPUT_END && +13 fish are mice +14 but geese go slow +15 data <<EOF +16 perl is lerp +17 and nothing else +18 EOF +19 toink +20 INPUT_END +21 +22 cat <<-\EOT ?!AMP?! +23 text goes here +24 data <<EOF +25 data goes here +26 EOF +27 more test here +28 EOT +29 +30 foobar +31 ) diff --git a/t/chainlint/nested-here-doc.test b/t/chainlint/nested-here-doc.test index f35404bf0f..9505c47a34 100644 --- a/t/chainlint/nested-here-doc.test +++ b/t/chainlint/nested-here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-here-doc' ' # LINT: inner "EOF" not misintrepreted as closing ARBITRARY here-doc cat <<ARBITRARY >foop && naddle @@ -31,3 +32,4 @@ ARBITRARY foobar ) +' diff --git a/t/chainlint/nested-loop-detect-failure.expect b/t/chainlint/nested-loop-detect-failure.expect index 3461df40e5..c13c4d2f90 100644 --- a/t/chainlint/nested-loop-detect-failure.expect +++ b/t/chainlint/nested-loop-detect-failure.expect @@ -1,31 +1,31 @@ -for i in 0 1 2 3 4 5 6 7 8 9; -do - for j in 0 1 2 3 4 5 6 7 8 9; - do - echo "$i$j" >"path$i$j" ?!LOOP?! - done ?!LOOP?! -done && - -for i in 0 1 2 3 4 5 6 7 8 9; -do - for j in 0 1 2 3 4 5 6 7 8 9; - do - echo "$i$j" >"path$i$j" || return 1 - done -done && - -for i in 0 1 2 3 4 5 6 7 8 9; -do - for j in 0 1 2 3 4 5 6 7 8 9; - do - echo "$i$j" >"path$i$j" ?!LOOP?! - done || return 1 -done && - -for i in 0 1 2 3 4 5 6 7 8 9; -do - for j in 0 1 2 3 4 5 6 7 8 9; - do - echo "$i$j" >"path$i$j" || return 1 - done || return 1 -done +2 for i in 0 1 2 3 4 5 6 7 8 9; +3 do +4 for j in 0 1 2 3 4 5 6 7 8 9; +5 do +6 echo "$i$j" >"path$i$j" ?!LOOP?! +7 done ?!LOOP?! +8 done && +9 +10 for i in 0 1 2 3 4 5 6 7 8 9; +11 do +12 for j in 0 1 2 3 4 5 6 7 8 9; +13 do +14 echo "$i$j" >"path$i$j" || return 1 +15 done +16 done && +17 +18 for i in 0 1 2 3 4 5 6 7 8 9; +19 do +20 for j in 0 1 2 3 4 5 6 7 8 9; +21 do +22 echo "$i$j" >"path$i$j" ?!LOOP?! +23 done || return 1 +24 done && +25 +26 for i in 0 1 2 3 4 5 6 7 8 9; +27 do +28 for j in 0 1 2 3 4 5 6 7 8 9; +29 do +30 echo "$i$j" >"path$i$j" || return 1 +31 done || return 1 +32 done diff --git a/t/chainlint/nested-loop-detect-failure.test b/t/chainlint/nested-loop-detect-failure.test index e6f0c1acfb..3d4b657412 100644 --- a/t/chainlint/nested-loop-detect-failure.test +++ b/t/chainlint/nested-loop-detect-failure.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-loop-detect-failure' ' # LINT: neither loop handles failure explicitly with "|| return 1" for i in 0 1 2 3 4 5 6 7 8 9; do @@ -33,3 +34,4 @@ do echo "$i$j" >"path$i$j" || return 1 done || return 1 done +' diff --git a/t/chainlint/nested-subshell-comment.expect b/t/chainlint/nested-subshell-comment.expect index 9138cf386d..f89a8d03a8 100644 --- a/t/chainlint/nested-subshell-comment.expect +++ b/t/chainlint/nested-subshell-comment.expect @@ -1,11 +1,11 @@ -( - foo && - ( - bar && - # bottles wobble while fiddles gobble - # minor numbers of cows (or do they?) - baz && - snaff - ) ?!AMP?! - fuzzy -) +2 ( +3 foo && +4 ( +5 bar && +6 # bottles wobble while fiddles gobble +7 # minor numbers of cows (or do they?) +8 baz && +9 snaff +10 ) ?!AMP?! +11 fuzzy +12 ) diff --git a/t/chainlint/nested-subshell-comment.test b/t/chainlint/nested-subshell-comment.test index 0215cdb192..b430580ce0 100644 --- a/t/chainlint/nested-subshell-comment.test +++ b/t/chainlint/nested-subshell-comment.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-subshell-comment' ' ( foo && ( @@ -11,3 +12,4 @@ ) fuzzy ) +' diff --git a/t/chainlint/nested-subshell.expect b/t/chainlint/nested-subshell.expect index 73ff28546a..811e8a7912 100644 --- a/t/chainlint/nested-subshell.expect +++ b/t/chainlint/nested-subshell.expect @@ -1,13 +1,13 @@ -( - cd foo && - ( - echo a && - echo b - ) >file && - - cd foo && - ( - echo a ?!AMP?! - echo b - ) >file -) +2 ( +3 cd foo && +4 ( +5 echo a && +6 echo b +7 ) >file && +8 +9 cd foo && +10 ( +11 echo a ?!AMP?! +12 echo b +13 ) >file +14 ) diff --git a/t/chainlint/nested-subshell.test b/t/chainlint/nested-subshell.test index 440ee9992d..c31da34b73 100644 --- a/t/chainlint/nested-subshell.test +++ b/t/chainlint/nested-subshell.test @@ -1,3 +1,4 @@ +test_expect_success 'nested-subshell' ' ( cd foo && ( @@ -11,3 +12,4 @@ echo b ) >file ) +' diff --git a/t/chainlint/not-heredoc.expect b/t/chainlint/not-heredoc.expect index 2e9bb135fe..611b7b75cb 100644 --- a/t/chainlint/not-heredoc.expect +++ b/t/chainlint/not-heredoc.expect @@ -1,14 +1,14 @@ -echo "<<<<<<< ours" && -echo ourside && -echo "=======" && -echo theirside && -echo ">>>>>>> theirs" && - -( - echo "<<<<<<< ours" && - echo ourside && - echo "=======" && - echo theirside && - echo ">>>>>>> theirs" ?!AMP?! - poodle -) >merged +2 echo "<<<<<<< ours" && +3 echo ourside && +4 echo "=======" && +5 echo theirside && +6 echo ">>>>>>> theirs" && +7 +8 ( +9 echo "<<<<<<< ours" && +10 echo ourside && +11 echo "=======" && +12 echo theirside && +13 echo ">>>>>>> theirs" ?!AMP?! +14 poodle +15 ) >merged diff --git a/t/chainlint/not-heredoc.test b/t/chainlint/not-heredoc.test index 9aa57346cd..09711e45e0 100644 --- a/t/chainlint/not-heredoc.test +++ b/t/chainlint/not-heredoc.test @@ -1,3 +1,4 @@ +test_expect_success 'not-heredoc' ' # LINT: "<< ours" inside string is not here-doc echo "<<<<<<< ours" && echo ourside && @@ -14,3 +15,4 @@ echo ">>>>>>> theirs" && echo ">>>>>>> theirs" poodle ) >merged +' diff --git a/t/chainlint/one-liner-for-loop.expect b/t/chainlint/one-liner-for-loop.expect index 51a3dc7c54..49dcf065ef 100644 --- a/t/chainlint/one-liner-for-loop.expect +++ b/t/chainlint/one-liner-for-loop.expect @@ -1,9 +1,9 @@ -git init dir-rename-and-content && -( - cd dir-rename-and-content && - test_write_lines 1 2 3 4 5 >foo && - mkdir olddir && - for i in a b c; do echo $i >olddir/$i; ?!LOOP?! done ?!AMP?! - git add foo olddir && - git commit -m "original" && -) +2 git init dir-rename-and-content && +3 ( +4 cd dir-rename-and-content && +5 test_write_lines 1 2 3 4 5 >foo && +6 mkdir olddir && +7 for i in a b c; do echo $i >olddir/$i; ?!LOOP?! done ?!AMP?! +8 git add foo olddir && +9 git commit -m "original" && +10 ) diff --git a/t/chainlint/one-liner-for-loop.test b/t/chainlint/one-liner-for-loop.test index 4bd8c066c7..00afd7ef76 100644 --- a/t/chainlint/one-liner-for-loop.test +++ b/t/chainlint/one-liner-for-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'one-liner-for-loop' ' git init dir-rename-and-content && ( cd dir-rename-and-content && @@ -8,3 +9,4 @@ git init dir-rename-and-content && git add foo olddir && git commit -m "original" && ) +' diff --git a/t/chainlint/one-liner.expect b/t/chainlint/one-liner.expect index 57a7a444c1..9861811283 100644 --- a/t/chainlint/one-liner.expect +++ b/t/chainlint/one-liner.expect @@ -1,9 +1,9 @@ -(foo && bar) && -(foo && bar) | -(foo && bar) >baz && - -(foo; ?!AMP?! bar) && -(foo; ?!AMP?! bar) | -(foo; ?!AMP?! bar) >baz && - -(foo "bar; baz") +2 (foo && bar) && +3 (foo && bar) | +4 (foo && bar) >baz && +5 +6 (foo; ?!AMP?! bar) && +7 (foo; ?!AMP?! bar) | +8 (foo; ?!AMP?! bar) >baz && +9 +10 (foo "bar; baz") diff --git a/t/chainlint/one-liner.test b/t/chainlint/one-liner.test index be9858fa29..6e42ee1b5e 100644 --- a/t/chainlint/one-liner.test +++ b/t/chainlint/one-liner.test @@ -1,3 +1,4 @@ +test_expect_success 'one-liner' ' # LINT: top-level one-liner subshell (foo && bar) && (foo && bar) | @@ -10,3 +11,4 @@ # LINT: ";" in string not misinterpreted as broken &&-chain (foo "bar; baz") +' diff --git a/t/chainlint/p4-filespec.expect b/t/chainlint/p4-filespec.expect index 1290fd1ff2..cff3e4e3d1 100644 --- a/t/chainlint/p4-filespec.expect +++ b/t/chainlint/p4-filespec.expect @@ -1,4 +1,4 @@ -( - p4 print -1 //depot/fiddle#42 >file && - foobar -) +2 ( +3 p4 print -1 //depot/fiddle#42 >file && +4 foobar +5 ) diff --git a/t/chainlint/p4-filespec.test b/t/chainlint/p4-filespec.test index 4fd2d6e2b8..8ba6b911dc 100644 --- a/t/chainlint/p4-filespec.test +++ b/t/chainlint/p4-filespec.test @@ -1,5 +1,7 @@ +test_expect_success 'p4-filespec' ' ( # LINT: Perforce revspec in filespec not misinterpreted as in-line comment p4 print -1 //depot/fiddle#42 >file && foobar ) +' diff --git a/t/chainlint/pipe.expect b/t/chainlint/pipe.expect index 811971b1a3..1bbe5a2ce1 100644 --- a/t/chainlint/pipe.expect +++ b/t/chainlint/pipe.expect @@ -1,10 +1,10 @@ -( - foo | - bar | - baz && - - fish | - cow ?!AMP?! - - sunder -) +2 ( +3 foo | +4 bar | +5 baz && +6 +7 fish | +8 cow ?!AMP?! +9 +10 sunder +11 ) diff --git a/t/chainlint/pipe.test b/t/chainlint/pipe.test index dd82534c66..1af81c243b 100644 --- a/t/chainlint/pipe.test +++ b/t/chainlint/pipe.test @@ -1,3 +1,4 @@ +test_expect_success 'pipe' ' ( # LINT: no "&&" needed on line ending with "|" foo | @@ -10,3 +11,4 @@ sunder ) +' diff --git a/t/chainlint/return-loop.expect b/t/chainlint/return-loop.expect index cfc0549bef..da8f9abea3 100644 --- a/t/chainlint/return-loop.expect +++ b/t/chainlint/return-loop.expect @@ -1,5 +1,5 @@ -while test $i -lt $((num - 5)) -do - git notes add -m "notes for commit$i" HEAD~$i || return 1 - i=$((i + 1)) -done +2 while test $i -lt $((num - 5)) +3 do +4 git notes add -m "notes for commit$i" HEAD~$i || return 1 +5 i=$((i + 1)) +6 done diff --git a/t/chainlint/return-loop.test b/t/chainlint/return-loop.test index f90b171300..ea76c3593a 100644 --- a/t/chainlint/return-loop.test +++ b/t/chainlint/return-loop.test @@ -1,6 +1,8 @@ +test_expect_success 'return-loop' ' while test $i -lt $((num - 5)) do # LINT: "|| return {n}" valid loop escape outside subshell; no "&&" needed git notes add -m "notes for commit$i" HEAD~$i || return 1 i=$((i + 1)) done +' diff --git a/t/chainlint/semicolon.expect b/t/chainlint/semicolon.expect index 3aa2259f36..866438310c 100644 --- a/t/chainlint/semicolon.expect +++ b/t/chainlint/semicolon.expect @@ -1,19 +1,19 @@ -( - cat foo ; ?!AMP?! echo bar ?!AMP?! - cat foo ; ?!AMP?! echo bar -) && -( - cat foo ; ?!AMP?! echo bar && - cat foo ; ?!AMP?! echo bar -) && -( - echo "foo; bar" && - cat foo; ?!AMP?! echo bar -) && -( - foo; -) && -(cd foo && - for i in a b c; do - echo; ?!LOOP?! - done) +2 ( +3 cat foo ; ?!AMP?! echo bar ?!AMP?! +4 cat foo ; ?!AMP?! echo bar +5 ) && +6 ( +7 cat foo ; ?!AMP?! echo bar && +8 cat foo ; ?!AMP?! echo bar +9 ) && +10 ( +11 echo "foo; bar" && +12 cat foo; ?!AMP?! echo bar +13 ) && +14 ( +15 foo; +16 ) && +17 (cd foo && +18 for i in a b c; do +19 echo; ?!LOOP?! +20 done) diff --git a/t/chainlint/semicolon.test b/t/chainlint/semicolon.test index 67e1192c50..fc0ba1b539 100644 --- a/t/chainlint/semicolon.test +++ b/t/chainlint/semicolon.test @@ -1,3 +1,4 @@ +test_expect_success 'semicolon' ' ( # LINT: missing internal "&&" and ending "&&" cat foo ; echo bar @@ -23,3 +24,4 @@ # LINT: semicolon unnecessary but legitimate echo; done) +' diff --git a/t/chainlint/sqstring-in-sqstring.expect b/t/chainlint/sqstring-in-sqstring.expect index cf0b591cf7..ba5d3c3a6d 100644 --- a/t/chainlint/sqstring-in-sqstring.expect +++ b/t/chainlint/sqstring-in-sqstring.expect @@ -1,4 +1,4 @@ -perl -e ' - defined($_ = -s $_) or die for @ARGV; - exit 1 if $ARGV[0] <= $ARGV[1]; -' test-2-$packname_2.pack test-3-$packname_3.pack +2 perl -e ' +3 defined($_ = -s $_) or die for @ARGV; +4 exit 1 if $ARGV[0] <= $ARGV[1]; +5 ' test-2-$packname_2.pack test-3-$packname_3.pack diff --git a/t/chainlint/sqstring-in-sqstring.test b/t/chainlint/sqstring-in-sqstring.test index 77a425e0c7..24169724a5 100644 --- a/t/chainlint/sqstring-in-sqstring.test +++ b/t/chainlint/sqstring-in-sqstring.test @@ -1,5 +1,7 @@ +test_expect_success 'sqstring-in-sqstring' ' # LINT: SQ-string Perl code fragment within SQ-string perl -e '\'' defined($_ = -s $_) or die for @ARGV; exit 1 if $ARGV[0] <= $ARGV[1]; '\'' test-2-$packname_2.pack test-3-$packname_3.pack +' diff --git a/t/chainlint/subshell-here-doc.expect b/t/chainlint/subshell-here-doc.expect index 75d6f607e2..5647500c82 100644 --- a/t/chainlint/subshell-here-doc.expect +++ b/t/chainlint/subshell-here-doc.expect @@ -1,30 +1,30 @@ -( - echo wobba \ - gorgo snoot \ - wafta snurb <<-EOF && - quoth the raven, - nevermore... - EOF - - cat <<EOF >bip ?!AMP?! - fish fly high -EOF - - echo <<-\EOF >bop - gomez - morticia - wednesday - pugsly - EOF -) && -( - cat <<-\ARBITRARY >bup && - glink - FIZZ - ARBITRARY - cat <<-"ARBITRARY3" >bup3 && - glink - FIZZ - ARBITRARY3 - meep -) +2 ( +3 echo wobba \ +4 gorgo snoot \ +5 wafta snurb <<-EOF && +6 quoth the raven, +7 nevermore... +8 EOF +9 +10 cat <<EOF >bip ?!AMP?! +11 fish fly high +12 EOF +13 +14 echo <<-\EOF >bop +15 gomez +16 morticia +17 wednesday +18 pugsly +19 EOF +20 ) && +21 ( +22 cat <<-\ARBITRARY >bup && +23 glink +24 FIZZ +25 ARBITRARY +26 cat <<-"ARBITRARY3" >bup3 && +27 glink +28 FIZZ +29 ARBITRARY3 +30 meep +31 ) diff --git a/t/chainlint/subshell-here-doc.test b/t/chainlint/subshell-here-doc.test index d40eb65583..4a38f47f01 100644 --- a/t/chainlint/subshell-here-doc.test +++ b/t/chainlint/subshell-here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'subshell-here-doc' ' ( # LINT: stitch together incomplete \-ending lines # LINT: swallow here-doc to avoid false positives in content @@ -33,3 +34,4 @@ EOF ARBITRARY3 meep ) +' diff --git a/t/chainlint/subshell-one-liner.expect b/t/chainlint/subshell-one-liner.expect index 8f694990e8..214316c6a0 100644 --- a/t/chainlint/subshell-one-liner.expect +++ b/t/chainlint/subshell-one-liner.expect @@ -1,19 +1,19 @@ -( - (foo && bar) && - (foo && bar) | - (foo && bar) >baz && - - (foo; ?!AMP?! bar) && - (foo; ?!AMP?! bar) | - (foo; ?!AMP?! bar) >baz && - - (foo || exit 1) && - (foo || exit 1) | - (foo || exit 1) >baz && - - (foo && bar) ?!AMP?! - - (foo && bar; ?!AMP?! baz) ?!AMP?! - - foobar -) +2 ( +3 (foo && bar) && +4 (foo && bar) | +5 (foo && bar) >baz && +6 +7 (foo; ?!AMP?! bar) && +8 (foo; ?!AMP?! bar) | +9 (foo; ?!AMP?! bar) >baz && +10 +11 (foo || exit 1) && +12 (foo || exit 1) | +13 (foo || exit 1) >baz && +14 +15 (foo && bar) ?!AMP?! +16 +17 (foo && bar; ?!AMP?! baz) ?!AMP?! +18 +19 foobar +20 ) diff --git a/t/chainlint/subshell-one-liner.test b/t/chainlint/subshell-one-liner.test index 37fa643c20..dac536afcc 100644 --- a/t/chainlint/subshell-one-liner.test +++ b/t/chainlint/subshell-one-liner.test @@ -1,3 +1,4 @@ +test_expect_success 'subshell-one-liner' ' ( # LINT: nested one-liner subshell (foo && bar) && @@ -22,3 +23,4 @@ foobar ) +' diff --git a/t/chainlint/t7900-subtree.expect b/t/chainlint/t7900-subtree.expect index 02f3129232..9e60338bcf 100644 --- a/t/chainlint/t7900-subtree.expect +++ b/t/chainlint/t7900-subtree.expect @@ -1,22 +1,22 @@ -( - chks="sub1 -sub2 -sub3 -sub4" && - chks_sub=$(cat <<TXT | sed "s,^,sub dir/," -$chks -TXT -) && - chkms="main-sub1 -main-sub2 -main-sub3 -main-sub4" && - chkms_sub=$(cat <<TXT | sed "s,^,sub dir/," -$chkms -TXT -) && - - subfiles=$(git ls-files) && - check_equal "$subfiles" "$chkms -$chks" -) +2 ( +3 chks="sub1 +4 sub2 +5 sub3 +6 sub4" && +7 chks_sub=$(cat <<TXT | sed "s,^,sub dir/," +8 $chks +9 TXT +10 ) && +11 chkms="main-sub1 +12 main-sub2 +13 main-sub3 +14 main-sub4" && +15 chkms_sub=$(cat <<TXT | sed "s,^,sub dir/," +16 $chkms +17 TXT +18 ) && +19 +20 subfiles=$(git ls-files) && +21 check_equal "$subfiles" "$chkms +22 $chks" +23 ) diff --git a/t/chainlint/t7900-subtree.test b/t/chainlint/t7900-subtree.test index 02f3129232..1f4f03300f 100644 --- a/t/chainlint/t7900-subtree.test +++ b/t/chainlint/t7900-subtree.test @@ -1,3 +1,4 @@ +test_expect_success 't7900-subtree' ' ( chks="sub1 sub2 @@ -20,3 +21,4 @@ TXT check_equal "$subfiles" "$chkms $chks" ) +' diff --git a/t/chainlint/token-pasting.expect b/t/chainlint/token-pasting.expect index 6a387917a7..64f3235d26 100644 --- a/t/chainlint/token-pasting.expect +++ b/t/chainlint/token-pasting.expect @@ -1,27 +1,27 @@ -git config filter.rot13.smudge ./rot13.sh && -git config filter.rot13.clean ./rot13.sh && - -{ - echo "*.t filter=rot13" ?!AMP?! - echo "*.i ident" -} >.gitattributes && - -{ - echo a b c d e f g h i j k l m ?!AMP?! - echo n o p q r s t u v w x y z ?!AMP?! - echo '$Id$' -} >test && -cat test >test.t && -cat test >test.o && -cat test >test.i && -git add test test.t test.i && -rm -f test test.t test.i && -git checkout -- test test.t test.i && - -echo "content-test2" >test2.o && -echo "content-test3 - filename with special characters" >"test3 'sq',$x=.o" ?!AMP?! - -downstream_url_for_sed=$( - printf "%sn" "$downstream_url" | - sed -e 's/\/\\/g' -e 's/[[/.*^$]/\&/g' -) +2 git config filter.rot13.smudge ./rot13.sh && +3 git config filter.rot13.clean ./rot13.sh && +4 +5 { +6 echo "*.t filter=rot13" ?!AMP?! +7 echo "*.i ident" +8 } >.gitattributes && +9 +10 { +11 echo a b c d e f g h i j k l m ?!AMP?! +12 echo n o p q r s t u v w x y z ?!AMP?! +13 echo '$Id$' +14 } >test && +15 cat test >test.t && +16 cat test >test.o && +17 cat test >test.i && +18 git add test test.t test.i && +19 rm -f test test.t test.i && +20 git checkout -- test test.t test.i && +21 +22 echo "content-test2" >test2.o && +23 echo "content-test3 - filename with special characters" >"test3 'sq',$x=.o" ?!AMP?! +24 +25 downstream_url_for_sed=$( +26 printf "%sn" "$downstream_url" | +27 sed -e 's/\/\\/g' -e 's/[[/.*^$]/\&/g' +28 ) diff --git a/t/chainlint/token-pasting.test b/t/chainlint/token-pasting.test index b4610ce815..590914b733 100644 --- a/t/chainlint/token-pasting.test +++ b/t/chainlint/token-pasting.test @@ -1,3 +1,4 @@ +test_expect_success 'token-pasting' ' # LINT: single token; composite of multiple strings git config filter.rot13.smudge ./rot13.sh && git config filter.rot13.clean ./rot13.sh && @@ -30,3 +31,4 @@ downstream_url_for_sed=$( # LINT: exit/enter string context; "&" inside string not command terminator sed -e '\''s/\\/\\\\/g'\'' -e '\''s/[[/.*^$]/\\&/g'\'' ) +' diff --git a/t/chainlint/unclosed-here-doc-indent.expect b/t/chainlint/unclosed-here-doc-indent.expect index 7c30a1a024..f78e23cb63 100644 --- a/t/chainlint/unclosed-here-doc-indent.expect +++ b/t/chainlint/unclosed-here-doc-indent.expect @@ -1,4 +1,4 @@ -command_which_is_run && -cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! && -we forget to end the here-doc -command_which_is_gobbled +2 command_which_is_run && +3 cat >expect <<-\EOF ?!UNCLOSED-HEREDOC?! && +4 we forget to end the here-doc +5 command_which_is_gobbled diff --git a/t/chainlint/unclosed-here-doc-indent.test b/t/chainlint/unclosed-here-doc-indent.test index 5c841a9dfd..7ac9d0f7d7 100644 --- a/t/chainlint/unclosed-here-doc-indent.test +++ b/t/chainlint/unclosed-here-doc-indent.test @@ -1,4 +1,6 @@ +test_expect_success 'unclosed-here-doc-indent' ' command_which_is_run && cat >expect <<-\EOF && we forget to end the here-doc command_which_is_gobbled +' diff --git a/t/chainlint/unclosed-here-doc.expect b/t/chainlint/unclosed-here-doc.expect index d65e50f78d..51304672cf 100644 --- a/t/chainlint/unclosed-here-doc.expect +++ b/t/chainlint/unclosed-here-doc.expect @@ -1,7 +1,7 @@ -command_which_is_run && -cat >expect <<\EOF ?!UNCLOSED-HEREDOC?! && - we try to end the here-doc below, - but the indentation throws us off - since the operator is not "<<-". - EOF -command_which_is_gobbled +2 command_which_is_run && +3 cat >expect <<\EOF ?!UNCLOSED-HEREDOC?! && +4 we try to end the here-doc below, +5 but the indentation throws us off +6 since the operator is not "<<-". +7 EOF +8 command_which_is_gobbled diff --git a/t/chainlint/unclosed-here-doc.test b/t/chainlint/unclosed-here-doc.test index 69d3786c34..68e78f06f3 100644 --- a/t/chainlint/unclosed-here-doc.test +++ b/t/chainlint/unclosed-here-doc.test @@ -1,3 +1,4 @@ +test_expect_success 'unclosed-here-doc' ' command_which_is_run && cat >expect <<\EOF && we try to end the here-doc below, @@ -5,3 +6,4 @@ cat >expect <<\EOF && since the operator is not "<<-". EOF command_which_is_gobbled +' diff --git a/t/chainlint/while-loop.expect b/t/chainlint/while-loop.expect index 06c1567f48..5ffabd5a93 100644 --- a/t/chainlint/while-loop.expect +++ b/t/chainlint/while-loop.expect @@ -1,14 +1,14 @@ -( - while true - do - echo foo ?!AMP?! - cat <<-\EOF ?!LOOP?! - bar - EOF - done ?!AMP?! - - while true; do - echo foo && - cat bar ?!LOOP?! - done -) +2 ( +3 while true +4 do +5 echo foo ?!AMP?! +6 cat <<-\EOF ?!LOOP?! +7 bar +8 EOF +9 done ?!AMP?! +10 +11 while true; do +12 echo foo && +13 cat bar ?!LOOP?! +14 done +15 ) diff --git a/t/chainlint/while-loop.test b/t/chainlint/while-loop.test index d09fb016e4..33a201906a 100644 --- a/t/chainlint/while-loop.test +++ b/t/chainlint/while-loop.test @@ -1,3 +1,4 @@ +test_expect_success 'while-loop' ' ( # LINT: "while", "do", "done" do not need "&&" while true @@ -17,3 +18,4 @@ cat bar done ) +' diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl index b2b28c2ced..6ee7700eb4 100755 --- a/t/check-non-portable-shell.pl +++ b/t/check-non-portable-shell.pl @@ -49,8 +49,8 @@ while (<>) { /\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)'; /\blocal\s+[A-Za-z0-9_]*=\$([A-Za-z0-9_{]|[(][^(])/ and err q(quote "$val" in 'local var=$val'); - /^\s*([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and - err '"FOO=bar shell_func" assignment extends beyond "shell_func"'; + /\b([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and !/test_env.+=/ and exists($func{$4}) and + err '"FOO=bar shell_func" is not portable (use test_env FOO=bar shell_func)'; $line = ''; # this resets our $. for each file close ARGV if eof; diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c index af43ee1cb5..3f23f21072 100644 --- a/t/helper/test-bitmap.c +++ b/t/helper/test-bitmap.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "git-compat-util.h" #include "pack-bitmap.h" @@ -13,21 +15,41 @@ static int bitmap_dump_hashes(void) return test_bitmap_hashes(the_repository); } +static int bitmap_dump_pseudo_merges(void) +{ + return test_bitmap_pseudo_merges(the_repository); +} + +static int bitmap_dump_pseudo_merge_commits(uint32_t n) +{ + return test_bitmap_pseudo_merge_commits(the_repository, n); +} + +static int bitmap_dump_pseudo_merge_objects(uint32_t n) +{ + return test_bitmap_pseudo_merge_objects(the_repository, n); +} + int cmd__bitmap(int argc, const char **argv) { setup_git_directory(); - if (argc != 2) - goto usage; - - if (!strcmp(argv[1], "list-commits")) + if (argc == 2 && !strcmp(argv[1], "list-commits")) return bitmap_list_commits(); - if (!strcmp(argv[1], "dump-hashes")) + if (argc == 2 && !strcmp(argv[1], "dump-hashes")) return bitmap_dump_hashes(); + if (argc == 2 && !strcmp(argv[1], "dump-pseudo-merges")) + return bitmap_dump_pseudo_merges(); + if (argc == 3 && !strcmp(argv[1], "dump-pseudo-merge-commits")) + return bitmap_dump_pseudo_merge_commits(atoi(argv[2])); + if (argc == 3 && !strcmp(argv[1], "dump-pseudo-merge-objects")) + return bitmap_dump_pseudo_merge_objects(atoi(argv[2])); -usage: usage("\ttest-tool bitmap list-commits\n" - "\ttest-tool bitmap dump-hashes"); + "\ttest-tool bitmap dump-hashes\n" + "\ttest-tool bitmap dump-pseudo-merges\n" + "\ttest-tool bitmap dump-pseudo-merge-commits <n>\n" + "\ttest-tool bitmap dump-pseudo-merge-objects <n>"); return -1; } diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c index 1281e66876..97541daf71 100644 --- a/t/helper/test-bloom.c +++ b/t/helper/test-bloom.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "bloom.h" #include "hex.h" @@ -49,6 +51,7 @@ static void get_bloom_filter_for_commit(const struct object_id *commit_oid) static const char *bloom_usage = "\n" " test-tool bloom get_murmur3 <string>\n" +" test-tool bloom get_murmur3_seven_highbit\n" " test-tool bloom generate_filter <string> [<string>...]\n" " test-tool bloom get_filter_for_commit <commit-hex>\n"; @@ -63,7 +66,13 @@ int cmd__bloom(int argc, const char **argv) uint32_t hashed; if (argc < 3) usage(bloom_usage); - hashed = murmur3_seeded(0, argv[2], strlen(argv[2])); + hashed = murmur3_seeded_v2(0, argv[2], strlen(argv[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); printf("Murmur3 Hash with seed=0:0x%08x\n", hashed); } diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c index 09dc78733c..0c5fa723d8 100644 --- a/t/helper/test-bundle-uri.c +++ b/t/helper/test-bundle-uri.c @@ -88,8 +88,6 @@ static int cmd_ls_remote(int argc, const char **argv) die(_("bad repository '%s'"), dest); die(_("no remote configured to get bundle URIs from")); } - if (!remote->url_nr) - die(_("remote '%s' has no configured URL"), dest); transport = transport_get(remote, NULL); if (transport_get_remote_bundle_uri(transport) < 0) { diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c index dc89ecfd71..5cdef3ebef 100644 --- a/t/helper/test-cache-tree.c +++ b/t/helper/test-cache-tree.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "gettext.h" #include "hex.h" diff --git a/t/helper/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c index 02b0b46c3f..3f0c7d0ed0 100644 --- a/t/helper/test-dump-cache-tree.c +++ b/t/helper/test-dump-cache-tree.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hash.h" #include "hex.h" diff --git a/t/helper/test-dump-fsmonitor.c b/t/helper/test-dump-fsmonitor.c index 4f215fea02..1b7f37a84f 100644 --- a/t/helper/test-dump-fsmonitor.c +++ b/t/helper/test-dump-fsmonitor.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "read-cache-ll.h" #include "repository.h" diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c index f472691a3c..a6720faf9c 100644 --- a/t/helper/test-dump-split-index.c +++ b/t/helper/test-dump-split-index.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "read-cache-ll.h" diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c index 9ff67c3967..4f010d5324 100644 --- a/t/helper/test-dump-untracked-cache.c +++ b/t/helper/test-dump-untracked-cache.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "dir.h" #include "hex.h" diff --git a/t/helper/test-example-decorate.c b/t/helper/test-example-decorate.c deleted file mode 100644 index 8f59f6be4c..0000000000 --- a/t/helper/test-example-decorate.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "test-tool.h" -#include "git-compat-util.h" -#include "object.h" -#include "decorate.h" -#include "repository.h" - -int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED) -{ - struct decoration n; - struct object_id one_oid = { {1} }; - struct object_id two_oid = { {2} }; - struct object_id three_oid = { {3} }; - struct object *one, *two, *three; - - int decoration_a, decoration_b; - - void *ret; - - int i, objects_noticed = 0; - - /* - * The struct must be zero-initialized. - */ - memset(&n, 0, sizeof(n)); - - /* - * Add 2 objects, one with a non-NULL decoration and one with a NULL - * decoration. - */ - one = lookup_unknown_object(the_repository, &one_oid); - two = lookup_unknown_object(the_repository, &two_oid); - ret = add_decoration(&n, one, &decoration_a); - if (ret) - BUG("when adding a brand-new object, NULL should be returned"); - ret = add_decoration(&n, two, NULL); - if (ret) - BUG("when adding a brand-new object, NULL should be returned"); - - /* - * When re-adding an already existing object, the old decoration is - * returned. - */ - ret = add_decoration(&n, one, NULL); - if (ret != &decoration_a) - BUG("when readding an already existing object, existing decoration should be returned"); - ret = add_decoration(&n, two, &decoration_b); - if (ret) - BUG("when readding an already existing object, existing decoration should be returned"); - - /* - * Lookup returns the added declarations, or NULL if the object was - * never added. - */ - ret = lookup_decoration(&n, one); - if (ret) - BUG("lookup should return added declaration"); - ret = lookup_decoration(&n, two); - if (ret != &decoration_b) - BUG("lookup should return added declaration"); - three = lookup_unknown_object(the_repository, &three_oid); - ret = lookup_decoration(&n, three); - if (ret) - BUG("lookup for unknown object should return NULL"); - - /* - * The user can also loop through all entries. - */ - for (i = 0; i < n.size; i++) { - if (n.entries[i].base) - objects_noticed++; - } - if (objects_noticed != 2) - BUG("should have 2 objects"); - - clear_decoration(&n, NULL); - - return 0; -} diff --git a/t/helper/test-find-pack.c b/t/helper/test-find-pack.c index e8bd793e58..14b2b0c12c 100644 --- a/t/helper/test-find-pack.c +++ b/t/helper/test-find-pack.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "object-name.h" #include "object-store.h" diff --git a/t/helper/test-fsmonitor-client.c b/t/helper/test-fsmonitor-client.c index 8280984d08..02bfe92e8d 100644 --- a/t/helper/test-fsmonitor-client.c +++ b/t/helper/test-fsmonitor-client.c @@ -3,6 +3,8 @@ * a `git fsmonitor--daemon` daemon. */ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "parse-options.h" #include "fsmonitor-ipc.h" diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c index b235da594f..7de822af51 100644 --- a/t/helper/test-hash-speed.c +++ b/t/helper/test-hash-speed.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "hash-ll.h" +#include "hash.h" #define NUM_SECONDS 3 diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c index 0eb0b3d49c..2912899558 100644 --- a/t/helper/test-hashmap.c +++ b/t/helper/test-hashmap.c @@ -36,7 +36,8 @@ static int test_entry_cmp(const void *cmp_data, } static struct test_entry *alloc_test_entry(unsigned int hash, - char *key, char *value) + const char *key, + const char *value) { size_t klen = strlen(key); size_t vlen = strlen(value); diff --git a/t/helper/test-json-writer.c b/t/helper/test-json-writer.c index afe393f597..a288069b04 100644 --- a/t/helper/test-json-writer.c +++ b/t/helper/test-json-writer.c @@ -174,7 +174,7 @@ static void make_arr4(int pretty) jw_end(&arr4); } -static char *expect_nest1 = +static const char *expect_nest1 = "{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}"; static struct json_writer nest1 = JSON_WRITER_INIT; @@ -195,10 +195,10 @@ static void make_nest1(int pretty) jw_release(&arr1); } -static char *expect_inline1 = +static const char *expect_inline1 = "{\"obj1\":{\"a\":\"abc\",\"b\":42,\"c\":true},\"arr1\":[\"abc\",42,true]}"; -static char *pretty_inline1 = +static const char *pretty_inline1 = ("{\n" " \"obj1\": {\n" " \"a\": \"abc\",\n" @@ -236,10 +236,10 @@ static void make_inline1(int pretty) jw_end(&inline1); } -static char *expect_inline2 = +static const char *expect_inline2 = "[[1,2],[3,4],{\"a\":\"abc\"}]"; -static char *pretty_inline2 = +static const char *pretty_inline2 = ("[\n" " [\n" " 1,\n" @@ -415,6 +415,7 @@ static void get_i(struct line *line, intmax_t *s_in) get_s(line, &s); + errno = 0; *s_in = strtol(s, &endptr, 10); if (*endptr || errno == ERANGE) die("line[%d]: invalid integer value", line->nr); @@ -427,6 +428,7 @@ static void get_d(struct line *line, double *s_in) get_s(line, &s); + errno = 0; *s_in = strtod(s, &endptr); if (*endptr || errno == ERANGE) die("line[%d]: invalid float value", line->nr); diff --git a/t/helper/test-lazy-init-name-hash.c b/t/helper/test-lazy-init-name-hash.c index 5f33bb7b8f..40f5df4412 100644 --- a/t/helper/test-lazy-init-name-hash.c +++ b/t/helper/test-lazy-init-name-hash.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "environment.h" #include "name-hash.h" diff --git a/t/helper/test-match-trees.c b/t/helper/test-match-trees.c index d0db5ff26f..e0e2048320 100644 --- a/t/helper/test-match-trees.c +++ b/t/helper/test-match-trees.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "match-trees.h" diff --git a/t/helper/test-oid-array.c b/t/helper/test-oid-array.c index aafe398ef0..076b849cbf 100644 --- a/t/helper/test-oid-array.c +++ b/t/helper/test-oid-array.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "oid-array.h" @@ -17,6 +19,8 @@ int cmd__oid_array(int argc UNUSED, const char **argv UNUSED) int nongit_ok; setup_git_directory_gently(&nongit_ok); + if (nongit_ok) + repo_set_hash_algo(the_repository, GIT_HASH_SHA1); while (strbuf_getline(&line, stdin) != EOF) { const char *arg; diff --git a/t/helper/test-oidmap.c b/t/helper/test-oidmap.c deleted file mode 100644 index bd30244a54..0000000000 --- a/t/helper/test-oidmap.c +++ /dev/null @@ -1,123 +0,0 @@ -#include "test-tool.h" -#include "hex.h" -#include "object-name.h" -#include "oidmap.h" -#include "repository.h" -#include "setup.h" -#include "strbuf.h" -#include "string-list.h" - -/* key is an oid and value is a name (could be a refname for example) */ -struct test_entry { - struct oidmap_entry entry; - char name[FLEX_ARRAY]; -}; - -#define DELIM " \t\r\n" - -/* - * Read stdin line by line and print result of commands to stdout: - * - * hash oidkey -> sha1hash(oidkey) - * put oidkey namevalue -> NULL / old namevalue - * get oidkey -> NULL / namevalue - * remove oidkey -> NULL / old namevalue - * iterate -> oidkey1 namevalue1\noidkey2 namevalue2\n... - * - */ -int cmd__oidmap(int argc UNUSED, const char **argv UNUSED) -{ - struct string_list parts = STRING_LIST_INIT_NODUP; - struct strbuf line = STRBUF_INIT; - struct oidmap map = OIDMAP_INIT; - - setup_git_directory(); - - /* init oidmap */ - oidmap_init(&map, 0); - - /* process commands from stdin */ - while (strbuf_getline(&line, stdin) != EOF) { - char *cmd, *p1, *p2; - struct test_entry *entry; - struct object_id oid; - - /* break line into command and up to two parameters */ - string_list_setlen(&parts, 0); - string_list_split_in_place(&parts, line.buf, DELIM, 2); - string_list_remove_empty_items(&parts, 0); - - /* ignore empty lines */ - if (!parts.nr) - continue; - if (!*parts.items[0].string || *parts.items[0].string == '#') - continue; - - cmd = parts.items[0].string; - p1 = parts.nr >= 1 ? parts.items[1].string : NULL; - p2 = parts.nr >= 2 ? parts.items[2].string : NULL; - - if (!strcmp("put", cmd) && p1 && p2) { - - if (repo_get_oid(the_repository, p1, &oid)) { - printf("Unknown oid: %s\n", p1); - continue; - } - - /* create entry with oid_key = p1, name_value = p2 */ - FLEX_ALLOC_STR(entry, name, p2); - oidcpy(&entry->entry.oid, &oid); - - /* add / replace entry */ - entry = oidmap_put(&map, entry); - - /* print and free replaced entry, if any */ - puts(entry ? entry->name : "NULL"); - free(entry); - - } else if (!strcmp("get", cmd) && p1) { - - if (repo_get_oid(the_repository, p1, &oid)) { - printf("Unknown oid: %s\n", p1); - continue; - } - - /* lookup entry in oidmap */ - entry = oidmap_get(&map, &oid); - - /* print result */ - puts(entry ? entry->name : "NULL"); - - } else if (!strcmp("remove", cmd) && p1) { - - if (repo_get_oid(the_repository, p1, &oid)) { - printf("Unknown oid: %s\n", p1); - continue; - } - - /* remove entry from oidmap */ - entry = oidmap_remove(&map, &oid); - - /* print result and free entry*/ - puts(entry ? entry->name : "NULL"); - free(entry); - - } else if (!strcmp("iterate", cmd)) { - - struct oidmap_iter iter; - oidmap_iter_init(&map, &iter); - while ((entry = oidmap_iter_next(&iter))) - printf("%s %s\n", oid_to_hex(&entry->entry.oid), entry->name); - - } else { - - printf("Unknown command %s\n", cmd); - - } - } - - string_list_clear(&parts, 0); - strbuf_release(&line); - oidmap_free(&map, 1); - return 0; -} diff --git a/t/helper/test-oidtree.c b/t/helper/test-oidtree.c deleted file mode 100644 index c7a1d4c642..0000000000 --- a/t/helper/test-oidtree.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "test-tool.h" -#include "hex.h" -#include "oidtree.h" -#include "setup.h" -#include "strbuf.h" - -static enum cb_next print_oid(const struct object_id *oid, void *data UNUSED) -{ - puts(oid_to_hex(oid)); - return CB_CONTINUE; -} - -int cmd__oidtree(int argc UNUSED, const char **argv UNUSED) -{ - struct oidtree ot; - struct strbuf line = STRBUF_INIT; - int nongit_ok; - int algo = GIT_HASH_UNKNOWN; - - oidtree_init(&ot); - setup_git_directory_gently(&nongit_ok); - - while (strbuf_getline(&line, stdin) != EOF) { - const char *arg; - struct object_id oid; - - if (skip_prefix(line.buf, "insert ", &arg)) { - if (get_oid_hex_any(arg, &oid) == GIT_HASH_UNKNOWN) - die("insert not a hexadecimal oid: %s", arg); - algo = oid.algo; - oidtree_insert(&ot, &oid); - } else if (skip_prefix(line.buf, "contains ", &arg)) { - if (get_oid_hex(arg, &oid)) - die("contains not a hexadecimal oid: %s", arg); - printf("%d\n", oidtree_contains(&ot, &oid)); - } else if (skip_prefix(line.buf, "each ", &arg)) { - char buf[GIT_MAX_HEXSZ + 1] = { '0' }; - memset(&oid, 0, sizeof(oid)); - memcpy(buf, arg, strlen(arg)); - buf[hash_algos[algo].hexsz] = '\0'; - get_oid_hex_any(buf, &oid); - oid.algo = algo; - oidtree_each(&ot, &oid, strlen(arg), print_oid, NULL); - } else if (!strcmp(line.buf, "clear")) { - oidtree_clear(&ot); - } else { - die("unknown command: %s", line.buf); - } - } - - strbuf_release(&line); - - return 0; -} diff --git a/t/helper/test-pack-mtimes.c b/t/helper/test-pack-mtimes.c index 67a964ef90..f8f9afbb5b 100644 --- a/t/helper/test-pack-mtimes.c +++ b/t/helper/test-pack-mtimes.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "strbuf.h" diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c index ded8116cc5..5250913d99 100644 --- a/t/helper/test-parse-options.c +++ b/t/helper/test-parse-options.c @@ -207,6 +207,7 @@ int cmd__parse_options(int argc, const char **argv) expect.strdup_strings = 1; string_list_clear(&expect, 0); string_list_clear(&list, 0); + free(file); return ret; } diff --git a/t/helper/test-partial-clone.c b/t/helper/test-partial-clone.c index 910a128614..0ead529167 100644 --- a/t/helper/test-partial-clone.c +++ b/t/helper/test-partial-clone.c @@ -21,7 +21,7 @@ static void object_info(const char *gitdir, const char *oid_hex) if (repo_init(&r, gitdir, NULL)) die("could not init repo"); - if (parse_oid_hex(oid_hex, &oid, &p)) + if (parse_oid_hex_algop(oid_hex, &oid, &p, r.hash_algo)) die("could not parse oid"); if (oid_object_info_extended(&r, &oid, &oi, 0)) die("could not obtain object info"); diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c index f30022d222..29361c7aab 100644 --- a/t/helper/test-proc-receive.c +++ b/t/helper/test-proc-receive.c @@ -3,8 +3,8 @@ #include "hex.h" #include "parse-options.h" #include "pkt-line.h" -#include "setup.h" #include "sigchain.h" +#include "string-list.h" static const char *proc_receive_usage[] = { "test-tool proc-receive [<options>]", @@ -92,9 +92,9 @@ static void proc_receive_read_commands(struct packet_reader *reader, if (die_read_commands) die("die with the --die-read-commands option"); - if (parse_oid_hex(reader->line, &old_oid, &p) || + if (parse_oid_hex_any(reader->line, &old_oid, &p) == GIT_HASH_UNKNOWN || *p++ != ' ' || - parse_oid_hex(p, &new_oid, &p) || + parse_oid_hex_any(p, &new_oid, &p) == GIT_HASH_UNKNOWN || *p++ != ' ') die("protocol error: expected 'old new ref', got '%s'", reader->line); @@ -128,7 +128,6 @@ static void proc_receive_read_push_options(struct packet_reader *reader, int cmd__proc_receive(int argc, const char **argv) { - int nongit_ok = 0; struct packet_reader reader; struct command *commands = NULL; struct string_list push_options = STRING_LIST_INIT_DUP; @@ -154,8 +153,6 @@ int cmd__proc_receive(int argc, const char **argv) OPT_END() }; - setup_git_directory_gently(&nongit_ok); - argc = parse_options(argc, argv, "test-tools", options, proc_receive_usage, 0); if (argc > 0) usage_msg_opt("Too many arguments.", proc_receive_usage, options); diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 1ba226f1f9..5dd374379c 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "commit.h" #include "commit-reach.h" diff --git a/t/helper/test-read-cache.c b/t/helper/test-read-cache.c index e803c43ece..d285c656bd 100644 --- a/t/helper/test-read-cache.c +++ b/t/helper/test-read-cache.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "config.h" #include "read-cache-ll.h" diff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c index 8c7a83f578..9018c9f541 100644 --- a/t/helper/test-read-graph.c +++ b/t/helper/test-read-graph.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "commit-graph.h" #include "repository.h" @@ -5,20 +7,8 @@ #include "bloom.h" #include "setup.h" -int cmd__read_graph(int argc UNUSED, const char **argv UNUSED) +static void dump_graph_info(struct commit_graph *graph) { - struct commit_graph *graph = NULL; - struct object_directory *odb; - - setup_git_directory(); - odb = the_repository->objects->odb; - - prepare_repo_settings(the_repository); - - graph = read_commit_graph_one(the_repository, odb); - if (!graph) - return 1; - printf("header: %08x %d %d %d %d\n", ntohl(*(uint32_t*)graph->data), *(unsigned char*)(graph->data + 4), @@ -57,8 +47,57 @@ int cmd__read_graph(int argc UNUSED, const char **argv UNUSED) if (graph->topo_levels) printf(" topo_levels"); printf("\n"); +} + +static void dump_graph_bloom_filters(struct commit_graph *graph) +{ + uint32_t i; + + for (i = 0; i < graph->num_commits + graph->num_commits_in_base; i++) { + struct bloom_filter filter = { 0 }; + size_t j; + + if (load_bloom_filter_from_graph(graph, &filter, i) < 0) { + fprintf(stderr, "missing Bloom filter for graph " + "position %"PRIu32"\n", i); + continue; + } + + for (j = 0; j < filter.len; j++) + printf("%02x", filter.data[j]); + if (filter.len) + printf("\n"); + } +} + +int cmd__read_graph(int argc, const char **argv) +{ + struct commit_graph *graph = NULL; + struct object_directory *odb; + int ret = 0; + + setup_git_directory(); + odb = the_repository->objects->odb; + + prepare_repo_settings(the_repository); + + graph = read_commit_graph_one(the_repository, odb); + if (!graph) { + ret = 1; + goto done; + } + + if (argc <= 1) + dump_graph_info(graph); + else if (!strcmp(argv[1], "bloom-filters")) + dump_graph_bloom_filters(graph); + else { + fprintf(stderr, "unknown sub-command: '%s'\n", argv[1]); + ret = 1; + } +done: UNLEAK(graph); - return 0; + return ret; } diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c index 4acae41bb9..83effc2b5f 100644 --- a/t/helper/test-read-midx.c +++ b/t/helper/test-read-midx.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "midx.h" diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index c9efd74c2b..637b8b294e 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "hex.h" #include "refs.h" @@ -126,6 +128,7 @@ static struct flag_definition transaction_flags[] = { FLAG_DEF(REF_FORCE_CREATE_REFLOG), FLAG_DEF(REF_SKIP_OID_VERIFICATION), FLAG_DEF(REF_SKIP_REFNAME_VERIFICATION), + FLAG_DEF(REF_SKIP_CREATE_REFLOG), { NULL, 0 } }; diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c index 9475db2f76..623cf3f0f5 100644 --- a/t/helper/test-reftable.c +++ b/t/helper/test-reftable.c @@ -5,12 +5,8 @@ int cmd__reftable(int argc, const char **argv) { /* test from simple to complex. */ - basics_test_main(argc, argv); - record_test_main(argc, argv); block_test_main(argc, argv); - pq_test_main(argc, argv); readwrite_test_main(argc, argv); - merged_test_main(argc, argv); stack_test_main(argc, argv); return 0; } diff --git a/t/helper/test-regex.c b/t/helper/test-regex.c index 80042eafc2..366bd70976 100644 --- a/t/helper/test-regex.c +++ b/t/helper/test-regex.c @@ -20,8 +20,8 @@ static struct reg_flag reg_flags[] = { static int test_regex_bug(void) { - char *pat = "[^={} \t]+"; - char *str = "={}\nfred"; + const char *pat = "[^={} \t]+"; + const char *str = "={}\nfred"; regex_t r; regmatch_t m[1]; diff --git a/t/helper/test-repository.c b/t/helper/test-repository.c index 0c7c5aa4dd..63c37de33d 100644 --- a/t/helper/test-repository.c +++ b/t/helper/test-repository.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "commit-graph.h" #include "commit.h" @@ -17,7 +19,7 @@ static void test_parse_commit_in_graph(const char *gitdir, const char *worktree, setup_git_env(gitdir); - memset(the_repository, 0, sizeof(*the_repository)); + repo_clear(the_repository); if (repo_init(&r, gitdir, worktree)) die("Couldn't init repo"); @@ -47,7 +49,7 @@ static void test_get_commit_tree_in_graph(const char *gitdir, setup_git_env(gitdir); - memset(the_repository, 0, sizeof(*the_repository)); + repo_clear(the_repository); if (repo_init(&r, gitdir, worktree)) die("Couldn't init repo"); diff --git a/t/helper/test-revision-walking.c b/t/helper/test-revision-walking.c index f346951bc2..071f5bd1e2 100644 --- a/t/helper/test-revision-walking.c +++ b/t/helper/test-revision-walking.c @@ -8,6 +8,8 @@ * published by the Free Software Foundation. */ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "commit.h" #include "diff.h" diff --git a/t/helper/test-rot13-filter.c b/t/helper/test-rot13-filter.c index f8d564c622..7e1d9e0ee4 100644 --- a/t/helper/test-rot13-filter.c +++ b/t/helper/test-rot13-filter.c @@ -136,7 +136,7 @@ static void free_delay_entries(void) strmap_clear(&delay, 0); } -static void add_delay_entry(char *pathname, int count, int requested) +static void add_delay_entry(const char *pathname, int count, int requested) { struct delay_entry *entry = xcalloc(1, sizeof(*entry)); entry->count = count; @@ -189,7 +189,8 @@ static void reply_list_available_blobs_cmd(void) static void command_loop(void) { for (;;) { - char *buf, *output; + char *buf; + const char *output; char *pathname; struct delay_entry *entry; struct strbuf input = STRBUF_INIT; diff --git a/t/helper/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c index 737cbe475b..64fff6e9e3 100644 --- a/t/helper/test-scrap-cache-tree.c +++ b/t/helper/test-scrap-cache-tree.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "lockfile.h" #include "read-cache-ll.h" diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c index dcb7f6c003..e60d000c03 100644 --- a/t/helper/test-sha1.c +++ b/t/helper/test-sha1.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "hash-ll.h" +#include "hash.h" int cmd__sha1(int ac, const char **av) { diff --git a/t/helper/test-sha256.c b/t/helper/test-sha256.c index 08cf149001..2fb20438f3 100644 --- a/t/helper/test-sha256.c +++ b/t/helper/test-sha256.c @@ -1,5 +1,5 @@ #include "test-tool.h" -#include "hash-ll.h" +#include "hash.h" int cmd__sha256(int ac, const char **av) { diff --git a/t/helper/test-submodule-config.c b/t/helper/test-submodule-config.c index 9df2f03ac8..cbe93f2f9e 100644 --- a/t/helper/test-submodule-config.c +++ b/t/helper/test-submodule-config.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "config.h" #include "hash.h" @@ -44,7 +46,7 @@ int cmd__submodule_config(int argc, const char **argv) path_or_name = arg[1]; if (commit[0] == '\0') - oidclr(&commit_oid); + oidclr(&commit_oid, the_repository->hash_algo); else if (repo_get_oid(the_repository, commit, &commit_oid) < 0) die_usage(argc, argv, "Commit not found."); diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c index ecd40ded99..6ca069ce63 100644 --- a/t/helper/test-submodule-nested-repo-config.c +++ b/t/helper/test-submodule-nested-repo-config.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "repository.h" #include "setup.h" diff --git a/t/helper/test-submodule.c b/t/helper/test-submodule.c index 7197969a08..22e518d229 100644 --- a/t/helper/test-submodule.c +++ b/t/helper/test-submodule.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "test-tool-utils.h" #include "parse-options.h" diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 7ad7d07018..da3e69128a 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -29,7 +29,6 @@ static struct test_cmd cmds[] = { { "dump-split-index", cmd__dump_split_index }, { "dump-untracked-cache", cmd__dump_untracked_cache }, { "env-helper", cmd__env_helper }, - { "example-decorate", cmd__example_decorate }, { "example-tap", cmd__example_tap }, { "find-pack", cmd__find_pack }, { "fsmonitor-client", cmd__fsmonitor_client }, @@ -45,8 +44,6 @@ static struct test_cmd cmds[] = { { "mergesort", cmd__mergesort }, { "mktemp", cmd__mktemp }, { "oid-array", cmd__oid_array }, - { "oidmap", cmd__oidmap }, - { "oidtree", cmd__oidtree }, { "online-cpus", cmd__online_cpus }, { "pack-mtimes", cmd__pack_mtimes }, { "parse-options", cmd__parse_options }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index d14b3072bd..642a34578c 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -23,7 +23,6 @@ int cmd__dump_split_index(int argc, const char **argv); int cmd__dump_untracked_cache(int argc, const char **argv); int cmd__dump_reftable(int argc, const char **argv); int cmd__env_helper(int argc, const char **argv); -int cmd__example_decorate(int argc, const char **argv); int cmd__example_tap(int argc, const char **argv); int cmd__find_pack(int argc, const char **argv); int cmd__fsmonitor_client(int argc, const char **argv); @@ -38,8 +37,6 @@ int cmd__lazy_init_name_hash(int argc, const char **argv); int cmd__match_trees(int argc, const char **argv); int cmd__mergesort(int argc, const char **argv); int cmd__mktemp(int argc, const char **argv); -int cmd__oidmap(int argc, const char **argv); -int cmd__oidtree(int argc, const char **argv); int cmd__online_cpus(int argc, const char **argv); int cmd__pack_mtimes(int argc, const char **argv); int cmd__parse_options(int argc, const char **argv); diff --git a/t/helper/test-trace2.c b/t/helper/test-trace2.c index 1adac29a57..c588c273ce 100644 --- a/t/helper/test-trace2.c +++ b/t/helper/test-trace2.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "strvec.h" #include "run-command.h" @@ -24,6 +26,7 @@ static int get_i(int *p_value, const char *data) if (!data || !*data) return MyError; + errno = 0; *p_value = strtol(data, &endptr, 10); if (*endptr || errno == ERANGE) return MyError; diff --git a/t/helper/test-write-cache.c b/t/helper/test-write-cache.c index 7e3da380a9..b37dd2c5d6 100644 --- a/t/helper/test-write-cache.c +++ b/t/helper/test-write-cache.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "test-tool.h" #include "lockfile.h" #include "read-cache-ll.h" diff --git a/t/lib-bundle-uri-protocol.sh b/t/lib-bundle-uri-protocol.sh index a4a1af8d02..de09b6b02e 100644 --- a/t/lib-bundle-uri-protocol.sh +++ b/t/lib-bundle-uri-protocol.sh @@ -18,7 +18,7 @@ git) start_git_daemon --export-all --enable=receive-pack BUNDLE_URI_PARENT="$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent" BUNDLE_URI_REPO_URI="$GIT_DAEMON_URL/parent" - BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl" + BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URI/fake.bdl" test_set_prereq BUNDLE_URI_GIT ;; http) @@ -26,7 +26,7 @@ http) start_httpd BUNDLE_URI_PARENT="$HTTPD_DOCUMENT_ROOT_PATH/http_parent" BUNDLE_URI_REPO_URI="$HTTPD_URL/smart/http_parent" - BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl" + BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URL/fake.bdl" test_set_prereq BUNDLE_URI_HTTP ;; *) diff --git a/t/perf/p5333-pseudo-merge-bitmaps.sh b/t/perf/p5333-pseudo-merge-bitmaps.sh new file mode 100755 index 0000000000..2e8b1d2635 --- /dev/null +++ b/t/perf/p5333-pseudo-merge-bitmaps.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +test_description='pseudo-merge bitmaps' +. ./perf-lib.sh + +test_perf_large_repo + +test_expect_success 'setup' ' + git \ + -c bitmapPseudoMerge.all.pattern="refs/" \ + -c bitmapPseudoMerge.all.threshold=now \ + -c bitmapPseudoMerge.all.stableThreshold=never \ + -c bitmapPseudoMerge.all.maxMerges=64 \ + -c pack.writeBitmapLookupTable=true \ + repack -adb +' + +test_perf 'git rev-list --count --all --objects (no bitmaps)' ' + git rev-list --objects --all +' + +test_perf 'git rev-list --count --all --objects (no pseudo-merges)' ' + GIT_TEST_USE_PSEUDO_MERGES=0 \ + git rev-list --objects --all --use-bitmap-index +' + +test_perf 'git rev-list --count --all --objects (with pseudo-merges)' ' + GIT_TEST_USE_PSEUDO_MERGES=1 \ + git rev-list --objects --all --use-bitmap-index +' + +test_done diff --git a/t/socks4-proxy.pl b/t/socks4-proxy.pl new file mode 100644 index 0000000000..4c3a35c008 --- /dev/null +++ b/t/socks4-proxy.pl @@ -0,0 +1,48 @@ +use strict; +use IO::Select; +use IO::Socket::UNIX; +use IO::Socket::INET; + +my $path = shift; + +unlink($path); +my $server = IO::Socket::UNIX->new(Listen => 1, Local => $path) + or die "unable to listen on $path: $!"; + +$| = 1; +print "ready\n"; + +while (my $client = $server->accept()) { + sysread $client, my $buf, 8; + my ($version, $cmd, $port, $ip) = unpack 'CCnN', $buf; + next unless $version == 4; # socks4 + next unless $cmd == 1; # TCP stream connection + + # skip NUL-terminated id + while (sysread $client, my $char, 1) { + last unless ord($char); + } + + # version(0), reply(5a == granted), port (ignored), ip (ignored) + syswrite $client, "\x00\x5a\x00\x00\x00\x00\x00\x00"; + + my $remote = IO::Socket::INET->new(PeerHost => $ip, PeerPort => $port) + or die "unable to connect to $ip/$port: $!"; + + my $io = IO::Select->new($client, $remote); + while ($io->count) { + for my $fh ($io->can_read(0)) { + for my $pair ([$client, $remote], [$remote, $client]) { + my ($from, $to) = @$pair; + next unless $fh == $from; + + my $r = sysread $from, my $buf, 1024; + if (!defined $r || $r <= 0) { + $io->remove($from); + next; + } + syswrite $to, $buf; + } + } + } +} diff --git a/t/t0006-date.sh b/t/t0006-date.sh index 3031256d14..fd373e1b39 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -8,6 +8,11 @@ TEST_PASSES_SANITIZE_LEAK=true # arbitrary reference time: 2009-08-30 19:20:00 GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW +if test_have_prereq TIME_IS_64BIT,TIME_T_IS_64BIT +then + test_set_prereq HAVE_64BIT_TIME +fi + check_relative() { t=$(($GIT_TEST_DATE_NOW - $1)) echo "$t -> $2" >expect @@ -80,14 +85,15 @@ check_show raw "$TIME" '1466000000 -0200' # arbitrary time absurdly far in the future FUTURE="5758122296 -0400" -check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" TIME_IS_64BIT,TIME_T_IS_64BIT -check_show iso-local "$FUTURE" "2152-06-19 22:24:56 +0000" TIME_IS_64BIT,TIME_T_IS_64BIT +check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" HAVE_64BIT_TIME +check_show iso-local "$FUTURE" "2152-06-19 22:24:56 +0000" HAVE_64BIT_TIME -check_parse() { +REQUIRE_64BIT_TIME= +check_parse () { echo "$1 -> $2" >expect - test_expect_${4:-success} "parse date ($1${3:+ TZ=$3})" " - TZ=${3:-$TZ} test-tool date parse '$1' >actual && - test_cmp expect actual + test_expect_success $REQUIRE_64BIT_TIME "parse date ($1${3:+ TZ=$3}) -> $2" " + TZ=${3:-$TZ} test-tool date parse '$1' >actual && + test_cmp expect actual " } @@ -117,6 +123,39 @@ check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500' check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5 check_parse 'Thu, 7 Apr 2005 15:14:13 -0700' '2005-04-07 15:14:13 -0700' +check_parse '1970-01-01 00:00:00' '1970-01-01 00:00:00 +0000' +check_parse '1970-01-01 00:00:00 +00' '1970-01-01 00:00:00 +0000' +check_parse '1970-01-01 00:00:00 Z' '1970-01-01 00:00:00 +0000' +check_parse '1970-01-01 00:00:00 -01' '1970-01-01 00:00:00 -0100' +check_parse '1970-01-01 00:00:00 +01' bad +check_parse '1970-01-01 00:00:00 +11' bad +check_parse '1970-01-01 00:59:59 +01' bad +check_parse '1970-01-01 01:00:00 +01' '1970-01-01 01:00:00 +0100' +check_parse '1970-01-01 01:00:00 +11' bad +check_parse '1970-01-02 00:00:00 +11' '1970-01-02 00:00:00 +1100' +check_parse '1969-12-31 23:59:59' bad +check_parse '1969-12-31 23:59:59 +00' bad +check_parse '1969-12-31 23:59:59 Z' bad +check_parse '1969-12-31 23:59:59 +11' bad +check_parse '1969-12-31 23:59:59 -11' bad + +REQUIRE_64BIT_TIME=HAVE_64BIT_TIME +check_parse '2099-12-31 23:59:59' '2099-12-31 23:59:59 +0000' +check_parse '2099-12-31 23:59:59 +00' '2099-12-31 23:59:59 +0000' +check_parse '2099-12-31 23:59:59 Z' '2099-12-31 23:59:59 +0000' +check_parse '2099-12-31 23:59:59 +01' '2099-12-31 23:59:59 +0100' +check_parse '2099-12-31 23:59:59 -01' bad +check_parse '2099-12-31 23:59:59 -11' bad +check_parse '2099-12-31 23:00:00 -01' bad +check_parse '2099-12-31 22:59:59 -01' '2099-12-31 22:59:59 -0100' +check_parse '2100-00-00 00:00:00' bad +check_parse '2099-12-30 00:00:00 -11' '2099-12-30 00:00:00 -1100' +check_parse '2100-00-00 00:00:00 +00' bad +check_parse '2100-00-00 00:00:00 Z' bad +check_parse '2100-00-00 00:00:00 -11' bad +check_parse '2100-00-00 00:00:00 +11' bad +REQUIRE_64BIT_TIME= + check_approxidate() { echo "$1 -> $2 +0000" >expect test_expect_${3:-success} "parse approxidate ($1)" " diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh index ff4fd9348c..9fc5882387 100755 --- a/t/t0007-git-var.sh +++ b/t/t0007-git-var.sh @@ -157,7 +157,7 @@ test_expect_success POSIXPERM 'GIT_SHELL_PATH points to a valid executable' ' test_expect_success MINGW 'GIT_SHELL_PATH points to a suitable shell' ' shellpath=$(git var GIT_SHELL_PATH) && case "$shellpath" in - *sh) ;; + [A-Z]:/*/sh.exe) test -f "$shellpath";; *) return 1;; esac ' diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh index 361446b2f4..02a18d4fdb 100755 --- a/t/t0008-ignores.sh +++ b/t/t0008-ignores.sh @@ -945,4 +945,12 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' ' test_grep "unable to access.*gitignore" err ' +test_expect_success EXPENSIVE 'large exclude file ignored in tree' ' + test_when_finished "rm .gitignore" && + dd if=/dev/zero of=.gitignore bs=101M count=1 && + git ls-files -o --exclude-standard 2>err && + echo "warning: ignoring excessively large pattern file: .gitignore" >expect && + test_cmp expect err +' + test_done diff --git a/t/t0015-hash.sh b/t/t0015-hash.sh deleted file mode 100755 index 0a087a1983..0000000000 --- a/t/t0015-hash.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -test_description='test basic hash implementation' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -test_expect_success 'test basic SHA-1 hash values' ' - test-tool sha1 </dev/null >actual && - grep da39a3ee5e6b4b0d3255bfef95601890afd80709 actual && - printf "a" | test-tool sha1 >actual && - grep 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 actual && - printf "abc" | test-tool sha1 >actual && - grep a9993e364706816aba3e25717850c26c9cd0d89d actual && - printf "message digest" | test-tool sha1 >actual && - grep c12252ceda8be8994d5fa0290a47231c1d16aae3 actual && - printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha1 >actual && - grep 32d10c7b8cf96570ca04ce37f2a19d84240d3a89 actual && - perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | - test-tool sha1 >actual && - grep 34aa973cd4c4daa4f61eeb2bdbad27316534016f actual && - printf "blob 0\0" | test-tool sha1 >actual && - grep e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 actual && - printf "blob 3\0abc" | test-tool sha1 >actual && - grep f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f actual && - printf "tree 0\0" | test-tool sha1 >actual && - grep 4b825dc642cb6eb9a060e54bf8d69288fbee4904 actual -' - -test_expect_success 'test basic SHA-256 hash values' ' - test-tool sha256 </dev/null >actual && - grep e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 actual && - printf "a" | test-tool sha256 >actual && - grep ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb actual && - printf "abc" | test-tool sha256 >actual && - grep ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad actual && - printf "message digest" | test-tool sha256 >actual && - grep f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650 actual && - printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha256 >actual && - grep 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 actual && - # Try to exercise the chunking code by turning autoflush on. - perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | - test-tool sha256 >actual && - grep cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 actual && - perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | - test-tool sha256 >actual && - grep e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35 actual && - printf "blob 0\0" | test-tool sha256 >actual && - grep 473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813 actual && - printf "blob 3\0abc" | test-tool sha256 >actual && - grep c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6 actual && - printf "tree 0\0" | test-tool sha256 >actual && - grep 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321 actual -' - -test_done diff --git a/t/t0016-oidmap.sh b/t/t0016-oidmap.sh deleted file mode 100755 index 0faef1f4f1..0000000000 --- a/t/t0016-oidmap.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/sh - -test_description='test oidmap' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -# This purposefully is very similar to t0011-hashmap.sh - -test_oidmap () { - echo "$1" | test-tool oidmap $3 >actual && - echo "$2" >expect && - test_cmp expect actual -} - - -test_expect_success 'setup' ' - - test_commit one && - test_commit two && - test_commit three && - test_commit four - -' - -test_expect_success 'put' ' - -test_oidmap "put one 1 -put two 2 -put invalidOid 4 -put three 3" "NULL -NULL -Unknown oid: invalidOid -NULL" - -' - -test_expect_success 'replace' ' - -test_oidmap "put one 1 -put two 2 -put three 3 -put invalidOid 4 -put two deux -put one un" "NULL -NULL -NULL -Unknown oid: invalidOid -2 -1" - -' - -test_expect_success 'get' ' - -test_oidmap "put one 1 -put two 2 -put three 3 -get two -get four -get invalidOid -get one" "NULL -NULL -NULL -2 -NULL -Unknown oid: invalidOid -1" - -' - -test_expect_success 'remove' ' - -test_oidmap "put one 1 -put two 2 -put three 3 -remove one -remove two -remove invalidOid -remove four" "NULL -NULL -NULL -1 -2 -Unknown oid: invalidOid -NULL" - -' - -test_expect_success 'iterate' ' - test-tool oidmap >actual.raw <<-\EOF && - put one 1 - put two 2 - put three 3 - iterate - EOF - - # sort "expect" too so we do not rely on the order of particular oids - sort >expect <<-EOF && - NULL - NULL - NULL - $(git rev-parse one) 1 - $(git rev-parse two) 2 - $(git rev-parse three) 3 - EOF - - sort <actual.raw >actual && - test_cmp expect actual -' - -test_done diff --git a/t/t0018-advice.sh b/t/t0018-advice.sh index 29306b367c..fac52322a7 100755 --- a/t/t0018-advice.sh +++ b/t/t0018-advice.sh @@ -96,7 +96,6 @@ test_expect_success 'advice should be printed when GIT_ADVICE is set to true' ' >README && GIT_ADVICE=true git status ) >actual && - cat actual > /tmp/actual && test_cmp expect actual ' diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index 0b4997022b..eeb2714d9d 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -5,6 +5,7 @@ test_description='blob conversion via gitattributes' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-terminal.sh diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh index 11c3e8f28e..5fe61f1291 100755 --- a/t/t0033-safe-directory.sh +++ b/t/t0033-safe-directory.sh @@ -71,7 +71,22 @@ test_expect_success 'safe.directory=*, but is reset' ' expect_rejected_dir ' +test_expect_success 'safe.directory with matching glob' ' + git config --global --unset-all safe.directory && + p=$(pwd) && + git config --global safe.directory "${p%/*}/*" && + git status +' + +test_expect_success 'safe.directory with unmatching glob' ' + git config --global --unset-all safe.directory && + p=$(pwd) && + git config --global safe.directory "${p%/*}no/*" && + expect_rejected_dir +' + test_expect_success 'safe.directory in included file' ' + git config --global --unset-all safe.directory && cat >gitconfig-include <<-EOF && [safe] directory = "$(pwd)" diff --git a/t/t0064-oid-array.sh b/t/t0064-oid-array.sh index 88c89e8f48..de74b692d0 100755 --- a/t/t0064-oid-array.sh +++ b/t/t0064-oid-array.sh @@ -15,6 +15,24 @@ echoid () { done } +test_expect_success 'without repository' ' + cat >expect <<-EOF && + 4444444444444444444444444444444444444444 + 5555555555555555555555555555555555555555 + 8888888888888888888888888888888888888888 + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + EOF + cat >input <<-EOF && + append 4444444444444444444444444444444444444444 + append 5555555555555555555555555555555555555555 + append 8888888888888888888888888888888888888888 + append aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + for_each_unique + EOF + nongit test-tool oid-array <input >actual && + test_cmp expect actual +' + test_expect_success 'ordered enumeration' ' echoid "" 44 55 88 aa >expect && { diff --git a/t/t0069-oidtree.sh b/t/t0069-oidtree.sh deleted file mode 100755 index 889db50818..0000000000 --- a/t/t0069-oidtree.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh - -test_description='basic tests for the oidtree implementation' -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -maxhexsz=$(test_oid hexsz) -echoid () { - prefix="${1:+$1 }" - shift - while test $# -gt 0 - do - shortoid="$1" - shift - difference=$(($maxhexsz - ${#shortoid})) - printf "%s%s%0${difference}d\\n" "$prefix" "$shortoid" "0" - done -} - -test_expect_success 'oidtree insert and contains' ' - cat >expect <<-\EOF && - 0 - 0 - 0 - 1 - 1 - 0 - EOF - { - echoid insert 444 1 2 3 4 5 a b c d e && - echoid contains 44 441 440 444 4440 4444 && - echo clear - } | test-tool oidtree >actual && - test_cmp expect actual -' - -test_expect_success 'oidtree each' ' - echoid "" 123 321 321 >expect && - { - echoid insert f 9 8 123 321 a b c d e && - echo each 12300 && - echo each 3211 && - echo each 3210 && - echo each 32100 && - echo clear - } | test-tool oidtree >actual && - test_cmp expect actual -' - -test_done diff --git a/t/t0095-bloom.sh b/t/t0095-bloom.sh index b567383eb8..c8d84ab606 100755 --- a/t/t0095-bloom.sh +++ b/t/t0095-bloom.sh @@ -29,6 +29,14 @@ test_expect_success 'compute unseeded murmur3 hash for test string 2' ' test_cmp expect actual ' +test_expect_success 'compute unseeded murmur3 hash for test string 3' ' + cat >expect <<-\EOF && + Murmur3 Hash with seed=0:0xa183ccfd + EOF + test-tool bloom get_murmur3_seven_highbit >actual && + test_cmp expect actual +' + test_expect_success 'compute bloom key for empty string' ' cat >expect <<-\EOF && Hashes:0x5615800c|0x5b966560|0x61174ab4|0x66983008|0x6c19155c|0x7199fab0|0x771ae004| diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh index c10e35905e..5d5b64205f 100755 --- a/t/t0301-credential-cache.sh +++ b/t/t0301-credential-cache.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='credential-cache tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-credential.sh diff --git a/t/t0302-credential-store.sh b/t/t0302-credential-store.sh index 716bf1af9f..f83db659e2 100755 --- a/t/t0302-credential-store.sh +++ b/t/t0302-credential-store.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='credential-store tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-credential.sh diff --git a/t/t0303-credential-external.sh b/t/t0303-credential-external.sh index 72ae405c3e..8aadbe86c4 100755 --- a/t/t0303-credential-external.sh +++ b/t/t0303-credential-external.sh @@ -29,6 +29,7 @@ you can set GIT_TEST_CREDENTIAL_HELPER_SETUP to a sequence of shell commands. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-credential.sh diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh index 92f570313d..20df336cc3 100755 --- a/t/t0600-reffiles-backend.sh +++ b/t/t0600-reffiles-backend.sh @@ -91,82 +91,82 @@ test_expect_success 'empty directory should not fool 1-arg delete' ' git update-ref --stdin ' -test_expect_success 'non-empty directory blocks create' ' +test_expect_success 'non-empty directory blocks create' - <<\EOT prefix=refs/ne-create && mkdir -p .git/$prefix/foo/bar && : >.git/$prefix/foo/bar/baz.lock && test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/foo': there is a non-empty directory '.git/$prefix/foo' blocking reference '$prefix/foo' EOF printf "%s\n" "update $prefix/foo $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo' EOF printf "%s\n" "update $prefix/foo $D $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'broken reference blocks create' ' +test_expect_success 'broken reference blocks create' - <<\EOT prefix=refs/broken-create && mkdir -p .git/$prefix && echo "gobbledigook" >.git/$prefix/foo && test_when_finished "rm -f .git/$prefix/foo" && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken + fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo': reference broken EOF printf "%s\n" "update $prefix/foo $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken + fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo': reference broken EOF printf "%s\n" "update $prefix/foo $D $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'non-empty directory blocks indirect create' ' +test_expect_success 'non-empty directory blocks indirect create' - <<\EOT prefix=refs/ne-indirect-create && git symbolic-ref $prefix/symref $prefix/foo && mkdir -p .git/$prefix/foo/bar && : >.git/$prefix/foo/bar/baz.lock && test_when_finished "rm -f .git/$prefix/foo/bar/baz.lock" && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: there is a non-empty directory $SQ.git/$prefix/foo$SQ blocking reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/symref': there is a non-empty directory '.git/$prefix/foo' blocking reference '$prefix/foo' EOF printf "%s\n" "update $prefix/symref $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo' EOF printf "%s\n" "update $prefix/symref $D $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'broken reference blocks indirect create' ' +test_expect_success 'broken reference blocks indirect create' - <<\EOT prefix=refs/broken-indirect-create && git symbolic-ref $prefix/symref $prefix/foo && echo "gobbledigook" >.git/$prefix/foo && test_when_finished "rm -f .git/$prefix/foo" && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken + fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo': reference broken EOF printf "%s\n" "update $prefix/symref $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ: reference broken + fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo': reference broken EOF printf "%s\n" "update $prefix/symref $D $C" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT test_expect_success 'no bogus intermediate values during delete' ' prefix=refs/slow-transaction && @@ -224,7 +224,7 @@ test_expect_success 'no bogus intermediate values during delete' ' test_must_fail git rev-parse --verify --quiet $prefix/foo ' -test_expect_success 'delete fails cleanly if packed-refs file is locked' ' +test_expect_success 'delete fails cleanly if packed-refs file is locked' - <<\EOT prefix=refs/locked-packed-refs && # Set up a reference with differing loose and packed versions: git update-ref $prefix/foo $C && @@ -236,9 +236,9 @@ test_expect_success 'delete fails cleanly if packed-refs file is locked' ' test_when_finished "rm -f .git/packed-refs.lock" && test_must_fail git update-ref -d $prefix/foo >out 2>err && git for-each-ref $prefix >actual && - test_grep "Unable to create $SQ.*packed-refs.lock$SQ: " err && + test_grep "Unable to create '.*packed-refs.lock': " err && test_cmp unchanged actual -' +EOT test_expect_success 'delete fails cleanly if packed-refs.new write fails' ' # Setup and expectations are similar to the test above. @@ -468,4 +468,36 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' esac ' +test_expect_success SYMLINKS 'symref transaction supports symlinks' ' + test_when_finished "git symbolic-ref -d TEST_SYMREF_HEAD" && + git update-ref refs/heads/new @ && + test_config core.prefersymlinkrefs true && + cat >stdin <<-EOF && + start + symref-create TEST_SYMREF_HEAD refs/heads/new + prepare + commit + EOF + git update-ref --no-deref --stdin <stdin && + test_path_is_symlink .git/TEST_SYMREF_HEAD && + test "$(test_readlink .git/TEST_SYMREF_HEAD)" = refs/heads/new +' + +test_expect_success 'symref transaction supports false symlink config' ' + test_when_finished "git symbolic-ref -d TEST_SYMREF_HEAD" && + git update-ref refs/heads/new @ && + test_config core.prefersymlinkrefs false && + cat >stdin <<-EOF && + start + symref-create TEST_SYMREF_HEAD refs/heads/new + prepare + commit + EOF + git update-ref --no-deref --stdin <stdin && + test_path_is_file .git/TEST_SYMREF_HEAD && + git symbolic-ref TEST_SYMREF_HEAD >actual && + echo refs/heads/new >expect && + test_cmp expect actual +' + test_done diff --git a/t/t0612-reftable-jgit-compatibility.sh b/t/t0612-reftable-jgit-compatibility.sh index d0d7e80b49..84922153ab 100755 --- a/t/t0612-reftable-jgit-compatibility.sh +++ b/t/t0612-reftable-jgit-compatibility.sh @@ -11,6 +11,7 @@ export GIT_TEST_DEFAULT_REF_FORMAT GIT_TEST_SPLIT_INDEX=0 export GIT_TEST_SPLIT_INDEX +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh if ! test_have_prereq JGIT diff --git a/t/t0613-reftable-write-options.sh b/t/t0613-reftable-write-options.sh index e2708e11d5..b1c6c97524 100755 --- a/t/t0613-reftable-write-options.sh +++ b/t/t0613-reftable-write-options.sh @@ -16,6 +16,7 @@ export GIT_TEST_DEFAULT_HASH GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'default write options' ' diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh index 11bf10424f..2b9720b0fe 100755 --- a/t/t1004-read-tree-m-u-wf.sh +++ b/t/t1004-read-tree-m-u-wf.sh @@ -5,6 +5,7 @@ test_description='read-tree -m -u checks working tree files' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-read-tree.sh diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index e12b221972..ff9bf213aa 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -1294,4 +1294,34 @@ test_expect_success 'batch-command flush without --buffer' ' grep "^fatal:.*flush is only for --buffer mode.*" err ' +script=' +use warnings; +use strict; +use IPC::Open2; +my ($opt, $oid, $expect, @pfx) = @ARGV; +my @cmd = (qw(git cat-file), $opt); +my $pid = open2(my $out, my $in, @cmd) or die "open2: @cmd"; +print $in @pfx, $oid, "\n" or die "print $!"; +my $rvec = ""; +vec($rvec, fileno($out), 1) = 1; +select($rvec, undef, undef, 30) or die "no response to `@pfx $oid` from @cmd"; +my $info = <$out>; +chop($info) eq "\n" or die "no LF"; +$info eq $expect or die "`$info` != `$expect`"; +close $in or die "close in $!"; +close $out or die "close out $!"; +waitpid $pid, 0; +$? == 0 or die "\$?=$?"; +' + +expect="$hello_oid blob $hello_size" + +test_expect_success PERL '--batch-check is unbuffered by default' ' + perl -e "$script" -- --batch-check $hello_oid "$expect" +' + +test_expect_success PERL '--batch-command info is unbuffered by default' ' + perl -e "$script" -- --batch-command $hello_oid "$expect" "info " +' + test_done diff --git a/t/t1015-read-index-unmerged.sh b/t/t1015-read-index-unmerged.sh index 55d22da32c..da737a32a2 100755 --- a/t/t1015-read-index-unmerged.sh +++ b/t/t1015-read-index-unmerged.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='Test various callers of read_index_unmerged' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup modify/delete + directory/file conflict' ' diff --git a/t/t1021-rerere-in-workdir.sh b/t/t1021-rerere-in-workdir.sh index 0b892894eb..69bf9476cb 100755 --- a/t/t1021-rerere-in-workdir.sh +++ b/t/t1021-rerere-in-workdir.sh @@ -4,6 +4,7 @@ test_description='rerere run in a workdir' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success SYMLINKS setup ' diff --git a/t/t1090-sparse-checkout-scope.sh b/t/t1090-sparse-checkout-scope.sh index 3a14218b24..da0e7714d5 100755 --- a/t/t1090-sparse-checkout-scope.sh +++ b/t/t1090-sparse-checkout-scope.sh @@ -6,6 +6,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh index ab3a105fff..8c5cd651b4 100755 --- a/t/t1091-sparse-checkout-builtin.sh +++ b/t/t1091-sparse-checkout-builtin.sh @@ -8,6 +8,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME GIT_TEST_SPLIT_INDEX=false export GIT_TEST_SPLIT_INDEX +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh list_files() { diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 2f1ae5fd3b..a2c0e1b4dc 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -159,7 +159,10 @@ init_repos () { git -C sparse-checkout sparse-checkout set deep && git -C sparse-index sparse-checkout init --cone --sparse-index && test_cmp_config -C sparse-index true index.sparse && - git -C sparse-index sparse-checkout set deep + git -C sparse-index sparse-checkout set deep && + + # Disable this message to keep stderr the same. + git -C sparse-index config advice.sparseIndexExpanded false } init_repos_as_submodules () { @@ -2331,4 +2334,15 @@ test_expect_success 'sparse-index is not expanded: check-attr' ' ensure_not_expanded check-attr -a --cached -- folder1/a ' +test_expect_success 'advice.sparseIndexExpanded' ' + init_repos && + + git -C sparse-index config --unset advice.sparseIndexExpanded && + git -C sparse-index sparse-checkout set deep/deeper1 && + mkdir -p sparse-index/deep/deeper2/deepest && + touch sparse-index/deep/deeper2/deepest/bogus && + git -C sparse-index status 2>err && + grep "The sparse index is expanding to a full index" err +' + test_done diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 9de2d95f06..f13277c8f3 100755 --- a/t/t1300-config.sh +++ b/t/t1300-config.sh @@ -2704,6 +2704,15 @@ test_expect_success '--get and --get-all with --fixed-value' ' test_must_fail git config --file=config --get-regexp --fixed-value fixed+ non-existent ' +test_expect_success '--fixed-value with value-less configuration' ' + test_when_finished rm -f config && + cat >config <<-\EOF && + [section] + key + EOF + git config --file=config --fixed-value section.key value pattern +' + test_expect_success 'includeIf.hasconfig:remote.*.url' ' git init hasremoteurlTest && test_when_finished "rm -rf hasremoteurlTest" && diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index bbee2783ab..eb1691860d 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -892,17 +892,23 @@ test_expect_success 'stdin update/create/verify combination works' ' ' test_expect_success 'stdin verify succeeds for correct value' ' + test-tool ref-store main for-each-reflog-ent $m >before && git rev-parse $m >expect && echo "verify $m $m" >stdin && git update-ref --stdin <stdin && git rev-parse $m >actual && - test_cmp expect actual + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent $m >after && + test_cmp before after ' test_expect_success 'stdin verify succeeds for missing reference' ' + test-tool ref-store main for-each-reflog-ent $m >before && echo "verify refs/heads/missing $Z" >stdin && git update-ref --stdin <stdin && - test_must_fail git rev-parse --verify -q refs/heads/missing + test_must_fail git rev-parse --verify -q refs/heads/missing && + test-tool ref-store main for-each-reflog-ent $m >after && + test_cmp before after ' test_expect_success 'stdin verify treats no value as missing' ' @@ -1356,6 +1362,7 @@ test_expect_success 'fails with duplicate HEAD update' ' ' test_expect_success 'fails with duplicate ref update via symref' ' + test_when_finished "git symbolic-ref -d refs/heads/symref2" && git branch target2 $A && git symbolic-ref refs/heads/symref2 refs/heads/target2 && cat >stdin <<-EOF && @@ -1643,4 +1650,423 @@ test_expect_success PIPE 'transaction flushes status updates' ' test_cmp expected actual ' +format_command () { + if test "$1" = "-z" + then + shift + printf "$F" "$@" + else + echo "$@" + fi +} + +for type in "" "-z" +do + + test_expect_success "stdin $type symref-verify fails without --no-deref" ' + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-verify refs/heads/symref" "$a" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: symref-verify: cannot operate with deref mode" err + ' + + test_expect_success "stdin $type symref-verify fails with too many arguments" ' + format_command $type "symref-verify refs/heads/symref" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + if test "$type" = "-z" + then + grep "fatal: unknown command: $a" err + else + grep "fatal: symref-verify refs/heads/symref: extra input: $a" err + fi + ' + + test_expect_success "stdin $type symref-verify succeeds for correct value" ' + git symbolic-ref refs/heads/symref >expect && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >before && + format_command $type "symref-verify refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >after && + test_cmp before after + ' + + test_expect_success "stdin $type symref-verify fails with no value" ' + git symbolic-ref refs/heads/symref >expect && + format_command $type "symref-verify refs/heads/symref" "" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-verify succeeds for dangling reference" ' + test_when_finished "git symbolic-ref -d refs/heads/symref2" && + test_must_fail git symbolic-ref refs/heads/nonexistent && + git symbolic-ref refs/heads/symref2 refs/heads/nonexistent && + format_command $type "symref-verify refs/heads/symref2" "refs/heads/nonexistent" >stdin && + git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-verify fails for missing reference" ' + test-tool ref-store main for-each-reflog-ent refs/heads/symref >before && + format_command $type "symref-verify refs/heads/missing" "refs/heads/unknown" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: cannot lock ref ${SQ}refs/heads/missing${SQ}: unable to resolve reference ${SQ}refs/heads/missing${SQ}" err && + test_must_fail git rev-parse --verify -q refs/heads/missing && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >after && + test_cmp before after + ' + + test_expect_success "stdin $type symref-verify fails for wrong value" ' + git symbolic-ref refs/heads/symref >expect && + format_command $type "symref-verify refs/heads/symref" "$b" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-verify fails for mistaken null value" ' + git symbolic-ref refs/heads/symref >expect && + format_command $type "symref-verify refs/heads/symref" "$Z" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-delete fails without --no-deref" ' + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-delete refs/heads/symref" "$a" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: symref-delete: cannot operate with deref mode" err + ' + + test_expect_success "stdin $type symref-delete fails with no ref" ' + format_command $type "symref-delete " >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: symref-delete: missing <ref>" err + ' + + test_expect_success "stdin $type symref-delete fails deleting regular ref" ' + test_when_finished "git update-ref -d refs/heads/regularref" && + git update-ref refs/heads/regularref $a && + format_command $type "symref-delete refs/heads/regularref" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: cannot lock ref ${SQ}refs/heads/regularref${SQ}: expected symref with target ${SQ}$a${SQ}: but is a regular ref" err + ' + + test_expect_success "stdin $type symref-delete fails with too many arguments" ' + format_command $type "symref-delete refs/heads/symref" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + if test "$type" = "-z" + then + grep "fatal: unknown command: $a" err + else + grep "fatal: symref-delete refs/heads/symref: extra input: $a" err + fi + ' + + test_expect_success "stdin $type symref-delete fails with wrong old value" ' + format_command $type "symref-delete refs/heads/symref" "$m" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: verifying symref target: ${SQ}refs/heads/symref${SQ}: is at $a but expected refs/heads/main" err && + git symbolic-ref refs/heads/symref >expect && + echo $a >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-delete works with right old value" ' + format_command $type "symref-delete refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + test_must_fail git rev-parse --verify -q refs/heads/symref + ' + + test_expect_success "stdin $type symref-delete works with empty old value" ' + git symbolic-ref refs/heads/symref $a >stdin && + format_command $type "symref-delete refs/heads/symref" "" >stdin && + git update-ref --stdin $type --no-deref <stdin && + test_must_fail git rev-parse --verify -q $b + ' + + test_expect_success "stdin $type symref-delete succeeds for dangling reference" ' + test_must_fail git symbolic-ref refs/heads/nonexistent && + git symbolic-ref refs/heads/symref2 refs/heads/nonexistent && + format_command $type "symref-delete refs/heads/symref2" "refs/heads/nonexistent" >stdin && + git update-ref --stdin $type --no-deref <stdin && + test_must_fail git symbolic-ref -d refs/heads/symref2 + ' + + test_expect_success "stdin $type symref-delete deletes regular ref without target" ' + git update-ref refs/heads/regularref $a && + format_command $type "symref-delete refs/heads/regularref" >stdin && + git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-create fails with too many arguments" ' + format_command $type "symref-create refs/heads/symref" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + if test "$type" = "-z" + then + grep "fatal: unknown command: $a" err + else + grep "fatal: symref-create refs/heads/symref: extra input: $a" err + fi + ' + + test_expect_success "stdin $type symref-create fails with no target" ' + format_command $type "symref-create refs/heads/symref" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-create fails with empty target" ' + format_command $type "symref-create refs/heads/symref" "" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin + ' + + test_expect_success "stdin $type symref-create works" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-create refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >expect && + echo $a >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-create works with --no-deref" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-create refs/heads/symref" "$a" && + git update-ref --stdin $type <stdin 2>err + ' + + test_expect_success "stdin $type create dangling symref ref works" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-create refs/heads/symref" "refs/heads/unkown" >stdin && + git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >expect && + echo refs/heads/unkown >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-create does not create reflogs by default" ' + test_when_finished "git symbolic-ref -d refs/symref" && + format_command $type "symref-create refs/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + git symbolic-ref refs/symref >expect && + echo $a >actual && + test_cmp expect actual && + test_must_fail git reflog exists refs/symref + ' + + test_expect_success "stdin $type symref-create reflogs with --create-reflog" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-create refs/heads/symref" "$a" >stdin && + git update-ref --create-reflog --stdin $type --no-deref <stdin && + git symbolic-ref refs/heads/symref >expect && + echo $a >actual && + test_cmp expect actual && + git reflog exists refs/heads/symref + ' + + test_expect_success "stdin $type symref-update fails with too many arguments" ' + format_command $type "symref-update refs/heads/symref" "$a" "ref" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + if test "$type" = "-z" + then + grep "fatal: unknown command: $a" err + else + grep "fatal: symref-update refs/heads/symref: extra input: $a" err + fi + ' + + test_expect_success "stdin $type symref-update fails with wrong old value argument" ' + format_command $type "symref-update refs/heads/symref" "$a" "foo" "$a" "$a" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: symref-update refs/heads/symref: invalid arg ${SQ}foo${SQ} for old value" err + ' + + test_expect_success "stdin $type symref-update creates with zero old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-update refs/heads/symref" "$a" "oid" "$Z" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update creates with no old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-update refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update creates dangling" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_must_fail git rev-parse refs/heads/nonexistent && + format_command $type "symref-update refs/heads/symref" "refs/heads/nonexistent" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo refs/heads/nonexistent >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update fails with wrong old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-update refs/heads/symref" "$m" "ref" "$b" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin 2>err && + grep "fatal: verifying symref target: ${SQ}refs/heads/symref${SQ}: is at $a but expected $b" err && + test_must_fail git rev-parse --verify -q $c + ' + + test_expect_success "stdin $type symref-update updates dangling ref" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_must_fail git rev-parse refs/heads/nonexistent && + git symbolic-ref refs/heads/symref refs/heads/nonexistent && + format_command $type "symref-update refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update updates dangling ref with old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_must_fail git rev-parse refs/heads/nonexistent && + git symbolic-ref refs/heads/symref refs/heads/nonexistent && + format_command $type "symref-update refs/heads/symref" "$a" "ref" "refs/heads/nonexistent" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update fails update dangling ref with wrong old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_must_fail git rev-parse refs/heads/nonexistent && + git symbolic-ref refs/heads/symref refs/heads/nonexistent && + format_command $type "symref-update refs/heads/symref" "$a" "ref" "refs/heads/wrongref" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin && + echo refs/heads/nonexistent >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update works with right old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-update refs/heads/symref" "$m" "ref" "$a" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $m >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update works with no old value" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-update refs/heads/symref" "$m" >stdin && + git update-ref --stdin $type --no-deref <stdin && + echo $m >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update fails with empty old ref-target" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + git symbolic-ref refs/heads/symref $a && + format_command $type "symref-update refs/heads/symref" "$m" "ref" "" >stdin && + test_must_fail git update-ref --stdin $type --no-deref <stdin && + echo $a >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update creates (with deref)" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + format_command $type "symref-update refs/heads/symref" "$a" >stdin && + git update-ref --stdin $type <stdin && + echo $a >expect && + git symbolic-ref --no-recurse refs/heads/symref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >actual && + grep "$Z $(git rev-parse $a)" actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref with correct old-oid" ' + test_when_finished "git symbolic-ref -d --no-recurse refs/heads/regularref" && + git update-ref --no-deref refs/heads/regularref $a && + format_command $type "symref-update refs/heads/regularref" "$a" "oid" "$(git rev-parse $a)" >stdin && + git update-ref --stdin $type <stdin && + echo $a >expect && + git symbolic-ref --no-recurse refs/heads/regularref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/regularref >actual && + grep "$(git rev-parse $a) $(git rev-parse $a)" actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref fails with wrong old-oid" ' + test_when_finished "git update-ref -d refs/heads/regularref" && + git update-ref --no-deref refs/heads/regularref $a && + format_command $type "symref-update refs/heads/regularref" "$a" "oid" "$(git rev-parse refs/heads/target2)" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: cannot lock ref ${SQ}refs/heads/regularref${SQ}: is at $(git rev-parse $a) but expected $(git rev-parse refs/heads/target2)" err && + echo $(git rev-parse $a) >expect && + git rev-parse refs/heads/regularref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref fails with invalid old-oid" ' + test_when_finished "git update-ref -d refs/heads/regularref" && + git update-ref --no-deref refs/heads/regularref $a && + format_command $type "symref-update refs/heads/regularref" "$a" "oid" "not-a-ref-oid" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: symref-update refs/heads/regularref: invalid oid: not-a-ref-oid" err && + echo $(git rev-parse $a) >expect && + git rev-parse refs/heads/regularref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update existing symref with zero old-oid" ' + test_when_finished "git symbolic-ref -d --no-recurse refs/heads/symref" && + git symbolic-ref refs/heads/symref refs/heads/target2 && + format_command $type "symref-update refs/heads/symref" "$a" "oid" "$Z" >stdin && + test_must_fail git update-ref --stdin $type <stdin 2>err && + grep "fatal: cannot lock ref ${SQ}refs/heads/symref${SQ}: reference already exists" err && + echo refs/heads/target2 >expect && + git symbolic-ref refs/heads/symref >actual && + test_cmp expect actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref (with deref)" ' + test_when_finished "git symbolic-ref -d refs/heads/symref" && + test_when_finished "git update-ref -d --no-deref refs/heads/symref2" && + git update-ref refs/heads/symref2 $a && + git symbolic-ref --no-recurse refs/heads/symref refs/heads/symref2 && + format_command $type "symref-update refs/heads/symref" "$a" >stdin && + git update-ref $type --stdin <stdin && + echo $a >expect && + git symbolic-ref --no-recurse refs/heads/symref2 >actual && + test_cmp expect actual && + echo refs/heads/symref2 >expect && + git symbolic-ref --no-recurse refs/heads/symref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/symref >actual && + grep "$(git rev-parse $a) $(git rev-parse $a)" actual + ' + + test_expect_success "stdin $type symref-update regular ref to symref" ' + test_when_finished "git symbolic-ref -d --no-recurse refs/heads/regularref" && + git update-ref --no-deref refs/heads/regularref $a && + format_command $type "symref-update refs/heads/regularref" "$a" >stdin && + git update-ref $type --stdin <stdin && + echo $a >expect && + git symbolic-ref --no-recurse refs/heads/regularref >actual && + test_cmp expect actual && + test-tool ref-store main for-each-reflog-ent refs/heads/regularref >actual && + grep "$(git rev-parse $a) $(git rev-parse $a)" actual + ' + +done + test_done diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh index 33fb7a38ff..403f6b8f7d 100755 --- a/t/t1403-show-ref.sh +++ b/t/t1403-show-ref.sh @@ -121,13 +121,13 @@ test_expect_success 'show-ref -d' ' ' -test_expect_success 'show-ref --heads, --tags, --head, pattern' ' +test_expect_success 'show-ref --branches, --tags, --head, pattern' ' for branch in B main side do echo $(git rev-parse refs/heads/$branch) refs/heads/$branch || return 1 - done >expect.heads && - git show-ref --heads >actual && - test_cmp expect.heads actual && + done >expect.branches && + git show-ref --branches >actual && + test_cmp expect.branches actual && for tag in A B C do @@ -136,15 +136,15 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' ' git show-ref --tags >actual && test_cmp expect.tags actual && - cat expect.heads expect.tags >expect && - git show-ref --heads --tags >actual && + cat expect.branches expect.tags >expect && + git show-ref --branches --tags >actual && test_cmp expect actual && { echo $(git rev-parse HEAD) HEAD && - cat expect.heads expect.tags + cat expect.branches expect.tags } >expect && - git show-ref --heads --tags --head >actual && + git show-ref --branches --tags --head >actual && test_cmp expect actual && { @@ -165,6 +165,14 @@ test_expect_success 'show-ref --heads, --tags, --head, pattern' ' test_cmp expect actual ' +test_expect_success 'show-ref --heads is deprecated and hidden' ' + test_expect_code 129 git show-ref -h >short-help && + test_grep ! -e --heads short-help && + git show-ref --heads >actual 2>warning && + test_grep ! deprecated warning && + test_cmp expect.branches actual +' + test_expect_success 'show-ref --verify HEAD' ' echo $(git rev-parse HEAD) HEAD >expect && git show-ref --verify HEAD >actual && diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh index 67ebd81a4c..df90112618 100755 --- a/t/t1404-update-ref-errors.sh +++ b/t/t1404-update-ref-errors.sh @@ -100,13 +100,13 @@ df_test() { printf "%s\n" "delete $delname" "create $addname $D" fi >commands && test_must_fail git update-ref --stdin <commands 2>output.err && - grep -E "fatal:( cannot lock ref $SQ$addname$SQ:)? $SQ$delref$SQ exists; cannot create $SQ$addref$SQ" output.err && + grep -E "fatal:( cannot lock ref '$addname':)? '$delref' exists; cannot create '$addref'" output.err && printf "%s\n" "$C $delref" >expected-refs && git for-each-ref --format="%(objectname) %(refname)" $prefix/r >actual-refs && test_cmp expected-refs actual-refs } -test_expect_success 'setup' ' +test_expect_success 'setup' - <<\EOT git commit --allow-empty -m Initial && C=$(git rev-parse HEAD) && @@ -114,283 +114,283 @@ test_expect_success 'setup' ' D=$(git rev-parse HEAD) && git commit --allow-empty -m Third && E=$(git rev-parse HEAD) -' +EOT -test_expect_success 'existing loose ref is a simple prefix of new' ' +test_expect_success 'existing loose ref is a simple prefix of new' - <<\EOT prefix=refs/1l && test_update_rejected "a c e" false "b c/x d" \ - "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x$SQ" + "'$prefix/c' exists; cannot create '$prefix/c/x'" -' +EOT -test_expect_success 'existing packed ref is a simple prefix of new' ' +test_expect_success 'existing packed ref is a simple prefix of new' - <<\EOT prefix=refs/1p && test_update_rejected "a c e" true "b c/x d" \ - "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x$SQ" + "'$prefix/c' exists; cannot create '$prefix/c/x'" -' +EOT -test_expect_success 'existing loose ref is a deeper prefix of new' ' +test_expect_success 'existing loose ref is a deeper prefix of new' - <<\EOT prefix=refs/2l && test_update_rejected "a c e" false "b c/x/y d" \ - "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x/y$SQ" + "'$prefix/c' exists; cannot create '$prefix/c/x/y'" -' +EOT -test_expect_success 'existing packed ref is a deeper prefix of new' ' +test_expect_success 'existing packed ref is a deeper prefix of new' - <<\EOT prefix=refs/2p && test_update_rejected "a c e" true "b c/x/y d" \ - "$SQ$prefix/c$SQ exists; cannot create $SQ$prefix/c/x/y$SQ" + "'$prefix/c' exists; cannot create '$prefix/c/x/y'" -' +EOT -test_expect_success 'new ref is a simple prefix of existing loose' ' +test_expect_success 'new ref is a simple prefix of existing loose' - <<\EOT prefix=refs/3l && test_update_rejected "a c/x e" false "b c d" \ - "$SQ$prefix/c/x$SQ exists; cannot create $SQ$prefix/c$SQ" + "'$prefix/c/x' exists; cannot create '$prefix/c'" -' +EOT -test_expect_success 'new ref is a simple prefix of existing packed' ' +test_expect_success 'new ref is a simple prefix of existing packed' - <<\EOT prefix=refs/3p && test_update_rejected "a c/x e" true "b c d" \ - "$SQ$prefix/c/x$SQ exists; cannot create $SQ$prefix/c$SQ" + "'$prefix/c/x' exists; cannot create '$prefix/c'" -' +EOT -test_expect_success 'new ref is a deeper prefix of existing loose' ' +test_expect_success 'new ref is a deeper prefix of existing loose' - <<\EOT prefix=refs/4l && test_update_rejected "a c/x/y e" false "b c d" \ - "$SQ$prefix/c/x/y$SQ exists; cannot create $SQ$prefix/c$SQ" + "'$prefix/c/x/y' exists; cannot create '$prefix/c'" -' +EOT -test_expect_success 'new ref is a deeper prefix of existing packed' ' +test_expect_success 'new ref is a deeper prefix of existing packed' - <<\EOT prefix=refs/4p && test_update_rejected "a c/x/y e" true "b c d" \ - "$SQ$prefix/c/x/y$SQ exists; cannot create $SQ$prefix/c$SQ" + "'$prefix/c/x/y' exists; cannot create '$prefix/c'" -' +EOT -test_expect_success 'one new ref is a simple prefix of another' ' +test_expect_success 'one new ref is a simple prefix of another' - <<\EOT prefix=refs/5 && test_update_rejected "a e" false "b c c/x d" \ - "cannot process $SQ$prefix/c$SQ and $SQ$prefix/c/x$SQ at the same time" + "cannot process '$prefix/c' and '$prefix/c/x' at the same time" -' +EOT -test_expect_success 'D/F conflict prevents add long + delete short' ' +test_expect_success 'D/F conflict prevents add long + delete short' - <<\EOT df_test refs/df-al-ds --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents add short + delete long' ' +test_expect_success 'D/F conflict prevents add short + delete long' - <<\EOT df_test refs/df-as-dl --add-del foo foo/bar -' +EOT -test_expect_success 'D/F conflict prevents delete long + add short' ' +test_expect_success 'D/F conflict prevents delete long + add short' - <<\EOT df_test refs/df-dl-as --del-add foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents delete short + add long' ' +test_expect_success 'D/F conflict prevents delete short + add long' - <<\EOT df_test refs/df-ds-al --del-add foo foo/bar -' +EOT -test_expect_success 'D/F conflict prevents add long + delete short packed' ' +test_expect_success 'D/F conflict prevents add long + delete short packed' - <<\EOT df_test refs/df-al-dsp --pack --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents add short + delete long packed' ' +test_expect_success 'D/F conflict prevents add short + delete long packed' - <<\EOT df_test refs/df-as-dlp --pack --add-del foo foo/bar -' +EOT -test_expect_success 'D/F conflict prevents delete long packed + add short' ' +test_expect_success 'D/F conflict prevents delete long packed + add short' - <<\EOT df_test refs/df-dlp-as --pack --del-add foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents delete short packed + add long' ' +test_expect_success 'D/F conflict prevents delete short packed + add long' - <<\EOT df_test refs/df-dsp-al --pack --del-add foo foo/bar -' +EOT # Try some combinations involving symbolic refs... -test_expect_success 'D/F conflict prevents indirect add long + delete short' ' +test_expect_success 'D/F conflict prevents indirect add long + delete short' - <<\EOT df_test refs/df-ial-ds --sym-add --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents indirect add long + indirect delete short' ' +test_expect_success 'D/F conflict prevents indirect add long + indirect delete short' - <<\EOT df_test refs/df-ial-ids --sym-add --sym-del --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents indirect add short + indirect delete long' ' +test_expect_success 'D/F conflict prevents indirect add short + indirect delete long' - <<\EOT df_test refs/df-ias-idl --sym-add --sym-del --add-del foo foo/bar -' +EOT -test_expect_success 'D/F conflict prevents indirect delete long + indirect add short' ' +test_expect_success 'D/F conflict prevents indirect delete long + indirect add short' - <<\EOT df_test refs/df-idl-ias --sym-add --sym-del --del-add foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents indirect add long + delete short packed' ' +test_expect_success 'D/F conflict prevents indirect add long + delete short packed' - <<\EOT df_test refs/df-ial-dsp --sym-add --pack --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents indirect add long + indirect delete short packed' ' +test_expect_success 'D/F conflict prevents indirect add long + indirect delete short packed' - <<\EOT df_test refs/df-ial-idsp --sym-add --sym-del --pack --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents add long + indirect delete short packed' ' +test_expect_success 'D/F conflict prevents add long + indirect delete short packed' - <<\EOT df_test refs/df-al-idsp --sym-del --pack --add-del foo/bar foo -' +EOT -test_expect_success 'D/F conflict prevents indirect delete long packed + indirect add short' ' +test_expect_success 'D/F conflict prevents indirect delete long packed + indirect add short' - <<\EOT df_test refs/df-idlp-ias --sym-add --sym-del --pack --del-add foo/bar foo -' +EOT # Test various errors when reading the old values of references... -test_expect_success 'missing old value blocks update' ' +test_expect_success 'missing old value blocks update' - <<\EOT prefix=refs/missing-update && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: unable to resolve reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/foo': unable to resolve reference '$prefix/foo' EOF printf "%s\n" "update $prefix/foo $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks update' ' +test_expect_success 'incorrect old value blocks update' - <<\EOT prefix=refs/incorrect-update && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/foo': is at $C but expected $D EOF printf "%s\n" "update $prefix/foo $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'existing old value blocks create' ' +test_expect_success 'existing old value blocks create' - <<\EOT prefix=refs/existing-create && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: reference already exists + fatal: cannot lock ref '$prefix/foo': reference already exists EOF printf "%s\n" "create $prefix/foo $E" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks delete' ' +test_expect_success 'incorrect old value blocks delete' - <<\EOT prefix=refs/incorrect-delete && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/foo$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/foo': is at $C but expected $D EOF printf "%s\n" "delete $prefix/foo $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'missing old value blocks indirect update' ' +test_expect_success 'missing old value blocks indirect update' - <<\EOT prefix=refs/missing-indirect-update && git symbolic-ref $prefix/symref $prefix/foo && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: unable to resolve reference $SQ$prefix/foo$SQ + fatal: cannot lock ref '$prefix/symref': unable to resolve reference '$prefix/foo' EOF printf "%s\n" "update $prefix/symref $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks indirect update' ' +test_expect_success 'incorrect old value blocks indirect update' - <<\EOT prefix=refs/incorrect-indirect-update && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/symref': is at $C but expected $D EOF printf "%s\n" "update $prefix/symref $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'existing old value blocks indirect create' ' +test_expect_success 'existing old value blocks indirect create' - <<\EOT prefix=refs/existing-indirect-create && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: reference already exists + fatal: cannot lock ref '$prefix/symref': reference already exists EOF printf "%s\n" "create $prefix/symref $E" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks indirect delete' ' +test_expect_success 'incorrect old value blocks indirect delete' - <<\EOT prefix=refs/incorrect-indirect-delete && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/symref': is at $C but expected $D EOF printf "%s\n" "delete $prefix/symref $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'missing old value blocks indirect no-deref update' ' +test_expect_success 'missing old value blocks indirect no-deref update' - <<\EOT prefix=refs/missing-noderef-update && git symbolic-ref $prefix/symref $prefix/foo && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: reference is missing but expected $D + fatal: cannot lock ref '$prefix/symref': reference is missing but expected $D EOF printf "%s\n" "option no-deref" "update $prefix/symref $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks indirect no-deref update' ' +test_expect_success 'incorrect old value blocks indirect no-deref update' - <<\EOT prefix=refs/incorrect-noderef-update && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/symref': is at $C but expected $D EOF printf "%s\n" "option no-deref" "update $prefix/symref $E $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'existing old value blocks indirect no-deref create' ' +test_expect_success 'existing old value blocks indirect no-deref create' - <<\EOT prefix=refs/existing-noderef-create && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: reference already exists + fatal: cannot lock ref '$prefix/symref': reference already exists EOF printf "%s\n" "option no-deref" "create $prefix/symref $E" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT -test_expect_success 'incorrect old value blocks indirect no-deref delete' ' +test_expect_success 'incorrect old value blocks indirect no-deref delete' - <<\EOT prefix=refs/incorrect-noderef-delete && git symbolic-ref $prefix/symref $prefix/foo && git update-ref $prefix/foo $C && cat >expected <<-EOF && - fatal: cannot lock ref $SQ$prefix/symref$SQ: is at $C but expected $D + fatal: cannot lock ref '$prefix/symref': is at $C but expected $D EOF printf "%s\n" "option no-deref" "delete $prefix/symref $D" | test_must_fail git update-ref --stdin 2>output.err && test_cmp expected output.err -' +EOT test_done diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh index 5bf883f1e3..246a3f46ab 100755 --- a/t/t1410-reflog.sh +++ b/t/t1410-reflog.sh @@ -146,6 +146,14 @@ test_expect_success rewind ' test_line_count = 5 output ' +test_expect_success 'reflog expire should not barf on an annotated tag' ' + test_when_finished "git tag -d v0.tag || :" && + git -c core.logAllRefUpdates=always \ + tag -a -m "tag name" v0.tag main && + git reflog expire --dry-run refs/tags/v0.tag 2>err && + test_grep ! "error: [Oo]bject .* not a commit" err +' + test_expect_success 'corrupt and check' ' corrupt $F && diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh index 067fd57290..5a812ca3c0 100755 --- a/t/t1416-ref-transaction-hooks.sh +++ b/t/t1416-ref-transaction-hooks.sh @@ -157,4 +157,58 @@ test_expect_success 'hook captures git-symbolic-ref updates' ' test_cmp expect actual ' +test_expect_success 'hook gets all queued symref updates' ' + test_when_finished "rm actual" && + + git update-ref refs/heads/branch $POST_OID && + git symbolic-ref refs/heads/symref refs/heads/main && + git symbolic-ref refs/heads/symrefd refs/heads/main && + git symbolic-ref refs/heads/symrefu refs/heads/main && + + test_hook reference-transaction <<-\EOF && + echo "$*" >>actual + while read -r line + do + printf "%s\n" "$line" + done >>actual + EOF + + # In the files backend, "delete" also triggers an additional transaction + # update on the packed-refs backend, which constitutes additional reflog + # entries. + if test_have_prereq REFFILES + then + cat >expect <<-EOF + aborted + $ZERO_OID $ZERO_OID refs/heads/symrefd + EOF + else + >expect + fi && + + cat >>expect <<-EOF && + prepared + ref:refs/heads/main $ZERO_OID refs/heads/symref + ref:refs/heads/main $ZERO_OID refs/heads/symrefd + $ZERO_OID ref:refs/heads/main refs/heads/symrefc + ref:refs/heads/main ref:refs/heads/branch refs/heads/symrefu + committed + ref:refs/heads/main $ZERO_OID refs/heads/symref + ref:refs/heads/main $ZERO_OID refs/heads/symrefd + $ZERO_OID ref:refs/heads/main refs/heads/symrefc + ref:refs/heads/main ref:refs/heads/branch refs/heads/symrefu + EOF + + git update-ref --no-deref --stdin <<-EOF && + start + symref-verify refs/heads/symref refs/heads/main + symref-delete refs/heads/symrefd refs/heads/main + symref-create refs/heads/symrefc refs/heads/main + symref-update refs/heads/symrefu refs/heads/branch ref refs/heads/main + prepare + commit + EOF + test_cmp expect actual +' + test_done diff --git a/t/t1460-refs-migrate.sh b/t/t1460-refs-migrate.sh new file mode 100755 index 0000000000..f7c0783d30 --- /dev/null +++ b/t/t1460-refs-migrate.sh @@ -0,0 +1,243 @@ +#!/bin/sh + +test_description='migration of ref storage backends' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_migration () { + git -C "$1" for-each-ref --include-root-refs \ + --format='%(refname) %(objectname) %(symref)' >expect && + git -C "$1" refs migrate --ref-format="$2" && + git -C "$1" for-each-ref --include-root-refs \ + --format='%(refname) %(objectname) %(symref)' >actual && + test_cmp expect actual && + + git -C "$1" rev-parse --show-ref-format >actual && + echo "$2" >expect && + test_cmp expect actual +} + +test_expect_success 'setup' ' + rm -rf .git && + # The migration does not yet support reflogs. + git config --global core.logAllRefUpdates false +' + +test_expect_success "superfluous arguments" ' + test_when_finished "rm -rf repo" && + git init repo && + test_must_fail git -C repo refs migrate foo 2>err && + cat >expect <<-EOF && + usage: too many arguments + EOF + test_cmp expect err +' + +test_expect_success "missing ref storage format" ' + test_when_finished "rm -rf repo" && + git init repo && + test_must_fail git -C repo refs migrate 2>err && + cat >expect <<-EOF && + usage: missing --ref-format=<format> + EOF + test_cmp expect err +' + +test_expect_success "unknown ref storage format" ' + test_when_finished "rm -rf repo" && + git init repo && + test_must_fail git -C repo refs migrate \ + --ref-format=unknown 2>err && + cat >expect <<-EOF && + error: unknown ref storage format ${SQ}unknown${SQ} + EOF + test_cmp expect err +' + +ref_formats="files reftable" +for from_format in $ref_formats +do + for to_format in $ref_formats + do + if test "$from_format" = "$to_format" + then + continue + fi + + test_expect_success "$from_format: migration to same format fails" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_must_fail git -C repo refs migrate \ + --ref-format=$from_format 2>err && + cat >expect <<-EOF && + error: repository already uses ${SQ}$from_format${SQ} format + EOF + test_cmp expect err + ' + + test_expect_success "$from_format -> $to_format: migration with reflog fails" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_config -C repo core.logAllRefUpdates true && + test_commit -C repo logged && + test_must_fail git -C repo refs migrate \ + --ref-format=$to_format 2>err && + cat >expect <<-EOF && + error: migrating reflogs is not supported yet + EOF + test_cmp expect err + ' + + test_expect_success "$from_format -> $to_format: migration with worktree fails" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + git -C repo worktree add wt && + test_must_fail git -C repo refs migrate \ + --ref-format=$to_format 2>err && + cat >expect <<-EOF && + error: migrating repositories with worktrees is not supported yet + EOF + test_cmp expect err + ' + + test_expect_success "$from_format -> $to_format: unborn HEAD" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_migration repo "$to_format" + ' + + test_expect_success "$from_format -> $to_format: single ref" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + test_migration repo "$to_format" + ' + + test_expect_success "$from_format -> $to_format: bare repository" ' + test_when_finished "rm -rf repo repo.git" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git clone --ref-format=$from_format --mirror repo repo.git && + test_migration repo.git "$to_format" + ' + + test_expect_success "$from_format -> $to_format: dangling symref" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git -C repo symbolic-ref BROKEN_HEAD refs/heads/nonexistent && + test_migration repo "$to_format" && + echo refs/heads/nonexistent >expect && + git -C repo symbolic-ref BROKEN_HEAD >actual && + test_cmp expect actual + ' + + test_expect_success "$from_format -> $to_format: broken ref" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + test-tool -C repo ref-store main update-ref "" refs/heads/broken \ + "$(test_oid 001)" "$ZERO_OID" REF_SKIP_CREATE_REFLOG,REF_SKIP_OID_VERIFICATION && + test_migration repo "$to_format" && + test_oid 001 >expect && + git -C repo rev-parse refs/heads/broken >actual && + test_cmp expect actual + ' + + test_expect_success "$from_format -> $to_format: pseudo-refs" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git -C repo update-ref FOO_HEAD HEAD && + test_migration repo "$to_format" + ' + + test_expect_success "$from_format -> $to_format: special refs are left alone" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git -C repo rev-parse HEAD >repo/.git/MERGE_HEAD && + git -C repo rev-parse MERGE_HEAD && + test_migration repo "$to_format" && + test_path_is_file repo/.git/MERGE_HEAD + ' + + test_expect_success "$from_format -> $to_format: a bunch of refs" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + + test_commit -C repo initial && + cat >input <<-EOF && + create FOO_HEAD HEAD + create refs/heads/branch-1 HEAD + create refs/heads/branch-2 HEAD + create refs/heads/branch-3 HEAD + create refs/heads/branch-4 HEAD + create refs/tags/tag-1 HEAD + create refs/tags/tag-2 HEAD + EOF + git -C repo update-ref --stdin <input && + test_migration repo "$to_format" + ' + + test_expect_success "$from_format -> $to_format: dry-run migration does not modify repository" ' + test_when_finished "rm -rf repo" && + git init --ref-format=$from_format repo && + test_commit -C repo initial && + git -C repo refs migrate --dry-run \ + --ref-format=$to_format >output && + grep "Finished dry-run migration of refs" output && + test_path_is_dir repo/.git/ref_migration.* && + echo $from_format >expect && + git -C repo rev-parse --show-ref-format >actual && + test_cmp expect actual + ' + done +done + +test_expect_success 'migrating from files format deletes backend files' ' + test_when_finished "rm -rf repo" && + git init --ref-format=files repo && + test_commit -C repo first && + git -C repo pack-refs --all && + test_commit -C repo second && + git -C repo update-ref ORIG_HEAD HEAD && + git -C repo rev-parse HEAD >repo/.git/FETCH_HEAD && + + test_path_is_file repo/.git/HEAD && + test_path_is_file repo/.git/ORIG_HEAD && + test_path_is_file repo/.git/refs/heads/main && + test_path_is_file repo/.git/packed-refs && + + test_migration repo reftable && + + echo "ref: refs/heads/.invalid" >expect && + test_cmp expect repo/.git/HEAD && + echo "this repository uses the reftable format" >expect && + test_cmp expect repo/.git/refs/heads && + test_path_is_file repo/.git/FETCH_HEAD && + test_path_is_missing repo/.git/ORIG_HEAD && + test_path_is_missing repo/.git/refs/heads/main && + test_path_is_missing repo/.git/logs && + test_path_is_missing repo/.git/packed-refs +' + +test_expect_success 'migrating from reftable format deletes backend files' ' + test_when_finished "rm -rf repo" && + git init --ref-format=reftable repo && + test_commit -C repo first && + + test_path_is_dir repo/.git/reftable && + test_migration repo files && + + test_path_is_missing repo/.git/reftable && + echo "ref: refs/heads/main" >expect && + test_cmp expect repo/.git/HEAD && + test_path_is_file repo/.git/refs/heads/main +' + +test_done diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index b754b9fd74..5eaa6428c4 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test git rev-parse --parseopt' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check_invalid_long_option () { diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh index 6ecfed86bc..e7e78a4028 100755 --- a/t/t1511-rev-parse-caret.sh +++ b/t/t1511-rev-parse-caret.sh @@ -5,6 +5,7 @@ test_description='tests for ref^{stuff}' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh index 70f1e0a998..f9d68ce74e 100755 --- a/t/t1512-rev-parse-disambiguation.sh +++ b/t/t1512-rev-parse-disambiguation.sh @@ -23,6 +23,7 @@ one tagged as v1.0.0. They all have one regular file each. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_cmp_failed_rev_parse () { diff --git a/t/t1517-outside-repo.sh b/t/t1517-outside-repo.sh index 557808ffa7..990a036582 100755 --- a/t/t1517-outside-repo.sh +++ b/t/t1517-outside-repo.sh @@ -56,4 +56,56 @@ test_expect_success 'grep outside repository' ' test_cmp expect actual ' +test_expect_success 'imap-send outside repository' ' + test_config_global imap.host imaps://localhost && + test_config_global imap.folder Drafts && + + echo nothing to send >expect && + test_must_fail git imap-send -v </dev/null 2>actual && + test_cmp expect actual && + + ( + cd non-repo && + test_must_fail git imap-send -v </dev/null 2>../actual + ) && + test_cmp expect actual +' + +test_expect_success 'check-ref-format outside repository' ' + git check-ref-format --branch refs/heads/xyzzy >expect && + nongit git check-ref-format --branch refs/heads/xyzzy >actual && + test_cmp expect actual +' + +test_expect_success 'diff outside repository' ' + echo one >one && + echo two >two && + test_must_fail git diff --no-index one two >expect.raw && + ( + cd non-repo && + cp ../one . && + cp ../two . && + test_must_fail git diff one two >../actual.raw + ) && + # outside repository diff falls back to SHA-1 but + # GIT_DEFAULT_HASH may be set to sha256 on the in-repo side. + sed -e "/^index /d" expect.raw >expect && + sed -e "/^index /d" actual.raw >actual && + test_cmp expect actual +' + +test_expect_success 'stripspace outside repository' ' + nongit git stripspace -s </dev/null +' + +test_expect_success 'remote-http outside repository' ' + test_must_fail git remote-http 2>actual && + test_grep "^error: remote-curl" actual && + ( + cd non-repo && + test_must_fail git remote-http 2>../actual + ) && + test_grep "^error: remote-curl" actual +' + test_done diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh index be3fcdde07..b3f6bc97b5 100755 --- a/t/t2030-unresolve-info.sh +++ b/t/t2030-unresolve-info.sh @@ -5,6 +5,7 @@ test_description='undoing resolution' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check_resolve_undo () { diff --git a/t/t2080-parallel-checkout-basics.sh b/t/t2080-parallel-checkout-basics.sh index 5ffe1a41e2..59e5570cb2 100755 --- a/t/t2080-parallel-checkout-basics.sh +++ b/t/t2080-parallel-checkout-basics.sh @@ -8,6 +8,7 @@ working tree. ' TEST_NO_CREATE_REPO=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-parallel-checkout.sh" diff --git a/t/t2082-parallel-checkout-attributes.sh b/t/t2082-parallel-checkout-attributes.sh index f3511cd43a..aec55496eb 100755 --- a/t/t2082-parallel-checkout-attributes.sh +++ b/t/t2082-parallel-checkout-attributes.sh @@ -10,6 +10,7 @@ properly (without access to the index or attribute stack). ' TEST_NO_CREATE_REPO=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-parallel-checkout.sh" . "$TEST_DIRECTORY/lib-encoding.sh" diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh index cc72ead79f..f0eab13f96 100755 --- a/t/t2107-update-index-basic.sh +++ b/t/t2107-update-index-basic.sh @@ -5,6 +5,7 @@ test_description='basic update-index tests Tests for command-line parsing and basic operation. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'update-index --nonsense fails' ' diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index ba320dc417..cfc4aeb179 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -6,6 +6,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t2500-untracked-overwriting.sh b/t/t2500-untracked-overwriting.sh index 5c0bf4d21f..714feb83be 100755 --- a/t/t2500-untracked-overwriting.sh +++ b/t/t2500-untracked-overwriting.sh @@ -2,6 +2,7 @@ test_description='Test handling of overwriting untracked files' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_setup_reset () { diff --git a/t/t2501-cwd-empty.sh b/t/t2501-cwd-empty.sh index f6d8d7d03d..8af4e8cfe3 100755 --- a/t/t2501-cwd-empty.sh +++ b/t/t2501-cwd-empty.sh @@ -2,6 +2,7 @@ test_description='Test handling of the current working directory becoming empty' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh index 800fc33165..6e587d27d7 100755 --- a/t/t3201-branch-contains.sh +++ b/t/t3201-branch-contains.sh @@ -2,6 +2,7 @@ test_description='branch --contains <commit>, --no-contains <commit> --merged, and --no-merged' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3202-show-branch.sh b/t/t3202-show-branch.sh index a1139f79e2..3b6dad0c46 100755 --- a/t/t3202-show-branch.sh +++ b/t/t3202-show-branch.sh @@ -2,6 +2,7 @@ test_description='test show-branch' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'error descriptions on empty repository' ' diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 7b05bf3961..973e20254b 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -5,6 +5,7 @@ test_description='range-diff tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Note that because of the range-diff's heuristics, test_commit does more @@ -545,6 +546,20 @@ do ' done +test_expect_success "--range-diff implies --cover-letter for multi-patch series" ' + test_when_finished "rm -f v2-000?-*" && + git format-patch -v2 --range-diff=topic main..unmodified && + test_grep "^Range-diff against v1:$" v2-0000-cover-letter.patch +' + +test_expect_success "explicit --no-cover-letter defeats implied --cover-letter" ' + test_when_finished "rm -f v2-000?-*" && + test_must_fail git format-patch --no-cover-letter \ + -v2 --range-diff=topic main..unmodified && + test_must_fail git -c format.coverLetter=no format-patch \ + -v2 --range-diff=topic main..unmodified +' + test_expect_success 'format-patch --range-diff as commentary' ' git format-patch --range-diff=HEAD~1 HEAD~1 >actual && test_when_finished "rm 0001-*" && diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index cf23c06c09..99137fb235 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -5,6 +5,7 @@ test_description='Test commit notes' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh write_script fake_editor <<\EOF @@ -1556,4 +1557,14 @@ test_expect_success 'empty notes are displayed by git log' ' test_cmp expect actual ' +test_expect_success 'empty notes do not invoke the editor' ' + test_commit 18th && + GIT_EDITOR="false" git notes add -C "$empty_blob" --allow-empty && + git notes remove HEAD && + GIT_EDITOR="false" git notes add -m "" --allow-empty && + git notes remove HEAD && + GIT_EDITOR="false" git notes add -F /dev/null --allow-empty && + git notes remove HEAD +' + test_done diff --git a/t/t3306-notes-prune.sh b/t/t3306-notes-prune.sh index 8f4102ff9e..b6e9f643e3 100755 --- a/t/t3306-notes-prune.sh +++ b/t/t3306-notes-prune.sh @@ -2,6 +2,7 @@ test_description='Test git notes prune' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup: create a few commits with notes' ' diff --git a/t/t3308-notes-merge.sh b/t/t3308-notes-merge.sh index 202702be1a..e1d05ff6bc 100755 --- a/t/t3308-notes-merge.sh +++ b/t/t3308-notes-merge.sh @@ -5,6 +5,7 @@ test_description='Test merging of notes trees' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3309-notes-merge-auto-resolve.sh b/t/t3309-notes-merge-auto-resolve.sh index 9bd5dbf341..f55277f499 100755 --- a/t/t3309-notes-merge-auto-resolve.sh +++ b/t/t3309-notes-merge-auto-resolve.sh @@ -5,6 +5,7 @@ test_description='Test notes merging with auto-resolving strategies' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Set up a notes merge scenario with all kinds of potential conflicts diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index e1c8c5f701..ae34bfad60 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -11,6 +11,7 @@ among other things. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh GIT_AUTHOR_NAME=author@name diff --git a/t/t3401-rebase-and-am-rename.sh b/t/t3401-rebase-and-am-rename.sh index f18bae9450..328c1d3a3f 100755 --- a/t/t3401-rebase-and-am-rename.sh +++ b/t/t3401-rebase-and-am-rename.sh @@ -2,6 +2,7 @@ test_description='git rebase + directory rename tests' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh index a1911c4a9d..4f1d6e8ea6 100755 --- a/t/t3403-rebase-skip.sh +++ b/t/t3403-rebase-skip.sh @@ -8,6 +8,7 @@ test_description='git rebase --merge --skip tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index d1bead61fa..f92baad138 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -2215,6 +2215,51 @@ test_expect_success 'bad labels and refs rejected when parsing todo list' ' test_path_is_missing execed ' +test_expect_success 'non-merge commands reject merge commits' ' + test_when_finished "test_might_fail git rebase --abort" && + git checkout E && + git merge I && + oid=$(git rev-parse HEAD) && + cat >todo <<-EOF && + pick $oid + reword $oid + edit $oid + fixup $oid + squash $oid + EOF + ( + set_replace_editor todo && + test_must_fail git rebase -i HEAD 2>actual + ) && + cat >expect <<-EOF && + error: ${SQ}pick${SQ} does not accept merge commits + hint: ${SQ}pick${SQ} does not take a merge commit. If you wanted to + hint: replay the merge, use ${SQ}merge -C${SQ} on the commit. + hint: Disable this message with "git config advice.rebaseTodoError false" + error: invalid line 1: pick $oid + error: ${SQ}reword${SQ} does not accept merge commits + hint: ${SQ}reword${SQ} does not take a merge commit. If you wanted to + hint: replay the merge and reword the commit message, use + hint: ${SQ}merge -c${SQ} on the commit + hint: Disable this message with "git config advice.rebaseTodoError false" + error: invalid line 2: reword $oid + error: ${SQ}edit${SQ} does not accept merge commits + hint: ${SQ}edit${SQ} does not take a merge commit. If you wanted to + hint: replay the merge, use ${SQ}merge -C${SQ} on the commit, and then + hint: ${SQ}break${SQ} to give the control back to you so that you can + hint: do ${SQ}git commit --amend && git rebase --continue${SQ}. + hint: Disable this message with "git config advice.rebaseTodoError false" + error: invalid line 3: edit $oid + error: cannot squash merge commit into another commit + error: invalid line 4: fixup $oid + error: cannot squash merge commit into another commit + error: invalid line 5: squash $oid + You can fix this with ${SQ}git rebase --edit-todo${SQ} and then run ${SQ}git rebase --continue${SQ}. + Or you can abort the rebase with ${SQ}git rebase --abort${SQ}. + EOF + test_cmp expect actual +' + # This must be the last test in this file test_expect_success '$EDITOR and friends are unchanged' ' test_editor_unchanged diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index a1d7fa7f7c..82108b67e6 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -5,6 +5,7 @@ test_description='messages from rebase operation' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh index 9f49c4228b..2c3f38d45a 100755 --- a/t/t3407-rebase-abort.sh +++ b/t/t3407-rebase-abort.sh @@ -5,6 +5,7 @@ test_description='git rebase --abort tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3417-rebase-whitespace-fix.sh b/t/t3417-rebase-whitespace-fix.sh index 96f2cf22fa..22ee3a2045 100755 --- a/t/t3417-rebase-whitespace-fix.sh +++ b/t/t3417-rebase-whitespace-fix.sh @@ -5,6 +5,7 @@ test_description='git rebase --whitespace=fix This test runs git rebase --whitespace=fix and make sure that it works. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # prepare initial revision of "file" with a blank line at the end diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh index 127216f722..c0d29c2154 100755 --- a/t/t3418-rebase-continue.sh +++ b/t/t3418-rebase-continue.sh @@ -5,6 +5,7 @@ test_description='git rebase --continue tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh index 1a820f1481..63e400b89f 100755 --- a/t/t3420-rebase-autostash.sh +++ b/t/t3420-rebase-autostash.sh @@ -7,6 +7,7 @@ test_description='git rebase --autostash tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh index 62d86d557d..737af80bb3 100755 --- a/t/t3421-rebase-topology-linear.sh +++ b/t/t3421-rebase-topology-linear.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='basic rebase topology tests' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3424-rebase-empty.sh b/t/t3424-rebase-empty.sh index 1ee6b00fd5..515c949ae3 100755 --- a/t/t3424-rebase-empty.sh +++ b/t/t3424-rebase-empty.sh @@ -2,6 +2,7 @@ test_description='git rebase of commits that start or become empty' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup test repository' ' diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh index 6f57aed9fa..365436ebfc 100755 --- a/t/t3428-rebase-signoff.sh +++ b/t/t3428-rebase-signoff.sh @@ -5,6 +5,7 @@ test_description='git rebase --signoff This test runs git rebase --signoff and make sure that it works. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh index 59b5d6b6f2..2aa8593f77 100755 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@ -21,6 +21,7 @@ Initial setup: GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh . "$TEST_DIRECTORY"/lib-log-graph.sh @@ -391,8 +392,7 @@ test_expect_success 'refuse to merge ancestors of HEAD' ' test_expect_success 'root commits' ' git checkout --orphan unrelated && - (GIT_AUTHOR_NAME="Parsnip" GIT_AUTHOR_EMAIL="root@example.com" \ - test_commit second-root) && + test_commit --author "Parsnip <root@example.com>" second-root && test_commit third-root && cat >script-from-scratch <<-\EOF && pick third-root diff --git a/t/t3434-rebase-i18n.sh b/t/t3434-rebase-i18n.sh index a4e482d2cd..26a48d6b10 100755 --- a/t/t3434-rebase-i18n.sh +++ b/t/t3434-rebase-i18n.sh @@ -17,6 +17,7 @@ Initial setup: GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh compare_msg () { diff --git a/t/t3500-cherry.sh b/t/t3500-cherry.sh index 78c3eac54b..61ca87512d 100755 --- a/t/t3500-cherry.sh +++ b/t/t3500-cherry.sh @@ -11,6 +11,7 @@ checks that git cherry only returns the second patch in the local branch GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh GIT_AUTHOR_EMAIL=bogus_email_address diff --git a/t/t3504-cherry-pick-rerere.sh b/t/t3504-cherry-pick-rerere.sh index 4581ae98b8..597c98e9c5 100755 --- a/t/t3504-cherry-pick-rerere.sh +++ b/t/t3504-cherry-pick-rerere.sh @@ -5,6 +5,7 @@ test_description='cherry-pick should rerere for conflicts' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh index 9748443530..ead3fb4680 100755 --- a/t/t3505-cherry-pick-empty.sh +++ b/t/t3505-cherry-pick-empty.sh @@ -5,6 +5,7 @@ test_description='test cherry-picking an empty commit' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 2d53ce754c..afa7727a4a 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -5,6 +5,7 @@ test_description='test cherry-picking many commits' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check_head_differs_from() { diff --git a/t/t3509-cherry-pick-merge-df.sh b/t/t3509-cherry-pick-merge-df.sh index f4159246e1..171cc6d76b 100755 --- a/t/t3509-cherry-pick-merge-df.sh +++ b/t/t3509-cherry-pick-merge-df.sh @@ -4,6 +4,7 @@ test_description='Test cherry-pick with directory/file conflicts' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'Initialize repository' ' diff --git a/t/t3602-rm-sparse-checkout.sh b/t/t3602-rm-sparse-checkout.sh index 08580fd3dc..fcdefba48c 100755 --- a/t/t3602-rm-sparse-checkout.sh +++ b/t/t3602-rm-sparse-checkout.sh @@ -2,6 +2,7 @@ test_description='git rm in sparse checked out working trees' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' " diff --git a/t/t3650-replay-basics.sh b/t/t3650-replay-basics.sh index 389670262e..12bd3db4cb 100755 --- a/t/t3650-replay-basics.sh +++ b/t/t3650-replay-basics.sh @@ -5,6 +5,7 @@ test_description='basic git replay tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh GIT_AUTHOR_NAME=author@name diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh index 6624a4f7c0..718438ffc7 100755 --- a/t/t3701-add-interactive.sh +++ b/t/t3701-add-interactive.sh @@ -43,21 +43,6 @@ force_color () { ) } -test_expect_success 'warn about add.interactive.useBuiltin' ' - cat >expect <<-\EOF && - warning: the add.interactive.useBuiltin setting has been removed! - See its entry in '\''git help config'\'' for details. - EOF - echo "No changes." >expect.out && - - for v in = =true =false - do - git -c "add.interactive.useBuiltin$v" add -p >out 2>actual && - test_cmp expect.out out && - test_cmp expect actual || return 1 - done -' - test_expect_success 'unknown command' ' test_when_finished "git reset --hard; rm -f command" && echo W >command && @@ -590,6 +575,54 @@ test_expect_success 'navigate to hunk via regex / pattern' ' test_cmp expect actual.trimmed ' +test_expect_success 'print again the hunk' ' + test_when_finished "git reset" && + tr _ " " >expect <<-EOF && + +15 + 20 + (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? @@ -1,2 +1,3 @@ + 10 + +15 + 20 + (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?_ + EOF + test_write_lines s y g 1 p | git add -p >actual && + tail -n 7 <actual >actual.trimmed && + test_cmp expect actual.trimmed +' + +test_expect_success TTY 'print again the hunk (PAGER)' ' + test_when_finished "git reset" && + cat >expect <<-EOF && + <GREEN>+<RESET><GREEN>15<RESET> + 20<RESET> + <BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET>PAGER <CYAN>@@ -1,2 +1,3 @@<RESET> + PAGER 10<RESET> + PAGER <GREEN>+<RESET><GREEN>15<RESET> + PAGER 20<RESET> + <BOLD;BLUE>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]? <RESET> + EOF + test_write_lines s y g 1 P | + ( + GIT_PAGER="sed s/^/PAGER\ /" && + export GIT_PAGER && + test_terminal git add -p >actual + ) && + tail -n 7 <actual | test_decode_color >actual.trimmed && + test_cmp expect actual.trimmed +' + +test_expect_success TTY 'P handles SIGPIPE when writing to pager' ' + test_when_finished "rm -f huge_file; git reset" && + printf "\n%2500000s" Y >huge_file && + git add -N huge_file && + test_write_lines P q | ( + GIT_PAGER="head -n 1" && + export GIT_PAGER && + test_terminal git add -p + ) +' + test_expect_success 'split hunk "add -p (edit)"' ' # Split, say Edit and do nothing. Then: # @@ -1179,4 +1212,23 @@ test_expect_success 'reset -p with unmerged files' ' test_must_be_empty staged ' +test_expect_success 'hunk splitting works with diff.suppressBlankEmpty' ' + test_config diff.suppressBlankEmpty true && + write_script fake-editor.sh <<-\EOF && + tr F G <"$1" >"$1.tmp" && + mv "$1.tmp" "$1" + EOF + + test_write_lines a b "" c d "" e f "" >file && + git add file && + test_write_lines A b "" c D "" e F "" >file && + ( + test_set_editor "$(pwd)/fake-editor.sh" && + test_write_lines s n y e q | git add -p file + ) && + git cat-file blob :file >actual && + test_write_lines a b "" c D "" e G "" >expect && + test_cmp expect actual +' + test_done diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index f27d09cfd9..db7b403bc1 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -5,6 +5,7 @@ test_description='commit and log output encodings' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh compare_with () { diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index 4b37f78829..5f0b9afc3f 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -8,6 +8,7 @@ test_description='i18n settings and format-patch | am pipe' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check_encoding () { diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index a7f71f8126..e4c0937f61 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -8,6 +8,7 @@ test_description='Test git stash' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-unique-files.sh diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh index 368fc2a6cc..aa5019fd6c 100755 --- a/t/t3904-stash-patch.sh +++ b/t/t3904-stash-patch.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='stash -p' + +TEST_PASSES_SANITIZE_LEAK=true . ./lib-patch-mode.sh test_expect_success 'setup' ' diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh index 1289ae3e07..a1733f45c3 100755 --- a/t/t3905-stash-include-untracked.sh +++ b/t/t3905-stash-include-untracked.sh @@ -5,6 +5,7 @@ test_description='Test git stash --include-untracked' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'stash save --include-untracked some dirty working directory' ' diff --git a/t/t3907-stash-show-config.sh b/t/t3907-stash-show-config.sh index 10914bba7b..7a2eb98b86 100755 --- a/t/t3907-stash-show-config.sh +++ b/t/t3907-stash-show-config.sh @@ -2,6 +2,7 @@ test_description='Test git stash show configuration.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh index 898267a6bd..6d5918c8fe 100755 --- a/t/t3910-mac-os-precompose.sh +++ b/t/t3910-mac-os-precompose.sh @@ -37,6 +37,27 @@ Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #50 Byte Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte Alongc=$Alongc$AEligatu$AEligatu #254 Byte + +ls_files_nfc_nfd () { + test_when_finished "git config --global --unset core.precomposeunicode" && + prglbl=$1 + prlocl=$2 + aumlcreat=$3 + aumllist=$4 + git config --global core.precomposeunicode $prglbl && + ( + rm -rf .git && + mkdir -p "somewhere/$prglbl/$prlocl/$aumlcreat" && + mypwd=$PWD && + cd "somewhere/$prglbl/$prlocl/$aumlcreat" && + git init && + git config core.precomposeunicode $prlocl && + git --literal-pathspecs ls-files "$mypwd/somewhere/$prglbl/$prlocl/$aumllist" 2>err && + >expected && + test_cmp expected err + ) +} + test_expect_success "detect if nfd needed" ' precomposeunicode=$(git config core.precomposeunicode) && test "$precomposeunicode" = true && @@ -211,8 +232,8 @@ test_expect_success "unicode decomposed: git restore -p . " ' ' # Test if the global core.precomposeunicode stops autosensing -# Must be the last test case test_expect_success "respect git config --global core.precomposeunicode" ' + test_when_finished "git config --global --unset core.precomposeunicode" && git config --global core.precomposeunicode true && rm -rf .git && git init && @@ -220,4 +241,20 @@ test_expect_success "respect git config --global core.precomposeunicode" ' test "$precomposeunicode" = "true" ' +test_expect_success "ls-files false false nfd nfd" ' + ls_files_nfc_nfd false false $Adiarnfd $Adiarnfd +' + +test_expect_success "ls-files false true nfd nfd" ' + ls_files_nfc_nfd false true $Adiarnfd $Adiarnfd +' + +test_expect_success "ls-files true false nfd nfd" ' + ls_files_nfc_nfd true false $Adiarnfd $Adiarnfd +' + +test_expect_success "ls-files true true nfd nfd" ' + ls_files_nfc_nfd true true $Adiarnfd $Adiarnfd +' + test_done diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index ba85b582c5..884f83fb8a 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -820,8 +820,8 @@ test_expect_success 'format-patch --notes --signoff' ' ' test_expect_success 'format-patch notes output control' ' + test_when_finished "git notes remove HEAD || :" && git notes add -m "notes config message" HEAD && - test_when_finished git notes remove HEAD && git format-patch -1 --stdout >out && ! grep "notes config message" out && @@ -848,10 +848,10 @@ test_expect_success 'format-patch notes output control' ' ' test_expect_success 'format-patch with multiple notes refs' ' + test_when_finished "git notes --ref note1 remove HEAD; + git notes --ref note2 remove HEAD || :" && git notes --ref note1 add -m "this is note 1" HEAD && - test_when_finished git notes --ref note1 remove HEAD && git notes --ref note2 add -m "this is note 2" HEAD && - test_when_finished git notes --ref note2 remove HEAD && git format-patch -1 --stdout >out && ! grep "this is note 1" out && @@ -892,10 +892,10 @@ test_expect_success 'format-patch with multiple notes refs' ' test_expect_success 'format-patch with multiple notes refs in config' ' test_when_finished "test_unconfig format.notes" && + test_when_finished "git notes --ref note1 remove HEAD; + git notes --ref note2 remove HEAD || :" && git notes --ref note1 add -m "this is note 1" HEAD && - test_when_finished git notes --ref note1 remove HEAD && git notes --ref note2 add -m "this is note 2" HEAD && - test_when_finished git notes --ref note2 remove HEAD && git config format.notes note1 && git format-patch -1 --stdout >out && @@ -2482,16 +2482,55 @@ test_expect_success 'interdiff: reroll-count with a integer' ' ' test_expect_success 'interdiff: solo-patch' ' - cat >expect <<-\EOF && - +fleep - - EOF git format-patch --interdiff=boop~2 -1 boop && - test_grep "^Interdiff:$" 0001-fleep.patch && - sed "1,/^ @@ /d; /^$/q" 0001-fleep.patch >actual && + + # remove up to the last "patch" output line, + # and remove everything below the signature mark. + sed -e "1,/^+fleep\$/d" -e "/^-- /,\$d" 0001-fleep.patch >actual && + + # fabricate Interdiff output. + git diff boop~2 boop >inter && + { + echo && + echo "Interdiff:" && + sed -e "s/^/ /" inter + } >expect && test_cmp expect actual ' +test_expect_success 'range-diff: solo-patch' ' + git format-patch --creation-factor=999 \ + --range-diff=boop~2..boop~1 -1 boop && + + # remove up to the last "patch" output line, + # and remove everything below the signature mark. + sed -e "1,/^+fleep\$/d" -e "/^-- /,\$d" 0001-fleep.patch >actual && + + # fabricate range-diff output. + { + echo && + echo "Range-diff:" && + git range-diff --creation-factor=999 \ + boop~2..boop~1 boop~1..boop + } >expect && + test_cmp expect actual +' + +test_expect_success 'interdiff: multi-patch, implicit --cover-letter' ' + test_when_finished "rm -f v23-0*.patch" && + git format-patch --interdiff=boop~2 -2 -v23 && + test_grep "^Interdiff against v22:$" v23-0000-cover-letter.patch && + test_cmp expect actual +' + +test_expect_success 'interdiff: explicit --no-cover-letter defeats implied --cover-letter' ' + test_when_finished "rm -f v23-0*.patch" && + test_must_fail git format-patch --no-cover-letter \ + --interdiff=boop~2 -2 -v23 && + test_must_fail git -c format.coverLetter=no format-patch \ + --interdiff=boop~2 -2 -v23 +' + test_expect_success 'format-patch does not respect diff.noprefix' ' git -c diff.noprefix format-patch -1 --stdout >actual && grep "^--- a/blorp" actual diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index b443626afd..851cfe4f32 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -1184,6 +1184,15 @@ test_expect_success 'detect moved code, complete file' ' test_cmp expected actual ' +test_expect_success '--color-moved with --no-ext-diff' ' + test_config color.diff.oldMoved "yellow" && + test_config color.diff.newMoved "blue" && + args="--color --color-moved=zebra --no-renames HEAD" && + git diff $args >expect && + git -c diff.external=echo diff --no-ext-diff $args >actual && + test_cmp expect actual +' + test_expect_success 'detect malicious moved code, inside file' ' test_config color.diff.oldMoved "normal red" && test_config color.diff.newMoved "normal green" && diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index fdd865f7c3..3baa52a9bf 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -172,6 +172,72 @@ test_expect_success 'no diff with -diff' ' grep Binary out ' +check_external_diff () { + expect_code=$1 + expect_out=$2 + expect_err=$3 + command_code=$4 + trust_exit_code=$5 + shift 5 + options="$@" + + command="echo output; exit $command_code;" + desc="external diff '$command' with trustExitCode=$trust_exit_code" + with_options="${options:+ with }$options" + + test_expect_success "$desc via attribute$with_options" " + test_config diff.foo.command \"$command\" && + test_config diff.foo.trustExitCode $trust_exit_code && + echo \"file diff=foo\" >.gitattributes && + test_expect_code $expect_code git diff $options >out 2>err && + test_cmp $expect_out out && + test_cmp $expect_err err + " + + test_expect_success "$desc via diff.external$with_options" " + test_config diff.external \"$command\" && + test_config diff.trustExitCode $trust_exit_code && + >.gitattributes && + test_expect_code $expect_code git diff $options >out 2>err && + test_cmp $expect_out out && + test_cmp $expect_err err + " + + test_expect_success "$desc via GIT_EXTERNAL_DIFF$with_options" " + >.gitattributes && + test_expect_code $expect_code env \ + GIT_EXTERNAL_DIFF=\"$command\" \ + GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE=$trust_exit_code \ + git diff $options >out 2>err && + test_cmp $expect_out out && + test_cmp $expect_err err + " +} + +test_expect_success 'setup output files' ' + : >empty && + echo output >output && + echo "fatal: external diff died, stopping at file" >error +' + +check_external_diff 0 output empty 0 off +check_external_diff 128 output error 1 off +check_external_diff 0 output empty 0 on +check_external_diff 0 output empty 1 on +check_external_diff 128 output error 2 on + +check_external_diff 1 output empty 0 off --exit-code +check_external_diff 128 output error 1 off --exit-code +check_external_diff 0 output empty 0 on --exit-code +check_external_diff 1 output empty 1 on --exit-code +check_external_diff 128 output error 2 on --exit-code + +check_external_diff 1 empty empty 0 off --quiet +check_external_diff 1 empty empty 1 off --quiet # we don't even call the program +check_external_diff 0 empty empty 0 on --quiet +check_external_diff 1 empty empty 1 on --quiet +check_external_diff 128 empty error 2 on --quiet + echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file test_expect_success 'force diff with "diff"' ' diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 74586f3813..4dcd7e9925 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -70,7 +70,7 @@ test_language_driver () { word_diff --color-words ' test_expect_success "diff driver '$lang' in Islandic" ' - LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \ + test_env LANG=is_IS.UTF-8 LANGUAGE=is LC_ALL="$is_IS_locale" \ word_diff --color-words ' } diff --git a/t/t4061-diff-indent.sh b/t/t4061-diff-indent.sh index 7750b87ca1..2942e5d9b9 100755 --- a/t/t4061-diff-indent.sh +++ b/t/t4061-diff-indent.sh @@ -6,6 +6,7 @@ test_description='Test diff indent heuristic. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-diff.sh diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index 4eb8444029..d9a1084b5e 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -130,4 +130,66 @@ test_expect_success 'git apply respects core.fileMode' ' test_grep ! "has type 100644, expected 100755" err ' +test_expect_success POSIXPERM 'patch mode for new file is canonicalized' ' + cat >patch <<-\EOF && + diff --git a/non-canon b/non-canon + new file mode 100660 + --- /dev/null + +++ b/non-canon + +content + EOF + test_when_finished "git reset --hard" && + ( + umask 0 && + git apply --index patch 2>err + ) && + test_must_be_empty err && + git ls-files -s -- non-canon >staged && + test_grep "^100644" staged && + ls -l non-canon >worktree && + test_grep "^-rw-rw-rw" worktree +' + +test_expect_success POSIXPERM 'patch mode for deleted file is canonicalized' ' + test_when_finished "git reset --hard" && + echo content >non-canon && + git add non-canon && + chmod 666 non-canon && + + cat >patch <<-\EOF && + diff --git a/non-canon b/non-canon + deleted file mode 100660 + --- a/non-canon + +++ /dev/null + @@ -1 +0,0 @@ + -content + EOF + git apply --index patch 2>err && + test_must_be_empty err && + git ls-files -- non-canon >staged && + test_must_be_empty staged && + test_path_is_missing non-canon +' + +test_expect_success POSIXPERM 'patch mode for mode change is canonicalized' ' + test_when_finished "git reset --hard" && + echo content >non-canon && + git add non-canon && + + cat >patch <<-\EOF && + diff --git a/non-canon b/non-canon + old mode 100660 + new mode 100770 + EOF + ( + umask 0 && + git apply --index patch 2>err + ) && + test_must_be_empty err && + git ls-files -s -- non-canon >staged && + test_grep "^100755" staged && + ls -l non-canon >worktree && + test_grep "^-rwxrwxrwx" worktree +' + test_done diff --git a/t/t4131-apply-fake-ancestor.sh b/t/t4131-apply-fake-ancestor.sh index b1361ce546..40c92115a6 100755 --- a/t/t4131-apply-fake-ancestor.sh +++ b/t/t4131-apply-fake-ancestor.sh @@ -5,6 +5,7 @@ test_description='git apply --build-fake-ancestor handling.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh index edb38da701..1825a89d6a 100755 --- a/t/t4151-am-abort.sh +++ b/t/t4151-am-abort.sh @@ -2,6 +2,7 @@ test_description='am --abort' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh index 4add7c7757..dd6ad8f7a8 100755 --- a/t/t4153-am-resume-override-opts.sh +++ b/t/t4153-am-resume-override-opts.sh @@ -2,8 +2,8 @@ test_description='git-am command-line options override saved options' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -. "$TEST_DIRECTORY"/lib-terminal.sh format_patch () { git format-patch --stdout -1 "$1" >"$1".eml @@ -27,7 +27,12 @@ test_expect_success 'setup' ' format_patch side2 ' -test_expect_success TTY '--3way overrides --no-3way' ' +test_expect_success '--retry fails without in-progress operation' ' + test_must_fail git am --retry 2>err && + test_grep "operation not in progress" err +' + +test_expect_success '--3way overrides --no-3way' ' rm -fr .git/rebase-apply && git reset --hard && git checkout renamed-file && @@ -40,7 +45,7 @@ test_expect_success TTY '--3way overrides --no-3way' ' # Applying side1 with am --3way will succeed due to the threeway-merge. # Applying side2 will fail as --3way does not apply to it. - test_must_fail test_terminal git am --3way </dev/zero && + test_must_fail git am --retry --3way && test_path_is_dir .git/rebase-apply && test side1 = "$(cat file2)" ' @@ -84,7 +89,7 @@ test_expect_success '--signoff overrides --no-signoff' ' test $(git cat-file commit HEAD | grep -c "Signed-off-by:") -eq 0 ' -test_expect_success TTY '--reject overrides --no-reject' ' +test_expect_success '--reject overrides --no-reject' ' rm -fr .git/rebase-apply && git reset --hard && git checkout first && @@ -94,7 +99,7 @@ test_expect_success TTY '--reject overrides --no-reject' ' test_path_is_dir .git/rebase-apply && test_path_is_missing file.rej && - test_must_fail test_terminal git am --reject </dev/zero && + test_must_fail git am --retry --reject && test_path_is_dir .git/rebase-apply && test_path_is_file file.rej ' diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index b0a3e84984..213b36fb96 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -25,6 +25,7 @@ test_description='git rerere GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index f698d0c9ad..c20c885724 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -9,6 +9,7 @@ test_description='git shortlog GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 86c695eb0a..51f7beb59f 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -1237,6 +1237,30 @@ test_expect_success 'log.abbrevCommit configuration' ' test_cmp expect.whatchanged.full actual ' +test_expect_success '--abbrev-commit with core.abbrev=false' ' + git log --no-abbrev >expect && + git -c core.abbrev=false log --abbrev-commit >actual && + test_cmp expect actual +' + +test_expect_success '--abbrev-commit with --no-abbrev' ' + git log --no-abbrev >expect && + git log --abbrev-commit --no-abbrev >actual && + test_cmp expect actual +' + +test_expect_success '--abbrev-commit with core.abbrev=9000' ' + git log --no-abbrev >expect && + git -c core.abbrev=9000 log --abbrev-commit >actual && + test_cmp expect actual +' + +test_expect_success '--abbrev-commit with --abbrev=9000' ' + git log --no-abbrev >expect && + git log --abbrev-commit --abbrev=9000 >actual && + test_cmp expect actual +' + test_expect_success 'show added path under "--follow -M"' ' # This tests for a regression introduced in v1.7.2-rc0~103^2~2 test_create_repo regression && diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh index 8a88dd7900..79e5f42760 100755 --- a/t/t4203-mailmap.sh +++ b/t/t4203-mailmap.sh @@ -5,6 +5,7 @@ test_description='.mailmap configurations' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup commits and contacts file' ' diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh index 605faea0c7..dc8ddb10af 100755 --- a/t/t4204-patch-id.sh +++ b/t/t4204-patch-id.sh @@ -114,6 +114,46 @@ test_expect_success 'patch-id supports git-format-patch output' ' test "$2" = $(git rev-parse HEAD) ' +test_expect_success 'patch-id computes the same for various formats' ' + # This test happens to consider "git log -p -1" output + # the canonical input format, so use it as the norm. + git log -1 -p same >log-p.output && + git patch-id <log-p.output >expect && + + # format-patch begins with "From <commit object name>" + git format-patch -1 --stdout same >format-patch.output && + git patch-id <format-patch.output >actual && + test_cmp actual expect && + + # "diff-tree --stdin -p" begins with "<commit object name>" + same=$(git rev-parse same) && + echo $same | git diff-tree --stdin -p >diff-tree.output && + git patch-id <diff-tree.output >actual && + test_cmp actual expect && + + # "diff-tree --stdin -v -p" begins with "commit <commit object name>" + echo $same | git diff-tree --stdin -p -v >diff-tree-v.output && + git patch-id <diff-tree-v.output >actual && + test_cmp actual expect +' + +hash=$(git rev-parse same:) +for cruft in "$hash" "commit $hash is bad" "From $hash status" +do + test_expect_success "patch-id with <$cruft> in log message" ' + git format-patch -1 --stdout same >patch-0 && + git patch-id <patch-0 >expect && + + { + sed -e "/^$/q" patch-0 && + printf "random message\n%s\n\n" "$cruft" && + sed -e "1,/^$/d" patch-0 + } >patch-cruft && + git patch-id <patch-cruft >actual && + test_cmp actual expect + ' +done + test_expect_success 'whitespace is irrelevant in footer' ' get_patch_id main && git checkout same && diff --git a/t/t4208-log-magic-pathspec.sh b/t/t4208-log-magic-pathspec.sh index 806b2809d4..2a46eb6bed 100755 --- a/t/t4208-log-magic-pathspec.sh +++ b/t/t4208-log-magic-pathspec.sh @@ -5,6 +5,7 @@ test_description='magic pathspec tests using git-log' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh index 2ba0324a69..3f163dc396 100755 --- a/t/t4216-log-bloom.sh +++ b/t/t4216-log-bloom.sh @@ -82,7 +82,23 @@ test_bloom_filters_used () { test_bloom_filters_not_used () { log_args=$1 setup "$log_args" && - ! grep -q "statistics:{\"filter_not_present\":" "$TRASH_DIRECTORY/trace.perf" && + + if grep -q "statistics:{\"filter_not_present\":" "$TRASH_DIRECTORY/trace.perf" + then + # if the Bloom filter system is initialized, ensure that no + # filters were used + data="statistics:{" + # unusable filters (e.g., those computed with a + # different value of commitGraph.changedPathsVersion) + # are counted in the filter_not_present bucket, so any + # value is OK there. + data="$data\"filter_not_present\":[0-9][0-9]*," + data="$data\"maybe\":0," + data="$data\"definitely_not\":0," + data="$data\"false_positive\":0}" + + grep -q "$data" "$TRASH_DIRECTORY/trace.perf" + fi && test_cmp log_wo_bloom log_w_bloom } @@ -163,7 +179,7 @@ test_expect_success 'setup - add commit-graph to the chain with Bloom filters' ' test_bloom_filters_used_when_some_filters_are_missing () { log_args=$1 - bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":9" + bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":10" setup "$log_args" && grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" && test_cmp log_wo_bloom log_w_bloom @@ -206,6 +222,10 @@ test_filter_trunc_large () { grep "\"key\":\"filter-trunc-large\",\"value\":\"$1\"" $2 } +test_filter_upgraded () { + grep "\"key\":\"filter-upgraded\",\"value\":\"$1\"" $2 +} + test_expect_success 'correctly report changes over limit' ' git init limits && ( @@ -405,8 +425,307 @@ test_expect_success 'Bloom generation backfills empty commits' ' ) ' +graph=.git/objects/info/commit-graph +graphdir=.git/objects/info/commit-graphs +chain=$graphdir/commit-graph-chain + +test_expect_success 'setup for mixed Bloom setting tests' ' + repo=mixed-bloom-settings && + + git init $repo && + for i in one two three + do + test_commit -C $repo $i file || return 1 + done +' + +test_expect_success 'ensure Bloom filters with incompatible settings are ignored' ' + # Compute Bloom filters with "unusual" settings. + git -C $repo rev-parse one >in && + GIT_TEST_BLOOM_SETTINGS_NUM_HASHES=3 git -C $repo commit-graph write \ + --stdin-commits --changed-paths --split <in && + layer=$(head -n 1 $repo/$chain) && + + # A commit-graph layer without Bloom filters "hides" the layers + # below ... + git -C $repo rev-parse two >in && + git -C $repo commit-graph write --stdin-commits --no-changed-paths \ + --split=no-merge <in && + + # Another commit-graph layer that has Bloom filters, but with + # standard settings, and is thus incompatible with the base + # layer written above. + git -C $repo rev-parse HEAD >in && + git -C $repo commit-graph write --stdin-commits --changed-paths \ + --split=no-merge <in && + + test_line_count = 3 $repo/$chain && + + # Ensure that incompatible Bloom filters are ignored. + git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- file \ + >expect 2>err && + git -C $repo log --oneline --no-decorate -- file >actual 2>err && + test_cmp expect actual && + grep "disabling Bloom filters for commit-graph layer .$layer." err +' + +test_expect_success 'merge graph layers with incompatible Bloom settings' ' + # Ensure that incompatible Bloom filters are ignored when + # merging existing layers. + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C $repo commit-graph write --reachable --changed-paths 2>err && + grep "disabling Bloom filters for commit-graph layer .$layer." err && + grep "{\"hash_version\":1,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt && + + test_path_is_file $repo/$graph && + test_dir_is_empty $repo/$graphdir && + + git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- \ + file >expect && + trace_out="$(pwd)/trace.perf" && + GIT_TRACE2_PERF="$trace_out" \ + git -C $repo log --oneline --no-decorate -- file >actual 2>err && + + test_cmp expect actual && + grep "statistics:{\"filter_not_present\":0," trace.perf && + test_must_be_empty err +' + +# chosen to be the same under all Unicode normalization forms +CENT=$(printf "\302\242") + +test_expect_success 'ensure Bloom filter with incompatible versions are ignored' ' + rm "$repo/$graph" && + + git -C $repo log --oneline --no-decorate -- $CENT >expect && + + # Compute v1 Bloom filters for commits at the bottom. + git -C $repo rev-parse HEAD^ >in && + git -C $repo commit-graph write --stdin-commits --changed-paths \ + --split <in && + + # Compute v2 Bloomfilters for the rest of the commits at the top. + git -C $repo rev-parse HEAD >in && + git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write \ + --stdin-commits --changed-paths --split=no-merge <in && + + test_line_count = 2 $repo/$chain && + + git -C $repo log --oneline --no-decorate -- $CENT >actual 2>err && + test_cmp expect actual && + + layer="$(head -n 1 $repo/$chain)" && + cat >expect.err <<-EOF && + warning: disabling Bloom filters for commit-graph layer $SQ$layer$SQ due to incompatible settings + EOF + test_cmp expect.err err && + + # Merge the two layers with incompatible bloom filter versions, + # ensuring that the v2 filters are used. + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write --reachable --changed-paths 2>err && + grep "disabling Bloom filters for commit-graph layer .$layer." err && + grep "{\"hash_version\":2,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt +' + +get_first_changed_path_filter () { + test-tool read-graph bloom-filters >filters.dat && + head -n 1 filters.dat +} + +test_expect_success 'set up repo with high bit path, version 1 changed-path' ' + git init highbit1 && + test_commit -C highbit1 c1 "$CENT" && + git -C highbit1 commit-graph write --reachable --changed-paths +' + +test_expect_success 'setup check value of version 1 changed-path' ' + ( + cd highbit1 && + echo "52a9" >expect && + get_first_changed_path_filter >actual + ) +' + +# expect will not match actual if char is unsigned by default. Write the test +# in this way, so that a user running this test script can still see if the two +# files match. (It will appear as an ordinary success if they match, and a skip +# if not.) +if test_cmp highbit1/expect highbit1/actual +then + test_set_prereq SIGNED_CHAR_BY_DEFAULT +fi +test_expect_success SIGNED_CHAR_BY_DEFAULT 'check value of version 1 changed-path' ' + # Only the prereq matters for this test. + true +' + +test_expect_success 'setup make another commit' ' + # "git log" does not use Bloom filters for root commits - see how, in + # revision.c, rev_compare_tree() (the only code path that eventually calls + # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit + # has one parent. Therefore, make another commit so that we perform the tests on + # a non-root commit. + test_commit -C highbit1 anotherc1 "another$CENT" +' + +test_expect_success 'version 1 changed-path used when version 1 requested' ' + ( + cd highbit1 && + test_bloom_filters_used "-- another$CENT" + ) +' + +test_expect_success 'version 1 changed-path not used when version 2 requested' ' + ( + cd highbit1 && + git config --add commitGraph.changedPathsVersion 2 && + test_bloom_filters_not_used "-- another$CENT" + ) +' + +test_expect_success 'version 1 changed-path used when autodetect requested' ' + ( + cd highbit1 && + git config --add commitGraph.changedPathsVersion -1 && + test_bloom_filters_used "-- another$CENT" + ) +' + +test_expect_success 'when writing another commit graph, preserve existing version 1 of changed-path' ' + test_commit -C highbit1 c1double "$CENT$CENT" && + git -C highbit1 commit-graph write --reachable --changed-paths && + ( + cd highbit1 && + git config --add commitGraph.changedPathsVersion -1 && + echo "options: bloom(1,10,7) read_generation_data" >expect && + test-tool read-graph >full && + grep options full >actual && + test_cmp expect actual + ) +' + +test_expect_success 'set up repo with high bit path, version 2 changed-path' ' + git init highbit2 && + git -C highbit2 config --add commitGraph.changedPathsVersion 2 && + test_commit -C highbit2 c2 "$CENT" && + git -C highbit2 commit-graph write --reachable --changed-paths +' + +test_expect_success 'check value of version 2 changed-path' ' + ( + cd highbit2 && + echo "c01f" >expect && + get_first_changed_path_filter >actual && + test_cmp expect actual + ) +' + +test_expect_success 'setup make another commit' ' + # "git log" does not use Bloom filters for root commits - see how, in + # revision.c, rev_compare_tree() (the only code path that eventually calls + # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit + # has one parent. Therefore, make another commit so that we perform the tests on + # a non-root commit. + test_commit -C highbit2 anotherc2 "another$CENT" +' + +test_expect_success 'version 2 changed-path used when version 2 requested' ' + ( + cd highbit2 && + test_bloom_filters_used "-- another$CENT" + ) +' + +test_expect_success 'version 2 changed-path not used when version 1 requested' ' + ( + cd highbit2 && + git config --add commitGraph.changedPathsVersion 1 && + test_bloom_filters_not_used "-- another$CENT" + ) +' + +test_expect_success 'version 2 changed-path used when autodetect requested' ' + ( + cd highbit2 && + git config --add commitGraph.changedPathsVersion -1 && + test_bloom_filters_used "-- another$CENT" + ) +' + +test_expect_success 'when writing another commit graph, preserve existing version 2 of changed-path' ' + test_commit -C highbit2 c2double "$CENT$CENT" && + git -C highbit2 commit-graph write --reachable --changed-paths && + ( + cd highbit2 && + git config --add commitGraph.changedPathsVersion -1 && + echo "options: bloom(2,10,7) read_generation_data" >expect && + test-tool read-graph >full && + grep options full >actual && + test_cmp expect actual + ) +' + +test_expect_success 'when writing commit graph, do not reuse changed-path of another version' ' + git init doublewrite && + test_commit -C doublewrite c "$CENT" && + + git -C doublewrite config --add commitGraph.changedPathsVersion 1 && + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C doublewrite commit-graph write --reachable --changed-paths && + test_filter_computed 1 trace2.txt && + test_filter_upgraded 0 trace2.txt && + + git -C doublewrite commit-graph write --reachable --changed-paths && + for v in -2 3 + do + git -C doublewrite config --add commitGraph.changedPathsVersion $v && + git -C doublewrite commit-graph write --reachable --changed-paths 2>err && + cat >expect <<-EOF && + warning: attempting to write a commit-graph, but ${SQ}commitGraph.changedPathsVersion${SQ} ($v) is not supported + EOF + test_cmp expect err || return 1 + done && + + git -C doublewrite config --add commitGraph.changedPathsVersion 2 && + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C doublewrite commit-graph write --reachable --changed-paths && + test_filter_computed 1 trace2.txt && + test_filter_upgraded 0 trace2.txt && + + ( + cd doublewrite && + echo "c01f" >expect && + get_first_changed_path_filter >actual && + test_cmp expect actual + ) +' + +test_expect_success 'when writing commit graph, reuse changed-path of another version where possible' ' + git init upgrade && + + test_commit -C upgrade base no-high-bits && + + git -C upgrade config --add commitGraph.changedPathsVersion 1 && + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C upgrade commit-graph write --reachable --changed-paths && + test_filter_computed 1 trace2.txt && + test_filter_upgraded 0 trace2.txt && + + git -C upgrade config --add commitGraph.changedPathsVersion 2 && + >trace2.txt && + GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \ + git -C upgrade commit-graph write --reachable --changed-paths && + test_filter_computed 0 trace2.txt && + test_filter_upgraded 1 trace2.txt +' + corrupt_graph () { - graph=.git/objects/info/commit-graph && test_when_finished "rm -rf $graph" && git commit-graph write --reachable --changed-paths && corrupt_chunk_file $graph "$@" diff --git a/t/t4253-am-keep-cr-dos.sh b/t/t4253-am-keep-cr-dos.sh index 0ee69d2a0c..2bcdd9f34f 100755 --- a/t/t4253-am-keep-cr-dos.sh +++ b/t/t4253-am-keep-cr-dos.sh @@ -9,6 +9,7 @@ test_description='git-am mbox with dos line ending. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Three patches which will be added as files with dos line ending. diff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh index a7ba08f728..04f3ccfc41 100755 --- a/t/t4255-am-submodule.sh +++ b/t/t4255-am-submodule.sh @@ -2,6 +2,7 @@ test_description='git am handling submodules' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh index cb67bac1c4..86bee33160 100755 --- a/t/t5150-request-pull.sh +++ b/t/t5150-request-pull.sh @@ -5,6 +5,7 @@ test_description='Test workflows involving pull request.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh if ! test_have_prereq PERL diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 61e2be2903..4ad023c846 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -3,9 +3,9 @@ # Copyright (c) 2005 Junio C Hamano # -test_description='git pack-object +test_description='git pack-object' -' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5305-include-tag.sh b/t/t5305-include-tag.sh index 44bd9ef45f..dc8fe55c82 100755 --- a/t/t5305-include-tag.sh +++ b/t/t5305-include-tag.sh @@ -4,6 +4,7 @@ test_description='git pack-object --include-tag' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh TRASH=$(pwd) diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh index a2b4442660..2916c07e3c 100755 --- a/t/t5318-commit-graph.sh +++ b/t/t5318-commit-graph.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='commit graph' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-chunk.sh diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index 10d2a6bf92..ace5ac3b61 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -1027,6 +1027,61 @@ test_expect_success 'repack --batch-size=<large> repacks everything' ' ) ' +test_expect_success 'repack/expire loop' ' + git init repack-expire && + test_when_finished "rm -fr repack-expire" && + ( + cd repack-expire && + + test_commit_bulk 5 && + + # Create three overlapping pack-files + git rev-list --objects HEAD~3 >in-1 && + git rev-list --objects HEAD~4..HEAD~2 >in-2 && + git rev-list --objects HEAD~3..HEAD >in-3 && + + # Create disconnected blobs + obj1=$(git hash-object -w in-1) && + obj2=$(git hash-object -w in-2) && + obj3=$(git hash-object -w in-3) && + + echo $obj2 >>in-2 && + echo $obj3 >>in-3 && + + for i in $(test_seq 3) + do + git pack-objects .git/objects/pack/test-$i <in-$i \ + || return 1 + done && + + rm -fr .git/objects/pack/pack-* && + git multi-pack-index write && + + for i in $(test_seq 3) + do + for file in $(ls .git/objects/pack/test-$i*) + do + test-tool chmtime =+$((3600*$i-25000)) $file || return 1 + done || return 1 + done && + + pack1=$(ls .git/objects/pack/test-1-*.pack) && + pack2=$(ls .git/objects/pack/test-2-*.pack) && + pack3=$(ls .git/objects/pack/test-3-*.pack) && + + # Prevent test-1 from being rewritten. + touch "${pack1%.pack}.keep" && + + # This repack-expire loop should repack all non-kept packs + # into a new pack and then delete the old packs. + git multi-pack-index repack && + git multi-pack-index expire && + + test_path_is_missing $pack3 && + test_path_is_missing $pack2 + ) +' + test_expect_success 'load reverse index when missing .idx, .pack' ' git init repo && test_when_finished "rm -fr repo" && diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh index 281266f788..77e91547ea 100755 --- a/t/t5324-split-commit-graph.sh +++ b/t/t5324-split-commit-graph.sh @@ -13,7 +13,8 @@ test_expect_success 'setup repo' ' git init && git config core.commitGraph true && git config gc.writeCommitGraph false && - infodir=".git/objects/info" && + objdir=".git/objects" && + infodir="$objdir/info" && graphdir="$infodir/commit-graphs" && test_oid_cache <<-EOM shallow sha1:2132 @@ -718,4 +719,27 @@ test_expect_success 'write generation data chunk when commit-graph chain is repl ) ' +test_expect_success 'temporary graph layer is discarded upon failure' ' + git init layer-discard && + ( + cd layer-discard && + + test_commit A && + test_commit B && + + # Intentionally remove commit "A" from the object store + # so that the commit-graph machinery fails to parse the + # parents of "B". + # + # This takes place after the commit-graph machinery has + # initialized a new temporary file to store the contents + # of the new graph layer, so will allow us to ensure + # that the temporary file is discarded upon failure. + rm $objdir/$(test_oid_to_path $(git rev-parse HEAD^)) && + + test_must_fail git commit-graph write --reachable --split && + test_dir_is_empty $graphdir + ) +' + test_done diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh index cc7220b6c0..916da389b6 100755 --- a/t/t5326-multi-pack-bitmaps.sh +++ b/t/t5326-multi-pack-bitmaps.sh @@ -551,4 +551,34 @@ do ' done +test_expect_success 'remove one packfile between MIDX bitmap writes' ' + git init remove-pack-between-writes && + ( + cd remove-pack-between-writes && + + test_commit A && + test_commit B && + test_commit C && + + # Create packs with the prefix "pack-A", "pack-B", + # "pack-C" to impose a lexicographic order on these + # packs so the pack being removed is always from the + # middle. + packdir=.git/objects/pack && + A="$(echo A | git pack-objects $packdir/pack-A --revs)" && + B="$(echo B | git pack-objects $packdir/pack-B --revs)" && + C="$(echo C | git pack-objects $packdir/pack-C --revs)" && + + git multi-pack-index write --bitmap && + + cat >in <<-EOF && + pack-A-$A.idx + pack-C-$C.idx + EOF + git multi-pack-index write --bitmap --stdin-packs <in && + + git rev-list --test-bitmap HEAD + ) +' + test_done diff --git a/t/t5332-multi-pack-reuse.sh b/t/t5332-multi-pack-reuse.sh index 3c20738bce..ed823f37bc 100755 --- a/t/t5332-multi-pack-reuse.sh +++ b/t/t5332-multi-pack-reuse.sh @@ -204,4 +204,30 @@ test_expect_success 'omit delta from uninteresting base (cross pack)' ' test_pack_objects_reused_all $(($objects_nr - 1)) $packs_nr ' +test_expect_success 'non-omitted delta in MIDX preferred pack' ' + test_config pack.allowPackReuse single && + + cat >p1.objects <<-EOF && + $(git rev-parse $base) + ^$(git rev-parse $delta^) + EOF + cat >p2.objects <<-EOF && + $(git rev-parse F) + EOF + + p1="$(git pack-objects --revs $packdir/pack <p1.objects)" && + p2="$(git pack-objects --revs $packdir/pack <p2.objects)" && + + cat >in <<-EOF && + pack-$p1.idx + pack-$p2.idx + EOF + git multi-pack-index write --bitmap --stdin-packs \ + --preferred-pack=pack-$p1.pack <in && + + git show-index <$packdir/pack-$p1.idx >expect && + + test_pack_objects_reused_all $(wc -l <expect) 1 +' + test_done diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh new file mode 100755 index 0000000000..f052f395a7 --- /dev/null +++ b/t/t5333-pseudo-merge-bitmaps.sh @@ -0,0 +1,393 @@ +#!/bin/sh + +test_description='pseudo-merge bitmaps' + +GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 + +. ./test-lib.sh + +test_pseudo_merges () { + test-tool bitmap dump-pseudo-merges +} + +test_pseudo_merge_commits () { + test-tool bitmap dump-pseudo-merge-commits "$1" +} + +test_pseudo_merges_satisfied () { + test_trace2_data bitmap pseudo_merges_satisfied "$1" +} + +test_pseudo_merges_cascades () { + test_trace2_data bitmap pseudo_merges_cascades "$1" +} + +test_pseudo_merges_reused () { + test_trace2_data pack-bitmap-write building_bitmaps_pseudo_merge_reused "$1" +} + +tag_everything () { + git rev-list --all --no-object-names >in && + perl -lne ' + print "create refs/tags/" . $. . " " . $1 if /([0-9a-f]+)/ + ' <in | git update-ref --stdin +} + +test_expect_success 'setup' ' + test_commit_bulk 512 && + tag_everything +' + +test_expect_success 'bitmap traversal without pseudo-merges' ' + git repack -adb && + + git rev-list --count --all --objects >expect && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + + test_pseudo_merges_satisfied 0 <trace2.txt && + test_pseudo_merges_cascades 0 <trace2.txt && + test_pseudo_merges >merges && + test_must_be_empty merges && + test_cmp expect actual +' + +test_expect_success 'pseudo-merges accurately represent their objects' ' + test_config bitmapPseudoMerge.test.pattern "refs/tags/" && + test_config bitmapPseudoMerge.test.maxMerges 8 && + test_config bitmapPseudoMerge.test.stableThreshold never && + + git repack -adb && + + test_pseudo_merges >merges && + test_line_count = 8 merges && + + for i in $(test_seq 0 $(($(wc -l <merges)-1))) + do + test-tool bitmap dump-pseudo-merge-commits $i >commits && + + git rev-list --objects --no-object-names --stdin <commits >expect.raw && + test-tool bitmap dump-pseudo-merge-objects $i >actual.raw && + + sort -u <expect.raw >expect && + sort -u <actual.raw >actual && + + test_cmp expect actual || return 1 + done +' + +test_expect_success 'bitmap traversal with pseudo-merges' ' + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + git rev-list --count --all --objects >expect && + + test_pseudo_merges_satisfied 8 <trace2.txt && + test_pseudo_merges_cascades 1 <trace2.txt && + test_cmp expect actual +' + +test_expect_success 'stale bitmap traversal with pseudo-merges' ' + test_commit other && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + git rev-list --count --all --objects >expect && + + test_pseudo_merges_satisfied 8 <trace2.txt && + test_pseudo_merges_cascades 1 <trace2.txt && + test_cmp expect actual +' + +test_expect_success 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' ' + test_config bitmapPseudoMerge.test.pattern "refs/tags/" && + test_config bitmapPseudoMerge.test.maxMerges 1 && + test_config bitmapPseudoMerge.test.stableThreshold never && + + commits_nr=$(git rev-list --all --count) && + + for rate in 1.0 0.5 0.25 + do + git -c bitmapPseudoMerge.test.sampleRate=$rate repack -adb && + + test_pseudo_merges >merges && + test_line_count = 1 merges && + test_pseudo_merge_commits 0 >commits && + + test-tool bitmap list-commits >bitmaps && + bitmaps_nr="$(wc -l <bitmaps)" && + + perl -MPOSIX -e "print ceil(\$ARGV[0]*(\$ARGV[1]-\$ARGV[2]))" \ + "$rate" "$commits_nr" "$bitmaps_nr" >expect && + + test $(cat expect) -eq $(wc -l <commits) || return 1 + done +' + +test_expect_success 'bitmapPseudoMerge.threshold excludes newer commits' ' + git init pseudo-merge-threshold && + ( + cd pseudo-merge-threshold && + + new="1672549200" && # 2023-01-01 + old="1641013200" && # 2022-01-01 + + GIT_COMMITTER_DATE="$new +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --message="new" --notick 128 && + + GIT_COMMITTER_DATE="$old +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --message="old" --notick 128 && + + tag_everything && + + git \ + -c bitmapPseudoMerge.test.pattern="refs/tags/" \ + -c bitmapPseudoMerge.test.maxMerges=1 \ + -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \ + -c bitmapPseudoMerge.test.stableThreshold=never \ + repack -adb && + + test_pseudo_merges >merges && + test_line_count = 1 merges && + + test_pseudo_merge_commits 0 >oids && + git cat-file --batch <oids >commits && + + test $(wc -l <oids) = $(grep -c "^committer.*$old +0000$" commits) + ) +' + +test_expect_success 'bitmapPseudoMerge.stableThreshold creates stable groups' ' + ( + cd pseudo-merge-threshold && + + new="1672549200" && # 2023-01-01 + mid="1654059600" && # 2022-06-01 + old="1641013200" && # 2022-01-01 + + GIT_COMMITTER_DATE="$mid +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --message="mid" --notick 128 && + + git for-each-ref --format="delete %(refname)" refs/tags >in && + git update-ref --stdin <in && + + tag_everything && + + git \ + -c bitmapPseudoMerge.test.pattern="refs/tags/" \ + -c bitmapPseudoMerge.test.maxMerges=1 \ + -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \ + -c bitmapPseudoMerge.test.stableThreshold=$(($mid - 1)) \ + -c bitmapPseudoMerge.test.stableSize=10 \ + repack -adb && + + test_pseudo_merges >merges && + merges_nr="$(wc -l <merges)" && + + for i in $(test_seq $(($merges_nr - 1))) + do + test_pseudo_merge_commits 0 >oids && + git cat-file --batch <oids >commits && + + expect="$(grep -c "^committer.*$old +0000$" commits)" && + actual="$(wc -l <oids)" && + + test $expect = $actual || return 1 + done && + + test_pseudo_merge_commits $(($merges_nr - 1)) >oids && + git cat-file --batch <oids >commits && + test $(wc -l <oids) = $(grep -c "^committer.*$mid +0000$" commits) + ) +' + +test_expect_success 'out of order thresholds are rejected' ' + test_must_fail git \ + -c bitmapPseudoMerge.test.pattern="refs/*" \ + -c bitmapPseudoMerge.test.threshold=1.month.ago \ + -c bitmapPseudoMerge.test.stableThreshold=1.week.ago \ + repack -adb 2>err && + + cat >expect <<-EOF && + fatal: pseudo-merge group ${SQ}test${SQ} has unstable threshold before stable one + EOF + + test_cmp expect err +' + +test_expect_success 'pseudo-merge pattern with capture groups' ' + git init pseudo-merge-captures && + ( + cd pseudo-merge-captures && + + test_commit_bulk 128 && + tag_everything && + + for r in $(test_seq 8) + do + test_commit_bulk 16 && + + git rev-list HEAD~16.. >in && + + perl -lne "print \"create refs/remotes/$r/tags/\$. \$_\"" <in | + git update-ref --stdin || return 1 + done && + + git \ + -c bitmapPseudoMerge.tags.pattern="refs/remotes/([0-9]+)/tags/" \ + -c bitmapPseudoMerge.tags.maxMerges=1 \ + repack -adb && + + git for-each-ref --format="%(objectname) %(refname)" >refs && + + test_pseudo_merges >merges && + for m in $(test_seq 0 $(($(wc -l <merges) - 1))) + do + test_pseudo_merge_commits $m >oids && + grep -f oids refs | + perl -lne "print \$1 if /refs\/remotes\/([0-9]+)/" | + sort -u || return 1 + done >remotes && + + test $(wc -l <remotes) -eq $(sort -u <remotes | wc -l) + ) +' + +test_expect_success 'pseudo-merge overlap setup' ' + git init pseudo-merge-overlap && + ( + cd pseudo-merge-overlap && + + test_commit_bulk 256 && + tag_everything && + + git \ + -c bitmapPseudoMerge.all.pattern="refs/" \ + -c bitmapPseudoMerge.all.maxMerges=1 \ + -c bitmapPseudoMerge.all.stableThreshold=never \ + -c bitmapPseudoMerge.tags.pattern="refs/tags/" \ + -c bitmapPseudoMerge.tags.maxMerges=1 \ + -c bitmapPseudoMerge.tags.stableThreshold=never \ + repack -adb + ) +' + +test_expect_success 'pseudo-merge overlap generates overlapping groups' ' + ( + cd pseudo-merge-overlap && + + test_pseudo_merges >merges && + test_line_count = 2 merges && + + test_pseudo_merge_commits 0 >commits-0.raw && + test_pseudo_merge_commits 1 >commits-1.raw && + + sort commits-0.raw >commits-0 && + sort commits-1.raw >commits-1 && + + comm -12 commits-0 commits-1 >overlap && + + test_line_count -gt 0 overlap + ) +' + +test_expect_success 'pseudo-merge overlap traversal' ' + ( + cd pseudo-merge-overlap && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + git rev-list --count --all --objects >expect && + + test_pseudo_merges_satisfied 2 <trace2.txt && + test_pseudo_merges_cascades 1 <trace2.txt && + test_cmp expect actual + ) +' + +test_expect_success 'pseudo-merge overlap stale traversal' ' + ( + cd pseudo-merge-overlap && + + test_commit other && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt \ + git rev-list --count --all --objects --use-bitmap-index >actual && + git rev-list --count --all --objects >expect && + + test_pseudo_merges_satisfied 2 <trace2.txt && + test_pseudo_merges_cascades 1 <trace2.txt && + test_cmp expect actual + ) +' + +test_expect_success 'pseudo-merge reuse' ' + git init pseudo-merge-reuse && + ( + cd pseudo-merge-reuse && + + stable="1641013200" && # 2022-01-01 + unstable="1672549200" && # 2023-01-01 + + GIT_COMMITTER_DATE="$stable +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --notick 128 && + GIT_COMMITTER_DATE="$unstable +0000" && + export GIT_COMMITTER_DATE && + test_commit_bulk --notick 128 && + + tag_everything && + + git \ + -c bitmapPseudoMerge.test.pattern="refs/tags/" \ + -c bitmapPseudoMerge.test.maxMerges=1 \ + -c bitmapPseudoMerge.test.threshold=now \ + -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \ + -c bitmapPseudoMerge.test.stableSize=512 \ + repack -adb && + + test_pseudo_merges >merges && + test_line_count = 2 merges && + + test_pseudo_merge_commits 0 >stable-oids.before && + test_pseudo_merge_commits 1 >unstable-oids.before && + + : >trace2.txt && + GIT_TRACE2_EVENT=$PWD/trace2.txt git \ + -c bitmapPseudoMerge.test.pattern="refs/tags/" \ + -c bitmapPseudoMerge.test.maxMerges=2 \ + -c bitmapPseudoMerge.test.threshold=now \ + -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \ + -c bitmapPseudoMerge.test.stableSize=512 \ + repack -adb && + + test_pseudo_merges_reused 1 <trace2.txt && + + test_pseudo_merges >merges && + test_line_count = 3 merges && + + test_pseudo_merge_commits 0 >stable-oids.after && + for i in 1 2 + do + test_pseudo_merge_commits $i || return 1 + done >unstable-oids.after && + + sort -u <stable-oids.before >expect && + sort -u <stable-oids.after >actual && + test_cmp expect actual && + + sort -u <unstable-oids.before >expect && + sort -u <unstable-oids.after >actual && + test_cmp expect actual + ) +' + +test_done diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index ad7f8c6f00..e99e728236 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -7,6 +7,7 @@ test_description='Test the post-rewrite hook.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 1bc15a3f08..585ea0ee16 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -993,6 +993,16 @@ test_expect_success 'ensure bogus fetch.negotiationAlgorithm yields error' ' fetch origin server_has both_have_2 ' +test_expect_success 'fetch-pack with fsckObjects and keep-file does not segfault' ' + rm -rf server client && + test_create_repo server && + test_commit -C server one && + + test_create_repo client && + git -c fetch.fsckObjects=true \ + -C client fetch-pack -k -k ../server HEAD +' + test_expect_success 'filtering by size' ' rm -rf server client && test_create_repo server && @@ -1046,7 +1056,7 @@ fetch_filter_blob_limit_zero () { # Ensure that commit is fetched, but blob is not commit=$(git -C "$SERVER" rev-parse two) && - blob=$(git hash-object server/two.t) && + blob=$(git hash-object "$SERVER/two.t") && git -C client rev-list --objects --missing=allow-any "$commit" >oids && grep "$commit" oids && ! grep "$blob" oids diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 7789ff12c4..08424e878e 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -1492,4 +1492,40 @@ test_expect_success 'refs/remotes/* <src> refspec and unqualified <dst> DWIM and ) ' +test_expect_success 'empty config clears remote.*.url list' ' + test_when_finished "git config --remove-section remote.multi" && + git config --add remote.multi.url wrong-one && + git config --add remote.multi.url wrong-two && + git -c remote.multi.url= \ + -c remote.multi.url=right-one \ + -c remote.multi.url=right-two \ + remote show -n multi >actual.raw && + grep URL actual.raw >actual && + cat >expect <<-\EOF && + Fetch URL: right-one + Push URL: right-one + Push URL: right-two + EOF + test_cmp expect actual +' + +test_expect_success 'empty config clears remote.*.pushurl list' ' + test_when_finished "git config --remove-section remote.multi" && + git config --add remote.multi.url right && + git config --add remote.multi.url will-be-ignored && + git config --add remote.multi.pushurl wrong-push-one && + git config --add remote.multi.pushurl wrong-push-two && + git -c remote.multi.pushurl= \ + -c remote.multi.pushurl=right-push-one \ + -c remote.multi.pushurl=right-push-two \ + remote show -n multi >actual.raw && + grep URL actual.raw >actual && + cat >expect <<-\EOF && + Fetch URL: right + Push URL: right-push-one + Push URL: right-push-two + EOF + test_cmp expect actual +' + test_done diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 5dbe107ce8..d64b40e408 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -5,6 +5,7 @@ test_description='git ls-remote' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh generate_references () { @@ -47,6 +48,7 @@ test_expect_success setup ' git show-ref -d >refs && sed -e "s/ / /" refs >>expected.all && + grep refs/heads/ expected.all >expected.branches && git remote add self "$(pwd)/.git" && git remote add self2 "." ' @@ -71,6 +73,27 @@ test_expect_success 'ls-remote self' ' test_cmp expected.all actual ' +test_expect_success 'ls-remote --branches self' ' + git ls-remote --branches self >actual && + test_cmp expected.branches actual && + git ls-remote -b self >actual && + test_cmp expected.branches actual +' + +test_expect_success 'ls-remote -h is deprecated w/o warning' ' + git ls-remote -h self >actual 2>warning && + test_cmp expected.branches actual && + test_grep ! deprecated warning +' + +test_expect_success 'ls-remote --heads is deprecated and hidden w/o warning' ' + test_expect_code 129 git ls-remote -h >short-help && + test_grep ! -e --head short-help && + git ls-remote --heads self >actual 2>warning && + test_cmp expected.branches actual && + test_grep ! deprecated warning +' + test_expect_success 'ls-remote --sort="version:refname" --tags self' ' generate_references \ refs/tags/mark \ @@ -275,7 +298,7 @@ test_expect_success 'ls-remote with filtered symref (refname)' ' test_cmp expect actual ' -test_expect_success 'ls-remote with filtered symref (--heads)' ' +test_expect_success 'ls-remote with filtered symref (--branches)' ' git symbolic-ref refs/heads/foo refs/tags/mark && cat >expect.v2 <<-EOF && ref: refs/tags/mark refs/heads/foo @@ -283,9 +306,9 @@ test_expect_success 'ls-remote with filtered symref (--heads)' ' $rev refs/heads/main EOF grep -v "^ref: refs/tags/" <expect.v2 >expect.v0 && - git -c protocol.version=0 ls-remote --symref --heads . >actual.v0 && + git -c protocol.version=0 ls-remote --symref --branches . >actual.v0 && test_cmp expect.v0 actual.v0 && - git -c protocol.version=2 ls-remote --symref --heads . >actual.v2 && + git -c protocol.version=2 ls-remote --symref --branches . >actual.v2 && test_cmp expect.v2 actual.v2 ' @@ -335,9 +358,9 @@ test_expect_success 'ls-remote patterns work with all protocol versions' ' test_expect_success 'ls-remote prefixes work with all protocol versions' ' git for-each-ref --format="%(objectname) %(refname)" \ refs/heads/ refs/tags/ >expect && - git -c protocol.version=0 ls-remote --heads --tags . >actual.v0 && + git -c protocol.version=0 ls-remote --branches --tags . >actual.v0 && test_cmp expect actual.v0 && - git -c protocol.version=2 ls-remote --heads --tags . >actual.v2 && + git -c protocol.version=2 ls-remote --branches --tags . >actual.v2 && test_cmp expect actual.v2 ' @@ -380,4 +403,17 @@ test_expect_success 'v0 clients can handle multiple symrefs' ' test_cmp expect actual ' +test_expect_success 'helper with refspec capability fails gracefully' ' + mkdir test-bin && + write_script test-bin/git-remote-foo <<-EOF && + echo import + echo refspec ${SQ}*:*${SQ} + EOF + ( + PATH="$PWD/test-bin:$PATH" && + export PATH && + test_must_fail nongit git ls-remote foo::bar + ) +' + test_done diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh index 25772c85c5..579872c258 100755 --- a/t/t5514-fetch-multiple.sh +++ b/t/t5514-fetch-multiple.sh @@ -5,6 +5,7 @@ test_description='fetch --all works correctly' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh setup_repository () { diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 2e7c0e1648..9d693eb57f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -230,6 +230,16 @@ test_expect_success 'push with negotiation proceeds anyway even if negotiation f test_grep "push negotiation failed" err ' +test_expect_success 'push deletion with negotiation' ' + mk_empty testrepo && + git push testrepo $the_first_commit:refs/heads/master && + git -c push.negotiate=1 push testrepo \ + :master $the_first_commit:refs/heads/next 2>errors-2 && + test_grep ! "negotiate-only needs one or " errors-2 && + git -c push.negotiate=1 push testrepo :next 2>errors-1 && + test_grep ! "negotiate-only needs one or " errors-1 +' + test_expect_success 'push with negotiation does not attempt to fetch submodules' ' mk_empty submodule_upstream && test_commit -C submodule_upstream submodule_commit && diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 47534f1062..1098cbd0a1 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -5,6 +5,7 @@ test_description='pulling into void' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh modify () { diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh index 14f7eced9a..bc2bada34c 100755 --- a/t/t5528-push-default.sh +++ b/t/t5528-push-default.sh @@ -4,6 +4,7 @@ test_description='check various push.default settings' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup bare remotes' ' diff --git a/t/t5529-push-errors.sh b/t/t5529-push-errors.sh index 0247137cb3..17d7257892 100755 --- a/t/t5529-push-errors.sh +++ b/t/t5529-push-errors.sh @@ -2,6 +2,9 @@ test_description='detect some push errors early (before contacting remote)' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh @@ -38,6 +41,20 @@ test_expect_success 'detect missing sha1 expressions early' ' test_cmp expect rp-ran ' +# We use an existing local_ref, since it follows a different flow in +# 'builtin/push.c:set_refspecs()' and we want to test that regression. +test_expect_success 'detect empty remote with existing local ref' ' + test_must_fail git push "" main 2> stderr && + grep "fatal: bad repository ${SQ}${SQ}" stderr +' + +# While similar to the previous test, here we want to ensure that +# even targeted refspecs are handled. +test_expect_success 'detect empty remote with targeted refspec' ' + test_must_fail git push "" HEAD:refs/heads/main 2> stderr && + grep "fatal: bad repository ${SQ}${SQ}" stderr +' + test_expect_success 'detect ambiguous refs early' ' git branch foo && git tag foo && diff --git a/t/t5535-fetch-push-symref.sh b/t/t5535-fetch-push-symref.sh index e8f6d233ff..7122af7fdb 100755 --- a/t/t5535-fetch-push-symref.sh +++ b/t/t5535-fetch-push-symref.sh @@ -2,6 +2,7 @@ test_description='avoiding conflicting update through symref aliasing' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh index 04b47ad84a..479d103469 100755 --- a/t/t5543-atomic-push.sh +++ b/t/t5543-atomic-push.sh @@ -5,6 +5,7 @@ test_description='pushing to a repository using the atomic push option' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh mk_repo_pair () { diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh index 5f16cbc58d..ea8e48f627 100755 --- a/t/t5550-http-fetch-dumb.sh +++ b/t/t5550-http-fetch-dumb.sh @@ -25,6 +25,12 @@ test_expect_success 'setup repository' ' git commit -m two ' +test_expect_success 'packfile without repository does not crash' ' + echo "fatal: not a git repository" >expect && + test_must_fail nongit git http-fetch --packfile=abc 2>err && + test_cmp expect err +' + setup_post_update_server_info_hook () { test_hook --setup -C "$1" post-update <<-\EOF && exec git update-server-info diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index a623a1058c..7b5ab0eae1 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -643,7 +643,6 @@ test_expect_success 'clone empty SHA-256 repository with protocol v0' ' test_expect_success 'passing hostname resolution information works' ' BOGUS_HOST=gitbogusexamplehost.invalid && BOGUS_HTTPD_URL=$HTTPD_PROTO://$BOGUS_HOST:$LIB_HTTPD_PORT && - test_must_fail git ls-remote "$BOGUS_HTTPD_URL/smart/repo.git" >/dev/null && git -c "http.curloptResolve=$BOGUS_HOST:$LIB_HTTPD_PORT:127.0.0.1" ls-remote "$BOGUS_HTTPD_URL/smart/repo.git" >/dev/null ' diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh index 48050162c2..70e3376d31 100755 --- a/t/t5553-set-upstream.sh +++ b/t/t5553-set-upstream.sh @@ -73,10 +73,10 @@ test_expect_success 'fetch --set-upstream main:other does not set the branch oth check_config_missing other2 ' -test_expect_success 'fetch --set-upstream http://nosuchdomain.example.com fails with invalid url' ' +test_expect_success 'fetch --set-upstream ./does-not-exist fails with invalid url' ' # main explicitly not cleared, we check that it is not touched from previous value clear_config other other2 && - test_must_fail git fetch --set-upstream http://nosuchdomain.example.com && + test_must_fail git fetch --set-upstream ./does-not-exist && check_config main upstream refs/heads/other && check_config_missing other && check_config_missing other2 @@ -143,10 +143,10 @@ test_expect_success 'pull --set-upstream upstream tag does not set the tag' ' check_config_missing three ' -test_expect_success 'pull --set-upstream http://nosuchdomain.example.com fails with invalid url' ' +test_expect_success 'pull --set-upstream ./does-not-exist fails with invalid url' ' # main explicitly not cleared, we check that it is not touched from previous value clear_config other other2 three && - test_must_fail git pull --set-upstream http://nosuchdomain.example.com && + test_must_fail git pull --set-upstream ./does-not-exist && check_config main upstream refs/heads/other && check_config_missing other && check_config_missing other2 && diff --git a/t/t5558-clone-bundle-uri.sh b/t/t5558-clone-bundle-uri.sh index 1ca5f745e7..cd05321e17 100755 --- a/t/t5558-clone-bundle-uri.sh +++ b/t/t5558-clone-bundle-uri.sh @@ -3,6 +3,7 @@ test_description='test fetching bundles with --bundle-uri' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-bundle.sh test_expect_success 'fail to clone from non-existent file' ' test_when_finished rm -rf test && @@ -19,10 +20,39 @@ test_expect_success 'fail to clone from non-bundle file' ' test_expect_success 'create bundle' ' git init clone-from && - git -C clone-from checkout -b topic && - test_commit -C clone-from A && - test_commit -C clone-from B && - git -C clone-from bundle create B.bundle topic + ( + cd clone-from && + git checkout -b topic && + + test_commit A && + git bundle create A.bundle topic && + + test_commit B && + git bundle create B.bundle topic && + + # Create a bundle with reference pointing to non-existent object. + commit_a=$(git rev-parse A) && + commit_b=$(git rev-parse B) && + sed -e "/^$/q" -e "s/$commit_a /$commit_b /" \ + <A.bundle >bad-header.bundle && + convert_bundle_to_pack \ + <A.bundle >>bad-header.bundle && + + tree_b=$(git rev-parse B^{tree}) && + cat >data <<-EOF && + tree $tree_b + parent $commit_b + author A U Thor + committer A U Thor + + commit: this is a commit with bad emails + + EOF + bad_commit=$(git hash-object --literally -t commit -w --stdin <data) && + git branch bad $bad_commit && + git bundle create bad-object.bundle bad && + git update-ref -d refs/heads/bad + ) ' test_expect_success 'clone with path bundle' ' @@ -33,6 +63,33 @@ test_expect_success 'clone with path bundle' ' test_cmp expect actual ' +test_expect_success 'clone with bundle that has bad header' ' + # Write bundle ref fails, but clone can still proceed. + git clone --bundle-uri="clone-from/bad-header.bundle" \ + clone-from clone-bad-header 2>err && + commit_b=$(git -C clone-from rev-parse B) && + test_grep "trying to write ref '\''refs/bundles/topic'\'' with nonexistent object $commit_b" err && + git -C clone-bad-header for-each-ref --format="%(refname)" >refs && + test_grep ! "refs/bundles/" refs +' + +test_expect_success 'clone with bundle that has bad object' ' + # Unbundle succeeds if no fsckObjects configured. + git clone --bundle-uri="clone-from/bad-object.bundle" \ + clone-from clone-bad-object-no-fsck && + git -C clone-bad-object-no-fsck for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + test_write_lines refs/bundles/bad >expect && + test_cmp expect actual && + + # Unbundle fails with fsckObjects set true, but clone can still proceed. + git -c fetch.fsckObjects=true clone --bundle-uri="clone-from/bad-object.bundle" \ + clone-from clone-bad-object-fsck 2>err && + test_grep "missingEmail" err && + git -C clone-bad-object-fsck for-each-ref --format="%(refname)" >refs && + test_grep ! "refs/bundles/" refs +' + test_expect_success 'clone with path bundle and non-default hash' ' test_when_finished "rm -rf clone-path-non-default-hash" && GIT_DEFAULT_HASH=sha256 git clone --bundle-uri="clone-from/B.bundle" \ @@ -259,6 +316,128 @@ test_expect_success 'clone bundle list (file, any mode, all failures)' ' ! grep "refs/bundles/" refs ' +test_expect_success 'negotiation: bundle with part of wanted commits' ' + test_when_finished "rm -f trace*.txt" && + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --bundle-uri="clone-from/A.bundle" \ + clone-from nego-bundle-part && + git -C nego-bundle-part for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + test_write_lines refs/bundles/topic >expect && + test_cmp expect actual && + # Ensure that refs/bundles/topic are sent as "have". + tip=$(git -C clone-from rev-parse A) && + test_grep "clone> have $tip" trace-packet.txt +' + +test_expect_success 'negotiation: bundle with all wanted commits' ' + test_when_finished "rm -f trace*.txt" && + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --single-branch --branch=topic --no-tags \ + --bundle-uri="clone-from/B.bundle" \ + clone-from nego-bundle-all && + git -C nego-bundle-all for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + test_write_lines refs/bundles/topic >expect && + test_cmp expect actual && + # We already have all needed commits so no "want" needed. + test_grep ! "clone> want " trace-packet.txt +' + +test_expect_success 'negotiation: bundle list (no heuristic)' ' + test_when_finished "rm -f trace*.txt" && + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + + [bundle "bundle-2"] + uri = file://$(pwd)/clone-from/bundle-2.bundle + EOF + + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from nego-bundle-list-no-heuristic && + + git -C nego-bundle-list-no-heuristic for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + EOF + test_cmp expect actual && + tip=$(git -C nego-bundle-list-no-heuristic rev-parse refs/bundles/left) && + test_grep "clone> have $tip" trace-packet.txt +' + +test_expect_success 'negotiation: bundle list (creationToken)' ' + test_when_finished "rm -f trace*.txt" && + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = file://$(pwd)/clone-from/bundle-2.bundle + creationToken = 2 + EOF + + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from nego-bundle-list-heuristic && + + git -C nego-bundle-list-heuristic for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + EOF + test_cmp expect actual && + tip=$(git -C nego-bundle-list-heuristic rev-parse refs/bundles/left) && + test_grep "clone> have $tip" trace-packet.txt +' + +test_expect_success 'negotiation: bundle list with all wanted commits' ' + test_when_finished "rm -f trace*.txt" && + cat >bundle-list <<-EOF && + [bundle] + version = 1 + mode = all + heuristic = creationToken + + [bundle "bundle-1"] + uri = file://$(pwd)/clone-from/bundle-1.bundle + creationToken = 1 + + [bundle "bundle-2"] + uri = file://$(pwd)/clone-from/bundle-2.bundle + creationToken = 2 + EOF + + GIT_TRACE_PACKET="$(pwd)/trace-packet.txt" \ + git clone --no-local --single-branch --branch=left --no-tags \ + --bundle-uri="file://$(pwd)/bundle-list" \ + clone-from nego-bundle-list-all && + + git -C nego-bundle-list-all for-each-ref --format="%(refname)" >refs && + grep "refs/bundles/" refs >actual && + cat >expect <<-\EOF && + refs/bundles/base + refs/bundles/left + EOF + test_cmp expect actual && + # We already have all needed commits so no "want" needed. + test_grep ! "clone> want " trace-packet.txt +' + ######################################################################### # HTTP tests begin here diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh index 4af796de67..ba03f6a09f 100755 --- a/t/t5563-simple-http-auth.sh +++ b/t/t5563-simple-http-auth.sh @@ -178,6 +178,122 @@ test_expect_success 'access using basic auth invalid credentials' ' EOF ' +test_expect_success 'access using basic proactive auth' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=200 + id=default status=403 + EOF + + test_config_global credential.helper test-helper && + test_config_global http.proactiveAuth basic && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + wwwauth[]=Basic + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using auto proactive auth with basic default' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + username=alice + password=secret-passwd + EOF + + # Basic base64(alice:secret-passwd) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Basic YWxpY2U6c2VjcmV0LXBhc3N3ZA== + EOF + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=200 + id=default status=403 + EOF + + test_config_global credential.helper test-helper && + test_config_global http.proactiveAuth auto && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + EOF + + expect_credential_query store <<-EOF + protocol=http + host=$HTTPD_DEST + username=alice + password=secret-passwd + EOF +' + +test_expect_success 'access using auto proactive auth with authtype from credential helper' ' + test_when_finished "per_test_cleanup" && + + set_credential_reply get <<-EOF && + capability[]=authtype + authtype=Bearer + credential=YS1naXQtdG9rZW4= + EOF + + # Basic base64(a-git-token) + cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF && + id=1 creds=Bearer YS1naXQtdG9rZW4= + EOF + + CHALLENGE="$HTTPD_ROOT_PATH/custom-auth.challenge" && + + cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF && + id=1 status=200 + id=default status=403 + EOF + + test_config_global credential.helper test-helper && + test_config_global http.proactiveAuth auto && + git ls-remote "$HTTPD_URL/custom_auth/repo.git" && + + expect_credential_query get <<-EOF && + capability[]=authtype + capability[]=state + protocol=http + host=$HTTPD_DEST + EOF + + expect_credential_query store <<-EOF + capability[]=authtype + authtype=Bearer + credential=YS1naXQtdG9rZW4= + protocol=http + host=$HTTPD_DEST + EOF +' + test_expect_success 'access using basic auth with extra challenges' ' test_when_finished "per_test_cleanup" && diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh index bb35b87071..4aef99bc28 100755 --- a/t/t5564-http-proxy.sh +++ b/t/t5564-http-proxy.sh @@ -39,4 +39,59 @@ test_expect_success 'clone can prompt for proxy password' ' expect_askpass pass proxuser ' +start_socks() { + mkfifo socks_output && + { + "$PERL_PATH" "$TEST_DIRECTORY/socks4-proxy.pl" "$1" >socks_output & + echo $! > "$TRASH_DIRECTORY/socks.pid" + } && + read line <socks_output && + test "$line" = ready +} + +# The %30 tests that the correct amount of percent-encoding is applied to the +# proxy string passed to curl. +test_lazy_prereq SOCKS_PROXY ' + test_have_prereq PERL && + start_socks "$TRASH_DIRECTORY/%30.sock" +' + +test_atexit ' + test ! -e "$TRASH_DIRECTORY/socks.pid" || + kill "$(cat "$TRASH_DIRECTORY/socks.pid")" +' + +# The below tests morally ought to be gated on a prerequisite that Git is +# linked with a libcurl that supports Unix socket paths for proxies (7.84 or +# later), but this is not easy to test right now. Instead, we || the tests with +# this function. +old_libcurl_error() { + grep -Fx "fatal: libcurl 7.84 or later is required to support paths in proxy URLs" "$1" +} + +test_expect_success SOCKS_PROXY 'clone via Unix socket' ' + test_when_finished "rm -rf clone" && + test_config_global http.proxy "socks4://localhost$PWD/%2530.sock" && { + { + GIT_TRACE_CURL=$PWD/trace git clone "$HTTPD_URL/smart/repo.git" clone 2>err && + grep -i "SOCKS4 request granted" trace + } || + old_libcurl_error err + } +' + +test_expect_success 'Unix socket requires socks*:' - <<\EOT + ! git clone -c http.proxy=localhost/path https://example.com/repo.git 2>err && { + grep -Fx "fatal: Invalid proxy URL 'localhost/path': only SOCKS proxies support paths" err || + old_libcurl_error err + } +EOT + +test_expect_success 'Unix socket requires localhost' - <<\EOT + ! git clone -c http.proxy=socks4://127.0.0.1/path https://example.com/repo.git 2>err && { + grep -Fx "fatal: Invalid proxy URL 'socks4://127.0.0.1/path': host must be localhost if a path is present" err || + old_libcurl_error err + } +EOT + test_done diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh index f9a9bf9503..c5f08b6799 100755 --- a/t/t5570-git-daemon.sh +++ b/t/t5570-git-daemon.sh @@ -4,6 +4,7 @@ test_description='test fetching over git protocol' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-git-daemon.sh diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index cc0b953f14..5d7ea147f1 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -46,6 +46,13 @@ test_expect_success 'output from clone' ' test $(grep Clon output | wc -l) = 1 ' +test_expect_success 'output from clone with core.abbrev does not crash' ' + rm -fr dst && + echo "Cloning into ${SQ}dst${SQ}..." >expect && + git -c core.abbrev=12 clone -n "file://$(pwd)/src" dst >actual 2>&1 && + test_cmp expect actual +' + test_expect_success 'clone does not keep pack' ' rm -fr dst && diff --git a/t/t5605-clone-local.sh b/t/t5605-clone-local.sh index a3055869bc..d9a320abd2 100755 --- a/t/t5605-clone-local.sh +++ b/t/t5605-clone-local.sh @@ -4,6 +4,7 @@ test_description='test local clone' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh repo_is_hardlinked() { @@ -163,7 +164,7 @@ test_expect_success REFFILES 'local clone from repo with corrupt refs fails grac echo a >corrupt/.git/refs/heads/topic && test_must_fail git clone corrupt working 2>err && - grep "has a null OID" err + grep "has neither a valid OID nor a target" err ' test_done diff --git a/t/t5607-clone-bundle.sh b/t/t5607-clone-bundle.sh index 0d1e92d996..7ceaa8194d 100755 --- a/t/t5607-clone-bundle.sh +++ b/t/t5607-clone-bundle.sh @@ -4,6 +4,7 @@ test_description='some bundle related tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' @@ -138,6 +139,41 @@ test_expect_success 'fetch SHA-1 from bundle' ' git fetch --no-tags foo/tip.bundle "$(cat hash)" ' +test_expect_success 'clone bundle with different fsckObjects configurations' ' + test_create_repo bundle-fsck && + ( + cd bundle-fsck && + test_commit A && + commit_a=$(git rev-parse A) && + tree_a=$(git rev-parse A^{tree}) && + cat >data <<-EOF && + tree $tree_a + parent $commit_a + author A U Thor + committer A U Thor + + commit: this is a commit with bad emails + + EOF + bad_commit=$(git hash-object --literally -t commit -w --stdin <data) && + git branch bad $bad_commit && + git bundle create bad.bundle bad + ) && + + git clone bundle-fsck/bad.bundle bundle-no-fsck && + + git -c fetch.fsckObjects=false -c transfer.fsckObjects=true \ + clone bundle-fsck/bad.bundle bundle-fetch-no-fsck && + + test_must_fail git -c fetch.fsckObjects=true \ + clone bundle-fsck/bad.bundle bundle-fetch-fsck 2>err && + test_grep "missingEmail" err && + + test_must_fail git -c transfer.fsckObjects=true \ + clone bundle-fsck/bad.bundle bundle-transfer-fsck 2>err && + test_grep "missingEmail" err +' + test_expect_success 'git bundle uses expected default format' ' git bundle create bundle HEAD^.. && cat >expect <<-EOF && diff --git a/t/t5612-clone-refspec.sh b/t/t5612-clone-refspec.sh index 3126cfd7e9..72762de977 100755 --- a/t/t5612-clone-refspec.sh +++ b/t/t5612-clone-refspec.sh @@ -4,6 +4,7 @@ test_description='test refspec written by clone-command' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t5801-remote-helpers.sh b/t/t5801-remote-helpers.sh index 4e0a77f985..20f43f7b7d 100755 --- a/t/t5801-remote-helpers.sh +++ b/t/t5801-remote-helpers.sh @@ -38,6 +38,29 @@ test_expect_success 'cloning from local repo' ' test_cmp server/file local/file ' +test_expect_success 'clone with remote.*.vcs config' ' + GIT_TRACE=$PWD/vcs-clone.trace \ + git clone --no-local -c remote.origin.vcs=testgit "$PWD/server" vcs-clone && + test_grep remote-testgit vcs-clone.trace +' + +test_expect_success 'fetch with configured remote.*.vcs' ' + git init vcs-fetch && + git -C vcs-fetch config remote.origin.vcs testgit && + git -C vcs-fetch config remote.origin.url "$PWD/server" && + GIT_TRACE=$PWD/vcs-fetch.trace \ + git -C vcs-fetch fetch origin && + test_grep remote-testgit vcs-fetch.trace +' + +test_expect_success 'vcs remote with no url' ' + NOURL_UPSTREAM=$PWD/server && + export NOURL_UPSTREAM && + git init vcs-nourl && + git -C vcs-nourl config remote.origin.vcs nourl && + git -C vcs-nourl fetch origin +' + test_expect_success 'create new commit on remote' ' (cd server && echo content >>file && diff --git a/t/t5801/git-remote-nourl b/t/t5801/git-remote-nourl new file mode 100755 index 0000000000..09be6013c5 --- /dev/null +++ b/t/t5801/git-remote-nourl @@ -0,0 +1,3 @@ +#!/bin/sh + +exec git-remote-testgit "$1" "$NOURL_UPSTREAM" diff --git a/t/t5801/git-remote-testgit b/t/t5801/git-remote-testgit index c5b10f5775..f8b476499f 100755 --- a/t/t5801/git-remote-testgit +++ b/t/t5801/git-remote-testgit @@ -26,7 +26,8 @@ then t_refspec="" fi -GIT_DIR="$url/.git" +unset $(git rev-parse --local-env-vars) +GIT_DIR=$(git -C "$url" rev-parse --absolute-git-dir) export GIT_DIR force= diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh index 6289a2e8b0..f6d17ee902 100755 --- a/t/t6000-rev-list-misc.sh +++ b/t/t6000-rev-list-misc.sh @@ -5,6 +5,7 @@ test_description='miscellaneous rev-list tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t6001-rev-list-graft.sh b/t/t6001-rev-list-graft.sh index 73a2465aa0..3553bbbfe7 100755 --- a/t/t6001-rev-list-graft.sh +++ b/t/t6001-rev-list-graft.sh @@ -5,6 +5,7 @@ test_description='Revision traversal vs grafts and path limiter' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh index 6f3e543977..2d337d7287 100755 --- a/t/t6007-rev-list-cherry-pick-file.sh +++ b/t/t6007-rev-list-cherry-pick-file.sh @@ -5,6 +5,7 @@ test_description='test git rev-list --cherry-pick -- file' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # A---B---D---F diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh index 44c726ea39..f96ea82e78 100755 --- a/t/t6010-merge-base.sh +++ b/t/t6010-merge-base.sh @@ -6,6 +6,7 @@ test_description='Merge base and parent list computation. ' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh M=1130000000 diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh index 39793cbbd6..4128269c1d 100755 --- a/t/t6013-rev-list-reverse-parents.sh +++ b/t/t6013-rev-list-reverse-parents.sh @@ -5,6 +5,7 @@ test_description='--reverse combines with --parents' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh diff --git a/t/t6017-rev-list-stdin.sh b/t/t6017-rev-list-stdin.sh index 4821b90e74..a0a40fe55c 100755 --- a/t/t6017-rev-list-stdin.sh +++ b/t/t6017-rev-list-stdin.sh @@ -8,6 +8,7 @@ test_description='log family learns --stdin' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check () { diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh index 3e6bcbf30c..fe75a06572 100755 --- a/t/t6020-bundle-misc.sh +++ b/t/t6020-bundle-misc.sh @@ -8,6 +8,7 @@ test_description='Test git-bundle' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-bundle.sh . "$TEST_DIRECTORY"/lib-terminal.sh diff --git a/t/t6112-rev-list-filters-objects.sh b/t/t6112-rev-list-filters-objects.sh index 43e1afd44c..0387f35a32 100755 --- a/t/t6112-rev-list-filters-objects.sh +++ b/t/t6112-rev-list-filters-objects.sh @@ -701,4 +701,16 @@ test_expect_success 'expand blob limit in protocol' ' grep "blob:limit=1024" trace ' +test_expect_success EXPENSIVE 'large sparse filter file ignored' ' + blob=$(dd if=/dev/zero bs=101M count=1 | + git hash-object -w --stdin) && + test_must_fail \ + git rev-list --all --objects --filter=sparse:oid=$blob 2>err && + cat >expect <<-EOF && + warning: ignoring excessively large pattern blob: $blob + fatal: unable to parse sparse filter data in $blob + EOF + test_cmp expect err +' + test_done diff --git a/t/t6115-rev-list-du.sh b/t/t6115-rev-list-du.sh index c0cfda62fa..21c4a211b1 100755 --- a/t/t6115-rev-list-du.sh +++ b/t/t6115-rev-list-du.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='basic tests of rev-list --disk-usage' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # we want a mix of reachable and unreachable, as well as diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index e78315d23d..05ed2510d9 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -14,6 +14,7 @@ test_description='test describe' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh check_describe () { @@ -671,4 +672,40 @@ test_expect_success 'setup misleading taggerdates' ' check_describe newer-tag-older-commit~1 --contains unique-file~2 +test_expect_success 'describe --dirty with a file with changed stat' ' + test_when_finished "rm -fr stat-dirty" && + git init stat-dirty && + ( + cd stat-dirty && + + echo A >file && + git add file && + git commit -m A && + git tag A -a -m A && + echo "A" >expect && + + test-tool chmtime -10 file && + git describe --dirty >actual && + test_cmp expect actual + ) +' + +test_expect_success 'describe --broken --dirty with a file with changed stat' ' + test_when_finished "rm -fr stat-dirty" && + git init stat-dirty && + ( + cd stat-dirty && + + echo A >file && + git add file && + git commit -m A && + git tag A -a -m A && + echo "A" >expect && + + test-tool chmtime -10 file && + git describe --dirty --broken >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t6130-pathspec-noglob.sh b/t/t6130-pathspec-noglob.sh index ba7902c9cd..82de25d549 100755 --- a/t/t6130-pathspec-noglob.sh +++ b/t/t6130-pathspec-noglob.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test globbing (and noglob) of pathspec limiting' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'create commits with glob characters' ' diff --git a/t/t6133-pathspec-rev-dwim.sh b/t/t6133-pathspec-rev-dwim.sh index a290ffca0d..6dd4bbbf9f 100755 --- a/t/t6133-pathspec-rev-dwim.sh +++ b/t/t6133-pathspec-rev-dwim.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='test dwim of revs versus pathspecs in revision parser' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t6402-merge-rename.sh b/t/t6402-merge-rename.sh index 2738b50c2a..729aac9842 100755 --- a/t/t6402-merge-rename.sh +++ b/t/t6402-merge-rename.sh @@ -4,6 +4,7 @@ test_description='Merge-recursive merging renames' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh modify () { diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh index 156a1efacf..9bf9524934 100755 --- a/t/t6406-merge-attr.sh +++ b/t/t6406-merge-attr.sh @@ -185,7 +185,7 @@ test_expect_success !WINDOWS 'custom merge driver that is killed with a signal' >./please-abort && echo "* merge=custom" >.gitattributes && - test_must_fail git merge main 2>err && + test_expect_code 2 git merge main 2>err && grep "^error: failed to execute internal merge" err && git ls-files -u >output && git diff --name-only HEAD >>output && @@ -261,4 +261,44 @@ test_expect_success 'binary files with union attribute' ' grep -i "warning.*cannot merge.*HEAD vs. bin-main" output ' +test_expect_success !WINDOWS 'custom merge driver that is killed with a signal on recursive merge' ' + test_when_finished "rm -f output please-abort" && + test_when_finished "git checkout side" && + + git reset --hard anchor && + + git checkout -b base-a main^ && + echo base-a >text && + git commit -m base-a text && + + git checkout -b base-b main^ && + echo base-b >text && + git commit -m base-b text && + + git checkout -b recursive-a base-a && + test_must_fail git merge base-b && + echo recursive-a >text && + git add text && + git commit -m recursive-a && + + git checkout -b recursive-b base-b && + test_must_fail git merge base-a && + echo recursive-b >text && + git add text && + git commit -m recursive-b && + + git config --replace-all \ + merge.custom.driver "./custom-merge %O %A %B 0 %P %S %X %Y" && + git config --replace-all \ + merge.custom.name "custom merge driver for testing" && + + >./please-abort && + echo "* merge=custom" >.gitattributes && + test_expect_code 2 git merge recursive-a 2>err && + grep "error: failed to execute internal merge" err && + git ls-files -u >output && + git diff --name-only HEAD >>output && + test_must_be_empty output +' + test_done diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh index 711b709e75..b99f29ef9b 100755 --- a/t/t6421-merge-partial-clone.sh +++ b/t/t6421-merge-partial-clone.sh @@ -230,8 +230,9 @@ test_expect_merge_algorithm failure success 'Objects downloaded for single relev grep fetch_count trace.output | cut -d "|" -f 9 | tr -d " ." >actual && test_cmp expect actual && - # Check the number of fetch commands exec-ed - grep d0.*fetch.negotiationAlgorithm trace.output >fetches && + # Check the number of fetch commands exec-ed by filtering trace to + # child_start events by the top-level program (2nd field == d0) + grep " d0 .* child_start .*fetch.negotiationAlgorithm" trace.output >fetches && test_line_count = 2 fetches && git rev-list --objects --all --missing=print | @@ -318,8 +319,9 @@ test_expect_merge_algorithm failure success 'Objects downloaded when a directory grep fetch_count trace.output | cut -d "|" -f 9 | tr -d " ." >actual && test_cmp expect actual && - # Check the number of fetch commands exec-ed - grep d0.*fetch.negotiationAlgorithm trace.output >fetches && + # Check the number of fetch commands exec-ed by filtering trace to + # child_start events by the top-level program (2nd field == d0) + grep " d0 .* child_start .*fetch.negotiationAlgorithm" trace.output >fetches && test_line_count = 1 fetches && git rev-list --objects --all --missing=print | @@ -422,8 +424,9 @@ test_expect_merge_algorithm failure success 'Objects downloaded with lots of ren grep fetch_count trace.output | cut -d "|" -f 9 | tr -d " ." >actual && test_cmp expect actual && - # Check the number of fetch commands exec-ed - grep d0.*fetch.negotiationAlgorithm trace.output >fetches && + # Check the number of fetch commands exec-ed by filtering trace to + # child_start events by the top-level program (2nd field == d0) + grep " d0 .* child_start .*fetch.negotiationAlgorithm" trace.output >fetches && test_line_count = 4 fetches && git rev-list --objects --all --missing=print | diff --git a/t/t6427-diff3-conflict-markers.sh b/t/t6427-diff3-conflict-markers.sh index dd5fe6a402..a13271b349 100755 --- a/t/t6427-diff3-conflict-markers.sh +++ b/t/t6427-diff3-conflict-markers.sh @@ -5,6 +5,7 @@ test_description='recursive merge diff3 style conflict markers' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Setup: diff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh index ca15e6dd6d..555f00f78a 100755 --- a/t/t6430-merge-recursive.sh +++ b/t/t6430-merge-recursive.sh @@ -5,6 +5,7 @@ test_description='merge-recursive backend test' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-merge.sh diff --git a/t/t6432-merge-recursive-space-options.sh b/t/t6432-merge-recursive-space-options.sh index db4b77e63d..c93538b0c3 100755 --- a/t/t6432-merge-recursive-space-options.sh +++ b/t/t6432-merge-recursive-space-options.sh @@ -14,6 +14,7 @@ test_description='merge-recursive space options GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b diff --git a/t/t6434-merge-recursive-rename-options.sh b/t/t6434-merge-recursive-rename-options.sh index a11707835b..df1d0c156c 100755 --- a/t/t6434-merge-recursive-rename-options.sh +++ b/t/t6434-merge-recursive-rename-options.sh @@ -29,6 +29,7 @@ mentions this in a different context). GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh get_expected_stages () { diff --git a/t/t6436-merge-overwrite.sh b/t/t6436-merge-overwrite.sh index 4f4376421e..ccc620477d 100755 --- a/t/t6436-merge-overwrite.sh +++ b/t/t6436-merge-overwrite.sh @@ -7,6 +7,7 @@ Do not overwrite changes.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 43d40175f8..1b5909d1b7 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -158,7 +158,7 @@ test_expect_success TTY 'with TTY: gc --no-quiet' ' git -c gc.writeCommitGraph=true gc --no-quiet >stdout 2>stderr && test_must_be_empty stdout && test_grep "Enumerating objects" stderr && - test_grep "Computing commit graph generation numbers" stderr + test_grep "Computing commit graph generation numbers: 100% (4/4), done." stderr ' test_expect_success 'gc --quiet' ' diff --git a/t/t7002-mv-sparse-checkout.sh b/t/t7002-mv-sparse-checkout.sh index 26582ae4e5..57969ce805 100755 --- a/t/t7002-mv-sparse-checkout.sh +++ b/t/t7002-mv-sparse-checkout.sh @@ -2,6 +2,7 @@ test_description='git mv in sparse working trees' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh setup_sparse_checkout () { diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh index e56ca5b0fa..a0296d6ca4 100755 --- a/t/t7006-pager.sh +++ b/t/t7006-pager.sh @@ -2,6 +2,7 @@ test_description='Test automatic use of a pager.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-pager.sh . "$TEST_DIRECTORY"/lib-terminal.sh @@ -725,18 +726,11 @@ test_expect_success TTY 'git discards pager non-zero exit without SIGPIPE' ' test_path_is_file pager-used ' -test_expect_success TTY 'git skips paging nonexisting command' ' - test_when_finished "rm trace.normal" && +test_expect_success TTY 'git errors when asked to execute nonexisting pager' ' + test_when_finished "rm -f err" && test_config core.pager "does-not-exist" && - GIT_TRACE2="$(pwd)/trace.normal" && - export GIT_TRACE2 && - test_when_finished "unset GIT_TRACE2" && - - test_terminal git log && - - grep child_exit trace.normal >child-exits && - test_line_count = 1 child-exits && - grep " code:-1 " child-exits + test_must_fail test_terminal git log 2>err && + test_grep "unable to execute pager" err ' test_expect_success TTY 'git returns SIGPIPE on propagated signals from pager' ' @@ -762,7 +756,7 @@ test_expect_success TTY 'git returns SIGPIPE on propagated signals from pager' ' test_expect_success TTY 'non-existent pager doesnt cause crash' ' test_config pager.show invalid-pager && - test_terminal git show + test_must_fail test_terminal git show ' test_done diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh index 520f96d09f..d9add2162e 100755 --- a/t/t7010-setup.sh +++ b/t/t7010-setup.sh @@ -2,6 +2,7 @@ test_description='setup taking and sanitizing funny paths' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success setup ' diff --git a/t/t7012-skip-worktree-writing.sh b/t/t7012-skip-worktree-writing.sh index cd5c20fe51..d984200c17 100755 --- a/t/t7012-skip-worktree-writing.sh +++ b/t/t7012-skip-worktree-writing.sh @@ -5,6 +5,7 @@ test_description='test worktree writing operations when skip-worktree is used' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7064-wtstatus-pv2.sh b/t/t7064-wtstatus-pv2.sh index 11884d2fc3..06c1301222 100755 --- a/t/t7064-wtstatus-pv2.sh +++ b/t/t7064-wtstatus-pv2.sh @@ -4,6 +4,7 @@ test_description='git status --porcelain=v2 This test exercises porcelain V2 output for git status.' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 42352dc0db..2d984eb4c6 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -23,6 +23,7 @@ Test switching across them. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_tick @@ -497,6 +498,19 @@ test_expect_success 'checkout unmerged stage' ' test ztheirside = "z$(cat file)" ' +test_expect_success 'checkout --ours is incompatible with switching' ' + test_must_fail git checkout --ours 2>error && + test_grep "needs the paths to check out" error && + + test_must_fail git checkout --ours HEAD 2>error && + test_grep "cannot be used with switching" error && + + test_must_fail git checkout --ours main 2>error && + test_grep "cannot be used with switching" error && + + git checkout --ours file +' + test_expect_success 'checkout path with --merge from tree-ish is a no-no' ' setup_conflicting_index && test_must_fail git checkout -m HEAD -- file diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 981488885f..098d8833b6 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -12,6 +12,7 @@ subcommands of git submodule. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup - enable local submodules' ' diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh index cc12f99f11..52f5e28154 100755 --- a/t/t7501-commit-basic-functionality.sh +++ b/t/t7501-commit-basic-functionality.sh @@ -9,6 +9,7 @@ test_description='git commit' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY/lib-diff.sh" diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh index 2128142a61..b88383df9e 100755 --- a/t/t7505-prepare-commit-msg-hook.sh +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -5,6 +5,7 @@ test_description='prepare-commit-msg hook' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up commits for rebasing' ' diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh index 802f8f704c..cdd5f2c697 100755 --- a/t/t7512-status-help.sh +++ b/t/t7512-status-help.sh @@ -10,6 +10,7 @@ test_description='git status advice' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-rebase.sh diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index e5ff073099..65fd3d8552 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -29,6 +29,7 @@ Testing basic merge operations/option parsing. GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh . "$TEST_DIRECTORY"/lib-gpg.sh @@ -236,6 +237,16 @@ test_expect_success 'merge c1 with c2' ' verify_parents $c1 $c2 ' +test_expect_success 'merge c1 with c2 when index.lock exists' ' + test_when_finished rm .git/index.lock && + git reset --hard c1 && + >.git/index.lock && + test_must_fail git merge c2 && + test_path_is_missing .git/MERGE_HEAD && + test_path_is_missing .git/MERGE_MODE && + test_path_is_missing .git/MERGE_MSG +' + test_expect_success 'merge --squash c3 with c7' ' git reset --hard c3 && test_must_fail git merge --squash c7 && diff --git a/t/t7606-merge-custom.sh b/t/t7606-merge-custom.sh index 81fb7c474c..135cb23085 100755 --- a/t/t7606-merge-custom.sh +++ b/t/t7606-merge-custom.sh @@ -14,6 +14,7 @@ Testing a custom strategy. * (tag: c0) c0 " +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'set up custom strategy' ' diff --git a/t/t7611-merge-abort.sh b/t/t7611-merge-abort.sh index d6975ca48d..992a8f9874 100755 --- a/t/t7611-merge-abort.sh +++ b/t/t7611-merge-abort.sh @@ -25,6 +25,7 @@ Next, test git merge --abort with the following variables: GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t7615-diff-algo-with-mergy-operations.sh b/t/t7615-diff-algo-with-mergy-operations.sh new file mode 100755 index 0000000000..9a83be518c --- /dev/null +++ b/t/t7615-diff-algo-with-mergy-operations.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +test_description='git merge and other operations that rely on merge + +Testing the influence of the diff algorithm on the merge output.' + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success 'setup' ' + cp "$TEST_DIRECTORY"/t7615/base.c file.c && + git add file.c && + git commit -m c0 && + git tag c0 && + cp "$TEST_DIRECTORY"/t7615/ours.c file.c && + git add file.c && + git commit -m c1 && + git tag c1 && + git reset --hard c0 && + cp "$TEST_DIRECTORY"/t7615/theirs.c file.c && + git add file.c && + git commit -m c2 && + git tag c2 +' + +GIT_TEST_MERGE_ALGORITHM=recursive + +test_expect_success 'merge c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' ' + git reset --hard c1 && + test_must_fail git merge -s recursive c2 +' + +test_expect_success 'merge c2 to c1 with recursive merge strategy succeeds with -Xdiff-algorithm=histogram' ' + git reset --hard c1 && + git merge --strategy recursive -Xdiff-algorithm=histogram c2 +' + +test_expect_success 'merge c2 to c1 with recursive merge strategy succeeds with diff.algorithm = histogram' ' + git reset --hard c1 && + git config diff.algorithm histogram && + git merge --strategy recursive c2 +' + +test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' ' + git reset --hard c1 && + test_must_fail git cherry-pick -s recursive c2 +' + +test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy succeeds with -Xdiff-algorithm=histogram' ' + git reset --hard c1 && + git cherry-pick --strategy recursive -Xdiff-algorithm=histogram c2 +' + +test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy succeeds with diff.algorithm = histogram' ' + git reset --hard c1 && + git config diff.algorithm histogram && + git cherry-pick --strategy recursive c2 +' + +test_done diff --git a/t/t7615/base.c b/t/t7615/base.c new file mode 100644 index 0000000000..c64abc5936 --- /dev/null +++ b/t/t7615/base.c @@ -0,0 +1,17 @@ +int f(int x, int y) +{ + if (x == 0) + { + return y; + } + return x; +} + +int g(size_t u) +{ + while (u < 30) + { + u++; + } + return u; +} diff --git a/t/t7615/ours.c b/t/t7615/ours.c new file mode 100644 index 0000000000..44d8251397 --- /dev/null +++ b/t/t7615/ours.c @@ -0,0 +1,17 @@ +int g(size_t u) +{ + while (u < 30) + { + u++; + } + return u; +} + +int h(int x, int y, int z) +{ + if (z == 0) + { + return x; + } + return y; +} diff --git a/t/t7615/theirs.c b/t/t7615/theirs.c new file mode 100644 index 0000000000..85f02146fe --- /dev/null +++ b/t/t7615/theirs.c @@ -0,0 +1,17 @@ +int f(int x, int y) +{ + if (x == 0) + { + return y; + } + return x; +} + +int g(size_t u) +{ + while (u > 34) + { + u--; + } + return u; +} diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 875dcfd98f..af2cf2f78a 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -31,6 +31,7 @@ int main(int argc, const char **argv) return 0; /* char ?? */ } + EOF test_expect_success setup ' diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh index 0147de304b..3596634039 100755 --- a/t/t8002-blame.sh +++ b/t/t8002-blame.sh @@ -5,6 +5,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh PROG='git blame -c' diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh index 731265541a..6288352f57 100755 --- a/t/t8003-blame-corner-cases.sh +++ b/t/t8003-blame-corner-cases.sh @@ -4,6 +4,7 @@ test_description='git blame corner cases' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pick_fc='s/^[0-9a-f^]* *\([^ ]*\) *(\([^ ]*\) .*/\1-\2/' diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh index 35414a5336..2c2a0b33f9 100755 --- a/t/t8004-blame-with-conflicts.sh +++ b/t/t8004-blame-with-conflicts.sh @@ -6,6 +6,7 @@ test_description='git blame on conflicted files' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup first case' ' diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh index 7683515155..42f8be25a3 100755 --- a/t/t8006-blame-textconv.sh +++ b/t/t8006-blame-textconv.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git blame textconv support' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh find_blame() { diff --git a/t/t8008-blame-formats.sh b/t/t8008-blame-formats.sh index ae4b579d24..fb5d225a67 100755 --- a/t/t8008-blame-formats.sh +++ b/t/t8008-blame-formats.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='blame output in various formats on a simple case' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh test_expect_success 'setup' ' diff --git a/t/t8009-blame-vs-topicbranches.sh b/t/t8009-blame-vs-topicbranches.sh index 72596e38b2..30331713b9 100755 --- a/t/t8009-blame-vs-topicbranches.sh +++ b/t/t8009-blame-vs-topicbranches.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='blaming trough history with topic branches' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Creates the history shown below. '*'s mark the first parent in the merges. diff --git a/t/t8011-blame-split-file.sh b/t/t8011-blame-split-file.sh index bdda0c03fe..da1801f4d2 100755 --- a/t/t8011-blame-split-file.sh +++ b/t/t8011-blame-split-file.sh @@ -10,6 +10,8 @@ Note that we need to use "blame -C" to find the commit for all lines. We will not bother testing that the non-C case fails to find it. That is how blame behaves now, but it is not a property we want to make sure is retained. ' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # help avoid typing and reading long strings of similar lines diff --git a/t/t8012-blame-colors.sh b/t/t8012-blame-colors.sh index c3a5f6d01f..9a79c109f2 100755 --- a/t/t8012-blame-colors.sh +++ b/t/t8012-blame-colors.sh @@ -5,6 +5,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME TEST_CREATE_REPO_NO_TEMPLATE=1 +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh PROG='git blame -c' diff --git a/t/t8013-blame-ignore-revs.sh b/t/t8013-blame-ignore-revs.sh index dbfbd86e83..d33788d867 100755 --- a/t/t8013-blame-ignore-revs.sh +++ b/t/t8013-blame-ignore-revs.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='ignore revisions when blaming' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh # Creates: diff --git a/t/t8014-blame-ignore-fuzzy.sh b/t/t8014-blame-ignore-fuzzy.sh index 0bd0341301..933222cea1 100755 --- a/t/t8014-blame-ignore-fuzzy.sh +++ b/t/t8014-blame-ignore-fuzzy.sh @@ -1,6 +1,8 @@ #!/bin/sh test_description='git blame ignore fuzzy heuristic' + +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh pick_author='s/^[0-9a-f^]* *(\([^ ]*\) .*/\1/' diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 58699f8e4e..64a4ab3736 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -1299,6 +1299,49 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' ' test_line_count = 1 msgfrom ' +test_expect_success $PREREQ 'setup expect for cc list' " +cat >expected-cc <<\EOF +!recipient@example.com! +!author@example.com! +!one@example.com! +!os@example.com! +!odd_?=mail@example.com! +!doug@example.com! +!codev@example.com! +!thor.au@example.com! +EOF +" + +test_expect_success $PREREQ 'cc list is sanitized' ' + clean_fake_sendmail && + test_commit weird_cc_body && + test_when_finished "git reset --hard HEAD^" && + git commit --amend -F - <<-EOF && + Test Cc: sanitization. + + Cc: Person, One <one@example.com> + Cc: Ronnie O${SQ}Sullivan <os@example.com> + Reviewed-by: Füñný Nâmé <odd_?=mail@example.com> + Reported-by: bugger on Jira + Reported-by: Douglas Reporter <doug@example.com> [from Jira profile] + BugID: 12345 + Co-developed-by: "C. O. Developer" <codev@example.com> + Signed-off-by: A. U. Thor <thor.au@example.com> + EOF + git send-email -1 --to=recipient@example.com \ + --smtp-server="$(pwd)/fake.sendmail" >actual-show-all-headers && + test_cmp expected-cc commandline1 && + test_grep "^(body) Adding cc: \"Person, One\" <one@example.com>" actual-show-all-headers && + test_grep "^(body) Adding cc: Ronnie O${SQ}Sullivan <os@example.com>" actual-show-all-headers && + test_grep "^(body) Adding cc: =?UTF-8?q?F=C3=BC=C3=B1n=C3=BD=20N=C3=A2m=C3=A9?="\ +" <odd_?=mail@example.com>" actual-show-all-headers && + test_grep "^(body) Ignoring Reported-by .* bugger on Jira" actual-show-all-headers && + test_grep "^(body) Adding cc: Douglas Reporter <doug@example.com>" actual-show-all-headers && + test_grep ! "12345" actual-show-all-headers && + test_grep "^(body) Adding cc: \"C. O. Developer\" <codev@example.com>" actual-show-all-headers && + test_grep "^(body) Adding cc: \"A. U. Thor\" <thor.au@example.com>" actual-show-all-headers +' + test_expect_success $PREREQ 'sendemail.composeencoding works' ' clean_fake_sendmail && git config sendemail.composeencoding iso-8859-1 && diff --git a/t/t9004-example.sh b/t/t9004-example.sh deleted file mode 100755 index 590aab0304..0000000000 --- a/t/t9004-example.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -test_description='check that example code compiles and runs' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -test_expect_success 'decorate' ' - test-tool example-decorate -' - -test_done diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 7679780fb8..ccfa415384 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -13,6 +13,7 @@ or warnings to log.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-gitweb.sh # ---------------------------------------------------------------------- diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh index 81d5625557..b41ea19331 100755 --- a/t/t9502-gitweb-standalone-parse-output.sh +++ b/t/t9502-gitweb-standalone-parse-output.sh @@ -13,6 +13,7 @@ in the HTTP header or the actual script output.' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-gitweb.sh # ---------------------------------------------------------------------- diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index 53af8e34ac..3e6dfce248 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -5,6 +5,7 @@ test_description='git p4 tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' @@ -297,8 +298,20 @@ test_expect_success 'exit when p4 fails to produce marshaled output' ' # p4 changes, files, or describe; just in p4 print. If P4CLIENT is unset, the # message will include "Librarian checkout". test_expect_success 'exit gracefully for p4 server errors' ' - test_when_finished "mv \"$db\"/depot/file1,v,hidden \"$db\"/depot/file1,v" && - mv "$db"/depot/file1,v "$db"/depot/file1,v,hidden && + # Note that newer Perforce versions started to store files + # compressed in directories. The case statement handles both + # old and new layout. + case "$(echo "$db"/depot/file1*)" in + *,v) + test_when_finished "mv \"$db\"/depot/file1,v,hidden \"$db\"/depot/file1,v" && + mv "$db"/depot/file1,v "$db"/depot/file1,v,hidden;; + *,d) + path="$(echo "$db"/depot/file1,d/*.gz)" && + test_when_finished "mv \"$path\",hidden \"$path\"" && + mv "$path" "$path",hidden;; + *) + BUG "unhandled p4d layout";; + esac && test_when_finished cleanup_git && test_expect_code 1 git p4 clone --dest="$git" //depot@1 >out 2>err && test_grep "Error from p4 print" err diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh index c598011635..cdbfacc727 100755 --- a/t/t9801-git-p4-branch.sh +++ b/t/t9801-git-p4-branch.sh @@ -5,6 +5,7 @@ test_description='git p4 tests for p4 branches' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9802-git-p4-filetype.sh b/t/t9802-git-p4-filetype.sh index bb236cd2b5..1bc48305b0 100755 --- a/t/t9802-git-p4-filetype.sh +++ b/t/t9802-git-p4-filetype.sh @@ -2,6 +2,7 @@ test_description='git p4 filetype tests' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' @@ -300,10 +301,22 @@ test_expect_success SYMLINKS 'empty symlink target' ' # text # @@ # + # Note that newer Perforce versions started to store files + # compressed in directories. The case statement handles both + # old and new layout. cd "$db/depot" && - sed "/@target1/{; s/target1/@/; n; d; }" \ - empty-symlink,v >empty-symlink,v.tmp && - mv empty-symlink,v.tmp empty-symlink,v + case "$(echo empty-symlink*)" in + empty-symlink,v) + sed "/@target1/{; s/target1/@/; n; d; }" \ + empty-symlink,v >empty-symlink,v.tmp && + mv empty-symlink,v.tmp empty-symlink,v;; + empty-symlink,d) + path="empty-symlink,d/$(ls empty-symlink,d/ | tail -n1)" && + rm "$path" && + gzip </dev/null >"$path";; + *) + BUG "unhandled p4d layout";; + esac ) && ( # Make sure symlink really is empty. Asking diff --git a/t/t9803-git-p4-shell-metachars.sh b/t/t9803-git-p4-shell-metachars.sh index 2913277013..ab7fe16266 100755 --- a/t/t9803-git-p4-shell-metachars.sh +++ b/t/t9803-git-p4-shell-metachars.sh @@ -2,6 +2,7 @@ test_description='git p4 transparency to shell metachars in filenames' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9804-git-p4-label.sh b/t/t9804-git-p4-label.sh index 3236457106..c8963fd398 100755 --- a/t/t9804-git-p4-label.sh +++ b/t/t9804-git-p4-label.sh @@ -2,6 +2,7 @@ test_description='git p4 label tests' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9805-git-p4-skip-submit-edit.sh b/t/t9805-git-p4-skip-submit-edit.sh index 90ef647db7..72dce3d2b4 100755 --- a/t/t9805-git-p4-skip-submit-edit.sh +++ b/t/t9805-git-p4-skip-submit-edit.sh @@ -2,6 +2,7 @@ test_description='git p4 skipSubmitEdit config variables' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh index c26d297433..e4ce44ebf3 100755 --- a/t/t9806-git-p4-options.sh +++ b/t/t9806-git-p4-options.sh @@ -5,6 +5,7 @@ test_description='git p4 options' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9808-git-p4-chdir.sh b/t/t9808-git-p4-chdir.sh index 58a9b3b71e..342f7f3d4a 100755 --- a/t/t9808-git-p4-chdir.sh +++ b/t/t9808-git-p4-chdir.sh @@ -2,6 +2,7 @@ test_description='git p4 relative chdir' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh index 9c9710d8c7..f33fdea889 100755 --- a/t/t9809-git-p4-client-view.sh +++ b/t/t9809-git-p4-client-view.sh @@ -2,6 +2,7 @@ test_description='git p4 client view' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh index 5fe83315ec..15e32c9f35 100755 --- a/t/t9810-git-p4-rcs.sh +++ b/t/t9810-git-p4-rcs.sh @@ -2,6 +2,7 @@ test_description='git p4 rcs keywords' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh CP1252="\223\224" diff --git a/t/t9811-git-p4-label-import.sh b/t/t9811-git-p4-label-import.sh index 5ac5383fb7..52a4b0af81 100755 --- a/t/t9811-git-p4-label-import.sh +++ b/t/t9811-git-p4-label-import.sh @@ -5,6 +5,7 @@ test_description='git p4 label tests' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh index 254a7c2446..46aa5fd56c 100755 --- a/t/t9812-git-p4-wildcards.sh +++ b/t/t9812-git-p4-wildcards.sh @@ -2,6 +2,7 @@ test_description='git p4 wildcards' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9813-git-p4-preserve-users.sh b/t/t9813-git-p4-preserve-users.sh index fd018c87a8..0efea28da2 100755 --- a/t/t9813-git-p4-preserve-users.sh +++ b/t/t9813-git-p4-preserve-users.sh @@ -2,6 +2,7 @@ test_description='git p4 preserve users' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh index 2a9838f37f..00df6ebd3b 100755 --- a/t/t9814-git-p4-rename.sh +++ b/t/t9814-git-p4-rename.sh @@ -2,6 +2,7 @@ test_description='git p4 rename' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh index c766fd159f..92ef9d8c24 100755 --- a/t/t9815-git-p4-submit-fail.sh +++ b/t/t9815-git-p4-submit-fail.sh @@ -2,6 +2,7 @@ test_description='git p4 submit failure handling' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9816-git-p4-locked.sh b/t/t9816-git-p4-locked.sh index 5e904ac80d..e687fbc25f 100755 --- a/t/t9816-git-p4-locked.sh +++ b/t/t9816-git-p4-locked.sh @@ -2,6 +2,7 @@ test_description='git p4 locked file behavior' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9817-git-p4-exclude.sh b/t/t9817-git-p4-exclude.sh index ec3d937c6a..3deb334fed 100755 --- a/t/t9817-git-p4-exclude.sh +++ b/t/t9817-git-p4-exclude.sh @@ -2,6 +2,7 @@ test_description='git p4 tests for excluded paths during clone and sync' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9818-git-p4-block.sh b/t/t9818-git-p4-block.sh index de591d875c..091bb72bdb 100755 --- a/t/t9818-git-p4-block.sh +++ b/t/t9818-git-p4-block.sh @@ -2,6 +2,7 @@ test_description='git p4 fetching changes in multiple blocks' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9819-git-p4-case-folding.sh b/t/t9819-git-p4-case-folding.sh index b4d93f0c17..985be20357 100755 --- a/t/t9819-git-p4-case-folding.sh +++ b/t/t9819-git-p4-case-folding.sh @@ -2,6 +2,7 @@ test_description='interaction with P4 case-folding' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh if test_have_prereq CASE_INSENSITIVE_FS diff --git a/t/t9820-git-p4-editor-handling.sh b/t/t9820-git-p4-editor-handling.sh index fa1bba1dd9..48e4dfb95c 100755 --- a/t/t9820-git-p4-editor-handling.sh +++ b/t/t9820-git-p4-editor-handling.sh @@ -2,6 +2,7 @@ test_description='git p4 handling of EDITOR' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9821-git-p4-path-variations.sh b/t/t9821-git-p4-path-variations.sh index ef80f1690b..49691c53da 100755 --- a/t/t9821-git-p4-path-variations.sh +++ b/t/t9821-git-p4-path-variations.sh @@ -2,6 +2,7 @@ test_description='Clone repositories with path case variations' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d with case folding enabled' ' diff --git a/t/t9822-git-p4-path-encoding.sh b/t/t9822-git-p4-path-encoding.sh index 572d395498..e62ed49f51 100755 --- a/t/t9822-git-p4-path-encoding.sh +++ b/t/t9822-git-p4-path-encoding.sh @@ -2,6 +2,7 @@ test_description='Clone repositories with non ASCII paths' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh UTF8_ESCAPED="a-\303\244_o-\303\266_u-\303\274.txt" diff --git a/t/t9823-git-p4-mock-lfs.sh b/t/t9823-git-p4-mock-lfs.sh index 88b76dc4d6..98a40d8af3 100755 --- a/t/t9823-git-p4-mock-lfs.sh +++ b/t/t9823-git-p4-mock-lfs.sh @@ -2,6 +2,7 @@ test_description='Clone repositories and store files in Mock LFS' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_file_is_not_in_mock_lfs () { diff --git a/t/t9825-git-p4-handle-utf16-without-bom.sh b/t/t9825-git-p4-handle-utf16-without-bom.sh index f049ff8229..d0b86537dd 100755 --- a/t/t9825-git-p4-handle-utf16-without-bom.sh +++ b/t/t9825-git-p4-handle-utf16-without-bom.sh @@ -2,6 +2,7 @@ test_description='git p4 handling of UTF-16 files without BOM' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh UTF16="\227\000\227\000" @@ -22,9 +23,25 @@ test_expect_success 'init depot with UTF-16 encoded file and artificially remove cd db && p4d -jc && # P4D automatically adds a BOM. Remove it here to make the file invalid. - sed -e "\$d" depot/file1,v >depot/file1,v.new && - mv depot/file1,v.new depot/file1,v && - printf "@$UTF16@" >>depot/file1,v && + # + # Note that newer Perforce versions started to store files + # compressed in directories. The case statement handles both + # old and new layout. + case "$(echo depot/file1*)" in + depot/file1,v) + sed -e "\$d" depot/file1,v >depot/file1,v.new && + mv depot/file1,v.new depot/file1,v && + printf "@$UTF16@" >>depot/file1,v;; + depot/file1,d) + path="$(echo depot/file1,d/*.gz)" && + gunzip -c "$path" >"$path.unzipped" && + sed -e "\$d" "$path.unzipped" >"$path.new" && + printf "$UTF16" >>"$path.new" && + gzip -c "$path.new" >"$path" && + rm "$path.unzipped" "$path.new";; + *) + BUG "unhandled p4d layout";; + esac && p4d -jrF checkpoint.1 ) ' diff --git a/t/t9826-git-p4-keep-empty-commits.sh b/t/t9826-git-p4-keep-empty-commits.sh index fd64afe064..54083f842e 100755 --- a/t/t9826-git-p4-keep-empty-commits.sh +++ b/t/t9826-git-p4-keep-empty-commits.sh @@ -2,6 +2,7 @@ test_description='Clone repositories and keep empty commits' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9827-git-p4-change-filetype.sh b/t/t9827-git-p4-change-filetype.sh index d3670bd7a2..3476ea2fd3 100755 --- a/t/t9827-git-p4-change-filetype.sh +++ b/t/t9827-git-p4-change-filetype.sh @@ -2,6 +2,7 @@ test_description='git p4 support for file type change' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9828-git-p4-map-user.sh b/t/t9828-git-p4-map-user.sh index ca6c2942bd..7c8f9e3930 100755 --- a/t/t9828-git-p4-map-user.sh +++ b/t/t9828-git-p4-map-user.sh @@ -2,6 +2,7 @@ test_description='Clone repositories and map users' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9829-git-p4-jobs.sh b/t/t9829-git-p4-jobs.sh index 88cfb1fcd3..3fc0948d9c 100755 --- a/t/t9829-git-p4-jobs.sh +++ b/t/t9829-git-p4-jobs.sh @@ -2,6 +2,7 @@ test_description='git p4 retrieve job info' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9830-git-p4-symlink-dir.sh b/t/t9830-git-p4-symlink-dir.sh index 3fb6960c18..02561a7f0e 100755 --- a/t/t9830-git-p4-symlink-dir.sh +++ b/t/t9830-git-p4-symlink-dir.sh @@ -2,6 +2,7 @@ test_description='git p4 symlinked directories' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9831-git-p4-triggers.sh b/t/t9831-git-p4-triggers.sh index ff6c0352e6..f287f41e37 100755 --- a/t/t9831-git-p4-triggers.sh +++ b/t/t9831-git-p4-triggers.sh @@ -2,6 +2,7 @@ test_description='git p4 with server triggers' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9832-unshelve.sh b/t/t9832-unshelve.sh index 6b3cb0414a..a266775408 100755 --- a/t/t9832-unshelve.sh +++ b/t/t9832-unshelve.sh @@ -6,6 +6,7 @@ last_shelved_change () { test_description='git p4 unshelve' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9833-errors.sh b/t/t9833-errors.sh index e22369ccdf..da1d30c142 100755 --- a/t/t9833-errors.sh +++ b/t/t9833-errors.sh @@ -2,6 +2,7 @@ test_description='git p4 errors' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9834-git-p4-file-dir-bug.sh b/t/t9834-git-p4-file-dir-bug.sh index dac67e89d7..565870fc74 100755 --- a/t/t9834-git-p4-file-dir-bug.sh +++ b/t/t9834-git-p4-file-dir-bug.sh @@ -6,6 +6,7 @@ This test creates files and directories with the same name in perforce and checks that git-p4 recovers from the error at the same time as the perforce repository.' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh test_expect_success 'start p4d' ' diff --git a/t/t9835-git-p4-metadata-encoding-python2.sh b/t/t9835-git-p4-metadata-encoding-python2.sh index 036bf79c66..ad20ffdede 100755 --- a/t/t9835-git-p4-metadata-encoding-python2.sh +++ b/t/t9835-git-p4-metadata-encoding-python2.sh @@ -6,6 +6,7 @@ This test checks that the import process handles inconsistent text encoding in p4 metadata (author names, commit messages, etc) without failing, and produces maximally sane output in git.' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh python_target_version='2' diff --git a/t/t9836-git-p4-metadata-encoding-python3.sh b/t/t9836-git-p4-metadata-encoding-python3.sh index 63350dc4b5..71ae763399 100755 --- a/t/t9836-git-p4-metadata-encoding-python3.sh +++ b/t/t9836-git-p4-metadata-encoding-python3.sh @@ -6,6 +6,7 @@ This test checks that the import process handles inconsistent text encoding in p4 metadata (author names, commit messages, etc) without failing, and produces maximally sane output in git.' +TEST_PASSES_SANITIZE_LEAK=true . ./lib-git-p4.sh python_target_version='3' diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 932d5ad759..cc6aa9f0cd 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -16,6 +16,7 @@ test_untraceable=UnfortunatelyYes GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-bash.sh complete () diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh index d667dda654..95e9955bca 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -8,6 +8,7 @@ test_description='test git-specific bash prompt functions' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +TEST_PASSES_SANITIZE_LEAK=true . ./lib-bash.sh . "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh" diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 862d80c974..fde9bf54fc 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -458,6 +458,7 @@ test_commit_bulk () { indir=. ref=HEAD n=1 + notick= message='commit %s' filename='%s.t' contents='content %s' @@ -488,6 +489,9 @@ test_commit_bulk () { filename="${1#--*=}-%s.t" contents="${1#--*=} %s" ;; + --notick) + notick=yes + ;; -*) BUG "invalid test_commit_bulk option: $1" ;; @@ -507,7 +511,10 @@ test_commit_bulk () { while test "$total" -gt 0 do - test_tick && + if test -z "$notick" + then + test_tick + fi && echo "commit $ref" printf 'author %s <%s> %s\n' \ "$GIT_AUTHOR_NAME" \ @@ -865,6 +872,24 @@ test_verify_prereq () { BUG "'$test_prereq' does not look like a prereq" } +# assign the variable named by "$1" with the contents of "$2"; +# if "$2" is "-", then read stdin into "$1" instead +test_body_or_stdin () { + if test "$2" != "-" + then + eval "$1=\$2" + return + fi + + # start with a newline, to match hanging newline from open-quote style + eval "$1=\$LF" + local test_line + while IFS= read -r test_line + do + eval "$1=\${$1}\${test_line}\${LF}" + done +} + test_expect_failure () { test_start_ "$@" test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= @@ -874,9 +899,11 @@ test_expect_failure () { export test_prereq if ! test_skip "$@" then + local test_body + test_body_or_stdin test_body "$2" test -n "$test_skip_test_preamble" || - say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $2" - if test_run_ "$2" expecting_failure + say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $test_body" + if test_run_ "$test_body" expecting_failure then test_known_broken_ok_ "$1" else @@ -895,13 +922,15 @@ test_expect_success () { export test_prereq if ! test_skip "$@" then + local test_body + test_body_or_stdin test_body "$2" test -n "$test_skip_test_preamble" || - say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $2" - if test_run_ "$2" + say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $test_body" + if test_run_ "$test_body" then test_ok_ "$1" else - test_failure_ "$@" + test_failure_ "$1" "$test_body" fi fi test_finish_ @@ -1096,6 +1125,11 @@ test_must_fail_acceptable () { done fi + if test "$1" = "nongit" + then + shift + fi + case "$1" in git|__git*|scalar|test-tool|test_terminal) return 0 diff --git a/t/test-lib.sh b/t/test-lib.sh index 79d3e0e7d9..54247604cb 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1269,9 +1269,12 @@ check_test_results_san_file_ () { then say "As TEST_PASSES_SANITIZE_LEAK=true isn't set the above leak is 'ok' with GIT_TEST_PASSING_SANITIZE_LEAK=check" && invert_exit_code=t - else - say "With GIT_TEST_SANITIZE_LEAK_LOG=true our logs revealed a memory leak, exit non-zero!" && + elif test "$test_failure" = 0 + then + say "Our logs revealed a memory leak, exit non-zero!" && invert_exit_code=t + else + say "Our logs revealed a memory leak..." fi } @@ -1575,33 +1578,28 @@ then test_done fi - if test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false + if ! mkdir -p "$TEST_RESULTS_SAN_DIR" then - if ! mkdir -p "$TEST_RESULTS_SAN_DIR" - then - BAIL_OUT "cannot create $TEST_RESULTS_SAN_DIR" - fi && - TEST_RESULTS_SAN_FILE="$TEST_RESULTS_SAN_DIR/$TEST_RESULTS_SAN_FILE_PFX" + BAIL_OUT "cannot create $TEST_RESULTS_SAN_DIR" + fi && + TEST_RESULTS_SAN_FILE="$TEST_RESULTS_SAN_DIR/$TEST_RESULTS_SAN_FILE_PFX" - # In case "test-results" is left over from a previous - # run: Only report if new leaks show up. - TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=$(nr_san_dir_leaks_) + # In case "test-results" is left over from a previous + # run: Only report if new leaks show up. + TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=$(nr_san_dir_leaks_) - # Don't litter *.leak dirs if there was nothing to report - test_atexit "rmdir \"$TEST_RESULTS_SAN_DIR\" 2>/dev/null || :" + # Don't litter *.leak dirs if there was nothing to report + test_atexit "rmdir \"$TEST_RESULTS_SAN_DIR\" 2>/dev/null || :" + + prepend_var LSAN_OPTIONS : dedup_token_length=9999 + prepend_var LSAN_OPTIONS : log_exe_name=1 + prepend_var LSAN_OPTIONS : log_path=\"$TEST_RESULTS_SAN_FILE\" + export LSAN_OPTIONS - prepend_var LSAN_OPTIONS : dedup_token_length=9999 - prepend_var LSAN_OPTIONS : log_exe_name=1 - prepend_var LSAN_OPTIONS : log_path=\"$TEST_RESULTS_SAN_FILE\" - export LSAN_OPTIONS - fi elif test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check" || test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false then BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_PASSING_SANITIZE_LEAK=true" -elif test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false -then - BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_SANITIZE_LEAK_LOG=true" fi if test "${GIT_TEST_CHAIN_LINT:-1}" != 0 && diff --git a/t/test-terminal.perl b/t/test-terminal.perl index 3810e9bb43..b8fd6a4f13 100755 --- a/t/test-terminal.perl +++ b/t/test-terminal.perl @@ -5,17 +5,15 @@ use warnings; use IO::Pty; use File::Copy; -# Run @$argv in the background with stdio redirected to $in, $out and $err. +# Run @$argv in the background with stdio redirected to $out and $err. sub start_child { - my ($argv, $in, $out, $err) = @_; + my ($argv, $out, $err) = @_; my $pid = fork; if (not defined $pid) { die "fork failed: $!" } elsif ($pid == 0) { - open STDIN, "<&", $in; open STDOUT, ">&", $out; open STDERR, ">&", $err; - close $in; close $out; exec(@$argv) or die "cannot exec '$argv->[0]': $!" } @@ -51,17 +49,6 @@ sub xsendfile { copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!"; } -sub copy_stdin { - my ($in) = @_; - my $pid = fork; - if (!$pid) { - xsendfile($in, \*STDIN); - exit 0; - } - close($in); - return $pid; -} - sub copy_stdio { my ($out, $err) = @_; my $pid = fork; @@ -81,25 +68,15 @@ if ($#ARGV < 1) { die "usage: test-terminal program args"; } $ENV{TERM} = 'vt100'; -my $parent_in = new IO::Pty; my $parent_out = new IO::Pty; my $parent_err = new IO::Pty; -$parent_in->set_raw(); $parent_out->set_raw(); $parent_err->set_raw(); -$parent_in->slave->set_raw(); $parent_out->slave->set_raw(); $parent_err->slave->set_raw(); -my $pid = start_child(\@ARGV, $parent_in->slave, $parent_out->slave, $parent_err->slave); -close $parent_in->slave; +my $pid = start_child(\@ARGV, $parent_out->slave, $parent_err->slave); close $parent_out->slave; close $parent_err->slave; -my $in_pid = copy_stdin($parent_in); copy_stdio($parent_out, $parent_err); my $ret = finish_child($pid); -# If the child process terminates before our copy_stdin() process is able to -# write all of its data to $parent_in, the copy_stdin() process could stall. -# Send SIGTERM to it to ensure it terminates. -kill 'TERM', $in_pid; -finish_child($in_pid); exit($ret); diff --git a/t/unit-tests/lib-oid.c b/t/unit-tests/lib-oid.c new file mode 100644 index 0000000000..37105f0a8f --- /dev/null +++ b/t/unit-tests/lib-oid.c @@ -0,0 +1,52 @@ +#include "test-lib.h" +#include "lib-oid.h" +#include "strbuf.h" +#include "hex.h" + +static int init_hash_algo(void) +{ + static int algo = -1; + + if (algo < 0) { + const char *algo_name = getenv("GIT_TEST_DEFAULT_HASH"); + algo = algo_name ? hash_algo_by_name(algo_name) : GIT_HASH_SHA1; + + if (!check(algo != GIT_HASH_UNKNOWN)) + test_msg("BUG: invalid GIT_TEST_DEFAULT_HASH value ('%s')", + algo_name); + } + return algo; +} + +static int get_oid_arbitrary_hex_algop(const char *hex, struct object_id *oid, + const struct git_hash_algo *algop) +{ + int ret; + size_t sz = strlen(hex); + struct strbuf buf = STRBUF_INIT; + + if (!check(sz <= algop->hexsz)) { + test_msg("BUG: hex string (%s) bigger than maximum allowed (%lu)", + hex, (unsigned long)algop->hexsz); + return -1; + } + + strbuf_add(&buf, hex, sz); + strbuf_addchars(&buf, '0', algop->hexsz - sz); + + ret = get_oid_hex_algop(buf.buf, oid, algop); + if (!check_int(ret, ==, 0)) + test_msg("BUG: invalid hex input (%s) provided", hex); + + strbuf_release(&buf); + return ret; +} + +int get_oid_arbitrary_hex(const char *hex, struct object_id *oid) +{ + int hash_algo = init_hash_algo(); + + if (!check_int(hash_algo, !=, GIT_HASH_UNKNOWN)) + return -1; + return get_oid_arbitrary_hex_algop(hex, oid, &hash_algos[hash_algo]); +} diff --git a/t/unit-tests/lib-oid.h b/t/unit-tests/lib-oid.h new file mode 100644 index 0000000000..8d2acca768 --- /dev/null +++ b/t/unit-tests/lib-oid.h @@ -0,0 +1,17 @@ +#ifndef LIB_OID_H +#define LIB_OID_H + +#include "hash.h" + +/* + * Convert arbitrary hex string to object_id. + * For example, passing "abc12" will generate + * "abc1200000000000000000000000000000000000" hex of length 40 for SHA-1 and + * create object_id with that. + * WARNING: passing a string of length more than the hexsz of respective hash + * algo is not allowed. The hash algo is decided based on GIT_TEST_DEFAULT_HASH + * environment variable. + */ +int get_oid_arbitrary_hex(const char *s, struct object_id *oid); + +#endif /* LIB_OID_H */ diff --git a/t/unit-tests/t-example-decorate.c b/t/unit-tests/t-example-decorate.c new file mode 100644 index 0000000000..a4a75db735 --- /dev/null +++ b/t/unit-tests/t-example-decorate.c @@ -0,0 +1,82 @@ +#define USE_THE_REPOSITORY_VARIABLE + +#include "test-lib.h" +#include "object.h" +#include "decorate.h" +#include "repository.h" + +struct test_vars { + struct object *one, *two, *three; + struct decoration n; + int decoration_a, decoration_b; +}; + +static void t_add(struct test_vars *vars) +{ + void *ret = add_decoration(&vars->n, vars->one, &vars->decoration_a); + + if (!check(ret == NULL)) + test_msg("when adding a brand-new object, NULL should be returned"); + ret = add_decoration(&vars->n, vars->two, NULL); + if (!check(ret == NULL)) + test_msg("when adding a brand-new object, NULL should be returned"); +} + +static void t_readd(struct test_vars *vars) +{ + void *ret = add_decoration(&vars->n, vars->one, NULL); + + if (!check(ret == &vars->decoration_a)) + test_msg("when readding an already existing object, existing decoration should be returned"); + ret = add_decoration(&vars->n, vars->two, &vars->decoration_b); + if (!check(ret == NULL)) + test_msg("when readding an already existing object, existing decoration should be returned"); +} + +static void t_lookup(struct test_vars *vars) +{ + void *ret = lookup_decoration(&vars->n, vars->one); + + if (!check(ret == NULL)) + test_msg("lookup should return added declaration"); + ret = lookup_decoration(&vars->n, vars->two); + if (!check(ret == &vars->decoration_b)) + test_msg("lookup should return added declaration"); + ret = lookup_decoration(&vars->n, vars->three); + if (!check(ret == NULL)) + test_msg("lookup for unknown object should return NULL"); +} + +static void t_loop(struct test_vars *vars) +{ + int i, objects_noticed = 0; + + for (i = 0; i < vars->n.size; i++) { + if (vars->n.entries[i].base) + objects_noticed++; + } + if (!check_int(objects_noticed, ==, 2)) + test_msg("should have 2 objects"); +} + +int cmd_main(int argc UNUSED, const char **argv UNUSED) +{ + struct object_id one_oid = { { 1 } }, two_oid = { { 2 } }, three_oid = { { 3 } }; + struct test_vars vars = { 0 }; + + vars.one = lookup_unknown_object(the_repository, &one_oid); + vars.two = lookup_unknown_object(the_repository, &two_oid); + vars.three = lookup_unknown_object(the_repository, &three_oid); + + TEST(t_add(&vars), + "Add 2 objects, one with a non-NULL decoration and one with a NULL decoration."); + TEST(t_readd(&vars), + "When re-adding an already existing object, the old decoration is returned."); + TEST(t_lookup(&vars), + "Lookup returns the added declarations, or NULL if the object was never added."); + TEST(t_loop(&vars), "The user can also loop through all entries."); + + clear_decoration(&vars.n, NULL); + + return test_done(); +} diff --git a/t/unit-tests/t-hash.c b/t/unit-tests/t-hash.c new file mode 100644 index 0000000000..e9a78bf2c0 --- /dev/null +++ b/t/unit-tests/t-hash.c @@ -0,0 +1,84 @@ +#include "test-lib.h" +#include "hex.h" +#include "strbuf.h" + +static void check_hash_data(const void *data, size_t data_length, + const char *expected_hashes[]) +{ + if (!check(data != NULL)) { + test_msg("BUG: NULL data pointer provided"); + return; + } + + for (size_t i = 1; i < ARRAY_SIZE(hash_algos); i++) { + git_hash_ctx ctx; + unsigned char hash[GIT_MAX_HEXSZ]; + const struct git_hash_algo *algop = &hash_algos[i]; + + algop->init_fn(&ctx); + algop->update_fn(&ctx, data, data_length); + algop->final_fn(hash, &ctx); + + if (!check_str(hash_to_hex_algop(hash, algop), expected_hashes[i - 1])) + test_msg("result does not match with the expected for %s\n", hash_algos[i].name); + } +} + +/* Works with a NUL terminated string. Doesn't work if it should contain a NUL character. */ +#define TEST_HASH_STR(data, expected_sha1, expected_sha256) do { \ + const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ + TEST(check_hash_data(data, strlen(data), expected_hashes), \ + "SHA1 and SHA256 (%s) works", #data); \ + } while (0) + +/* Only works with a literal string, useful when it contains a NUL character. */ +#define TEST_HASH_LITERAL(literal, expected_sha1, expected_sha256) do { \ + const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ + TEST(check_hash_data(literal, (sizeof(literal) - 1), expected_hashes), \ + "SHA1 and SHA256 (%s) works", #literal); \ + } while (0) + +int cmd_main(int argc, const char **argv) +{ + struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT; + struct strbuf alphabet_100000 = STRBUF_INIT; + + strbuf_addstrings(&aaaaaaaaaa_100000, "aaaaaaaaaa", 100000); + strbuf_addstrings(&alphabet_100000, "abcdefghijklmnopqrstuvwxyz", 100000); + + TEST_HASH_STR("", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + TEST_HASH_STR("a", + "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", + "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"); + TEST_HASH_STR("abc", + "a9993e364706816aba3e25717850c26c9cd0d89d", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + TEST_HASH_STR("message digest", + "c12252ceda8be8994d5fa0290a47231c1d16aae3", + "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"); + TEST_HASH_STR("abcdefghijklmnopqrstuvwxyz", + "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", + "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73"); + TEST_HASH_STR(aaaaaaaaaa_100000.buf, + "34aa973cd4c4daa4f61eeb2bdbad27316534016f", + "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + TEST_HASH_STR(alphabet_100000.buf, + "e7da7c55b3484fdf52aebec9cbe7b85a98f02fd4", + "e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35"); + TEST_HASH_LITERAL("blob 0\0", + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813"); + TEST_HASH_LITERAL("blob 3\0abc", + "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f", + "c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6"); + TEST_HASH_LITERAL("tree 0\0", + "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321"); + + strbuf_release(&aaaaaaaaaa_100000); + strbuf_release(&alphabet_100000); + + return test_done(); +} diff --git a/t/unit-tests/t-oidmap.c b/t/unit-tests/t-oidmap.c new file mode 100644 index 0000000000..b22e52d08b --- /dev/null +++ b/t/unit-tests/t-oidmap.c @@ -0,0 +1,181 @@ +#include "test-lib.h" +#include "lib-oid.h" +#include "oidmap.h" +#include "hash.h" +#include "hex.h" + +/* + * Elements we will put in oidmap structs are made of a key: the entry.oid + * field, which is of type struct object_id, and a value: the name field (could + * be a refname for example). + */ +struct test_entry { + struct oidmap_entry entry; + char name[FLEX_ARRAY]; +}; + +static const char *const key_val[][2] = { { "11", "one" }, + { "22", "two" }, + { "33", "three" } }; + +static void setup(void (*f)(struct oidmap *map)) +{ + struct oidmap map = OIDMAP_INIT; + int ret = 0; + + for (size_t i = 0; i < ARRAY_SIZE(key_val); i++){ + struct test_entry *entry; + + FLEX_ALLOC_STR(entry, name, key_val[i][1]); + if ((ret = get_oid_arbitrary_hex(key_val[i][0], &entry->entry.oid))) { + free(entry); + break; + } + entry = oidmap_put(&map, entry); + if (!check(entry == NULL)) + free(entry); + } + + if (!ret) + f(&map); + oidmap_free(&map, 1); +} + +static void t_replace(struct oidmap *map) +{ + struct test_entry *entry, *prev; + + FLEX_ALLOC_STR(entry, name, "un"); + if (get_oid_arbitrary_hex("11", &entry->entry.oid)) + return; + prev = oidmap_put(map, entry); + if (!check(prev != NULL)) + return; + check_str(prev->name, "one"); + free(prev); + + FLEX_ALLOC_STR(entry, name, "deux"); + if (get_oid_arbitrary_hex("22", &entry->entry.oid)) + return; + prev = oidmap_put(map, entry); + if (!check(prev != NULL)) + return; + check_str(prev->name, "two"); + free(prev); +} + +static void t_get(struct oidmap *map) +{ + struct test_entry *entry; + struct object_id oid; + + if (get_oid_arbitrary_hex("22", &oid)) + return; + entry = oidmap_get(map, &oid); + if (!check(entry != NULL)) + return; + check_str(entry->name, "two"); + + if (get_oid_arbitrary_hex("44", &oid)) + return; + check(oidmap_get(map, &oid) == NULL); + + if (get_oid_arbitrary_hex("11", &oid)) + return; + entry = oidmap_get(map, &oid); + if (!check(entry != NULL)) + return; + check_str(entry->name, "one"); +} + +static void t_remove(struct oidmap *map) +{ + struct test_entry *entry; + struct object_id oid; + + if (get_oid_arbitrary_hex("11", &oid)) + return; + entry = oidmap_remove(map, &oid); + if (!check(entry != NULL)) + return; + check_str(entry->name, "one"); + check(oidmap_get(map, &oid) == NULL); + free(entry); + + if (get_oid_arbitrary_hex("22", &oid)) + return; + entry = oidmap_remove(map, &oid); + if (!check(entry != NULL)) + return; + check_str(entry->name, "two"); + check(oidmap_get(map, &oid) == NULL); + free(entry); + + if (get_oid_arbitrary_hex("44", &oid)) + return; + check(oidmap_remove(map, &oid) == NULL); +} + +static int key_val_contains(struct test_entry *entry, char seen[]) +{ + for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) { + struct object_id oid; + + if (get_oid_arbitrary_hex(key_val[i][0], &oid)) + return -1; + + if (oideq(&entry->entry.oid, &oid)) { + if (seen[i]) + return 2; + seen[i] = 1; + return 0; + } + } + return 1; +} + +static void t_iterate(struct oidmap *map) +{ + struct oidmap_iter iter; + struct test_entry *entry; + char seen[ARRAY_SIZE(key_val)] = { 0 }; + int count = 0; + + oidmap_iter_init(map, &iter); + while ((entry = oidmap_iter_next(&iter))) { + int ret; + if (!check_int((ret = key_val_contains(entry, seen)), ==, 0)) { + switch (ret) { + case -1: + break; /* error message handled by get_oid_arbitrary_hex() */ + case 1: + test_msg("obtained entry was not given in the input\n" + " name: %s\n oid: %s\n", + entry->name, oid_to_hex(&entry->entry.oid)); + break; + case 2: + test_msg("duplicate entry detected\n" + " name: %s\n oid: %s\n", + entry->name, oid_to_hex(&entry->entry.oid)); + break; + default: + test_msg("BUG: invalid return value (%d) from key_val_contains()", + ret); + break; + } + } else { + count++; + } + } + check_int(count, ==, ARRAY_SIZE(key_val)); + check_int(hashmap_get_size(&map->map), ==, ARRAY_SIZE(key_val)); +} + +int cmd_main(int argc UNUSED, const char **argv UNUSED) +{ + TEST(setup(t_replace), "replace works"); + TEST(setup(t_get), "get works"); + TEST(setup(t_remove), "remove works"); + TEST(setup(t_iterate), "iterate works"); + return test_done(); +} diff --git a/t/unit-tests/t-oidtree.c b/t/unit-tests/t-oidtree.c new file mode 100644 index 0000000000..a38754b066 --- /dev/null +++ b/t/unit-tests/t-oidtree.c @@ -0,0 +1,122 @@ +#include "test-lib.h" +#include "lib-oid.h" +#include "oidtree.h" +#include "hash.h" +#include "hex.h" +#include "strvec.h" + +#define FILL_TREE(tree, ...) \ + do { \ + const char *hexes[] = { __VA_ARGS__ }; \ + if (fill_tree_loc(tree, hexes, ARRAY_SIZE(hexes))) \ + return; \ + } while (0) + +static int fill_tree_loc(struct oidtree *ot, const char *hexes[], size_t n) +{ + for (size_t i = 0; i < n; i++) { + struct object_id oid; + if (!check_int(get_oid_arbitrary_hex(hexes[i], &oid), ==, 0)) + return -1; + oidtree_insert(ot, &oid); + } + return 0; +} + +static void check_contains(struct oidtree *ot, const char *hex, int expected) +{ + struct object_id oid; + + if (!check_int(get_oid_arbitrary_hex(hex, &oid), ==, 0)) + return; + if (!check_int(oidtree_contains(ot, &oid), ==, expected)) + test_msg("oid: %s", oid_to_hex(&oid)); +} + +struct expected_hex_iter { + size_t i; + struct strvec expected_hexes; + const char *query; +}; + +static enum cb_next check_each_cb(const struct object_id *oid, void *data) +{ + struct expected_hex_iter *hex_iter = data; + struct object_id expected; + + if (!check_int(hex_iter->i, <, hex_iter->expected_hexes.nr)) { + test_msg("error: extraneous callback for query: ('%s'), object_id: ('%s')", + hex_iter->query, oid_to_hex(oid)); + return CB_BREAK; + } + + if (!check_int(get_oid_arbitrary_hex(hex_iter->expected_hexes.v[hex_iter->i], + &expected), ==, 0)) + ; /* the data is bogus and cannot be used */ + else if (!check(oideq(oid, &expected))) + test_msg("expected: %s\n got: %s\n query: %s", + oid_to_hex(&expected), oid_to_hex(oid), hex_iter->query); + + hex_iter->i += 1; + return CB_CONTINUE; +} + +LAST_ARG_MUST_BE_NULL +static void check_each(struct oidtree *ot, const char *query, ...) +{ + struct object_id oid; + struct expected_hex_iter hex_iter = { .expected_hexes = STRVEC_INIT, + .query = query }; + const char *arg; + va_list hex_args; + + va_start(hex_args, query); + while ((arg = va_arg(hex_args, const char *))) + strvec_push(&hex_iter.expected_hexes, arg); + va_end(hex_args); + + if (!check_int(get_oid_arbitrary_hex(query, &oid), ==, 0)) + return; + oidtree_each(ot, &oid, strlen(query), check_each_cb, &hex_iter); + + if (!check_int(hex_iter.i, ==, hex_iter.expected_hexes.nr)) + test_msg("error: could not find some 'object_id's for query ('%s')", query); + strvec_clear(&hex_iter.expected_hexes); +} + +static void setup(void (*f)(struct oidtree *ot)) +{ + struct oidtree ot; + + oidtree_init(&ot); + f(&ot); + oidtree_clear(&ot); +} + +static void t_contains(struct oidtree *ot) +{ + FILL_TREE(ot, "444", "1", "2", "3", "4", "5", "a", "b", "c", "d", "e"); + check_contains(ot, "44", 0); + check_contains(ot, "441", 0); + check_contains(ot, "440", 0); + check_contains(ot, "444", 1); + check_contains(ot, "4440", 1); + check_contains(ot, "4444", 0); +} + +static void t_each(struct oidtree *ot) +{ + FILL_TREE(ot, "f", "9", "8", "123", "321", "320", "a", "b", "c", "d", "e"); + check_each(ot, "12300", "123", NULL); + check_each(ot, "3211", NULL); /* should not reach callback */ + check_each(ot, "3210", "321", NULL); + check_each(ot, "32100", "321", NULL); + check_each(ot, "32", "320", "321", NULL); +} + +int cmd_main(int argc UNUSED, const char **argv UNUSED) +{ + TEST(setup(t_contains), "oidtree insert and contains works"); + TEST(setup(t_each), "oidtree each works"); + return test_done(); +} diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c new file mode 100644 index 0000000000..4e80bdf16d --- /dev/null +++ b/t/unit-tests/t-reftable-basics.c @@ -0,0 +1,160 @@ +/* +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 test_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); + check_int(idx, ==, testcases[i].expected_idx); + } +} + +static void test_names_length(void) +{ + const char *a[] = { "a", "b", NULL }; + check_int(names_length(a), ==, 2); +} + +static void test_names_equal(void) +{ + 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)); +} + +static void test_parse_names_normal(void) +{ + char in1[] = "line\n"; + char in2[] = "a\nb\nc"; + char **out = NULL; + parse_names(in1, strlen(in1), &out); + check_str(out[0], "line"); + check(!out[1]); + free_names(out); + + parse_names(in2, strlen(in2), &out); + check_str(out[0], "a"); + check_str(out[1], "b"); + check_str(out[2], "c"); + check(!out[3]); + free_names(out); +} + +static void test_parse_names_drop_empty(void) +{ + char in[] = "a\n\nb\n"; + char **out = NULL; + parse_names(in, strlen(in), &out); + check_str(out[0], "a"); + /* simply '\n' should be dropped as empty string */ + check_str(out[1], "b"); + check(!out[2]); + free_names(out); +} + +static void test_common_prefix(void) +{ + struct strbuf a = STRBUF_INIT; + struct strbuf b = STRBUF_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++) { + strbuf_addstr(&a, cases[i].a); + strbuf_addstr(&b, cases[i].b); + check_int(common_prefix_size(&a, &b), ==, cases[i].want); + strbuf_reset(&a); + strbuf_reset(&b); + } + strbuf_release(&a); + strbuf_release(&b); +} + +static void test_u24_roundtrip(void) +{ + uint32_t in = 0x112233; + uint8_t dest[3]; + uint32_t out; + put_be24(dest, in); + out = get_be24(dest); + check_int(in, ==, out); +} + +static void test_u16_roundtrip(void) +{ + uint32_t in = 0xfef1; + uint8_t dest[3]; + uint32_t out; + put_be16(dest, in); + out = get_be16(dest); + check_int(in, ==, out); +} + +int cmd_main(int argc, const char *argv[]) +{ + TEST(test_common_prefix(), "common_prefix_size works"); + TEST(test_parse_names_normal(), "parse_names works for basic input"); + TEST(test_parse_names_drop_empty(), "parse_names drops empty string"); + TEST(test_binsearch(), "binary search with binsearch works"); + TEST(test_names_length(), "names_length retuns size of a NULL-terminated string array"); + TEST(test_names_equal(), "names_equal compares NULL-terminated string arrays"); + TEST(test_u24_roundtrip(), "put_be24 and get_be24 work"); + TEST(test_u16_roundtrip(), "put_be16 and get_be16 work"); + + return test_done(); +} diff --git a/reftable/merged_test.c b/t/unit-tests/t-reftable-merged.c index 33a17efcde..b6263ee8b5 100644 --- a/reftable/merged_test.c +++ b/t/unit-tests/t-reftable-merged.c @@ -6,27 +6,33 @@ license that can be found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd */ -#include "merged.h" - -#include "system.h" +#include "test-lib.h" +#include "reftable/blocksource.h" +#include "reftable/constants.h" +#include "reftable/merged.h" +#include "reftable/reader.h" +#include "reftable/reftable-error.h" +#include "reftable/reftable-generic.h" +#include "reftable/reftable-merged.h" +#include "reftable/reftable-writer.h" + +static ssize_t strbuf_add_void(void *b, const void *data, const size_t sz) +{ + strbuf_add(b, data, sz); + return sz; +} -#include "basics.h" -#include "blocksource.h" -#include "constants.h" -#include "reader.h" -#include "record.h" -#include "test_framework.h" -#include "reftable-merged.h" -#include "reftable-tests.h" -#include "reftable-generic.h" -#include "reftable-writer.h" +static int noop_flush(void *arg) +{ + return 0; +} static void write_test_table(struct strbuf *buf, - struct reftable_ref_record refs[], int n) + struct reftable_ref_record refs[], const size_t n) { uint64_t min = 0xffffffff; uint64_t max = 0; - int i = 0; + size_t i; int err; struct reftable_write_options opts = { @@ -35,12 +41,10 @@ static void write_test_table(struct strbuf *buf, struct reftable_writer *w = NULL; for (i = 0; i < n; i++) { uint64_t ui = refs[i].update_index; - if (ui > max) { + if (ui > max) max = ui; - } - if (ui < min) { + if (ui < min) min = ui; - } } w = reftable_new_writer(&strbuf_add_void, &noop_flush, buf, &opts); @@ -49,21 +53,19 @@ static void write_test_table(struct strbuf *buf, for (i = 0; i < n; i++) { uint64_t before = refs[i].update_index; int n = reftable_writer_add_ref(w, &refs[i]); - EXPECT(n == 0); - EXPECT(before == refs[i].update_index); + check_int(n, ==, 0); + check_int(before, ==, refs[i].update_index); } err = reftable_writer_close(w); - EXPECT_ERR(err); + check(!err); reftable_writer_free(w); } -static void write_test_log_table(struct strbuf *buf, - struct reftable_log_record logs[], int n, - uint64_t update_index) +static void write_test_log_table(struct strbuf *buf, struct reftable_log_record logs[], + const size_t n, const uint64_t update_index) { - int i = 0; int err; struct reftable_write_options opts = { @@ -74,13 +76,13 @@ static void write_test_log_table(struct strbuf *buf, w = reftable_new_writer(&strbuf_add_void, &noop_flush, buf, &opts); reftable_writer_set_limits(w, update_index, update_index); - for (i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { int err = reftable_writer_add_log(w, &logs[i]); - EXPECT_ERR(err); + check(!err); } err = reftable_writer_close(w); - EXPECT_ERR(err); + check(!err); reftable_writer_free(w); } @@ -88,8 +90,8 @@ static void write_test_log_table(struct strbuf *buf, static struct reftable_merged_table * merged_table_from_records(struct reftable_ref_record **refs, struct reftable_block_source **source, - struct reftable_reader ***readers, int *sizes, - struct strbuf *buf, size_t n) + struct reftable_reader ***readers, const size_t *sizes, + struct strbuf *buf, const size_t n) { struct reftable_merged_table *mt = NULL; struct reftable_table *tabs; @@ -105,102 +107,104 @@ merged_table_from_records(struct reftable_ref_record **refs, err = reftable_new_reader(&(*readers)[i], &(*source)[i], "name"); - EXPECT_ERR(err); + check(!err); reftable_table_from_reader(&tabs[i], (*readers)[i]); } err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID); - EXPECT_ERR(err); + check(!err); return mt; } -static void readers_destroy(struct reftable_reader **readers, size_t n) +static void readers_destroy(struct reftable_reader **readers, const size_t n) { - int i = 0; - for (; i < n; i++) + for (size_t i = 0; i < n; i++) reftable_reader_free(readers[i]); reftable_free(readers); } -static void test_merged_between(void) +static void t_merged_single_record(void) { struct reftable_ref_record r1[] = { { - .refname = "b", + .refname = (char *) "b", .update_index = 1, .value_type = REFTABLE_REF_VAL1, .value.val1 = { 1, 2, 3, 0 }, } }; struct reftable_ref_record r2[] = { { - .refname = "a", + .refname = (char *) "a", .update_index = 2, .value_type = REFTABLE_REF_DELETION, } }; + struct reftable_ref_record r3[] = { { + .refname = (char *) "c", + .update_index = 3, + .value_type = REFTABLE_REF_DELETION, + } }; - struct reftable_ref_record *refs[] = { r1, r2 }; - int sizes[] = { 1, 1 }; - struct strbuf bufs[2] = { STRBUF_INIT, STRBUF_INIT }; + struct reftable_ref_record *refs[] = { r1, r2, r3 }; + size_t sizes[] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; + struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }; struct reftable_block_source *bs = NULL; struct reftable_reader **readers = NULL; struct reftable_merged_table *mt = - merged_table_from_records(refs, &bs, &readers, sizes, bufs, 2); - int i; - struct reftable_ref_record ref = { NULL }; - struct reftable_iterator it = { NULL }; + merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3); + struct reftable_ref_record ref = { 0 }; + struct reftable_iterator it = { 0 }; int err; merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); err = reftable_iterator_seek_ref(&it, "a"); - EXPECT_ERR(err); + check(!err); err = reftable_iterator_next_ref(&it, &ref); - EXPECT_ERR(err); - EXPECT(ref.update_index == 2); + check(!err); + check(reftable_ref_record_equal(&r2[0], &ref, GIT_SHA1_RAWSZ)); reftable_ref_record_release(&ref); reftable_iterator_destroy(&it); - readers_destroy(readers, 2); + readers_destroy(readers, 3); reftable_merged_table_free(mt); - for (i = 0; i < ARRAY_SIZE(bufs); i++) { + for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) strbuf_release(&bufs[i]); - } reftable_free(bs); } -static void test_merged(void) +static void t_merged_refs(void) { struct reftable_ref_record r1[] = { { - .refname = "a", + .refname = (char *) "a", .update_index = 1, .value_type = REFTABLE_REF_VAL1, .value.val1 = { 1 }, }, { - .refname = "b", + .refname = (char *) "b", .update_index = 1, .value_type = REFTABLE_REF_VAL1, .value.val1 = { 1 }, }, { - .refname = "c", + .refname = (char *) "c", .update_index = 1, .value_type = REFTABLE_REF_VAL1, .value.val1 = { 1 }, } }; struct reftable_ref_record r2[] = { { - .refname = "a", + .refname = (char *) "a", .update_index = 2, .value_type = REFTABLE_REF_DELETION, } }; struct reftable_ref_record r3[] = { { - .refname = "c", + .refname = (char *) "c", .update_index = 3, .value_type = REFTABLE_REF_VAL1, .value.val1 = { 2 }, }, { - .refname = "d", + .refname = (char *) "d", .update_index = 3, .value_type = REFTABLE_REF_VAL1, .value.val1 = { 1 }, @@ -215,27 +219,28 @@ static void test_merged(void) }; struct reftable_ref_record *refs[] = { r1, r2, r3 }; - int sizes[3] = { 3, 1, 2 }; + size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }; struct reftable_block_source *bs = NULL; struct reftable_reader **readers = NULL; struct reftable_merged_table *mt = merged_table_from_records(refs, &bs, &readers, sizes, bufs, 3); - struct reftable_iterator it = { NULL }; + struct reftable_iterator it = { 0 }; int err; struct reftable_ref_record *out = NULL; size_t len = 0; size_t cap = 0; - int i = 0; + size_t i; merged_table_init_iter(mt, &it, BLOCK_TYPE_REF); err = reftable_iterator_seek_ref(&it, "a"); - EXPECT_ERR(err); - EXPECT(reftable_merged_table_hash_id(mt) == GIT_SHA1_FORMAT_ID); - EXPECT(reftable_merged_table_min_update_index(mt) == 1); + check(!err); + check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID); + check_int(reftable_merged_table_min_update_index(mt), ==, 1); + check_int(reftable_merged_table_max_update_index(mt), ==, 3); while (len < 100) { /* cap loops/recursion. */ - struct reftable_ref_record ref = { NULL }; + struct reftable_ref_record ref = { 0 }; int err = reftable_iterator_next_ref(&it, &ref); if (err > 0) break; @@ -245,19 +250,16 @@ static void test_merged(void) } reftable_iterator_destroy(&it); - EXPECT(ARRAY_SIZE(want) == len); - for (i = 0; i < len; i++) { - EXPECT(reftable_ref_record_equal(want[i], &out[i], + check_int(ARRAY_SIZE(want), ==, len); + for (i = 0; i < len; i++) + check(reftable_ref_record_equal(want[i], &out[i], GIT_SHA1_RAWSZ)); - } - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) reftable_ref_record_release(&out[i]); - } reftable_free(out); - for (i = 0; i < 3; i++) { + for (i = 0; i < 3; i++) strbuf_release(&bufs[i]); - } readers_destroy(readers, 3); reftable_merged_table_free(mt); reftable_free(bs); @@ -266,8 +268,8 @@ static void test_merged(void) static struct reftable_merged_table * merged_table_from_log_records(struct reftable_log_record **logs, struct reftable_block_source **source, - struct reftable_reader ***readers, int *sizes, - struct strbuf *buf, size_t n) + struct reftable_reader ***readers, const size_t *sizes, + struct strbuf *buf, const size_t n) { struct reftable_merged_table *mt = NULL; struct reftable_table *tabs; @@ -283,59 +285,59 @@ merged_table_from_log_records(struct reftable_log_record **logs, err = reftable_new_reader(&(*readers)[i], &(*source)[i], "name"); - EXPECT_ERR(err); + check(!err); reftable_table_from_reader(&tabs[i], (*readers)[i]); } err = reftable_new_merged_table(&mt, tabs, n, GIT_SHA1_FORMAT_ID); - EXPECT_ERR(err); + check(!err); return mt; } -static void test_merged_logs(void) +static void t_merged_logs(void) { struct reftable_log_record r1[] = { { - .refname = "a", + .refname = (char *) "a", .update_index = 2, .value_type = REFTABLE_LOG_UPDATE, .value.update = { .old_hash = { 2 }, /* deletion */ - .name = "jane doe", - .email = "jane@invalid", - .message = "message2", + .name = (char *) "jane doe", + .email = (char *) "jane@invalid", + .message = (char *) "message2", } }, { - .refname = "a", + .refname = (char *) "a", .update_index = 1, .value_type = REFTABLE_LOG_UPDATE, .value.update = { .old_hash = { 1 }, .new_hash = { 2 }, - .name = "jane doe", - .email = "jane@invalid", - .message = "message1", + .name = (char *) "jane doe", + .email = (char *) "jane@invalid", + .message = (char *) "message1", } }, }; struct reftable_log_record r2[] = { { - .refname = "a", + .refname = (char *) "a", .update_index = 3, .value_type = REFTABLE_LOG_UPDATE, .value.update = { .new_hash = { 3 }, - .name = "jane doe", - .email = "jane@invalid", - .message = "message3", + .name = (char *) "jane doe", + .email = (char *) "jane@invalid", + .message = (char *) "message3", } }, }; struct reftable_log_record r3[] = { { - .refname = "a", + .refname = (char *) "a", .update_index = 2, .value_type = REFTABLE_LOG_DELETION, }, @@ -347,27 +349,28 @@ static void test_merged_logs(void) }; struct reftable_log_record *logs[] = { r1, r2, r3 }; - int sizes[3] = { 2, 1, 1 }; + size_t sizes[3] = { ARRAY_SIZE(r1), ARRAY_SIZE(r2), ARRAY_SIZE(r3) }; struct strbuf bufs[3] = { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }; struct reftable_block_source *bs = NULL; struct reftable_reader **readers = NULL; struct reftable_merged_table *mt = merged_table_from_log_records( logs, &bs, &readers, sizes, bufs, 3); - struct reftable_iterator it = { NULL }; + struct reftable_iterator it = { 0 }; int err; struct reftable_log_record *out = NULL; size_t len = 0; size_t cap = 0; - int i = 0; + size_t i; merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG); err = reftable_iterator_seek_log(&it, "a"); - EXPECT_ERR(err); - EXPECT(reftable_merged_table_hash_id(mt) == GIT_SHA1_FORMAT_ID); - EXPECT(reftable_merged_table_min_update_index(mt) == 1); + check(!err); + check_int(reftable_merged_table_hash_id(mt), ==, GIT_SHA1_FORMAT_ID); + check_int(reftable_merged_table_min_update_index(mt), ==, 1); + check_int(reftable_merged_table_max_update_index(mt), ==, 3); while (len < 100) { /* cap loops/recursion. */ - struct reftable_log_record log = { NULL }; + struct reftable_log_record log = { 0 }; int err = reftable_iterator_next_log(&it, &log); if (err > 0) break; @@ -377,35 +380,32 @@ static void test_merged_logs(void) } reftable_iterator_destroy(&it); - EXPECT(ARRAY_SIZE(want) == len); - for (i = 0; i < len; i++) { - EXPECT(reftable_log_record_equal(want[i], &out[i], + check_int(ARRAY_SIZE(want), ==, len); + for (i = 0; i < len; i++) + check(reftable_log_record_equal(want[i], &out[i], GIT_SHA1_RAWSZ)); - } merged_table_init_iter(mt, &it, BLOCK_TYPE_LOG); err = reftable_iterator_seek_log_at(&it, "a", 2); - EXPECT_ERR(err); + check(!err); reftable_log_record_release(&out[0]); err = reftable_iterator_next_log(&it, &out[0]); - EXPECT_ERR(err); - EXPECT(reftable_log_record_equal(&out[0], &r3[0], GIT_SHA1_RAWSZ)); + check(!err); + check(reftable_log_record_equal(&out[0], &r3[0], GIT_SHA1_RAWSZ)); reftable_iterator_destroy(&it); - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) reftable_log_record_release(&out[i]); - } reftable_free(out); - for (i = 0; i < 3; i++) { + for (i = 0; i < 3; i++) strbuf_release(&bufs[i]); - } readers_destroy(readers, 3); reftable_merged_table_free(mt); reftable_free(bs); } -static void test_default_write_opts(void) +static void t_default_write_opts(void) { struct reftable_write_options opts = { 0 }; struct strbuf buf = STRBUF_INIT; @@ -413,11 +413,11 @@ static void test_default_write_opts(void) reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts); struct reftable_ref_record rec = { - .refname = "master", + .refname = (char *) "master", .update_index = 1, }; int err; - struct reftable_block_source source = { NULL }; + struct reftable_block_source source = { 0 }; struct reftable_table *tab = reftable_calloc(1, sizeof(*tab)); uint32_t hash_id; struct reftable_reader *rd = NULL; @@ -426,36 +426,38 @@ static void test_default_write_opts(void) reftable_writer_set_limits(w, 1, 1); err = reftable_writer_add_ref(w, &rec); - EXPECT_ERR(err); + check(!err); err = reftable_writer_close(w); - EXPECT_ERR(err); + check(!err); reftable_writer_free(w); block_source_from_strbuf(&source, &buf); err = reftable_new_reader(&rd, &source, "filename"); - EXPECT_ERR(err); + check(!err); hash_id = reftable_reader_hash_id(rd); - EXPECT(hash_id == GIT_SHA1_FORMAT_ID); + check_int(hash_id, ==, GIT_SHA1_FORMAT_ID); reftable_table_from_reader(&tab[0], rd); + err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA256_FORMAT_ID); + check_int(err, ==, REFTABLE_FORMAT_ERROR); err = reftable_new_merged_table(&merged, tab, 1, GIT_SHA1_FORMAT_ID); - EXPECT_ERR(err); + check(!err); reftable_reader_free(rd); reftable_merged_table_free(merged); strbuf_release(&buf); } -/* XXX test refs_for(oid) */ -int merged_test_main(int argc, const char *argv[]) +int cmd_main(int argc, const char *argv[]) { - RUN_TEST(test_merged_logs); - RUN_TEST(test_merged_between); - RUN_TEST(test_merged); - RUN_TEST(test_default_write_opts); - return 0; + 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_single_record(), "ref ocurring in only one record can be fetched"); + + return test_done(); } diff --git a/t/unit-tests/t-reftable-pq.c b/t/unit-tests/t-reftable-pq.c new file mode 100644 index 0000000000..039bd0f1f9 --- /dev/null +++ b/t/unit-tests/t-reftable-pq.c @@ -0,0 +1,152 @@ +/* +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/constants.h" +#include "reftable/pq.h" + +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])); + } +} + +static int pq_entry_equal(struct pq_entry *a, struct pq_entry *b) +{ + return !reftable_record_cmp(a->rec, b->rec) && (a->index == b->index); +} + +static void t_pq_record(void) +{ + struct merged_iter_pqueue pq = { 0 }; + struct reftable_record recs[54]; + size_t N = ARRAY_SIZE(recs) - 1, i; + char *last = NULL; + + for (i = 0; i < N; i++) { + reftable_record_init(&recs[i], BLOCK_TYPE_REF); + recs[i].u.ref.refname = xstrfmt("%02"PRIuMAX, (uintmax_t)i); + } + + i = 1; + do { + struct pq_entry e = { + .rec = &recs[i], + }; + + merged_iter_pqueue_add(&pq, &e); + merged_iter_pqueue_check(&pq); + i = (i * 7) % N; + } while (i != 1); + + while (!merged_iter_pqueue_is_empty(pq)) { + struct pq_entry top = merged_iter_pqueue_top(pq); + struct pq_entry e = merged_iter_pqueue_remove(&pq); + merged_iter_pqueue_check(&pq); + + check(pq_entry_equal(&top, &e)); + check(reftable_record_type(e.rec) == BLOCK_TYPE_REF); + if (last) + check_int(strcmp(last, e.rec->u.ref.refname), <, 0); + last = e.rec->u.ref.refname; + } + + for (i = 0; i < N; i++) + reftable_record_release(&recs[i]); + merged_iter_pqueue_release(&pq); +} + +static void t_pq_index(void) +{ + struct merged_iter_pqueue pq = { 0 }; + struct reftable_record recs[13]; + char *last = NULL; + size_t N = ARRAY_SIZE(recs), i; + + for (i = 0; i < N; i++) { + reftable_record_init(&recs[i], BLOCK_TYPE_REF); + recs[i].u.ref.refname = (char *) "refs/heads/master"; + } + + i = 1; + do { + struct pq_entry e = { + .rec = &recs[i], + .index = i, + }; + + merged_iter_pqueue_add(&pq, &e); + merged_iter_pqueue_check(&pq); + i = (i * 7) % N; + } while (i != 1); + + for (i = N - 1; i > 0; i--) { + struct pq_entry top = merged_iter_pqueue_top(pq); + struct pq_entry e = merged_iter_pqueue_remove(&pq); + merged_iter_pqueue_check(&pq); + + check(pq_entry_equal(&top, &e)); + check(reftable_record_type(e.rec) == BLOCK_TYPE_REF); + check_int(e.index, ==, i); + if (last) + check_str(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) +{ + struct merged_iter_pqueue pq = { 0 }; + struct reftable_record recs[13]; + size_t N = ARRAY_SIZE(recs), i; + + for (i = 0; i < N; i++) { + reftable_record_init(&recs[i], BLOCK_TYPE_REF); + recs[i].u.ref.refname = (char *) "refs/heads/master"; + } + + i = 1; + do { + struct pq_entry e = { + .rec = &recs[i], + .index = i, + }; + + merged_iter_pqueue_add(&pq, &e); + merged_iter_pqueue_check(&pq); + i = (i * 7) % N; + } while (i != 1); + + for (i = N - 1; i > 0; i--) { + struct pq_entry top = merged_iter_pqueue_top(pq); + struct pq_entry e = merged_iter_pqueue_remove(&pq); + + merged_iter_pqueue_check(&pq); + check(pq_entry_equal(&top, &e)); + check(reftable_record_equal(top.rec, &recs[i], GIT_SHA1_RAWSZ)); + for (size_t j = 0; i < pq.len; j++) { + check(pq_less(&top, &pq.heap[j])); + check_int(top.index, >, j); + } + } + + merged_iter_pqueue_release(&pq); +} + +int cmd_main(int argc, const char *argv[]) +{ + 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-record.c b/t/unit-tests/t-reftable-record.c new file mode 100644 index 0000000000..cb649ee419 --- /dev/null +++ b/t/unit-tests/t-reftable-record.c @@ -0,0 +1,551 @@ +/* + 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/constants.h" +#include "reftable/record.h" + +static void t_copy(struct reftable_record *rec) +{ + struct reftable_record copy; + uint8_t typ; + + typ = reftable_record_type(rec); + reftable_record_init(©, typ); + reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); + /* do it twice to catch memory leaks */ + reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); + check(reftable_record_equal(rec, ©, GIT_SHA1_RAWSZ)); + + reftable_record_release(©); +} + +static void t_varint_roundtrip(void) +{ + uint64_t inputs[] = { 0, + 1, + 27, + 127, + 128, + 257, + 4096, + ((uint64_t)1 << 63), + ((uint64_t)1 << 63) + ((uint64_t)1 << 63) - 1 }; + + for (size_t i = 0; i < ARRAY_SIZE(inputs); i++) { + uint8_t dest[10]; + + struct string_view out = { + .buf = dest, + .len = sizeof(dest), + }; + uint64_t in = inputs[i]; + int n = put_var_int(&out, in); + uint64_t got = 0; + + check_int(n, >, 0); + out.len = n; + n = get_var_int(&got, &out); + check_int(n, >, 0); + + check_int(got, ==, in); + } +} + +static void set_hash(uint8_t *h, int j) +{ + for (int i = 0; i < hash_size(GIT_SHA1_FORMAT_ID); i++) + h[i] = (j >> i) & 0xff; +} + +static void t_reftable_ref_record_comparison(void) +{ + struct reftable_record in[3] = { + { + .type = BLOCK_TYPE_REF, + .u.ref.refname = (char *) "refs/heads/master", + .u.ref.value_type = REFTABLE_REF_VAL1, + }, + { + .type = BLOCK_TYPE_REF, + .u.ref.refname = (char *) "refs/heads/master", + .u.ref.value_type = REFTABLE_REF_DELETION, + }, + { + .type = BLOCK_TYPE_REF, + .u.ref.refname = (char *) "HEAD", + .u.ref.value_type = REFTABLE_REF_SYMREF, + .u.ref.value.symref = (char *) "refs/heads/master", + }, + }; + + check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); + + check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); + + in[1].u.ref.value_type = in[0].u.ref.value_type; + check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); +} + +static void t_reftable_ref_record_compare_name(void) +{ + struct reftable_ref_record recs[3] = { + { + .refname = (char *) "refs/heads/a" + }, + { + .refname = (char *) "refs/heads/b" + }, + { + .refname = (char *) "refs/heads/a" + }, + }; + + 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); +} + +static void t_reftable_ref_record_roundtrip(void) +{ + struct strbuf scratch = STRBUF_INIT; + + for (int i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) { + struct reftable_record in = { + .type = BLOCK_TYPE_REF, + .u.ref.value_type = i, + }; + struct reftable_record out = { .type = BLOCK_TYPE_REF }; + struct strbuf key = STRBUF_INIT; + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + int n, m; + + in.u.ref.value_type = i; + switch (i) { + case REFTABLE_REF_DELETION: + break; + case REFTABLE_REF_VAL1: + set_hash(in.u.ref.value.val1, 1); + break; + case REFTABLE_REF_VAL2: + set_hash(in.u.ref.value.val2.value, 1); + set_hash(in.u.ref.value.val2.target_value, 2); + break; + case REFTABLE_REF_SYMREF: + in.u.ref.value.symref = xstrdup("target"); + break; + } + in.u.ref.refname = xstrdup("refs/heads/master"); + + t_copy(&in); + + check_int(reftable_record_val_type(&in), ==, i); + check_int(reftable_record_is_deletion(&in), ==, i == REFTABLE_REF_DELETION); + + reftable_record_key(&in, &key); + n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); + check_int(n, >, 0); + + /* decode into a non-zero reftable_record to test for leaks. */ + m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ, &scratch); + check_int(n, ==, m); + + check(reftable_ref_record_equal(&in.u.ref, &out.u.ref, + GIT_SHA1_RAWSZ)); + reftable_record_release(&in); + + strbuf_release(&key); + reftable_record_release(&out); + } + + strbuf_release(&scratch); +} + +static void t_reftable_log_record_comparison(void) +{ + struct reftable_record in[3] = { + { + .type = BLOCK_TYPE_LOG, + .u.log.refname = (char *) "refs/heads/master", + .u.log.update_index = 42, + }, + { + .type = BLOCK_TYPE_LOG, + .u.log.refname = (char *) "refs/heads/master", + .u.log.update_index = 22, + }, + { + .type = BLOCK_TYPE_LOG, + .u.log.refname = (char *) "refs/heads/main", + .u.log.update_index = 22, + }, + }; + + check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); + /* comparison should be reversed for equal keys, because + * comparison is now performed on the basis of update indices */ + check_int(reftable_record_cmp(&in[0], &in[1]), <, 0); + + in[1].u.log.update_index = in[0].u.log.update_index; + check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); +} + +static void t_reftable_log_record_compare_key(void) +{ + struct reftable_log_record logs[3] = { + { + .refname = (char *) "refs/heads/a", + .update_index = 1, + }, + { + .refname = (char *) "refs/heads/b", + .update_index = 2, + }, + { + .refname = (char *) "refs/heads/a", + .update_index = 3, + }, + }; + + check_int(reftable_log_record_compare_key(&logs[0], &logs[1]), <, 0); + check_int(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); + + check_int(reftable_log_record_compare_key(&logs[0], &logs[2]), >, 0); + check_int(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); +} + +static void t_reftable_log_record_roundtrip(void) +{ + struct reftable_log_record in[] = { + { + .refname = xstrdup("refs/heads/master"), + .update_index = 42, + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .name = xstrdup("han-wen"), + .email = xstrdup("hanwen@google.com"), + .message = xstrdup("test"), + .time = 1577123507, + .tz_offset = 100, + }, + } + }, + { + .refname = xstrdup("refs/heads/master"), + .update_index = 22, + .value_type = REFTABLE_LOG_DELETION, + }, + { + .refname = xstrdup("branch"), + .update_index = 33, + .value_type = REFTABLE_LOG_UPDATE, + } + }; + struct strbuf scratch = STRBUF_INIT; + set_hash(in[0].value.update.new_hash, 1); + set_hash(in[0].value.update.old_hash, 2); + 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])); + + for (size_t i = 0; i < ARRAY_SIZE(in); i++) { + struct reftable_record rec = { .type = BLOCK_TYPE_LOG }; + struct strbuf key = STRBUF_INIT; + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + /* populate out, to check for leaks. */ + struct reftable_record out = { + .type = BLOCK_TYPE_LOG, + .u.log = { + .refname = xstrdup("old name"), + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .name = xstrdup("old name"), + .email = xstrdup("old@email"), + .message = xstrdup("old message"), + }, + }, + }, + }; + int n, m, valtype; + + rec.u.log = in[i]; + + t_copy(&rec); + + reftable_record_key(&rec, &key); + + n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ); + check_int(n, >=, 0); + valtype = reftable_record_val_type(&rec); + m = reftable_record_decode(&out, key, valtype, dest, + GIT_SHA1_RAWSZ, &scratch); + check_int(n, ==, m); + + check(reftable_log_record_equal(&in[i], &out.u.log, + GIT_SHA1_RAWSZ)); + reftable_log_record_release(&in[i]); + strbuf_release(&key); + reftable_record_release(&out); + } + + strbuf_release(&scratch); +} + +static void t_key_roundtrip(void) +{ + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + struct strbuf last_key = STRBUF_INIT; + struct strbuf key = STRBUF_INIT; + struct strbuf roundtrip = STRBUF_INIT; + int restart; + uint8_t extra; + int n, m; + uint8_t rt_extra; + + strbuf_addstr(&last_key, "refs/heads/master"); + strbuf_addstr(&key, "refs/tags/bla"); + extra = 6; + n = reftable_encode_key(&restart, dest, last_key, key, extra); + check(!restart); + check_int(n, >, 0); + + strbuf_addstr(&roundtrip, "refs/heads/master"); + m = reftable_decode_key(&roundtrip, &rt_extra, dest); + check_int(n, ==, m); + check(!strbuf_cmp(&key, &roundtrip)); + check_int(rt_extra, ==, extra); + + strbuf_release(&last_key); + strbuf_release(&key); + strbuf_release(&roundtrip); +} + +static void t_reftable_obj_record_comparison(void) +{ + + uint8_t id_bytes[] = { 0, 1, 2, 3, 4, 5, 6 }; + uint64_t offsets[] = { 0, 16, 32, 48, 64, 80, 96, 112}; + struct reftable_record in[3] = { + { + .type = BLOCK_TYPE_OBJ, + .u.obj.hash_prefix = id_bytes, + .u.obj.hash_prefix_len = 7, + .u.obj.offsets = offsets, + .u.obj.offset_len = 8, + }, + { + .type = BLOCK_TYPE_OBJ, + .u.obj.hash_prefix = id_bytes, + .u.obj.hash_prefix_len = 7, + .u.obj.offsets = offsets, + .u.obj.offset_len = 5, + }, + { + .type = BLOCK_TYPE_OBJ, + .u.obj.hash_prefix = id_bytes, + .u.obj.hash_prefix_len = 5, + }, + }; + + check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); + + check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); + + in[1].u.obj.offset_len = in[0].u.obj.offset_len; + check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); +} + +static void t_reftable_obj_record_roundtrip(void) +{ + uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 }; + uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 }; + struct reftable_obj_record recs[3] = { + { + .hash_prefix = testHash1, + .hash_prefix_len = 5, + .offsets = till9, + .offset_len = 3, + }, + { + .hash_prefix = testHash1, + .hash_prefix_len = 5, + .offsets = till9, + .offset_len = 9, + }, + { + .hash_prefix = testHash1, + .hash_prefix_len = 5, + }, + }; + struct strbuf scratch = STRBUF_INIT; + + for (size_t i = 0; i < ARRAY_SIZE(recs); i++) { + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + struct reftable_record in = { + .type = BLOCK_TYPE_OBJ, + .u = { + .obj = recs[i], + }, + }; + struct strbuf key = STRBUF_INIT; + struct reftable_record out = { .type = BLOCK_TYPE_OBJ }; + int n, m; + uint8_t extra; + + check(!reftable_record_is_deletion(&in)); + t_copy(&in); + reftable_record_key(&in, &key); + n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); + check_int(n, >, 0); + extra = reftable_record_val_type(&in); + m = reftable_record_decode(&out, key, extra, dest, + GIT_SHA1_RAWSZ, &scratch); + check_int(n, ==, m); + + check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); + strbuf_release(&key); + reftable_record_release(&out); + } + + strbuf_release(&scratch); +} + +static void t_reftable_index_record_comparison(void) +{ + struct reftable_record in[3] = { + { + .type = BLOCK_TYPE_INDEX, + .u.idx.offset = 22, + .u.idx.last_key = STRBUF_INIT, + }, + { + .type = BLOCK_TYPE_INDEX, + .u.idx.offset = 32, + .u.idx.last_key = STRBUF_INIT, + }, + { + .type = BLOCK_TYPE_INDEX, + .u.idx.offset = 32, + .u.idx.last_key = STRBUF_INIT, + }, + }; + strbuf_addstr(&in[0].u.idx.last_key, "refs/heads/master"); + strbuf_addstr(&in[1].u.idx.last_key, "refs/heads/master"); + strbuf_addstr(&in[2].u.idx.last_key, "refs/heads/branch"); + + check(!reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); + + check(!reftable_record_equal(&in[1], &in[2], GIT_SHA1_RAWSZ)); + check_int(reftable_record_cmp(&in[1], &in[2]), >, 0); + + in[1].u.idx.offset = in[0].u.idx.offset; + check(reftable_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); + check(!reftable_record_cmp(&in[0], &in[1])); + + for (size_t i = 0; i < ARRAY_SIZE(in); i++) + reftable_record_release(&in[i]); +} + +static void t_reftable_index_record_roundtrip(void) +{ + struct reftable_record in = { + .type = BLOCK_TYPE_INDEX, + .u.idx = { + .offset = 42, + .last_key = STRBUF_INIT, + }, + }; + uint8_t buffer[1024] = { 0 }; + struct string_view dest = { + .buf = buffer, + .len = sizeof(buffer), + }; + struct strbuf scratch = STRBUF_INIT; + struct strbuf key = STRBUF_INIT; + struct reftable_record out = { + .type = BLOCK_TYPE_INDEX, + .u.idx = { .last_key = STRBUF_INIT }, + }; + int n, m; + uint8_t extra; + + strbuf_addstr(&in.u.idx.last_key, "refs/heads/master"); + reftable_record_key(&in, &key); + t_copy(&in); + + check(!reftable_record_is_deletion(&in)); + check(!strbuf_cmp(&key, &in.u.idx.last_key)); + n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); + check_int(n, >, 0); + + extra = reftable_record_val_type(&in); + m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ, + &scratch); + check_int(m, ==, n); + + check(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); + + reftable_record_release(&out); + strbuf_release(&key); + strbuf_release(&scratch); + strbuf_release(&in.u.idx.last_key); +} + +int cmd_main(int argc, const char *argv[]) +{ + 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_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-strbuf.c b/t/unit-tests/t-strbuf.c index de434a4441..6027dafef7 100644 --- a/t/unit-tests/t-strbuf.c +++ b/t/unit-tests/t-strbuf.c @@ -2,7 +2,8 @@ #include "strbuf.h" /* wrapper that supplies tests with an empty, initialized strbuf */ -static void setup(void (*f)(struct strbuf*, void*), void *data) +static void setup(void (*f)(struct strbuf*, const void*), + const void *data) { struct strbuf buf = STRBUF_INIT; @@ -13,7 +14,8 @@ static void setup(void (*f)(struct strbuf*, void*), void *data) } /* wrapper that supplies tests with a populated, initialized strbuf */ -static void setup_populated(void (*f)(struct strbuf*, void*), char *init_str, void *data) +static void setup_populated(void (*f)(struct strbuf*, const void*), + const char *init_str, const void *data) { struct strbuf buf = STRBUF_INIT; @@ -64,7 +66,7 @@ static void t_dynamic_init(void) strbuf_release(&buf); } -static void t_addch(struct strbuf *buf, void *data) +static void t_addch(struct strbuf *buf, const void *data) { const char *p_ch = data; const char ch = *p_ch; @@ -83,7 +85,7 @@ static void t_addch(struct strbuf *buf, void *data) check_char(buf->buf[buf->len], ==, '\0'); } -static void t_addstr(struct strbuf *buf, void *data) +static void t_addstr(struct strbuf *buf, const void *data) { const char *text = data; size_t len = strlen(text); diff --git a/t/unit-tests/t-strvec.c b/t/unit-tests/t-strvec.c index d4615ab06d..fa1a041469 100644 --- a/t/unit-tests/t-strvec.c +++ b/t/unit-tests/t-strvec.c @@ -3,38 +3,21 @@ #include "strvec.h" #define check_strvec(vec, ...) \ - check_strvec_loc(TEST_LOCATION(), vec, __VA_ARGS__) -LAST_ARG_MUST_BE_NULL -static void check_strvec_loc(const char *loc, struct strvec *vec, ...) -{ - va_list ap; - size_t nr = 0; - - va_start(ap, vec); - while (1) { - const char *str = va_arg(ap, const char *); - if (!str) - break; - - if (!check_uint(vec->nr, >, nr) || - !check_uint(vec->alloc, >, nr) || - !check_str(vec->v[nr], str)) { - struct strbuf msg = STRBUF_INIT; - strbuf_addf(&msg, "strvec index %"PRIuMAX, (uintmax_t) nr); - test_assert(loc, msg.buf, 0); - strbuf_release(&msg); - va_end(ap); - return; - } - - nr++; - } - va_end(ap); - - check_uint(vec->nr, ==, nr); - check_uint(vec->alloc, >=, nr); - check_pointer_eq(vec->v[nr], NULL); -} + do { \ + const char *expect[] = { __VA_ARGS__ }; \ + if (check_uint(ARRAY_SIZE(expect), >, 0) && \ + check_pointer_eq(expect[ARRAY_SIZE(expect) - 1], NULL) && \ + check_uint((vec)->nr, ==, ARRAY_SIZE(expect) - 1) && \ + check_uint((vec)->nr, <=, (vec)->alloc)) { \ + for (size_t i = 0; i < ARRAY_SIZE(expect); i++) { \ + if (!check_str((vec)->v[i], expect[i])) { \ + test_msg(" i: %"PRIuMAX, \ + (uintmax_t)i); \ + break; \ + } \ + } \ + } \ + } while (0) static void t_static_init(void) { diff --git a/t/unit-tests/test-lib.h b/t/unit-tests/test-lib.h index 2de6d715d5..c59f646fd9 100644 --- a/t/unit-tests/test-lib.h +++ b/t/unit-tests/test-lib.h @@ -76,8 +76,9 @@ int test_assert(const char *location, const char *check, int ok); int check_bool_loc(const char *loc, const char *check, int ok); /* - * Compare two integers. Prints a message with the two values if the - * comparison fails. NB this is not thread safe. + * Compare the equality of two pointers of same type. Prints a message + * with the two values if the equality fails. NB this is not thread + * safe. */ #define check_pointer_eq(a, b) \ (test__tmp[0].p = (a), test__tmp[1].p = (b), \ @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "environment.h" #include "tag.h" diff --git a/tmp-objdir.c b/tmp-objdir.c index 3509258be5..a8e4553f27 100644 --- a/tmp-objdir.c +++ b/tmp-objdir.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "tmp-objdir.h" #include "abspath.h" @@ -390,6 +390,7 @@ void trace2_region_enter_printf_va_fl(const char *file, int line, trace2_region_enter_printf_va_fl(__FILE__, __LINE__, (category), \ (label), (repo), (fmt), (ap)) +__attribute__((format (printf, 6, 7))) void trace2_region_enter_printf_fl(const char *file, int line, const char *category, const char *label, const struct repository *repo, @@ -63,7 +63,7 @@ struct arg_item { static LIST_HEAD(conf_head); -static char *separators = ":"; +static const char *separators = ":"; static int configured; diff --git a/transport-helper.c b/transport-helper.c index 9820947ab2..09b3560ffd 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "transport.h" #include "quote.h" diff --git a/transport.c b/transport.c index 83ddea8fbc..7c4af9f56f 100644 --- a/transport.c +++ b/transport.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "advice.h" #include "config.h" @@ -184,7 +186,8 @@ static int fetch_refs_from_bundle(struct transport *transport, if (!data->get_refs_from_bundle_called) get_refs_from_bundle_inner(transport); ret = unbundle(the_repository, &data->header, data->fd, - &extra_index_pack_args, 0); + &extra_index_pack_args, + fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0); transport->hash_algo = data->header.hash_algo; return ret; } @@ -1112,6 +1115,8 @@ static struct transport_vtable builtin_smart_vtable = { struct transport *transport_get(struct remote *remote, const char *url) { const char *helper; + char *helper_to_free = NULL; + const char *p; struct transport *ret = xcalloc(1, sizeof(*ret)); ret->progress = isatty(2); @@ -1127,22 +1132,19 @@ struct transport *transport_get(struct remote *remote, const char *url) ret->remote = remote; helper = remote->foreign_vcs; - if (!url && remote->url) - url = remote->url[0]; + if (!url) + url = remote->url.v[0]; ret->url = url; - /* maybe it is a foreign URL? */ - if (url) { - const char *p = url; - - while (is_urlschemechar(p == url, *p)) - p++; - if (starts_with(p, "::")) - helper = xstrndup(url, p - url); - } + p = url; + while (is_urlschemechar(p == url, *p)) + p++; + if (starts_with(p, "::")) + helper = helper_to_free = xstrndup(url, p - url); if (helper) { transport_helper_init(ret, helper); + free(helper_to_free); } else if (starts_with(url, "rsync:")) { die(_("git-over-rsync is no longer supported")); } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) { diff --git a/tree-diff.c b/tree-diff.c index 46107772d1..9252481df3 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -8,6 +8,7 @@ #include "tree.h" #include "tree-walk.h" #include "environment.h" +#include "repository.h" /* * Some mode bits are also used internally for computations. diff --git a/tree-walk.c b/tree-walk.c index 6565d9ad99..a033397965 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "tree-walk.h" #include "dir.h" @@ -38,8 +40,8 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l desc->entry.path = path; desc->entry.mode = (desc->flags & TREE_DESC_RAW_MODES) ? mode : canon_mode(mode); desc->entry.pathlen = len - 1; - oidread_algop(&desc->entry.oid, (const unsigned char *)path + len, - desc->algo); + oidread(&desc->entry.oid, (const unsigned char *)path + len, + desc->algo); return 0; } diff --git a/tree-walk.h b/tree-walk.h index 0b1067fbc5..aaea689f9a 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -1,7 +1,7 @@ #ifndef TREE_WALK_H #define TREE_WALK_H -#include "hash-ll.h" +#include "hash.h" struct index_state; struct repository; @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "hex.h" #include "tree.h" diff --git a/unpack-trees.c b/unpack-trees.c index 304ea2ed86..7dc884fafd 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "advice.h" #include "strvec.h" diff --git a/upload-pack.c b/upload-pack.c index b726f7a57d..0052c6a4dc 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "config.h" #include "environment.h" diff --git a/userdiff.c b/userdiff.c index 82bc76b910..c4ebb9ff73 100644 --- a/userdiff.c +++ b/userdiff.c @@ -333,7 +333,7 @@ PATTERNS("scheme", "|([^][)(}{[ \t])+"), PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", "\\\\[a-zA-Z@]+|\\\\.|([a-zA-Z0-9]|[^\x01-\x7f])+"), -{ "default", NULL, NULL, -1, { NULL, 0 } }, +{ .name = "default", .binary = -1 }, }; #undef PATTERNS #undef IPATTERN @@ -399,7 +399,7 @@ static struct userdiff_driver *userdiff_find_by_namelen(const char *name, size_t static int parse_funcname(struct userdiff_funcname *f, const char *k, const char *v, int cflags) { - if (git_config_string(&f->pattern, k, v) < 0) + if (git_config_string((char **) &f->pattern, k, v) < 0) return -1; f->cflags = cflags; return 0; @@ -445,15 +445,19 @@ int userdiff_config(const char *k, const char *v) if (!strcmp(type, "binary")) return parse_tristate(&drv->binary, k, v); if (!strcmp(type, "command")) - return git_config_string(&drv->external, k, v); + return git_config_string((char **) &drv->external.cmd, k, v); + if (!strcmp(type, "trustexitcode")) { + drv->external.trust_exit_code = git_config_bool(k, v); + return 0; + } if (!strcmp(type, "textconv")) - return git_config_string(&drv->textconv, k, v); + return git_config_string((char **) &drv->textconv, k, v); if (!strcmp(type, "cachetextconv")) return parse_bool(&drv->textconv_want_cache, k, v); if (!strcmp(type, "wordregex")) - return git_config_string(&drv->word_regex, k, v); + return git_config_string((char **) &drv->word_regex, k, v); if (!strcmp(type, "algorithm")) - return git_config_string(&drv->algorithm, k, v); + return git_config_string((char **) &drv->algorithm, k, v); return 0; } diff --git a/userdiff.h b/userdiff.h index cc8e5abfef..7565930337 100644 --- a/userdiff.h +++ b/userdiff.h @@ -7,19 +7,24 @@ struct index_state; struct repository; struct userdiff_funcname { - char *pattern; + const char *pattern; int cflags; }; +struct external_diff { + char *cmd; + unsigned trust_exit_code:1; +}; + struct userdiff_driver { const char *name; - char *external; - char *algorithm; + struct external_diff external; + const char *algorithm; int binary; struct userdiff_funcname funcname; - char *word_regex; - char *word_regex_multi_byte; - char *textconv; + const char *word_regex; + const char *word_regex_multi_byte; + const char *textconv; struct notes_cache *textconv_cache; int textconv_want_cache; }; @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "hex.h" diff --git a/worktree.c b/worktree.c index 12eadacc61..f3c4c8ec54 100644 --- a/worktree.c +++ b/worktree.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "abspath.h" #include "environment.h" @@ -53,6 +55,15 @@ static void add_head_info(struct worktree *wt) wt->is_detached = 1; } +static int is_current_worktree(struct worktree *wt) +{ + char *git_dir = absolute_pathdup(get_git_dir()); + const char *wt_git_dir = get_worktree_git_dir(wt); + int is_current = !fspathcmp(git_dir, absolute_path(wt_git_dir)); + free(git_dir); + return is_current; +} + /** * get the main worktree */ @@ -76,6 +87,7 @@ static struct worktree *get_main_worktree(int skip_reading_head) */ worktree->is_bare = (is_bare_repository_cfg == 1) || is_bare_repository(); + worktree->is_current = is_current_worktree(worktree); if (!skip_reading_head) add_head_info(worktree); return worktree; @@ -102,6 +114,7 @@ struct worktree *get_linked_worktree(const char *id, worktree->repo = the_repository; worktree->path = strbuf_detach(&worktree_path, NULL); worktree->id = xstrdup(id); + worktree->is_current = is_current_worktree(worktree); if (!skip_reading_head) add_head_info(worktree); @@ -111,23 +124,6 @@ done: return worktree; } -static void mark_current_worktree(struct worktree **worktrees) -{ - char *git_dir = absolute_pathdup(get_git_dir()); - int i; - - for (i = 0; worktrees[i]; i++) { - struct worktree *wt = worktrees[i]; - const char *wt_git_dir = get_worktree_git_dir(wt); - - if (!fspathcmp(git_dir, absolute_path(wt_git_dir))) { - wt->is_current = 1; - break; - } - } - free(git_dir); -} - /* * NEEDSWORK: This function exists so that we can look up metadata of a * worktree without trying to access any of its internals like the refdb. It @@ -164,7 +160,6 @@ static struct worktree **get_worktrees_internal(int skip_reading_head) ALLOC_GROW(list, counter + 1, alloc); list[counter] = NULL; - mark_current_worktree(list); return list; } diff --git a/worktree.h b/worktree.h index 7cc6d90e66..11279d0c8f 100644 --- a/worktree.h +++ b/worktree.h @@ -178,14 +178,6 @@ int is_worktree_being_rebased(const struct worktree *wt, const char *target); int is_worktree_being_bisected(const struct worktree *wt, const char *target); /* - * Similar to git_path() but can produce paths for a specified - * worktree instead of current one - */ -const char *worktree_git_path(const struct worktree *wt, - const char *fmt, ...) - __attribute__((format (printf, 2, 3))); - -/* * Return a refname suitable for access from the current ref store. */ void strbuf_worktree_ref(const struct worktree *wt, diff --git a/wt-status.c b/wt-status.c index ff4be071ca..b778eef989 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "advice.h" #include "wt-status.h" @@ -126,6 +128,7 @@ void status_printf(struct wt_status *s, const char *color, va_end(ap); } +__attribute__((format (printf, 3, 4))) static void status_printf_more(struct wt_status *s, const char *color, const char *fmt, ...) { @@ -641,7 +644,7 @@ static void wt_status_collect_changes_index(struct wt_status *s) repo_init_revisions(s->repo, &rev, NULL); memset(&opt, 0, sizeof(opt)); - opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference; + opt.def = s->is_initial ? empty_tree_oid_hex(the_repository->hash_algo) : s->reference; setup_revisions(0, NULL, &rev, &opt); rev.diffopt.flags.override_submodule_config = 1; @@ -1136,7 +1139,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s) rev.diffopt.ita_invisible_in_index = 1; memset(&opt, 0, sizeof(opt)); - opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference; + opt.def = s->is_initial ? empty_tree_oid_hex(the_repository->hash_algo) : s->reference; setup_revisions(0, NULL, &rev, &opt); rev.diffopt.output_format |= DIFF_FORMAT_PATCH; @@ -2408,7 +2411,7 @@ static void wt_porcelain_v2_print_unmerged_entry( int mode; struct object_id oid; } stages[3]; - char *key; + const char *key; char submodule_token[5]; char unmerged_prefix = 'u'; char eol_char = s->null_termination ? '\0' : '\n'; diff --git a/xdiff-interface.c b/xdiff-interface.c index 16ed8ac492..d5dc88661e 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -1,3 +1,5 @@ +#define USE_THE_REPOSITORY_VARIABLE + #include "git-compat-util.h" #include "gettext.h" #include "config.h" diff --git a/xdiff-interface.h b/xdiff-interface.h index 38537169b7..1ed430b622 100644 --- a/xdiff-interface.h +++ b/xdiff-interface.h @@ -1,7 +1,7 @@ #ifndef XDIFF_INTERFACE_H #define XDIFF_INTERFACE_H -#include "hash-ll.h" +#include "hash.h" #include "xdiff/xdiff.h" /* |
