summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/Makefile4
-rw-r--r--Documentation/RelNotes/2.30.0.txt28
-rw-r--r--Documentation/RelNotes/2.31.0.txt91
-rw-r--r--Documentation/SubmittingPatches2
-rw-r--r--Documentation/config/core.txt2
-rw-r--r--Documentation/config/http.txt4
-rw-r--r--Documentation/config/trace2.txt2
-rw-r--r--Documentation/git-clone.txt4
-rw-r--r--Documentation/git-init.txt11
-rw-r--r--Documentation/git-ls-files.txt5
-rw-r--r--Documentation/git-maintenance.txt120
-rw-r--r--Documentation/git-mktag.txt39
-rw-r--r--Documentation/git-p4.txt2
-rw-r--r--Documentation/git-rev-parse.txt74
-rw-r--r--Documentation/git-send-email.txt6
-rw-r--r--Documentation/git-status.txt28
-rw-r--r--Documentation/git-update-index.txt5
-rw-r--r--Documentation/git-worktree.txt5
-rw-r--r--Documentation/git.txt4
-rw-r--r--Documentation/githooks.txt2
-rw-r--r--Documentation/gitmodules.txt30
-rw-r--r--Documentation/pretty-formats.txt34
-rw-r--r--Documentation/technical/index-format.txt10
-rw-r--r--Documentation/technical/multi-pack-index.txt4
-rw-r--r--Documentation/technical/pack-format.txt17
-rw-r--r--Documentation/technical/reftable.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL3
-rw-r--r--Makefile28
l---------RelNotes2
-rw-r--r--abspath.c64
-rw-r--r--apply.c2
-rw-r--r--bisect.c2
-rw-r--r--builtin/am.c4
-rw-r--r--builtin/blame.c48
-rw-r--r--builtin/branch.c10
-rw-r--r--builtin/checkout.c6
-rw-r--r--builtin/clone.c17
-rw-r--r--builtin/commit-graph.c6
-rw-r--r--builtin/fast-export.c23
-rw-r--r--builtin/for-each-ref.c2
-rw-r--r--builtin/for-each-repo.c7
-rw-r--r--builtin/fsck.c20
-rw-r--r--builtin/gc.c431
-rw-r--r--builtin/index-pack.c2
-rw-r--r--builtin/init-db.c8
-rw-r--r--builtin/log.c8
-rw-r--r--builtin/mktag.c235
-rw-r--r--builtin/name-rev.c4
-rw-r--r--builtin/pack-objects.c1
-rw-r--r--builtin/pack-redundant.c6
-rw-r--r--builtin/pull.c70
-rw-r--r--builtin/rebase.c4
-rw-r--r--builtin/rev-parse.c106
-rw-r--r--builtin/shortlog.c10
-rw-r--r--builtin/stash.c165
-rw-r--r--builtin/submodule--helper.c24
-rw-r--r--builtin/tag.c2
-rw-r--r--builtin/worktree.c2
-rw-r--r--cache.h96
-rwxr-xr-xci/install-dependencies.sh8
-rw-r--r--commit-graph.c121
-rw-r--r--commit.c26
-rw-r--r--commit.h5
-rw-r--r--config.c2
-rw-r--r--config.mak.uname4
-rw-r--r--connect.c2
-rw-r--r--contrib/completion/git-completion.bash50
-rw-r--r--diff.c3
-rw-r--r--diffcore-rename.c209
-rw-r--r--ewah/bitmap.c54
-rw-r--r--ewah/ewah_bitmap.c15
-rw-r--r--ewah/ewok.h3
-rw-r--r--fsck.c60
-rw-r--r--fsck.h16
-rw-r--r--gettext.c94
-rw-r--r--git-compat-util.h2
-rw-r--r--git-gui/Makefile2
-rwxr-xr-xgit-gui/git-gui--askpass15
-rwxr-xr-xgit-gui/git-gui.sh30
-rw-r--r--git-gui/lib/commit.tcl1
-rw-r--r--git-gui/lib/themed.tcl41
-rw-r--r--git-gui/po/ru.po3019
-rw-r--r--git-mergetool--lib.sh6
-rwxr-xr-xgit-p4.py2
-rw-r--r--gitweb/Makefile2
-rw-r--r--hash-lookup.c (renamed from sha1-lookup.c)22
-rw-r--r--hash-lookup.h (renamed from sha1-lookup.h)18
-rw-r--r--hash.h95
-rw-r--r--list-objects-filter.c2
-rw-r--r--merge-ort.c1943
-rw-r--r--merge-ort.h19
-rw-r--r--merge-recursive.c11
-rw-r--r--midx.c4
-rw-r--r--object-file.c (renamed from sha1-file.c)10
-rw-r--r--object-name.c (renamed from sha1-name.c)16
-rw-r--r--oid-array.c21
-rw-r--r--oid-array.h34
-rw-r--r--pack-bitmap-write.c468
-rw-r--r--pack-bitmap.c139
-rw-r--r--pack-bitmap.h8
-rw-r--r--packfile.c2
-rw-r--r--parse-options.h6
-rw-r--r--patch-ids.c2
-rw-r--r--po/TEAMS4
-rw-r--r--po/bg.po5080
-rw-r--r--po/ca.po7137
-rw-r--r--po/de.po5329
-rw-r--r--po/fr.po5156
-rw-r--r--po/git.pot4969
-rw-r--r--po/pl.po25969
-rw-r--r--po/sv.po5198
-rw-r--r--po/tr.po5246
-rw-r--r--po/vi.po5404
-rw-r--r--po/zh_CN.po5063
-rw-r--r--po/zh_TW.po5346
-rw-r--r--pretty.c10
-rw-r--r--read-cache.c12
-rw-r--r--ref-filter.c75
-rw-r--r--ref-filter.h13
-rw-r--r--refs.c24
-rw-r--r--refs.h4
-rw-r--r--refs/files-backend.c4
-rw-r--r--remote.c21
-rw-r--r--rerere.c4
-rw-r--r--revision.c31
-rw-r--r--strmap.h4
-rw-r--r--submodule.c7
-rw-r--r--t/lib-submodule-update.sh16
-rw-r--r--t/oid-info/README2
-rwxr-xr-xt/perf/p7519-fsmonitor.sh7
-rw-r--r--t/perf/perf-lib.sh12
-rwxr-xr-xt/t0001-init.sh17
-rwxr-xr-xt/t0064-oid-array.sh (renamed from t/t0064-sha1-array.sh)9
-rwxr-xr-xt/t0068-for-each-repo.sh6
-rwxr-xr-xt/t1006-cat-file.sh2
-rwxr-xr-xt/t1300-config.sh72
-rwxr-xr-xt/t1400-update-ref.sh75
-rwxr-xr-xt/t1500-rev-parse.sh57
-rwxr-xr-xt/t1510-repo-setup.sh2
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh2
-rwxr-xr-xt/t2016-checkout-patch.sh5
-rwxr-xr-xt/t2406-worktree-repair.sh26
-rwxr-xr-xt/t3200-branch.sh267
-rwxr-xr-xt/t3201-branch-contains.sh83
-rwxr-xr-xt/t3203-branch-output.sh94
-rwxr-xr-xt/t3205-branch-color.sh9
-rwxr-xr-xt/t3800-mktag.sh236
-rwxr-xr-xt/t4015-diff-whitespace.sh24
-rwxr-xr-xt/t4058-diff-duplicates.sh114
-rwxr-xr-xt/t4129-apply-samemode.sh2
-rwxr-xr-xt/t4205-log-pretty-formats.sh99
-rwxr-xr-xt/t5310-pack-bitmaps.sh177
-rwxr-xr-xt/t5323-pack-redundant.sh37
-rwxr-xr-xt/t5505-remote.sh156
-rwxr-xr-xt/t5510-fetch.sh168
-rwxr-xr-xt/t5516-fetch-push.sh4
-rwxr-xr-xt/t5526-fetch-submodules.sh117
-rwxr-xr-xt/t5570-git-daemon.sh5
-rwxr-xr-xt/t5582-fetch-negative-refspec.sh51
-rwxr-xr-xt/t5616-partial-clone.sh10
-rwxr-xr-xt/t5703-upload-pack-ref-in-want.sh65
-rwxr-xr-xt/t6016-rev-list-graph-simplify-history.sh354
-rwxr-xr-xt/t6030-bisect-porcelain.sh16
-rwxr-xr-xt/t6050-replace.sh2
-rwxr-xr-xt/t6300-for-each-ref.sh178
-rwxr-xr-xt/t6302-for-each-ref-filter.sh59
-rwxr-xr-xt/t7012-skip-worktree-writing.sh88
-rwxr-xr-xt/t7064-wtstatus-pv2.sh103
-rwxr-xr-xt/t7416-submodule-dash-url.sh15
-rwxr-xr-xt/t7601-merge-pull-config.sh66
-rwxr-xr-xt/t7610-mergetool.sh11
-rwxr-xr-xt/t7900-maintenance.sh124
-rwxr-xr-xt/t9902-completion.sh329
-rw-r--r--t/test-lib-functions.sh13
-rw-r--r--t/test-lib.sh15
-rw-r--r--trailer.c15
-rw-r--r--trailer.h2
-rw-r--r--tree.c2
-rw-r--r--tree.h2
-rw-r--r--upload-pack.c2
-rw-r--r--worktree.c41
-rw-r--r--wt-status.c4
-rw-r--r--wt-status.h2
184 files changed, 61716 insertions, 30432 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 69dbe4b..b980407 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -272,7 +272,9 @@ install-html: html
../GIT-VERSION-FILE: FORCE
$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE
+ifneq ($(MAKECMDGOALS),clean)
-include ../GIT-VERSION-FILE
+endif
#
# Determine "include::" file references in asciidoc files.
@@ -286,7 +288,9 @@ doc.dep : $(docdep_prereqs) $(wildcard *.txt) $(wildcard config/*.txt) build-doc
$(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \
mv $@+ $@
+ifneq ($(MAKECMDGOALS),clean)
-include doc.dep
+endif
cmds_txt = cmds-ancillaryinterrogators.txt \
cmds-ancillarymanipulators.txt \
diff --git a/Documentation/RelNotes/2.30.0.txt b/Documentation/RelNotes/2.30.0.txt
index df8df8a..c2f1dc7 100644
--- a/Documentation/RelNotes/2.30.0.txt
+++ b/Documentation/RelNotes/2.30.0.txt
@@ -81,8 +81,8 @@ UI, Workflows & Features
* "git update-ref --stdin" learns to take multiple transactions in a
single session.
- * Various subcommands of "git config" that takes value_regex
- learn the "--literal-value" option to take the value_regex option
+ * Various subcommands of "git config" that take value_regex
+ learned the "--literal-value" option to take the value_regex option
as a literal string.
* The transport layer was taught to optionally exchange the session
@@ -120,11 +120,11 @@ Performance, Internal Implementation, Development Support etc.
test pieces to run.
* Adjust tests so that they won't scream when the default initial
- branch name is changed to 'main'.
+ branch name is different from 'master'.
* Rewriting "git bisect" in C continues.
- * More preliminary tests have been added to document desired outcome
+ * More preliminary tests have been added to document desired outcomes
of various "directory rename" situations.
* Micro clean-up of a couple of test scripts.
@@ -136,9 +136,6 @@ Performance, Internal Implementation, Development Support etc.
* The code to detect premature EOF in the sideband demultiplexer has
been cleaned up.
- * Test scripts are being prepared to transition of the default branch
- name to 'main'.
-
* "git fetch --depth=<n>" over the stateless RPC / smart HTTP
transport handled EOF from the client poorly at the server end.
@@ -252,7 +249,7 @@ Fixes since v2.29
(merge c779386182 jc/sequencer-stopped-sha-simplify later to maint).
* The code to see if "git stash drop" can safely remove refs/stash
- has been made more carerful.
+ has been made more careful.
(merge 4f44c5659b rs/empty-reflog-check-fix later to maint).
* "git log -L<range>:<path>" is documented to take no pathspec, but
@@ -299,7 +296,7 @@ Fixes since v2.29
(merge 81c4c5cf2e jk/4gb-idx later to maint).
* Since jgit does not yet work with SHA-256 repositories, mark the
- tests that uses it not to run unless we are testing with ShA-1
+ tests that use it not to run unless we are testing with ShA-1
repositories.
(merge ea699b4adc sg/t5310-jgit-wants-sha1 later to maint).
@@ -337,7 +334,7 @@ Fixes since v2.29
(merge 506ec2fbda tb/idx-midx-race-fix later to maint).
* "git apply" adjusted the permission bits of working-tree files and
- directories according core.sharedRepository setting by mistake and
+ directories according to core.sharedRepository setting by mistake and
for a long time, which has been corrected.
(merge eb3c027e17 mt/do-not-use-scld-in-working-tree later to maint).
@@ -363,6 +360,10 @@ Fixes since v2.29
* Tighten error checking in the codepath that responds to "git fetch".
(merge d43a21bdbb jk/check-config-parsing-error-in-upload-pack later to maint).
+ * "git pack-redundant" when there is only one packfile used to crash,
+ which has been corrected.
+ (merge 0696232390 jx/pack-redundant-on-single-pack later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge 3e0a5dc9af cc/doc-filter-branch-typofix later to maint).
(merge 32c83afc2c cw/ci-ghwf-check-ws-errors later to maint).
@@ -391,3 +392,10 @@ Fixes since v2.29
(merge 08e9df2395 jk/multi-line-indent-style-fix later to maint).
(merge e66590348a da/vs-build-iconv-fix later to maint).
(merge 7fe07275be js/cmake-extra-built-ins-fix later to maint).
+ (merge 633eebe142 jb/midx-doc-update later to maint).
+ (merge 5885367e8f jh/index-v2-doc-on-fsmn later to maint).
+ (merge 14639a4779 jc/compat-util-setitimer-fix later to maint).
+ (merge 56f56ac50b ab/unreachable-break later to maint).
+ (merge 731d578b4f rb/nonstop-config-mak-uname-update later to maint).
+ (merge f4698738f9 es/perf-export-fix later to maint).
+ (merge 773c694142 nk/refspecs-negative-fix later to maint).
diff --git a/Documentation/RelNotes/2.31.0.txt b/Documentation/RelNotes/2.31.0.txt
new file mode 100644
index 0000000..47041f3
--- /dev/null
+++ b/Documentation/RelNotes/2.31.0.txt
@@ -0,0 +1,91 @@
+Git 2.31 Release Notes
+======================
+
+Updates since v2.30
+-------------------
+
+UI, Workflows & Features
+
+ * The "--format=%(trailers)" mechanism gets enhanced to make it
+ easier to design output for machine consumption.
+
+ * When a user does not tell "git pull" to use rebase or merge, the
+ command gives a loud message telling a user to choose between
+ rebase or merge but creates a merge anyway, forcing users who would
+ want to rebase to redo the operation. Fix an early part of this
+ problem by tightening the condition to give the message---there is
+ no reason to stop or force the user to choose between rebase or
+ merge if the history fast-forwards.
+
+ * The configuration variable 'core.abbrev' can be set to 'no' to
+ force no abbreviation regardless of the hash algorithm.
+
+ * "git rev-parse" can be explicitly told to give output as absolute
+ or relative path with the `--path-format=(absolute|relative)` option.
+
+ * Bash completion (in contrib/) update to make it easier for
+ end-users to add completion for their custom "git" subcommands.
+
+ * "git maintenance" learned to drive scheduled maintenance on
+ platforms whose native scheduling methods are not 'cron'.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * A 3-year old test that was not testing anything useful has been
+ corrected.
+
+ * Retire more names with "sha1" in it.
+
+ * The topological walk codepath is covered by new trace2 stats.
+
+
+Fixes since v2.30
+-----------------
+
+ * Diagnose command line error of "git rebase" early.
+ (merge ca5120c339 rs/rebase-commit-validation later to maint).
+
+ * Clean up option descriptions in "git cmd --help".
+ (merge e73fe3dd02 zh/arg-help-format later to maint).
+
+ * "git stash" did not work well in a sparsely checked out working
+ tree.
+ (merge ba359fd507 en/stash-apply-sparse-checkout later to maint).
+
+ * Some tests expect that "ls -l" output has either '-' or 'x' for
+ group executable bit, but setgid bit can be inherited from parent
+ directory and make these fields 'S' or 's' instead, causing test
+ failures.
+ (merge ea8bbf2a4e mt/t4129-with-setgid-dir later to maint).
+
+ * "git for-each-repo --config=<var> <cmd>" should not run <cmd> for
+ any repository when the configuration variable <var> is not defined
+ even once.
+ (merge 6c62f01552 ds/for-each-repo-noopfix later to maint).
+
+ * Fix 2.29 regression where "git mergetool --tool-help" fails to list
+ all the available tools.
+ (merge 80f5a16798 pb/mergetool-tool-help-fix later to maint).
+
+ * Fix for procedure to building CI test environment for mac.
+ (merge 3831132ace jc/macos-install-dependencies-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 505a276596 pk/subsub-fetch-fix-take-2 later to maint).
+ (merge 33fc56253b fc/t6030-bisect-reset-removes-auxiliary-files later to maint).
+ (merge 7efc378205 ta/doc-typofix later to maint).
+ (merge 1f4e9319c7 pb/doc-modules-git-work-tree-typofix later to maint).
+ (merge 04f6b0a192 ma/t1300-cleanup later to maint).
+ (merge 7b77f5a13e ma/doc-pack-format-varint-for-sizes later to maint).
+ (merge cc2d43be2b nk/perf-fsmonitor-cleanup later to maint).
+ (merge c8302c6c00 ar/t6016-modernise later to maint).
+ (merge 0454986e78 jc/sign-off later to maint).
+ (merge 155067ab4f vv/send-email-with-less-secure-apps-access later to maint).
+ (merge acaabcf391 jk/t5516-deflake later to maint).
+ (merge a1e03535db ad/t4129-setfacl-target-fix later to maint).
+ (merge b356d23638 ug/doc-lose-dircache later to maint).
+ (merge 9371c0e9dd ab/gettext-charset-comment-fix later to maint).
+ (merge 52fc4f195c dl/p4-encode-after-kw-expansion later to maint).
+ (merge 4eb56b56e7 bc/doc-status-short later to maint).
+ (merge a4a1ca22ef tb/local-clone-race-doc later to maint).
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index d12094b..0452db2 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -307,7 +307,7 @@ wrote the patch or have the right to pass it on under the same license
as ours, by "signing off" your patch. Without sign-off, we cannot
accept your patches.
-If you can certify the below D-C-O:
+If (and only if) you certify the below D-C-O:
[[dco]]
.Developer's Certificate of Origin 1.1
diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
index 160aaca..c04f62a 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -625,4 +625,6 @@ core.abbrev::
computed based on the approximate number of packed objects
in your repository, which hopefully is enough for
abbreviated object names to stay unique for some time.
+ If set to "no", no abbreviation is made and the object names
+ are shown in their full length.
The minimum length is 4.
diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt
index 3968fbb..7003661 100644
--- a/Documentation/config/http.txt
+++ b/Documentation/config/http.txt
@@ -42,12 +42,12 @@ http.proxySSLKey::
http.proxySSLCertPasswordProtected::
Enable Git's password prompt for the proxy SSL certificate. Otherwise OpenSSL
will prompt the user, possibly many times, if the certificate or private key
- is encrypted. Can be overriden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
+ is encrypted. Can be overridden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
environment variable.
http.proxySSLCAInfo::
Pathname to the file containing the certificate bundle that should be used to
- verify the proxy with when using an HTTPS proxy. Can be overriden by the
+ verify the proxy with when using an HTTPS proxy. Can be overridden by the
`GIT_PROXY_SSL_CAINFO` environment variable.
http.emptyAuth::
diff --git a/Documentation/config/trace2.txt b/Documentation/config/trace2.txt
index 01d3afd..fe1642f 100644
--- a/Documentation/config/trace2.txt
+++ b/Documentation/config/trace2.txt
@@ -54,7 +54,7 @@ trace2.envVars::
`GIT_HTTP_USER_AGENT,GIT_CONFIG` would cause the trace2 output to
contain events listing the overrides for HTTP user agent and the
location of the Git configuration file (assuming any are set). May be
- overriden by the `GIT_TRACE2_ENV_VARS` environment variable. Unset by
+ overridden by the `GIT_TRACE2_ENV_VARS` environment variable. Unset by
default.
trace2.destinationDebug::
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 876aedc..02d9c19 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -57,6 +57,10 @@ repository is specified as a URL, then this flag is ignored (and we
never use the local optimizations). Specifying `--no-local` will
override the default when `/path/to/repo` is given, using the regular
Git transport instead.
++
+*NOTE*: this operation can race with concurrent modification to the
+source repository, similar to running `cp -r src dst` while modifying
+`src`.
--no-hardlinks::
Force the cloning process from a repository on a local
diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index 59ecda6..b611d80 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -20,8 +20,9 @@ DESCRIPTION
This command creates an empty Git repository - basically a `.git`
directory with subdirectories for `objects`, `refs/heads`,
-`refs/tags`, and template files. An initial `HEAD` file that
-references the HEAD of the master branch is also created.
+`refs/tags`, and template files. An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).
If the `$GIT_DIR` environment variable is set then it specifies a path
to use instead of `./.git` for the base of the repository.
@@ -73,8 +74,10 @@ If this is reinitialization, the repository will be moved to the specified path.
-b <branch-name>::
--initial-branch=<branch-name>::
-Use the specified name for the initial branch in the newly created repository.
-If not specified, fall back to the default name: `master`.
+Use the specified name for the initial branch in the newly created
+repository. If not specified, fall back to the default name (currently
+`master`, but this is subject to change in the future; the name can be
+customized via the `init.defaultBranch` configuration variable).
--shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index cbcf526..0a3b526 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -23,9 +23,8 @@ SYNOPSIS
DESCRIPTION
-----------
-This merges the file listing in the directory cache index with the
-actual working directory list, and shows different combinations of the
-two.
+This merges the file listing in the index with the actual working
+directory list, and shows different combinations of the two.
One or more of the options below may be used to determine the files
shown:
diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt
index 6fec1eb..3b43217 100644
--- a/Documentation/git-maintenance.txt
+++ b/Documentation/git-maintenance.txt
@@ -38,7 +38,7 @@ register::
for running in the background without disrupting foreground
processes.
+
-The `register` subcomand will also set the `maintenance.strategy` config
+The `register` subcommand will also set the `maintenance.strategy` config
value to `incremental`, if this value is not previously set. The
`incremental` strategy uses the following schedule for each maintenance
task:
@@ -101,7 +101,7 @@ This is done to avoid disrupting the remote-tracking branches. The end users
expect these refs to stay unmoved unless they initiate a fetch. With prefetch
task, however, the objects necessary to complete a later real fetch would
already be obtained, so the real fetch would go faster. In the ideal case,
-it will just become an update to bunch of remote-tracking branches without
+it will just become an update to a bunch of remote-tracking branches without
any object transfer.
gc::
@@ -218,6 +218,122 @@ Further, the `git gc` command should not be combined with
but does not take the lock in the same way as `git maintenance run`. If
possible, use `git maintenance run --task=gc` instead of `git gc`.
+The following sections describe the mechanisms put in place to run
+background maintenance by `git maintenance start` and how to customize
+them.
+
+BACKGROUND MAINTENANCE ON POSIX SYSTEMS
+---------------------------------------
+
+The standard mechanism for scheduling background tasks on POSIX systems
+is cron(8). This tool executes commands based on a given schedule. The
+current list of user-scheduled tasks can be found by running `crontab -l`.
+The schedule written by `git maintenance start` is similar to this:
+
+-----------------------------------------------------------------------
+# BEGIN GIT MAINTENANCE SCHEDULE
+# The following schedule was created by Git
+# Any edits made in this region might be
+# replaced in the future by a Git command.
+
+0 1-23 * * * "/<path>/git" --exec-path="/<path>" for-each-repo --config=maintenance.repo maintenance run --schedule=hourly
+0 0 * * 1-6 "/<path>/git" --exec-path="/<path>" for-each-repo --config=maintenance.repo maintenance run --schedule=daily
+0 0 * * 0 "/<path>/git" --exec-path="/<path>" for-each-repo --config=maintenance.repo maintenance run --schedule=weekly
+
+# END GIT MAINTENANCE SCHEDULE
+-----------------------------------------------------------------------
+
+The comments are used as a region to mark the schedule as written by Git.
+Any modifications within this region will be completely deleted by
+`git maintenance stop` or overwritten by `git maintenance start`.
+
+The `crontab` entry specifies the full path of the `git` executable to
+ensure that the executed `git` command is the same one with which
+`git maintenance start` was issued independent of `PATH`. If the same user
+runs `git maintenance start` with multiple Git executables, then only the
+latest executable is used.
+
+These commands use `git for-each-repo --config=maintenance.repo` to run
+`git maintenance run --schedule=<frequency>` on each repository listed in
+the multi-valued `maintenance.repo` config option. These are typically
+loaded from the user-specific global config. The `git maintenance` process
+then determines which maintenance tasks are configured to run on each
+repository with each `<frequency>` using the `maintenance.<task>.schedule`
+config options. These values are loaded from the global or repository
+config values.
+
+If the config values are insufficient to achieve your desired background
+maintenance schedule, then you can create your own schedule. If you run
+`crontab -e`, then an editor will load with your user-specific `cron`
+schedule. In that editor, you can add your own schedule lines. You could
+start by adapting the default schedule listed earlier, or you could read
+the crontab(5) documentation for advanced scheduling techniques. Please
+do use the full path and `--exec-path` techniques from the default
+schedule to ensure you are executing the correct binaries in your
+schedule.
+
+
+BACKGROUND MAINTENANCE ON MACOS SYSTEMS
+---------------------------------------
+
+While macOS technically supports `cron`, using `crontab -e` requires
+elevated privileges and the executed process does not have a full user
+context. Without a full user context, Git and its credential helpers
+cannot access stored credentials, so some maintenance tasks are not
+functional.
+
+Instead, `git maintenance start` interacts with the `launchctl` tool,
+which is the recommended way to schedule timed jobs in macOS. Scheduling
+maintenance through `git maintenance (start|stop)` requires some
+`launchctl` features available only in macOS 10.11 or later.
+
+Your user-specific scheduled tasks are stored as XML-formatted `.plist`
+files in `~/Library/LaunchAgents/`. You can see the currently-registered
+tasks using the following command:
+
+-----------------------------------------------------------------------
+$ ls ~/Library/LaunchAgents/org.git-scm.git*
+org.git-scm.git.daily.plist
+org.git-scm.git.hourly.plist
+org.git-scm.git.weekly.plist
+-----------------------------------------------------------------------
+
+One task is registered for each `--schedule=<frequency>` option. To
+inspect how the XML format describes each schedule, open one of these
+`.plist` files in an editor and inspect the `<array>` element following
+the `<key>StartCalendarInterval</key>` element.
+
+`git maintenance start` will overwrite these files and register the
+tasks again with `launchctl`, so any customizations should be done by
+creating your own `.plist` files with distinct names. Similarly, the
+`git maintenance stop` command will unregister the tasks with `launchctl`
+and delete the `.plist` files.
+
+To create more advanced customizations to your background tasks, see
+launchctl.plist(5) for more information.
+
+
+BACKGROUND MAINTENANCE ON WINDOWS SYSTEMS
+-----------------------------------------
+
+Windows does not support `cron` and instead has its own system for
+scheduling background tasks. The `git maintenance start` command uses
+the `schtasks` command to submit tasks to this system. You can inspect
+all background tasks using the Task Scheduler application. The tasks
+added by Git have names of the form `Git Maintenance (<frequency>)`.
+The Task Scheduler GUI has ways to inspect these tasks, but you can also
+export the tasks to XML files and view the details there.
+
+Note that since Git is a console application, these background tasks
+create a console window visible to the current user. This can be changed
+manually by selecting the "Run whether user is logged in or not" option
+in Task Scheduler. This change requires a password input, which is why
+`git maintenance start` does not select it by default.
+
+If you want to customize the background tasks, please rename the tasks
+so future calls to `git maintenance (start|stop)` do not overwrite your
+custom tasks.
+
GIT
---
diff --git a/Documentation/git-mktag.txt b/Documentation/git-mktag.txt
index fa6a756..17a2603 100644
--- a/Documentation/git-mktag.txt
+++ b/Documentation/git-mktag.txt
@@ -3,7 +3,7 @@ git-mktag(1)
NAME
----
-git-mktag - Creates a tag object
+git-mktag - Creates a tag object with extra validation
SYNOPSIS
@@ -11,25 +11,52 @@ SYNOPSIS
[verse]
'git mktag'
+OPTIONS
+-------
+
+--strict::
+ By default mktag turns on the equivalent of
+ linkgit:git-fsck[1] `--strict` mode. Use `--no-strict` to
+ disable it.
+
DESCRIPTION
-----------
-Reads a tag contents on standard input and creates a tag object
-that can also be used to sign other objects.
-The output is the new tag's <object> identifier.
+Reads a tag contents on standard input and creates a tag object. The
+output is the new tag's <object> identifier.
+
+This command is mostly equivalent to linkgit:git-hash-object[1]
+invoked with `-t tag -w --stdin`. I.e. both of these will create and
+write a tag found in `my-tag`:
+
+ git mktag <my-tag
+ git hash-object -t tag -w --stdin <my-tag
+
+The difference is that mktag will die before writing the tag if the
+tag doesn't pass a linkgit:git-fsck[1] check.
+
+The "fsck" check done mktag is stricter than what linkgit:git-fsck[1]
+would run by default in that all `fsck.<msg-id>` messages are promoted
+from warnings to errors (so e.g. a missing "tagger" line is an error).
+
+Extra headers in the object are also an error under mktag, but ignored
+by linkgit:git-fsck[1]. This extra check can be turned off by setting
+the appropriate `fsck.<msg-id>` varible:
+
+ git -c fsck.extraHeaderEntry=ignore mktag <my-tag-with-headers
Tag Format
----------
A tag signature file, to be fed to this command's standard input,
has a very simple fixed format: four lines of
- object <sha1>
+ object <hash>
type <typename>
tag <tagname>
tagger <tagger>
followed by some 'optional' free-form message (some tags created
-by older Git may not have `tagger` line). The message, when
+by older Git may not have `tagger` line). The message, when it
exists, is separated by a blank line from the header. The
message part may contain a signature that Git itself doesn't
care about, but that can be verified with gpg.
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index ec233ac..f89e68b 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -397,7 +397,7 @@ changelist text. Exiting with a non-zero status from the script
will abort the process.
The purpose of the hook is to edit the message file in place,
-and it is not supressed by the `--no-verify` option. This hook
+and it is not suppressed by the `--no-verify` option. This hook
is called even if `--prepare-p4-only` is set.
p4-changelist
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 5013daa..6b8ca08 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -212,6 +212,18 @@ Options for Files
Only the names of the variables are listed, not their value,
even if they are set.
+--path-format=(absolute|relative)::
+ Controls the behavior of certain other options. If specified as absolute, the
+ paths printed by those options will be absolute and canonical. If specified as
+ relative, the paths will be relative to the current working directory if that
+ is possible. The default is option specific.
++
+This option may be specified multiple times and affects only the arguments that
+follow it on the command line, either to the end of the command line or the next
+instance of this option.
+
+The following options are modified by `--path-format`:
+
--git-dir::
Show `$GIT_DIR` if defined. Otherwise show the path to
the .git directory. The path shown, when relative, is
@@ -221,27 +233,9 @@ If `$GIT_DIR` is not defined and the current directory
is not detected to lie in a Git repository or work tree
print a message to stderr and exit with nonzero status.
---absolute-git-dir::
- Like `--git-dir`, but its output is always the canonicalized
- absolute path.
-
--git-common-dir::
Show `$GIT_COMMON_DIR` if defined, else `$GIT_DIR`.
---is-inside-git-dir::
- When the current working directory is below the repository
- directory print "true", otherwise "false".
-
---is-inside-work-tree::
- When the current working directory is inside the work tree of the
- repository print "true", otherwise "false".
-
---is-bare-repository::
- When the repository is bare print "true", otherwise "false".
-
---is-shallow-repository::
- When the repository is shallow print "true", otherwise "false".
-
--resolve-git-dir <path>::
Check if <path> is a valid repository or a gitfile that
points at a valid repository, and print the location of the
@@ -255,19 +249,9 @@ print a message to stderr and exit with nonzero status.
$GIT_OBJECT_DIRECTORY is set to /foo/bar then "git rev-parse
--git-path objects/abc" returns /foo/bar/abc.
---show-cdup::
- When the command is invoked from a subdirectory, show the
- path of the top-level directory relative to the current
- directory (typically a sequence of "../", or an empty string).
-
---show-prefix::
- When the command is invoked from a subdirectory, show the
- path of the current directory relative to the top-level
- directory.
-
--show-toplevel::
- Show the absolute path of the top-level directory of the working
- tree. If there is no working tree, report an error.
+ Show the (by default, absolute) path of the top-level directory
+ of the working tree. If there is no working tree, report an error.
--show-superproject-working-tree::
Show the absolute path of the root of the superproject's
@@ -279,6 +263,36 @@ print a message to stderr and exit with nonzero status.
Show the path to the shared index file in split index mode, or
empty if not in split-index mode.
+The following options are unaffected by `--path-format`:
+
+--absolute-git-dir::
+ Like `--git-dir`, but its output is always the canonicalized
+ absolute path.
+
+--is-inside-git-dir::
+ When the current working directory is below the repository
+ directory print "true", otherwise "false".
+
+--is-inside-work-tree::
+ When the current working directory is inside the work tree of the
+ repository print "true", otherwise "false".
+
+--is-bare-repository::
+ When the repository is bare print "true", otherwise "false".
+
+--is-shallow-repository::
+ When the repository is shallow print "true", otherwise "false".
+
+--show-cdup::
+ When the command is invoked from a subdirectory, show the
+ path of the top-level directory relative to the current
+ directory (typically a sequence of "../", or an empty string).
+
+--show-prefix::
+ When the command is invoked from a subdirectory, show the
+ path of the current directory relative to the top-level
+ directory.
+
--show-object-format[=(storage|input|output)]::
Show the object format (hash algorithm) used for the repository
for storage inside the `.git` directory, input, or output. For
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index b7bbbea..93708ae 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -494,10 +494,14 @@ edit ~/.gitconfig to specify your account settings:
smtpServerPort = 587
----
-If you have multifactor authentication setup on your gmail account, you will
+If you have multi-factor authentication set up on your Gmail account, you will
need to generate an app-specific password for use with 'git send-email'. Visit
https://security.google.com/settings/security/apppasswords to create it.
+If you do not have multi-factor authentication set up on your Gmail account,
+you will need to allow less secure app access. Visit
+https://myaccount.google.com/lesssecureapps to enable it.
+
Once your commits are ready to be sent to the mailing list, run the
following commands:
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 7731b45..c0764e8 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -184,11 +184,26 @@ characters, that field will be quoted in the manner of a C string
literal: surrounded by ASCII double quote (34) characters, and with
interior special characters backslash-escaped.
-For paths with merge conflicts, `X` and `Y` show the modification
-states of each side of the merge. For paths that do not have merge
-conflicts, `X` shows the status of the index, and `Y` shows the status
-of the work tree. For untracked paths, `XY` are `??`. Other status
-codes can be interpreted as follows:
+There are three different types of states that are shown using this format, and
+each one uses the `XY` syntax differently:
+
+* When a merge is occurring and the merge was successful, or outside of a merge
+ situation, `X` shows the status of the index and `Y` shows the status of the
+ working tree.
+* When a merge conflict has occurred and has not yet been resolved, `X` and `Y`
+ show the state introduced by each head of the merge, relative to the common
+ ancestor. These paths are said to be _unmerged_.
+* When a path is untracked, `X` and `Y` are always the same, since they are
+ unknown to the index. `??` is used for untracked paths. Ignored files are
+ not listed unless `--ignored` is used; if it is, ignored files are indicated
+ by `!!`.
+
+Note that the term _merge_ here also includes rebases using the default
+`--merge` strategy, cherry-picks, and anything else using the merge machinery.
+
+In the following table, these three classes are shown in separate sections, and
+these characters are used for `X` and `Y` fields for the first two sections that
+show tracked paths:
* ' ' = unmodified
* 'M' = modified
@@ -198,9 +213,6 @@ codes can be interpreted as follows:
* 'C' = copied
* 'U' = updated but unmerged
-Ignored files are not listed, unless `--ignored` option is in effect,
-in which case `XY` are `!!`.
-
....
X Y Meaning
-------------------------------------------------
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 1489cb0..2853f16 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -30,9 +30,8 @@ SYNOPSIS
DESCRIPTION
-----------
-Modifies the index or directory cache. Each file mentioned is updated
-into the index and any 'unmerged' or 'needs updating' state is
-cleared.
+Modifies the index. Each file mentioned is updated into the index and
+any 'unmerged' or 'needs updating' state is cleared.
See also linkgit:git-add[1] for a more user-friendly way to do some of
the most common operations on the index.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index af06128..02a706c 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -143,6 +143,11 @@ locate it. Running `repair` within the recently-moved working tree will
reestablish the connection. If multiple linked working trees are moved,
running `repair` from any working tree with each tree's new `<path>` as
an argument, will reestablish the connection to all the specified paths.
++
+If both the main working tree and linked working trees have been moved
+manually, then running `repair` in the main working tree and specifying the
+new `<path>` of each linked working tree will reestablish all connections
+in both directions.
unlock::
diff --git a/Documentation/git.txt b/Documentation/git.txt
index c463b93..a6d4ad0 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -609,8 +609,8 @@ other
`GIT_SEQUENCE_EDITOR`::
This environment variable overrides the configured Git editor
when editing the todo list of an interactive rebase. See also
- linkit::git-rebase[1] and the `sequence.editor` option in
- linkit::git-config[1].
+ linkgit:git-rebase[1] and the `sequence.editor` option in
+ linkgit:git-config[1].
`GIT_SSH`::
`GIT_SSH_COMMAND`::
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index ffccfc7..1f3b57d 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -644,7 +644,7 @@ changelist text. Exiting with a non-zero status from the script
will abort the process.
The purpose of the hook is to edit the message file in place,
-and it is not supressed by the `--no-verify` option. This hook
+and it is not suppressed by the `--no-verify` option. This hook
is called even if `--prepare-p4-only` is set.
Run `git-p4 submit --help` for details.
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
index 539b4e1..8e333dd 100644
--- a/Documentation/gitmodules.txt
+++ b/Documentation/gitmodules.txt
@@ -7,7 +7,7 @@ gitmodules - Defining submodule properties
SYNOPSIS
--------
-$GIT_WORK_DIR/.gitmodules
+$GIT_WORK_TREE/.gitmodules
DESCRIPTION
@@ -27,19 +27,19 @@ submodule.<name>.path::
Defines the path, relative to the top-level directory of the Git
working tree, where the submodule is expected to be checked out.
The path name must not end with a `/`. All submodule paths must
- be unique within the .gitmodules file.
+ be unique within the `.gitmodules` file.
submodule.<name>.url::
Defines a URL from which the submodule repository can be cloned.
This may be either an absolute URL ready to be passed to
- linkgit:git-clone[1] or (if it begins with ./ or ../) a location
+ linkgit:git-clone[1] or (if it begins with `./` or `../`) a location
relative to the superproject's origin repository.
In addition, there are a number of optional keys:
submodule.<name>.update::
Defines the default update procedure for the named submodule,
- i.e. how the submodule is updated by "git submodule update"
+ i.e. how the submodule is updated by the `git submodule update`
command in the superproject. This is only used by `git
submodule init` to initialize the configuration variable of
the same name. Allowed values here are 'checkout', 'rebase',
@@ -49,7 +49,7 @@ submodule.<name>.update::
submodule.<name>.branch::
A remote branch name for tracking updates in the upstream submodule.
- If the option is not specified, it defaults to the remote 'HEAD'.
+ If the option is not specified, it defaults to the remote `HEAD`.
A special value of `.` is used to indicate that the name of the branch
in the submodule should be the same name as the current branch in the
current repository. See the `--remote` documentation in
@@ -57,14 +57,14 @@ submodule.<name>.branch::
submodule.<name>.fetchRecurseSubmodules::
This option can be used to control recursive fetching of this
- submodule. If this option is also present in the submodules entry in
- .git/config of the superproject, the setting there will override the
- one found in .gitmodules.
+ submodule. If this option is also present in the submodule's entry in
+ `.git/config` of the superproject, the setting there will override the
+ one found in `.gitmodules`.
Both settings can be overridden on the command line by using the
- "--[no-]recurse-submodules" option to "git fetch" and "git pull".
+ `--[no-]recurse-submodules` option to `git fetch` and `git pull`.
submodule.<name>.ignore::
- Defines under what circumstances "git status" and the diff family show
+ Defines under what circumstances `git status` and the diff family show
a submodule as modified. The following values are supported:
+
--
@@ -73,7 +73,7 @@ submodule.<name>.ignore::
been staged).
dirty;; All changes to the submodule's work tree will be ignored, only
- committed differences between the HEAD of the submodule and its
+ committed differences between the `HEAD` of the submodule and its
recorded state in the superproject are taken into account.
untracked;; Only untracked files in submodules will be ignored.
@@ -84,12 +84,12 @@ submodule.<name>.ignore::
differences, and modifications to tracked and untracked files are
shown. This is the default option.
-If this option is also present in the submodules entry in .git/config
+If this option is also present in the submodule's entry in `.git/config`
of the superproject, the setting there will override the one found in
-.gitmodules.
+`.gitmodules`.
Both settings can be overridden on the command line by using the
-"--ignore-submodules" option. The 'git submodule' commands are not
+`--ignore-submodules` option. The `git submodule` commands are not
affected by this setting.
--
@@ -102,7 +102,7 @@ submodule.<name>.shallow::
EXAMPLES
--------
-Consider the following .gitmodules file:
+Consider the following `.gitmodules` file:
----
[submodule "libfoo"]
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 84bbc74..6b59e28 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -252,7 +252,15 @@ endif::git-rev-list[]
interpreted by
linkgit:git-interpret-trailers[1]. The
`trailers` string may be followed by a colon
- and zero or more comma-separated options:
+ and zero or more comma-separated options.
+ If any option is provided multiple times the
+ last occurance wins.
++
+The boolean options accept an optional value `[=<BOOL>]`. The values
+`true`, `false`, `on`, `off` etc. are all accepted. See the "boolean"
+sub-section in "EXAMPLES" in linkgit:git-config[1]. If a boolean
+option is given with no value, it's enabled.
++
** 'key=<K>': only show trailers with specified key. Matching is done
case-insensitively and trailing colon is optional. If option is
given multiple times trailer lines matching any of the keys are
@@ -261,27 +269,25 @@ endif::git-rev-list[]
desired it can be disabled with `only=false`. E.g.,
`%(trailers:key=Reviewed-by)` shows trailer lines with key
`Reviewed-by`.
-** 'only[=val]': select whether non-trailer lines from the trailer
- block should be included. The `only` keyword may optionally be
- followed by an equal sign and one of `true`, `on`, `yes` to omit or
- `false`, `off`, `no` to show the non-trailer lines. If option is
- given without value it is enabled. If given multiple times the last
- value is used.
+** 'only[=<BOOL>]': select whether non-trailer lines from the trailer
+ block should be included.
** 'separator=<SEP>': specify a separator inserted between trailer
lines. When this option is not given each trailer line is
terminated with a line feed character. The string SEP may contain
the literal formatting codes described above. To use comma as
separator one must use `%x2C` as it would otherwise be parsed as
- next option. If separator option is given multiple times only the
- last one is used. E.g., `%(trailers:key=Ticket,separator=%x2C )`
+ next option. E.g., `%(trailers:key=Ticket,separator=%x2C )`
shows all trailer lines whose key is "Ticket" separated by a comma
and a space.
-** 'unfold[=val]': make it behave as if interpret-trailer's `--unfold`
- option was given. In same way as to for `only` it can be followed
- by an equal sign and explicit value. E.g.,
+** 'unfold[=<BOOL>]': make it behave as if interpret-trailer's `--unfold`
+ option was given. E.g.,
`%(trailers:only,unfold=true)` unfolds and shows all trailer lines.
-** 'valueonly[=val]': skip over the key part of the trailer line and only
- show the value part. Also this optionally allows explicit value.
+** 'keyonly[=<BOOL>]': only show the key part of the trailer.
+** 'valueonly[=<BOOL>]': only show the value part of the trailer.
+** 'key_value_separator=<SEP>': specify a separator inserted between
+ trailer lines. When this option is not given each trailer key-value
+ pair is separated by ": ". Otherwise it shares the same semantics
+ as 'separator=<SEP>' above.
NOTE: Some placeholders may depend on other options given to the
revision traversal engine. For example, the `%g*` reflog options will
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index f9a3644..69edf46 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -306,12 +306,18 @@ The remaining data of each directory block is grouped by type:
The extension starts with
- - 32-bit version number: the current supported version is 1.
+ - 32-bit version number: the current supported versions are 1 and 2.
- - 64-bit time: the extension data reflects all changes through the given
+ - (Version 1)
+ 64-bit time: the extension data reflects all changes through the given
time which is stored as the nanoseconds elapsed since midnight,
January 1, 1970.
+ - (Version 2)
+ A null terminated string: an opaque token defined by the file system
+ monitor application. The extension data reflects all changes relative
+ to that token.
+
- 32-bit bitmap size: the size of the CE_FSMONITOR_VALID bitmap.
- An ewah bitmap, the n-th bit indicates whether the n-th index entry
diff --git a/Documentation/technical/multi-pack-index.txt b/Documentation/technical/multi-pack-index.txt
index 4e76314..e8e377a 100644
--- a/Documentation/technical/multi-pack-index.txt
+++ b/Documentation/technical/multi-pack-index.txt
@@ -60,10 +60,6 @@ Design Details
Future Work
-----------
-- Add a 'verify' subcommand to the 'git midx' builtin to verify the
- contents of the multi-pack-index file match the offsets listed in
- the corresponding pack-indexes.
-
- The multi-pack-index allows many packfiles, especially in a context
where repacking is expensive (such as a very large repo), or
unexpected maintenance time is unacceptable (such as a high-demand
diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt
index f96b2e6..96d2fc5 100644
--- a/Documentation/technical/pack-format.txt
+++ b/Documentation/technical/pack-format.txt
@@ -55,6 +55,18 @@ Valid object types are:
Type 5 is reserved for future expansion. Type 0 is invalid.
+=== Size encoding
+
+This document uses the following "size encoding" of non-negative
+integers: From each byte, the seven least significant bits are
+used to form the resulting integer. As long as the most significant
+bit is 1, this process continues; the byte with MSB 0 provides the
+last seven bits. The seven-bit chunks are concatenated. Later
+values are more significant.
+
+This size encoding should not be confused with the "offset encoding",
+which is also used in this document.
+
=== Deltified representation
Conceptually there are only four object types: commit, tree, tag and
@@ -73,7 +85,10 @@ Ref-delta can also refer to an object outside the pack (i.e. the
so-called "thin pack"). When stored on disk however, the pack should
be self contained to avoid cyclic dependency.
-The delta data is a sequence of instructions to reconstruct an object
+The delta data starts with the size of the base object and the
+size of the object to be reconstructed. These sizes are
+encoded using the size encoding from above. The remainder of
+the delta data is a sequence of instructions to reconstruct the object
from the base object. If the base object is deltified, it must be
converted to canonical form first. Each instruction appends more and
more data to the target object until it's complete. There are two
diff --git a/Documentation/technical/reftable.txt b/Documentation/technical/reftable.txt
index 2951840..8095ab2 100644
--- a/Documentation/technical/reftable.txt
+++ b/Documentation/technical/reftable.txt
@@ -446,7 +446,7 @@ especially if readers will not use the object name to ref mapping.
Object blocks use unique, abbreviated 2-32 object name keys, mapping to
ref blocks containing references pointing to that object directly, or as
the peeled value of an annotated tag. Like ref blocks, object blocks use
-the file's standard block size. The abbrevation length is available in
+the file's standard block size. The abbreviation length is available in
the footer as `obj_id_len`.
To save space in small files, object blocks may be omitted if the ref
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index c3bbcc9..0327733 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.30.0-rc0
+DEF_VER=v2.30.GIT
LF='
'
diff --git a/INSTALL b/INSTALL
index 9ba33e6..8474ad0 100644
--- a/INSTALL
+++ b/INSTALL
@@ -165,8 +165,7 @@ Issues of note:
use English. Under autoconf the configure script will do this
automatically if it can't find libintl on the system.
- - Python version 2.4 or later (but not 3.x, which is not
- supported by Perforce) is needed to use the git-p4 interface
+ - Python version 2.7 or later is needed to use the git-p4 interface
to Perforce.
- Some platform specific issues are dealt with Makefile rules,
diff --git a/Makefile b/Makefile
index 6fb86c5..4edfda3 100644
--- a/Makefile
+++ b/Makefile
@@ -303,7 +303,7 @@ all::
# modules, instead of the fallbacks shipped with Git.
#
# Define PYTHON_PATH to the path of your Python binary (often /usr/bin/python
-# but /usr/bin/python2.7 on some platforms).
+# but /usr/bin/python2.7 or /usr/bin/python3 on some platforms).
#
# Define NO_PYTHON if you do not want Python scripts or libraries at all.
#
@@ -901,6 +901,7 @@ LIB_OBJS += gettext.o
LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o
LIB_OBJS += grep.o
+LIB_OBJS += hash-lookup.o
LIB_OBJS += hashmap.o
LIB_OBJS += help.o
LIB_OBJS += hex.o
@@ -937,6 +938,8 @@ LIB_OBJS += notes-cache.o
LIB_OBJS += notes-merge.o
LIB_OBJS += notes-utils.o
LIB_OBJS += notes.o
+LIB_OBJS += object-file.o
+LIB_OBJS += object-name.o
LIB_OBJS += object.o
LIB_OBJS += oid-array.o
LIB_OBJS += oidmap.o
@@ -993,9 +996,6 @@ LIB_OBJS += sequencer.o
LIB_OBJS += serve.o
LIB_OBJS += server-info.o
LIB_OBJS += setup.o
-LIB_OBJS += sha1-file.o
-LIB_OBJS += sha1-lookup.o
-LIB_OBJS += sha1-name.o
LIB_OBJS += shallow.o
LIB_OBJS += sideband.o
LIB_OBJS += sigchain.o
@@ -1554,9 +1554,6 @@ endif
ifdef NO_SYMLINK_HEAD
BASIC_CFLAGS += -DNO_SYMLINK_HEAD
endif
-ifdef GETTEXT_POISON
-$(warning The GETTEXT_POISON option has been removed in favor of runtime GIT_TEST_GETTEXT_POISON. See t/README!)
-endif
ifdef NO_GETTEXT
BASIC_CFLAGS += -DNO_GETTEXT
USE_GETTEXT_SCHEME ?= fallthrough
@@ -3062,9 +3059,9 @@ GIT_TARNAME = git-$(GIT_VERSION)
GIT_ARCHIVE_EXTRA_FILES = \
--prefix=$(GIT_TARNAME)/ \
--add-file=configure \
- --add-file=$(GIT_TARNAME)/version \
+ --add-file=.dist-tmp-dir/version \
--prefix=$(GIT_TARNAME)/git-gui/ \
- --add-file=$(GIT_TARNAME)/git-gui/version
+ --add-file=.dist-tmp-dir/git-gui/version
ifdef DC_SHA1_SUBMODULE
GIT_ARCHIVE_EXTRA_FILES += \
--prefix=$(GIT_TARNAME)/sha1collisiondetection/ \
@@ -3076,13 +3073,14 @@ GIT_ARCHIVE_EXTRA_FILES += \
--add-file=sha1collisiondetection/lib/ubc_check.h
endif
dist: git-archive$(X) configure
- @mkdir -p $(GIT_TARNAME)
- @echo $(GIT_VERSION) > $(GIT_TARNAME)/version
- @$(MAKE) -C git-gui TARDIR=../$(GIT_TARNAME)/git-gui dist-version
+ @$(RM) -r .dist-tmp-dir
+ @mkdir .dist-tmp-dir
+ @echo $(GIT_VERSION) > .dist-tmp-dir/version
+ @$(MAKE) -C git-gui TARDIR=../.dist-tmp-dir/git-gui dist-version
./git-archive --format=tar \
$(GIT_ARCHIVE_EXTRA_FILES) \
--prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
- @$(RM) -r $(GIT_TARNAME)
+ @$(RM) -r .dist-tmp-dir
gzip -f -9 $(GIT_TARNAME).tar
rpm::
@@ -3159,8 +3157,8 @@ clean: profile-clean coverage-clean cocciclean
$(RM) -r bin-wrappers $(dep_dirs) $(compdb_dir) compile_commands.json
$(RM) -r po/build/
$(RM) *.pyc *.pyo */*.pyc */*.pyo $(GENERATED_H) $(ETAGS_TARGET) tags cscope*
- $(RM) -r $(GIT_TARNAME) .doc-tmp-dir
- $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
+ $(RM) -r .dist-tmp-dir .doc-tmp-dir
+ $(RM) $(GIT_TARNAME).tar.gz
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
$(MAKE) -C Documentation/ clean
$(RM) Documentation/GIT-EXCLUDED-PROGRAMS
diff --git a/RelNotes b/RelNotes
index dc8c04b..3324fc0 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.30.0.txt \ No newline at end of file
+Documentation/RelNotes/2.31.0.txt \ No newline at end of file
diff --git a/abspath.c b/abspath.c
index 6f15a41..39e06b5 100644
--- a/abspath.c
+++ b/abspath.c
@@ -67,19 +67,15 @@ static void get_root_part(struct strbuf *resolved, struct strbuf *remaining)
#endif
/*
- * Return the real path (i.e., absolute path, with symlinks resolved
- * and extra slashes removed) equivalent to the specified path. (If
- * you want an absolute path but don't mind links, use
- * absolute_path().) Places the resolved realpath in the provided strbuf.
- *
- * The directory part of path (i.e., everything up to the last
- * dir_sep) must denote a valid, existing directory, but the last
- * component need not exist. If die_on_error is set, then die with an
- * informative error message if there is a problem. Otherwise, return
- * NULL on errors (without generating any output).
+ * If set, any number of trailing components may be missing; otherwise, only one
+ * may be.
*/
-char *strbuf_realpath(struct strbuf *resolved, const char *path,
- int die_on_error)
+#define REALPATH_MANY_MISSING (1 << 0)
+/* Should we die if there's an error? */
+#define REALPATH_DIE_ON_ERROR (1 << 1)
+
+static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
+ int flags)
{
struct strbuf remaining = STRBUF_INIT;
struct strbuf next = STRBUF_INIT;
@@ -89,7 +85,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
struct stat st;
if (!*path) {
- if (die_on_error)
+ if (flags & REALPATH_DIE_ON_ERROR)
die("The empty string is not a valid path");
else
goto error_out;
@@ -101,7 +97,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
if (!resolved->len) {
/* relative path; can use CWD as the initial resolved path */
if (strbuf_getcwd(resolved)) {
- if (die_on_error)
+ if (flags & REALPATH_DIE_ON_ERROR)
die_errno("unable to get current working directory");
else
goto error_out;
@@ -129,8 +125,9 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
if (lstat(resolved->buf, &st)) {
/* error out unless this was the last component */
- if (errno != ENOENT || remaining.len) {
- if (die_on_error)
+ if (errno != ENOENT ||
+ (!(flags & REALPATH_MANY_MISSING) && remaining.len)) {
+ if (flags & REALPATH_DIE_ON_ERROR)
die_errno("Invalid path '%s'",
resolved->buf);
else
@@ -143,7 +140,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
if (num_symlinks++ > MAXSYMLINKS) {
errno = ELOOP;
- if (die_on_error)
+ if (flags & REALPATH_DIE_ON_ERROR)
die("More than %d nested symlinks "
"on path '%s'", MAXSYMLINKS, path);
else
@@ -153,7 +150,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
len = strbuf_readlink(&symlink, resolved->buf,
st.st_size);
if (len < 0) {
- if (die_on_error)
+ if (flags & REALPATH_DIE_ON_ERROR)
die_errno("Invalid symlink '%s'",
resolved->buf);
else
@@ -202,6 +199,37 @@ error_out:
return retval;
}
+/*
+ * Return the real path (i.e., absolute path, with symlinks resolved
+ * and extra slashes removed) equivalent to the specified path. (If
+ * you want an absolute path but don't mind links, use
+ * absolute_path().) Places the resolved realpath in the provided strbuf.
+ *
+ * The directory part of path (i.e., everything up to the last
+ * dir_sep) must denote a valid, existing directory, but the last
+ * component need not exist. If die_on_error is set, then die with an
+ * informative error message if there is a problem. Otherwise, return
+ * NULL on errors (without generating any output).
+ */
+char *strbuf_realpath(struct strbuf *resolved, const char *path,
+ int die_on_error)
+{
+ return strbuf_realpath_1(resolved, path,
+ die_on_error ? REALPATH_DIE_ON_ERROR : 0);
+}
+
+/*
+ * Just like strbuf_realpath, but allows an arbitrary number of path
+ * components to be missing.
+ */
+char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path,
+ int die_on_error)
+{
+ return strbuf_realpath_1(resolved, path,
+ ((die_on_error ? REALPATH_DIE_ON_ERROR : 0) |
+ REALPATH_MANY_MISSING));
+}
+
char *real_pathdup(const char *path, int die_on_error)
{
struct strbuf realpath = STRBUF_INIT;
diff --git a/apply.c b/apply.c
index 4a4e9a0..668b16e 100644
--- a/apply.c
+++ b/apply.c
@@ -3948,10 +3948,8 @@ static int check_patch(struct apply_state *state, struct patch *patch)
break; /* happy */
case EXISTS_IN_INDEX:
return error(_("%s: already exists in index"), new_name);
- break;
case EXISTS_IN_INDEX_AS_ITA:
return error(_("%s: does not match index"), new_name);
- break;
case EXISTS_IN_WORKTREE:
return error(_("%s: already exists in working directory"),
new_name);
diff --git a/bisect.c b/bisect.c
index d8c2c8f..75ea0eb 100644
--- a/bisect.c
+++ b/bisect.c
@@ -6,7 +6,7 @@
#include "refs.h"
#include "list-objects.h"
#include "quote.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
#include "run-command.h"
#include "log-tree.h"
#include "bisect.h"
diff --git a/builtin/am.c b/builtin/am.c
index f22c73a..8355e35 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -2284,10 +2284,10 @@ int cmd_am(int argc, const char **argv, const char *prefix)
N_("skip the current patch"),
RESUME_SKIP),
OPT_CMDMODE(0, "abort", &resume.mode,
- N_("restore the original branch and abort the patching operation."),
+ N_("restore the original branch and abort the patching operation"),
RESUME_ABORT),
OPT_CMDMODE(0, "quit", &resume.mode,
- N_("abort the patching operation but keep HEAD where it is."),
+ N_("abort the patching operation but keep HEAD where it is"),
RESUME_QUIT),
{ OPTION_CALLBACK, 0, "show-current-patch", &resume.mode,
"(diff|raw)",
diff --git a/builtin/blame.c b/builtin/blame.c
index 6f7e324..2c1c02c 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -866,33 +866,33 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
const char *revs_file = NULL;
const char *contents_from = NULL;
const struct option options[] = {
- OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
- OPT_BOOL('b', NULL, &blank_boundary, N_("Do not show object names of boundary commits (Default: off)")),
- OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
- OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")),
- OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")),
- OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE),
- OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
- OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
- OPT_BIT('p', "porcelain", &output_option, N_("Show in a format designed for machine consumption"), OUTPUT_PORCELAIN),
- OPT_BIT(0, "line-porcelain", &output_option, N_("Show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
- OPT_BIT('c', NULL, &output_option, N_("Use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT),
- OPT_BIT('t', NULL, &output_option, N_("Show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP),
- OPT_BIT('l', NULL, &output_option, N_("Show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME),
- OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
- OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
- OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
- OPT_STRING_LIST(0, "ignore-rev", &ignore_rev_list, N_("rev"), N_("Ignore <rev> when blaming")),
- OPT_STRING_LIST(0, "ignore-revs-file", &ignore_revs_file_list, N_("file"), N_("Ignore revisions from <file>")),
+ OPT_BOOL(0, "incremental", &incremental, N_("show blame entries as we find them, incrementally")),
+ OPT_BOOL('b', NULL, &blank_boundary, N_("do not show object names of boundary commits (Default: off)")),
+ OPT_BOOL(0, "root", &show_root, N_("do not treat root commits as boundaries (Default: off)")),
+ OPT_BOOL(0, "show-stats", &show_stats, N_("show work cost statistics")),
+ OPT_BOOL(0, "progress", &show_progress, N_("force progress reporting")),
+ OPT_BIT(0, "score-debug", &output_option, N_("show output score for blame entries"), OUTPUT_SHOW_SCORE),
+ OPT_BIT('f', "show-name", &output_option, N_("show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
+ OPT_BIT('n', "show-number", &output_option, N_("show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
+ OPT_BIT('p', "porcelain", &output_option, N_("show in a format designed for machine consumption"), OUTPUT_PORCELAIN),
+ OPT_BIT(0, "line-porcelain", &output_option, N_("show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
+ OPT_BIT('c', NULL, &output_option, N_("use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT),
+ OPT_BIT('t', NULL, &output_option, N_("show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP),
+ OPT_BIT('l', NULL, &output_option, N_("show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME),
+ OPT_BIT('s', NULL, &output_option, N_("suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
+ OPT_BIT('e', "show-email", &output_option, N_("show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
+ OPT_BIT('w', NULL, &xdl_opts, N_("ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
+ OPT_STRING_LIST(0, "ignore-rev", &ignore_rev_list, N_("rev"), N_("ignore <rev> when blaming")),
+ OPT_STRING_LIST(0, "ignore-revs-file", &ignore_revs_file_list, N_("file"), N_("ignore revisions from <file>")),
OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
- OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
- OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
- OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
- OPT_CALLBACK_F('C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback),
- OPT_CALLBACK_F('M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback),
+ OPT_BIT(0, "minimal", &xdl_opts, N_("spend extra cycles to find better match"), XDF_NEED_MINIMAL),
+ OPT_STRING('S', NULL, &revs_file, N_("file"), N_("use revisions from <file> instead of calling git-rev-list")),
+ OPT_STRING(0, "contents", &contents_from, N_("file"), N_("use <file>'s contents as the final image")),
+ OPT_CALLBACK_F('C', NULL, &opt, N_("score"), N_("find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback),
+ OPT_CALLBACK_F('M', NULL, &opt, N_("score"), N_("find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback),
OPT_STRING_LIST('L', NULL, &range_list, N_("range"),
- N_("Process only line range <start>,<end> or function :<funcname>")),
+ N_("process only line range <start>,<end> or function :<funcname>")),
OPT__ABBREV(&abbrev),
OPT_END()
};
diff --git a/builtin/branch.c b/builtin/branch.c
index 173b736..8c0b428 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -538,7 +538,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
oldref.buf, newref.buf);
- if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf))
+ if (!copy &&
+ (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) &&
+ rename_ref(oldref.buf, newref.buf, logmsg.buf))
die(_("Branch rename failed"));
if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf))
die(_("Branch copy failed"));
@@ -724,7 +726,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
print_current_branch_name();
return 0;
} else if (list) {
- /* git branch --local also shows HEAD when it is detached */
+ /* git branch --list also shows HEAD when it is detached */
if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
filter.kind |= FILTER_REFS_DETACHED_HEAD;
filter.name_patterns = argv;
@@ -737,7 +739,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
*/
if (!sorting)
sorting = ref_default_sorting();
- ref_sorting_icase_all(sorting, icase);
+ ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
+ ref_sorting_set_sort_flags_all(
+ sorting, REF_SORTING_DETACHED_HEAD_FIRST, 1);
print_ref_list(&filter, sorting, &format);
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 9b82119..c9ba23c 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -480,9 +480,11 @@ static int checkout_paths(const struct checkout_opts *opts,
* with the hex of the commit (whether it's in `...` form or
* not) for the run_add_interactive() machinery to work
* properly. However, there is special logic for the HEAD case
- * so we mustn't replace that.
+ * so we mustn't replace that. Also, when we were given a
+ * tree-object, new_branch_info->commit would be NULL, but we
+ * do not have to do any replacement, either.
*/
- if (rev && strcmp(rev, "HEAD"))
+ if (rev && new_branch_info->commit && strcmp(rev, "HEAD"))
rev = oid_to_hex_r(rev_oid, &new_branch_info->commit->object.oid);
if (opts->checkout_index && opts->checkout_worktree)
diff --git a/builtin/clone.c b/builtin/clone.c
index a084192..e335734 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1293,8 +1293,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
break;
}
- if (!is_local && !complete_refs_before_fetch)
- transport_fetch_refs(transport, mapped_refs);
+ if (!is_local && !complete_refs_before_fetch) {
+ err = transport_fetch_refs(transport, mapped_refs);
+ if (err)
+ goto cleanup;
+ }
remote_head = find_ref_by_name(refs, "HEAD");
remote_head_points_at =
@@ -1323,7 +1326,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote_head = NULL;
option_no_checkout = 1;
if (!option_bare) {
- const char *branch = git_default_branch_name();
+ const char *branch = git_default_branch_name(0);
char *ref = xstrfmt("refs/heads/%s", branch);
install_branch_config(0, branch, remote_name, ref);
@@ -1339,8 +1342,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (is_local)
clone_local(path, git_dir);
- else if (refs && complete_refs_before_fetch)
- transport_fetch_refs(transport, mapped_refs);
+ else if (refs && complete_refs_before_fetch) {
+ err = transport_fetch_refs(transport, mapped_refs);
+ if (err)
+ goto cleanup;
+ }
update_remote_refs(refs, mapped_refs, remote_head_points_at,
branch_top.buf, reflog_msg.buf, transport,
@@ -1367,6 +1373,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
junk_mode = JUNK_LEAVE_REPO;
err = checkout(submodule_progress);
+cleanup:
free(remote_name);
strbuf_release(&reflog_msg);
strbuf_release(&branch_top);
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 78fa08f..cd86315 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -78,7 +78,7 @@ static int graph_verify(int argc, const char **argv)
static struct option builtin_commit_graph_verify_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
N_("dir"),
- N_("The object directory to store the graph")),
+ N_("the object directory to store the graph")),
OPT_BOOL(0, "shallow", &opts.shallow,
N_("if the commit-graph is split, only verify the tip file")),
OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
@@ -208,7 +208,7 @@ static int graph_write(int argc, const char **argv)
static struct option builtin_commit_graph_write_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
N_("dir"),
- N_("The object directory to store the graph")),
+ N_("the object directory to store the graph")),
OPT_BOOL(0, "reachable", &opts.reachable,
N_("start walk at all refs")),
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
@@ -314,7 +314,7 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
static struct option builtin_commit_graph_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
N_("dir"),
- N_("The object directory to store the graph")),
+ N_("the object directory to store the graph")),
OPT_END(),
};
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index d2e33f5..85a76e0 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -923,7 +923,6 @@ static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
if (!tag)
die("Tag %s points nowhere?", e->name);
return (struct commit *)tag;
- break;
}
default:
return NULL;
@@ -1206,32 +1205,32 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
N_("select handling of commit messages in an alternate encoding"),
parse_opt_reencode_mode),
OPT_STRING(0, "export-marks", &export_filename, N_("file"),
- N_("Dump marks to this file")),
+ N_("dump marks to this file")),
OPT_STRING(0, "import-marks", &import_filename, N_("file"),
- N_("Import marks from this file")),
+ N_("import marks from this file")),
OPT_STRING(0, "import-marks-if-exists",
&import_filename_if_exists,
N_("file"),
- N_("Import marks from this file if it exists")),
+ N_("import marks from this file if it exists")),
OPT_BOOL(0, "fake-missing-tagger", &fake_missing_tagger,
- N_("Fake a tagger when tags lack one")),
+ N_("fake a tagger when tags lack one")),
OPT_BOOL(0, "full-tree", &full_tree,
- N_("Output full tree for each commit")),
+ N_("output full tree for each commit")),
OPT_BOOL(0, "use-done-feature", &use_done_feature,
- N_("Use the done feature to terminate the stream")),
- OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
+ N_("use the done feature to terminate the stream")),
+ OPT_BOOL(0, "no-data", &no_data, N_("skip output of blob data")),
OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
- N_("Apply refspec to exported refs")),
+ N_("apply refspec to exported refs")),
OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
OPT_CALLBACK_F(0, "anonymize-map", &anonymized_seeds, N_("from:to"),
N_("convert <from> to <to> in anonymized output"),
PARSE_OPT_NONEG, parse_opt_anonymize_map),
OPT_BOOL(0, "reference-excluded-parents",
- &reference_excluded_commits, N_("Reference parents which are not in fast-export stream by object id")),
+ &reference_excluded_commits, N_("reference parents which are not in fast-export stream by object id")),
OPT_BOOL(0, "show-original-ids", &show_original_ids,
- N_("Show original object ids of blobs/commits")),
+ N_("show original object ids of blobs/commits")),
OPT_BOOL(0, "mark-tags", &mark_tags,
- N_("Label tags with mark ids")),
+ N_("label tags with mark ids")),
OPT_END()
};
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 9d1ecda..cb9c81a 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -70,7 +70,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
if (!sorting)
sorting = ref_default_sorting();
- ref_sorting_icase_all(sorting, icase);
+ ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
filter.ignore_case = icase;
filter.name_patterns = argv;
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
index 5bba623..52be64a 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -51,6 +51,13 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
values = repo_config_get_value_multi(the_repository,
config_key);
+ /*
+ * Do nothing on an empty list, which is equivalent to the case
+ * where the config variable does not exist at all.
+ */
+ if (!values)
+ return 0;
+
for (i = 0; !result && i < values->nr; i++)
result = run_command_on_repo(values->items[i].string, &args);
diff --git a/builtin/fsck.c b/builtin/fsck.c
index fbf26ca..821e779 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -73,25 +73,7 @@ static const char *printable_type(const struct object_id *oid,
static int fsck_config(const char *var, const char *value, void *cb)
{
- if (strcmp(var, "fsck.skiplist") == 0) {
- const char *path;
- struct strbuf sb = STRBUF_INIT;
-
- if (git_config_pathname(&path, var, value))
- return 1;
- strbuf_addf(&sb, "skiplist=%s", path);
- free((char *)path);
- fsck_set_msg_types(&fsck_obj_options, sb.buf);
- strbuf_release(&sb);
- return 0;
- }
-
- if (skip_prefix(var, "fsck.", &var)) {
- fsck_set_msg_type(&fsck_obj_options, var, value);
- return 0;
- }
-
- return git_default_config(var, value, cb);
+ return fsck_config_internal(var, value, cb, &fsck_obj_options);
}
static int objerror(struct object *obj, const char *err)
diff --git a/builtin/gc.c b/builtin/gc.c
index b57fda4..fe35b10 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -92,7 +92,7 @@ static void process_log_file(void)
*/
int saved_errno = errno;
fprintf(stderr, _("Failed to fstat %s: %s"),
- get_tempfile_path(log_lock.tempfile),
+ get_lock_file_path(&log_lock),
strerror(saved_errno));
fflush(stderr);
commit_lock_file(&log_lock);
@@ -1493,38 +1493,368 @@ static int maintenance_unregister(void)
return run_command(&config_unset);
}
+static const char *get_frequency(enum schedule_priority schedule)
+{
+ switch (schedule) {
+ case SCHEDULE_HOURLY:
+ return "hourly";
+ case SCHEDULE_DAILY:
+ return "daily";
+ case SCHEDULE_WEEKLY:
+ return "weekly";
+ default:
+ BUG("invalid schedule %d", schedule);
+ }
+}
+
+static char *launchctl_service_name(const char *frequency)
+{
+ struct strbuf label = STRBUF_INIT;
+ strbuf_addf(&label, "org.git-scm.git.%s", frequency);
+ return strbuf_detach(&label, NULL);
+}
+
+static char *launchctl_service_filename(const char *name)
+{
+ char *expanded;
+ struct strbuf filename = STRBUF_INIT;
+ strbuf_addf(&filename, "~/Library/LaunchAgents/%s.plist", name);
+
+ expanded = expand_user_path(filename.buf, 1);
+ if (!expanded)
+ die(_("failed to expand path '%s'"), filename.buf);
+
+ strbuf_release(&filename);
+ return expanded;
+}
+
+static char *launchctl_get_uid(void)
+{
+ return xstrfmt("gui/%d", getuid());
+}
+
+static int launchctl_boot_plist(int enable, const char *filename, const char *cmd)
+{
+ int result;
+ struct child_process child = CHILD_PROCESS_INIT;
+ char *uid = launchctl_get_uid();
+
+ strvec_split(&child.args, cmd);
+ if (enable)
+ strvec_push(&child.args, "bootstrap");
+ else
+ strvec_push(&child.args, "bootout");
+ strvec_push(&child.args, uid);
+ strvec_push(&child.args, filename);
+
+ child.no_stderr = 1;
+ child.no_stdout = 1;
+
+ if (start_command(&child))
+ die(_("failed to start launchctl"));
+
+ result = finish_command(&child);
+
+ free(uid);
+ return result;
+}
+
+static int launchctl_remove_plist(enum schedule_priority schedule, const char *cmd)
+{
+ const char *frequency = get_frequency(schedule);
+ char *name = launchctl_service_name(frequency);
+ char *filename = launchctl_service_filename(name);
+ int result = launchctl_boot_plist(0, filename, cmd);
+ unlink(filename);
+ free(filename);
+ free(name);
+ return result;
+}
+
+static int launchctl_remove_plists(const char *cmd)
+{
+ return launchctl_remove_plist(SCHEDULE_HOURLY, cmd) ||
+ launchctl_remove_plist(SCHEDULE_DAILY, cmd) ||
+ launchctl_remove_plist(SCHEDULE_WEEKLY, cmd);
+}
+
+static int launchctl_schedule_plist(const char *exec_path, enum schedule_priority schedule, const char *cmd)
+{
+ FILE *plist;
+ int i;
+ const char *preamble, *repeat;
+ const char *frequency = get_frequency(schedule);
+ char *name = launchctl_service_name(frequency);
+ char *filename = launchctl_service_filename(name);
+
+ if (safe_create_leading_directories(filename))
+ die(_("failed to create directories for '%s'"), filename);
+ plist = xfopen(filename, "w");
+
+ preamble = "<?xml version=\"1.0\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+ "<plist version=\"1.0\">"
+ "<dict>\n"
+ "<key>Label</key><string>%s</string>\n"
+ "<key>ProgramArguments</key>\n"
+ "<array>\n"
+ "<string>%s/git</string>\n"
+ "<string>--exec-path=%s</string>\n"
+ "<string>for-each-repo</string>\n"
+ "<string>--config=maintenance.repo</string>\n"
+ "<string>maintenance</string>\n"
+ "<string>run</string>\n"
+ "<string>--schedule=%s</string>\n"
+ "</array>\n"
+ "<key>StartCalendarInterval</key>\n"
+ "<array>\n";
+ fprintf(plist, preamble, name, exec_path, exec_path, frequency);
+
+ switch (schedule) {
+ case SCHEDULE_HOURLY:
+ repeat = "<dict>\n"
+ "<key>Hour</key><integer>%d</integer>\n"
+ "<key>Minute</key><integer>0</integer>\n"
+ "</dict>\n";
+ for (i = 1; i <= 23; i++)
+ fprintf(plist, repeat, i);
+ break;
+
+ case SCHEDULE_DAILY:
+ repeat = "<dict>\n"
+ "<key>Day</key><integer>%d</integer>\n"
+ "<key>Hour</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>0</integer>\n"
+ "</dict>\n";
+ for (i = 1; i <= 6; i++)
+ fprintf(plist, repeat, i);
+ break;
+
+ case SCHEDULE_WEEKLY:
+ fprintf(plist,
+ "<dict>\n"
+ "<key>Day</key><integer>0</integer>\n"
+ "<key>Hour</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>0</integer>\n"
+ "</dict>\n");
+ break;
+
+ default:
+ /* unreachable */
+ break;
+ }
+ fprintf(plist, "</array>\n</dict>\n</plist>\n");
+ fclose(plist);
+
+ /* bootout might fail if not already running, so ignore */
+ launchctl_boot_plist(0, filename, cmd);
+ if (launchctl_boot_plist(1, filename, cmd))
+ die(_("failed to bootstrap service %s"), filename);
+
+ free(filename);
+ free(name);
+ return 0;
+}
+
+static int launchctl_add_plists(const char *cmd)
+{
+ const char *exec_path = git_exec_path();
+
+ return launchctl_schedule_plist(exec_path, SCHEDULE_HOURLY, cmd) ||
+ launchctl_schedule_plist(exec_path, SCHEDULE_DAILY, cmd) ||
+ launchctl_schedule_plist(exec_path, SCHEDULE_WEEKLY, cmd);
+}
+
+static int launchctl_update_schedule(int run_maintenance, int fd, const char *cmd)
+{
+ if (run_maintenance)
+ return launchctl_add_plists(cmd);
+ else
+ return launchctl_remove_plists(cmd);
+}
+
+static char *schtasks_task_name(const char *frequency)
+{
+ struct strbuf label = STRBUF_INIT;
+ strbuf_addf(&label, "Git Maintenance (%s)", frequency);
+ return strbuf_detach(&label, NULL);
+}
+
+static int schtasks_remove_task(enum schedule_priority schedule, const char *cmd)
+{
+ int result;
+ struct strvec args = STRVEC_INIT;
+ const char *frequency = get_frequency(schedule);
+ char *name = schtasks_task_name(frequency);
+
+ strvec_split(&args, cmd);
+ strvec_pushl(&args, "/delete", "/tn", name, "/f", NULL);
+
+ result = run_command_v_opt(args.v, 0);
+
+ strvec_clear(&args);
+ free(name);
+ return result;
+}
+
+static int schtasks_remove_tasks(const char *cmd)
+{
+ return schtasks_remove_task(SCHEDULE_HOURLY, cmd) ||
+ schtasks_remove_task(SCHEDULE_DAILY, cmd) ||
+ schtasks_remove_task(SCHEDULE_WEEKLY, cmd);
+}
+
+static int schtasks_schedule_task(const char *exec_path, enum schedule_priority schedule, const char *cmd)
+{
+ int result;
+ struct child_process child = CHILD_PROCESS_INIT;
+ const char *xml;
+ struct tempfile *tfile;
+ const char *frequency = get_frequency(schedule);
+ char *name = schtasks_task_name(frequency);
+ struct strbuf tfilename = STRBUF_INIT;
+
+ strbuf_addf(&tfilename, "%s/schedule_%s_XXXXXX",
+ get_git_common_dir(), frequency);
+ tfile = xmks_tempfile(tfilename.buf);
+ strbuf_release(&tfilename);
+
+ if (!fdopen_tempfile(tfile, "w"))
+ die(_("failed to create temp xml file"));
+
+ xml = "<?xml version=\"1.0\" ?>\n"
+ "<Task version=\"1.4\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\">\n"
+ "<Triggers>\n"
+ "<CalendarTrigger>\n";
+ fputs(xml, tfile->fp);
+
+ switch (schedule) {
+ case SCHEDULE_HOURLY:
+ fprintf(tfile->fp,
+ "<StartBoundary>2020-01-01T01:00:00</StartBoundary>\n"
+ "<Enabled>true</Enabled>\n"
+ "<ScheduleByDay>\n"
+ "<DaysInterval>1</DaysInterval>\n"
+ "</ScheduleByDay>\n"
+ "<Repetition>\n"
+ "<Interval>PT1H</Interval>\n"
+ "<Duration>PT23H</Duration>\n"
+ "<StopAtDurationEnd>false</StopAtDurationEnd>\n"
+ "</Repetition>\n");
+ break;
+
+ case SCHEDULE_DAILY:
+ fprintf(tfile->fp,
+ "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+ "<Enabled>true</Enabled>\n"
+ "<ScheduleByWeek>\n"
+ "<DaysOfWeek>\n"
+ "<Monday />\n"
+ "<Tuesday />\n"
+ "<Wednesday />\n"
+ "<Thursday />\n"
+ "<Friday />\n"
+ "<Saturday />\n"
+ "</DaysOfWeek>\n"
+ "<WeeksInterval>1</WeeksInterval>\n"
+ "</ScheduleByWeek>\n");
+ break;
+
+ case SCHEDULE_WEEKLY:
+ fprintf(tfile->fp,
+ "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+ "<Enabled>true</Enabled>\n"
+ "<ScheduleByWeek>\n"
+ "<DaysOfWeek>\n"
+ "<Sunday />\n"
+ "</DaysOfWeek>\n"
+ "<WeeksInterval>1</WeeksInterval>\n"
+ "</ScheduleByWeek>\n");
+ break;
+
+ default:
+ break;
+ }
+
+ xml = "</CalendarTrigger>\n"
+ "</Triggers>\n"
+ "<Principals>\n"
+ "<Principal id=\"Author\">\n"
+ "<LogonType>InteractiveToken</LogonType>\n"
+ "<RunLevel>LeastPrivilege</RunLevel>\n"
+ "</Principal>\n"
+ "</Principals>\n"
+ "<Settings>\n"
+ "<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>\n"
+ "<Enabled>true</Enabled>\n"
+ "<Hidden>true</Hidden>\n"
+ "<UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>\n"
+ "<WakeToRun>false</WakeToRun>\n"
+ "<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>\n"
+ "<Priority>7</Priority>\n"
+ "</Settings>\n"
+ "<Actions Context=\"Author\">\n"
+ "<Exec>\n"
+ "<Command>\"%s\\git.exe\"</Command>\n"
+ "<Arguments>--exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
+ "</Exec>\n"
+ "</Actions>\n"
+ "</Task>\n";
+ fprintf(tfile->fp, xml, exec_path, exec_path, frequency);
+ strvec_split(&child.args, cmd);
+ strvec_pushl(&child.args, "/create", "/tn", name, "/f", "/xml",
+ get_tempfile_path(tfile), NULL);
+ close_tempfile_gently(tfile);
+
+ child.no_stdout = 1;
+ child.no_stderr = 1;
+
+ if (start_command(&child))
+ die(_("failed to start schtasks"));
+ result = finish_command(&child);
+
+ delete_tempfile(&tfile);
+ free(name);
+ return result;
+}
+
+static int schtasks_schedule_tasks(const char *cmd)
+{
+ const char *exec_path = git_exec_path();
+
+ return schtasks_schedule_task(exec_path, SCHEDULE_HOURLY, cmd) ||
+ schtasks_schedule_task(exec_path, SCHEDULE_DAILY, cmd) ||
+ schtasks_schedule_task(exec_path, SCHEDULE_WEEKLY, cmd);
+}
+
+static int schtasks_update_schedule(int run_maintenance, int fd, const char *cmd)
+{
+ if (run_maintenance)
+ return schtasks_schedule_tasks(cmd);
+ else
+ return schtasks_remove_tasks(cmd);
+}
+
#define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE"
#define END_LINE "# END GIT MAINTENANCE SCHEDULE"
-static int update_background_schedule(int run_maintenance)
+static int crontab_update_schedule(int run_maintenance, int fd, const char *cmd)
{
int result = 0;
int in_old_region = 0;
struct child_process crontab_list = CHILD_PROCESS_INIT;
struct child_process crontab_edit = CHILD_PROCESS_INIT;
FILE *cron_list, *cron_in;
- const char *crontab_name;
struct strbuf line = STRBUF_INIT;
- struct lock_file lk;
- char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path);
- if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0)
- return error(_("another process is scheduling background maintenance"));
-
- crontab_name = getenv("GIT_TEST_CRONTAB");
- if (!crontab_name)
- crontab_name = "crontab";
-
- strvec_split(&crontab_list.args, crontab_name);
+ strvec_split(&crontab_list.args, cmd);
strvec_push(&crontab_list.args, "-l");
crontab_list.in = -1;
- crontab_list.out = dup(lk.tempfile->fd);
+ crontab_list.out = dup(fd);
crontab_list.git_cmd = 0;
- if (start_command(&crontab_list)) {
- result = error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
- goto cleanup;
- }
+ if (start_command(&crontab_list))
+ return error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
/* Ignore exit code, as an empty crontab will return error. */
finish_command(&crontab_list);
@@ -1533,17 +1863,15 @@ static int update_background_schedule(int run_maintenance)
* Read from the .lock file, filtering out the old
* schedule while appending the new schedule.
*/
- cron_list = fdopen(lk.tempfile->fd, "r");
+ cron_list = fdopen(fd, "r");
rewind(cron_list);
- strvec_split(&crontab_edit.args, crontab_name);
+ strvec_split(&crontab_edit.args, cmd);
crontab_edit.in = -1;
crontab_edit.git_cmd = 0;
- if (start_command(&crontab_edit)) {
- result = error(_("failed to run 'crontab'; your system might not support 'cron'"));
- goto cleanup;
- }
+ if (start_command(&crontab_edit))
+ return error(_("failed to run 'crontab'; your system might not support 'cron'"));
cron_in = fdopen(crontab_edit.in, "w");
if (!cron_in) {
@@ -1554,11 +1882,10 @@ static int update_background_schedule(int run_maintenance)
while (!strbuf_getline_lf(&line, cron_list)) {
if (!in_old_region && !strcmp(line.buf, BEGIN_LINE))
in_old_region = 1;
- if (in_old_region)
- continue;
- fprintf(cron_in, "%s\n", line.buf);
- if (in_old_region && !strcmp(line.buf, END_LINE))
+ else if (in_old_region && !strcmp(line.buf, END_LINE))
in_old_region = 0;
+ else if (!in_old_region)
+ fprintf(cron_in, "%s\n", line.buf);
}
if (run_maintenance) {
@@ -1588,14 +1915,54 @@ static int update_background_schedule(int run_maintenance)
close(crontab_edit.in);
done_editing:
- if (finish_command(&crontab_edit)) {
+ if (finish_command(&crontab_edit))
result = error(_("'crontab' died"));
- goto cleanup;
+ else
+ fclose(cron_list);
+ return result;
+}
+
+#if defined(__APPLE__)
+static const char platform_scheduler[] = "launchctl";
+#elif defined(GIT_WINDOWS_NATIVE)
+static const char platform_scheduler[] = "schtasks";
+#else
+static const char platform_scheduler[] = "crontab";
+#endif
+
+static int update_background_schedule(int enable)
+{
+ int result;
+ const char *scheduler = platform_scheduler;
+ const char *cmd = scheduler;
+ char *testing;
+ struct lock_file lk;
+ char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path);
+
+ testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER"));
+ if (testing) {
+ char *sep = strchr(testing, ':');
+ if (!sep)
+ die("GIT_TEST_MAINT_SCHEDULER unparseable: %s", testing);
+ *sep = '\0';
+ scheduler = testing;
+ cmd = sep + 1;
}
- fclose(cron_list);
-cleanup:
+ if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0)
+ return error(_("another process is scheduling background maintenance"));
+
+ if (!strcmp(scheduler, "launchctl"))
+ result = launchctl_update_schedule(enable, get_lock_file_fd(&lk), cmd);
+ else if (!strcmp(scheduler, "schtasks"))
+ result = schtasks_update_schedule(enable, get_lock_file_fd(&lk), cmd);
+ else if (!strcmp(scheduler, "crontab"))
+ result = crontab_update_schedule(enable, get_lock_file_fd(&lk), cmd);
+ else
+ die("unknown background scheduler: %s", scheduler);
+
rollback_lock_file(&lk);
+ free(testing);
return result;
}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 4b8d86e..557bd2f 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1641,7 +1641,7 @@ static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)
/*
* Get rid of the idx file as we do not need it anymore.
* NEEDSWORK: extract this bit from free_pack_by_name() in
- * sha1-file.c, perhaps? It shouldn't matter very much as we
+ * object-file.c, perhaps? It shouldn't matter very much as we
* know we haven't installed this pack (hence we never have
* read anything from it).
*/
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 01bc648..dcc45be 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -202,7 +202,8 @@ void initialize_repository_version(int hash_algo, int reinit)
static int create_default_files(const char *template_path,
const char *original_git_dir,
const char *initial_branch,
- const struct repository_format *fmt)
+ const struct repository_format *fmt,
+ int quiet)
{
struct stat st1;
struct strbuf buf = STRBUF_INIT;
@@ -267,7 +268,7 @@ static int create_default_files(const char *template_path,
char *ref;
if (!initial_branch)
- initial_branch = git_default_branch_name();
+ initial_branch = git_default_branch_name(quiet);
ref = xstrfmt("refs/heads/%s", initial_branch);
if (check_refname_format(ref, 0) < 0)
@@ -438,7 +439,8 @@ int init_db(const char *git_dir, const char *real_git_dir,
validate_hash_algorithm(&repo_fmt, hash);
reinit = create_default_files(template_dir, original_git_dir,
- initial_branch, &repo_fmt);
+ initial_branch, &repo_fmt,
+ flags & INIT_DB_QUIET);
if (reinit && initial_branch)
warning(_("re-init: ignored --initial-branch=%s"),
initial_branch);
diff --git a/builtin/log.c b/builtin/log.c
index bd6ff4f..f23ccdb 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -177,7 +177,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
const struct option builtin_log_options[] = {
OPT__QUIET(&quiet, N_("suppress diff output")),
OPT_BOOL(0, "source", &source, N_("show source")),
- OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
+ OPT_BOOL(0, "use-mailmap", &mailmap, N_("use mail map file")),
OPT_ALIAS(0, "mailmap", "use-mailmap"),
OPT_STRING_LIST(0, "decorate-refs", &decorate_refs_include,
N_("pattern"), N_("only decorate refs that match <pattern>")),
@@ -186,7 +186,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
OPT_CALLBACK_F(0, "decorate", NULL, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback),
OPT_CALLBACK('L', NULL, &line_cb, "range:file",
- N_("Trace the evolution of line range <start>,<end> or function :<funcname> in <file>"),
+ N_("trace the evolution of line range <start>,<end> or function :<funcname> in <file>"),
log_line_range_callback),
OPT_END()
};
@@ -1757,13 +1757,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
OPT_INTEGER(0, "filename-max-length", &fmt_patch_name_max,
N_("max length of output filename")),
OPT_CALLBACK_F(0, "rfc", &rev, NULL,
- N_("Use [RFC PATCH] instead of [PATCH]"),
+ N_("use [RFC PATCH] instead of [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback),
OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
N_("cover-from-description-mode"),
N_("generate parts of a cover letter based on a branch's description")),
OPT_CALLBACK_F(0, "subject-prefix", &rev, N_("prefix"),
- N_("Use [<prefix>] instead of [PATCH]"),
+ N_("use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback),
OPT_CALLBACK_F('o', "output-directory", &output_directory,
N_("dir"), N_("store resulting files in <dir>"),
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 4982d3a..41a399a 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,179 +1,110 @@
#include "builtin.h"
+#include "parse-options.h"
#include "tag.h"
#include "replace-object.h"
#include "object-store.h"
+#include "fsck.h"
+#include "config.h"
-/*
- * A signature file has a very simple fixed format: four lines
- * of "object <sha1>" + "type <typename>" + "tag <tagname>" +
- * "tagger <committer>", followed by a blank line, a free-form tag
- * message and a signature block that git itself doesn't care about,
- * but that can be verified with gpg or similar.
- *
- * The first four lines are guaranteed to be at least 83 bytes:
- * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the
- * shortest possible type-line, "tag .\n" at 6 bytes is the shortest
- * single-character-tag line, and "tagger . <> 0 +0000\n" at 20 bytes is
- * the shortest possible tagger-line.
- */
-
-/*
- * We refuse to tag something we can't verify. Just because.
- */
-static int verify_object(const struct object_id *oid, const char *expected_type)
+static char const * const builtin_mktag_usage[] = {
+ N_("git mktag"),
+ NULL
+};
+static int option_strict = 1;
+
+static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
+
+static int mktag_config(const char *var, const char *value, void *cb)
{
- int ret = -1;
- enum object_type type;
- unsigned long size;
- void *buffer = read_object_file(oid, &type, &size);
- const struct object_id *repl = lookup_replace_object(the_repository, oid);
-
- if (buffer) {
- if (type == type_from_string(expected_type)) {
- ret = check_object_signature(the_repository, repl,
- buffer, size,
- expected_type);
+ return fsck_config_internal(var, value, cb, &fsck_options);
+}
+
+static int mktag_fsck_error_func(struct fsck_options *o,
+ const struct object_id *oid,
+ enum object_type object_type,
+ int msg_type, const char *message)
+{
+ switch (msg_type) {
+ case FSCK_WARN:
+ if (!option_strict) {
+ fprintf_ln(stderr, _("warning: tag input does not pass fsck: %s"), message);
+ return 0;
+
}
- free(buffer);
+ /* fallthrough */
+ case FSCK_ERROR:
+ /*
+ * We treat both warnings and errors as errors, things
+ * like missing "tagger" lines are "only" warnings
+ * under fsck, we've always considered them an error.
+ */
+ fprintf_ln(stderr, _("error: tag input does not pass fsck: %s"), message);
+ return 1;
+ default:
+ BUG(_("%d (FSCK_IGNORE?) should never trigger this callback"),
+ msg_type);
}
- return ret;
}
-static int verify_tag(char *buffer, unsigned long size)
+static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
{
- int typelen;
- char type[20];
- struct object_id oid;
- const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb, *p;
- size_t len;
-
- if (size < 84)
- return error("wanna fool me ? you obviously got the size wrong !");
-
- buffer[size] = 0;
-
- /* Verify object line */
- object = buffer;
- if (memcmp(object, "object ", 7))
- return error("char%d: does not start with \"object \"", 0);
-
- if (parse_oid_hex(object + 7, &oid, &p))
- return error("char%d: could not get SHA1 hash", 7);
-
- /* Verify type line */
- type_line = p + 1;
- if (memcmp(type_line - 1, "\ntype ", 6))
- return error("char%d: could not find \"\\ntype \"", 47);
-
- /* Verify tag-line */
- tag_line = strchr(type_line, '\n');
- if (!tag_line)
- return error("char%"PRIuMAX": could not find next \"\\n\"",
- (uintmax_t) (type_line - buffer));
- tag_line++;
- if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n')
- return error("char%"PRIuMAX": no \"tag \" found",
- (uintmax_t) (tag_line - buffer));
-
- /* Get the actual type */
- typelen = tag_line - type_line - strlen("type \n");
- if (typelen >= sizeof(type))
- return error("char%"PRIuMAX": type too long",
- (uintmax_t) (type_line+5 - buffer));
-
- memcpy(type, type_line+5, typelen);
- type[typelen] = 0;
-
- /* Verify that the object matches */
- if (verify_object(&oid, type))
- return error("char%d: could not verify object %s", 7, oid_to_hex(&oid));
-
- /* Verify the tag-name: we don't allow control characters or spaces in it */
- tag_line += 4;
- for (;;) {
- unsigned char c = *tag_line++;
- if (c == '\n')
- break;
- if (c > ' ')
- continue;
- return error("char%"PRIuMAX": could not verify tag name",
- (uintmax_t) (tag_line - buffer));
- }
+ int ret;
+ enum object_type type;
+ unsigned long size;
+ void *buffer;
+ const struct object_id *repl;
+
+ buffer = read_object_file(tagged_oid, &type, &size);
+ if (!buffer)
+ die(_("could not read tagged object '%s'"),
+ oid_to_hex(tagged_oid));
+ if (type != *tagged_type)
+ die(_("object '%s' tagged as '%s', but is a '%s' type"),
+ oid_to_hex(tagged_oid),
+ type_name(*tagged_type), type_name(type));
+
+ repl = lookup_replace_object(the_repository, tagged_oid);
+ ret = check_object_signature(the_repository, repl,
+ buffer, size, type_name(*tagged_type));
+ free(buffer);
- /* Verify the tagger line */
- tagger_line = tag_line;
-
- if (memcmp(tagger_line, "tagger ", 7))
- return error("char%"PRIuMAX": could not find \"tagger \"",
- (uintmax_t) (tagger_line - buffer));
-
- /*
- * Check for correct form for name and email
- * i.e. " <" followed by "> " on _this_ line
- * No angle brackets within the name or email address fields.
- * No spaces within the email address field.
- */
- tagger_line += 7;
- if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, "> ")) ||
- strpbrk(tagger_line, "<>\n") != lb+1 ||
- strpbrk(lb+2, "><\n ") != rb)
- return error("char%"PRIuMAX": malformed tagger field",
- (uintmax_t) (tagger_line - buffer));
-
- /* Check for author name, at least one character, space is acceptable */
- if (lb == tagger_line)
- return error("char%"PRIuMAX": missing tagger name",
- (uintmax_t) (tagger_line - buffer));
-
- /* timestamp, 1 or more digits followed by space */
- tagger_line = rb + 2;
- if (!(len = strspn(tagger_line, "0123456789")))
- return error("char%"PRIuMAX": missing tag timestamp",
- (uintmax_t) (tagger_line - buffer));
- tagger_line += len;
- if (*tagger_line != ' ')
- return error("char%"PRIuMAX": malformed tag timestamp",
- (uintmax_t) (tagger_line - buffer));
- tagger_line++;
-
- /* timezone, 5 digits [+-]hhmm, max. 1400 */
- if (!((tagger_line[0] == '+' || tagger_line[0] == '-') &&
- strspn(tagger_line+1, "0123456789") == 4 &&
- tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400))
- return error("char%"PRIuMAX": malformed tag timezone",
- (uintmax_t) (tagger_line - buffer));
- tagger_line += 6;
-
- /* Verify the blank line separating the header from the body */
- if (*tagger_line != '\n')
- return error("char%"PRIuMAX": trailing garbage in tag header",
- (uintmax_t) (tagger_line - buffer));
-
- /* The actual stuff afterwards we don't care about.. */
- return 0;
+ return ret;
}
int cmd_mktag(int argc, const char **argv, const char *prefix)
{
+ static struct option builtin_mktag_options[] = {
+ OPT_BOOL(0, "strict", &option_strict,
+ N_("enable more strict checking")),
+ OPT_END(),
+ };
struct strbuf buf = STRBUF_INIT;
+ struct object_id tagged_oid;
+ int tagged_type;
struct object_id result;
- if (argc != 1)
- usage("git mktag");
+ argc = parse_options(argc, argv, NULL,
+ builtin_mktag_options,
+ builtin_mktag_usage, 0);
- if (strbuf_read(&buf, 0, 4096) < 0) {
- die_errno("could not read from stdin");
- }
+ if (strbuf_read(&buf, 0, 0) < 0)
+ die_errno(_("could not read from stdin"));
+
+ fsck_options.error_func = mktag_fsck_error_func;
+ fsck_set_msg_type(&fsck_options, "extraheaderentry", "warn");
+ /* config might set fsck.extraHeaderEntry=* again */
+ git_config(mktag_config, NULL);
+ if (fsck_tag_standalone(NULL, buf.buf, buf.len, &fsck_options,
+ &tagged_oid, &tagged_type))
+ die(_("tag on stdin did not pass our strict fsck check"));
- /* Verify it for some basic sanity: it needs to start with
- "object <sha1>\ntype\ntagger " */
- if (verify_tag(buf.buf, buf.len) < 0)
- die("invalid tag signature file");
+ if (verify_object_in_tag(&tagged_oid, &tagged_type))
+ die(_("tag on stdin did not refer to a valid object"));
if (write_object_file(buf.buf, buf.len, tag_type, &result) < 0)
- die("unable to write tag file");
+ die(_("unable to write tag file"));
strbuf_release(&buf);
- printf("%s\n", oid_to_hex(&result));
+ puts(oid_to_hex(&result));
return 0;
}
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 725dd04..3fe71a8 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -7,7 +7,7 @@
#include "refs.h"
#include "parse-options.h"
#include "prio-queue.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
#include "commit-slab.h"
/*
@@ -408,7 +408,7 @@ static const char *get_exact_ref_match(const struct object *o)
tip_table.sorted = 1;
}
- found = sha1_pos(o->oid.hash, tip_table.table, tip_table.nr,
+ found = hash_pos(o->oid.hash, tip_table.table, tip_table.nr,
nth_tip_table_ent);
if (0 <= found)
return tip_table.table[found].refname;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 5617c01..2a00358 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1104,7 +1104,6 @@ static void write_pack_file(void)
stop_progress(&progress_state);
bitmap_writer_show_progress(progress);
- bitmap_writer_reuse_bitmaps(&to_pack);
bitmap_writer_select_commits(indexed_commits, indexed_commits_nr, -1);
bitmap_writer_build(&to_pack);
bitmap_writer_finish(written_list, nr_written,
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index d3b5ee8..6e115a8 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -473,6 +473,12 @@ static void cmp_local_packs(void)
{
struct pack_list *subset, *pl = local_packs;
+ /* only one packfile */
+ if (!pl->next) {
+ llist_init(&pl->unique_objects);
+ return;
+ }
+
while ((subset = pl)) {
while ((subset = subset->next))
cmp_two_packs(pl, subset);
diff --git a/builtin/pull.c b/builtin/pull.c
index aa56ebc..e8927fc 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -324,7 +324,7 @@ static const char *config_get_ff(void)
* looks for the value of "pull.rebase". If both configuration keys do not
* exist, returns REBASE_FALSE.
*/
-static enum rebase_type config_get_rebase(void)
+static enum rebase_type config_get_rebase(int *rebase_unspecified)
{
struct branch *curr_branch = branch_get("HEAD");
const char *value;
@@ -344,20 +344,7 @@ static enum rebase_type config_get_rebase(void)
if (!git_config_get_value("pull.rebase", &value))
return parse_config_rebase("pull.rebase", value, 1);
- if (opt_verbosity >= 0 && !opt_ff) {
- advise(_("Pulling without specifying how to reconcile divergent branches is\n"
- "discouraged. You can squelch this message by running one of the following\n"
- "commands sometime before your next pull:\n"
- "\n"
- " git config pull.rebase false # merge (the default strategy)\n"
- " git config pull.rebase true # rebase\n"
- " git config pull.ff only # fast-forward only\n"
- "\n"
- "You can replace \"git config\" with \"git config --global\" to set a default\n"
- "preference for all repositories. You can also pass --rebase, --no-rebase,\n"
- "or --ff-only on the command line to override the configured default per\n"
- "invocation.\n"));
- }
+ *rebase_unspecified = 1;
return REBASE_FALSE;
}
@@ -924,6 +911,36 @@ static int run_rebase(const struct object_id *newbase,
return ret;
}
+static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_head)
+{
+ int ret;
+ struct commit_list *list = NULL;
+ struct commit *merge_head, *head;
+
+ head = lookup_commit_reference(the_repository, orig_head);
+ commit_list_insert(head, &list);
+ merge_head = lookup_commit_reference(the_repository, orig_merge_head);
+ ret = repo_is_descendant_of(the_repository, merge_head, list);
+ free_commit_list(list);
+ return ret;
+}
+
+static void show_advice_pull_non_ff(void)
+{
+ advise(_("Pulling without specifying how to reconcile divergent branches is\n"
+ "discouraged. You can squelch this message by running one of the following\n"
+ "commands sometime before your next pull:\n"
+ "\n"
+ " git config pull.rebase false # merge (the default strategy)\n"
+ " git config pull.rebase true # rebase\n"
+ " git config pull.ff only # fast-forward only\n"
+ "\n"
+ "You can replace \"git config\" with \"git config --global\" to set a default\n"
+ "preference for all repositories. You can also pass --rebase, --no-rebase,\n"
+ "or --ff-only on the command line to override the configured default per\n"
+ "invocation.\n"));
+}
+
int cmd_pull(int argc, const char **argv, const char *prefix)
{
const char *repo, **refspecs;
@@ -931,6 +948,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
struct object_id orig_head, curr_head;
struct object_id rebase_fork_point;
int autostash;
+ int rebase_unspecified = 0;
+ int can_ff;
if (!getenv("GIT_REFLOG_ACTION"))
set_reflog_message(argc, argv);
@@ -952,7 +971,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
opt_ff = xstrdup_or_null(config_get_ff());
if (opt_rebase < 0)
- opt_rebase = config_get_rebase();
+ opt_rebase = config_get_rebase(&rebase_unspecified);
if (read_cache_unmerged())
die_resolve_conflict("pull");
@@ -1026,6 +1045,13 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (opt_rebase && merge_heads.nr > 1)
die(_("Cannot rebase onto multiple branches."));
+ can_ff = get_can_ff(&orig_head, &merge_heads.oid[0]);
+
+ if (rebase_unspecified && !opt_ff && !can_ff) {
+ if (opt_verbosity >= 0)
+ show_advice_pull_non_ff();
+ }
+
if (opt_rebase) {
int ret = 0;
int ran_ff = 0;
@@ -1040,22 +1066,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
submodule_touches_in_range(the_repository, &upstream, &curr_head))
die(_("cannot rebase with locally recorded submodule modifications"));
if (!autostash) {
- struct commit_list *list = NULL;
- struct commit *merge_head, *head;
-
- head = lookup_commit_reference(the_repository,
- &orig_head);
- commit_list_insert(head, &list);
- merge_head = lookup_commit_reference(the_repository,
- &merge_heads.oid[0]);
- if (repo_is_descendant_of(the_repository,
- merge_head, list)) {
+ if (can_ff) {
/* we can fast-forward this without invoking rebase */
opt_ff = "--ff-only";
ran_ff = 1;
ret = run_merge();
}
- free_commit_list(list);
}
if (!ran_ff)
ret = run_rebase(&newbase, &upstream);
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 19c7b37..840dbd7 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1917,7 +1917,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die_if_checked_out(buf.buf, 1);
options.head_name = xstrdup(buf.buf);
/* If not is it a valid ref (branch or commit)? */
- } else if (!get_oid(branch_name, &options.orig_head))
+ } else if (!get_oid(branch_name, &options.orig_head) &&
+ lookup_commit_reference(the_repository,
+ &options.orig_head))
options.head_name = NULL;
else
die(_("fatal: no such branch/commit '%s'"),
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 69ba732..85bad90 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -583,6 +583,75 @@ static void handle_ref_opt(const char *pattern, const char *prefix)
clear_ref_exclusion(&ref_excludes);
}
+enum format_type {
+ /* We would like a relative path. */
+ FORMAT_RELATIVE,
+ /* We would like a canonical absolute path. */
+ FORMAT_CANONICAL,
+ /* We would like the default behavior. */
+ FORMAT_DEFAULT,
+};
+
+enum default_type {
+ /* Our default is a relative path. */
+ DEFAULT_RELATIVE,
+ /* Our default is a relative path if there's a shared root. */
+ DEFAULT_RELATIVE_IF_SHARED,
+ /* Our default is a canonical absolute path. */
+ DEFAULT_CANONICAL,
+ /* Our default is not to modify the item. */
+ DEFAULT_UNMODIFIED,
+};
+
+static void print_path(const char *path, const char *prefix, enum format_type format, enum default_type def)
+{
+ char *cwd = NULL;
+ /*
+ * We don't ever produce a relative path if prefix is NULL, so set the
+ * prefix to the current directory so that we can produce a relative
+ * path whenever possible. If we're using RELATIVE_IF_SHARED mode, then
+ * we want an absolute path unless the two share a common prefix, so don't
+ * set it in that case, since doing so causes a relative path to always
+ * be produced if possible.
+ */
+ if (!prefix && (format != FORMAT_DEFAULT || def != DEFAULT_RELATIVE_IF_SHARED))
+ prefix = cwd = xgetcwd();
+ if (format == FORMAT_DEFAULT && def == DEFAULT_UNMODIFIED) {
+ puts(path);
+ } else if (format == FORMAT_RELATIVE ||
+ (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE)) {
+ /*
+ * In order for relative_path to work as expected, we need to
+ * make sure that both paths are absolute paths. If we don't,
+ * we can end up with an unexpected absolute path that the user
+ * didn't want.
+ */
+ struct strbuf buf = STRBUF_INIT, realbuf = STRBUF_INIT, prefixbuf = STRBUF_INIT;
+ if (!is_absolute_path(path)) {
+ strbuf_realpath_forgiving(&realbuf, path, 1);
+ path = realbuf.buf;
+ }
+ if (!is_absolute_path(prefix)) {
+ strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
+ prefix = prefixbuf.buf;
+ }
+ puts(relative_path(path, prefix, &buf));
+ strbuf_release(&buf);
+ strbuf_release(&realbuf);
+ strbuf_release(&prefixbuf);
+ } else if (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE_IF_SHARED) {
+ struct strbuf buf = STRBUF_INIT;
+ puts(relative_path(path, prefix, &buf));
+ strbuf_release(&buf);
+ } else {
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_realpath_forgiving(&buf, path, 1);
+ puts(buf.buf);
+ strbuf_release(&buf);
+ }
+ free(cwd);
+}
+
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
{
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
@@ -596,6 +665,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT;
const int hexsz = the_hash_algo->hexsz;
int seen_end_of_options = 0;
+ enum format_type format = FORMAT_DEFAULT;
if (argc > 1 && !strcmp("--parseopt", argv[1]))
return cmd_parseopt(argc - 1, argv + 1, prefix);
@@ -668,8 +738,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!argv[i + 1])
die("--git-path requires an argument");
strbuf_reset(&buf);
- puts(relative_path(git_path("%s", argv[i + 1]),
- prefix, &buf));
+ print_path(git_path("%s", argv[i + 1]), prefix,
+ format,
+ DEFAULT_RELATIVE_IF_SHARED);
i++;
continue;
}
@@ -687,6 +758,16 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
show(arg);
continue;
}
+ if (opt_with_value(arg, "--path-format", &arg)) {
+ if (!strcmp(arg, "absolute")) {
+ format = FORMAT_CANONICAL;
+ } else if (!strcmp(arg, "relative")) {
+ format = FORMAT_RELATIVE;
+ } else {
+ die("unknown argument to --path-format: %s", arg);
+ }
+ continue;
+ }
if (!strcmp(arg, "--default")) {
def = argv[++i];
if (!def)
@@ -807,7 +888,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "--show-toplevel")) {
const char *work_tree = get_git_work_tree();
if (work_tree)
- puts(work_tree);
+ print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
else
die("this operation must be run in a work tree");
continue;
@@ -815,7 +896,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (!strcmp(arg, "--show-superproject-working-tree")) {
struct strbuf superproject = STRBUF_INIT;
if (get_superproject_working_tree(&superproject))
- puts(superproject.buf);
+ print_path(superproject.buf, prefix, format, DEFAULT_UNMODIFIED);
strbuf_release(&superproject);
continue;
}
@@ -850,16 +931,18 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
char *cwd;
int len;
+ enum format_type wanted = format;
if (arg[2] == 'g') { /* --git-dir */
if (gitdir) {
- puts(gitdir);
+ print_path(gitdir, prefix, format, DEFAULT_UNMODIFIED);
continue;
}
if (!prefix) {
- puts(".git");
+ print_path(".git", prefix, format, DEFAULT_UNMODIFIED);
continue;
}
} else { /* --absolute-git-dir */
+ wanted = FORMAT_CANONICAL;
if (!gitdir && !prefix)
gitdir = ".git";
if (gitdir) {
@@ -872,14 +955,14 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
cwd = xgetcwd();
len = strlen(cwd);
- printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s%s.git", cwd, len && cwd[len-1] != '/' ? "/" : "");
free(cwd);
+ print_path(buf.buf, prefix, wanted, DEFAULT_CANONICAL);
continue;
}
if (!strcmp(arg, "--git-common-dir")) {
- strbuf_reset(&buf);
- puts(relative_path(get_git_common_dir(),
- prefix, &buf));
+ print_path(get_git_common_dir(), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
continue;
}
if (!strcmp(arg, "--is-inside-git-dir")) {
@@ -909,8 +992,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (the_index.split_index) {
const struct object_id *oid = &the_index.split_index->base_oid;
const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
- strbuf_reset(&buf);
- puts(relative_path(path, prefix, &buf));
+ print_path(path, prefix, format, DEFAULT_RELATIVE);
}
continue;
}
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index c52e4cc..1c0b3a9 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -360,19 +360,19 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
const struct option options[] = {
OPT_BIT('c', "committer", &log.groups,
- N_("Group by committer rather than author"),
+ N_("group by committer rather than author"),
SHORTLOG_GROUP_COMMITTER),
OPT_BOOL('n', "numbered", &log.sort_by_number,
N_("sort output according to the number of commits per author")),
OPT_BOOL('s', "summary", &log.summary,
- N_("Suppress commit descriptions, only provides commit count")),
+ N_("suppress commit descriptions, only provides commit count")),
OPT_BOOL('e', "email", &log.email,
- N_("Show the email address of each author")),
+ N_("show the email address of each author")),
OPT_CALLBACK_F('w', NULL, &log, N_("<w>[,<i1>[,<i2>]]"),
- N_("Linewrap output"), PARSE_OPT_OPTARG,
+ N_("linewrap output"), PARSE_OPT_OPTARG,
&parse_wrap_args),
OPT_CALLBACK(0, "group", &log, N_("field"),
- N_("Group by field"), parse_group_option),
+ N_("group by field"), parse_group_option),
OPT_END(),
};
diff --git a/builtin/stash.c b/builtin/stash.c
index e1f8235..9bc85f9 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -325,35 +325,6 @@ static void add_diff_to_buf(struct diff_queue_struct *q,
}
}
-static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
-{
- struct child_process cp = CHILD_PROCESS_INIT;
- const char *c_tree_hex = oid_to_hex(c_tree);
-
- /*
- * diff-index is very similar to diff-tree above, and should be
- * converted together with update_index.
- */
- cp.git_cmd = 1;
- strvec_pushl(&cp.args, "diff-index", "--cached", "--name-only",
- "--diff-filter=A", NULL);
- strvec_push(&cp.args, c_tree_hex);
- return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
-}
-
-static int update_index(struct strbuf *out)
-{
- struct child_process cp = CHILD_PROCESS_INIT;
-
- /*
- * Update-index is very complicated and may need to have a public
- * function exposed in order to remove this forking.
- */
- cp.git_cmd = 1;
- strvec_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
- return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
-}
-
static int restore_untracked(struct object_id *u_tree)
{
int res;
@@ -385,6 +356,121 @@ static int restore_untracked(struct object_id *u_tree)
return res;
}
+static void unstage_changes_unless_new(struct object_id *orig_tree)
+{
+ /*
+ * When we enter this function, there has been a clean merge of
+ * relevant trees, and the merge logic always stages whatever merges
+ * cleanly. We want to unstage those changes, unless it corresponds
+ * to a file that didn't exist as of orig_tree.
+ *
+ * However, if any SKIP_WORKTREE path is modified relative to
+ * orig_tree, then we want to clear the SKIP_WORKTREE bit and write
+ * it to the worktree before unstaging.
+ */
+
+ struct checkout state = CHECKOUT_INIT;
+ struct diff_options diff_opts;
+ struct lock_file lock = LOCK_INIT;
+ int i;
+
+ /* If any entries have skip_worktree set, we'll have to check 'em out */
+ state.force = 1;
+ state.quiet = 1;
+ state.refresh_cache = 1;
+ state.istate = &the_index;
+
+ /*
+ * Step 1: get a difference between orig_tree (which corresponding
+ * to the index before a merge was run) and the current index
+ * (reflecting the changes brought in by the merge).
+ */
+ diff_setup(&diff_opts);
+ diff_opts.flags.recursive = 1;
+ diff_opts.detect_rename = 0;
+ diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+ diff_setup_done(&diff_opts);
+
+ do_diff_cache(orig_tree, &diff_opts);
+ diffcore_std(&diff_opts);
+
+ /* Iterate over the paths that changed due to the merge... */
+ for (i = 0; i < diff_queued_diff.nr; i++) {
+ struct diff_filepair *p;
+ struct cache_entry *ce;
+ int pos;
+
+ /* Look up the path's position in the current index. */
+ p = diff_queued_diff.queue[i];
+ pos = index_name_pos(&the_index, p->two->path,
+ strlen(p->two->path));
+
+ /*
+ * Step 2: Place changes in the working tree
+ *
+ * Stash is about restoring changes *to the working tree*.
+ * So if the merge successfully got a new version of some
+ * path, but left it out of the working tree, then clear the
+ * SKIP_WORKTREE bit and write it to the working tree.
+ */
+ if (pos >= 0 && ce_skip_worktree(active_cache[pos])) {
+ struct stat st;
+
+ ce = active_cache[pos];
+ if (!lstat(ce->name, &st)) {
+ /* Conflicting path present; relocate it */
+ struct strbuf new_path = STRBUF_INIT;
+ int fd;
+
+ strbuf_addf(&new_path,
+ "%s.stash.XXXXXX", ce->name);
+ fd = xmkstemp(new_path.buf);
+ close(fd);
+ printf(_("WARNING: Untracked file in way of "
+ "tracked file! Renaming\n "
+ " %s -> %s\n"
+ " to make room.\n"),
+ ce->name, new_path.buf);
+ if (rename(ce->name, new_path.buf))
+ die("Failed to move %s to %s\n",
+ ce->name, new_path.buf);
+ strbuf_release(&new_path);
+ }
+ checkout_entry(ce, &state, NULL, NULL);
+ ce->ce_flags &= ~CE_SKIP_WORKTREE;
+ }
+
+ /*
+ * Step 3: "unstage" changes, as long as they are still tracked
+ */
+ if (p->one->oid_valid) {
+ /*
+ * Path existed in orig_tree; restore index entry
+ * from that tree in order to "unstage" the changes.
+ */
+ int option = ADD_CACHE_OK_TO_REPLACE;
+ if (pos < 0)
+ option = ADD_CACHE_OK_TO_ADD;
+
+ ce = make_cache_entry(&the_index,
+ p->one->mode,
+ &p->one->oid,
+ p->one->path,
+ 0, 0);
+ add_index_entry(&the_index, ce, option);
+ }
+ }
+ diff_flush(&diff_opts);
+
+ /*
+ * Step 4: write the new index to disk
+ */
+ repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
+ if (write_locked_index(&the_index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
+ die(_("Unable to write index."));
+}
+
static int do_apply_stash(const char *prefix, struct stash_info *info,
int index, int quiet)
{
@@ -467,26 +553,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
if (reset_tree(&index_tree, 0, 0))
return -1;
} else {
- struct strbuf out = STRBUF_INIT;
-
- if (get_newly_staged(&out, &c_tree)) {
- strbuf_release(&out);
- return -1;
- }
-
- if (reset_tree(&c_tree, 0, 1)) {
- strbuf_release(&out);
- return -1;
- }
-
- ret = update_index(&out);
- strbuf_release(&out);
- if (ret)
- return -1;
-
- /* read back the result of update_index() back from the disk */
- discard_cache();
- read_cache();
+ unstage_changes_unless_new(&c_tree);
}
if (!quiet) {
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c30896c..c2bd882 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -562,9 +562,9 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
struct module_list list = MODULE_LIST_INIT;
struct option module_foreach_options[] = {
- OPT__QUIET(&info.quiet, N_("Suppress output of entering each submodule command")),
+ OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
OPT_BOOL(0, "recursive", &info.recursive,
- N_("Recurse into nested submodules")),
+ N_("recurse into nested submodules")),
OPT_END()
};
@@ -706,7 +706,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
int quiet = 0;
struct option module_init_options[] = {
- OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
+ OPT__QUIET(&quiet, N_("suppress output for initializing a submodule")),
OPT_END()
};
@@ -883,8 +883,8 @@ static int module_status(int argc, const char **argv, const char *prefix)
int quiet = 0;
struct option module_status_options[] = {
- OPT__QUIET(&quiet, N_("Suppress submodule status output")),
- OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
+ OPT__QUIET(&quiet, N_("suppress submodule status output")),
+ OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
OPT_END()
};
@@ -1482,9 +1482,9 @@ static int module_sync(int argc, const char **argv, const char *prefix)
int recursive = 0;
struct option module_sync_options[] = {
- OPT__QUIET(&quiet, N_("Suppress output of synchronizing submodule url")),
+ OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
OPT_BOOL(0, "recursive", &recursive,
- N_("Recurse into nested submodules")),
+ N_("recurse into nested submodules")),
OPT_END()
};
@@ -1620,9 +1620,9 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
int all = 0;
struct option module_deinit_options[] = {
- OPT__QUIET(&quiet, N_("Suppress submodule status output")),
- OPT__FORCE(&force, N_("Remove submodule working trees even if they contain local changes"), 0),
- OPT_BOOL(0, "all", &all, N_("Unregister all submodules")),
+ OPT__QUIET(&quiet, N_("suppress submodule status output")),
+ OPT__FORCE(&force, N_("remove submodule working trees even if they contain local changes"), 0),
+ OPT_BOOL(0, "all", &all, N_("unregister all submodules")),
OPT_END()
};
@@ -2337,7 +2337,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "dissociate", &suc.dissociate,
N_("use --reference only while cloning")),
OPT_STRING(0, "depth", &suc.depth, "<depth>",
- N_("Create a shallow clone truncated to the "
+ N_("create a shallow clone truncated to the "
"specified number of revisions")),
OPT_INTEGER('j', "jobs", &suc.max_jobs,
N_("parallel jobs")),
@@ -2678,7 +2678,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
char *config_name;
struct option options[] = {
- OPT__QUIET(&quiet, N_("Suppress output for setting url of a submodule")),
+ OPT__QUIET(&quiet, N_("suppress output for setting url of a submodule")),
OPT_END()
};
const char *const usage[] = {
diff --git a/builtin/tag.c b/builtin/tag.c
index ecf0117..24d35b7 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -485,7 +485,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
}
if (!sorting)
sorting = ref_default_sorting();
- ref_sorting_icase_all(sorting, icase);
+ ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
filter.ignore_case = icase;
if (cmdmode == 'l') {
int ret;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 197fd24..71287b2 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1052,10 +1052,10 @@ static int repair(int ac, const char **av, const char *prefix)
int rc = 0;
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
- repair_worktrees(report_repair, &rc);
p = ac > 0 ? av : self;
for (; *p; p++)
repair_worktree_at_path(*p, report_repair, &rc);
+ repair_worktrees(report_repair, &rc);
return rc;
}
diff --git a/cache.h b/cache.h
index 8d279bc..eefa93b 100644
--- a/cache.h
+++ b/cache.h
@@ -1123,100 +1123,6 @@ const char *repo_find_unique_abbrev(struct repository *r, const struct object_id
int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);
#define find_unique_abbrev_r(hex, oid, len) repo_find_unique_abbrev_r(the_repository, hex, oid, len)
-extern const struct object_id null_oid;
-
-static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
-{
- /*
- * 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 (the_hash_algo->rawsz == GIT_MAX_RAWSZ)
- return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
- return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
-}
-
-static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
-{
- return hashcmp(oid1->hash, oid2->hash);
-}
-
-static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
-{
- /*
- * We write this here instead of deferring to hashcmp so that the
- * compiler can properly inline it and avoid calling memcmp.
- */
- if (the_hash_algo->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)
-{
- return hasheq(oid1->hash, oid2->hash);
-}
-
-static inline int is_null_oid(const struct object_id *oid)
-{
- return oideq(oid, &null_oid);
-}
-
-static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
-{
- memcpy(sha_dst, sha_src, the_hash_algo->rawsz);
-}
-
-static inline void oidcpy(struct object_id *dst, const struct object_id *src)
-{
- memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
-}
-
-static inline struct object_id *oiddup(const struct object_id *src)
-{
- struct object_id *dst = xmalloc(sizeof(struct object_id));
- oidcpy(dst, src);
- return dst;
-}
-
-static inline void hashclr(unsigned char *hash)
-{
- memset(hash, 0, the_hash_algo->rawsz);
-}
-
-static inline void oidclr(struct object_id *oid)
-{
- memset(oid->hash, 0, GIT_MAX_RAWSZ);
-}
-
-static inline void oidread(struct object_id *oid, const unsigned char *hash)
-{
- memcpy(oid->hash, hash, the_hash_algo->rawsz);
-}
-
-static inline int is_empty_blob_sha1(const unsigned char *sha1)
-{
- return hasheq(sha1, the_hash_algo->empty_blob->hash);
-}
-
-static inline int is_empty_blob_oid(const struct object_id *oid)
-{
- return oideq(oid, the_hash_algo->empty_blob);
-}
-
-static inline int is_empty_tree_sha1(const unsigned char *sha1)
-{
- return hasheq(sha1, the_hash_algo->empty_tree->hash);
-}
-
-static inline int is_empty_tree_oid(const struct object_id *oid)
-{
- return oideq(oid, the_hash_algo->empty_tree);
-}
-
-const char *empty_tree_oid_hex(void);
-const char *empty_blob_oid_hex(void);
-
/* set default permissions by passing mode arguments to open(2) */
int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
int git_mkstemp_mode(char *pattern, int mode);
@@ -1325,6 +1231,8 @@ static inline int is_absolute_path(const char *path)
int is_directory(const char *);
char *strbuf_realpath(struct strbuf *resolved, const char *path,
int die_on_error);
+char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path,
+ int die_on_error);
char *real_pathdup(const char *path, int die_on_error);
const char *absolute_path(const char *path);
char *absolute_pathdup(const char *path);
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index 0229a77..0b1184e 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -44,13 +44,13 @@ osx-clang|osx-gcc)
test -z "$BREW_INSTALL_PACKAGES" ||
brew install $BREW_INSTALL_PACKAGES
brew link --force gettext
- brew cask install --no-quarantine perforce || {
+ brew install --cask --no-quarantine perforce || {
# Update the definitions and try again
cask_repo="$(brew --repository)"/Library/Taps/homebrew/homebrew-cask &&
- git -C "$cask_repo" pull --no-stat &&
- brew cask install --no-quarantine perforce
+ git -C "$cask_repo" pull --no-stat --ff-only &&
+ brew install --cask --no-quarantine perforce
} ||
- brew install caskroom/cask/perforce
+ brew install homebrew/cask/perforce
case "$jobname" in
osx-gcc)
brew install gcc@9
diff --git a/commit-graph.c b/commit-graph.c
index 6f62a07..f3486ec 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -7,7 +7,7 @@
#include "object.h"
#include "refs.h"
#include "revision.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
#include "commit-graph.h"
#include "object-store.h"
#include "alloc.h"
@@ -932,21 +932,15 @@ struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit
struct packed_commit_list {
struct commit **list;
- int nr;
- int alloc;
-};
-
-struct packed_oid_list {
- struct object_id *list;
- int nr;
- int alloc;
+ size_t nr;
+ size_t alloc;
};
struct write_commit_graph_context {
struct repository *r;
struct object_directory *odb;
char *graph_name;
- struct packed_oid_list oids;
+ struct oid_array oids;
struct packed_commit_list commits;
int num_extra_edges;
unsigned long approx_nr_objects;
@@ -1049,7 +1043,7 @@ static int write_graph_chunk_data(struct hashfile *f,
if (!parent)
edge_value = GRAPH_PARENT_NONE;
else {
- edge_value = sha1_pos(parent->item->object.oid.hash,
+ edge_value = hash_pos(parent->item->object.oid.hash,
ctx->commits.list,
ctx->commits.nr,
commit_to_sha1);
@@ -1080,7 +1074,7 @@ static int write_graph_chunk_data(struct hashfile *f,
else if (parent->next)
edge_value = GRAPH_EXTRA_EDGES_NEEDED | num_extra_edges;
else {
- edge_value = sha1_pos(parent->item->object.oid.hash,
+ edge_value = hash_pos(parent->item->object.oid.hash,
ctx->commits.list,
ctx->commits.nr,
commit_to_sha1);
@@ -1149,7 +1143,7 @@ static int write_graph_chunk_extra_edges(struct hashfile *f,
/* Since num_parents > 2, this initializer is safe. */
for (parent = (*list)->parents->next; parent; parent = parent->next) {
- int edge_value = sha1_pos(parent->item->object.oid.hash,
+ int edge_value = hash_pos(parent->item->object.oid.hash,
ctx->commits.list,
ctx->commits.nr,
commit_to_sha1);
@@ -1240,13 +1234,6 @@ static int write_graph_chunk_bloom_data(struct hashfile *f,
return 0;
}
-static int oid_compare(const void *_a, const void *_b)
-{
- const struct object_id *a = (const struct object_id *)_a;
- const struct object_id *b = (const struct object_id *)_b;
- return oidcmp(a, b);
-}
-
static int add_packed_commits(const struct object_id *oid,
struct packed_git *pack,
uint32_t pos,
@@ -1267,10 +1254,7 @@ static int add_packed_commits(const struct object_id *oid,
if (type != OBJ_COMMIT)
return 0;
- ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
- oidcpy(&(ctx->oids.list[ctx->oids.nr]), oid);
- ctx->oids.nr++;
-
+ oid_array_append(&ctx->oids, oid);
set_commit_pos(ctx->r, oid);
return 0;
@@ -1281,9 +1265,7 @@ static void add_missing_parents(struct write_commit_graph_context *ctx, struct c
struct commit_list *parent;
for (parent = commit->parents; parent; parent = parent->next) {
if (!(parent->item->object.flags & REACHABLE)) {
- ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
- oidcpy(&ctx->oids.list[ctx->oids.nr], &(parent->item->object.oid));
- ctx->oids.nr++;
+ oid_array_append(&ctx->oids, &parent->item->object.oid);
parent->item->object.flags |= REACHABLE;
}
}
@@ -1302,7 +1284,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
ctx->oids.nr);
for (i = 0; i < ctx->oids.nr; i++) {
display_progress(ctx->progress, i + 1);
- commit = lookup_commit(ctx->r, &ctx->oids.list[i]);
+ commit = lookup_commit(ctx->r, &ctx->oids.oid[i]);
if (commit)
commit->object.flags |= REACHABLE;
}
@@ -1319,7 +1301,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
0);
for (i = 0; i < ctx->oids.nr; i++) {
display_progress(ctx->progress, i + 1);
- commit = lookup_commit(ctx->r, &ctx->oids.list[i]);
+ commit = lookup_commit(ctx->r, &ctx->oids.oid[i]);
if (!commit)
continue;
@@ -1339,7 +1321,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)
ctx->oids.nr);
for (i = 0; i < ctx->oids.nr; i++) {
display_progress(ctx->progress, i + 1);
- commit = lookup_commit(ctx->r, &ctx->oids.list[i]);
+ commit = lookup_commit(ctx->r, &ctx->oids.oid[i]);
if (commit)
commit->object.flags &= ~REACHABLE;
@@ -1567,9 +1549,7 @@ static int fill_oids_from_commits(struct write_commit_graph_context *ctx,
oidset_iter_init(commits, &iter);
while ((oid = oidset_iter_next(&iter))) {
- ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
- oidcpy(&ctx->oids.list[ctx->oids.nr], oid);
- ctx->oids.nr++;
+ oid_array_append(&ctx->oids, oid);
}
return 0;
@@ -1588,35 +1568,6 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
stop_progress(&ctx->progress);
}
-static uint32_t count_distinct_commits(struct write_commit_graph_context *ctx)
-{
- uint32_t i, count_distinct = 1;
-
- if (ctx->report_progress)
- ctx->progress = start_delayed_progress(
- _("Counting distinct commits in commit graph"),
- ctx->oids.nr);
- display_progress(ctx->progress, 0); /* TODO: Measure QSORT() progress */
- QSORT(ctx->oids.list, ctx->oids.nr, oid_compare);
-
- for (i = 1; i < ctx->oids.nr; i++) {
- display_progress(ctx->progress, i + 1);
- if (!oideq(&ctx->oids.list[i - 1], &ctx->oids.list[i])) {
- if (ctx->split) {
- struct commit *c = lookup_commit(ctx->r, &ctx->oids.list[i]);
-
- if (!c || commit_graph_position(c) != COMMIT_NOT_FROM_GRAPH)
- continue;
- }
-
- count_distinct++;
- }
- }
- stop_progress(&ctx->progress);
-
- return count_distinct;
-}
-
static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
{
uint32_t i;
@@ -1628,15 +1579,14 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
ctx->progress = start_delayed_progress(
_("Finding extra edges in commit graph"),
ctx->oids.nr);
- for (i = 0; i < ctx->oids.nr; i++) {
+ oid_array_sort(&ctx->oids);
+ for (i = 0; i < ctx->oids.nr; i = oid_array_next_unique(&ctx->oids, i)) {
unsigned int num_parents;
display_progress(ctx->progress, i + 1);
- if (i > 0 && oideq(&ctx->oids.list[i - 1], &ctx->oids.list[i]))
- continue;
ALLOC_GROW(ctx->commits.list, ctx->commits.nr + 1, ctx->commits.alloc);
- ctx->commits.list[ctx->commits.nr] = lookup_commit(ctx->r, &ctx->oids.list[i]);
+ ctx->commits.list[ctx->commits.nr] = lookup_commit(ctx->r, &ctx->oids.oid[i]);
if (ctx->split && flags != COMMIT_GRAPH_SPLIT_REPLACE &&
commit_graph_position(ctx->commits.list[ctx->commits.nr]) != COMMIT_NOT_FROM_GRAPH)
@@ -1744,8 +1694,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
} else {
hold_lock_file_for_update_mode(&lk, ctx->graph_name,
LOCK_DIE_ON_ERROR, 0444);
- fd = lk.tempfile->fd;
- f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
+ fd = get_lock_file_fd(&lk);
+ f = hashfd(fd, get_lock_file_path(&lk));
}
chunks[0].id = GRAPH_CHUNKID_OIDFANOUT;
@@ -1883,7 +1833,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
result = rename(ctx->graph_name, final_graph_name);
for (i = 0; i < ctx->num_commit_graphs_after; i++)
- fprintf(lk.tempfile->fp, "%s\n", ctx->commit_graph_hash_after[i]);
+ fprintf(get_lock_file_fp(&lk), "%s\n", ctx->commit_graph_hash_after[i]);
if (result) {
error(_("failed to rename temporary commit-graph file"));
@@ -2155,7 +2105,7 @@ int write_commit_graph(struct object_directory *odb,
const struct commit_graph_opts *opts)
{
struct write_commit_graph_context *ctx;
- uint32_t i, count_distinct = 0;
+ uint32_t i;
int res = 0;
int replace = 0;
struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
@@ -2227,26 +2177,16 @@ int write_commit_graph(struct object_directory *odb,
}
ctx->approx_nr_objects = approximate_object_count();
- ctx->oids.alloc = ctx->approx_nr_objects / 32;
-
- if (ctx->split && opts && ctx->oids.alloc > opts->max_commits)
- ctx->oids.alloc = opts->max_commits;
- if (ctx->append) {
+ if (ctx->append)
prepare_commit_graph_one(ctx->r, ctx->odb);
- if (ctx->r->objects->commit_graph)
- ctx->oids.alloc += ctx->r->objects->commit_graph->num_commits;
- }
-
- if (ctx->oids.alloc < 1024)
- ctx->oids.alloc = 1024;
- ALLOC_ARRAY(ctx->oids.list, ctx->oids.alloc);
if (ctx->append && ctx->r->objects->commit_graph) {
struct commit_graph *g = ctx->r->objects->commit_graph;
for (i = 0; i < g->num_commits; i++) {
- const unsigned char *hash = g->chunk_oid_lookup + g->hash_len * i;
- hashcpy(ctx->oids.list[ctx->oids.nr++].hash, hash);
+ struct object_id oid;
+ hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * i);
+ oid_array_append(&ctx->oids, &oid);
}
}
@@ -2268,17 +2208,6 @@ int write_commit_graph(struct object_directory *odb,
close_reachable(ctx);
- count_distinct = count_distinct_commits(ctx);
-
- if (count_distinct >= GRAPH_EDGE_LAST_MASK) {
- error(_("the commit graph format cannot write %d commits"), count_distinct);
- res = -1;
- goto cleanup;
- }
-
- ctx->commits.alloc = count_distinct;
- ALLOC_ARRAY(ctx->commits.list, ctx->commits.alloc);
-
copy_oids_to_commits(ctx);
if (ctx->commits.nr >= GRAPH_EDGE_LAST_MASK) {
@@ -2313,7 +2242,7 @@ int write_commit_graph(struct object_directory *odb,
cleanup:
free(ctx->graph_name);
free(ctx->commits.list);
- free(ctx->oids.list);
+ oid_array_clear(&ctx->oids);
if (ctx->commit_graph_filenames_after) {
for (i = 0; i < ctx->num_commit_graphs_after; i++) {
diff --git a/commit.c b/commit.c
index fe1fa3d..bab8d5a 100644
--- a/commit.c
+++ b/commit.c
@@ -14,7 +14,7 @@
#include "mergesort.h"
#include "commit-slab.h"
#include "prio-queue.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
#include "wt-status.h"
#include "advice.h"
#include "refs.h"
@@ -113,7 +113,7 @@ static const unsigned char *commit_graft_sha1_access(size_t index, void *table)
int commit_graft_pos(struct repository *r, const unsigned char *sha1)
{
- return sha1_pos(sha1, r->parsed_objects->grafts,
+ return hash_pos(sha1, r->parsed_objects->grafts,
r->parsed_objects->grafts_nr,
commit_graft_sha1_access);
}
@@ -544,6 +544,17 @@ struct commit_list *commit_list_insert(struct commit *item, struct commit_list *
return new_list;
}
+int commit_list_contains(struct commit *item, struct commit_list *list)
+{
+ while (list) {
+ if (list->item == item)
+ return 1;
+ list = list->next;
+ }
+
+ return 0;
+}
+
unsigned commit_list_count(const struct commit_list *l)
{
unsigned c = 0;
@@ -563,6 +574,17 @@ struct commit_list *copy_commit_list(struct commit_list *list)
return head;
}
+struct commit_list *reverse_commit_list(struct commit_list *list)
+{
+ struct commit_list *next = NULL, *current, *backup;
+ for (current = list; current; current = backup) {
+ backup = current->next;
+ current->next = next;
+ next = current;
+ }
+ return next;
+}
+
void free_commit_list(struct commit_list *list)
{
while (list)
diff --git a/commit.h b/commit.h
index 5467786..f4e7b01 100644
--- a/commit.h
+++ b/commit.h
@@ -167,6 +167,8 @@ int find_commit_subject(const char *commit_buffer, const char **subject);
struct commit_list *commit_list_insert(struct commit *item,
struct commit_list **list);
+int commit_list_contains(struct commit *item,
+ struct commit_list *list);
struct commit_list **commit_list_append(struct commit *commit,
struct commit_list **next);
unsigned commit_list_count(const struct commit_list *l);
@@ -177,6 +179,9 @@ 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);
+/* Modify list in-place to reverse it, returning new head; list will be tail */
+struct commit_list *reverse_commit_list(struct commit_list *list);
+
void free_commit_list(struct commit_list *list);
struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
diff --git a/config.c b/config.c
index 1137bd7..4c0cf3a 100644
--- a/config.c
+++ b/config.c
@@ -1217,6 +1217,8 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
return config_error_nonbool(var);
if (!strcasecmp(value, "auto"))
default_abbrev = -1;
+ else if (!git_parse_maybe_bool_text(value))
+ default_abbrev = the_hash_algo->hexsz;
else {
int abbrev = git_config_int(var, value);
if (abbrev < minimum_abbrev || abbrev > the_hash_algo->hexsz)
diff --git a/config.mak.uname b/config.mak.uname
index 5b30a91..198ab1e 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -574,10 +574,6 @@ ifeq ($(uname_S),NONSTOP_KERNEL)
NO_MMAP = YesPlease
NO_POLL = YesPlease
NO_INTPTR_T = UnfortunatelyYes
- # Bug report 10-120822-4477 submitted to HP NonStop development.
- MKDIR_WO_TRAILING_SLASH = YesPlease
- # RFE 10-120912-4693 submitted to HP NonStop development.
- NO_SETITIMER = UnfortunatelyYes
SANE_TOOL_PATH = /usr/coreutils/bin:/usr/local/bin
SHELL_PATH = /usr/coreutils/bin/bash
endif
diff --git a/connect.c b/connect.c
index 8b8f56c..9c97fee 100644
--- a/connect.c
+++ b/connect.c
@@ -1160,6 +1160,8 @@ static struct child_process *git_connect_git(int fd[2], char *hostandport,
target_host = xstrdup(hostandport);
transport_check_allowed("git");
+ if (strchr(target_host, '\n') || strchr(path, '\n'))
+ die(_("newline is forbidden in git:// hosts and repo paths"));
/*
* These underlying connection commands die() if they
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 463a312..4b1f426 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -29,6 +29,15 @@
# tell the completion to use commit completion. This also works with aliases
# of form "!sh -c '...'". For example, "!sh -c ': git commit ; ... '".
#
+# If you have a command that is not part of git, but you would still
+# like completion, you can use __git_complete:
+#
+# __git_complete gl git_log
+#
+# Or if it's a main command (i.e. git or gitk):
+#
+# __git_complete gk gitk
+#
# Compatible with bash 3.2.57.
#
# You can set the following environment variables to influence the behavior of
@@ -3358,15 +3367,19 @@ __git_support_parseopt_helper () {
esac
}
+__git_have_func () {
+ declare -f -- "$1" >/dev/null 2>&1
+}
+
__git_complete_command () {
local command="$1"
local completion_func="_git_${command//-/_}"
- if ! declare -f $completion_func >/dev/null 2>/dev/null &&
- declare -f _completion_loader >/dev/null 2>/dev/null
+ if ! __git_have_func $completion_func &&
+ __git_have_func _completion_loader
then
_completion_loader "git-$command"
fi
- if declare -f $completion_func >/dev/null 2>/dev/null
+ if __git_have_func $completion_func
then
$completion_func
return 0
@@ -3493,10 +3506,7 @@ __git_func_wrap ()
$1
}
-# Setup completion for certain functions defined above by setting common
-# variables and workarounds.
-# This is NOT a public function; use at your own risk.
-__git_complete ()
+___git_complete ()
{
local wrapper="__git_wrap${2}"
eval "$wrapper () { __git_func_wrap $2 ; }"
@@ -3504,13 +3514,33 @@ __git_complete ()
|| complete -o default -o nospace -F $wrapper $1
}
-__git_complete git __git_main
-__git_complete gitk __gitk_main
+# Setup the completion for git commands
+# 1: command or alias
+# 2: function to call (e.g. `git`, `gitk`, `git_fetch`)
+__git_complete ()
+{
+ local func
+
+ if __git_have_func $2; then
+ func=$2
+ elif __git_have_func __$2_main; then
+ func=__$2_main
+ elif __git_have_func _$2; then
+ func=_$2
+ else
+ echo "ERROR: could not find function '$2'" 1>&2
+ return 1
+ fi
+ ___git_complete $1 $func
+}
+
+___git_complete git __git_main
+___git_complete gitk __gitk_main
# The following are necessary only for Cygwin, and only are needed
# when the user has tab-completed the executable name and consequently
# included the '.exe' suffix.
#
if [ "$OSTYPE" = cygwin ]; then
- __git_complete git.exe __git_main
+ ___git_complete git.exe __git_main
fi
diff --git a/diff.c b/diff.c
index 643f4f3..2253ec8 100644
--- a/diff.c
+++ b/diff.c
@@ -4634,7 +4634,8 @@ void diff_setup_done(struct diff_options *options)
* inside contents.
*/
- if ((options->xdl_opts & XDF_WHITESPACE_FLAGS))
+ if ((options->xdl_opts & XDF_WHITESPACE_FLAGS) ||
+ options->ignore_regex_nr)
options->flags.diff_from_contents = 1;
else
options->flags.diff_from_contents = 0;
diff --git a/diffcore-rename.c b/diffcore-rename.c
index d367a6d..90db9eb 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -9,63 +9,36 @@
#include "hashmap.h"
#include "progress.h"
#include "promisor-remote.h"
+#include "strmap.h"
/* Table of rename/copy destinations */
static struct diff_rename_dst {
- struct diff_filespec *two;
- struct diff_filepair *pair;
+ struct diff_filepair *p;
+ struct diff_filespec *filespec_to_free;
+ int is_rename; /* false -> just a create; true -> rename or copy */
} *rename_dst;
static int rename_dst_nr, rename_dst_alloc;
+/* Mapping from break source pathname to break destination index */
+static struct strintmap *break_idx = NULL;
-static int find_rename_dst(struct diff_filespec *two)
-{
- int first, last;
-
- first = 0;
- last = rename_dst_nr;
- while (last > first) {
- int next = first + ((last - first) >> 1);
- struct diff_rename_dst *dst = &(rename_dst[next]);
- int cmp = strcmp(two->path, dst->two->path);
- if (!cmp)
- return next;
- if (cmp < 0) {
- last = next;
- continue;
- }
- first = next+1;
- }
- return -first - 1;
-}
-
-static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two)
+static struct diff_rename_dst *locate_rename_dst(struct diff_filepair *p)
{
- int ofs = find_rename_dst(two);
- return ofs < 0 ? NULL : &rename_dst[ofs];
+ /* Lookup by p->ONE->path */
+ int idx = break_idx ? strintmap_get(break_idx, p->one->path) : -1;
+ return (idx == -1) ? NULL : &rename_dst[idx];
}
/*
* Returns 0 on success, -1 if we found a duplicate.
*/
-static int add_rename_dst(struct diff_filespec *two)
+static int add_rename_dst(struct diff_filepair *p)
{
- int first = find_rename_dst(two);
-
- if (first >= 0)
- return -1;
- first = -first - 1;
-
- /* insert to make it at "first" */
ALLOC_GROW(rename_dst, rename_dst_nr + 1, rename_dst_alloc);
+ rename_dst[rename_dst_nr].p = p;
+ rename_dst[rename_dst_nr].filespec_to_free = NULL;
+ rename_dst[rename_dst_nr].is_rename = 0;
rename_dst_nr++;
- if (first < rename_dst_nr)
- MOVE_ARRAY(rename_dst + first + 1, rename_dst + first,
- rename_dst_nr - first - 1);
- rename_dst[first].two = alloc_filespec(two->path);
- fill_filespec(rename_dst[first].two, &two->oid, two->oid_valid,
- two->mode);
- rename_dst[first].pair = NULL;
return 0;
}
@@ -76,36 +49,20 @@ static struct diff_rename_src {
} *rename_src;
static int rename_src_nr, rename_src_alloc;
-static struct diff_rename_src *register_rename_src(struct diff_filepair *p)
+static void register_rename_src(struct diff_filepair *p)
{
- int first, last;
- struct diff_filespec *one = p->one;
- unsigned short score = p->score;
-
- first = 0;
- last = rename_src_nr;
- while (last > first) {
- int next = first + ((last - first) >> 1);
- struct diff_rename_src *src = &(rename_src[next]);
- int cmp = strcmp(one->path, src->p->one->path);
- if (!cmp)
- return src;
- if (cmp < 0) {
- last = next;
- continue;
+ if (p->broken_pair) {
+ if (!break_idx) {
+ break_idx = xmalloc(sizeof(*break_idx));
+ strintmap_init(break_idx, -1);
}
- first = next+1;
+ strintmap_set(break_idx, p->one->path, rename_dst_nr);
}
- /* insert to make it at "first" */
ALLOC_GROW(rename_src, rename_src_nr + 1, rename_src_alloc);
+ rename_src[rename_src_nr].p = p;
+ rename_src[rename_src_nr].score = p->score;
rename_src_nr++;
- if (first < rename_src_nr)
- MOVE_ARRAY(rename_src + first + 1, rename_src + first,
- rename_src_nr - first - 1);
- rename_src[first].p = p;
- rename_src[first].score = score;
- return &(rename_src[first]);
}
static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
@@ -141,14 +98,14 @@ static void prefetch(void *prefetch_options)
struct oid_array to_fetch = OID_ARRAY_INIT;
for (i = 0; i < rename_dst_nr; i++) {
- if (rename_dst[i].pair)
+ if (rename_dst[i].p->renamed_pair)
/*
* The loop in diffcore_rename() will not need these
* blobs, so skip prefetching.
*/
continue; /* already found exact match */
diff_add_if_missing(options->repo, &to_fetch,
- rename_dst[i].two);
+ rename_dst[i].p->two);
}
for (i = 0; i < rename_src_nr; i++) {
if (options->skip_unmodified &&
@@ -258,26 +215,24 @@ static int estimate_similarity(struct repository *r,
static void record_rename_pair(int dst_index, int src_index, int score)
{
- struct diff_filespec *src, *dst;
- struct diff_filepair *dp;
+ struct diff_filepair *src = rename_src[src_index].p;
+ struct diff_filepair *dst = rename_dst[dst_index].p;
- if (rename_dst[dst_index].pair)
+ if (dst->renamed_pair)
die("internal error: dst already matched.");
- src = rename_src[src_index].p->one;
- src->rename_used++;
- src->count++;
+ src->one->rename_used++;
+ src->one->count++;
- dst = rename_dst[dst_index].two;
- dst->count++;
+ rename_dst[dst_index].filespec_to_free = dst->one;
+ rename_dst[dst_index].is_rename = 1;
- dp = diff_queue(NULL, src, dst);
- dp->renamed_pair = 1;
- if (!strcmp(src->path, dst->path))
- dp->score = rename_src[src_index].score;
+ dst->one = src->one;
+ dst->renamed_pair = 1;
+ if (!strcmp(dst->one->path, dst->two->path))
+ dst->score = rename_src[src_index].score;
else
- dp->score = score;
- rename_dst[dst_index].pair = dp;
+ dst->score = score;
}
/*
@@ -323,7 +278,7 @@ static int find_identical_files(struct hashmap *srcs,
struct diff_options *options)
{
int renames = 0;
- struct diff_filespec *target = rename_dst[dst_index].two;
+ struct diff_filespec *target = rename_dst[dst_index].p->two;
struct file_similarity *p, *best = NULL;
int i = 100, best_score = -1;
unsigned int hash = hash_filespec(options->repo, target);
@@ -434,12 +389,11 @@ static void record_if_better(struct diff_score m[], struct diff_score *o)
* 1 if we need to disable inexact rename detection;
* 2 if we would be under the limit if we were given -C instead of -C -C.
*/
-static int too_many_rename_candidates(int num_create,
+static int too_many_rename_candidates(int num_destinations, int num_sources,
struct diff_options *options)
{
int rename_limit = options->rename_limit;
- int num_src = rename_src_nr;
- int i;
+ int i, limited_sources;
options->needed_rename_limit = 0;
@@ -447,31 +401,34 @@ static int too_many_rename_candidates(int num_create,
* This basically does a test for the rename matrix not
* growing larger than a "rename_limit" square matrix, ie:
*
- * num_create * num_src > rename_limit * rename_limit
+ * num_destinations * num_sources > rename_limit * rename_limit
+ *
+ * We use st_mult() to check overflow conditions; in the
+ * exceptional circumstance that size_t isn't large enough to hold
+ * the multiplication, the system won't be able to allocate enough
+ * memory for the matrix anyway.
*/
if (rename_limit <= 0)
rename_limit = 32767;
- if ((num_create <= rename_limit || num_src <= rename_limit) &&
- ((uint64_t)num_create * (uint64_t)num_src
- <= (uint64_t)rename_limit * (uint64_t)rename_limit))
+ if (st_mult(num_destinations, num_sources)
+ <= st_mult(rename_limit, rename_limit))
return 0;
options->needed_rename_limit =
- num_src > num_create ? num_src : num_create;
+ num_sources > num_destinations ? num_sources : num_destinations;
/* Are we running under -C -C? */
if (!options->flags.find_copies_harder)
return 1;
/* Would we bust the limit if we were running under -C? */
- for (num_src = i = 0; i < rename_src_nr; i++) {
+ for (limited_sources = i = 0; i < num_sources; i++) {
if (diff_unmodified_pair(rename_src[i].p))
continue;
- num_src++;
+ limited_sources++;
}
- if ((num_create <= rename_limit || num_src <= rename_limit) &&
- ((uint64_t)num_create * (uint64_t)num_src
- <= (uint64_t)rename_limit * (uint64_t)rename_limit))
+ if (st_mult(num_destinations, limited_sources)
+ <= st_mult(rename_limit, rename_limit))
return 2;
return 1;
}
@@ -487,7 +444,7 @@ static int find_renames(struct diff_score *mx, int dst_cnt, int minimum_score, i
(mx[i].score < minimum_score))
break; /* there is no more usable pair. */
dst = &rename_dst[mx[i].dst];
- if (dst->pair)
+ if (dst->is_rename)
continue; /* already done, either exact or fuzzy. */
if (!copies && rename_src[mx[i].src].p->one->rename_used)
continue;
@@ -505,7 +462,7 @@ void diffcore_rename(struct diff_options *options)
struct diff_queue_struct outq;
struct diff_score *mx;
int i, j, rename_count, skip_unmodified = 0;
- int num_create, dst_cnt;
+ int num_destinations, dst_cnt;
struct progress *progress = NULL;
if (!minimum_score)
@@ -522,7 +479,7 @@ void diffcore_rename(struct diff_options *options)
else if (!options->flags.rename_empty &&
is_empty_blob_oid(&p->two->oid))
continue;
- else if (add_rename_dst(p->two) < 0) {
+ else if (add_rename_dst(p) < 0) {
warning("skipping rename detection, detected"
" duplicate destination '%s'",
p->two->path);
@@ -570,13 +527,14 @@ void diffcore_rename(struct diff_options *options)
* Calculate how many renames are left (but all the source
* files still remain as options for rename/copies!)
*/
- num_create = (rename_dst_nr - rename_count);
+ num_destinations = (rename_dst_nr - rename_count);
/* All done? */
- if (!num_create)
+ if (!num_destinations)
goto cleanup;
- switch (too_many_rename_candidates(num_create, options)) {
+ switch (too_many_rename_candidates(num_destinations, rename_src_nr,
+ options)) {
case 1:
goto cleanup;
case 2:
@@ -590,15 +548,16 @@ void diffcore_rename(struct diff_options *options)
if (options->show_rename_progress) {
progress = start_delayed_progress(
_("Performing inexact rename detection"),
- (uint64_t)rename_dst_nr * (uint64_t)rename_src_nr);
+ (uint64_t)num_destinations * (uint64_t)rename_src_nr);
}
- mx = xcalloc(st_mult(NUM_CANDIDATE_PER_DST, num_create), sizeof(*mx));
+ mx = xcalloc(st_mult(NUM_CANDIDATE_PER_DST, num_destinations),
+ sizeof(*mx));
for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
- struct diff_filespec *two = rename_dst[i].two;
+ struct diff_filespec *two = rename_dst[i].p->two;
struct diff_score *m;
- if (rename_dst[i].pair)
+ if (rename_dst[i].is_rename)
continue; /* dealt with exact match already. */
m = &mx[dst_cnt * NUM_CANDIDATE_PER_DST];
@@ -629,7 +588,8 @@ void diffcore_rename(struct diff_options *options)
diff_free_filespec_blob(two);
}
dst_cnt++;
- display_progress(progress, (uint64_t)(i+1)*(uint64_t)rename_src_nr);
+ display_progress(progress,
+ (uint64_t)dst_cnt * (uint64_t)rename_src_nr);
}
stop_progress(&progress);
@@ -654,22 +614,8 @@ void diffcore_rename(struct diff_options *options)
diff_q(&outq, p);
}
else if (!DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
- /*
- * Creation
- *
- * We would output this create record if it has
- * not been turned into a rename/copy already.
- */
- struct diff_rename_dst *dst = locate_rename_dst(p->two);
- if (dst && dst->pair) {
- diff_q(&outq, dst->pair);
- pair_to_free = p;
- }
- else
- /* no matching rename/copy source, so
- * record this as a creation.
- */
- diff_q(&outq, p);
+ /* Creation */
+ diff_q(&outq, p);
}
else if (DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two)) {
/*
@@ -690,8 +636,10 @@ void diffcore_rename(struct diff_options *options)
*/
if (DIFF_PAIR_BROKEN(p)) {
/* broken delete */
- struct diff_rename_dst *dst = locate_rename_dst(p->one);
- if (dst && dst->pair)
+ struct diff_rename_dst *dst = locate_rename_dst(p);
+ if (!dst)
+ BUG("tracking failed somehow; failed to find associated dst for broken pair");
+ if (dst->is_rename)
/* counterpart is now rename/copy */
pair_to_free = p;
}
@@ -701,16 +649,14 @@ void diffcore_rename(struct diff_options *options)
pair_to_free = p;
}
- if (pair_to_free)
- ;
- else
+ if (!pair_to_free)
diff_q(&outq, p);
}
else if (!diff_unmodified_pair(p))
/* all the usual ones need to be kept */
diff_q(&outq, p);
else
- /* no need to keep unmodified pairs */
+ /* no need to keep unmodified pairs; FIXME: remove earlier? */
pair_to_free = p;
if (pair_to_free)
@@ -723,11 +669,16 @@ void diffcore_rename(struct diff_options *options)
diff_debug_queue("done collapsing", q);
for (i = 0; i < rename_dst_nr; i++)
- free_filespec(rename_dst[i].two);
+ if (rename_dst[i].filespec_to_free)
+ free_filespec(rename_dst[i].filespec_to_free);
FREE_AND_NULL(rename_dst);
rename_dst_nr = rename_dst_alloc = 0;
FREE_AND_NULL(rename_src);
rename_src_nr = rename_src_alloc = 0;
+ if (break_idx) {
+ strintmap_clear(break_idx);
+ FREE_AND_NULL(break_idx);
+ }
return;
}
diff --git a/ewah/bitmap.c b/ewah/bitmap.c
index d8cec58..0d31cdc 100644
--- a/ewah/bitmap.c
+++ b/ewah/bitmap.c
@@ -35,18 +35,26 @@ struct bitmap *bitmap_new(void)
return bitmap_word_alloc(32);
}
+struct bitmap *bitmap_dup(const struct bitmap *src)
+{
+ struct bitmap *dst = bitmap_word_alloc(src->word_alloc);
+ COPY_ARRAY(dst->words, src->words, src->word_alloc);
+ return dst;
+}
+
+static void bitmap_grow(struct bitmap *self, size_t word_alloc)
+{
+ size_t old_size = self->word_alloc;
+ ALLOC_GROW(self->words, word_alloc, self->word_alloc);
+ memset(self->words + old_size, 0x0,
+ (self->word_alloc - old_size) * sizeof(eword_t));
+}
+
void bitmap_set(struct bitmap *self, size_t pos)
{
size_t block = EWAH_BLOCK(pos);
- if (block >= self->word_alloc) {
- size_t old_size = self->word_alloc;
- self->word_alloc = block ? block * 2 : 1;
- REALLOC_ARRAY(self->words, self->word_alloc);
- memset(self->words + old_size, 0x0,
- (self->word_alloc - old_size) * sizeof(eword_t));
- }
-
+ bitmap_grow(self, block + 1);
self->words[block] |= EWAH_MASK(pos);
}
@@ -121,6 +129,15 @@ void bitmap_and_not(struct bitmap *self, struct bitmap *other)
self->words[i] &= ~other->words[i];
}
+void bitmap_or(struct bitmap *self, const struct bitmap *other)
+{
+ size_t i;
+
+ bitmap_grow(self, other->word_alloc);
+ for (i = 0; i < other->word_alloc; i++)
+ self->words[i] |= other->words[i];
+}
+
void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)
{
size_t original_size = self->word_alloc;
@@ -178,6 +195,27 @@ int bitmap_equals(struct bitmap *self, struct bitmap *other)
return 1;
}
+int bitmap_is_subset(struct bitmap *self, struct bitmap *other)
+{
+ size_t common_size, i;
+
+ if (self->word_alloc < other->word_alloc)
+ common_size = self->word_alloc;
+ else {
+ common_size = other->word_alloc;
+ for (i = common_size; i < self->word_alloc; i++) {
+ if (self->words[i])
+ return 1;
+ }
+ }
+
+ for (i = 0; i < common_size; i++) {
+ if (self->words[i] & ~other->words[i])
+ return 1;
+ }
+ return 0;
+}
+
void bitmap_reset(struct bitmap *bitmap)
{
memset(bitmap->words, 0x0, bitmap->word_alloc * sizeof(eword_t));
diff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c
index d59b1af..2a8c7c5 100644
--- a/ewah/ewah_bitmap.c
+++ b/ewah/ewah_bitmap.c
@@ -19,6 +19,7 @@
#include "git-compat-util.h"
#include "ewok.h"
#include "ewok_rlw.h"
+#include "cache.h"
static inline size_t min_size(size_t a, size_t b)
{
@@ -33,20 +34,13 @@ static inline size_t max_size(size_t a, size_t b)
static inline void buffer_grow(struct ewah_bitmap *self, size_t new_size)
{
size_t rlw_offset = (uint8_t *)self->rlw - (uint8_t *)self->buffer;
-
- if (self->alloc_size >= new_size)
- return;
-
- self->alloc_size = new_size;
- REALLOC_ARRAY(self->buffer, self->alloc_size);
+ ALLOC_GROW(self->buffer, new_size, self->alloc_size);
self->rlw = self->buffer + (rlw_offset / sizeof(eword_t));
}
static inline void buffer_push(struct ewah_bitmap *self, eword_t value)
{
- if (self->buffer_size + 1 >= self->alloc_size)
- buffer_grow(self, self->buffer_size * 3 / 2);
-
+ buffer_grow(self, self->buffer_size + 1);
self->buffer[self->buffer_size++] = value;
}
@@ -137,8 +131,7 @@ void ewah_add_dirty_words(
rlw_set_literal_words(self->rlw, literals + can_add);
- if (self->buffer_size + can_add >= self->alloc_size)
- buffer_grow(self, (self->buffer_size + can_add) * 3 / 2);
+ buffer_grow(self, self->buffer_size + can_add);
if (negate) {
size_t i;
diff --git a/ewah/ewok.h b/ewah/ewok.h
index 011852b..6692096 100644
--- a/ewah/ewok.h
+++ b/ewah/ewok.h
@@ -173,13 +173,14 @@ struct bitmap {
struct bitmap *bitmap_new(void);
struct bitmap *bitmap_word_alloc(size_t word_alloc);
+struct bitmap *bitmap_dup(const struct bitmap *src);
void bitmap_set(struct bitmap *self, size_t pos);
void bitmap_unset(struct bitmap *self, size_t pos);
int bitmap_get(struct bitmap *self, size_t pos);
void bitmap_reset(struct bitmap *self);
void bitmap_free(struct bitmap *self);
int bitmap_equals(struct bitmap *self, struct bitmap *other);
-int bitmap_is_subset(struct bitmap *self, struct bitmap *super);
+int bitmap_is_subset(struct bitmap *self, struct bitmap *other);
struct ewah_bitmap * bitmap_to_ewah(struct bitmap *bitmap);
struct bitmap *ewah_to_bitmap(struct ewah_bitmap *ewah);
diff --git a/fsck.c b/fsck.c
index f82e2fe..4b7f0b7 100644
--- a/fsck.c
+++ b/fsck.c
@@ -80,7 +80,9 @@ static struct oidset gitmodules_done = OIDSET_INIT;
/* infos (reported as warnings, but ignored by default) */ \
FUNC(GITMODULES_PARSE, INFO) \
FUNC(BAD_TAG_NAME, INFO) \
- FUNC(MISSING_TAGGER_ENTRY, INFO)
+ FUNC(MISSING_TAGGER_ENTRY, INFO) \
+ /* ignored (elevated when requested) */ \
+ FUNC(EXTRA_HEADER_ENTRY, IGNORE)
#define MSG_ID(id, msg_type) FSCK_MSG_##id,
enum fsck_msg_id {
@@ -911,6 +913,16 @@ static int fsck_tag(const struct object_id *oid, const char *buffer,
unsigned long size, struct fsck_options *options)
{
struct object_id tagged_oid;
+ int tagged_type;
+ return fsck_tag_standalone(oid, buffer, size, options, &tagged_oid,
+ &tagged_type);
+}
+
+int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
+ unsigned long size, struct fsck_options *options,
+ struct object_id *tagged_oid,
+ int *tagged_type)
+{
int ret = 0;
char *eol;
struct strbuf sb = STRBUF_INIT;
@@ -924,7 +936,7 @@ static int fsck_tag(const struct object_id *oid, const char *buffer,
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
goto done;
}
- if (parse_oid_hex(buffer, &tagged_oid, &p) || *p != '\n') {
+ if (parse_oid_hex(buffer, tagged_oid, &p) || *p != '\n') {
ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
if (ret)
goto done;
@@ -940,7 +952,8 @@ static int fsck_tag(const struct object_id *oid, const char *buffer,
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
goto done;
}
- if (type_from_string_gently(buffer, eol - buffer, 1) < 0)
+ *tagged_type = type_from_string_gently(buffer, eol - buffer, 1);
+ if (*tagged_type < 0)
ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
if (ret)
goto done;
@@ -974,6 +987,21 @@ static int fsck_tag(const struct object_id *oid, const char *buffer,
}
else
ret = fsck_ident(&buffer, oid, OBJ_TAG, options);
+ if (!*buffer)
+ goto done;
+
+ if (!starts_with(buffer, "\n")) {
+ /*
+ * The verify_headers() check will allow
+ * e.g. "[...]tagger <tagger>\nsome
+ * garbage\n\nmessage" to pass, thinking "some
+ * garbage" could be a custom header. E.g. "mktag"
+ * doesn't want any unknown headers.
+ */
+ ret = report(options, oid, OBJ_TAG, FSCK_MSG_EXTRA_HEADER_ENTRY, "invalid format - extra header(s) after 'tagger'");
+ if (ret)
+ goto done;
+ }
done:
strbuf_release(&sb);
@@ -1082,7 +1110,7 @@ static int check_submodule_url(const char *url)
if (looks_like_command_line_option(url))
return -1;
- if (submodule_url_is_relative(url)) {
+ if (submodule_url_is_relative(url) || starts_with(url, "git://")) {
char *decoded;
const char *next;
int has_nl;
@@ -1284,3 +1312,27 @@ int fsck_finish(struct fsck_options *options)
oidset_clear(&gitmodules_done);
return ret;
}
+
+int fsck_config_internal(const char *var, const char *value, void *cb,
+ struct fsck_options *options)
+{
+ if (strcmp(var, "fsck.skiplist") == 0) {
+ const char *path;
+ struct strbuf sb = STRBUF_INIT;
+
+ if (git_config_pathname(&path, var, value))
+ return 1;
+ strbuf_addf(&sb, "skiplist=%s", path);
+ free((char *)path);
+ fsck_set_msg_types(options, sb.buf);
+ strbuf_release(&sb);
+ return 0;
+ }
+
+ if (skip_prefix(var, "fsck.", &var)) {
+ fsck_set_msg_type(options, var, value);
+ return 0;
+ }
+
+ return git_default_config(var, value, cb);
+}
diff --git a/fsck.h b/fsck.h
index 69cf715..423c467 100644
--- a/fsck.h
+++ b/fsck.h
@@ -63,6 +63,15 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
struct fsck_options *options);
/*
+ * fsck a tag, and pass info about it back to the caller. This is
+ * exposed fsck_object() internals for git-mktag(1).
+ */
+int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
+ unsigned long size, struct fsck_options *options,
+ struct object_id *tagged_oid,
+ int *tag_type);
+
+/*
* Some fsck checks are context-dependent, and may end up queued; run this
* after completing all fsck_object() calls in order to resolve any remaining
* checks.
@@ -94,4 +103,11 @@ void fsck_put_object_name(struct fsck_options *options,
const char *fsck_describe_object(struct fsck_options *options,
const struct object_id *oid);
+/*
+ * git_config() callback for use by fsck-y tools that want to support
+ * fsck.<msg> fsck.skipList etc.
+ */
+int fsck_config_internal(const char *var, const char *value, void *cb,
+ struct fsck_options *options);
+
#endif
diff --git a/gettext.c b/gettext.c
index 35d2c12..1b56421 100644
--- a/gettext.c
+++ b/gettext.c
@@ -87,88 +87,24 @@ static int test_vsnprintf(const char *fmt, ...)
static void init_gettext_charset(const char *domain)
{
- /*
- This trick arranges for messages to be emitted in the user's
- requested encoding, but avoids setting LC_CTYPE from the
- environment for the whole program.
-
- This primarily done to avoid a bug in vsnprintf in the GNU C
- Library [1]. which triggered a "your vsnprintf is broken" error
- on Git's own repository when inspecting v0.99.6~1 under a UTF-8
- locale.
-
- That commit contains a ISO-8859-1 encoded author name, which
- the locale aware vsnprintf(3) won't interpolate in the format
- argument, due to mismatch between the data encoding and the
- locale.
-
- Even if it wasn't for that bug we wouldn't want to use LC_CTYPE at
- this point, because it'd require auditing all the code that uses C
- functions whose semantics are modified by LC_CTYPE.
-
- But only setting LC_MESSAGES as we do creates a problem, since
- we declare the encoding of our PO files[2] the gettext
- implementation will try to recode it to the user's locale, but
- without LC_CTYPE it'll emit something like this on 'git init'
- under the Icelandic locale:
-
- Bj? til t?ma Git lind ? /hlagh/.git/
-
- Gettext knows about the encoding of our PO file, but we haven't
- told it about the user's encoding, so all the non-US-ASCII
- characters get encoded to question marks.
-
- But we're in luck! We can set LC_CTYPE from the environment
- only while we call nl_langinfo and
- bind_textdomain_codeset. That suffices to tell gettext what
- encoding it should emit in, so it'll now say:
-
- Bjó til tóma Git lind í /hlagh/.git/
-
- And the equivalent ISO-8859-1 string will be emitted under a
- ISO-8859-1 locale.
-
- With this change way we get the advantages of setting LC_CTYPE
- (talk to the user in his language/encoding), without the major
- drawbacks (changed semantics for C functions we rely on).
-
- However foreign functions using other message catalogs that
- aren't using our neat trick will still have a problem, e.g. if
- we have to call perror(3):
-
- #include <stdio.h>
- #include <locale.h>
- #include <errno.h>
-
- int main(void)
- {
- setlocale(LC_MESSAGES, "");
- setlocale(LC_CTYPE, "C");
- errno = ENODEV;
- perror("test");
- return 0;
- }
-
- Running that will give you a message with question marks:
-
- $ LANGUAGE= LANG=de_DE.utf8 ./test
- test: Kein passendes Ger?t gefunden
-
- The vsnprintf bug has been fixed since glibc 2.17.
-
- Then we could simply set LC_CTYPE from the environment, which would
- make things like the external perror(3) messages work.
-
- See t/t0203-gettext-setlocale-sanity.sh's "gettext.c" tests for
- regression tests.
-
- 1. http://sourceware.org/bugzilla/show_bug.cgi?id=6530
- 2. E.g. "Content-Type: text/plain; charset=UTF-8\n" in po/is.po
- */
setlocale(LC_CTYPE, "");
charset = locale_charset();
bind_textdomain_codeset(domain, charset);
- /* the string is taken from v0.99.6~1 */
+
+ /*
+ * Work around an old bug fixed in glibc 2.17 (released on
+ * 2012-12-24), at the cost of potentially making translated
+ * messages from external functions like perror() emitted in
+ * the wrong encoding.
+ *
+ * The bug affected e.g. git.git's own 7eb93c89651 ([PATCH]
+ * Simplify git script, 2005-09-07), which is the origin of
+ * the "David_K\345gedal" test string.
+ *
+ * See a much longer comment added to this file in 5e9637c6297
+ * (i18n: add infrastructure for translating Git with gettext,
+ * 2011-11-18) for more details.
+ */
if (test_vsnprintf("%.*s", 13, "David_K\345gedal") < 0)
setlocale(LC_CTYPE, "C");
}
diff --git a/git-compat-util.h b/git-compat-util.h
index 7d509c5..104993b 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -273,7 +273,7 @@ struct itimerval {
#ifdef NO_SETITIMER
static inline int setitimer(int which, const struct itimerval *value, struct itimerval *newvalue) {
- ; /* nothing */
+ return 0; /* pretend success */
}
#endif
diff --git a/git-gui/Makefile b/git-gui/Makefile
index f10caed..56c85a8 100644
--- a/git-gui/Makefile
+++ b/git-gui/Makefile
@@ -9,7 +9,9 @@ all::
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
+ifneq ($(MAKECMDGOALS),clean)
-include GIT-VERSION-FILE
+endif
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
diff --git a/git-gui/git-gui--askpass b/git-gui/git-gui--askpass
index 1c99ee8..71a536d 100755
--- a/git-gui/git-gui--askpass
+++ b/git-gui/git-gui--askpass
@@ -26,8 +26,21 @@ pack .m -side top -fill x -padx 20 -pady 20 -expand 1
entry .e -textvariable answer -width 50
pack .e -side top -fill x -padx 10 -pady 10
+proc on_show_input_changed {args} {
+ global show_input
+ if {$show_input} {
+ .e configure -show ""
+ } else {
+ .e configure -show "*"
+ }
+}
+trace add variable show_input write "on_show_input_changed"
+
+set show_input 0
+
if {!$yesno} {
- .e configure -show "*"
+ checkbutton .cb_show -text "Show input" -variable show_input
+ pack .cb_show -side top -anchor nw
}
frame .b
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 867b8ce..201524c 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -720,9 +720,6 @@ proc rmsel_tag {text} {
-background [$text cget -background] \
-foreground [$text cget -foreground] \
-borderwidth 0
- $text tag conf in_sel\
- -background $color::select_bg \
- -foreground $color::select_fg
bind $text <Motion> break
return $text
}
@@ -1482,6 +1479,7 @@ proc rescan {after {honor_trustmtime 1}} {
} elseif {[run_prepare_commit_msg_hook]} {
} elseif {[load_message MERGE_MSG]} {
} elseif {[load_message SQUASH_MSG]} {
+ } elseif {[load_message [get_config commit.template]]} {
}
$ui_comm edit reset
$ui_comm edit modified false
@@ -1616,6 +1614,12 @@ proc run_prepare_commit_msg_hook {} {
fconfigure $fd_sm -encoding utf-8
puts -nonewline $fd_pcm [read $fd_sm]
close $fd_sm
+ } elseif {[file isfile [get_config commit.template]]} {
+ set pcm_source "template"
+ set fd_sm [open [get_config commit.template] r]
+ fconfigure $fd_sm -encoding utf-8
+ puts -nonewline $fd_pcm [read $fd_sm]
+ close $fd_sm
} else {
set pcm_source ""
}
@@ -2305,11 +2309,10 @@ proc do_quit {{rc {1}}} {
if {$GITGUI_BCK_exists && ![$ui_comm edit modified]} {
file rename -force [gitdir GITGUI_BCK] $save
set GITGUI_BCK_exists 0
- } else {
+ } elseif {[$ui_comm edit modified]} {
set msg [string trim [$ui_comm get 0.0 end]]
regsub -all -line {[ \r\t]+$} $msg {} msg
- if {(![string match amend* $commit_type]
- || [$ui_comm edit modified])
+ if {![string match amend* $commit_type]
&& $msg ne {}} {
catch {
set fd [open $save w]
@@ -3322,11 +3325,20 @@ if {!$use_ttk} {
.vpane.files paneconfigure .vpane.files.index -sticky news
}
+proc set_selection_colors {w has_focus} {
+ foreach tag [list in_diff in_sel] {
+ $w tag conf $tag \
+ -background [expr {$has_focus ? $color::select_bg : $color::inactive_select_bg}] \
+ -foreground [expr {$has_focus ? $color::select_fg : $color::inactive_select_fg}]
+ }
+}
+
foreach i [list $ui_index $ui_workdir] {
rmsel_tag $i
- $i tag conf in_diff \
- -background $color::select_bg \
- -foreground $color::select_fg
+
+ set_selection_colors $i 0
+ bind $i <FocusIn> { set_selection_colors %W 1 }
+ bind $i <FocusOut> { set_selection_colors %W 0 }
}
unset i
diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl
index b516aa2..11379f8 100644
--- a/git-gui/lib/commit.tcl
+++ b/git-gui/lib/commit.tcl
@@ -456,6 +456,7 @@ A rescan will be automatically started now.
}
$ui_comm delete 0.0 end
+ load_message [get_config commit.template]
$ui_comm edit reset
$ui_comm edit modified false
if {$::GITGUI_BCK_exists} {
diff --git a/git-gui/lib/themed.tcl b/git-gui/lib/themed.tcl
index 83e3ac7..f43d84e 100644
--- a/git-gui/lib/themed.tcl
+++ b/git-gui/lib/themed.tcl
@@ -6,19 +6,25 @@ namespace eval color {
# Variable colors
# Preffered way to set widget colors is using add_option.
# In some cases, like with tags in_diff/in_sel, we use these colors.
- variable select_bg lightgray
- variable select_fg black
+ variable select_bg lightgray
+ variable select_fg black
+ variable inactive_select_bg lightgray
+ variable inactive_select_fg black
proc sync_with_theme {} {
- set base_bg [ttk::style lookup . -background]
- set base_fg [ttk::style lookup . -foreground]
- set text_bg [ttk::style lookup Treeview -background]
- set text_fg [ttk::style lookup Treeview -foreground]
- set select_bg [ttk::style lookup Default -selectbackground]
- set select_fg [ttk::style lookup Default -selectforeground]
+ set base_bg [ttk::style lookup . -background]
+ set base_fg [ttk::style lookup . -foreground]
+ set text_bg [ttk::style lookup Treeview -background]
+ set text_fg [ttk::style lookup Treeview -foreground]
+ set select_bg [ttk::style lookup Default -selectbackground]
+ set select_fg [ttk::style lookup Default -selectforeground]
+ set inactive_select_bg [convert_rgb_to_gray $select_bg]
+ set inactive_select_fg $select_fg
set color::select_bg $select_bg
set color::select_fg $select_fg
+ set color::inactive_select_bg $inactive_select_bg
+ set color::inactive_select_fg $inactive_select_fg
proc add_option {key val} {
option add $key $val widgetDefault
@@ -34,11 +40,22 @@ namespace eval color {
}
add_option *Text.Background $text_bg
add_option *Text.Foreground $text_fg
- add_option *Text.HighlightBackground $base_bg
- add_option *Text.HighlightColor $select_bg
+ add_option *Text.selectBackground $select_bg
+ add_option *Text.selectForeground $select_fg
+ add_option *Text.inactiveSelectBackground $inactive_select_bg
+ add_option *Text.inactiveSelectForeground $inactive_select_fg
}
}
+proc convert_rgb_to_gray {rgb} {
+ # Simply take the average of red, green and blue. This wouldn't be good
+ # enough for, say, converting a photo to grayscale, but for this simple
+ # purpose of approximating the brightness of a color it's good enough.
+ lassign [winfo rgb . $rgb] r g b
+ set gray [expr {($r / 256 + $g / 256 + $b / 256) / 3}]
+ return [format "#%2.2X%2.2X%2.2X" $gray $gray $gray]
+}
+
proc ttk_get_current_theme {} {
# Handle either current Tk or older versions of 8.5
if {[catch {set theme [ttk::style theme use]}]} {
@@ -174,7 +191,7 @@ proc InitEntryFrame {} {
proc gold_frame {w args} {
global use_ttk
- if {$use_ttk} {
+ if {$use_ttk && ![is_MacOSX]} {
eval [linsert $args 0 ttk::frame $w -style Gold.TFrame]
} else {
eval [linsert $args 0 frame $w -background gold]
@@ -183,7 +200,7 @@ proc gold_frame {w args} {
proc tlabel {w args} {
global use_ttk
- if {$use_ttk} {
+ if {$use_ttk && ![is_MacOSX]} {
set cmd [list ttk::label $w -style Color.TLabel]
foreach {k v} $args {
switch -glob -- $k {
diff --git a/git-gui/po/ru.po b/git-gui/po/ru.po
index 9f5305c..161ee1a 100644
--- a/git-gui/po/ru.po
+++ b/git-gui/po/ru.po
@@ -2,14 +2,14 @@
# Copyright (C) 2007 Shawn Pearce
# This file is distributed under the same license as the git-gui package.
# Translators:
-# Dimitriy Ryazantcev <DJm00n@mail.ru>, 2015-2016
+# Dimitriy Ryazantcev <DJm00n@mail.ru>, 2015-2016,2020
# Irina Riesen <irina.riesen@gmail.com>, 2007
msgid ""
msgstr ""
"Project-Id-Version: Git Russian Localization Project\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-01-26 15:47-0800\n"
-"PO-Revision-Date: 2016-06-30 12:39+0000\n"
+"POT-Creation-Date: 2020-02-08 22:54+0100\n"
+"PO-Revision-Date: 2020-11-05 11:20+0000\n"
"Last-Translator: Dimitriy Ryazantcev <DJm00n@mail.ru>\n"
"Language-Team: Russian (http://www.transifex.com/djm00n/git-po-ru/language/ru/)\n"
"MIME-Version: 1.0\n"
@@ -18,33 +18,33 @@ msgstr ""
"Language: ru\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
-#: git-gui.sh:41 git-gui.sh:793 git-gui.sh:807 git-gui.sh:820 git-gui.sh:903
-#: git-gui.sh:922
-msgid "git-gui: fatal error"
-msgstr "git-gui: критическая ошибка"
-
-#: git-gui.sh:743
+#: git-gui.sh:847
#, tcl-format
msgid "Invalid font specified in %s:"
msgstr "В %s установлен неверный шрифт:"
-#: git-gui.sh:779
+#: git-gui.sh:901
msgid "Main Font"
msgstr "Шрифт интерфейса"
-#: git-gui.sh:780
+#: git-gui.sh:902
msgid "Diff/Console Font"
msgstr "Шрифт консоли и изменений (diff)"
-#: git-gui.sh:794
+#: git-gui.sh:917 git-gui.sh:931 git-gui.sh:944 git-gui.sh:1034
+#: git-gui.sh:1053 git-gui.sh:3212
+msgid "git-gui: fatal error"
+msgstr "git-gui: критическая ошибка"
+
+#: git-gui.sh:918
msgid "Cannot find git in PATH."
msgstr "git не найден в PATH."
-#: git-gui.sh:821
+#: git-gui.sh:945
msgid "Cannot parse Git version string:"
msgstr "Невозможно распознать строку версии Git: "
-#: git-gui.sh:839
+#: git-gui.sh:970
#, tcl-format
msgid ""
"Git version cannot be determined.\n"
@@ -56,473 +56,519 @@ msgid ""
"Assume '%s' is version 1.5.0?\n"
msgstr "Невозможно определить версию Git\n\n%s указывает на версию «%s».\n\nдля %s требуется версия Git, начиная с 1.5.0\n\nПредположить, что «%s» и есть версия 1.5.0?\n"
-#: git-gui.sh:1128
+#: git-gui.sh:1267
msgid "Git directory not found:"
msgstr "Каталог Git не найден:"
-#: git-gui.sh:1146
+#: git-gui.sh:1301
msgid "Cannot move to top of working directory:"
msgstr "Невозможно перейти к корню рабочего каталога репозитория: "
-#: git-gui.sh:1154
+#: git-gui.sh:1309
msgid "Cannot use bare repository:"
msgstr "Невозможно использование репозитория без рабочего каталога:"
-#: git-gui.sh:1162
+#: git-gui.sh:1317
msgid "No working directory"
msgstr "Отсутствует рабочий каталог"
-#: git-gui.sh:1334 lib/checkout_op.tcl:306
+#: git-gui.sh:1491 lib/checkout_op.tcl:306
msgid "Refreshing file status..."
msgstr "Обновление информации о состоянии файлов…"
-#: git-gui.sh:1390
+#: git-gui.sh:1551
msgid "Scanning for modified files ..."
msgstr "Поиск измененных файлов…"
-#: git-gui.sh:1454
+#: git-gui.sh:1629
msgid "Calling prepare-commit-msg hook..."
msgstr "Вызов перехватчика prepare-commit-msg…"
-#: git-gui.sh:1471
+#: git-gui.sh:1646
msgid "Commit declined by prepare-commit-msg hook."
msgstr "Коммит прерван перехватчиком prepare-commit-msg."
-#: git-gui.sh:1629 lib/browser.tcl:246
+#: git-gui.sh:1804 lib/browser.tcl:252
msgid "Ready."
msgstr "Готово."
-#: git-gui.sh:1787
+#: git-gui.sh:1968
#, tcl-format
-msgid "Displaying only %s of %s files."
-msgstr "Показано %s из %s файлов."
+msgid ""
+"Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s "
+"files."
+msgstr "Лимит отображаемых файлов достигнут (gui.maxfilesdisplayed = %s), не все %s файлы показаны."
-#: git-gui.sh:1913
+#: git-gui.sh:2091
msgid "Unmodified"
msgstr "Не изменено"
-#: git-gui.sh:1915
+#: git-gui.sh:2093
msgid "Modified, not staged"
msgstr "Изменено, не в индексе"
-#: git-gui.sh:1916 git-gui.sh:1924
+#: git-gui.sh:2094 git-gui.sh:2106
msgid "Staged for commit"
msgstr "В индексе для коммита"
-#: git-gui.sh:1917 git-gui.sh:1925
+#: git-gui.sh:2095 git-gui.sh:2107
msgid "Portions staged for commit"
msgstr "Части, в индексе для коммита"
-#: git-gui.sh:1918 git-gui.sh:1926
+#: git-gui.sh:2096 git-gui.sh:2108
msgid "Staged for commit, missing"
msgstr "В индексе для коммита, отсутствует"
-#: git-gui.sh:1920
+#: git-gui.sh:2098
msgid "File type changed, not staged"
msgstr "Тип файла изменён, не в индексе"
-#: git-gui.sh:1921
+#: git-gui.sh:2099 git-gui.sh:2100
+msgid "File type changed, old type staged for commit"
+msgstr "Тип файла изменён, старый тип файла в индексе"
+
+#: git-gui.sh:2101
msgid "File type changed, staged"
msgstr "Тип файла изменён, в индексе"
-#: git-gui.sh:1923
+#: git-gui.sh:2102
+msgid "File type change staged, modification not staged"
+msgstr "Изменение типа файла в индексе, изменение не в индексе"
+
+#: git-gui.sh:2103
+msgid "File type change staged, file missing"
+msgstr "Изменение типа файла в индексе, файл не найден"
+
+#: git-gui.sh:2105
msgid "Untracked, not staged"
msgstr "Не отслеживается, не в индексе"
-#: git-gui.sh:1928
+#: git-gui.sh:2110
msgid "Missing"
msgstr "Отсутствует"
-#: git-gui.sh:1929
+#: git-gui.sh:2111
msgid "Staged for removal"
msgstr "В индексе для удаления"
-#: git-gui.sh:1930
+#: git-gui.sh:2112
msgid "Staged for removal, still present"
msgstr "В индексе для удаления, еще не удалено"
-#: git-gui.sh:1932 git-gui.sh:1933 git-gui.sh:1934 git-gui.sh:1935
-#: git-gui.sh:1936 git-gui.sh:1937
+#: git-gui.sh:2114 git-gui.sh:2115 git-gui.sh:2116 git-gui.sh:2117
+#: git-gui.sh:2118 git-gui.sh:2119
msgid "Requires merge resolution"
msgstr "Требуется разрешение конфликта при слиянии"
-#: git-gui.sh:1972
-msgid "Starting gitk... please wait..."
-msgstr "Запускается gitk… Подождите, пожалуйста…"
-
-#: git-gui.sh:1984
+#: git-gui.sh:2164
msgid "Couldn't find gitk in PATH"
msgstr "gitk не найден в PATH."
-#: git-gui.sh:2043
+#: git-gui.sh:2210 git-gui.sh:2245
+#, tcl-format
+msgid "Starting %s... please wait..."
+msgstr "Запускается %s… Подождите, пожалуйста…"
+
+#: git-gui.sh:2224
msgid "Couldn't find git gui in PATH"
msgstr "git gui не найден в PATH."
-#: git-gui.sh:2455 lib/choose_repository.tcl:36
+#: git-gui.sh:2726 lib/choose_repository.tcl:53
msgid "Repository"
msgstr "Репозиторий"
-#: git-gui.sh:2456
+#: git-gui.sh:2727
msgid "Edit"
-msgstr "Редактировать"
+msgstr "Правка"
-#: git-gui.sh:2458 lib/choose_rev.tcl:561
+#: git-gui.sh:2729 lib/choose_rev.tcl:567
msgid "Branch"
msgstr "Ветка"
-#: git-gui.sh:2461 lib/choose_rev.tcl:548
+#: git-gui.sh:2732 lib/choose_rev.tcl:554
msgid "Commit@@noun"
msgstr "Коммит"
-#: git-gui.sh:2464 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168
+#: git-gui.sh:2735 lib/merge.tcl:127 lib/merge.tcl:174
msgid "Merge"
msgstr "Слияние"
-#: git-gui.sh:2465 lib/choose_rev.tcl:557
+#: git-gui.sh:2736 lib/choose_rev.tcl:563
msgid "Remote"
msgstr "Внешние репозитории"
-#: git-gui.sh:2468
+#: git-gui.sh:2739
msgid "Tools"
msgstr "Вспомогательные операции"
-#: git-gui.sh:2477
+#: git-gui.sh:2748
msgid "Explore Working Copy"
msgstr "Просмотр рабочего каталога"
-#: git-gui.sh:2483
+#: git-gui.sh:2763
+msgid "Git Bash"
+msgstr "Git Bash"
+
+#: git-gui.sh:2772
msgid "Browse Current Branch's Files"
msgstr "Просмотреть файлы текущей ветки"
-#: git-gui.sh:2487
+#: git-gui.sh:2776
msgid "Browse Branch Files..."
msgstr "Показать файлы ветки…"
-#: git-gui.sh:2492
+#: git-gui.sh:2781
msgid "Visualize Current Branch's History"
msgstr "Показать историю текущей ветки"
-#: git-gui.sh:2496
+#: git-gui.sh:2785
msgid "Visualize All Branch History"
msgstr "Показать историю всех веток"
-#: git-gui.sh:2503
+#: git-gui.sh:2792
#, tcl-format
msgid "Browse %s's Files"
msgstr "Показать файлы ветки %s"
-#: git-gui.sh:2505
+#: git-gui.sh:2794
#, tcl-format
msgid "Visualize %s's History"
msgstr "Показать историю ветки %s"
-#: git-gui.sh:2510 lib/database.tcl:27 lib/database.tcl:67
+#: git-gui.sh:2799 lib/database.tcl:40
msgid "Database Statistics"
msgstr "Статистика базы данных"
-#: git-gui.sh:2513 lib/database.tcl:34
+#: git-gui.sh:2802 lib/database.tcl:33
msgid "Compress Database"
msgstr "Сжать базу данных"
-#: git-gui.sh:2516
+#: git-gui.sh:2805
msgid "Verify Database"
msgstr "Проверить базу данных"
-#: git-gui.sh:2523 git-gui.sh:2527 git-gui.sh:2531 lib/shortcut.tcl:8
-#: lib/shortcut.tcl:40 lib/shortcut.tcl:72
+#: git-gui.sh:2812 git-gui.sh:2816 git-gui.sh:2820
msgid "Create Desktop Icon"
msgstr "Создать ярлык на рабочем столе"
-#: git-gui.sh:2539 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191
+#: git-gui.sh:2828 lib/choose_repository.tcl:209 lib/choose_repository.tcl:217
msgid "Quit"
msgstr "Выход"
-#: git-gui.sh:2547
+#: git-gui.sh:2836
msgid "Undo"
msgstr "Отменить"
-#: git-gui.sh:2550
+#: git-gui.sh:2839
msgid "Redo"
msgstr "Повторить"
-#: git-gui.sh:2554 git-gui.sh:3109
+#: git-gui.sh:2843 git-gui.sh:3461
msgid "Cut"
msgstr "Вырезать"
-#: git-gui.sh:2557 git-gui.sh:3112 git-gui.sh:3186 git-gui.sh:3259
+#: git-gui.sh:2846 git-gui.sh:3464 git-gui.sh:3540 git-gui.sh:3633
#: lib/console.tcl:69
msgid "Copy"
msgstr "Копировать"
-#: git-gui.sh:2560 git-gui.sh:3115
+#: git-gui.sh:2849 git-gui.sh:3467
msgid "Paste"
msgstr "Вставить"
-#: git-gui.sh:2563 git-gui.sh:3118 lib/branch_delete.tcl:26
-#: lib/remote_branch_delete.tcl:38
+#: git-gui.sh:2852 git-gui.sh:3470 lib/remote_branch_delete.tcl:39
+#: lib/branch_delete.tcl:28
msgid "Delete"
msgstr "Удалить"
-#: git-gui.sh:2567 git-gui.sh:3122 git-gui.sh:3263 lib/console.tcl:71
+#: git-gui.sh:2856 git-gui.sh:3474 git-gui.sh:3637 lib/console.tcl:71
msgid "Select All"
-msgstr "Выделить все"
+msgstr "Выделить всё"
-#: git-gui.sh:2576
+#: git-gui.sh:2865
msgid "Create..."
msgstr "Создать…"
-#: git-gui.sh:2582
+#: git-gui.sh:2871
msgid "Checkout..."
msgstr "Перейти…"
-#: git-gui.sh:2588
+#: git-gui.sh:2877
msgid "Rename..."
msgstr "Переименовать…"
-#: git-gui.sh:2593
+#: git-gui.sh:2882
msgid "Delete..."
msgstr "Удалить…"
-#: git-gui.sh:2598
+#: git-gui.sh:2887
msgid "Reset..."
msgstr "Сбросить…"
-#: git-gui.sh:2608
+#: git-gui.sh:2897
msgid "Done"
msgstr "Завершено"
-#: git-gui.sh:2610
+#: git-gui.sh:2899
msgid "Commit@@verb"
msgstr "Закоммитить"
-#: git-gui.sh:2619 git-gui.sh:3050
-msgid "New Commit"
-msgstr "Новый коммит"
-
-#: git-gui.sh:2627 git-gui.sh:3057
+#: git-gui.sh:2908 git-gui.sh:3400
msgid "Amend Last Commit"
msgstr "Исправить последний коммит"
-#: git-gui.sh:2637 git-gui.sh:3011 lib/remote_branch_delete.tcl:99
+#: git-gui.sh:2918 git-gui.sh:3361 lib/remote_branch_delete.tcl:101
msgid "Rescan"
msgstr "Перечитать"
-#: git-gui.sh:2643
+#: git-gui.sh:2924
msgid "Stage To Commit"
msgstr "Добавить в индекс"
-#: git-gui.sh:2649
+#: git-gui.sh:2930
msgid "Stage Changed Files To Commit"
msgstr "Добавить изменённые файлы в индекс"
-#: git-gui.sh:2655
+#: git-gui.sh:2936
msgid "Unstage From Commit"
msgstr "Убрать из издекса"
-#: git-gui.sh:2661 lib/index.tcl:412
+#: git-gui.sh:2942 lib/index.tcl:521
msgid "Revert Changes"
msgstr "Обратить изменения"
-#: git-gui.sh:2669 git-gui.sh:3310 git-gui.sh:3341
+#: git-gui.sh:2950 git-gui.sh:3700 git-gui.sh:3731
msgid "Show Less Context"
msgstr "Меньше контекста"
-#: git-gui.sh:2673 git-gui.sh:3314 git-gui.sh:3345
+#: git-gui.sh:2954 git-gui.sh:3704 git-gui.sh:3735
msgid "Show More Context"
msgstr "Больше контекста"
-#: git-gui.sh:2680 git-gui.sh:3024 git-gui.sh:3133
+#: git-gui.sh:2961 git-gui.sh:3374 git-gui.sh:3485
msgid "Sign Off"
msgstr "Вставить Signed-off-by"
-#: git-gui.sh:2696
+#: git-gui.sh:2977
msgid "Local Merge..."
msgstr "Локальное слияние…"
-#: git-gui.sh:2701
+#: git-gui.sh:2982
msgid "Abort Merge..."
msgstr "Прервать слияние…"
-#: git-gui.sh:2713 git-gui.sh:2741
+#: git-gui.sh:2994 git-gui.sh:3022
msgid "Add..."
msgstr "Добавить…"
-#: git-gui.sh:2717
+#: git-gui.sh:2998
msgid "Push..."
msgstr "Отправить…"
-#: git-gui.sh:2721
+#: git-gui.sh:3002
msgid "Delete Branch..."
msgstr "Удалить ветку…"
-#: git-gui.sh:2731 git-gui.sh:3292
+#: git-gui.sh:3012 git-gui.sh:3666
msgid "Options..."
msgstr "Настройки…"
-#: git-gui.sh:2742
+#: git-gui.sh:3023
msgid "Remove..."
msgstr "Удалить…"
-#: git-gui.sh:2751 lib/choose_repository.tcl:50
+#: git-gui.sh:3032 lib/choose_repository.tcl:67
msgid "Help"
-msgstr "Помощь"
+msgstr "Справка"
-#: git-gui.sh:2755 git-gui.sh:2759 lib/about.tcl:14
-#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53
+#: git-gui.sh:3036 git-gui.sh:3040 lib/choose_repository.tcl:61
+#: lib/choose_repository.tcl:70 lib/about.tcl:14
#, tcl-format
msgid "About %s"
msgstr "О %s"
-#: git-gui.sh:2783
+#: git-gui.sh:3064
msgid "Online Documentation"
msgstr "Документация в интернете"
-#: git-gui.sh:2786 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56
+#: git-gui.sh:3067 lib/choose_repository.tcl:64 lib/choose_repository.tcl:73
msgid "Show SSH Key"
msgstr "Показать ключ SSH"
-#: git-gui.sh:2893
+#: git-gui.sh:3097 git-gui.sh:3229
+msgid "usage:"
+msgstr "использование:"
+
+#: git-gui.sh:3101 git-gui.sh:3233
+msgid "Usage"
+msgstr "Использование"
+
+#: git-gui.sh:3182 lib/blame.tcl:575
+msgid "Error"
+msgstr "Ошибка"
+
+#: git-gui.sh:3213
#, tcl-format
msgid "fatal: cannot stat path %s: No such file or directory"
msgstr "критическая ошибка: %s: нет такого файла или каталога"
-#: git-gui.sh:2926
+#: git-gui.sh:3246
msgid "Current Branch:"
msgstr "Текущая ветка:"
-#: git-gui.sh:2947
-msgid "Staged Changes (Will Commit)"
-msgstr "Изменения в индексе (будут закоммичены)"
-
-#: git-gui.sh:2967
+#: git-gui.sh:3271
msgid "Unstaged Changes"
msgstr "Изменено (не будет сохранено)"
-#: git-gui.sh:3017
+#: git-gui.sh:3293
+msgid "Staged Changes (Will Commit)"
+msgstr "Изменения в индексе (будут закоммичены)"
+
+#: git-gui.sh:3367
msgid "Stage Changed"
msgstr "Индексировать всё"
-#: git-gui.sh:3036 lib/transport.tcl:104 lib/transport.tcl:193
+#: git-gui.sh:3386 lib/transport.tcl:137
msgid "Push"
msgstr "Отправить"
-#: git-gui.sh:3071
+#: git-gui.sh:3413
msgid "Initial Commit Message:"
msgstr "Сообщение первого коммита:"
-#: git-gui.sh:3072
+#: git-gui.sh:3414
msgid "Amended Commit Message:"
msgstr "Сообщение исправленного коммита:"
-#: git-gui.sh:3073
+#: git-gui.sh:3415
msgid "Amended Initial Commit Message:"
msgstr "Сообщение исправленного первого коммита:"
-#: git-gui.sh:3074
+#: git-gui.sh:3416
msgid "Amended Merge Commit Message:"
msgstr "Сообщение исправленного слияния:"
-#: git-gui.sh:3075
+#: git-gui.sh:3417
msgid "Merge Commit Message:"
msgstr "Сообщение слияния:"
-#: git-gui.sh:3076
+#: git-gui.sh:3418
msgid "Commit Message:"
msgstr "Сообщение коммита:"
-#: git-gui.sh:3125 git-gui.sh:3267 lib/console.tcl:73
+#: git-gui.sh:3477 git-gui.sh:3641 lib/console.tcl:73
msgid "Copy All"
msgstr "Копировать все"
-#: git-gui.sh:3149 lib/blame.tcl:104
+#: git-gui.sh:3501 lib/blame.tcl:106
msgid "File:"
msgstr "Файл:"
-#: git-gui.sh:3255
+#: git-gui.sh:3549 lib/choose_repository.tcl:1100
+msgid "Open"
+msgstr "Открыть"
+
+#: git-gui.sh:3629
msgid "Refresh"
msgstr "Обновить"
-#: git-gui.sh:3276
+#: git-gui.sh:3650
msgid "Decrease Font Size"
msgstr "Уменьшить размер шрифта"
-#: git-gui.sh:3280
+#: git-gui.sh:3654
msgid "Increase Font Size"
msgstr "Увеличить размер шрифта"
-#: git-gui.sh:3288 lib/blame.tcl:281
+#: git-gui.sh:3662 lib/blame.tcl:296
msgid "Encoding"
msgstr "Кодировка"
-#: git-gui.sh:3299
+#: git-gui.sh:3673
msgid "Apply/Reverse Hunk"
msgstr "Применить/Убрать изменение"
-#: git-gui.sh:3304
+#: git-gui.sh:3678
msgid "Apply/Reverse Line"
msgstr "Применить/Убрать строку"
-#: git-gui.sh:3323
+#: git-gui.sh:3684 git-gui.sh:3794 git-gui.sh:3805
+msgid "Revert Hunk"
+msgstr "Обратить изменения блока"
+
+#: git-gui.sh:3689 git-gui.sh:3801 git-gui.sh:3812
+msgid "Revert Line"
+msgstr "Обратить изменения строки"
+
+#: git-gui.sh:3694 git-gui.sh:3791
+msgid "Undo Last Revert"
+msgstr "Отменить последнее обращение изменений"
+
+#: git-gui.sh:3713
msgid "Run Merge Tool"
msgstr "Запустить программу слияния"
-#: git-gui.sh:3328
+#: git-gui.sh:3718
msgid "Use Remote Version"
msgstr "Взять внешнюю версию"
-#: git-gui.sh:3332
+#: git-gui.sh:3722
msgid "Use Local Version"
msgstr "Взять локальную версию"
-#: git-gui.sh:3336
+#: git-gui.sh:3726
msgid "Revert To Base"
msgstr "Обратить изменения"
-#: git-gui.sh:3354
+#: git-gui.sh:3744
msgid "Visualize These Changes In The Submodule"
msgstr "Показать эти изменения подмодуля"
-#: git-gui.sh:3358
+#: git-gui.sh:3748
msgid "Visualize Current Branch History In The Submodule"
msgstr "Показать историю текущей ветки подмодуля"
-#: git-gui.sh:3362
+#: git-gui.sh:3752
msgid "Visualize All Branch History In The Submodule"
msgstr "Показать историю всех веток подмодуля"
-#: git-gui.sh:3367
+#: git-gui.sh:3757
msgid "Start git gui In The Submodule"
msgstr "Запустить git gui в подмодуле"
-#: git-gui.sh:3389
+#: git-gui.sh:3793
msgid "Unstage Hunk From Commit"
msgstr "Убрать блок из индекса"
-#: git-gui.sh:3391
+#: git-gui.sh:3797
msgid "Unstage Lines From Commit"
msgstr "Убрать строки из индекса"
-#: git-gui.sh:3393
+#: git-gui.sh:3798 git-gui.sh:3809
+msgid "Revert Lines"
+msgstr "Обратить изменения строк"
+
+#: git-gui.sh:3800
msgid "Unstage Line From Commit"
msgstr "Убрать строку из индекса"
-#: git-gui.sh:3396
+#: git-gui.sh:3804
msgid "Stage Hunk For Commit"
msgstr "Добавить блок в индекс"
-#: git-gui.sh:3398
+#: git-gui.sh:3808
msgid "Stage Lines For Commit"
msgstr "Добавить строки в индекс"
-#: git-gui.sh:3400
+#: git-gui.sh:3811
msgid "Stage Line For Commit"
msgstr "Добавить строку в индекс"
-#: git-gui.sh:3424
+#: git-gui.sh:3861
msgid "Initializing..."
msgstr "Инициализация…"
-#: git-gui.sh:3541
+#: git-gui.sh:4017
#, tcl-format
msgid ""
"Possible environment issues exist.\n"
@@ -533,14 +579,14 @@ msgid ""
"\n"
msgstr "Возможны ошибки в переменных окружения.\n\nПеременные окружения, которые возможно\nбудут проигнорированы командами Git,\nзапущенными из %s\n\n"
-#: git-gui.sh:3570
+#: git-gui.sh:4046
msgid ""
"\n"
"This is due to a known issue with the\n"
"Tcl binary distributed by Cygwin."
msgstr "\nЭто известная проблема с Tcl,\nраспространяемым Cygwin."
-#: git-gui.sh:3575
+#: git-gui.sh:4051
#, tcl-format
msgid ""
"\n"
@@ -551,309 +597,148 @@ msgid ""
"~/.gitconfig file.\n"
msgstr "\n\nВместо использования %s можно\nсохранить значения user.name и\nuser.email в Вашем персональном\nфайле ~/.gitconfig.\n"
-#: lib/about.tcl:26
-msgid "git-gui - a graphical user interface for Git."
-msgstr "git-gui - графический пользовательский интерфейс к Git."
-
-#: lib/blame.tcl:72
-msgid "File Viewer"
-msgstr "Просмотр файла"
-
-#: lib/blame.tcl:78
-msgid "Commit:"
-msgstr "Коммит:"
-
-#: lib/blame.tcl:271
-msgid "Copy Commit"
-msgstr "Копировать SHA-1"
-
-#: lib/blame.tcl:275
-msgid "Find Text..."
-msgstr "Найти текст…"
-
-#: lib/blame.tcl:284
-msgid "Do Full Copy Detection"
-msgstr "Провести полный поиск копий"
+#: lib/spellcheck.tcl:57
+msgid "Unsupported spell checker"
+msgstr "Неподдерживаемая программа проверки правописания"
-#: lib/blame.tcl:288
-msgid "Show History Context"
-msgstr "Показать исторический контекст"
+#: lib/spellcheck.tcl:65
+msgid "Spell checking is unavailable"
+msgstr "Проверка правописания не доступна"
-#: lib/blame.tcl:291
-msgid "Blame Parent Commit"
-msgstr "Авторы родительского коммита"
+#: lib/spellcheck.tcl:68
+msgid "Invalid spell checking configuration"
+msgstr "Неправильная конфигурация программы проверки правописания"
-#: lib/blame.tcl:450
+#: lib/spellcheck.tcl:70
#, tcl-format
-msgid "Reading %s..."
-msgstr "Чтение %s…"
-
-#: lib/blame.tcl:557
-msgid "Loading copy/move tracking annotations..."
-msgstr "Загрузка аннотации копирований/переименований…"
-
-#: lib/blame.tcl:577
-msgid "lines annotated"
-msgstr "строк прокомментировано"
-
-#: lib/blame.tcl:769
-msgid "Loading original location annotations..."
-msgstr "Загрузка аннотаций первоначального положения объекта…"
-
-#: lib/blame.tcl:772
-msgid "Annotation complete."
-msgstr "Аннотация завершена."
-
-#: lib/blame.tcl:802
-msgid "Busy"
-msgstr "Занят"
-
-#: lib/blame.tcl:803
-msgid "Annotation process is already running."
-msgstr "Аннотация уже запущена"
-
-#: lib/blame.tcl:842
-msgid "Running thorough copy detection..."
-msgstr "Выполнение полного поиска копий…"
-
-#: lib/blame.tcl:910
-msgid "Loading annotation..."
-msgstr "Загрузка аннотации…"
-
-#: lib/blame.tcl:963
-msgid "Author:"
-msgstr "Автор:"
-
-#: lib/blame.tcl:967
-msgid "Committer:"
-msgstr "Коммитер:"
-
-#: lib/blame.tcl:972
-msgid "Original File:"
-msgstr "Исходный файл:"
-
-#: lib/blame.tcl:1020
-msgid "Cannot find HEAD commit:"
-msgstr "Не удалось найти текущее состояние:"
-
-#: lib/blame.tcl:1075
-msgid "Cannot find parent commit:"
-msgstr "Не удалось найти родительское состояние:"
-
-#: lib/blame.tcl:1090
-msgid "Unable to display parent"
-msgstr "Не могу показать предка"
-
-#: lib/blame.tcl:1091 lib/diff.tcl:320
-msgid "Error loading diff:"
-msgstr "Ошибка загрузки изменений:"
-
-#: lib/blame.tcl:1231
-msgid "Originally By:"
-msgstr "Источник:"
-
-#: lib/blame.tcl:1237
-msgid "In File:"
-msgstr "Файл:"
-
-#: lib/blame.tcl:1242
-msgid "Copied Or Moved Here By:"
-msgstr "Скопировано/перемещено в:"
-
-#: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19
-msgid "Checkout Branch"
-msgstr "Перейти на ветку"
-
-#: lib/branch_checkout.tcl:23
-msgid "Checkout"
-msgstr "Перейти"
-
-#: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35
-#: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282
-#: lib/checkout_op.tcl:579 lib/choose_font.tcl:43 lib/merge.tcl:172
-#: lib/option.tcl:125 lib/remote_add.tcl:32 lib/remote_branch_delete.tcl:42
-#: lib/tools_dlg.tcl:40 lib/tools_dlg.tcl:204 lib/tools_dlg.tcl:352
-#: lib/transport.tcl:108
-msgid "Cancel"
-msgstr "Отмена"
-
-#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 lib/tools_dlg.tcl:328
-msgid "Revision"
-msgstr "Версия"
-
-#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:280
-msgid "Options"
-msgstr "Настройки"
-
-#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:92
-msgid "Fetch Tracking Branch"
-msgstr "Извлечь изменения из внешней ветки"
-
-#: lib/branch_checkout.tcl:44
-msgid "Detach From Local Branch"
-msgstr "Отсоединить от локальной ветки"
-
-#: lib/branch_create.tcl:22
-msgid "Create Branch"
-msgstr "Создать ветку"
-
-#: lib/branch_create.tcl:27
-msgid "Create New Branch"
-msgstr "Создать новую ветку"
-
-#: lib/branch_create.tcl:31 lib/choose_repository.tcl:381
-msgid "Create"
-msgstr "Создать"
-
-#: lib/branch_create.tcl:40
-msgid "Branch Name"
-msgstr "Имя ветки"
-
-#: lib/branch_create.tcl:43 lib/remote_add.tcl:39 lib/tools_dlg.tcl:50
-msgid "Name:"
-msgstr "Название:"
-
-#: lib/branch_create.tcl:58
-msgid "Match Tracking Branch Name"
-msgstr "Соответствовать имени отслеживаемой ветки"
-
-#: lib/branch_create.tcl:66
-msgid "Starting Revision"
-msgstr "Начальная версия"
-
-#: lib/branch_create.tcl:72
-msgid "Update Existing Branch:"
-msgstr "Обновить имеющуюся ветку:"
+msgid "Reverting dictionary to %s."
+msgstr "Словарь вернут к %s."
-#: lib/branch_create.tcl:75
-msgid "No"
-msgstr "Нет"
+#: lib/spellcheck.tcl:73
+msgid "Spell checker silently failed on startup"
+msgstr "Программа проверки правописания не смогла запуститься"
-#: lib/branch_create.tcl:80
-msgid "Fast Forward Only"
-msgstr "Только Fast Forward"
+#: lib/spellcheck.tcl:80
+msgid "Unrecognized spell checker"
+msgstr "Нераспознанная программа проверки правописания"
-#: lib/branch_create.tcl:85 lib/checkout_op.tcl:571
-msgid "Reset"
-msgstr "Сброс"
+#: lib/spellcheck.tcl:186
+msgid "No Suggestions"
+msgstr "Исправлений не найдено"
-#: lib/branch_create.tcl:97
-msgid "Checkout After Creation"
-msgstr "После создания сделать текущей"
+#: lib/spellcheck.tcl:388
+msgid "Unexpected EOF from spell checker"
+msgstr "Программа проверки правописания прервала передачу данных"
-#: lib/branch_create.tcl:131
-msgid "Please select a tracking branch."
-msgstr "Укажите отлеживаемую ветку."
+#: lib/spellcheck.tcl:392
+msgid "Spell Checker Failed"
+msgstr "Ошибка проверки правописания"
-#: lib/branch_create.tcl:140
+#: lib/transport.tcl:6 lib/remote_add.tcl:132
#, tcl-format
-msgid "Tracking branch %s is not a branch in the remote repository."
-msgstr "Отслеживаемая ветка %s не является веткой на внешнем репозитории."
+msgid "fetch %s"
+msgstr "извлечение %s"
-#: lib/branch_create.tcl:153 lib/branch_rename.tcl:86
-msgid "Please supply a branch name."
-msgstr "Укажите имя ветки."
+#: lib/transport.tcl:7
+#, tcl-format
+msgid "Fetching new changes from %s"
+msgstr "Извлечение изменений из %s "
-#: lib/branch_create.tcl:164 lib/branch_rename.tcl:106
+#: lib/transport.tcl:18
#, tcl-format
-msgid "'%s' is not an acceptable branch name."
-msgstr "Недопустимое имя ветки «%s»."
+msgid "remote prune %s"
+msgstr "чистка внешнего %s"
-#: lib/branch_delete.tcl:15
-msgid "Delete Branch"
-msgstr "Удаление ветки"
+#: lib/transport.tcl:19
+#, tcl-format
+msgid "Pruning tracking branches deleted from %s"
+msgstr "Чистка отслеживаемых веток, удалённых из %s"
-#: lib/branch_delete.tcl:20
-msgid "Delete Local Branch"
-msgstr "Удалить локальную ветку"
+#: lib/transport.tcl:25
+msgid "fetch all remotes"
+msgstr "извлечь со всех внешних репозиториев"
-#: lib/branch_delete.tcl:37
-msgid "Local Branches"
-msgstr "Локальные ветки"
+#: lib/transport.tcl:26
+msgid "Fetching new changes from all remotes"
+msgstr "Получение изменений со всех внешних репозиториев"
-#: lib/branch_delete.tcl:52
-msgid "Delete Only If Merged Into"
-msgstr "Удалить только в случае, если было слияние с"
+#: lib/transport.tcl:40
+msgid "remote prune all remotes"
+msgstr "чистка всех внешних репозиториев"
-#: lib/branch_delete.tcl:54 lib/remote_branch_delete.tcl:119
-msgid "Always (Do not perform merge checks)"
-msgstr "Всегда (не выполнять проверку на слияние)"
+#: lib/transport.tcl:41
+msgid "Pruning tracking branches deleted from all remotes"
+msgstr "Чистка отслеживаемых веток, удалённых со всех внешних репозиториев"
-#: lib/branch_delete.tcl:103
+#: lib/transport.tcl:54 lib/transport.tcl:92 lib/transport.tcl:110
+#: lib/remote_add.tcl:162
#, tcl-format
-msgid "The following branches are not completely merged into %s:"
-msgstr "Ветки, которые не полностью сливаются с %s:"
-
-#: lib/branch_delete.tcl:115 lib/remote_branch_delete.tcl:217
-msgid ""
-"Recovering deleted branches is difficult.\n"
-"\n"
-"Delete the selected branches?"
-msgstr "Восстановить удаленные ветки сложно.\n\nПродолжить?"
+msgid "push %s"
+msgstr "отправить %s"
-#: lib/branch_delete.tcl:141
+#: lib/transport.tcl:55
#, tcl-format
-msgid ""
-"Failed to delete branches:\n"
-"%s"
-msgstr "Не удалось удалить ветки:\n%s"
+msgid "Pushing changes to %s"
+msgstr "Отправка изменений в %s "
-#: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22
-msgid "Rename Branch"
-msgstr "Переименование ветки"
+#: lib/transport.tcl:93
+#, tcl-format
+msgid "Mirroring to %s"
+msgstr "Точное копирование в %s"
-#: lib/branch_rename.tcl:26
-msgid "Rename"
-msgstr "Переименовать"
+#: lib/transport.tcl:111
+#, tcl-format
+msgid "Pushing %s %s to %s"
+msgstr "Отправка %s %s в %s"
-#: lib/branch_rename.tcl:36
-msgid "Branch:"
-msgstr "Ветка:"
+#: lib/transport.tcl:132
+msgid "Push Branches"
+msgstr "Отправить ветки"
-#: lib/branch_rename.tcl:39
-msgid "New Name:"
-msgstr "Новое название:"
+#: lib/transport.tcl:141 lib/checkout_op.tcl:580 lib/remote_add.tcl:34
+#: lib/browser.tcl:292 lib/branch_checkout.tcl:30 lib/branch_rename.tcl:32
+#: lib/choose_font.tcl:45 lib/option.tcl:127 lib/tools_dlg.tcl:41
+#: lib/tools_dlg.tcl:202 lib/tools_dlg.tcl:345 lib/remote_branch_delete.tcl:43
+#: lib/branch_create.tcl:37 lib/branch_delete.tcl:34 lib/merge.tcl:178
+msgid "Cancel"
+msgstr "Отмена"
-#: lib/branch_rename.tcl:75
-msgid "Please select a branch to rename."
-msgstr "Укажите ветку для переименования."
+#: lib/transport.tcl:147
+msgid "Source Branches"
+msgstr "Исходные ветки"
-#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:202
-#, tcl-format
-msgid "Branch '%s' already exists."
-msgstr "Ветка «%s» уже существует."
+#: lib/transport.tcl:162
+msgid "Destination Repository"
+msgstr "Репозиторий назначения"
-#: lib/branch_rename.tcl:117
-#, tcl-format
-msgid "Failed to rename '%s'."
-msgstr "Не удалось переименовать «%s». "
+#: lib/transport.tcl:165 lib/remote_branch_delete.tcl:51
+msgid "Remote:"
+msgstr "внешний:"
-#: lib/browser.tcl:17
-msgid "Starting..."
-msgstr "Запуск…"
+#: lib/transport.tcl:187 lib/remote_branch_delete.tcl:72
+msgid "Arbitrary Location:"
+msgstr "Указанное положение:"
-#: lib/browser.tcl:26
-msgid "File Browser"
-msgstr "Просмотр списка файлов"
+#: lib/transport.tcl:205
+msgid "Transfer Options"
+msgstr "Настройки отправки"
-#: lib/browser.tcl:126 lib/browser.tcl:143
-#, tcl-format
-msgid "Loading %s..."
-msgstr "Загрузка %s…"
+#: lib/transport.tcl:207
+msgid "Force overwrite existing branch (may discard changes)"
+msgstr "Принудительно перезаписать существующую ветку (возможна потеря изменений)"
-#: lib/browser.tcl:187
-msgid "[Up To Parent]"
-msgstr "[На уровень выше]"
+#: lib/transport.tcl:211
+msgid "Use thin pack (for slow network connections)"
+msgstr "Использовать thin pack (для медленных сетевых подключений)"
-#: lib/browser.tcl:267 lib/browser.tcl:273
-msgid "Browse Branch Files"
-msgstr "Показать файлы ветки"
+#: lib/transport.tcl:215
+msgid "Include tags"
+msgstr "Передать метки"
-#: lib/browser.tcl:278 lib/choose_repository.tcl:398
-#: lib/choose_repository.tcl:486 lib/choose_repository.tcl:497
-#: lib/choose_repository.tcl:1028
-msgid "Browse"
-msgstr "Показать"
+#: lib/transport.tcl:229
+#, tcl-format
+msgid "%s (%s): Push"
+msgstr "%s (%s): Отправка"
#: lib/checkout_op.tcl:85
#, tcl-format
@@ -865,8 +750,8 @@ msgstr "Извлечение %s из %s "
msgid "fatal: Cannot resolve %s"
msgstr "критическая ошибка: невозможно разрешить %s"
-#: lib/checkout_op.tcl:146 lib/console.tcl:81 lib/database.tcl:31
-#: lib/sshkey.tcl:53
+#: lib/checkout_op.tcl:146 lib/sshkey.tcl:58 lib/console.tcl:81
+#: lib/database.tcl:30
msgid "Close"
msgstr "Закрыть"
@@ -880,6 +765,11 @@ msgstr "Ветка «%s» не существует."
msgid "Failed to configure simplified git-pull for '%s'."
msgstr "Ошибка создания упрощённой конфигурации git pull для «%s»."
+#: lib/checkout_op.tcl:202 lib/branch_rename.tcl:102
+#, tcl-format
+msgid "Branch '%s' already exists."
+msgstr "Ветка «%s» уже существует."
+
#: lib/checkout_op.tcl:229
#, tcl-format
msgid ""
@@ -921,51 +811,55 @@ msgstr "Обновление рабочего каталога из «%s»…"
msgid "files checked out"
msgstr "файлы извлечены"
-#: lib/checkout_op.tcl:376
+#: lib/checkout_op.tcl:377
#, tcl-format
msgid "Aborted checkout of '%s' (file level merging is required)."
msgstr "Прерван переход на «%s» (требуется слияние содержимого файлов)"
-#: lib/checkout_op.tcl:377
+#: lib/checkout_op.tcl:378
msgid "File level merge required."
msgstr "Требуется слияние содержания файлов."
-#: lib/checkout_op.tcl:381
+#: lib/checkout_op.tcl:382
#, tcl-format
msgid "Staying on branch '%s'."
msgstr "Ветка «%s» остаётся текущей."
-#: lib/checkout_op.tcl:452
+#: lib/checkout_op.tcl:453
msgid ""
"You are no longer on a local branch.\n"
"\n"
"If you wanted to be on a branch, create one now starting from 'This Detached Checkout'."
msgstr "Вы более не находитесь на локальной ветке.\n\nЕсли вы хотите снова вернуться к какой-нибудь ветке, создайте её сейчас, начиная с «Текущего отсоединенного состояния»."
-#: 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 "Выполнен переход на «%s»."
-#: lib/checkout_op.tcl:535
+#: lib/checkout_op.tcl:536
#, tcl-format
msgid "Resetting '%s' to '%s' will lose the following commits:"
msgstr "Сброс «%s» на «%s» приведет к потере следующих коммитов:"
-#: lib/checkout_op.tcl:557
+#: lib/checkout_op.tcl:558
msgid "Recovering lost commits may not be easy."
msgstr "Восстановить потерянные коммиты будет сложно."
-#: lib/checkout_op.tcl:562
+#: lib/checkout_op.tcl:563
#, tcl-format
msgid "Reset '%s'?"
msgstr "Сбросить «%s»?"
-#: lib/checkout_op.tcl:567 lib/merge.tcl:164 lib/tools_dlg.tcl:343
+#: lib/checkout_op.tcl:568 lib/tools_dlg.tcl:336 lib/merge.tcl:170
msgid "Visualize"
msgstr "Наглядно"
-#: lib/checkout_op.tcl:635
+#: lib/checkout_op.tcl:572 lib/branch_create.tcl:85
+msgid "Reset"
+msgstr "Сброс"
+
+#: lib/checkout_op.tcl:636
#, tcl-format
msgid ""
"Failed to set current branch.\n"
@@ -975,256 +869,1384 @@ msgid ""
"This should not have occurred. %s will now close and give up."
msgstr "Не удалось установить текущую ветку.\n\nВаш рабочий каталог обновлён только частично. Были обновлены все файлы кроме служебных файлов Git. \n\nЭтого не должно было произойти. %s завершается."
-#: lib/choose_font.tcl:39
+#: lib/remote_add.tcl:20
+#, tcl-format
+msgid "%s (%s): Add Remote"
+msgstr "%s (%s): Добавление внешнего репозитория"
+
+#: lib/remote_add.tcl:25
+msgid "Add New Remote"
+msgstr "Добавить внешний репозиторий"
+
+#: lib/remote_add.tcl:30 lib/tools_dlg.tcl:37
+msgid "Add"
+msgstr "Добавить"
+
+#: lib/remote_add.tcl:39
+msgid "Remote Details"
+msgstr "Информация о внешнем репозитории"
+
+#: lib/remote_add.tcl:41 lib/tools_dlg.tcl:51 lib/branch_create.tcl:44
+msgid "Name:"
+msgstr "Название:"
+
+#: lib/remote_add.tcl:50
+msgid "Location:"
+msgstr "Положение:"
+
+#: lib/remote_add.tcl:60
+msgid "Further Action"
+msgstr "Следующая операция"
+
+#: lib/remote_add.tcl:63
+msgid "Fetch Immediately"
+msgstr "Сразу извлечь изменения"
+
+#: lib/remote_add.tcl:69
+msgid "Initialize Remote Repository and Push"
+msgstr "Инициализировать внешний репозиторий и отправить"
+
+#: lib/remote_add.tcl:75
+msgid "Do Nothing Else Now"
+msgstr "Больше ничего не делать"
+
+#: lib/remote_add.tcl:100
+msgid "Please supply a remote name."
+msgstr "Укажите название внешнего репозитория."
+
+#: lib/remote_add.tcl:113
+#, tcl-format
+msgid "'%s' is not an acceptable remote name."
+msgstr "«%s» не является допустимым именем внешнего репозитория."
+
+#: lib/remote_add.tcl:124
+#, tcl-format
+msgid "Failed to add remote '%s' of location '%s'."
+msgstr "Не удалось добавить «%s» из «%s». "
+
+#: lib/remote_add.tcl:133
+#, tcl-format
+msgid "Fetching the %s"
+msgstr "Извлечение %s"
+
+#: lib/remote_add.tcl:156
+#, tcl-format
+msgid "Do not know how to initialize repository at location '%s'."
+msgstr "Невозможно инициализировать репозиторий в «%s»."
+
+#: lib/remote_add.tcl:163
+#, tcl-format
+msgid "Setting up the %s (at %s)"
+msgstr "Настройка %s (в %s)"
+
+#: lib/browser.tcl:17
+msgid "Starting..."
+msgstr "Запуск…"
+
+#: lib/browser.tcl:27
+#, tcl-format
+msgid "%s (%s): File Browser"
+msgstr "%s (%s): Просмотр списка файлов"
+
+#: lib/browser.tcl:132 lib/browser.tcl:149
+#, tcl-format
+msgid "Loading %s..."
+msgstr "Загрузка %s…"
+
+#: lib/browser.tcl:193
+msgid "[Up To Parent]"
+msgstr "[На уровень выше]"
+
+#: lib/browser.tcl:275
+#, tcl-format
+msgid "%s (%s): Browse Branch Files"
+msgstr "%s (%s): Просмотр файлов ветки"
+
+#: lib/browser.tcl:282
+msgid "Browse Branch Files"
+msgstr "Показать файлы ветки"
+
+#: lib/browser.tcl:288 lib/choose_repository.tcl:437
+#: lib/choose_repository.tcl:524 lib/choose_repository.tcl:533
+#: lib/choose_repository.tcl:1115
+msgid "Browse"
+msgstr "Показать"
+
+#: lib/browser.tcl:297 lib/branch_checkout.tcl:35 lib/tools_dlg.tcl:321
+msgid "Revision"
+msgstr "Версия"
+
+#: lib/index.tcl:6
+msgid "Unable to unlock the index."
+msgstr "Не удалось разблокировать индекс"
+
+#: lib/index.tcl:30
+msgid "Index Error"
+msgstr "Ошибка в индексе"
+
+#: lib/index.tcl:32
+msgid ""
+"Updating the Git index failed. A rescan will be automatically started to "
+"resynchronize git-gui."
+msgstr "Не удалось обновить индекс Git. Состояние репозитория будет перечитано автоматически."
+
+#: lib/index.tcl:43
+msgid "Continue"
+msgstr "Продолжить"
+
+#: lib/index.tcl:46
+msgid "Unlock Index"
+msgstr "Разблокировать индекс"
+
+#: lib/index.tcl:77 lib/index.tcl:146 lib/index.tcl:220 lib/index.tcl:587
+#: lib/choose_repository.tcl:999
+msgid "files"
+msgstr "файлов"
+
+#: lib/index.tcl:326
+msgid "Unstaging selected files from commit"
+msgstr "Уборка выбранных файлов из индекса"
+
+#: lib/index.tcl:330
+#, tcl-format
+msgid "Unstaging %s from commit"
+msgstr "Удаление %s из индекса"
+
+#: lib/index.tcl:369
+msgid "Ready to commit."
+msgstr "Готов для коммита."
+
+#: lib/index.tcl:378
+msgid "Adding selected files"
+msgstr "Добавление выбранных файлов"
+
+#: lib/index.tcl:382
+#, tcl-format
+msgid "Adding %s"
+msgstr "Добавление %s…"
+
+#: lib/index.tcl:412
+#, tcl-format
+msgid "Stage %d untracked files?"
+msgstr "Проиндексировать %d неотслеживаемые файла?"
+
+#: lib/index.tcl:420
+msgid "Adding all changed files"
+msgstr "Добавление всех измененных файлов"
+
+#: lib/index.tcl:503
+#, tcl-format
+msgid "Revert changes in file %s?"
+msgstr "Обратить изменения в файле %s?"
+
+#: lib/index.tcl:508
+#, tcl-format
+msgid "Revert changes in these %i files?"
+msgstr "Обратить изменения в %i файле(-ах)?"
+
+#: lib/index.tcl:517
+msgid "Any unstaged changes will be permanently lost by the revert."
+msgstr "Любые непроиндексированные изменения, будут потеряны при обращении изменений."
+
+#: lib/index.tcl:520 lib/index.tcl:563
+msgid "Do Nothing"
+msgstr "Ничего не делать"
+
+#: lib/index.tcl:545
+#, tcl-format
+msgid "Delete untracked file %s?"
+msgstr "Удалить неотслеживаемый файл %s?"
+
+#: lib/index.tcl:550
+#, tcl-format
+msgid "Delete these %i untracked files?"
+msgstr "Удалить %i неотслеживаемые файла?"
+
+#: lib/index.tcl:560
+msgid "Files will be permanently deleted."
+msgstr "Файлы будут удалены навсегда."
+
+#: lib/index.tcl:564
+msgid "Delete Files"
+msgstr "Удалить файлы"
+
+#: lib/index.tcl:586
+msgid "Deleting"
+msgstr "Удаление"
+
+#: lib/index.tcl:665
+msgid "Encountered errors deleting files:\n"
+msgstr "Возникшие ошибки при удалении файлов:\n"
+
+#: lib/index.tcl:674
+#, tcl-format
+msgid "None of the %d selected files could be deleted."
+msgstr "Не удалось удалить ни один из выбранных %d файлов."
+
+#: lib/index.tcl:679
+#, tcl-format
+msgid "%d of the %d selected files could not be deleted."
+msgstr "Не удалось удалить %d из выбранных %d файлов."
+
+#: lib/index.tcl:726
+msgid "Reverting selected files"
+msgstr "Обращение изменений в выбранных файлах"
+
+#: lib/index.tcl:730
+#, tcl-format
+msgid "Reverting %s"
+msgstr "Обращение изменений в %s"
+
+#: lib/branch_checkout.tcl:16
+#, tcl-format
+msgid "%s (%s): Checkout Branch"
+msgstr "%s (%s): Переход на ветку"
+
+#: lib/branch_checkout.tcl:21
+msgid "Checkout Branch"
+msgstr "Перейти на ветку"
+
+#: lib/branch_checkout.tcl:26
+msgid "Checkout"
+msgstr "Перейти"
+
+#: lib/branch_checkout.tcl:39 lib/option.tcl:310 lib/branch_create.tcl:69
+msgid "Options"
+msgstr "Настройки"
+
+#: lib/branch_checkout.tcl:42 lib/branch_create.tcl:92
+msgid "Fetch Tracking Branch"
+msgstr "Извлечь изменения из внешней ветки"
+
+#: lib/branch_checkout.tcl:47
+msgid "Detach From Local Branch"
+msgstr "Отсоединить от локальной ветки"
+
+#: lib/status_bar.tcl:263
+#, tcl-format
+msgid "%s ... %*i of %*i %s (%3i%%)"
+msgstr "%s … %*i из %*i %s (%3i%%)"
+
+#: lib/remote.tcl:200
+msgid "Push to"
+msgstr "Отправить"
+
+#: lib/remote.tcl:218
+msgid "Remove Remote"
+msgstr "Удалить ссылку на внешний репозиторий"
+
+#: lib/remote.tcl:223
+msgid "Prune from"
+msgstr "Чистка"
+
+#: lib/remote.tcl:228
+msgid "Fetch from"
+msgstr "Извлечение из"
+
+#: lib/remote.tcl:249 lib/remote.tcl:253 lib/remote.tcl:258 lib/remote.tcl:264
+msgid "All"
+msgstr "Все"
+
+#: lib/branch_rename.tcl:15
+#, tcl-format
+msgid "%s (%s): Rename Branch"
+msgstr "%s (%s): Переименовать ветку"
+
+#: lib/branch_rename.tcl:23
+msgid "Rename Branch"
+msgstr "Переименование ветки"
+
+#: lib/branch_rename.tcl:28
+msgid "Rename"
+msgstr "Переименовать"
+
+#: lib/branch_rename.tcl:38
+msgid "Branch:"
+msgstr "Ветка:"
+
+#: lib/branch_rename.tcl:46
+msgid "New Name:"
+msgstr "Новое название:"
+
+#: lib/branch_rename.tcl:81
+msgid "Please select a branch to rename."
+msgstr "Укажите ветку для переименования."
+
+#: lib/branch_rename.tcl:92 lib/branch_create.tcl:154
+msgid "Please supply a branch name."
+msgstr "Укажите имя ветки."
+
+#: lib/branch_rename.tcl:112 lib/branch_create.tcl:165
+#, tcl-format
+msgid "'%s' is not an acceptable branch name."
+msgstr "Недопустимое имя ветки «%s»."
+
+#: lib/branch_rename.tcl:123
+#, tcl-format
+msgid "Failed to rename '%s'."
+msgstr "Не удалось переименовать «%s». "
+
+#: lib/choose_font.tcl:41
msgid "Select"
msgstr "Выбрать"
-#: lib/choose_font.tcl:53
+#: lib/choose_font.tcl:55
msgid "Font Family"
msgstr "Шрифт"
-#: lib/choose_font.tcl:74
+#: lib/choose_font.tcl:76
msgid "Font Size"
msgstr "Размер шрифта"
-#: lib/choose_font.tcl:91
+#: lib/choose_font.tcl:93
msgid "Font Example"
msgstr "Пример текста"
-#: lib/choose_font.tcl:103
+#: lib/choose_font.tcl:105
msgid ""
"This is example text.\n"
"If you like this text, it can be your font."
msgstr "Это пример текста.\nЕсли Вам нравится этот текст, это может быть Ваш шрифт."
-#: lib/choose_repository.tcl:28
+#: lib/option.tcl:11
+#, tcl-format
+msgid "Invalid global encoding '%s'"
+msgstr "Неверная глобальная кодировка «%s»"
+
+#: lib/option.tcl:19
+#, tcl-format
+msgid "Invalid repo encoding '%s'"
+msgstr "Неверная кодировка репозитория «%s»"
+
+#: lib/option.tcl:119
+msgid "Restore Defaults"
+msgstr "Восстановить настройки по умолчанию"
+
+#: lib/option.tcl:123
+msgid "Save"
+msgstr "Сохранить"
+
+#: lib/option.tcl:133
+#, tcl-format
+msgid "%s Repository"
+msgstr "Для репозитория %s"
+
+#: lib/option.tcl:134
+msgid "Global (All Repositories)"
+msgstr "Общие (для всех репозиториев)"
+
+#: lib/option.tcl:140
+msgid "User Name"
+msgstr "Имя пользователя"
+
+#: lib/option.tcl:141
+msgid "Email Address"
+msgstr "Адрес электронной почты"
+
+#: lib/option.tcl:143
+msgid "Summarize Merge Commits"
+msgstr "Суммарное сообщение при слиянии"
+
+#: lib/option.tcl:144
+msgid "Merge Verbosity"
+msgstr "Уровень детальности сообщений при слиянии"
+
+#: lib/option.tcl:145
+msgid "Show Diffstat After Merge"
+msgstr "Показать отчет об изменениях после слияния"
+
+#: lib/option.tcl:146
+msgid "Use Merge Tool"
+msgstr "Использовать для слияния программу"
+
+#: lib/option.tcl:148
+msgid "Trust File Modification Timestamps"
+msgstr "Доверять времени модификации файла"
+
+#: lib/option.tcl:149
+msgid "Prune Tracking Branches During Fetch"
+msgstr "Чистка отслеживаемых веток при извлечении изменений"
+
+#: lib/option.tcl:150
+msgid "Match Tracking Branches"
+msgstr "Такое же имя, как и у отслеживаемой ветки"
+
+#: lib/option.tcl:151
+msgid "Use Textconv For Diffs and Blames"
+msgstr "Использовать Textconv для просмотра различий и авторства"
+
+#: lib/option.tcl:152
+msgid "Blame Copy Only On Changed Files"
+msgstr "Поиск копий только в изменённых файлах"
+
+#: lib/option.tcl:153
+msgid "Maximum Length of Recent Repositories List"
+msgstr "Максимальная длинна списка недавних репозиториев"
+
+#: lib/option.tcl:154
+msgid "Minimum Letters To Blame Copy On"
+msgstr "Минимальное количество символов для поиска копий"
+
+#: lib/option.tcl:155
+msgid "Blame History Context Radius (days)"
+msgstr "Радиус исторического контекста (в днях)"
+
+#: lib/option.tcl:156
+msgid "Number of Diff Context Lines"
+msgstr "Число строк в контексте diff"
+
+#: lib/option.tcl:157
+msgid "Additional Diff Parameters"
+msgstr "Дополнительные параметры для diff"
+
+#: lib/option.tcl:158
+msgid "Commit Message Text Width"
+msgstr "Ширина текста сообщения коммита"
+
+#: lib/option.tcl:159
+msgid "New Branch Name Template"
+msgstr "Шаблон для имени новой ветки"
+
+#: lib/option.tcl:160
+msgid "Default File Contents Encoding"
+msgstr "Кодировка содержания файла по умолчанию"
+
+#: lib/option.tcl:161
+msgid "Warn before committing to a detached head"
+msgstr "Предупреждать перед коммитом в отделённый HEAD"
+
+#: lib/option.tcl:162
+msgid "Staging of untracked files"
+msgstr "Индексирование неотслеживаемых файлов"
+
+#: lib/option.tcl:163
+msgid "Show untracked files"
+msgstr "Показать неотслеживаемые файлы"
+
+#: lib/option.tcl:164
+msgid "Tab spacing"
+msgstr "Ширина табуляции"
+
+#: lib/option.tcl:182 lib/option.tcl:197 lib/option.tcl:220 lib/option.tcl:282
+#: lib/database.tcl:57
+#, tcl-format
+msgid "%s:"
+msgstr "%s:"
+
+#: lib/option.tcl:210
+msgid "Change"
+msgstr "Изменить"
+
+#: lib/option.tcl:254
+msgid "Spelling Dictionary:"
+msgstr "Словарь для проверки правописания:"
+
+#: lib/option.tcl:284
+msgid "Change Font"
+msgstr "Изменить"
+
+#: lib/option.tcl:288
+#, tcl-format
+msgid "Choose %s"
+msgstr "Выберите %s"
+
+#: lib/option.tcl:294
+msgid "pt."
+msgstr "п."
+
+#: lib/option.tcl:308
+msgid "Preferences"
+msgstr "Настройки"
+
+#: lib/option.tcl:345
+msgid "Failed to completely save options:"
+msgstr "Не удалось полностью сохранить настройки:"
+
+#: lib/encoding.tcl:443
+msgid "Default"
+msgstr "По умолчанию"
+
+#: lib/encoding.tcl:448
+#, tcl-format
+msgid "System (%s)"
+msgstr "Системная (%s)"
+
+#: lib/encoding.tcl:459 lib/encoding.tcl:465
+msgid "Other"
+msgstr "Другая"
+
+#: lib/tools.tcl:76
+#, tcl-format
+msgid "Running %s requires a selected file."
+msgstr "Запуск %s требует выбранного файла."
+
+#: lib/tools.tcl:92
+#, tcl-format
+msgid "Are you sure you want to run %1$s on file \"%2$s\"?"
+msgstr "Вы действительно хотите выполнить %1$s на «%2$s»?"
+
+#: lib/tools.tcl:96
+#, tcl-format
+msgid "Are you sure you want to run %s?"
+msgstr "Действительно запустить %s?"
+
+#: lib/tools.tcl:118
+#, tcl-format
+msgid "Tool: %s"
+msgstr "Вспомогательная операция: %s"
+
+#: lib/tools.tcl:119
+#, tcl-format
+msgid "Running: %s"
+msgstr "Выполнение: %s"
+
+#: lib/tools.tcl:158
+#, tcl-format
+msgid "Tool completed successfully: %s"
+msgstr "Программа %s завершилась успешно."
+
+#: lib/tools.tcl:160
+#, tcl-format
+msgid "Tool failed: %s"
+msgstr "Ошибка выполнения программы: %s"
+
+#: lib/mergetool.tcl:8
+msgid "Force resolution to the base version?"
+msgstr "Использовать базовую версию для разрешения конфликта?"
+
+#: lib/mergetool.tcl:9
+msgid "Force resolution to this branch?"
+msgstr "Использовать версию из этой ветки для разрешения конфликта?"
+
+#: lib/mergetool.tcl:10
+msgid "Force resolution to the other branch?"
+msgstr "Использовать версию из другой ветки для разрешения конфликта?"
+
+#: lib/mergetool.tcl:14
+#, tcl-format
+msgid ""
+"Note that the diff shows only conflicting changes.\n"
+"\n"
+"%s will be overwritten.\n"
+"\n"
+"This operation can be undone only by restarting the merge."
+msgstr "Внимание! Список изменений показывает только конфликтующие отличия.\n\n%s будет переписан.\n\nЭто действие можно отменить только перезапуском операции слияния."
+
+#: lib/mergetool.tcl:45
+#, tcl-format
+msgid "File %s seems to have unresolved conflicts, still stage?"
+msgstr "Похоже, что файл %s содержит неразрешенные конфликты. Продолжить индексацию?"
+
+#: lib/mergetool.tcl:60
+#, tcl-format
+msgid "Adding resolution for %s"
+msgstr "Добавляю результат разрешения для %s"
+
+#: lib/mergetool.tcl:141
+msgid "Cannot resolve deletion or link conflicts using a tool"
+msgstr "Программа слияния не обрабатывает конфликты с удалением или участием ссылок"
+
+#: lib/mergetool.tcl:146
+msgid "Conflict file does not exist"
+msgstr "Конфликтующий файл не существует"
+
+#: lib/mergetool.tcl:246
+#, tcl-format
+msgid "Not a GUI merge tool: '%s'"
+msgstr "«%s» не является программой слияния"
+
+#: lib/mergetool.tcl:275
+#, tcl-format
+msgid "Unsupported merge tool '%s'"
+msgstr "Неподдерживаемая программа слияния «%s»"
+
+#: lib/mergetool.tcl:310
+msgid "Merge tool is already running, terminate it?"
+msgstr "Программа слияния уже работает. Прервать?"
+
+#: lib/mergetool.tcl:330
+#, tcl-format
+msgid ""
+"Error retrieving versions:\n"
+"%s"
+msgstr "Ошибка получения версий:\n%s"
+
+#: lib/mergetool.tcl:350
+#, tcl-format
+msgid ""
+"Could not start the merge tool:\n"
+"\n"
+"%s"
+msgstr "Ошибка запуска программы слияния:\n\n%s"
+
+#: lib/mergetool.tcl:354
+msgid "Running merge tool..."
+msgstr "Запуск программы слияния…"
+
+#: lib/mergetool.tcl:382 lib/mergetool.tcl:390
+msgid "Merge tool failed."
+msgstr "Ошибка выполнения программы слияния."
+
+#: lib/tools_dlg.tcl:22
+#, tcl-format
+msgid "%s (%s): Add Tool"
+msgstr "%s (%s): Добавить инструмент"
+
+#: lib/tools_dlg.tcl:28
+msgid "Add New Tool Command"
+msgstr "Новая вспомогательная операция"
+
+#: lib/tools_dlg.tcl:34
+msgid "Add globally"
+msgstr "Добавить для всех репозиториев"
+
+#: lib/tools_dlg.tcl:46
+msgid "Tool Details"
+msgstr "Описание вспомогательной операции"
+
+#: lib/tools_dlg.tcl:49
+msgid "Use '/' separators to create a submenu tree:"
+msgstr "Используйте «/» для создания подменю"
+
+#: lib/tools_dlg.tcl:60
+msgid "Command:"
+msgstr "Команда:"
+
+#: lib/tools_dlg.tcl:71
+msgid "Show a dialog before running"
+msgstr "Показать диалог перед запуском"
+
+#: lib/tools_dlg.tcl:77
+msgid "Ask the user to select a revision (sets $REVISION)"
+msgstr "Запрос на выбор версии (устанавливает $REVISION)"
+
+#: lib/tools_dlg.tcl:82
+msgid "Ask the user for additional arguments (sets $ARGS)"
+msgstr "Запрос дополнительных аргументов (устанавливает $ARGS)"
+
+#: lib/tools_dlg.tcl:89
+msgid "Don't show the command output window"
+msgstr "Не показывать окно вывода команды"
+
+#: lib/tools_dlg.tcl:94
+msgid "Run only if a diff is selected ($FILENAME not empty)"
+msgstr "Запуск только если показан список изменений ($FILENAME не пусто)"
+
+#: lib/tools_dlg.tcl:118
+msgid "Please supply a name for the tool."
+msgstr "Укажите название вспомогательной операции."
+
+#: lib/tools_dlg.tcl:126
+#, tcl-format
+msgid "Tool '%s' already exists."
+msgstr "Вспомогательная операция «%s» уже существует."
+
+#: lib/tools_dlg.tcl:148
+#, tcl-format
+msgid ""
+"Could not add tool:\n"
+"%s"
+msgstr "Ошибка добавления программы:\n%s"
+
+#: lib/tools_dlg.tcl:187
+#, tcl-format
+msgid "%s (%s): Remove Tool"
+msgstr "%s (%s): Удалить инструмент"
+
+#: lib/tools_dlg.tcl:193
+msgid "Remove Tool Commands"
+msgstr "Удалить команды программы"
+
+#: lib/tools_dlg.tcl:198
+msgid "Remove"
+msgstr "Удалить"
+
+#: lib/tools_dlg.tcl:231
+msgid "(Blue denotes repository-local tools)"
+msgstr "(Синим выделены программы локальные репозиторию)"
+
+#: lib/tools_dlg.tcl:283
+#, tcl-format
+msgid "%s (%s):"
+msgstr "%s (%s):"
+
+#: lib/tools_dlg.tcl:292
+#, tcl-format
+msgid "Run Command: %s"
+msgstr "Запуск команды: %s"
+
+#: lib/tools_dlg.tcl:306
+msgid "Arguments"
+msgstr "Аргументы"
+
+#: lib/tools_dlg.tcl:341
+msgid "OK"
+msgstr "OK"
+
+#: lib/search.tcl:48
+msgid "Find:"
+msgstr "Поиск:"
+
+#: lib/search.tcl:50
+msgid "Next"
+msgstr "Дальше"
+
+#: lib/search.tcl:51
+msgid "Prev"
+msgstr "Обратно"
+
+#: lib/search.tcl:52
+msgid "RegExp"
+msgstr "Регулярные выражения"
+
+#: lib/search.tcl:54
+msgid "Case"
+msgstr "Учёт регистра"
+
+#: lib/shortcut.tcl:8 lib/shortcut.tcl:43 lib/shortcut.tcl:75
+#, tcl-format
+msgid "%s (%s): Create Desktop Icon"
+msgstr "%s (%s): Создать ярлык на рабочем столе"
+
+#: lib/shortcut.tcl:24 lib/shortcut.tcl:65
+msgid "Cannot write shortcut:"
+msgstr "Невозможно записать ссылку:"
+
+#: lib/shortcut.tcl:140
+msgid "Cannot write icon:"
+msgstr "Невозможно записать значок:"
+
+#: lib/remote_branch_delete.tcl:29
+#, tcl-format
+msgid "%s (%s): Delete Branch Remotely"
+msgstr "%s (%s): Удаление внешней ветки"
+
+#: lib/remote_branch_delete.tcl:34
+msgid "Delete Branch Remotely"
+msgstr "Удаление ветки во внешнем репозитории"
+
+#: lib/remote_branch_delete.tcl:48
+msgid "From Repository"
+msgstr "Из репозитория"
+
+#: lib/remote_branch_delete.tcl:88
+msgid "Branches"
+msgstr "Ветки"
+
+#: lib/remote_branch_delete.tcl:110
+msgid "Delete Only If"
+msgstr "Удалить только в случае, если"
+
+#: lib/remote_branch_delete.tcl:112
+msgid "Merged Into:"
+msgstr "Слияние с:"
+
+#: lib/remote_branch_delete.tcl:120 lib/branch_delete.tcl:53
+msgid "Always (Do not perform merge checks)"
+msgstr "Всегда (не выполнять проверку на слияние)"
+
+#: lib/remote_branch_delete.tcl:153
+msgid "A branch is required for 'Merged Into'."
+msgstr "Для операции «Слияние с» требуется указать ветку."
+
+#: lib/remote_branch_delete.tcl:185
+#, tcl-format
+msgid ""
+"The following branches are not completely merged into %s:\n"
+"\n"
+" - %s"
+msgstr "Следующие ветки могут быть объединены с %s при помощи операции слияния:\n\n - %s"
+
+#: lib/remote_branch_delete.tcl:190
+#, tcl-format
+msgid ""
+"One or more of the merge tests failed because you have not fetched the "
+"necessary commits. Try fetching from %s first."
+msgstr "Некоторые тесты на слияние не прошли, потому что вы не извлекли необходимые коммиты. Попытайтесь извлечь их из %s."
+
+#: lib/remote_branch_delete.tcl:208
+msgid "Please select one or more branches to delete."
+msgstr "Укажите одну или несколько веток для удаления."
+
+#: lib/remote_branch_delete.tcl:218 lib/branch_delete.tcl:115
+msgid ""
+"Recovering deleted branches is difficult.\n"
+"\n"
+"Delete the selected branches?"
+msgstr "Восстановить удаленные ветки сложно.\n\nПродолжить?"
+
+#: lib/remote_branch_delete.tcl:227
+#, tcl-format
+msgid "Deleting branches from %s"
+msgstr "Удаление веток из %s"
+
+#: lib/remote_branch_delete.tcl:300
+msgid "No repository selected."
+msgstr "Не указан репозиторий."
+
+#: lib/remote_branch_delete.tcl:305
+#, tcl-format
+msgid "Scanning %s..."
+msgstr "Перечитывание %s…"
+
+#: lib/choose_repository.tcl:45
msgid "Git Gui"
msgstr "Git Gui"
-#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:386
+#: lib/choose_repository.tcl:104 lib/choose_repository.tcl:427
msgid "Create New Repository"
msgstr "Создать новый репозиторий"
-#: lib/choose_repository.tcl:93
+#: lib/choose_repository.tcl:110
msgid "New..."
msgstr "Новый…"
-#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:471
+#: lib/choose_repository.tcl:117 lib/choose_repository.tcl:511
msgid "Clone Existing Repository"
msgstr "Склонировать существующий репозиторий"
-#: lib/choose_repository.tcl:106
+#: lib/choose_repository.tcl:128
msgid "Clone..."
msgstr "Клонировать…"
-#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:1016
+#: lib/choose_repository.tcl:135 lib/choose_repository.tcl:1105
msgid "Open Existing Repository"
msgstr "Выбрать существующий репозиторий"
-#: lib/choose_repository.tcl:119
+#: lib/choose_repository.tcl:141
msgid "Open..."
msgstr "Открыть…"
-#: lib/choose_repository.tcl:132
+#: lib/choose_repository.tcl:154
msgid "Recent Repositories"
msgstr "Недавние репозитории"
-#: lib/choose_repository.tcl:138
+#: lib/choose_repository.tcl:164
msgid "Open Recent Repository:"
msgstr "Открыть последний репозиторий"
-#: lib/choose_repository.tcl:306 lib/choose_repository.tcl:313
-#: lib/choose_repository.tcl:320
+#: lib/choose_repository.tcl:331 lib/choose_repository.tcl:338
+#: lib/choose_repository.tcl:345
#, tcl-format
msgid "Failed to create repository %s:"
msgstr "Не удалось создать репозиторий %s:"
-#: lib/choose_repository.tcl:391
+#: lib/choose_repository.tcl:422 lib/branch_create.tcl:33
+msgid "Create"
+msgstr "Создать"
+
+#: lib/choose_repository.tcl:432
msgid "Directory:"
msgstr "Каталог:"
-#: lib/choose_repository.tcl:423 lib/choose_repository.tcl:550
-#: lib/choose_repository.tcl:1052
+#: lib/choose_repository.tcl:462 lib/choose_repository.tcl:588
+#: lib/choose_repository.tcl:1139
msgid "Git Repository"
msgstr "Репозиторий"
-#: lib/choose_repository.tcl:448
+#: lib/choose_repository.tcl:487
#, tcl-format
msgid "Directory %s already exists."
msgstr "Каталог '%s' уже существует."
-#: lib/choose_repository.tcl:452
+#: lib/choose_repository.tcl:491
#, tcl-format
msgid "File %s already exists."
msgstr "Файл '%s' уже существует."
-#: lib/choose_repository.tcl:466
+#: lib/choose_repository.tcl:506
msgid "Clone"
msgstr "Склонировать"
-#: lib/choose_repository.tcl:479
+#: lib/choose_repository.tcl:519
msgid "Source Location:"
msgstr "Исходное положение:"
-#: lib/choose_repository.tcl:490
+#: lib/choose_repository.tcl:528
msgid "Target Directory:"
msgstr "Каталог назначения:"
-#: lib/choose_repository.tcl:502
+#: lib/choose_repository.tcl:538
msgid "Clone Type:"
msgstr "Тип клона:"
-#: lib/choose_repository.tcl:508
+#: lib/choose_repository.tcl:543
msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
msgstr "Стандартный (Быстрый, полуизбыточный, «жесткие» ссылки)"
-#: lib/choose_repository.tcl:514
+#: lib/choose_repository.tcl:548
msgid "Full Copy (Slower, Redundant Backup)"
msgstr "Полная копия (Медленный, создает резервную копию)"
-#: lib/choose_repository.tcl:520
+#: lib/choose_repository.tcl:553
msgid "Shared (Fastest, Not Recommended, No Backup)"
msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)"
-#: lib/choose_repository.tcl:556 lib/choose_repository.tcl:603
-#: lib/choose_repository.tcl:749 lib/choose_repository.tcl:819
-#: lib/choose_repository.tcl:1058 lib/choose_repository.tcl:1066
+#: lib/choose_repository.tcl:560
+msgid "Recursively clone submodules too"
+msgstr "Также рекурсивно клонировать подмодули"
+
+#: lib/choose_repository.tcl:594 lib/choose_repository.tcl:641
+#: lib/choose_repository.tcl:790 lib/choose_repository.tcl:864
+#: lib/choose_repository.tcl:1145 lib/choose_repository.tcl:1153
#, tcl-format
msgid "Not a Git repository: %s"
-msgstr "Каталог не является репозиторием: %s"
+msgstr "Каталог не является репозиторием Git: %s"
-#: lib/choose_repository.tcl:592
+#: lib/choose_repository.tcl:630
msgid "Standard only available for local repository."
msgstr "Стандартный клон возможен только для локального репозитория."
-#: lib/choose_repository.tcl:596
+#: lib/choose_repository.tcl:634
msgid "Shared only available for local repository."
msgstr "Общий клон возможен только для локального репозитория."
-#: lib/choose_repository.tcl:617
+#: lib/choose_repository.tcl:655
#, tcl-format
msgid "Location %s already exists."
-msgstr "Путь '%s' уже существует."
+msgstr "Путь %s уже существует."
-#: lib/choose_repository.tcl:628
+#: lib/choose_repository.tcl:666
msgid "Failed to configure origin"
-msgstr "Не могу сконфигурировать исходный репозиторий."
+msgstr "Не удалось сконфигурировать исходный репозиторий"
-#: lib/choose_repository.tcl:640
+#: lib/choose_repository.tcl:678
msgid "Counting objects"
-msgstr "Считаю объекты"
+msgstr "Подсчёт объектов"
-#: lib/choose_repository.tcl:641
+#: lib/choose_repository.tcl:679
msgid "buckets"
msgstr "блоки"
-#: lib/choose_repository.tcl:665
+#: lib/choose_repository.tcl:703
#, tcl-format
msgid "Unable to copy objects/info/alternates: %s"
-msgstr "Не могу скопировать objects/info/alternates: %s"
+msgstr "Не удалось скопировать objects/info/alternates: %s"
-#: lib/choose_repository.tcl:701
+#: lib/choose_repository.tcl:740
#, tcl-format
msgid "Nothing to clone from %s."
msgstr "Нечего клонировать с %s."
-#: lib/choose_repository.tcl:703 lib/choose_repository.tcl:917
-#: lib/choose_repository.tcl:929
+#: lib/choose_repository.tcl:742 lib/choose_repository.tcl:962
+#: lib/choose_repository.tcl:974
msgid "The 'master' branch has not been initialized."
-msgstr "Не инициализирована ветвь «master»."
+msgstr "Не инициализирована ветка «master»."
-#: lib/choose_repository.tcl:716
+#: lib/choose_repository.tcl:755
msgid "Hardlinks are unavailable. Falling back to copying."
-msgstr "«Жесткие ссылки» недоступны. Будет использовано копирование."
+msgstr "Жесткие ссылки недоступны. Будет использовано копирование."
-#: lib/choose_repository.tcl:728
+#: lib/choose_repository.tcl:769
#, tcl-format
msgid "Cloning from %s"
-msgstr "Клонирование %s"
+msgstr "Клонирование из %s"
-#: lib/choose_repository.tcl:759
+#: lib/choose_repository.tcl:800
msgid "Copying objects"
-msgstr "Копирование objects"
+msgstr "Копирование объектов"
-#: lib/choose_repository.tcl:760
+#: lib/choose_repository.tcl:801
msgid "KiB"
msgstr "КБ"
-#: lib/choose_repository.tcl:784
+#: lib/choose_repository.tcl:825
#, tcl-format
msgid "Unable to copy object: %s"
msgstr "Не могу скопировать объект: %s"
-#: lib/choose_repository.tcl:794
+#: lib/choose_repository.tcl:837
msgid "Linking objects"
msgstr "Создание ссылок на objects"
-#: lib/choose_repository.tcl:795
+#: lib/choose_repository.tcl:838
msgid "objects"
msgstr "объекты"
-#: lib/choose_repository.tcl:803
+#: lib/choose_repository.tcl:846
#, tcl-format
msgid "Unable to hardlink object: %s"
msgstr "Не могу создать «жесткую ссылку» на объект: %s"
-#: lib/choose_repository.tcl:858
+#: lib/choose_repository.tcl:903
msgid "Cannot fetch branches and objects. See console output for details."
msgstr "Не удалось извлечь ветки и объекты. Дополнительная информация на консоли."
-#: lib/choose_repository.tcl:869
+#: lib/choose_repository.tcl:914
msgid "Cannot fetch tags. See console output for details."
msgstr "Не удалось извлечь метки. Дополнительная информация на консоли."
-#: lib/choose_repository.tcl:893
+#: lib/choose_repository.tcl:938
msgid "Cannot determine HEAD. See console output for details."
msgstr "Не могу определить HEAD. Дополнительная информация на консоли."
-#: lib/choose_repository.tcl:902
+#: lib/choose_repository.tcl:947
#, tcl-format
msgid "Unable to cleanup %s"
msgstr "Не могу очистить %s"
-#: lib/choose_repository.tcl:908
+#: lib/choose_repository.tcl:953
msgid "Clone failed."
msgstr "Клонирование не удалось."
-#: lib/choose_repository.tcl:915
+#: lib/choose_repository.tcl:960
msgid "No default branch obtained."
msgstr "Ветка по умолчанию не была получена."
-#: lib/choose_repository.tcl:926
+#: lib/choose_repository.tcl:971
#, tcl-format
msgid "Cannot resolve %s as a commit."
msgstr "Не могу распознать %s как коммит."
-#: lib/choose_repository.tcl:938
+#: lib/choose_repository.tcl:998
msgid "Creating working directory"
msgstr "Создаю рабочий каталог"
-#: lib/choose_repository.tcl:939 lib/index.tcl:67 lib/index.tcl:130
-#: lib/index.tcl:198
-msgid "files"
-msgstr "файлов"
-
-#: lib/choose_repository.tcl:968
+#: lib/choose_repository.tcl:1028
msgid "Initial file checkout failed."
msgstr "Не удалось получить начальное состояние файлов репозитория."
-#: lib/choose_repository.tcl:1011
-msgid "Open"
-msgstr "Открыть"
+#: lib/choose_repository.tcl:1072
+msgid "Cloning submodules"
+msgstr "Клонирование подмодулей"
-#: lib/choose_repository.tcl:1021
+#: lib/choose_repository.tcl:1087
+msgid "Cannot clone submodules."
+msgstr "Не удалось клонировать подмодули."
+
+#: lib/choose_repository.tcl:1110
msgid "Repository:"
msgstr "Репозиторий:"
-#: lib/choose_repository.tcl:1072
+#: lib/choose_repository.tcl:1159
#, tcl-format
msgid "Failed to open repository %s:"
msgstr "Не удалось открыть репозиторий %s:"
-#: lib/choose_rev.tcl:53
+#: lib/about.tcl:26
+msgid "git-gui - a graphical user interface for Git."
+msgstr "git-gui - графический пользовательский интерфейс к Git."
+
+#: lib/blame.tcl:74
+#, tcl-format
+msgid "%s (%s): File Viewer"
+msgstr "%s (%s): Просмотр файла"
+
+#: lib/blame.tcl:80
+msgid "Commit:"
+msgstr "Коммит:"
+
+#: lib/blame.tcl:282
+msgid "Copy Commit"
+msgstr "Копировать SHA-1"
+
+#: lib/blame.tcl:286
+msgid "Find Text..."
+msgstr "Найти текст…"
+
+#: lib/blame.tcl:290
+msgid "Goto Line..."
+msgstr "Перейти на строку…"
+
+#: lib/blame.tcl:299
+msgid "Do Full Copy Detection"
+msgstr "Провести полный поиск копий"
+
+#: lib/blame.tcl:303
+msgid "Show History Context"
+msgstr "Показать исторический контекст"
+
+#: lib/blame.tcl:306
+msgid "Blame Parent Commit"
+msgstr "Авторы родительского коммита"
+
+#: lib/blame.tcl:468
+#, tcl-format
+msgid "Reading %s..."
+msgstr "Чтение %s…"
+
+#: lib/blame.tcl:596
+msgid "Loading copy/move tracking annotations..."
+msgstr "Загрузка аннотации копирований/переименований…"
+
+#: lib/blame.tcl:613
+msgid "lines annotated"
+msgstr "строк прокомментировано"
+
+#: lib/blame.tcl:815
+msgid "Loading original location annotations..."
+msgstr "Загрузка аннотаций первоначального положения объекта…"
+
+#: lib/blame.tcl:818
+msgid "Annotation complete."
+msgstr "Аннотация завершена."
+
+#: lib/blame.tcl:849
+msgid "Busy"
+msgstr "Занят"
+
+#: lib/blame.tcl:850
+msgid "Annotation process is already running."
+msgstr "Аннотация уже запущена"
+
+#: lib/blame.tcl:889
+msgid "Running thorough copy detection..."
+msgstr "Выполнение полного поиска копий…"
+
+#: lib/blame.tcl:957
+msgid "Loading annotation..."
+msgstr "Загрузка аннотации…"
+
+#: lib/blame.tcl:1010
+msgid "Author:"
+msgstr "Автор:"
+
+#: lib/blame.tcl:1014
+msgid "Committer:"
+msgstr "Коммитер:"
+
+#: lib/blame.tcl:1019
+msgid "Original File:"
+msgstr "Исходный файл:"
+
+#: lib/blame.tcl:1067
+msgid "Cannot find HEAD commit:"
+msgstr "Не удалось найти текущее состояние:"
+
+#: lib/blame.tcl:1122
+msgid "Cannot find parent commit:"
+msgstr "Не удалось найти родительское состояние:"
+
+#: lib/blame.tcl:1137
+msgid "Unable to display parent"
+msgstr "Не могу показать предка"
+
+#: lib/blame.tcl:1138 lib/diff.tcl:345
+msgid "Error loading diff:"
+msgstr "Ошибка загрузки изменений:"
+
+#: lib/blame.tcl:1279
+msgid "Originally By:"
+msgstr "Источник:"
+
+#: lib/blame.tcl:1285
+msgid "In File:"
+msgstr "Файл:"
+
+#: lib/blame.tcl:1290
+msgid "Copied Or Moved Here By:"
+msgstr "Скопировано/перемещено в:"
+
+#: lib/diff.tcl:77
+#, tcl-format
+msgid ""
+"No differences detected.\n"
+"\n"
+"%s has no changes.\n"
+"\n"
+"The modification date of this file was updated by another application, but the content within the file was not changed.\n"
+"\n"
+"A rescan will be automatically started to find other files which may have the same state."
+msgstr "Изменений не обнаружено.\n\nв %s отсутствуют изменения.\n\nДата изменения файла была обновлена другой программой, но содержимое файла осталось прежним.\n\nСейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы."
+
+#: lib/diff.tcl:117
+#, tcl-format
+msgid "Loading diff of %s..."
+msgstr "Загрузка изменений %s…"
+
+#: lib/diff.tcl:143
+msgid ""
+"LOCAL: deleted\n"
+"REMOTE:\n"
+msgstr "ЛОКАЛЬНО: удалён\nВНЕШНИЙ:\n"
+
+#: lib/diff.tcl:148
+msgid ""
+"REMOTE: deleted\n"
+"LOCAL:\n"
+msgstr "ВНЕШНИЙ: удалён\nЛОКАЛЬНО:\n"
+
+#: lib/diff.tcl:155
+msgid "LOCAL:\n"
+msgstr "ЛОКАЛЬНО:\n"
+
+#: lib/diff.tcl:158
+msgid "REMOTE:\n"
+msgstr "ВНЕШНИЙ:\n"
+
+#: lib/diff.tcl:220 lib/diff.tcl:344
+#, tcl-format
+msgid "Unable to display %s"
+msgstr "Не могу показать %s"
+
+#: lib/diff.tcl:221
+msgid "Error loading file:"
+msgstr "Ошибка загрузки файла:"
+
+#: lib/diff.tcl:227
+msgid "Git Repository (subproject)"
+msgstr "Репозиторий Git (подпроект)"
+
+#: lib/diff.tcl:239
+msgid "* Binary file (not showing content)."
+msgstr "* Двоичный файл (содержимое не показано)"
+
+#: lib/diff.tcl:244
+#, tcl-format
+msgid ""
+"* Untracked file is %d bytes.\n"
+"* Showing only first %d bytes.\n"
+msgstr "* Размер неотслеживаемого файла %d байт.\n* Показано первых %d байт.\n"
+
+#: lib/diff.tcl:250
+#, tcl-format
+msgid ""
+"\n"
+"* Untracked file clipped here by %s.\n"
+"* To see the entire file, use an external editor.\n"
+msgstr "\n* Неотслеживаемый файл обрезан: %s.\n* Чтобы увидеть весь файл, используйте внешний редактор.\n"
+
+#: lib/diff.tcl:583
+msgid "Failed to unstage selected hunk."
+msgstr "Не удалось исключить выбранную часть."
+
+#: lib/diff.tcl:591
+msgid "Failed to revert selected hunk."
+msgstr "Не удалось обратить изменения выбранного блока."
+
+#: lib/diff.tcl:594
+msgid "Failed to stage selected hunk."
+msgstr "Не удалось проиндексировать выбранный блок изменений."
+
+#: lib/diff.tcl:687
+msgid "Failed to unstage selected line."
+msgstr "Не удалось исключить выбранную строку."
+
+#: lib/diff.tcl:696
+msgid "Failed to revert selected line."
+msgstr "Не удалось обратить изменения выбраной строки."
+
+#: lib/diff.tcl:700
+msgid "Failed to stage selected line."
+msgstr "Не удалось проиндексировать выбранную строку."
+
+#: lib/diff.tcl:889
+msgid "Failed to undo last revert."
+msgstr "Не удалось отменить посленднее обращение изменений."
+
+#: lib/sshkey.tcl:34
+msgid "No keys found."
+msgstr "Ключ не найден"
+
+#: lib/sshkey.tcl:37
+#, tcl-format
+msgid "Found a public key in: %s"
+msgstr "Публичный ключ из %s"
+
+#: lib/sshkey.tcl:43
+msgid "Generate Key"
+msgstr "Создать ключ"
+
+#: lib/sshkey.tcl:61
+msgid "Copy To Clipboard"
+msgstr "Скопировать в буфер обмена"
+
+#: lib/sshkey.tcl:75
+msgid "Your OpenSSH Public Key"
+msgstr "Ваш публичный ключ OpenSSH"
+
+#: lib/sshkey.tcl:83
+msgid "Generating..."
+msgstr "Создание…"
+
+#: lib/sshkey.tcl:89
+#, tcl-format
+msgid ""
+"Could not start ssh-keygen:\n"
+"\n"
+"%s"
+msgstr "Ошибка запуска ssh-keygen:\n\n%s"
+
+#: lib/sshkey.tcl:116
+msgid "Generation failed."
+msgstr "Ключ не создан."
+
+#: lib/sshkey.tcl:123
+msgid "Generation succeeded, but no keys found."
+msgstr "Создание ключа завершилось, но результат не был найден"
+
+#: lib/sshkey.tcl:126
+#, tcl-format
+msgid "Your key is in: %s"
+msgstr "Ваш ключ находится в: %s"
+
+#: lib/branch_create.tcl:23
+#, tcl-format
+msgid "%s (%s): Create Branch"
+msgstr "%s (%s): Создание ветки"
+
+#: lib/branch_create.tcl:28
+msgid "Create New Branch"
+msgstr "Создать новую ветку"
+
+#: lib/branch_create.tcl:42
+msgid "Branch Name"
+msgstr "Имя ветки"
+
+#: lib/branch_create.tcl:57
+msgid "Match Tracking Branch Name"
+msgstr "Соответствовать имени отслеживаемой ветки"
+
+#: lib/branch_create.tcl:66
+msgid "Starting Revision"
+msgstr "Начальная версия"
+
+#: lib/branch_create.tcl:72
+msgid "Update Existing Branch:"
+msgstr "Обновить имеющуюся ветку:"
+
+#: lib/branch_create.tcl:75
+msgid "No"
+msgstr "Нет"
+
+#: lib/branch_create.tcl:80
+msgid "Fast Forward Only"
+msgstr "Только Fast Forward"
+
+#: lib/branch_create.tcl:97
+msgid "Checkout After Creation"
+msgstr "После создания сделать текущей"
+
+#: lib/branch_create.tcl:132
+msgid "Please select a tracking branch."
+msgstr "Укажите отлеживаемую ветку."
+
+#: lib/branch_create.tcl:141
+#, tcl-format
+msgid "Tracking branch %s is not a branch in the remote repository."
+msgstr "Отслеживаемая ветка %s не является веткой на внешнем репозитории."
+
+#: lib/console.tcl:59
+msgid "Working... please wait..."
+msgstr "В процессе… пожалуйста, ждите…"
+
+#: lib/console.tcl:186
+msgid "Success"
+msgstr "Процесс успешно завершен"
+
+#: lib/console.tcl:200
+msgid "Error: Command Failed"
+msgstr "Ошибка: не удалось выполнить команду"
+
+#: lib/line.tcl:17
+msgid "Goto Line:"
+msgstr "Перейти на строку:"
+
+#: lib/line.tcl:23
+msgid "Go"
+msgstr "Перейти"
+
+#: lib/choose_rev.tcl:52
msgid "This Detached Checkout"
msgstr "Текущее отсоединенное состояние"
@@ -1232,36 +2254,36 @@ msgstr "Текущее отсоединенное состояние"
msgid "Revision Expression:"
msgstr "Выражение для определения версии:"
-#: lib/choose_rev.tcl:74
+#: lib/choose_rev.tcl:72
msgid "Local Branch"
msgstr "Локальная ветка:"
-#: lib/choose_rev.tcl:79
+#: lib/choose_rev.tcl:77
msgid "Tracking Branch"
msgstr "Отслеживаемая ветка"
-#: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538
+#: lib/choose_rev.tcl:82 lib/choose_rev.tcl:544
msgid "Tag"
msgstr "Метка"
-#: lib/choose_rev.tcl:317
+#: lib/choose_rev.tcl:321
#, tcl-format
msgid "Invalid revision: %s"
msgstr "Неверная версия: %s"
-#: lib/choose_rev.tcl:338
+#: lib/choose_rev.tcl:342
msgid "No revision selected."
msgstr "Версия не указана."
-#: lib/choose_rev.tcl:346
+#: lib/choose_rev.tcl:350
msgid "Revision expression is empty."
msgstr "Пустое выражение для определения версии."
-#: lib/choose_rev.tcl:531
+#: lib/choose_rev.tcl:537
msgid "Updated"
msgstr "Обновлено"
-#: lib/choose_rev.tcl:559
+#: lib/choose_rev.tcl:565
msgid "URL"
msgstr "Ссылка"
@@ -1279,24 +2301,24 @@ msgid ""
"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 "Невозможно исправить коммит во время слияния.\n\nТекущее слияние не завершено. Невозможно исправить предыдуий коммит, не прерывая эту операцию.\n"
-#: lib/commit.tcl:48
+#: lib/commit.tcl:56
msgid "Error loading commit data for amend:"
msgstr "Ошибка при загрузке данных для исправления коммита:"
-#: lib/commit.tcl:75
+#: lib/commit.tcl:83
msgid "Unable to obtain your identity:"
msgstr "Невозможно получить информацию об авторстве:"
-#: lib/commit.tcl:80
+#: lib/commit.tcl:88
msgid "Invalid GIT_COMMITTER_IDENT:"
msgstr "Недопустимый GIT_COMMITTER_IDENT:"
-#: lib/commit.tcl:129
+#: lib/commit.tcl:138
#, tcl-format
msgid "warning: Tcl does not support encoding '%s'."
msgstr "предупреждение: Tcl не поддерживает кодировку «%s»."
-#: lib/commit.tcl:149
+#: lib/commit.tcl:158
msgid ""
"Last scanned state does not match repository state.\n"
"\n"
@@ -1305,7 +2327,7 @@ msgid ""
"The rescan will be automatically started now.\n"
msgstr "Последнее прочитанное состояние репозитория не соответствует текущему.\n\nС момента последней проверки репозиторий был изменен другой программой Git. Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь. \n\nЭто будет сделано сейчас автоматически.\n"
-#: lib/commit.tcl:172
+#: lib/commit.tcl:182
#, tcl-format
msgid ""
"Unmerged files cannot be committed.\n"
@@ -1313,7 +2335,7 @@ msgid ""
"File %s has merge conflicts. You must resolve them and stage the file before committing.\n"
msgstr "Нельзя выполнить коммит с незавершённой операцией слияния.\n\nДля файла %s возник конфликт слияния. Разрешите конфликт и добавьте их в индекс перед выполнением коммита.\n"
-#: lib/commit.tcl:180
+#: lib/commit.tcl:190
#, tcl-format
msgid ""
"Unknown file state %s detected.\n"
@@ -1321,14 +2343,14 @@ msgid ""
"File %s cannot be committed by this program.\n"
msgstr "Обнаружено неизвестное состояние файла %s.\n\nФайл %s не может быть закоммичен этой программой.\n"
-#: lib/commit.tcl:188
+#: lib/commit.tcl:198
msgid ""
"No changes to commit.\n"
"\n"
"You must stage at least 1 file before you can commit.\n"
msgstr "Отсутствуют изменения для сохранения.\n\nДобавьте в индекс хотя бы один файл перед выполнением коммита.\n"
-#: lib/commit.tcl:203
+#: lib/commit.tcl:213
msgid ""
"Please supply a commit message.\n"
"\n"
@@ -1339,40 +2361,47 @@ msgid ""
"- Remaining lines: Describe why this change is good.\n"
msgstr "Укажите сообщение коммита.\n\nРекомендуется следующий формат сообщения:\n\n- в первой строке краткое описание сделанных изменений\n- вторая строка пустая\n- в оставшихся строках опишите, что дают ваши изменения\n"
-#: lib/commit.tcl:234
+#: lib/commit.tcl:244
msgid "Calling pre-commit hook..."
msgstr "Вызов перехватчика pre-commit…"
-#: lib/commit.tcl:249
+#: lib/commit.tcl:259
msgid "Commit declined by pre-commit hook."
msgstr "Коммит прерван переватчиком pre-commit."
-#: lib/commit.tcl:272
+#: lib/commit.tcl:278
+msgid ""
+"You are about to commit on a detached head. This is a potentially dangerous thing to do because if you switch to another branch you will lose your 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 "Вы собираетесь сделать коммит в отделённый HEAD. Это действие потенциально опасно, так как если вы переключитесь на другую ветку после этого, то вы потеряете свои изменения и их сложно будет потом найти с помощью журнала ссылок (reflog). Вам скорее всего следует отменить этот коммит и создать новую ветку до продолжения.\n \n Вы действительно хотите продолжить и создать коммит?"
+
+#: lib/commit.tcl:299
msgid "Calling commit-msg hook..."
msgstr "Вызов перехватчика commit-msg…"
-#: lib/commit.tcl:287
+#: lib/commit.tcl:314
msgid "Commit declined by commit-msg hook."
msgstr "Коммит прерван переватчиком commit-msg"
-#: lib/commit.tcl:300
+#: lib/commit.tcl:327
msgid "Committing changes..."
msgstr "Коммит изменений…"
-#: lib/commit.tcl:316
+#: lib/commit.tcl:344
msgid "write-tree failed:"
msgstr "Программа write-tree завершилась с ошибкой:"
-#: lib/commit.tcl:317 lib/commit.tcl:361 lib/commit.tcl:382
+#: lib/commit.tcl:345 lib/commit.tcl:395 lib/commit.tcl:422
msgid "Commit failed."
msgstr "Не удалось закоммитить изменения."
-#: lib/commit.tcl:334
+#: lib/commit.tcl:362
#, tcl-format
msgid "Commit %s appears to be corrupt"
msgstr "Коммит %s похоже поврежден"
-#: lib/commit.tcl:339
+#: lib/commit.tcl:367
msgid ""
"No changes to commit.\n"
"\n"
@@ -1381,63 +2410,95 @@ msgid ""
"A rescan will be automatically started now.\n"
msgstr "Нет изменения для коммита.\n\nНи один файл не был изменен и не было слияния.\n\nСейчас автоматически запустится перечитывание репозитория.\n"
-#: lib/commit.tcl:346
+#: lib/commit.tcl:374
msgid "No changes to commit."
msgstr "Нет изменения для коммита."
-#: lib/commit.tcl:360
+#: lib/commit.tcl:394
msgid "commit-tree failed:"
msgstr "Программа commit-tree завершилась с ошибкой:"
-#: lib/commit.tcl:381
+#: lib/commit.tcl:421
msgid "update-ref failed:"
msgstr "Программа update-ref завершилась с ошибкой:"
-#: lib/commit.tcl:469
+#: lib/commit.tcl:514
#, tcl-format
msgid "Created commit %s: %s"
msgstr "Создан коммит %s: %s "
-#: lib/console.tcl:59
-msgid "Working... please wait..."
-msgstr "В процессе… пожалуйста, ждите…"
+#: lib/branch_delete.tcl:16
+#, tcl-format
+msgid "%s (%s): Delete Branch"
+msgstr "%s (%s): Удаление ветки"
-#: lib/console.tcl:186
-msgid "Success"
-msgstr "Процесс успешно завершен"
+#: lib/branch_delete.tcl:21
+msgid "Delete Local Branch"
+msgstr "Удалить локальную ветку"
-#: lib/console.tcl:200
-msgid "Error: Command Failed"
-msgstr "Ошибка: не удалось выполнить команду"
+#: lib/branch_delete.tcl:39
+msgid "Local Branches"
+msgstr "Локальные ветки"
-#: lib/database.tcl:43
+#: lib/branch_delete.tcl:51
+msgid "Delete Only If Merged Into"
+msgstr "Удалить только в случае, если было слияние с"
+
+#: lib/branch_delete.tcl:103
+#, tcl-format
+msgid "The following branches are not completely merged into %s:"
+msgstr "Ветки, которые не полностью сливаются с %s:"
+
+#: lib/branch_delete.tcl:131
+#, tcl-format
+msgid " - %s:"
+msgstr " — %s:"
+
+#: lib/branch_delete.tcl:141
+#, tcl-format
+msgid ""
+"Failed to delete branches:\n"
+"%s"
+msgstr "Не удалось удалить ветки:\n%s"
+
+#: lib/date.tcl:25
+#, tcl-format
+msgid "Invalid date from Git: %s"
+msgstr "Неправильная дата в репозитории: %s"
+
+#: lib/database.tcl:42
msgid "Number of loose objects"
msgstr "Количество несвязанных объектов"
-#: lib/database.tcl:44
+#: lib/database.tcl:43
msgid "Disk space used by loose objects"
msgstr "Объем дискового пространства, занятый несвязанными объектами"
-#: lib/database.tcl:45
+#: lib/database.tcl:44
msgid "Number of packed objects"
msgstr "Количество упакованных объектов"
-#: lib/database.tcl:46
+#: lib/database.tcl:45
msgid "Number of packs"
msgstr "Количество pack-файлов"
-#: lib/database.tcl:47
+#: lib/database.tcl:46
msgid "Disk space used by packed objects"
msgstr "Объем дискового пространства, занятый упакованными объектами"
-#: lib/database.tcl:48
+#: lib/database.tcl:47
msgid "Packed objects waiting for pruning"
msgstr "Несвязанные объекты, которые можно удалить"
-#: lib/database.tcl:49
+#: lib/database.tcl:48
msgid "Garbage files"
msgstr "Мусор"
+#: lib/database.tcl:66
+#, tcl-format
+msgid "%s (%s): Database Statistics"
+msgstr "%s (%s): Статистика базы данных"
+
#: lib/database.tcl:72
msgid "Compressing the object database"
msgstr "Сжатие базы объектов"
@@ -1456,183 +2517,29 @@ msgid ""
"Compress the database now?"
msgstr "Этот репозиторий сейчас содержит примерно %i свободных объектов\n\nДля лучшей производительности рекомендуется сжать базу данных.\n\nСжать базу данных сейчас?"
-#: lib/date.tcl:25
-#, tcl-format
-msgid "Invalid date from Git: %s"
-msgstr "Неправильная дата в репозитории: %s"
-
-#: lib/diff.tcl:64
-#, tcl-format
-msgid ""
-"No differences detected.\n"
-"\n"
-"%s has no changes.\n"
-"\n"
-"The modification date of this file was updated by another application, but the content within the file was not changed.\n"
-"\n"
-"A rescan will be automatically started to find other files which may have the same state."
-msgstr "Изменений не обнаружено.\n\nв %s отсутствуют изменения.\n\nДата изменения файла была обновлена другой программой, но содержимое файла осталось прежним.\n\nСейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы."
-
-#: lib/diff.tcl:104
-#, tcl-format
-msgid "Loading diff of %s..."
-msgstr "Загрузка изменений %s…"
-
-#: lib/diff.tcl:125
-msgid ""
-"LOCAL: deleted\n"
-"REMOTE:\n"
-msgstr "ЛОКАЛЬНО: удалён\nВНЕШНИЙ:\n"
-
-#: lib/diff.tcl:130
-msgid ""
-"REMOTE: deleted\n"
-"LOCAL:\n"
-msgstr "ВНЕШНИЙ: удалён\nЛОКАЛЬНО:\n"
-
-#: lib/diff.tcl:137
-msgid "LOCAL:\n"
-msgstr "ЛОКАЛЬНО:\n"
-
-#: lib/diff.tcl:140
-msgid "REMOTE:\n"
-msgstr "ВНЕШНИЙ:\n"
-
-#: lib/diff.tcl:202 lib/diff.tcl:319
+#: lib/error.tcl:20
#, tcl-format
-msgid "Unable to display %s"
-msgstr "Не могу показать %s"
+msgid "%s: error"
+msgstr "%s: ошибка"
-#: lib/diff.tcl:203
-msgid "Error loading file:"
-msgstr "Ошибка загрузки файла:"
-
-#: lib/diff.tcl:210
-msgid "Git Repository (subproject)"
-msgstr "Репозиторий Git (подпроект)"
-
-#: lib/diff.tcl:222
-msgid "* Binary file (not showing content)."
-msgstr "* Двоичный файл (содержимое не показано)"
-
-#: lib/diff.tcl:227
-#, tcl-format
-msgid ""
-"* Untracked file is %d bytes.\n"
-"* Showing only first %d bytes.\n"
-msgstr "* Размер неотслеживаемого файла %d байт.\n* Показано первых %d байт.\n"
-
-#: lib/diff.tcl:233
+#: lib/error.tcl:36
#, tcl-format
-msgid ""
-"\n"
-"* Untracked file clipped here by %s.\n"
-"* To see the entire file, use an external editor.\n"
-msgstr "\n* Неотслеживаемый файл обрезан: %s.\n* Чтобы увидеть весь файл, используйте внешний редактор.\n"
+msgid "%s: warning"
+msgstr "%s: предупреждение"
-#: lib/diff.tcl:482
-msgid "Failed to unstage selected hunk."
-msgstr "Не удалось исключить выбранную часть."
-
-#: lib/diff.tcl:489
-msgid "Failed to stage selected hunk."
-msgstr "Не удалось проиндексировать выбранный блок изменений."
-
-#: lib/diff.tcl:568
-msgid "Failed to unstage selected line."
-msgstr "Не удалось исключить выбранную строку."
-
-#: lib/diff.tcl:576
-msgid "Failed to stage selected line."
-msgstr "Не удалось проиндексировать выбранную строку."
-
-#: lib/encoding.tcl:443
-msgid "Default"
-msgstr "По умолчанию"
-
-#: lib/encoding.tcl:448
+#: lib/error.tcl:80
#, tcl-format
-msgid "System (%s)"
-msgstr "Системная (%s)"
-
-#: lib/encoding.tcl:459 lib/encoding.tcl:465
-msgid "Other"
-msgstr "Другая"
-
-#: lib/error.tcl:20 lib/error.tcl:114
-msgid "error"
-msgstr "ошибка"
-
-#: lib/error.tcl:36
-msgid "warning"
-msgstr "предупреждение"
+msgid "%s hook failed:"
+msgstr "ошибка перехватчика %s:"
-#: lib/error.tcl:94
+#: lib/error.tcl:96
msgid "You must correct the above errors before committing."
msgstr "Перед коммитом, исправьте вышеуказанные ошибки."
-#: lib/index.tcl:6
-msgid "Unable to unlock the index."
-msgstr "Не удалось разблокировать индекс"
-
-#: lib/index.tcl:15
-msgid "Index Error"
-msgstr "Ошибка в индексе"
-
-#: lib/index.tcl:17
-msgid ""
-"Updating the Git index failed. A rescan will be automatically started to "
-"resynchronize git-gui."
-msgstr "Не удалось обновить индекс Git. Состояние репозитория будет перечитано автоматически."
-
-#: lib/index.tcl:28
-msgid "Continue"
-msgstr "Продолжить"
-
-#: lib/index.tcl:31
-msgid "Unlock Index"
-msgstr "Разблокировать индекс"
-
-#: lib/index.tcl:289
-#, tcl-format
-msgid "Unstaging %s from commit"
-msgstr "Удаление %s из индекса"
-
-#: lib/index.tcl:328
-msgid "Ready to commit."
-msgstr "Готов для коммита."
-
-#: lib/index.tcl:341
-#, tcl-format
-msgid "Adding %s"
-msgstr "Добавление %s…"
-
-#: lib/index.tcl:398
-#, tcl-format
-msgid "Revert changes in file %s?"
-msgstr "Обратить изменения в файле %s?"
-
-#: lib/index.tcl:400
+#: lib/error.tcl:116
#, tcl-format
-msgid "Revert changes in these %i files?"
-msgstr "Обратить изменения в %i файле(-ах)?"
-
-#: lib/index.tcl:408
-msgid "Any unstaged changes will be permanently lost by the revert."
-msgstr "Любые непроиндексированные изменения, будут потеряны при обращении изменений."
-
-#: lib/index.tcl:411
-msgid "Do Nothing"
-msgstr "Ничего не делать"
-
-#: lib/index.tcl:429
-msgid "Reverting selected files"
-msgstr "Обращение изменений в выбранных файлах"
-
-#: lib/index.tcl:433
-#, tcl-format
-msgid "Reverting %s"
-msgstr "Обращение изменений в %s"
+msgid "%s (%s): error"
+msgstr "%s (%s): ошибка"
#: lib/merge.tcl:13
msgid ""
@@ -1670,41 +2577,46 @@ msgid ""
"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 "Вы находитесь в процессе изменений.\n\nФайл %s изменён.\n\nВы должны завершить текущий коммит перед началом слияния. В случае необходимости, это позволит прервать операцию слияния.\n"
-#: lib/merge.tcl:107
+#: lib/merge.tcl:108
#, tcl-format
msgid "%s of %s"
msgstr "%s из %s"
-#: lib/merge.tcl:120
+#: lib/merge.tcl:126
#, tcl-format
msgid "Merging %s and %s..."
msgstr "Слияние %s и %s…"
-#: lib/merge.tcl:131
+#: lib/merge.tcl:137
msgid "Merge completed successfully."
msgstr "Слияние успешно завершено."
-#: lib/merge.tcl:133
+#: lib/merge.tcl:139
msgid "Merge failed. Conflict resolution is required."
msgstr "Не удалось завершить слияние. Требуется разрешение конфликта."
-#: lib/merge.tcl:158
+#: lib/merge.tcl:156
+#, tcl-format
+msgid "%s (%s): Merge"
+msgstr "%s (%s): Слияние"
+
+#: lib/merge.tcl:164
#, tcl-format
msgid "Merge Into %s"
msgstr "Слияние с %s"
-#: lib/merge.tcl:177
+#: lib/merge.tcl:183
msgid "Revision To Merge"
msgstr "Версия, с которой провести слияние"
-#: lib/merge.tcl:212
+#: lib/merge.tcl:218
msgid ""
"Cannot abort while amending.\n"
"\n"
"You must finish amending this commit.\n"
msgstr "Невозможно прервать исправление.\n\nЗавершите текущее исправление коммита.\n"
-#: lib/merge.tcl:222
+#: lib/merge.tcl:228
msgid ""
"Abort merge?\n"
"\n"
@@ -1713,7 +2625,7 @@ msgid ""
"Continue with aborting the current merge?"
msgstr "Прервать операцию слияния?\n\nПрерывание текущего слияния приведет к потере *ВСЕХ* несохраненных изменений.\n\nПродолжить?"
-#: lib/merge.tcl:228
+#: lib/merge.tcl:234
msgid ""
"Reset changes?\n"
"\n"
@@ -1722,661 +2634,18 @@ msgid ""
"Continue with resetting the current changes?"
msgstr "Сбросить изменения?\n\nСброс изменений приведет к потере *ВСЕХ* несохраненных изменений.\n\nПродолжить?"
-#: lib/merge.tcl:239
+#: lib/merge.tcl:246
msgid "Aborting"
msgstr "Прерываю"
-#: lib/merge.tcl:239
+#: lib/merge.tcl:247
msgid "files reset"
msgstr "изменения в файлах отменены"
-#: lib/merge.tcl:267
+#: lib/merge.tcl:277
msgid "Abort failed."
msgstr "Прервать не удалось."
-#: lib/merge.tcl:269
+#: lib/merge.tcl:279
msgid "Abort completed. Ready."
msgstr "Прервано."
-
-#: lib/mergetool.tcl:8
-msgid "Force resolution to the base version?"
-msgstr "Использовать базовую версию для разрешения конфликта?"
-
-#: lib/mergetool.tcl:9
-msgid "Force resolution to this branch?"
-msgstr "Использовать версию из этой ветки для разрешения конфликта?"
-
-#: lib/mergetool.tcl:10
-msgid "Force resolution to the other branch?"
-msgstr "Использовать версию из другой ветки для разрешения конфликта?"
-
-#: lib/mergetool.tcl:14
-#, tcl-format
-msgid ""
-"Note that the diff shows only conflicting changes.\n"
-"\n"
-"%s will be overwritten.\n"
-"\n"
-"This operation can be undone only by restarting the merge."
-msgstr "Внимание! Список изменений показывает только конфликтующие отличия.\n\n%s будет переписан.\n\nЭто действие можно отменить только перезапуском операции слияния."
-
-#: lib/mergetool.tcl:45
-#, tcl-format
-msgid "File %s seems to have unresolved conflicts, still stage?"
-msgstr "Похоже, что файл %s содержит неразрешенные конфликты. Продолжить индексацию?"
-
-#: lib/mergetool.tcl:60
-#, tcl-format
-msgid "Adding resolution for %s"
-msgstr "Добавляю результат разрешения для %s"
-
-#: lib/mergetool.tcl:141
-msgid "Cannot resolve deletion or link conflicts using a tool"
-msgstr "Программа слияния не обрабатывает конфликты с удалением или участием ссылок"
-
-#: lib/mergetool.tcl:146
-msgid "Conflict file does not exist"
-msgstr "Конфликтующий файл не существует"
-
-#: lib/mergetool.tcl:264
-#, tcl-format
-msgid "Not a GUI merge tool: '%s'"
-msgstr "«%s» не является программой слияния"
-
-#: lib/mergetool.tcl:268
-#, tcl-format
-msgid "Unsupported merge tool '%s'"
-msgstr "Неподдерживаемая программа слияния «%s»"
-
-#: lib/mergetool.tcl:303
-msgid "Merge tool is already running, terminate it?"
-msgstr "Программа слияния уже работает. Прервать?"
-
-#: lib/mergetool.tcl:323
-#, tcl-format
-msgid ""
-"Error retrieving versions:\n"
-"%s"
-msgstr "Ошибка получения версий:\n%s"
-
-#: lib/mergetool.tcl:343
-#, tcl-format
-msgid ""
-"Could not start the merge tool:\n"
-"\n"
-"%s"
-msgstr "Ошибка запуска программы слияния:\n\n%s"
-
-#: lib/mergetool.tcl:347
-msgid "Running merge tool..."
-msgstr "Запуск программы слияния…"
-
-#: lib/mergetool.tcl:375 lib/mergetool.tcl:383
-msgid "Merge tool failed."
-msgstr "Ошибка выполнения программы слияния."
-
-#: lib/option.tcl:11
-#, tcl-format
-msgid "Invalid global encoding '%s'"
-msgstr "Неверная глобальная кодировка «%s»"
-
-#: lib/option.tcl:19
-#, tcl-format
-msgid "Invalid repo encoding '%s'"
-msgstr "Неверная кодировка репозитория «%s»"
-
-#: lib/option.tcl:117
-msgid "Restore Defaults"
-msgstr "Восстановить настройки по умолчанию"
-
-#: lib/option.tcl:121
-msgid "Save"
-msgstr "Сохранить"
-
-#: lib/option.tcl:131
-#, tcl-format
-msgid "%s Repository"
-msgstr "Для репозитория %s"
-
-#: lib/option.tcl:132
-msgid "Global (All Repositories)"
-msgstr "Общие (для всех репозиториев)"
-
-#: lib/option.tcl:138
-msgid "User Name"
-msgstr "Имя пользователя"
-
-#: lib/option.tcl:139
-msgid "Email Address"
-msgstr "Адрес электронной почты"
-
-#: lib/option.tcl:141
-msgid "Summarize Merge Commits"
-msgstr "Суммарное сообщение при слиянии"
-
-#: lib/option.tcl:142
-msgid "Merge Verbosity"
-msgstr "Уровень детальности сообщений при слиянии"
-
-#: lib/option.tcl:143
-msgid "Show Diffstat After Merge"
-msgstr "Показать отчет об изменениях после слияния"
-
-#: lib/option.tcl:144
-msgid "Use Merge Tool"
-msgstr "Использовать для слияния программу"
-
-#: lib/option.tcl:146
-msgid "Trust File Modification Timestamps"
-msgstr "Доверять времени модификации файла"
-
-#: lib/option.tcl:147
-msgid "Prune Tracking Branches During Fetch"
-msgstr "Чистка отслеживаемых веток при извлечении изменений"
-
-#: lib/option.tcl:148
-msgid "Match Tracking Branches"
-msgstr "Такое же имя, как и у отслеживаемой ветки"
-
-#: lib/option.tcl:149
-msgid "Blame Copy Only On Changed Files"
-msgstr "Поиск копий только в изменённых файлах"
-
-#: lib/option.tcl:150
-msgid "Minimum Letters To Blame Copy On"
-msgstr "Минимальное количество символов для поиска копий"
-
-#: lib/option.tcl:151
-msgid "Blame History Context Radius (days)"
-msgstr "Радиус исторического контекста (в днях)"
-
-#: lib/option.tcl:152
-msgid "Number of Diff Context Lines"
-msgstr "Число строк в контексте diff"
-
-#: lib/option.tcl:153
-msgid "Commit Message Text Width"
-msgstr "Ширина текста сообщения коммита"
-
-#: lib/option.tcl:154
-msgid "New Branch Name Template"
-msgstr "Шаблон для имени новой ветки"
-
-#: lib/option.tcl:155
-msgid "Default File Contents Encoding"
-msgstr "Кодировка содержания файла по умолчанию"
-
-#: lib/option.tcl:203
-msgid "Change"
-msgstr "Изменить"
-
-#: lib/option.tcl:230
-msgid "Spelling Dictionary:"
-msgstr "Словарь для проверки правописания:"
-
-#: lib/option.tcl:254
-msgid "Change Font"
-msgstr "Изменить"
-
-#: lib/option.tcl:258
-#, tcl-format
-msgid "Choose %s"
-msgstr "Выберите %s"
-
-#: lib/option.tcl:264
-msgid "pt."
-msgstr "pt."
-
-#: lib/option.tcl:278
-msgid "Preferences"
-msgstr "Настройки"
-
-#: lib/option.tcl:314
-msgid "Failed to completely save options:"
-msgstr "Не удалось полностью сохранить настройки:"
-
-#: lib/remote.tcl:163
-msgid "Remove Remote"
-msgstr "Удалить ссылку на внешний репозиторий"
-
-#: lib/remote.tcl:168
-msgid "Prune from"
-msgstr "Чистка"
-
-#: lib/remote.tcl:173
-msgid "Fetch from"
-msgstr "Извлечение из"
-
-#: lib/remote.tcl:215
-msgid "Push to"
-msgstr "Отправить"
-
-#: lib/remote_add.tcl:19
-msgid "Add Remote"
-msgstr "Зарегистрировать внешний репозиторий"
-
-#: lib/remote_add.tcl:24
-msgid "Add New Remote"
-msgstr "Добавить внешний репозиторий"
-
-#: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36
-msgid "Add"
-msgstr "Добавить"
-
-#: lib/remote_add.tcl:37
-msgid "Remote Details"
-msgstr "Информация о внешнем репозитории"
-
-#: lib/remote_add.tcl:50
-msgid "Location:"
-msgstr "Положение:"
-
-#: lib/remote_add.tcl:62
-msgid "Further Action"
-msgstr "Следующая операция"
-
-#: lib/remote_add.tcl:65
-msgid "Fetch Immediately"
-msgstr "Сразу извлечь изменения"
-
-#: lib/remote_add.tcl:71
-msgid "Initialize Remote Repository and Push"
-msgstr "Инициализировать внешний репозиторий и отправить"
-
-#: lib/remote_add.tcl:77
-msgid "Do Nothing Else Now"
-msgstr "Больше ничего не делать"
-
-#: lib/remote_add.tcl:101
-msgid "Please supply a remote name."
-msgstr "Укажите название внешнего репозитория."
-
-#: lib/remote_add.tcl:114
-#, tcl-format
-msgid "'%s' is not an acceptable remote name."
-msgstr "«%s» не является допустимым именем внешнего репозитория."
-
-#: lib/remote_add.tcl:125
-#, tcl-format
-msgid "Failed to add remote '%s' of location '%s'."
-msgstr "Не удалось добавить «%s» из «%s». "
-
-#: lib/remote_add.tcl:133 lib/transport.tcl:6
-#, tcl-format
-msgid "fetch %s"
-msgstr "извлечение %s"
-
-#: lib/remote_add.tcl:134
-#, tcl-format
-msgid "Fetching the %s"
-msgstr "Извлечение %s"
-
-#: lib/remote_add.tcl:157
-#, tcl-format
-msgid "Do not know how to initialize repository at location '%s'."
-msgstr "Невозможно инициализировать репозиторий в «%s»."
-
-#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63
-#: lib/transport.tcl:81
-#, tcl-format
-msgid "push %s"
-msgstr "отправить %s"
-
-#: lib/remote_add.tcl:164
-#, tcl-format
-msgid "Setting up the %s (at %s)"
-msgstr "Настройка %s (в %s)"
-
-#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
-msgid "Delete Branch Remotely"
-msgstr "Удаление ветки во внешнем репозитории"
-
-#: lib/remote_branch_delete.tcl:47
-msgid "From Repository"
-msgstr "Из репозитория"
-
-#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134
-msgid "Remote:"
-msgstr "внешний:"
-
-#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149
-msgid "Arbitrary Location:"
-msgstr "Указанное положение:"
-
-#: lib/remote_branch_delete.tcl:84
-msgid "Branches"
-msgstr "Ветки"
-
-#: lib/remote_branch_delete.tcl:109
-msgid "Delete Only If"
-msgstr "Удалить только в случае, если"
-
-#: lib/remote_branch_delete.tcl:111
-msgid "Merged Into:"
-msgstr "Слияние с:"
-
-#: lib/remote_branch_delete.tcl:152
-msgid "A branch is required for 'Merged Into'."
-msgstr "Для операции «Слияние с» требуется указать ветку."
-
-#: lib/remote_branch_delete.tcl:184
-#, tcl-format
-msgid ""
-"The following branches are not completely merged into %s:\n"
-"\n"
-" - %s"
-msgstr "Следующие ветки могут быть объединены с %s при помощи операции слияния:\n\n - %s"
-
-#: lib/remote_branch_delete.tcl:189
-#, tcl-format
-msgid ""
-"One or more of the merge tests failed because you have not fetched the "
-"necessary commits. Try fetching from %s first."
-msgstr "Некоторые тесты на слияние не прошли, потому что вы не извлекли необходимые коммиты. Попытайтесь извлечь их из %s."
-
-#: lib/remote_branch_delete.tcl:207
-msgid "Please select one or more branches to delete."
-msgstr "Укажите одну или несколько веток для удаления."
-
-#: lib/remote_branch_delete.tcl:226
-#, tcl-format
-msgid "Deleting branches from %s"
-msgstr "Удаление веток из %s"
-
-#: lib/remote_branch_delete.tcl:292
-msgid "No repository selected."
-msgstr "Не указан репозиторий."
-
-#: lib/remote_branch_delete.tcl:297
-#, tcl-format
-msgid "Scanning %s..."
-msgstr "Перечитывание %s…"
-
-#: lib/search.tcl:21
-msgid "Find:"
-msgstr "Поиск:"
-
-#: lib/search.tcl:23
-msgid "Next"
-msgstr "Дальше"
-
-#: lib/search.tcl:24
-msgid "Prev"
-msgstr "Обратно"
-
-#: lib/search.tcl:25
-msgid "Case-Sensitive"
-msgstr "Игн. большие/маленькие"
-
-#: lib/shortcut.tcl:21 lib/shortcut.tcl:62
-msgid "Cannot write shortcut:"
-msgstr "Невозможно записать ссылку:"
-
-#: lib/shortcut.tcl:137
-msgid "Cannot write icon:"
-msgstr "Невозможно записать значок:"
-
-#: lib/spellcheck.tcl:57
-msgid "Unsupported spell checker"
-msgstr "Неподдерживаемая программа проверки правописания"
-
-#: lib/spellcheck.tcl:65
-msgid "Spell checking is unavailable"
-msgstr "Проверка правописания не доступна"
-
-#: lib/spellcheck.tcl:68
-msgid "Invalid spell checking configuration"
-msgstr "Неправильная конфигурация программы проверки правописания"
-
-#: lib/spellcheck.tcl:70
-#, tcl-format
-msgid "Reverting dictionary to %s."
-msgstr "Словарь вернут к %s."
-
-#: lib/spellcheck.tcl:73
-msgid "Spell checker silently failed on startup"
-msgstr "Программа проверки правописания не смогла запуститься"
-
-#: lib/spellcheck.tcl:80
-msgid "Unrecognized spell checker"
-msgstr "Нераспознанная программа проверки правописания"
-
-#: lib/spellcheck.tcl:186
-msgid "No Suggestions"
-msgstr "Исправлений не найдено"
-
-#: lib/spellcheck.tcl:388
-msgid "Unexpected EOF from spell checker"
-msgstr "Программа проверки правописания прервала передачу данных"
-
-#: lib/spellcheck.tcl:392
-msgid "Spell Checker Failed"
-msgstr "Ошибка проверки правописания"
-
-#: lib/sshkey.tcl:31
-msgid "No keys found."
-msgstr "Ключ не найден"
-
-#: lib/sshkey.tcl:34
-#, tcl-format
-msgid "Found a public key in: %s"
-msgstr "Публичный ключ из %s"
-
-#: lib/sshkey.tcl:40
-msgid "Generate Key"
-msgstr "Создать ключ"
-
-#: lib/sshkey.tcl:56
-msgid "Copy To Clipboard"
-msgstr "Скопировать в буфер обмена"
-
-#: lib/sshkey.tcl:70
-msgid "Your OpenSSH Public Key"
-msgstr "Ваш публичный ключ OpenSSH"
-
-#: lib/sshkey.tcl:78
-msgid "Generating..."
-msgstr "Создание…"
-
-#: lib/sshkey.tcl:84
-#, tcl-format
-msgid ""
-"Could not start ssh-keygen:\n"
-"\n"
-"%s"
-msgstr "Ошибка запуска ssh-keygen:\n\n%s"
-
-#: lib/sshkey.tcl:111
-msgid "Generation failed."
-msgstr "Ключ не создан."
-
-#: lib/sshkey.tcl:118
-msgid "Generation succeeded, but no keys found."
-msgstr "Создание ключа завершилось, но результат не был найден"
-
-#: lib/sshkey.tcl:121
-#, tcl-format
-msgid "Your key is in: %s"
-msgstr "Ваш ключ находится в: %s"
-
-#: lib/status_bar.tcl:83
-#, tcl-format
-msgid "%s ... %*i of %*i %s (%3i%%)"
-msgstr "%s … %*i из %*i %s (%3i%%)"
-
-#: lib/tools.tcl:75
-#, tcl-format
-msgid "Running %s requires a selected file."
-msgstr "Запуск %s требует выбранного файла."
-
-#: lib/tools.tcl:90
-#, tcl-format
-msgid "Are you sure you want to run %s?"
-msgstr "Действительно запустить %s?"
-
-#: lib/tools.tcl:110
-#, tcl-format
-msgid "Tool: %s"
-msgstr "Вспомогательная операция: %s"
-
-#: lib/tools.tcl:111
-#, tcl-format
-msgid "Running: %s"
-msgstr "Выполнение: %s"
-
-#: lib/tools.tcl:149
-#, tcl-format
-msgid "Tool completed successfully: %s"
-msgstr "Программа %s завершилась успешно."
-
-#: lib/tools.tcl:151
-#, tcl-format
-msgid "Tool failed: %s"
-msgstr "Ошибка выполнения программы: %s"
-
-#: lib/tools_dlg.tcl:22
-msgid "Add Tool"
-msgstr "Добавить вспомогательную операцию"
-
-#: lib/tools_dlg.tcl:28
-msgid "Add New Tool Command"
-msgstr "Новая вспомогательная операция"
-
-#: lib/tools_dlg.tcl:33
-msgid "Add globally"
-msgstr "Добавить для всех репозиториев"
-
-#: lib/tools_dlg.tcl:45
-msgid "Tool Details"
-msgstr "Описание вспомогательной операции"
-
-#: lib/tools_dlg.tcl:48
-msgid "Use '/' separators to create a submenu tree:"
-msgstr "Используйте «/» для создания подменю"
-
-#: lib/tools_dlg.tcl:61
-msgid "Command:"
-msgstr "Команда:"
-
-#: lib/tools_dlg.tcl:74
-msgid "Show a dialog before running"
-msgstr "Показать диалог перед запуском"
-
-#: lib/tools_dlg.tcl:80
-msgid "Ask the user to select a revision (sets $REVISION)"
-msgstr "Запрос на выбор версии (устанавливает $REVISION)"
-
-#: lib/tools_dlg.tcl:85
-msgid "Ask the user for additional arguments (sets $ARGS)"
-msgstr "Запрос дополнительных аргументов (устанавливает $ARGS)"
-
-#: lib/tools_dlg.tcl:92
-msgid "Don't show the command output window"
-msgstr "Не показывать окно вывода команды"
-
-#: lib/tools_dlg.tcl:97
-msgid "Run only if a diff is selected ($FILENAME not empty)"
-msgstr "Запуск только если показан список изменений ($FILENAME не пусто)"
-
-#: lib/tools_dlg.tcl:121
-msgid "Please supply a name for the tool."
-msgstr "Укажите название вспомогательной операции."
-
-#: lib/tools_dlg.tcl:129
-#, tcl-format
-msgid "Tool '%s' already exists."
-msgstr "Вспомогательная операция «%s» уже существует."
-
-#: lib/tools_dlg.tcl:151
-#, tcl-format
-msgid ""
-"Could not add tool:\n"
-"%s"
-msgstr "Ошибка добавления программы:\n%s"
-
-#: lib/tools_dlg.tcl:190
-msgid "Remove Tool"
-msgstr "Удалить программу"
-
-#: lib/tools_dlg.tcl:196
-msgid "Remove Tool Commands"
-msgstr "Удалить команды программы"
-
-#: lib/tools_dlg.tcl:200
-msgid "Remove"
-msgstr "Удалить"
-
-#: lib/tools_dlg.tcl:236
-msgid "(Blue denotes repository-local tools)"
-msgstr "(Синим выделены программы локальные репозиторию)"
-
-#: lib/tools_dlg.tcl:297
-#, tcl-format
-msgid "Run Command: %s"
-msgstr "Запуск команды: %s"
-
-#: lib/tools_dlg.tcl:311
-msgid "Arguments"
-msgstr "Аргументы"
-
-#: lib/tools_dlg.tcl:348
-msgid "OK"
-msgstr "OK"
-
-#: lib/transport.tcl:7
-#, tcl-format
-msgid "Fetching new changes from %s"
-msgstr "Извлечение изменений из %s "
-
-#: lib/transport.tcl:18
-#, tcl-format
-msgid "remote prune %s"
-msgstr "чистка внешнего %s"
-
-#: lib/transport.tcl:19
-#, tcl-format
-msgid "Pruning tracking branches deleted from %s"
-msgstr "Чистка отслеживаемых веток, удалённых из %s"
-
-#: lib/transport.tcl:26
-#, tcl-format
-msgid "Pushing changes to %s"
-msgstr "Отправка изменений в %s "
-
-#: lib/transport.tcl:64
-#, tcl-format
-msgid "Mirroring to %s"
-msgstr "Точное копирование в %s"
-
-#: lib/transport.tcl:82
-#, tcl-format
-msgid "Pushing %s %s to %s"
-msgstr "Отправка %s %s в %s"
-
-#: lib/transport.tcl:100
-msgid "Push Branches"
-msgstr "Отправить ветки"
-
-#: lib/transport.tcl:114
-msgid "Source Branches"
-msgstr "Исходные ветки"
-
-#: lib/transport.tcl:131
-msgid "Destination Repository"
-msgstr "Репозиторий назначения"
-
-#: lib/transport.tcl:169
-msgid "Transfer Options"
-msgstr "Настройки отправки"
-
-#: lib/transport.tcl:171
-msgid "Force overwrite existing branch (may discard changes)"
-msgstr "Принудительно перезаписать существующую ветку (возможна потеря изменений)"
-
-#: lib/transport.tcl:175
-msgid "Use thin pack (for slow network connections)"
-msgstr "Использовать thin pack (для медленных сетевых подключений)"
-
-#: lib/transport.tcl:179
-msgid "Include tags"
-msgstr "Передать метки"
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index 7225abd..78f3647 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -46,9 +46,11 @@ show_tool_names () {
while read scriptname
do
setup_tool "$scriptname" 2>/dev/null
- variants="$variants$(list_tool_variants)\n"
+ # We need an actual line feed here
+ variants="$variants
+$(list_tool_variants)"
done
- variants="$(echo "$variants" | sort | uniq)"
+ variants="$(echo "$variants" | sort -u)"
for toolname in $variants
do
diff --git a/git-p4.py b/git-p4.py
index 6ae5bbf..09c9e93 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -3031,7 +3031,7 @@ class P4Sync(Command, P4UserMap):
regexp = re.compile(pattern, re.VERBOSE)
text = ''.join(decode_text_stream(c) for c in contents)
text = regexp.sub(r'$\1$', text)
- contents = [ text ]
+ contents = [ encode_text_stream(text) ]
if self.largeFileSystem:
(git_mode, contents) = self.largeFileSystem.processContent(git_mode, relPath, contents)
diff --git a/gitweb/Makefile b/gitweb/Makefile
index cd194d0..f13e23c 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -48,7 +48,9 @@ HIGHLIGHT_BIN = highlight
../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE
+ifneq ($(MAKECMDGOALS),clean)
-include ../GIT-VERSION-FILE
+endif
### Build rules
diff --git a/sha1-lookup.c b/hash-lookup.c
index 2918584..1191856 100644
--- a/sha1-lookup.c
+++ b/hash-lookup.c
@@ -1,9 +1,9 @@
#include "cache.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
-static uint32_t take2(const unsigned char *sha1)
+static uint32_t take2(const unsigned char *hash)
{
- return ((sha1[0] << 8) | sha1[1]);
+ return ((hash[0] << 8) | hash[1]);
}
/*
@@ -47,11 +47,11 @@ static uint32_t take2(const unsigned char *sha1)
*/
/*
* The table should contain "nr" elements.
- * The sha1 of element i (between 0 and nr - 1) should be returned
+ * The hash of element i (between 0 and nr - 1) should be returned
* by "fn(i, table)".
*/
-int sha1_pos(const unsigned char *hash, void *table, size_t nr,
- sha1_access_fn fn)
+int hash_pos(const unsigned char *hash, void *table, size_t nr,
+ hash_access_fn fn)
{
size_t hi = nr;
size_t lo = 0;
@@ -74,7 +74,7 @@ int sha1_pos(const unsigned char *hash, void *table, size_t nr,
if (lov != hiv) {
/*
* At this point miv could be equal
- * to hiv (but sha1 could still be higher);
+ * to hiv (but hash could still be higher);
* the invariant of (mi < hi) should be
* kept.
*/
@@ -100,17 +100,17 @@ int sha1_pos(const unsigned char *hash, void *table, size_t nr,
return index_pos_to_insert_pos(lo);
}
-int bsearch_hash(const unsigned char *sha1, const uint32_t *fanout_nbo,
+int bsearch_hash(const unsigned char *hash, const uint32_t *fanout_nbo,
const unsigned char *table, size_t stride, uint32_t *result)
{
uint32_t hi, lo;
- hi = ntohl(fanout_nbo[*sha1]);
- lo = ((*sha1 == 0x0) ? 0 : ntohl(fanout_nbo[*sha1 - 1]));
+ hi = ntohl(fanout_nbo[*hash]);
+ lo = ((*hash == 0x0) ? 0 : ntohl(fanout_nbo[*hash - 1]));
while (lo < hi) {
unsigned mi = lo + (hi - lo) / 2;
- int cmp = hashcmp(table + mi * stride, sha1);
+ int cmp = hashcmp(table + mi * stride, hash);
if (!cmp) {
if (result)
diff --git a/sha1-lookup.h b/hash-lookup.h
index 5afcd01..5d476de 100644
--- a/sha1-lookup.h
+++ b/hash-lookup.h
@@ -1,20 +1,20 @@
-#ifndef SHA1_LOOKUP_H
-#define SHA1_LOOKUP_H
+#ifndef HASH_LOOKUP_H
+#define HASH_LOOKUP_H
-typedef const unsigned char *sha1_access_fn(size_t index, void *table);
+typedef const unsigned char *hash_access_fn(size_t index, void *table);
-int sha1_pos(const unsigned char *sha1,
+int hash_pos(const unsigned char *hash,
void *table,
size_t nr,
- sha1_access_fn fn);
+ hash_access_fn fn);
/*
- * Searches for sha1 in table, using the given fanout table to determine the
+ * Searches for hash in table, using the given fanout table to determine the
* interval to search, then using binary search. Returns 1 if found, 0 if not.
*
* Takes the following parameters:
*
- * - sha1: the hash to search for
+ * - hash: the hash to search for
* - fanout_nbo: a 256-element array of NETWORK-order 32-bit integers; the
* integer at position i represents the number of elements in table whose
* first byte is less than or equal to i
@@ -23,10 +23,10 @@ int sha1_pos(const unsigned char *sha1,
* GIT_MAX_RAWSZ or greater)
* - result: if not NULL, this function stores the element index of the
* position found (if the search is successful) or the index of the least
- * element that is greater than sha1 (if the search is not successful)
+ * element that is greater than hash (if the search is not successful)
*
* This function does not verify the validity of the fanout table.
*/
-int bsearch_hash(const unsigned char *sha1, const uint32_t *fanout_nbo,
+int bsearch_hash(const unsigned char *hash, const uint32_t *fanout_nbo,
const unsigned char *table, size_t stride, uint32_t *result);
#endif
diff --git a/hash.h b/hash.h
index e0f3f16..3fb0c3d 100644
--- a/hash.h
+++ b/hash.h
@@ -2,6 +2,7 @@
#define HASH_H
#include "git-compat-util.h"
+#include "repository.h"
#if defined(SHA1_PPC)
#include "ppc/sha1.h"
@@ -184,4 +185,98 @@ struct object_id {
#define the_hash_algo the_repository->hash_algo
+extern const struct object_id null_oid;
+
+static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
+{
+ /*
+ * 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 (the_hash_algo->rawsz == GIT_MAX_RAWSZ)
+ return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
+ return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
+}
+
+static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
+{
+ return hashcmp(oid1->hash, oid2->hash);
+}
+
+static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
+{
+ /*
+ * We write this here instead of deferring to hashcmp so that the
+ * compiler can properly inline it and avoid calling memcmp.
+ */
+ if (the_hash_algo->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)
+{
+ return hasheq(oid1->hash, oid2->hash);
+}
+
+static inline int is_null_oid(const struct object_id *oid)
+{
+ return oideq(oid, &null_oid);
+}
+
+static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
+{
+ memcpy(sha_dst, sha_src, the_hash_algo->rawsz);
+}
+
+static inline void oidcpy(struct object_id *dst, const struct object_id *src)
+{
+ memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
+}
+
+static inline struct object_id *oiddup(const struct object_id *src)
+{
+ struct object_id *dst = xmalloc(sizeof(struct object_id));
+ oidcpy(dst, src);
+ return dst;
+}
+
+static inline void hashclr(unsigned char *hash)
+{
+ memset(hash, 0, the_hash_algo->rawsz);
+}
+
+static inline void oidclr(struct object_id *oid)
+{
+ memset(oid->hash, 0, GIT_MAX_RAWSZ);
+}
+
+static inline void oidread(struct object_id *oid, const unsigned char *hash)
+{
+ memcpy(oid->hash, hash, the_hash_algo->rawsz);
+}
+
+static inline int is_empty_blob_sha1(const unsigned char *sha1)
+{
+ return hasheq(sha1, the_hash_algo->empty_blob->hash);
+}
+
+static inline int is_empty_blob_oid(const struct object_id *oid)
+{
+ return oideq(oid, the_hash_algo->empty_blob);
+}
+
+static inline int is_empty_tree_sha1(const unsigned char *sha1)
+{
+ return hasheq(sha1, the_hash_algo->empty_tree->hash);
+}
+
+static inline int is_empty_tree_oid(const struct object_id *oid)
+{
+ return oideq(oid, the_hash_algo->empty_tree);
+}
+
+const char *empty_tree_oid_hex(void);
+const char *empty_blob_oid_hex(void);
+
#endif
diff --git a/list-objects-filter.c b/list-objects-filter.c
index 0a3ef3c..4ec0041 100644
--- a/list-objects-filter.c
+++ b/list-objects-filter.c
@@ -21,7 +21,7 @@
* in the traversal (until we mark it SEEN). This is a way to
* let us silently de-dup calls to show() in the caller. This
* is subtly different from the "revision.h:SHOWN" and the
- * "sha1-name.c:ONELINE_SEEN" bits. And also different from
+ * "object-name.c:ONELINE_SEEN" bits. And also different from
* the non-de-dup usage in pack-bitmap.c
*/
#define FILTER_SHOWN_BUT_REVISIT (1<<21)
diff --git a/merge-ort.c b/merge-ort.c
index b487901..d36a92b 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -17,20 +17,1949 @@
#include "cache.h"
#include "merge-ort.h"
+#include "alloc.h"
+#include "blob.h"
+#include "cache-tree.h"
+#include "commit.h"
+#include "commit-reach.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "dir.h"
+#include "object-store.h"
+#include "strmap.h"
+#include "tree.h"
+#include "unpack-trees.h"
+#include "xdiff-interface.h"
+
+/*
+ * We have many arrays of size 3. Whenever we have such an array, the
+ * indices refer to one of the sides of the three-way merge. This is so
+ * pervasive that the constants 0, 1, and 2 are used in many places in the
+ * code (especially in arithmetic operations to find the other side's index
+ * or to compute a relevant mask), but sometimes these enum names are used
+ * to aid code clarity.
+ *
+ * See also 'filemask' and 'dirmask' in struct conflict_info; the "ith side"
+ * referred to there is one of these three sides.
+ */
+enum merge_side {
+ MERGE_BASE = 0,
+ MERGE_SIDE1 = 1,
+ MERGE_SIDE2 = 2
+};
+
+struct rename_info {
+ /*
+ * pairs: pairing of filenames from diffcore_rename()
+ *
+ * Index 1 and 2 correspond to sides 1 & 2 as used in
+ * conflict_info.stages. Index 0 unused.
+ */
+ struct diff_queue_struct pairs[3];
+
+ /*
+ * needed_limit: value needed for inexact rename detection to run
+ *
+ * If the current rename limit wasn't high enough for inexact
+ * rename detection to run, this records the limit needed. Otherwise,
+ * this value remains 0.
+ */
+ int needed_limit;
+};
+
+struct merge_options_internal {
+ /*
+ * paths: primary data structure in all of merge ort.
+ *
+ * The keys of paths:
+ * * are full relative paths from the toplevel of the repository
+ * (e.g. "drivers/firmware/raspberrypi.c").
+ * * store all relevant paths in the repo, both directories and
+ * files (e.g. drivers, drivers/firmware would also be included)
+ * * these keys serve to intern all the path strings, which allows
+ * us to do pointer comparison on directory names instead of
+ * strcmp; we just have to be careful to use the interned strings.
+ * (Technically paths_to_free may track some strings that were
+ * removed from froms paths.)
+ *
+ * The values of paths:
+ * * either a pointer to a merged_info, or a conflict_info struct
+ * * merged_info contains all relevant information for a
+ * non-conflicted entry.
+ * * conflict_info contains a merged_info, plus any additional
+ * information about a conflict such as the higher orders stages
+ * involved and the names of the paths those came from (handy
+ * once renames get involved).
+ * * a path may start "conflicted" (i.e. point to a conflict_info)
+ * and then a later step (e.g. three-way content merge) determines
+ * it can be cleanly merged, at which point it'll be marked clean
+ * and the algorithm will ignore any data outside the contained
+ * merged_info for that entry
+ * * If an entry remains conflicted, the merged_info portion of a
+ * conflict_info will later be filled with whatever version of
+ * the file should be placed in the working directory (e.g. an
+ * as-merged-as-possible variation that contains conflict markers).
+ */
+ struct strmap paths;
+
+ /*
+ * conflicted: a subset of keys->values from "paths"
+ *
+ * conflicted is basically an optimization between process_entries()
+ * and record_conflicted_index_entries(); the latter could loop over
+ * ALL the entries in paths AGAIN and look for the ones that are
+ * still conflicted, but since process_entries() has to loop over
+ * all of them, it saves the ones it couldn't resolve in this strmap
+ * so that record_conflicted_index_entries() can iterate just the
+ * relevant entries.
+ */
+ struct strmap conflicted;
+
+ /*
+ * paths_to_free: additional list of strings to free
+ *
+ * If keys are removed from "paths", they are added to paths_to_free
+ * to ensure they are later freed. We avoid free'ing immediately since
+ * other places (e.g. conflict_info.pathnames[]) may still be
+ * referencing these paths.
+ */
+ struct string_list paths_to_free;
+
+ /*
+ * output: special messages and conflict notices for various paths
+ *
+ * This is a map of pathnames (a subset of the keys in "paths" above)
+ * to strbufs. It gathers various warning/conflict/notice messages
+ * for later processing.
+ */
+ struct strmap output;
+
+ /*
+ * renames: various data relating to rename detection
+ */
+ struct rename_info renames;
+
+ /*
+ * current_dir_name: temporary var used in collect_merge_info_callback()
+ *
+ * Used to set merged_info.directory_name; see documentation for that
+ * variable and the requirements placed on that field.
+ */
+ const char *current_dir_name;
+
+ /* call_depth: recursion level counter for merging merge bases */
+ int call_depth;
+};
+
+struct version_info {
+ struct object_id oid;
+ unsigned short mode;
+};
+
+struct merged_info {
+ /* if is_null, ignore result. otherwise result has oid & mode */
+ struct version_info result;
+ unsigned is_null:1;
+
+ /*
+ * clean: whether the path in question is cleanly merged.
+ *
+ * see conflict_info.merged for more details.
+ */
+ unsigned clean:1;
+
+ /*
+ * basename_offset: offset of basename of path.
+ *
+ * perf optimization to avoid recomputing offset of final '/'
+ * character in pathname (0 if no '/' in pathname).
+ */
+ size_t basename_offset;
+
+ /*
+ * directory_name: containing directory name.
+ *
+ * Note that we assume directory_name is constructed such that
+ * strcmp(dir1_name, dir2_name) == 0 iff dir1_name == dir2_name,
+ * i.e. string equality is equivalent to pointer equality. For this
+ * to hold, we have to be careful setting directory_name.
+ */
+ const char *directory_name;
+};
+
+struct conflict_info {
+ /*
+ * merged: the version of the path that will be written to working tree
+ *
+ * WARNING: It is critical to check merged.clean and ensure it is 0
+ * before reading any conflict_info fields outside of merged.
+ * Allocated merge_info structs will always have clean set to 1.
+ * Allocated conflict_info structs will have merged.clean set to 0
+ * initially. The merged.clean field is how we know if it is safe
+ * to access other parts of conflict_info besides merged; if a
+ * conflict_info's merged.clean is changed to 1, the rest of the
+ * algorithm is not allowed to look at anything outside of the
+ * merged member anymore.
+ */
+ struct merged_info merged;
+
+ /* oids & modes from each of the three trees for this path */
+ struct version_info stages[3];
+
+ /* pathnames for each stage; may differ due to rename detection */
+ const char *pathnames[3];
+
+ /* Whether this path is/was involved in a directory/file conflict */
+ unsigned df_conflict:1;
+
+ /*
+ * Whether this path is/was involved in a non-content conflict other
+ * than a directory/file conflict (e.g. rename/rename, rename/delete,
+ * file location based on possible directory rename).
+ */
+ unsigned path_conflict:1;
+
+ /*
+ * For filemask and dirmask, the ith bit corresponds to whether the
+ * ith entry is a file (filemask) or a directory (dirmask). Thus,
+ * filemask & dirmask is always zero, and filemask | dirmask is at
+ * most 7 but can be less when a path does not appear as either a
+ * file or a directory on at least one side of history.
+ *
+ * Note that these masks are related to enum merge_side, as the ith
+ * entry corresponds to side i.
+ *
+ * These values come from a traverse_trees() call; more info may be
+ * found looking at tree-walk.h's struct traverse_info,
+ * particularly the documentation above the "fn" member (note that
+ * filemask = mask & ~dirmask from that documentation).
+ */
+ unsigned filemask:3;
+ unsigned dirmask:3;
+
+ /*
+ * Optimization to track which stages match, to avoid the need to
+ * recompute it in multiple steps. Either 0 or at least 2 bits are
+ * set; if at least 2 bits are set, their corresponding stages match.
+ */
+ unsigned match_mask:3;
+};
+
+/*** Function Grouping: various utility functions ***/
+
+/*
+ * For the next three macros, see warning for conflict_info.merged.
+ *
+ * In each of the below, mi is a struct merged_info*, and ci was defined
+ * as a struct conflict_info* (but we need to verify ci isn't actually
+ * pointed at a struct merged_info*).
+ *
+ * INITIALIZE_CI: Assign ci to mi but only if it's safe; set to NULL otherwise.
+ * VERIFY_CI: Ensure that something we assigned to a conflict_info* is one.
+ * ASSIGN_AND_VERIFY_CI: Similar to VERIFY_CI but do assignment first.
+ */
+#define INITIALIZE_CI(ci, mi) do { \
+ (ci) = (!(mi) || (mi)->clean) ? NULL : (struct conflict_info *)(mi); \
+} while (0)
+#define VERIFY_CI(ci) assert(ci && !ci->merged.clean);
+#define ASSIGN_AND_VERIFY_CI(ci, mi) do { \
+ (ci) = (struct conflict_info *)(mi); \
+ assert((ci) && !(mi)->clean); \
+} while (0)
+
+static void free_strmap_strings(struct strmap *map)
+{
+ struct hashmap_iter iter;
+ struct strmap_entry *entry;
+
+ strmap_for_each_entry(map, &iter, entry) {
+ free((char*)entry->key);
+ }
+}
+
+static void clear_or_reinit_internal_opts(struct merge_options_internal *opti,
+ int reinitialize)
+{
+ void (*strmap_func)(struct strmap *, int) =
+ reinitialize ? strmap_partial_clear : strmap_clear;
+
+ /*
+ * We marked opti->paths with strdup_strings = 0, so that we
+ * wouldn't have to make another copy of the fullpath created by
+ * make_traverse_path from setup_path_info(). But, now that we've
+ * used it and have no other references to these strings, it is time
+ * to deallocate them.
+ */
+ free_strmap_strings(&opti->paths);
+ strmap_func(&opti->paths, 1);
+
+ /*
+ * All keys and values in opti->conflicted are a subset of those in
+ * opti->paths. We don't want to deallocate anything twice, so we
+ * don't free the keys and we pass 0 for free_values.
+ */
+ strmap_func(&opti->conflicted, 0);
+
+ /*
+ * opti->paths_to_free is similar to opti->paths; we created it with
+ * strdup_strings = 0 to avoid making _another_ copy of the fullpath
+ * but now that we've used it and have no other references to these
+ * strings, it is time to deallocate them. We do so by temporarily
+ * setting strdup_strings to 1.
+ */
+ opti->paths_to_free.strdup_strings = 1;
+ string_list_clear(&opti->paths_to_free, 0);
+ opti->paths_to_free.strdup_strings = 0;
+
+ if (!reinitialize) {
+ struct hashmap_iter iter;
+ struct strmap_entry *e;
+
+ /* Release and free each strbuf found in output */
+ strmap_for_each_entry(&opti->output, &iter, e) {
+ struct strbuf *sb = e->value;
+ strbuf_release(sb);
+ /*
+ * While strictly speaking we don't need to free(sb)
+ * here because we could pass free_values=1 when
+ * calling strmap_clear() on opti->output, that would
+ * require strmap_clear to do another
+ * strmap_for_each_entry() loop, so we just free it
+ * while we're iterating anyway.
+ */
+ free(sb);
+ }
+ strmap_clear(&opti->output, 0);
+ }
+}
+
+static int err(struct merge_options *opt, const char *err, ...)
+{
+ va_list params;
+ struct strbuf sb = STRBUF_INIT;
+
+ strbuf_addstr(&sb, "error: ");
+ va_start(params, err);
+ strbuf_vaddf(&sb, err, params);
+ va_end(params);
+
+ error("%s", sb.buf);
+ strbuf_release(&sb);
+
+ return -1;
+}
+
+__attribute__((format (printf, 4, 5)))
+static void path_msg(struct merge_options *opt,
+ const char *path,
+ int omittable_hint, /* skippable under --remerge-diff */
+ const char *fmt, ...)
+{
+ va_list ap;
+ struct strbuf *sb = strmap_get(&opt->priv->output, path);
+ if (!sb) {
+ sb = xmalloc(sizeof(*sb));
+ strbuf_init(sb, 0);
+ strmap_put(&opt->priv->output, path, sb);
+ }
+
+ va_start(ap, fmt);
+ strbuf_vaddf(sb, fmt, ap);
+ va_end(ap);
+
+ strbuf_addch(sb, '\n');
+}
+
+/*** Function Grouping: functions related to collect_merge_info() ***/
+
+static void setup_path_info(struct merge_options *opt,
+ struct string_list_item *result,
+ const char *current_dir_name,
+ int current_dir_name_len,
+ char *fullpath, /* we'll take over ownership */
+ struct name_entry *names,
+ struct name_entry *merged_version,
+ unsigned is_null, /* boolean */
+ unsigned df_conflict, /* boolean */
+ unsigned filemask,
+ unsigned dirmask,
+ int resolved /* boolean */)
+{
+ /* result->util is void*, so mi is a convenience typed variable */
+ struct merged_info *mi;
+
+ assert(!is_null || resolved);
+ assert(!df_conflict || !resolved); /* df_conflict implies !resolved */
+ assert(resolved == (merged_version != NULL));
+
+ mi = xcalloc(1, resolved ? sizeof(struct merged_info) :
+ sizeof(struct conflict_info));
+ mi->directory_name = current_dir_name;
+ mi->basename_offset = current_dir_name_len;
+ mi->clean = !!resolved;
+ if (resolved) {
+ mi->result.mode = merged_version->mode;
+ oidcpy(&mi->result.oid, &merged_version->oid);
+ mi->is_null = !!is_null;
+ } else {
+ int i;
+ struct conflict_info *ci;
+
+ ASSIGN_AND_VERIFY_CI(ci, mi);
+ for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
+ ci->pathnames[i] = fullpath;
+ ci->stages[i].mode = names[i].mode;
+ oidcpy(&ci->stages[i].oid, &names[i].oid);
+ }
+ ci->filemask = filemask;
+ ci->dirmask = dirmask;
+ ci->df_conflict = !!df_conflict;
+ if (dirmask)
+ /*
+ * Assume is_null for now, but if we have entries
+ * under the directory then when it is complete in
+ * write_completed_directory() it'll update this.
+ * Also, for D/F conflicts, we have to handle the
+ * directory first, then clear this bit and process
+ * the file to see how it is handled -- that occurs
+ * near the top of process_entry().
+ */
+ mi->is_null = 1;
+ }
+ strmap_put(&opt->priv->paths, fullpath, mi);
+ result->string = fullpath;
+ result->util = mi;
+}
+
+static int collect_merge_info_callback(int n,
+ unsigned long mask,
+ unsigned long dirmask,
+ struct name_entry *names,
+ struct traverse_info *info)
+{
+ /*
+ * n is 3. Always.
+ * common ancestor (mbase) has mask 1, and stored in index 0 of names
+ * head of side 1 (side1) has mask 2, and stored in index 1 of names
+ * head of side 2 (side2) has mask 4, and stored in index 2 of names
+ */
+ struct merge_options *opt = info->data;
+ struct merge_options_internal *opti = opt->priv;
+ struct string_list_item pi; /* Path Info */
+ struct conflict_info *ci; /* typed alias to pi.util (which is void*) */
+ struct name_entry *p;
+ size_t len;
+ char *fullpath;
+ const char *dirname = opti->current_dir_name;
+ unsigned filemask = mask & ~dirmask;
+ unsigned match_mask = 0; /* will be updated below */
+ unsigned mbase_null = !(mask & 1);
+ unsigned side1_null = !(mask & 2);
+ unsigned side2_null = !(mask & 4);
+ unsigned side1_matches_mbase = (!side1_null && !mbase_null &&
+ names[0].mode == names[1].mode &&
+ oideq(&names[0].oid, &names[1].oid));
+ unsigned side2_matches_mbase = (!side2_null && !mbase_null &&
+ names[0].mode == names[2].mode &&
+ oideq(&names[0].oid, &names[2].oid));
+ unsigned sides_match = (!side1_null && !side2_null &&
+ names[1].mode == names[2].mode &&
+ oideq(&names[1].oid, &names[2].oid));
+
+ /*
+ * Note: When a path is a file on one side of history and a directory
+ * in another, we have a directory/file conflict. In such cases, if
+ * the conflict doesn't resolve from renames and deletions, then we
+ * always leave directories where they are and move files out of the
+ * way. Thus, while struct conflict_info has a df_conflict field to
+ * track such conflicts, we ignore that field for any directories at
+ * a path and only pay attention to it for files at the given path.
+ * The fact that we leave directories were they are also means that
+ * we do not need to worry about getting additional df_conflict
+ * information propagated from parent directories down to children
+ * (unlike, say traverse_trees_recursive() in unpack-trees.c, which
+ * sets a newinfo.df_conflicts field specifically to propagate it).
+ */
+ unsigned df_conflict = (filemask != 0) && (dirmask != 0);
+
+ /* n = 3 is a fundamental assumption. */
+ if (n != 3)
+ BUG("Called collect_merge_info_callback wrong");
+
+ /*
+ * A bunch of sanity checks verifying that traverse_trees() calls
+ * us the way I expect. Could just remove these at some point,
+ * though maybe they are helpful to future code readers.
+ */
+ assert(mbase_null == is_null_oid(&names[0].oid));
+ assert(side1_null == is_null_oid(&names[1].oid));
+ assert(side2_null == is_null_oid(&names[2].oid));
+ assert(!mbase_null || !side1_null || !side2_null);
+ assert(mask > 0 && mask < 8);
+
+ /* Determine match_mask */
+ if (side1_matches_mbase)
+ match_mask = (side2_matches_mbase ? 7 : 3);
+ else if (side2_matches_mbase)
+ match_mask = 5;
+ else if (sides_match)
+ match_mask = 6;
+
+ /*
+ * Get the name of the relevant filepath, which we'll pass to
+ * setup_path_info() for tracking.
+ */
+ p = names;
+ while (!p->mode)
+ p++;
+ len = traverse_path_len(info, p->pathlen);
+
+ /* +1 in both of the following lines to include the NUL byte */
+ fullpath = xmalloc(len + 1);
+ make_traverse_path(fullpath, len + 1, info, p->path, p->pathlen);
+
+ /*
+ * If mbase, side1, and side2 all match, we can resolve early. Even
+ * if these are trees, there will be no renames or anything
+ * underneath.
+ */
+ if (side1_matches_mbase && side2_matches_mbase) {
+ /* mbase, side1, & side2 all match; use mbase as resolution */
+ setup_path_info(opt, &pi, dirname, info->pathlen, fullpath,
+ names, names+0, mbase_null, 0,
+ filemask, dirmask, 1);
+ return mask;
+ }
+
+ /*
+ * Record information about the path so we can resolve later in
+ * process_entries.
+ */
+ setup_path_info(opt, &pi, dirname, info->pathlen, fullpath,
+ names, NULL, 0, df_conflict, filemask, dirmask, 0);
+
+ ci = pi.util;
+ VERIFY_CI(ci);
+ ci->match_mask = match_mask;
+
+ /* If dirmask, recurse into subdirectories */
+ if (dirmask) {
+ struct traverse_info newinfo;
+ struct tree_desc t[3];
+ void *buf[3] = {NULL, NULL, NULL};
+ const char *original_dir_name;
+ int i, ret;
+
+ ci->match_mask &= filemask;
+ newinfo = *info;
+ newinfo.prev = info;
+ newinfo.name = p->path;
+ newinfo.namelen = p->pathlen;
+ newinfo.pathlen = st_add3(newinfo.pathlen, p->pathlen, 1);
+ /*
+ * If this directory we are about to recurse into cared about
+ * its parent directory (the current directory) having a D/F
+ * conflict, then we'd propagate the masks in this way:
+ * newinfo.df_conflicts |= (mask & ~dirmask);
+ * But we don't worry about propagating D/F conflicts. (See
+ * comment near setting of local df_conflict variable near
+ * the beginning of this function).
+ */
+
+ for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
+ if (i == 1 && side1_matches_mbase)
+ t[1] = t[0];
+ else if (i == 2 && side2_matches_mbase)
+ t[2] = t[0];
+ else if (i == 2 && sides_match)
+ t[2] = t[1];
+ else {
+ const struct object_id *oid = NULL;
+ if (dirmask & 1)
+ oid = &names[i].oid;
+ buf[i] = fill_tree_descriptor(opt->repo,
+ t + i, oid);
+ }
+ dirmask >>= 1;
+ }
+
+ original_dir_name = opti->current_dir_name;
+ opti->current_dir_name = pi.string;
+ ret = traverse_trees(NULL, 3, t, &newinfo);
+ opti->current_dir_name = original_dir_name;
+
+ for (i = MERGE_BASE; i <= MERGE_SIDE2; i++)
+ free(buf[i]);
+
+ if (ret < 0)
+ return -1;
+ }
+
+ return mask;
+}
+
+static int collect_merge_info(struct merge_options *opt,
+ struct tree *merge_base,
+ struct tree *side1,
+ struct tree *side2)
+{
+ int ret;
+ struct tree_desc t[3];
+ struct traverse_info info;
+ const char *toplevel_dir_placeholder = "";
+
+ opt->priv->current_dir_name = toplevel_dir_placeholder;
+ setup_traverse_info(&info, toplevel_dir_placeholder);
+ info.fn = collect_merge_info_callback;
+ info.data = opt;
+ info.show_all_errors = 1;
+
+ parse_tree(merge_base);
+ parse_tree(side1);
+ parse_tree(side2);
+ init_tree_desc(t + 0, merge_base->buffer, merge_base->size);
+ init_tree_desc(t + 1, side1->buffer, side1->size);
+ init_tree_desc(t + 2, side2->buffer, side2->size);
+
+ ret = traverse_trees(NULL, 3, t, &info);
+
+ return ret;
+}
+
+/*** Function Grouping: functions related to threeway content merges ***/
+
+static int handle_content_merge(struct merge_options *opt,
+ const char *path,
+ const struct version_info *o,
+ const struct version_info *a,
+ const struct version_info *b,
+ const char *pathnames[3],
+ const int extra_marker_size,
+ struct version_info *result)
+{
+ die("Not yet implemented");
+}
+
+/*** Function Grouping: functions related to detect_and_process_renames(), ***
+ *** which are split into directory and regular rename detection sections. ***/
+
+/*** Function Grouping: functions related to directory rename detection ***/
+
+/*** Function Grouping: functions related to regular rename detection ***/
+
+static int process_renames(struct merge_options *opt,
+ struct diff_queue_struct *renames)
+{
+ int clean_merge = 1, i;
+
+ for (i = 0; i < renames->nr; ++i) {
+ const char *oldpath = NULL, *newpath;
+ struct diff_filepair *pair = renames->queue[i];
+ struct conflict_info *oldinfo = NULL, *newinfo = NULL;
+ struct strmap_entry *old_ent, *new_ent;
+ unsigned int old_sidemask;
+ int target_index, other_source_index;
+ int source_deleted, collision, type_changed;
+ const char *rename_branch = NULL, *delete_branch = NULL;
+
+ old_ent = strmap_get_entry(&opt->priv->paths, pair->one->path);
+ oldpath = old_ent->key;
+ oldinfo = old_ent->value;
+
+ new_ent = strmap_get_entry(&opt->priv->paths, pair->two->path);
+ newpath = new_ent->key;
+ newinfo = new_ent->value;
+
+ /*
+ * diff_filepairs have copies of pathnames, thus we have to
+ * use standard 'strcmp()' (negated) instead of '=='.
+ */
+ if (i + 1 < renames->nr &&
+ !strcmp(oldpath, renames->queue[i+1]->one->path)) {
+ /* Handle rename/rename(1to2) or rename/rename(1to1) */
+ const char *pathnames[3];
+ struct version_info merged;
+ struct conflict_info *base, *side1, *side2;
+ unsigned was_binary_blob = 0;
+
+ pathnames[0] = oldpath;
+ pathnames[1] = newpath;
+ pathnames[2] = renames->queue[i+1]->two->path;
+
+ base = strmap_get(&opt->priv->paths, pathnames[0]);
+ side1 = strmap_get(&opt->priv->paths, pathnames[1]);
+ side2 = strmap_get(&opt->priv->paths, pathnames[2]);
+
+ VERIFY_CI(base);
+ VERIFY_CI(side1);
+ VERIFY_CI(side2);
+
+ if (!strcmp(pathnames[1], pathnames[2])) {
+ /* Both sides renamed the same way */
+ assert(side1 == side2);
+ memcpy(&side1->stages[0], &base->stages[0],
+ sizeof(merged));
+ side1->filemask |= (1 << MERGE_BASE);
+ /* Mark base as resolved by removal */
+ base->merged.is_null = 1;
+ base->merged.clean = 1;
+
+ /* We handled both renames, i.e. i+1 handled */
+ i++;
+ /* Move to next rename */
+ continue;
+ }
+
+ /* This is a rename/rename(1to2) */
+ clean_merge = handle_content_merge(opt,
+ pair->one->path,
+ &base->stages[0],
+ &side1->stages[1],
+ &side2->stages[2],
+ pathnames,
+ 1 + 2 * opt->priv->call_depth,
+ &merged);
+ if (!clean_merge &&
+ merged.mode == side1->stages[1].mode &&
+ oideq(&merged.oid, &side1->stages[1].oid))
+ was_binary_blob = 1;
+ memcpy(&side1->stages[1], &merged, sizeof(merged));
+ if (was_binary_blob) {
+ /*
+ * Getting here means we were attempting to
+ * merge a binary blob.
+ *
+ * Since we can't merge binaries,
+ * handle_content_merge() just takes one
+ * side. But we don't want to copy the
+ * contents of one side to both paths. We
+ * used the contents of side1 above for
+ * side1->stages, let's use the contents of
+ * side2 for side2->stages below.
+ */
+ oidcpy(&merged.oid, &side2->stages[2].oid);
+ merged.mode = side2->stages[2].mode;
+ }
+ memcpy(&side2->stages[2], &merged, sizeof(merged));
+
+ side1->path_conflict = 1;
+ side2->path_conflict = 1;
+ /*
+ * TODO: For renames we normally remove the path at the
+ * old name. It would thus seem consistent to do the
+ * same for rename/rename(1to2) cases, but we haven't
+ * done so traditionally and a number of the regression
+ * tests now encode an expectation that the file is
+ * left there at stage 1. If we ever decide to change
+ * this, add the following two lines here:
+ * base->merged.is_null = 1;
+ * base->merged.clean = 1;
+ * and remove the setting of base->path_conflict to 1.
+ */
+ base->path_conflict = 1;
+ path_msg(opt, oldpath, 0,
+ _("CONFLICT (rename/rename): %s renamed to "
+ "%s in %s and to %s in %s."),
+ pathnames[0],
+ pathnames[1], opt->branch1,
+ pathnames[2], opt->branch2);
+
+ i++; /* We handled both renames, i.e. i+1 handled */
+ continue;
+ }
+
+ VERIFY_CI(oldinfo);
+ VERIFY_CI(newinfo);
+ target_index = pair->score; /* from collect_renames() */
+ assert(target_index == 1 || target_index == 2);
+ other_source_index = 3 - target_index;
+ old_sidemask = (1 << other_source_index); /* 2 or 4 */
+ source_deleted = (oldinfo->filemask == 1);
+ collision = ((newinfo->filemask & old_sidemask) != 0);
+ type_changed = !source_deleted &&
+ (S_ISREG(oldinfo->stages[other_source_index].mode) !=
+ S_ISREG(newinfo->stages[target_index].mode));
+ if (type_changed && collision) {
+ /*
+ * special handling so later blocks can handle this...
+ *
+ * if type_changed && collision are both true, then this
+ * was really a double rename, but one side wasn't
+ * detected due to lack of break detection. I.e.
+ * something like
+ * orig: has normal file 'foo'
+ * side1: renames 'foo' to 'bar', adds 'foo' symlink
+ * side2: renames 'foo' to 'bar'
+ * In this case, the foo->bar rename on side1 won't be
+ * detected because the new symlink named 'foo' is
+ * there and we don't do break detection. But we detect
+ * this here because we don't want to merge the content
+ * of the foo symlink with the foo->bar file, so we
+ * have some logic to handle this special case. The
+ * easiest way to do that is make 'bar' on side1 not
+ * be considered a colliding file but the other part
+ * of a normal rename. If the file is very different,
+ * well we're going to get content merge conflicts
+ * anyway so it doesn't hurt. And if the colliding
+ * file also has a different type, that'll be handled
+ * by the content merge logic in process_entry() too.
+ *
+ * See also t6430, 'rename vs. rename/symlink'
+ */
+ collision = 0;
+ }
+ if (source_deleted) {
+ if (target_index == 1) {
+ rename_branch = opt->branch1;
+ delete_branch = opt->branch2;
+ } else {
+ rename_branch = opt->branch2;
+ delete_branch = opt->branch1;
+ }
+ }
+
+ assert(source_deleted || oldinfo->filemask & old_sidemask);
+
+ /* Need to check for special types of rename conflicts... */
+ if (collision && !source_deleted) {
+ /* collision: rename/add or rename/rename(2to1) */
+ const char *pathnames[3];
+ struct version_info merged;
+
+ struct conflict_info *base, *side1, *side2;
+ unsigned clean;
+
+ pathnames[0] = oldpath;
+ pathnames[other_source_index] = oldpath;
+ pathnames[target_index] = newpath;
+
+ base = strmap_get(&opt->priv->paths, pathnames[0]);
+ side1 = strmap_get(&opt->priv->paths, pathnames[1]);
+ side2 = strmap_get(&opt->priv->paths, pathnames[2]);
+
+ VERIFY_CI(base);
+ VERIFY_CI(side1);
+ VERIFY_CI(side2);
+
+ clean = handle_content_merge(opt, pair->one->path,
+ &base->stages[0],
+ &side1->stages[1],
+ &side2->stages[2],
+ pathnames,
+ 1 + 2 * opt->priv->call_depth,
+ &merged);
+
+ memcpy(&newinfo->stages[target_index], &merged,
+ sizeof(merged));
+ if (!clean) {
+ path_msg(opt, newpath, 0,
+ _("CONFLICT (rename involved in "
+ "collision): rename of %s -> %s has "
+ "content conflicts AND collides "
+ "with another path; this may result "
+ "in nested conflict markers."),
+ oldpath, newpath);
+ }
+ } else if (collision && source_deleted) {
+ /*
+ * rename/add/delete or rename/rename(2to1)/delete:
+ * since oldpath was deleted on the side that didn't
+ * do the rename, there's not much of a content merge
+ * we can do for the rename. oldinfo->merged.is_null
+ * was already set, so we just leave things as-is so
+ * they look like an add/add conflict.
+ */
+
+ newinfo->path_conflict = 1;
+ path_msg(opt, newpath, 0,
+ _("CONFLICT (rename/delete): %s renamed "
+ "to %s in %s, but deleted in %s."),
+ oldpath, newpath, rename_branch, delete_branch);
+ } else {
+ /*
+ * a few different cases...start by copying the
+ * existing stage(s) from oldinfo over the newinfo
+ * and update the pathname(s).
+ */
+ memcpy(&newinfo->stages[0], &oldinfo->stages[0],
+ sizeof(newinfo->stages[0]));
+ newinfo->filemask |= (1 << MERGE_BASE);
+ newinfo->pathnames[0] = oldpath;
+ if (type_changed) {
+ /* rename vs. typechange */
+ /* Mark the original as resolved by removal */
+ memcpy(&oldinfo->stages[0].oid, &null_oid,
+ sizeof(oldinfo->stages[0].oid));
+ oldinfo->stages[0].mode = 0;
+ oldinfo->filemask &= 0x06;
+ } else if (source_deleted) {
+ /* rename/delete */
+ newinfo->path_conflict = 1;
+ path_msg(opt, newpath, 0,
+ _("CONFLICT (rename/delete): %s renamed"
+ " to %s in %s, but deleted in %s."),
+ oldpath, newpath,
+ rename_branch, delete_branch);
+ } else {
+ /* normal rename */
+ memcpy(&newinfo->stages[other_source_index],
+ &oldinfo->stages[other_source_index],
+ sizeof(newinfo->stages[0]));
+ newinfo->filemask |= (1 << other_source_index);
+ newinfo->pathnames[other_source_index] = oldpath;
+ }
+ }
+
+ if (!type_changed) {
+ /* Mark the original as resolved by removal */
+ oldinfo->merged.is_null = 1;
+ oldinfo->merged.clean = 1;
+ }
+
+ }
+
+ return clean_merge;
+}
+
+static int compare_pairs(const void *a_, const void *b_)
+{
+ const struct diff_filepair *a = *((const struct diff_filepair **)a_);
+ const struct diff_filepair *b = *((const struct diff_filepair **)b_);
+
+ return strcmp(a->one->path, b->one->path);
+}
+
+/* Call diffcore_rename() to compute which files have changed on given side */
+static void detect_regular_renames(struct merge_options *opt,
+ struct tree *merge_base,
+ struct tree *side,
+ unsigned side_index)
+{
+ struct diff_options diff_opts;
+ struct rename_info *renames = &opt->priv->renames;
+
+ repo_diff_setup(opt->repo, &diff_opts);
+ diff_opts.flags.recursive = 1;
+ diff_opts.flags.rename_empty = 0;
+ diff_opts.detect_rename = DIFF_DETECT_RENAME;
+ diff_opts.rename_limit = opt->rename_limit;
+ if (opt->rename_limit <= 0)
+ diff_opts.rename_limit = 1000;
+ diff_opts.rename_score = opt->rename_score;
+ diff_opts.show_rename_progress = opt->show_rename_progress;
+ diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+ diff_setup_done(&diff_opts);
+ diff_tree_oid(&merge_base->object.oid, &side->object.oid, "",
+ &diff_opts);
+ diffcore_std(&diff_opts);
+
+ if (diff_opts.needed_rename_limit > renames->needed_limit)
+ renames->needed_limit = diff_opts.needed_rename_limit;
+
+ renames->pairs[side_index] = diff_queued_diff;
+
+ diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+ diff_queued_diff.nr = 0;
+ diff_queued_diff.queue = NULL;
+ diff_flush(&diff_opts);
+}
+
+/*
+ * Get information of all renames which occurred in 'side_pairs', discarding
+ * non-renames.
+ */
+static int collect_renames(struct merge_options *opt,
+ struct diff_queue_struct *result,
+ unsigned side_index)
+{
+ int i, clean = 1;
+ struct diff_queue_struct *side_pairs;
+ struct rename_info *renames = &opt->priv->renames;
+
+ side_pairs = &renames->pairs[side_index];
+
+ for (i = 0; i < side_pairs->nr; ++i) {
+ struct diff_filepair *p = side_pairs->queue[i];
+
+ if (p->status != 'R') {
+ diff_free_filepair(p);
+ continue;
+ }
+
+ /*
+ * p->score comes back from diffcore_rename_extended() with
+ * the similarity of the renamed file. The similarity is
+ * was used to determine that the two files were related
+ * and are a rename, which we have already used, but beyond
+ * that we have no use for the similarity. So p->score is
+ * now irrelevant. However, process_renames() will need to
+ * know which side of the merge this rename was associated
+ * with, so overwrite p->score with that value.
+ */
+ p->score = side_index;
+ result->queue[result->nr++] = p;
+ }
+
+ return clean;
+}
+
+static int detect_and_process_renames(struct merge_options *opt,
+ struct tree *merge_base,
+ struct tree *side1,
+ struct tree *side2)
+{
+ struct diff_queue_struct combined;
+ struct rename_info *renames = &opt->priv->renames;
+ int s, clean = 1;
+
+ memset(&combined, 0, sizeof(combined));
+
+ detect_regular_renames(opt, merge_base, side1, MERGE_SIDE1);
+ detect_regular_renames(opt, merge_base, side2, MERGE_SIDE2);
+
+ ALLOC_GROW(combined.queue,
+ renames->pairs[1].nr + renames->pairs[2].nr,
+ combined.alloc);
+ clean &= collect_renames(opt, &combined, MERGE_SIDE1);
+ clean &= collect_renames(opt, &combined, MERGE_SIDE2);
+ QSORT(combined.queue, combined.nr, compare_pairs);
+
+ clean &= process_renames(opt, &combined);
+
+ /* Free memory for renames->pairs[] and combined */
+ for (s = MERGE_SIDE1; s <= MERGE_SIDE2; s++) {
+ free(renames->pairs[s].queue);
+ DIFF_QUEUE_CLEAR(&renames->pairs[s]);
+ }
+ if (combined.nr) {
+ int i;
+ for (i = 0; i < combined.nr; i++)
+ diff_free_filepair(combined.queue[i]);
+ free(combined.queue);
+ }
+
+ return clean;
+}
+
+/*** Function Grouping: functions related to process_entries() ***/
+
+static int string_list_df_name_compare(const char *one, const char *two)
+{
+ int onelen = strlen(one);
+ int twolen = strlen(two);
+ /*
+ * Here we only care that entries for D/F conflicts are
+ * adjacent, in particular with the file of the D/F conflict
+ * appearing before files below the corresponding directory.
+ * The order of the rest of the list is irrelevant for us.
+ *
+ * To achieve this, we sort with df_name_compare and provide
+ * the mode S_IFDIR so that D/F conflicts will sort correctly.
+ * We use the mode S_IFDIR for everything else for simplicity,
+ * since in other cases any changes in their order due to
+ * sorting cause no problems for us.
+ */
+ int cmp = df_name_compare(one, onelen, S_IFDIR,
+ two, twolen, S_IFDIR);
+ /*
+ * Now that 'foo' and 'foo/bar' compare equal, we have to make sure
+ * that 'foo' comes before 'foo/bar'.
+ */
+ if (cmp)
+ return cmp;
+ return onelen - twolen;
+}
+
+struct directory_versions {
+ /*
+ * versions: list of (basename -> version_info)
+ *
+ * The basenames are in reverse lexicographic order of full pathnames,
+ * as processed in process_entries(). This puts all entries within
+ * a directory together, and covers the directory itself after
+ * everything within it, allowing us to write subtrees before needing
+ * to record information for the tree itself.
+ */
+ struct string_list versions;
+
+ /*
+ * offsets: list of (full relative path directories -> integer offsets)
+ *
+ * Since versions contains basenames from files in multiple different
+ * directories, we need to know which entries in versions correspond
+ * to which directories. Values of e.g.
+ * "" 0
+ * src 2
+ * src/moduleA 5
+ * Would mean that entries 0-1 of versions are files in the toplevel
+ * directory, entries 2-4 are files under src/, and the remaining
+ * entries starting at index 5 are files under src/moduleA/.
+ */
+ struct string_list offsets;
+
+ /*
+ * last_directory: directory that previously processed file found in
+ *
+ * last_directory starts NULL, but records the directory in which the
+ * previous file was found within. As soon as
+ * directory(current_file) != last_directory
+ * then we need to start updating accounting in versions & offsets.
+ * Note that last_directory is always the last path in "offsets" (or
+ * NULL if "offsets" is empty) so this exists just for quick access.
+ */
+ const char *last_directory;
+
+ /* last_directory_len: cached computation of strlen(last_directory) */
+ unsigned last_directory_len;
+};
+
+static int tree_entry_order(const void *a_, const void *b_)
+{
+ const struct string_list_item *a = a_;
+ const struct string_list_item *b = b_;
+
+ const struct merged_info *ami = a->util;
+ const struct merged_info *bmi = b->util;
+ return base_name_compare(a->string, strlen(a->string), ami->result.mode,
+ b->string, strlen(b->string), bmi->result.mode);
+}
+
+static void write_tree(struct object_id *result_oid,
+ struct string_list *versions,
+ unsigned int offset,
+ size_t hash_size)
+{
+ size_t maxlen = 0, extra;
+ unsigned int nr = versions->nr - offset;
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list relevant_entries = STRING_LIST_INIT_NODUP;
+ int i;
+
+ /*
+ * We want to sort the last (versions->nr-offset) entries in versions.
+ * Do so by abusing the string_list API a bit: make another string_list
+ * that contains just those entries and then sort them.
+ *
+ * We won't use relevant_entries again and will let it just pop off the
+ * stack, so there won't be allocation worries or anything.
+ */
+ relevant_entries.items = versions->items + offset;
+ relevant_entries.nr = versions->nr - offset;
+ QSORT(relevant_entries.items, relevant_entries.nr, tree_entry_order);
+
+ /* Pre-allocate some space in buf */
+ extra = hash_size + 8; /* 8: 6 for mode, 1 for space, 1 for NUL char */
+ for (i = 0; i < nr; i++) {
+ maxlen += strlen(versions->items[offset+i].string) + extra;
+ }
+ strbuf_grow(&buf, maxlen);
+
+ /* Write each entry out to buf */
+ for (i = 0; i < nr; i++) {
+ struct merged_info *mi = versions->items[offset+i].util;
+ struct version_info *ri = &mi->result;
+ strbuf_addf(&buf, "%o %s%c",
+ ri->mode,
+ versions->items[offset+i].string, '\0');
+ strbuf_add(&buf, ri->oid.hash, hash_size);
+ }
+
+ /* Write this object file out, and record in result_oid */
+ write_object_file(buf.buf, buf.len, tree_type, result_oid);
+ strbuf_release(&buf);
+}
+
+static void record_entry_for_tree(struct directory_versions *dir_metadata,
+ const char *path,
+ struct merged_info *mi)
+{
+ const char *basename;
+
+ if (mi->is_null)
+ /* nothing to record */
+ return;
+
+ basename = path + mi->basename_offset;
+ assert(strchr(basename, '/') == NULL);
+ string_list_append(&dir_metadata->versions,
+ basename)->util = &mi->result;
+}
+
+static void write_completed_directory(struct merge_options *opt,
+ const char *new_directory_name,
+ struct directory_versions *info)
+{
+ const char *prev_dir;
+ struct merged_info *dir_info = NULL;
+ unsigned int offset;
+
+ /*
+ * Some explanation of info->versions and info->offsets...
+ *
+ * process_entries() iterates over all relevant files AND
+ * directories in reverse lexicographic order, and calls this
+ * function. Thus, an example of the paths that process_entries()
+ * could operate on (along with the directories for those paths
+ * being shown) is:
+ *
+ * xtract.c ""
+ * tokens.txt ""
+ * src/moduleB/umm.c src/moduleB
+ * src/moduleB/stuff.h src/moduleB
+ * src/moduleB/baz.c src/moduleB
+ * src/moduleB src
+ * src/moduleA/foo.c src/moduleA
+ * src/moduleA/bar.c src/moduleA
+ * src/moduleA src
+ * src ""
+ * Makefile ""
+ *
+ * info->versions:
+ *
+ * always contains the unprocessed entries and their
+ * version_info information. For example, after the first five
+ * entries above, info->versions would be:
+ *
+ * xtract.c <xtract.c's version_info>
+ * token.txt <token.txt's version_info>
+ * umm.c <src/moduleB/umm.c's version_info>
+ * stuff.h <src/moduleB/stuff.h's version_info>
+ * baz.c <src/moduleB/baz.c's version_info>
+ *
+ * Once a subdirectory is completed we remove the entries in
+ * that subdirectory from info->versions, writing it as a tree
+ * (write_tree()). Thus, as soon as we get to src/moduleB,
+ * info->versions would be updated to
+ *
+ * xtract.c <xtract.c's version_info>
+ * token.txt <token.txt's version_info>
+ * moduleB <src/moduleB's version_info>
+ *
+ * info->offsets:
+ *
+ * helps us track which entries in info->versions correspond to
+ * which directories. When we are N directories deep (e.g. 4
+ * for src/modA/submod/subdir/), we have up to N+1 unprocessed
+ * directories (+1 because of toplevel dir). Corresponding to
+ * the info->versions example above, after processing five entries
+ * info->offsets will be:
+ *
+ * "" 0
+ * src/moduleB 2
+ *
+ * which is used to know that xtract.c & token.txt are from the
+ * toplevel dirctory, while umm.c & stuff.h & baz.c are from the
+ * src/moduleB directory. Again, following the example above,
+ * once we need to process src/moduleB, then info->offsets is
+ * updated to
+ *
+ * "" 0
+ * src 2
+ *
+ * which says that moduleB (and only moduleB so far) is in the
+ * src directory.
+ *
+ * One unique thing to note about info->offsets here is that
+ * "src" was not added to info->offsets until there was a path
+ * (a file OR directory) immediately below src/ that got
+ * processed.
+ *
+ * Since process_entry() just appends new entries to info->versions,
+ * write_completed_directory() only needs to do work if the next path
+ * is in a directory that is different than the last directory found
+ * in info->offsets.
+ */
+
+ /*
+ * If we are working with the same directory as the last entry, there
+ * is no work to do. (See comments above the directory_name member of
+ * struct merged_info for why we can use pointer comparison instead of
+ * strcmp here.)
+ */
+ if (new_directory_name == info->last_directory)
+ return;
+
+ /*
+ * If we are just starting (last_directory is NULL), or last_directory
+ * is a prefix of the current directory, then we can just update
+ * info->offsets to record the offset where we started this directory
+ * and update last_directory to have quick access to it.
+ */
+ if (info->last_directory == NULL ||
+ !strncmp(new_directory_name, info->last_directory,
+ info->last_directory_len)) {
+ uintptr_t offset = info->versions.nr;
+
+ info->last_directory = new_directory_name;
+ info->last_directory_len = strlen(info->last_directory);
+ /*
+ * Record the offset into info->versions where we will
+ * start recording basenames of paths found within
+ * new_directory_name.
+ */
+ string_list_append(&info->offsets,
+ info->last_directory)->util = (void*)offset;
+ return;
+ }
+
+ /*
+ * The next entry that will be processed will be within
+ * new_directory_name. Since at this point we know that
+ * new_directory_name is within a different directory than
+ * info->last_directory, we have all entries for info->last_directory
+ * in info->versions and we need to create a tree object for them.
+ */
+ dir_info = strmap_get(&opt->priv->paths, info->last_directory);
+ assert(dir_info);
+ offset = (uintptr_t)info->offsets.items[info->offsets.nr-1].util;
+ if (offset == info->versions.nr) {
+ /*
+ * Actually, we don't need to create a tree object in this
+ * case. Whenever all files within a directory disappear
+ * during the merge (e.g. unmodified on one side and
+ * deleted on the other, or files were renamed elsewhere),
+ * then we get here and the directory itself needs to be
+ * omitted from its parent tree as well.
+ */
+ dir_info->is_null = 1;
+ } else {
+ /*
+ * Write out the tree to the git object directory, and also
+ * record the mode and oid in dir_info->result.
+ */
+ dir_info->is_null = 0;
+ dir_info->result.mode = S_IFDIR;
+ write_tree(&dir_info->result.oid, &info->versions, offset,
+ opt->repo->hash_algo->rawsz);
+ }
+
+ /*
+ * We've now used several entries from info->versions and one entry
+ * from info->offsets, so we get rid of those values.
+ */
+ info->offsets.nr--;
+ info->versions.nr = offset;
+
+ /*
+ * Now we've taken care of the completed directory, but we need to
+ * prepare things since future entries will be in
+ * new_directory_name. (In particular, process_entry() will be
+ * appending new entries to info->versions.) So, we need to make
+ * sure new_directory_name is the last entry in info->offsets.
+ */
+ prev_dir = info->offsets.nr == 0 ? NULL :
+ info->offsets.items[info->offsets.nr-1].string;
+ if (new_directory_name != prev_dir) {
+ uintptr_t c = info->versions.nr;
+ string_list_append(&info->offsets,
+ new_directory_name)->util = (void*)c;
+ }
+
+ /* And, of course, we need to update last_directory to match. */
+ info->last_directory = new_directory_name;
+ info->last_directory_len = strlen(info->last_directory);
+}
+
+/* Per entry merge function */
+static void process_entry(struct merge_options *opt,
+ const char *path,
+ struct conflict_info *ci,
+ struct directory_versions *dir_metadata)
+{
+ VERIFY_CI(ci);
+ assert(ci->filemask >= 0 && ci->filemask <= 7);
+ /* ci->match_mask == 7 was handled in collect_merge_info_callback() */
+ assert(ci->match_mask == 0 || ci->match_mask == 3 ||
+ ci->match_mask == 5 || ci->match_mask == 6);
+
+ if (ci->dirmask) {
+ record_entry_for_tree(dir_metadata, path, &ci->merged);
+ if (ci->filemask == 0)
+ /* nothing else to handle */
+ return;
+ assert(ci->df_conflict);
+ }
+
+ if (ci->df_conflict) {
+ die("Not yet implemented.");
+ }
+
+ /*
+ * NOTE: Below there is a long switch-like if-elseif-elseif... block
+ * which the code goes through even for the df_conflict cases
+ * above. Well, it will once we don't die-not-implemented above.
+ */
+ if (ci->match_mask) {
+ ci->merged.clean = 1;
+ if (ci->match_mask == 6) {
+ /* stages[1] == stages[2] */
+ ci->merged.result.mode = ci->stages[1].mode;
+ oidcpy(&ci->merged.result.oid, &ci->stages[1].oid);
+ } else {
+ /* determine the mask of the side that didn't match */
+ unsigned int othermask = 7 & ~ci->match_mask;
+ int side = (othermask == 4) ? 2 : 1;
+
+ ci->merged.result.mode = ci->stages[side].mode;
+ ci->merged.is_null = !ci->merged.result.mode;
+ oidcpy(&ci->merged.result.oid, &ci->stages[side].oid);
+
+ assert(othermask == 2 || othermask == 4);
+ assert(ci->merged.is_null ==
+ (ci->filemask == ci->match_mask));
+ }
+ } else if (ci->filemask >= 6 &&
+ (S_IFMT & ci->stages[1].mode) !=
+ (S_IFMT & ci->stages[2].mode)) {
+ /*
+ * Two different items from (file/submodule/symlink)
+ */
+ die("Not yet implemented.");
+ } else if (ci->filemask >= 6) {
+ /*
+ * TODO: Needs a two-way or three-way content merge, but we're
+ * just being lazy and copying the version from HEAD and
+ * leaving it as conflicted.
+ */
+ ci->merged.clean = 0;
+ ci->merged.result.mode = ci->stages[1].mode;
+ oidcpy(&ci->merged.result.oid, &ci->stages[1].oid);
+ /* When we fix above, we'll call handle_content_merge() */
+ (void)handle_content_merge;
+ } else if (ci->filemask == 3 || ci->filemask == 5) {
+ /* Modify/delete */
+ const char *modify_branch, *delete_branch;
+ int side = (ci->filemask == 5) ? 2 : 1;
+ int index = opt->priv->call_depth ? 0 : side;
+
+ ci->merged.result.mode = ci->stages[index].mode;
+ oidcpy(&ci->merged.result.oid, &ci->stages[index].oid);
+ ci->merged.clean = 0;
+
+ modify_branch = (side == 1) ? opt->branch1 : opt->branch2;
+ delete_branch = (side == 1) ? opt->branch2 : opt->branch1;
+
+ if (ci->path_conflict &&
+ oideq(&ci->stages[0].oid, &ci->stages[side].oid)) {
+ /*
+ * This came from a rename/delete; no action to take,
+ * but avoid printing "modify/delete" conflict notice
+ * since the contents were not modified.
+ */
+ } else {
+ path_msg(opt, path, 0,
+ _("CONFLICT (modify/delete): %s deleted in %s "
+ "and modified in %s. Version %s of %s left "
+ "in tree."),
+ path, delete_branch, modify_branch,
+ modify_branch, path);
+ }
+ } else if (ci->filemask == 2 || ci->filemask == 4) {
+ /* Added on one side */
+ int side = (ci->filemask == 4) ? 2 : 1;
+ ci->merged.result.mode = ci->stages[side].mode;
+ oidcpy(&ci->merged.result.oid, &ci->stages[side].oid);
+ ci->merged.clean = !ci->df_conflict && !ci->path_conflict;
+ } else if (ci->filemask == 1) {
+ /* Deleted on both sides */
+ ci->merged.is_null = 1;
+ ci->merged.result.mode = 0;
+ oidcpy(&ci->merged.result.oid, &null_oid);
+ ci->merged.clean = !ci->path_conflict;
+ }
+
+ /*
+ * If still conflicted, record it separately. This allows us to later
+ * iterate over just conflicted entries when updating the index instead
+ * of iterating over all entries.
+ */
+ if (!ci->merged.clean)
+ strmap_put(&opt->priv->conflicted, path, ci);
+ record_entry_for_tree(dir_metadata, path, &ci->merged);
+}
+
+static void process_entries(struct merge_options *opt,
+ struct object_id *result_oid)
+{
+ struct hashmap_iter iter;
+ struct strmap_entry *e;
+ struct string_list plist = STRING_LIST_INIT_NODUP;
+ struct string_list_item *entry;
+ struct directory_versions dir_metadata = { STRING_LIST_INIT_NODUP,
+ STRING_LIST_INIT_NODUP,
+ NULL, 0 };
+
+ if (strmap_empty(&opt->priv->paths)) {
+ oidcpy(result_oid, opt->repo->hash_algo->empty_tree);
+ return;
+ }
+
+ /* Hack to pre-allocate plist to the desired size */
+ ALLOC_GROW(plist.items, strmap_get_size(&opt->priv->paths), plist.alloc);
+
+ /* Put every entry from paths into plist, then sort */
+ strmap_for_each_entry(&opt->priv->paths, &iter, e) {
+ string_list_append(&plist, e->key)->util = e->value;
+ }
+ plist.cmp = string_list_df_name_compare;
+ string_list_sort(&plist);
+
+ /*
+ * Iterate over the items in reverse order, so we can handle paths
+ * below a directory before needing to handle the directory itself.
+ *
+ * This allows us to write subtrees before we need to write trees,
+ * and it also enables sane handling of directory/file conflicts
+ * (because it allows us to know whether the directory is still in
+ * the way when it is time to process the file at the same path).
+ */
+ for (entry = &plist.items[plist.nr-1]; entry >= plist.items; --entry) {
+ char *path = entry->string;
+ /*
+ * NOTE: mi may actually be a pointer to a conflict_info, but
+ * we have to check mi->clean first to see if it's safe to
+ * reassign to such a pointer type.
+ */
+ struct merged_info *mi = entry->util;
+
+ write_completed_directory(opt, mi->directory_name,
+ &dir_metadata);
+ if (mi->clean)
+ record_entry_for_tree(&dir_metadata, path, mi);
+ else {
+ struct conflict_info *ci = (struct conflict_info *)mi;
+ process_entry(opt, path, ci, &dir_metadata);
+ }
+ }
+
+ if (dir_metadata.offsets.nr != 1 ||
+ (uintptr_t)dir_metadata.offsets.items[0].util != 0) {
+ printf("dir_metadata.offsets.nr = %d (should be 1)\n",
+ dir_metadata.offsets.nr);
+ printf("dir_metadata.offsets.items[0].util = %u (should be 0)\n",
+ (unsigned)(uintptr_t)dir_metadata.offsets.items[0].util);
+ fflush(stdout);
+ BUG("dir_metadata accounting completely off; shouldn't happen");
+ }
+ write_tree(result_oid, &dir_metadata.versions, 0,
+ opt->repo->hash_algo->rawsz);
+ string_list_clear(&plist, 0);
+ string_list_clear(&dir_metadata.versions, 0);
+ string_list_clear(&dir_metadata.offsets, 0);
+}
+
+/*** Function Grouping: functions related to merge_switch_to_result() ***/
+
+static int checkout(struct merge_options *opt,
+ struct tree *prev,
+ struct tree *next)
+{
+ /* Switch the index/working copy from old to new */
+ int ret;
+ struct tree_desc trees[2];
+ struct unpack_trees_options unpack_opts;
+
+ memset(&unpack_opts, 0, sizeof(unpack_opts));
+ unpack_opts.head_idx = -1;
+ unpack_opts.src_index = opt->repo->index;
+ unpack_opts.dst_index = opt->repo->index;
+
+ setup_unpack_trees_porcelain(&unpack_opts, "merge");
+
+ /*
+ * NOTE: if this were just "git checkout" code, we would probably
+ * read or refresh the cache and check for a conflicted index, but
+ * builtin/merge.c or sequencer.c really needs to read the index
+ * and check for conflicted entries before starting merging for a
+ * good user experience (no sense waiting for merges/rebases before
+ * erroring out), so there's no reason to duplicate that work here.
+ */
+
+ /* 2-way merge to the new branch */
+ unpack_opts.update = 1;
+ unpack_opts.merge = 1;
+ unpack_opts.quiet = 0; /* FIXME: sequencer might want quiet? */
+ unpack_opts.verbose_update = (opt->verbosity > 2);
+ unpack_opts.fn = twoway_merge;
+ if (1/* FIXME: opts->overwrite_ignore*/) {
+ unpack_opts.dir = xcalloc(1, sizeof(*unpack_opts.dir));
+ unpack_opts.dir->flags |= DIR_SHOW_IGNORED;
+ setup_standard_excludes(unpack_opts.dir);
+ }
+ parse_tree(prev);
+ init_tree_desc(&trees[0], prev->buffer, prev->size);
+ parse_tree(next);
+ init_tree_desc(&trees[1], next->buffer, next->size);
+
+ ret = unpack_trees(2, trees, &unpack_opts);
+ clear_unpack_trees_porcelain(&unpack_opts);
+ dir_clear(unpack_opts.dir);
+ FREE_AND_NULL(unpack_opts.dir);
+ return ret;
+}
+
+static int record_conflicted_index_entries(struct merge_options *opt,
+ struct index_state *index,
+ struct strmap *paths,
+ struct strmap *conflicted)
+{
+ struct hashmap_iter iter;
+ struct strmap_entry *e;
+ int errs = 0;
+ int original_cache_nr;
+
+ if (strmap_empty(conflicted))
+ return 0;
+
+ original_cache_nr = index->cache_nr;
+
+ /* Put every entry from paths into plist, then sort */
+ strmap_for_each_entry(conflicted, &iter, e) {
+ const char *path = e->key;
+ struct conflict_info *ci = e->value;
+ int pos;
+ struct cache_entry *ce;
+ int i;
+
+ VERIFY_CI(ci);
+
+ /*
+ * The index will already have a stage=0 entry for this path,
+ * because we created an as-merged-as-possible version of the
+ * file and checkout() moved the working copy and index over
+ * to that version.
+ *
+ * However, previous iterations through this loop will have
+ * added unstaged entries to the end of the cache which
+ * ignore the standard alphabetical ordering of cache
+ * entries and break invariants needed for index_name_pos()
+ * to work. However, we know the entry we want is before
+ * those appended cache entries, so do a temporary swap on
+ * cache_nr to only look through entries of interest.
+ */
+ SWAP(index->cache_nr, original_cache_nr);
+ pos = index_name_pos(index, path, strlen(path));
+ SWAP(index->cache_nr, original_cache_nr);
+ if (pos < 0) {
+ if (ci->filemask != 1)
+ BUG("Conflicted %s but nothing in basic working tree or index; this shouldn't happen", path);
+ cache_tree_invalidate_path(index, path);
+ } else {
+ ce = index->cache[pos];
+
+ /*
+ * Clean paths with CE_SKIP_WORKTREE set will not be
+ * written to the working tree by the unpack_trees()
+ * call in checkout(). Our conflicted entries would
+ * have appeared clean to that code since we ignored
+ * the higher order stages. Thus, we need override
+ * the CE_SKIP_WORKTREE bit and manually write those
+ * files to the working disk here.
+ *
+ * TODO: Implement this CE_SKIP_WORKTREE fixup.
+ */
+
+ /*
+ * Mark this cache entry for removal and instead add
+ * new stage>0 entries corresponding to the
+ * conflicts. If there are many conflicted entries, we
+ * want to avoid memmove'ing O(NM) entries by
+ * inserting the new entries one at a time. So,
+ * instead, we just add the new cache entries to the
+ * end (ignoring normal index requirements on sort
+ * order) and sort the index once we're all done.
+ */
+ ce->ce_flags |= CE_REMOVE;
+ }
+
+ for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
+ struct version_info *vi;
+ if (!(ci->filemask & (1ul << i)))
+ continue;
+ vi = &ci->stages[i];
+ ce = make_cache_entry(index, vi->mode, &vi->oid,
+ path, i+1, 0);
+ add_index_entry(index, ce, ADD_CACHE_JUST_APPEND);
+ }
+ }
+
+ /*
+ * Remove the unused cache entries (and invalidate the relevant
+ * cache-trees), then sort the index entries to get the conflicted
+ * entries we added to the end into their right locations.
+ */
+ remove_marked_cache_entries(index, 1);
+ QSORT(index->cache, index->cache_nr, cmp_cache_name_compare);
+
+ return errs;
+}
+
void merge_switch_to_result(struct merge_options *opt,
struct tree *head,
struct merge_result *result,
int update_worktree_and_index,
int display_update_msgs)
{
- die("Not yet implemented");
+ assert(opt->priv == NULL);
+ if (result->clean >= 0 && update_worktree_and_index) {
+ struct merge_options_internal *opti = result->priv;
+
+ if (checkout(opt, head, result->tree)) {
+ /* failure to function */
+ result->clean = -1;
+ return;
+ }
+
+ if (record_conflicted_index_entries(opt, opt->repo->index,
+ &opti->paths,
+ &opti->conflicted)) {
+ /* failure to function */
+ result->clean = -1;
+ return;
+ }
+ }
+
+ if (display_update_msgs) {
+ struct merge_options_internal *opti = result->priv;
+ struct hashmap_iter iter;
+ struct strmap_entry *e;
+ struct string_list olist = STRING_LIST_INIT_NODUP;
+ int i;
+
+ /* Hack to pre-allocate olist to the desired size */
+ ALLOC_GROW(olist.items, strmap_get_size(&opti->output),
+ olist.alloc);
+
+ /* Put every entry from output into olist, then sort */
+ strmap_for_each_entry(&opti->output, &iter, e) {
+ string_list_append(&olist, e->key)->util = e->value;
+ }
+ string_list_sort(&olist);
+
+ /* Iterate over the items, printing them */
+ for (i = 0; i < olist.nr; ++i) {
+ struct strbuf *sb = olist.items[i].util;
+
+ printf("%s", sb->buf);
+ }
+ string_list_clear(&olist, 0);
+
+ /* Also include needed rename limit adjustment now */
+ diff_warn_rename_limit("merge.renamelimit",
+ opti->renames.needed_limit, 0);
+ }
+
merge_finalize(opt, result);
}
void merge_finalize(struct merge_options *opt,
struct merge_result *result)
{
- die("Not yet implemented");
+ struct merge_options_internal *opti = result->priv;
+
+ assert(opt->priv == NULL);
+
+ clear_or_reinit_internal_opts(opti, 0);
+ FREE_AND_NULL(opti);
+}
+
+/*** Function Grouping: helper functions for merge_incore_*() ***/
+
+static inline void set_commit_tree(struct commit *c, struct tree *t)
+{
+ c->maybe_tree = t;
+}
+
+static struct commit *make_virtual_commit(struct repository *repo,
+ struct tree *tree,
+ const char *comment)
+{
+ struct commit *commit = alloc_commit_node(repo);
+
+ set_merge_remote_desc(commit, comment, (struct object *)commit);
+ set_commit_tree(commit, tree);
+ commit->object.parsed = 1;
+ return commit;
+}
+
+static void merge_start(struct merge_options *opt, struct merge_result *result)
+{
+ /* Sanity checks on opt */
+ assert(opt->repo);
+
+ assert(opt->branch1 && opt->branch2);
+
+ assert(opt->detect_directory_renames >= MERGE_DIRECTORY_RENAMES_NONE &&
+ opt->detect_directory_renames <= MERGE_DIRECTORY_RENAMES_TRUE);
+ assert(opt->rename_limit >= -1);
+ assert(opt->rename_score >= 0 && opt->rename_score <= MAX_SCORE);
+ assert(opt->show_rename_progress >= 0 && opt->show_rename_progress <= 1);
+
+ assert(opt->xdl_opts >= 0);
+ assert(opt->recursive_variant >= MERGE_VARIANT_NORMAL &&
+ opt->recursive_variant <= MERGE_VARIANT_THEIRS);
+
+ /*
+ * detect_renames, verbosity, buffer_output, and obuf are ignored
+ * fields that were used by "recursive" rather than "ort" -- but
+ * sanity check them anyway.
+ */
+ assert(opt->detect_renames >= -1 &&
+ opt->detect_renames <= DIFF_DETECT_COPY);
+ assert(opt->verbosity >= 0 && opt->verbosity <= 5);
+ assert(opt->buffer_output <= 2);
+ assert(opt->obuf.len == 0);
+
+ assert(opt->priv == NULL);
+
+ /* Default to histogram diff. Actually, just hardcode it...for now. */
+ opt->xdl_opts = DIFF_WITH_ALG(opt, HISTOGRAM_DIFF);
+
+ /* Initialization of opt->priv, our internal merge data */
+ opt->priv = xcalloc(1, sizeof(*opt->priv));
+
+ /*
+ * Although we initialize opt->priv->paths with strdup_strings=0,
+ * that's just to avoid making yet another copy of an allocated
+ * string. Putting the entry into paths means we are taking
+ * ownership, so we will later free it. paths_to_free is similar.
+ *
+ * In contrast, conflicted just has a subset of keys from paths, so
+ * we don't want to free those (it'd be a duplicate free).
+ */
+ strmap_init_with_options(&opt->priv->paths, NULL, 0);
+ strmap_init_with_options(&opt->priv->conflicted, NULL, 0);
+ string_list_init(&opt->priv->paths_to_free, 0);
+
+ /*
+ * keys & strbufs in output will sometimes need to outlive "paths",
+ * so it will have a copy of relevant keys. It's probably a small
+ * subset of the overall paths that have special output.
+ */
+ strmap_init(&opt->priv->output);
+}
+
+/*** Function Grouping: merge_incore_*() and their internal variants ***/
+
+/*
+ * Originally from merge_trees_internal(); heavily adapted, though.
+ */
+static void merge_ort_nonrecursive_internal(struct merge_options *opt,
+ struct tree *merge_base,
+ struct tree *side1,
+ struct tree *side2,
+ struct merge_result *result)
+{
+ struct object_id working_tree_oid;
+
+ if (collect_merge_info(opt, merge_base, side1, side2) != 0) {
+ /*
+ * TRANSLATORS: The %s arguments are: 1) tree hash of a merge
+ * base, and 2-3) the trees for the two trees we're merging.
+ */
+ err(opt, _("collecting merge info failed for trees %s, %s, %s"),
+ oid_to_hex(&merge_base->object.oid),
+ oid_to_hex(&side1->object.oid),
+ oid_to_hex(&side2->object.oid));
+ result->clean = -1;
+ return;
+ }
+
+ result->clean = detect_and_process_renames(opt, merge_base,
+ side1, side2);
+ process_entries(opt, &working_tree_oid);
+
+ /* Set return values */
+ result->tree = parse_tree_indirect(&working_tree_oid);
+ /* existence of conflicted entries implies unclean */
+ result->clean &= strmap_empty(&opt->priv->conflicted);
+ if (!opt->priv->call_depth) {
+ result->priv = opt->priv;
+ opt->priv = NULL;
+ }
+}
+
+/*
+ * Originally from merge_recursive_internal(); somewhat adapted, though.
+ */
+static void merge_ort_internal(struct merge_options *opt,
+ struct commit_list *merge_bases,
+ struct commit *h1,
+ struct commit *h2,
+ struct merge_result *result)
+{
+ struct commit_list *iter;
+ struct commit *merged_merge_bases;
+ const char *ancestor_name;
+ struct strbuf merge_base_abbrev = STRBUF_INIT;
+
+ if (!merge_bases) {
+ merge_bases = get_merge_bases(h1, h2);
+ /* See merge-ort.h:merge_incore_recursive() declaration NOTE */
+ merge_bases = reverse_commit_list(merge_bases);
+ }
+
+ merged_merge_bases = pop_commit(&merge_bases);
+ if (merged_merge_bases == NULL) {
+ /* if there is no common ancestor, use an empty tree */
+ struct tree *tree;
+
+ tree = lookup_tree(opt->repo, opt->repo->hash_algo->empty_tree);
+ merged_merge_bases = make_virtual_commit(opt->repo, tree,
+ "ancestor");
+ ancestor_name = "empty tree";
+ } else if (merge_bases) {
+ ancestor_name = "merged common ancestors";
+ } else {
+ strbuf_add_unique_abbrev(&merge_base_abbrev,
+ &merged_merge_bases->object.oid,
+ DEFAULT_ABBREV);
+ ancestor_name = merge_base_abbrev.buf;
+ }
+
+ for (iter = merge_bases; iter; iter = iter->next) {
+ const char *saved_b1, *saved_b2;
+ struct commit *prev = merged_merge_bases;
+
+ opt->priv->call_depth++;
+ /*
+ * When the merge fails, the result contains files
+ * with conflict markers. The cleanness flag is
+ * ignored (unless indicating an error), it was never
+ * actually used, as result of merge_trees has always
+ * overwritten it: the committed "conflicts" were
+ * already resolved.
+ */
+ saved_b1 = opt->branch1;
+ saved_b2 = opt->branch2;
+ opt->branch1 = "Temporary merge branch 1";
+ opt->branch2 = "Temporary merge branch 2";
+ merge_ort_internal(opt, NULL, prev, iter->item, result);
+ if (result->clean < 0)
+ return;
+ opt->branch1 = saved_b1;
+ opt->branch2 = saved_b2;
+ opt->priv->call_depth--;
+
+ merged_merge_bases = make_virtual_commit(opt->repo,
+ result->tree,
+ "merged tree");
+ commit_list_insert(prev, &merged_merge_bases->parents);
+ commit_list_insert(iter->item,
+ &merged_merge_bases->parents->next);
+
+ clear_or_reinit_internal_opts(opt->priv, 1);
+ }
+
+ opt->ancestor = ancestor_name;
+ merge_ort_nonrecursive_internal(opt,
+ repo_get_commit_tree(opt->repo,
+ merged_merge_bases),
+ repo_get_commit_tree(opt->repo, h1),
+ repo_get_commit_tree(opt->repo, h2),
+ result);
+ strbuf_release(&merge_base_abbrev);
+ opt->ancestor = NULL; /* avoid accidental re-use of opt->ancestor */
}
void merge_incore_nonrecursive(struct merge_options *opt,
@@ -39,7 +1968,9 @@ void merge_incore_nonrecursive(struct merge_options *opt,
struct tree *side2,
struct merge_result *result)
{
- die("Not yet implemented");
+ assert(opt->ancestor != NULL);
+ merge_start(opt, result);
+ merge_ort_nonrecursive_internal(opt, merge_base, side1, side2, result);
}
void merge_incore_recursive(struct merge_options *opt,
@@ -48,5 +1979,9 @@ void merge_incore_recursive(struct merge_options *opt,
struct commit *side2,
struct merge_result *result)
{
- die("Not yet implemented");
+ /* We set the ancestor label based on the merge_bases */
+ assert(opt->ancestor == NULL);
+
+ merge_start(opt, result);
+ merge_ort_internal(opt, merge_bases, side1, side2, result);
}
diff --git a/merge-ort.h b/merge-ort.h
index 74adcca..d53a0a3 100644
--- a/merge-ort.h
+++ b/merge-ort.h
@@ -7,7 +7,14 @@ struct commit;
struct tree;
struct merge_result {
- /* Whether the merge is clean */
+ /*
+ * Whether the merge is clean; possible values:
+ * 1: clean
+ * 0: not clean (merge conflicts)
+ * <0: operation aborted prematurely. (object database
+ * unreadable, disk full, etc.) Worktree may be left in an
+ * inconsistent state if operation failed near the end.
+ */
int clean;
/*
@@ -27,6 +34,16 @@ struct merge_result {
/*
* rename-detecting three-way merge with recursive ancestor consolidation.
* working tree and index are untouched.
+ *
+ * merge_bases will be consumed (emptied) so make a copy if you need it.
+ *
+ * NOTE: empirically, the recursive algorithm will perform better if you
+ * pass the merge_bases in the order of oldest commit to the
+ * newest[1][2].
+ *
+ * [1] https://lore.kernel.org/git/nycvar.QRO.7.76.6.1907252055500.21907@tvgsbejvaqbjf.bet/
+ * [2] commit 8918b0c9c2 ("merge-recur: try to merge older merge bases
+ * first", 2006-08-09)
*/
void merge_incore_recursive(struct merge_options *opt,
struct commit_list *merge_bases,
diff --git a/merge-recursive.c b/merge-recursive.c
index f736a0f..b052974 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -3517,17 +3517,6 @@ static int merge_trees_internal(struct merge_options *opt,
return clean;
}
-static struct commit_list *reverse_commit_list(struct commit_list *list)
-{
- struct commit_list *next = NULL, *current, *backup;
- for (current = list; current; current = backup) {
- backup = current->next;
- current->next = next;
- next = current;
- }
- return next;
-}
-
/*
* Merge the commits h1 and h2, returning a flag (int) indicating the
* cleanness of the merge. Also, if opt->priv->call_depth, create a
diff --git a/midx.c b/midx.c
index 79c282b..05c40a9 100644
--- a/midx.c
+++ b/midx.c
@@ -5,7 +5,7 @@
#include "lockfile.h"
#include "packfile.h"
#include "object-store.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
#include "midx.h"
#include "progress.h"
#include "trace2.h"
@@ -918,7 +918,7 @@ static int write_midx_internal(const char *object_dir, struct multi_pack_index *
(pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
hold_lock_file_for_update(&lk, midx_name, LOCK_DIE_ON_ERROR);
- f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
+ f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
FREE_AND_NULL(midx_name);
if (packs.m)
diff --git a/sha1-file.c b/object-file.c
index c3c49d2..5bcfde8 100644
--- a/sha1-file.c
+++ b/object-file.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*
- * This handles basic git sha1 object files - packing, unpacking,
+ * This handles basic git object files - packing, unpacking,
* creation etc.
*/
#include "cache.h"
@@ -20,7 +20,7 @@
#include "tree-walk.h"
#include "refs.h"
#include "pack-revindex.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
#include "bulk-checkin.h"
#include "repository.h"
#include "replace-object.h"
@@ -508,9 +508,9 @@ static int alt_odb_usable(struct raw_object_store *o,
* LF separated. Its base points at a statically allocated buffer that
* contains "/the/directory/corresponding/to/.git/objects/...", while
* its name points just after the slash at the end of ".git/objects/"
- * in the example above, and has enough space to hold 40-byte hex
- * SHA1, an extra slash for the first level indirection, and the
- * terminating NUL.
+ * in the example above, and has enough space to hold all hex characters
+ * of the object ID, an extra slash for the first level indirection, and
+ * the terminating NUL.
*/
static void read_info_alternates(struct repository *r,
const char *relative_base,
diff --git a/sha1-name.c b/object-name.c
index 0b23b86..64202de 100644
--- a/sha1-name.c
+++ b/object-name.c
@@ -85,7 +85,7 @@ static void update_candidates(struct disambiguate_state *ds, const struct object
/* otherwise, current can be discarded and candidate is still good */
}
-static int match_sha(unsigned, const unsigned char *, const unsigned char *);
+static int match_hash(unsigned, const unsigned char *, const unsigned char *);
static void find_short_object_filename(struct disambiguate_state *ds)
{
@@ -102,7 +102,7 @@ static void find_short_object_filename(struct disambiguate_state *ds)
while (!ds->ambiguous && pos < loose_objects->nr) {
const struct object_id *oid;
oid = loose_objects->oid + pos;
- if (!match_sha(ds->len, ds->bin_pfx.hash, oid->hash))
+ if (!match_hash(ds->len, ds->bin_pfx.hash, oid->hash))
break;
update_candidates(ds, oid);
pos++;
@@ -110,7 +110,7 @@ static void find_short_object_filename(struct disambiguate_state *ds)
}
}
-static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)
+static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
{
do {
if (*a != *b)
@@ -145,7 +145,7 @@ static void unique_in_midx(struct multi_pack_index *m,
for (i = first; i < num && !ds->ambiguous; i++) {
struct object_id oid;
current = nth_midxed_object_oid(&oid, m, i);
- if (!match_sha(ds->len, ds->bin_pfx.hash, current->hash))
+ if (!match_hash(ds->len, ds->bin_pfx.hash, current->hash))
break;
update_candidates(ds, current);
}
@@ -173,7 +173,7 @@ static void unique_in_pack(struct packed_git *p,
for (i = first; i < num && !ds->ambiguous; i++) {
struct object_id oid;
nth_packed_object_id(&oid, p, i);
- if (!match_sha(ds->len, ds->bin_pfx.hash, oid.hash))
+ if (!match_hash(ds->len, ds->bin_pfx.hash, oid.hash))
break;
update_candidates(ds, &oid);
}
@@ -483,7 +483,7 @@ static enum get_oid_result get_short_oid(struct repository *r,
if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {
struct oid_array collect = OID_ARRAY_INIT;
- error(_("short SHA1 %s is ambiguous"), ds.hex_pfx);
+ error(_("short object ID %s is ambiguous"), ds.hex_pfx);
/*
* We may still have ambiguity if we simply saw a series of
@@ -1811,7 +1811,7 @@ static enum get_oid_result get_oid_with_context_1(struct repository *repo,
if (!ret)
return ret;
/*
- * sha1:path --> object name of path in ent sha1
+ * tree:path --> object name of path in tree
* :path -> object name of absolute path in index
* :./path -> object name of path relative to cwd in index
* :[0-3]:path -> object name of path in index at stage
@@ -1949,6 +1949,6 @@ enum get_oid_result get_oid_with_context(struct repository *repo,
struct object_context *oc)
{
if (flags & GET_OID_FOLLOW_SYMLINKS && flags & GET_OID_ONLY_TO_DIE)
- BUG("incompatible flags for get_sha1_with_context");
+ BUG("incompatible flags for get_oid_with_context");
return get_oid_with_context_1(repo, str, flags, NULL, oid, oc);
}
diff --git a/oid-array.c b/oid-array.c
index 8657a5c..889b311 100644
--- a/oid-array.c
+++ b/oid-array.c
@@ -1,6 +1,6 @@
#include "cache.h"
#include "oid-array.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
void oid_array_append(struct oid_array *array, const struct object_id *oid)
{
@@ -14,8 +14,10 @@ static int void_hashcmp(const void *a, const void *b)
return oidcmp(a, b);
}
-static void oid_array_sort(struct oid_array *array)
+void oid_array_sort(struct oid_array *array)
{
+ if (array->sorted)
+ return;
QSORT(array->oid, array->nr, void_hashcmp);
array->sorted = 1;
}
@@ -28,9 +30,8 @@ static const unsigned char *sha1_access(size_t index, void *table)
int oid_array_lookup(struct oid_array *array, const struct object_id *oid)
{
- if (!array->sorted)
- oid_array_sort(array);
- return sha1_pos(oid->hash, array->oid, array->nr, sha1_access);
+ oid_array_sort(array);
+ return hash_pos(oid->hash, array->oid, array->nr, sha1_access);
}
void oid_array_clear(struct oid_array *array)
@@ -64,14 +65,10 @@ int oid_array_for_each_unique(struct oid_array *array,
{
size_t i;
- if (!array->sorted)
- oid_array_sort(array);
+ oid_array_sort(array);
- for (i = 0; i < array->nr; i++) {
- int ret;
- if (i > 0 && oideq(array->oid + i, array->oid + i - 1))
- continue;
- ret = fn(array->oid + i, data);
+ for (i = 0; i < array->nr; i = oid_array_next_unique(array, i)) {
+ int ret = fn(array->oid + i, data);
if (ret)
return ret;
}
diff --git a/oid-array.h b/oid-array.h
index f28d322..72bca78 100644
--- a/oid-array.h
+++ b/oid-array.h
@@ -1,5 +1,7 @@
-#ifndef SHA1_ARRAY_H
-#define SHA1_ARRAY_H
+#ifndef OID_ARRAY_H
+#define OID_ARRAY_H
+
+#include "hash.h"
/**
* The API provides storage and manipulation of sets of object identifiers.
@@ -106,4 +108,30 @@ void oid_array_filter(struct oid_array *array,
for_each_oid_fn want,
void *cbdata);
-#endif /* SHA1_ARRAY_H */
+/**
+ * Sort the array in order of ascending object id.
+ */
+void oid_array_sort(struct oid_array *array);
+
+/**
+ * Find the next unique oid in the array after position "cur".
+ * The array must be sorted for this to work. You can iterate
+ * over unique elements like this:
+ *
+ * size_t i;
+ * oid_array_sort(array);
+ * for (i = 0; i < array->nr; i = oid_array_next_unique(array, i))
+ * printf("%s", oid_to_hex(array->oids[i]);
+ *
+ * Non-unique iteration can just increment with "i++" to visit each element.
+ */
+static inline size_t oid_array_next_unique(struct oid_array *array, size_t cur)
+{
+ do {
+ cur++;
+ } while (cur < array->nr &&
+ oideq(array->oid + cur, array->oid + cur - 1));
+ return cur;
+}
+
+#endif /* OID_ARRAY_H */
diff --git a/pack-bitmap-write.c b/pack-bitmap-write.c
index 5e998bd..92460a6 100644
--- a/pack-bitmap-write.c
+++ b/pack-bitmap-write.c
@@ -9,9 +9,10 @@
#include "pack-revindex.h"
#include "pack.h"
#include "pack-bitmap.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
#include "pack-objects.h"
#include "commit-reach.h"
+#include "prio-queue.h"
struct bitmapped_commit {
struct commit *commit;
@@ -29,7 +30,6 @@ struct bitmap_writer {
struct ewah_bitmap *tags;
kh_oid_map_t *bitmaps;
- kh_oid_map_t *reused;
struct packing_data *to_pack;
struct bitmapped_commit *selected;
@@ -110,10 +110,8 @@ void bitmap_writer_build_type_index(struct packing_data *to_pack,
/**
* Compute the actual bitmaps
*/
-static struct object **seen_objects;
-static unsigned int seen_objects_nr, seen_objects_alloc;
-static inline void push_bitmapped_commit(struct commit *commit, struct ewah_bitmap *reused)
+static inline void push_bitmapped_commit(struct commit *commit)
{
if (writer.selected_nr >= writer.selected_alloc) {
writer.selected_alloc = (writer.selected_alloc + 32) * 2;
@@ -121,27 +119,12 @@ static inline void push_bitmapped_commit(struct commit *commit, struct ewah_bitm
}
writer.selected[writer.selected_nr].commit = commit;
- writer.selected[writer.selected_nr].bitmap = reused;
+ writer.selected[writer.selected_nr].bitmap = NULL;
writer.selected[writer.selected_nr].flags = 0;
writer.selected_nr++;
}
-static inline void mark_as_seen(struct object *object)
-{
- ALLOC_GROW(seen_objects, seen_objects_nr + 1, seen_objects_alloc);
- seen_objects[seen_objects_nr++] = object;
-}
-
-static inline void reset_all_seen(void)
-{
- unsigned int i;
- for (i = 0; i < seen_objects_nr; ++i) {
- seen_objects[i]->flags &= ~(SEEN | ADDED | SHOWN);
- }
- seen_objects_nr = 0;
-}
-
static uint32_t find_object_pos(const struct object_id *oid)
{
struct object_entry *entry = packlist_find(writer.to_pack, oid);
@@ -154,60 +137,6 @@ static uint32_t find_object_pos(const struct object_id *oid)
return oe_in_pack_pos(writer.to_pack, entry);
}
-static void show_object(struct object *object, const char *name, void *data)
-{
- struct bitmap *base = data;
- bitmap_set(base, find_object_pos(&object->oid));
- mark_as_seen(object);
-}
-
-static void show_commit(struct commit *commit, void *data)
-{
- mark_as_seen((struct object *)commit);
-}
-
-static int
-add_to_include_set(struct bitmap *base, struct commit *commit)
-{
- khiter_t hash_pos;
- uint32_t bitmap_pos = find_object_pos(&commit->object.oid);
-
- if (bitmap_get(base, bitmap_pos))
- return 0;
-
- hash_pos = kh_get_oid_map(writer.bitmaps, commit->object.oid);
- if (hash_pos < kh_end(writer.bitmaps)) {
- struct bitmapped_commit *bc = kh_value(writer.bitmaps, hash_pos);
- bitmap_or_ewah(base, bc->bitmap);
- return 0;
- }
-
- bitmap_set(base, bitmap_pos);
- return 1;
-}
-
-static int
-should_include(struct commit *commit, void *_data)
-{
- struct bitmap *base = _data;
-
- if (!add_to_include_set(base, commit)) {
- struct commit_list *parent = commit->parents;
-
- mark_as_seen((struct object *)commit);
-
- while (parent) {
- parent->item->object.flags |= SEEN;
- mark_as_seen((struct object *)parent->item);
- parent = parent->next;
- }
-
- return 0;
- }
-
- return 1;
-}
-
static void compute_xor_offsets(void)
{
static const int MAX_XOR_OFFSET_SEARCH = 10;
@@ -248,79 +177,326 @@ static void compute_xor_offsets(void)
}
}
-void bitmap_writer_build(struct packing_data *to_pack)
-{
- static const double REUSE_BITMAP_THRESHOLD = 0.2;
+struct bb_commit {
+ struct commit_list *reverse_edges;
+ struct bitmap *commit_mask;
+ struct bitmap *bitmap;
+ unsigned selected:1,
+ maximal:1;
+ unsigned idx; /* within selected array */
+};
- int i, reuse_after, need_reset;
- struct bitmap *base = bitmap_new();
- struct rev_info revs;
+define_commit_slab(bb_data, struct bb_commit);
- writer.bitmaps = kh_init_oid_map();
- writer.to_pack = to_pack;
+struct bitmap_builder {
+ struct bb_data data;
+ struct commit **commits;
+ size_t commits_nr, commits_alloc;
+};
- if (writer.show_progress)
- writer.progress = start_progress("Building bitmaps", writer.selected_nr);
+static void bitmap_builder_init(struct bitmap_builder *bb,
+ struct bitmap_writer *writer,
+ struct bitmap_index *old_bitmap)
+{
+ struct rev_info revs;
+ struct commit *commit;
+ struct commit_list *reusable = NULL;
+ struct commit_list *r;
+ unsigned int i, num_maximal = 0;
- repo_init_revisions(to_pack->repo, &revs, NULL);
- revs.tag_objects = 1;
- revs.tree_objects = 1;
- revs.blob_objects = 1;
- revs.no_walk = 0;
+ memset(bb, 0, sizeof(*bb));
+ init_bb_data(&bb->data);
- revs.include_check = should_include;
reset_revision_walk();
+ repo_init_revisions(writer->to_pack->repo, &revs, NULL);
+ revs.topo_order = 1;
+ 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);
+
+ ent->selected = 1;
+ ent->maximal = 1;
+ ent->idx = i;
+
+ ent->commit_mask = bitmap_new();
+ bitmap_set(ent->commit_mask, i);
+
+ add_pending_object(&revs, &c->object, "");
+ }
+
+ if (prepare_revision_walk(&revs))
+ die("revision walk setup failed");
+
+ while ((commit = get_revision(&revs))) {
+ struct commit_list *p = commit->parents;
+ struct bb_commit *c_ent;
+
+ parse_commit_or_die(commit);
+
+ c_ent = bb_data_at(&bb->data, commit);
+
+ /*
+ * If there is no commit_mask, there is no reason to iterate
+ * over this commit; it is not selected (if it were, it would
+ * not have a blank commit mask) and all its children have
+ * existing bitmaps (see the comment starting with "This commit
+ * has an existing bitmap" below), so it does not contribute
+ * anything to the final bitmap file or its descendants.
+ */
+ if (!c_ent->commit_mask)
+ continue;
+
+ if (old_bitmap && bitmap_for_commit(old_bitmap, commit)) {
+ /*
+ * This commit has an existing bitmap, so we can
+ * get its bits immediately without an object
+ * walk. That is, it is reusable as-is and there is no
+ * need to continue walking beyond it.
+ *
+ * Mark it as such and add it to bb->commits separately
+ * to avoid allocating a position in the commit mask.
+ */
+ commit_list_insert(commit, &reusable);
+ goto next;
+ }
+
+ if (c_ent->maximal) {
+ num_maximal++;
+ ALLOC_GROW(bb->commits, bb->commits_nr + 1, bb->commits_alloc);
+ bb->commits[bb->commits_nr++] = commit;
+ }
+
+ if (p) {
+ struct bb_commit *p_ent = bb_data_at(&bb->data, p->item);
+ int c_not_p, p_not_c;
+
+ if (!p_ent->commit_mask) {
+ p_ent->commit_mask = bitmap_new();
+ c_not_p = 1;
+ p_not_c = 0;
+ } else {
+ c_not_p = bitmap_is_subset(c_ent->commit_mask, p_ent->commit_mask);
+ p_not_c = bitmap_is_subset(p_ent->commit_mask, c_ent->commit_mask);
+ }
+
+ if (!c_not_p)
+ continue;
+
+ bitmap_or(p_ent->commit_mask, c_ent->commit_mask);
+
+ if (p_not_c)
+ p_ent->maximal = 1;
+ else {
+ p_ent->maximal = 0;
+ free_commit_list(p_ent->reverse_edges);
+ p_ent->reverse_edges = NULL;
+ }
- reuse_after = writer.selected_nr * REUSE_BITMAP_THRESHOLD;
- need_reset = 0;
+ if (c_ent->maximal) {
+ commit_list_insert(commit, &p_ent->reverse_edges);
+ } else {
+ struct commit_list *cc = c_ent->reverse_edges;
+
+ for (; cc; cc = cc->next) {
+ if (!commit_list_contains(cc->item, p_ent->reverse_edges))
+ commit_list_insert(cc->item, &p_ent->reverse_edges);
+ }
+ }
+ }
+
+next:
+ bitmap_free(c_ent->commit_mask);
+ c_ent->commit_mask = NULL;
+ }
+
+ for (r = reusable; r; r = r->next) {
+ ALLOC_GROW(bb->commits, bb->commits_nr + 1, bb->commits_alloc);
+ bb->commits[bb->commits_nr++] = r->item;
+ }
+
+ trace2_data_intmax("pack-bitmap-write", the_repository,
+ "num_selected_commits", writer->selected_nr);
+ trace2_data_intmax("pack-bitmap-write", the_repository,
+ "num_maximal_commits", num_maximal);
+
+ free_commit_list(reusable);
+}
+
+static void bitmap_builder_clear(struct bitmap_builder *bb)
+{
+ clear_bb_data(&bb->data);
+ free(bb->commits);
+ bb->commits_nr = bb->commits_alloc = 0;
+}
+
+static void fill_bitmap_tree(struct bitmap *bitmap,
+ struct tree *tree)
+{
+ uint32_t pos;
+ struct tree_desc desc;
+ struct name_entry entry;
+
+ /*
+ * If our bit is already set, then there is nothing to do. Both this
+ * tree and all of its children will be set.
+ */
+ pos = find_object_pos(&tree->object.oid);
+ if (bitmap_get(bitmap, pos))
+ return;
+ bitmap_set(bitmap, pos);
- for (i = writer.selected_nr - 1; i >= 0; --i) {
- struct bitmapped_commit *stored;
- struct object *object;
+ if (parse_tree(tree) < 0)
+ die("unable to load tree object %s",
+ oid_to_hex(&tree->object.oid));
+ init_tree_desc(&desc, tree->buffer, tree->size);
- khiter_t hash_pos;
- int hash_ret;
+ while (tree_entry(&desc, &entry)) {
+ switch (object_type(entry.mode)) {
+ case OBJ_TREE:
+ fill_bitmap_tree(bitmap,
+ lookup_tree(the_repository, &entry.oid));
+ break;
+ case OBJ_BLOB:
+ bitmap_set(bitmap, find_object_pos(&entry.oid));
+ break;
+ default:
+ /* Gitlink, etc; not reachable */
+ break;
+ }
+ }
- stored = &writer.selected[i];
- object = (struct object *)stored->commit;
+ free_tree_buffer(tree);
+}
- if (stored->bitmap == NULL) {
- if (i < writer.selected_nr - 1 &&
- (need_reset ||
- !in_merge_bases(writer.selected[i + 1].commit,
- stored->commit))) {
- bitmap_reset(base);
- reset_all_seen();
+static void fill_bitmap_commit(struct bb_commit *ent,
+ struct commit *commit,
+ struct prio_queue *queue,
+ struct prio_queue *tree_queue,
+ struct bitmap_index *old_bitmap,
+ const uint32_t *mapping)
+{
+ if (!ent->bitmap)
+ ent->bitmap = bitmap_new();
+
+ prio_queue_put(queue, commit);
+
+ while (queue->nr) {
+ struct commit_list *p;
+ struct commit *c = prio_queue_get(queue);
+
+ if (old_bitmap && mapping) {
+ struct ewah_bitmap *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
+ * parents or the tree for this commit.
+ */
+ if (old && !rebuild_bitmap(mapping, old, ent->bitmap))
+ continue;
+ }
+
+ /*
+ * Mark ourselves and queue our tree. The commit
+ * walk ensures we cover all parents.
+ */
+ bitmap_set(ent->bitmap, find_object_pos(&c->object.oid));
+ prio_queue_put(tree_queue, get_commit_tree(c));
+
+ for (p = c->parents; p; p = p->next) {
+ int pos = find_object_pos(&p->item->object.oid);
+ if (!bitmap_get(ent->bitmap, pos)) {
+ bitmap_set(ent->bitmap, pos);
+ prio_queue_put(queue, p->item);
}
+ }
+ }
- add_pending_object(&revs, object, "");
- revs.include_check_data = base;
+ while (tree_queue->nr)
+ fill_bitmap_tree(ent->bitmap, prio_queue_get(tree_queue));
+}
- if (prepare_revision_walk(&revs))
- die("revision walk setup failed");
+static void store_selected(struct bb_commit *ent, struct commit *commit)
+{
+ struct bitmapped_commit *stored = &writer.selected[ent->idx];
+ khiter_t hash_pos;
+ int hash_ret;
- traverse_commit_list(&revs, show_commit, show_object, base);
+ stored->bitmap = bitmap_to_ewah(ent->bitmap);
- object_array_clear(&revs.pending);
+ hash_pos = kh_put_oid_map(writer.bitmaps, commit->object.oid, &hash_ret);
+ if (hash_ret == 0)
+ die("Duplicate entry when writing index: %s",
+ oid_to_hex(&commit->object.oid));
+ kh_value(writer.bitmaps, hash_pos) = stored;
+}
- stored->bitmap = bitmap_to_ewah(base);
- need_reset = 0;
- } else
- need_reset = 1;
+void bitmap_writer_build(struct packing_data *to_pack)
+{
+ struct bitmap_builder bb;
+ size_t i;
+ int nr_stored = 0; /* for progress */
+ struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
+ struct prio_queue tree_queue = { NULL };
+ struct bitmap_index *old_bitmap;
+ uint32_t *mapping;
- if (i >= reuse_after)
- stored->flags |= BITMAP_FLAG_REUSE;
+ writer.bitmaps = kh_init_oid_map();
+ writer.to_pack = to_pack;
- hash_pos = kh_put_oid_map(writer.bitmaps, object->oid, &hash_ret);
- if (hash_ret == 0)
- die("Duplicate entry when writing index: %s",
- oid_to_hex(&object->oid));
+ if (writer.show_progress)
+ writer.progress = start_progress("Building bitmaps", writer.selected_nr);
+ trace2_region_enter("pack-bitmap-write", "building_bitmaps_total",
+ the_repository);
+
+ old_bitmap = prepare_bitmap_git(to_pack->repo);
+ if (old_bitmap)
+ mapping = create_bitmap_mapping(old_bitmap, to_pack);
+ else
+ mapping = NULL;
+
+ bitmap_builder_init(&bb, &writer, old_bitmap);
+ for (i = bb.commits_nr; i > 0; i--) {
+ struct commit *commit = bb.commits[i-1];
+ struct bb_commit *ent = bb_data_at(&bb.data, commit);
+ struct commit *child;
+ int reused = 0;
+
+ fill_bitmap_commit(ent, commit, &queue, &tree_queue,
+ old_bitmap, mapping);
+
+ if (ent->selected) {
+ store_selected(ent, commit);
+ nr_stored++;
+ display_progress(writer.progress, nr_stored);
+ }
- kh_value(writer.bitmaps, hash_pos) = stored;
- display_progress(writer.progress, writer.selected_nr - i);
+ while ((child = pop_commit(&ent->reverse_edges))) {
+ struct bb_commit *child_ent =
+ bb_data_at(&bb.data, child);
+
+ if (child_ent->bitmap)
+ bitmap_or(child_ent->bitmap, ent->bitmap);
+ else if (reused)
+ child_ent->bitmap = bitmap_dup(ent->bitmap);
+ else {
+ child_ent->bitmap = ent->bitmap;
+ reused = 1;
+ }
+ }
+ if (!reused)
+ bitmap_free(ent->bitmap);
+ ent->bitmap = NULL;
}
+ clear_prio_queue(&queue);
+ clear_prio_queue(&tree_queue);
+ bitmap_builder_clear(&bb);
+ free(mapping);
+
+ trace2_region_leave("pack-bitmap-write", "building_bitmaps_total",
+ the_repository);
- bitmap_free(base);
stop_progress(&writer.progress);
compute_xor_offsets();
@@ -360,35 +536,6 @@ static int date_compare(const void *_a, const void *_b)
return (long)b->date - (long)a->date;
}
-void bitmap_writer_reuse_bitmaps(struct packing_data *to_pack)
-{
- struct bitmap_index *bitmap_git;
- if (!(bitmap_git = prepare_bitmap_git(to_pack->repo)))
- return;
-
- writer.reused = kh_init_oid_map();
- rebuild_existing_bitmaps(bitmap_git, to_pack, writer.reused,
- writer.show_progress);
- /*
- * NEEDSWORK: rebuild_existing_bitmaps() makes writer.reused reference
- * some bitmaps in bitmap_git, so we can't free the latter.
- */
-}
-
-static struct ewah_bitmap *find_reused_bitmap(const struct object_id *oid)
-{
- khiter_t hash_pos;
-
- if (!writer.reused)
- return NULL;
-
- hash_pos = kh_get_oid_map(writer.reused, *oid);
- if (hash_pos >= kh_end(writer.reused))
- return NULL;
-
- return kh_value(writer.reused, hash_pos);
-}
-
void bitmap_writer_select_commits(struct commit **indexed_commits,
unsigned int indexed_commits_nr,
int max_bitmaps)
@@ -402,12 +549,11 @@ void bitmap_writer_select_commits(struct commit **indexed_commits,
if (indexed_commits_nr < 100) {
for (i = 0; i < indexed_commits_nr; ++i)
- push_bitmapped_commit(indexed_commits[i], NULL);
+ push_bitmapped_commit(indexed_commits[i]);
return;
}
for (;;) {
- struct ewah_bitmap *reused_bitmap = NULL;
struct commit *chosen = NULL;
next = next_commit_index(i);
@@ -422,15 +568,13 @@ void bitmap_writer_select_commits(struct commit **indexed_commits,
if (next == 0) {
chosen = indexed_commits[i];
- reused_bitmap = find_reused_bitmap(&chosen->object.oid);
} else {
chosen = indexed_commits[i + next];
for (j = 0; j <= next; ++j) {
struct commit *cm = indexed_commits[i + j];
- reused_bitmap = find_reused_bitmap(&cm->object.oid);
- if (reused_bitmap || (cm->object.flags & NEEDS_BITMAP) != 0) {
+ if ((cm->object.flags & NEEDS_BITMAP) != 0) {
chosen = cm;
break;
}
@@ -440,7 +584,7 @@ void bitmap_writer_select_commits(struct commit **indexed_commits,
}
}
- push_bitmapped_commit(chosen, reused_bitmap);
+ push_bitmapped_commit(chosen);
i += next + 1;
display_progress(writer.progress, i);
@@ -482,7 +626,7 @@ static void write_selected_commits_v1(struct hashfile *f,
struct bitmapped_commit *stored = &writer.selected[i];
int commit_pos =
- sha1_pos(stored->commit->object.oid.hash, index, index_nr, sha1_access);
+ hash_pos(stored->commit->object.oid.hash, index, index_nr, sha1_access);
if (commit_pos < 0)
BUG("trying to write commit not in index");
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 4077e73..d88745f 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -138,9 +138,10 @@ static struct ewah_bitmap *read_bitmap_1(struct bitmap_index *index)
static int load_bitmap_header(struct bitmap_index *index)
{
struct bitmap_disk_header *header = (void *)index->map;
+ size_t header_size = sizeof(*header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz;
- if (index->map_size < sizeof(*header) + the_hash_algo->rawsz)
- return error("Corrupted bitmap index (missing header data)");
+ if (index->map_size < header_size + the_hash_algo->rawsz)
+ return error("Corrupted bitmap index (too small)");
if (memcmp(header->magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE)) != 0)
return error("Corrupted bitmap index file (wrong header)");
@@ -152,19 +153,23 @@ static int load_bitmap_header(struct bitmap_index *index)
/* Parse known bitmap format options */
{
uint32_t flags = ntohs(header->options);
+ size_t cache_size = st_mult(index->pack->num_objects, sizeof(uint32_t));
+ unsigned char *index_end = index->map + index->map_size - the_hash_algo->rawsz;
if ((flags & BITMAP_OPT_FULL_DAG) == 0)
return error("Unsupported options for bitmap index file "
"(Git requires BITMAP_OPT_FULL_DAG)");
if (flags & BITMAP_OPT_HASH_CACHE) {
- unsigned char *end = index->map + index->map_size - the_hash_algo->rawsz;
- index->hashes = ((uint32_t *)end) - index->pack->num_objects;
+ if (cache_size > index_end - index->map - header_size)
+ return error("corrupted bitmap index file (too short to fit hash cache)");
+ index->hashes = (void *)(index_end - cache_size);
+ index_end -= cache_size;
}
}
index->entry_count = ntohl(header->entry_count);
- index->map_pos += sizeof(*header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz;
+ index->map_pos += header_size;
return 0;
}
@@ -224,11 +229,16 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
uint32_t commit_idx_pos;
struct object_id oid;
+ if (index->map_size - index->map_pos < 6)
+ return error("corrupt ewah bitmap: truncated header for entry %d", i);
+
commit_idx_pos = read_be32(index->map, &index->map_pos);
xor_offset = read_u8(index->map, &index->map_pos);
flags = read_u8(index->map, &index->map_pos);
- nth_packed_object_id(&oid, index->pack, commit_idx_pos);
+ if (nth_packed_object_id(&oid, index->pack, commit_idx_pos) < 0)
+ return error("corrupt ewah bitmap: commit index %u out of range",
+ (unsigned)commit_idx_pos);
bitmap = read_bitmap_1(index);
if (!bitmap)
@@ -370,6 +380,16 @@ struct include_data {
struct bitmap *seen;
};
+struct ewah_bitmap *bitmap_for_commit(struct bitmap_index *bitmap_git,
+ struct commit *commit)
+{
+ khiter_t hash_pos = kh_get_oid_map(bitmap_git->bitmaps,
+ commit->object.oid);
+ if (hash_pos >= kh_end(bitmap_git->bitmaps))
+ return NULL;
+ return lookup_stored_bitmap(kh_value(bitmap_git->bitmaps, hash_pos));
+}
+
static inline int bitmap_position_extended(struct bitmap_index *bitmap_git,
const struct object_id *oid)
{
@@ -455,10 +475,10 @@ static void show_commit(struct commit *commit, void *data)
static int add_to_include_set(struct bitmap_index *bitmap_git,
struct include_data *data,
- const struct object_id *oid,
+ struct commit *commit,
int bitmap_pos)
{
- khiter_t hash_pos;
+ struct ewah_bitmap *partial;
if (data->seen && bitmap_get(data->seen, bitmap_pos))
return 0;
@@ -466,10 +486,9 @@ static int add_to_include_set(struct bitmap_index *bitmap_git,
if (bitmap_get(data->base, bitmap_pos))
return 0;
- hash_pos = kh_get_oid_map(bitmap_git->bitmaps, *oid);
- if (hash_pos < kh_end(bitmap_git->bitmaps)) {
- struct stored_bitmap *st = kh_value(bitmap_git->bitmaps, hash_pos);
- bitmap_or_ewah(data->base, lookup_stored_bitmap(st));
+ partial = bitmap_for_commit(bitmap_git, commit);
+ if (partial) {
+ bitmap_or_ewah(data->base, partial);
return 0;
}
@@ -488,8 +507,7 @@ static int should_include(struct commit *commit, void *_data)
(struct object *)commit,
NULL);
- if (!add_to_include_set(data->bitmap_git, data, &commit->object.oid,
- bitmap_pos)) {
+ if (!add_to_include_set(data->bitmap_git, data, commit, bitmap_pos)) {
struct commit_list *parent = commit->parents;
while (parent) {
@@ -503,6 +521,23 @@ static int should_include(struct commit *commit, void *_data)
return 1;
}
+static int add_commit_to_bitmap(struct bitmap_index *bitmap_git,
+ struct bitmap **base,
+ struct commit *commit)
+{
+ struct ewah_bitmap *or_with = bitmap_for_commit(bitmap_git, commit);
+
+ if (!or_with)
+ return 0;
+
+ if (*base == NULL)
+ *base = ewah_to_bitmap(or_with);
+ else
+ bitmap_or_ewah(*base, or_with);
+
+ return 1;
+}
+
static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
struct rev_info *revs,
struct object_list *roots,
@@ -526,21 +561,10 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
struct object *object = roots->item;
roots = roots->next;
- if (object->type == OBJ_COMMIT) {
- khiter_t pos = kh_get_oid_map(bitmap_git->bitmaps, object->oid);
-
- if (pos < kh_end(bitmap_git->bitmaps)) {
- struct stored_bitmap *st = kh_value(bitmap_git->bitmaps, pos);
- struct ewah_bitmap *or_with = lookup_stored_bitmap(st);
-
- if (base == NULL)
- base = ewah_to_bitmap(or_with);
- else
- bitmap_or_ewah(base, or_with);
-
- object->flags |= SEEN;
- continue;
- }
+ if (object->type == OBJ_COMMIT &&
+ add_commit_to_bitmap(bitmap_git, &base, (struct commit *)object)) {
+ object->flags |= SEEN;
+ continue;
}
object_list_insert(object, &not_mapped);
@@ -1272,10 +1296,10 @@ void test_bitmap_walk(struct rev_info *revs)
{
struct object *root;
struct bitmap *result = NULL;
- khiter_t pos;
size_t result_popcnt;
struct bitmap_test_data tdata;
struct bitmap_index *bitmap_git;
+ struct ewah_bitmap *bm;
if (!(bitmap_git = prepare_bitmap_git(revs->repo)))
die("failed to load bitmap indexes");
@@ -1287,12 +1311,9 @@ void test_bitmap_walk(struct rev_info *revs)
bitmap_git->version, bitmap_git->entry_count);
root = revs->pending.objects[0].item;
- pos = kh_get_oid_map(bitmap_git->bitmaps, root->oid);
-
- if (pos < kh_end(bitmap_git->bitmaps)) {
- struct stored_bitmap *st = kh_value(bitmap_git->bitmaps, pos);
- struct ewah_bitmap *bm = lookup_stored_bitmap(st);
+ bm = bitmap_for_commit(bitmap_git, (struct commit *)root);
+ if (bm) {
fprintf(stderr, "Found bitmap for %s. %d bits / %08x checksum\n",
oid_to_hex(&root->oid), (int)bm->bit_size, ewah_checksum(bm));
@@ -1323,14 +1344,14 @@ void test_bitmap_walk(struct rev_info *revs)
if (bitmap_equals(result, tdata.base))
fprintf(stderr, "OK!\n");
else
- fprintf(stderr, "Mismatch!\n");
+ die("mismatch in bitmap results");
free_bitmap_index(bitmap_git);
}
-static int rebuild_bitmap(uint32_t *reposition,
- struct ewah_bitmap *source,
- struct bitmap *dest)
+int rebuild_bitmap(const uint32_t *reposition,
+ struct ewah_bitmap *source,
+ struct bitmap *dest)
{
uint32_t pos = 0;
struct ewah_iterator it;
@@ -1359,19 +1380,11 @@ static int rebuild_bitmap(uint32_t *reposition,
return 0;
}
-int rebuild_existing_bitmaps(struct bitmap_index *bitmap_git,
- struct packing_data *mapping,
- kh_oid_map_t *reused_bitmaps,
- int show_progress)
+uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git,
+ struct packing_data *mapping)
{
uint32_t i, num_objects;
uint32_t *reposition;
- struct bitmap *rebuild;
- struct stored_bitmap *stored;
- struct progress *progress = NULL;
-
- khiter_t hash_pos;
- int hash_ret;
num_objects = bitmap_git->pack->num_objects;
reposition = xcalloc(num_objects, sizeof(uint32_t));
@@ -1389,33 +1402,7 @@ int rebuild_existing_bitmaps(struct bitmap_index *bitmap_git,
reposition[i] = oe_in_pack_pos(mapping, oe) + 1;
}
- rebuild = bitmap_new();
- i = 0;
-
- if (show_progress)
- progress = start_progress("Reusing bitmaps", 0);
-
- kh_foreach_value(bitmap_git->bitmaps, stored, {
- if (stored->flags & BITMAP_FLAG_REUSE) {
- if (!rebuild_bitmap(reposition,
- lookup_stored_bitmap(stored),
- rebuild)) {
- hash_pos = kh_put_oid_map(reused_bitmaps,
- stored->oid,
- &hash_ret);
- kh_value(reused_bitmaps, hash_pos) =
- bitmap_to_ewah(rebuild);
- }
- bitmap_reset(rebuild);
- display_progress(progress, ++i);
- }
- });
-
- stop_progress(&progress);
-
- free(reposition);
- bitmap_free(rebuild);
- return 0;
+ return reposition;
}
void free_bitmap_index(struct bitmap_index *b)
diff --git a/pack-bitmap.h b/pack-bitmap.h
index 1203120..25dfcf5 100644
--- a/pack-bitmap.h
+++ b/pack-bitmap.h
@@ -73,7 +73,13 @@ void bitmap_writer_set_checksum(unsigned char *sha1);
void bitmap_writer_build_type_index(struct packing_data *to_pack,
struct pack_idx_entry **index,
uint32_t index_nr);
-void bitmap_writer_reuse_bitmaps(struct packing_data *to_pack);
+uint32_t *create_bitmap_mapping(struct bitmap_index *bitmap_git,
+ struct packing_data *mapping);
+int rebuild_bitmap(const uint32_t *reposition,
+ struct ewah_bitmap *source,
+ struct bitmap *dest);
+struct ewah_bitmap *bitmap_for_commit(struct bitmap_index *bitmap_git,
+ struct commit *commit);
void bitmap_writer_select_commits(struct commit **indexed_commits,
unsigned int indexed_commits_nr, int max_bitmaps);
void bitmap_writer_build(struct packing_data *to_pack);
diff --git a/packfile.c b/packfile.c
index 86f5c8d..62d92e0 100644
--- a/packfile.c
+++ b/packfile.c
@@ -7,7 +7,7 @@
#include "packfile.h"
#include "delta.h"
#include "streaming.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
#include "commit.h"
#include "object.h"
#include "tag.h"
diff --git a/parse-options.h b/parse-options.h
index 7030d8f..ff6506a 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -82,9 +82,9 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
* stores pointers to the values to be filled.
*
* `argh`::
- * token to explain the kind of argument this option wants. Keep it
- * homogeneous across the repository. Should be wrapped by N_() for
- * translation.
+ * token to explain the kind of argument this option wants. Does not
+ * begin in capital letter, and does not end with a full stop.
+ * Should be wrapped by N_() for translation.
*
* `help`::
* the short help associated to what the option does.
diff --git a/patch-ids.c b/patch-ids.c
index 21973e4..cf5e804 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -1,7 +1,7 @@
#include "cache.h"
#include "diff.h"
#include "commit.h"
-#include "sha1-lookup.h"
+#include "hash-lookup.h"
#include "patch-ids.h"
static int patch_id_defined(struct commit *commit)
diff --git a/po/TEAMS b/po/TEAMS
index 2fc21ad..677cece 100644
--- a/po/TEAMS
+++ b/po/TEAMS
@@ -42,6 +42,10 @@ Leader: Gwan-gyeong Mun <elongbug@gmail.com>
Members: Changwoo Ryu <cwryu@debian.org>
Sihyeon Jang <uneedsihyeon@gmail.com>
+Language: pl (Polish)
+Repository: https://github.com/Arusekk/git-po
+Leader: Arusekk <arek_koz@o2.pl>
+
Language: pt_PT (Portuguese - Portugal)
Repository: https://github.com/git-l10n-pt-PT/git-po/
Leader: Daniel Santos <hello@brighterdan.com>
diff --git a/po/bg.po b/po/bg.po
index c2af082..d73e84c 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -148,6 +148,7 @@
# end packet пакет за край
# identity самоличност, информация за
# boundary commit гранично подаване
+# integrate (changes) внасяне (на промени)
# ------------------------
# „$var“ - може да не сработва за shell има gettext и eval_gettext - проверка - намират се лесно по „$
# ------------------------
@@ -164,10 +165,10 @@
# for i in `sort -u FILES`; do cnt=`grep $i FILES | wc -l`; echo $cnt $i ;done | sort -n
msgid ""
msgstr ""
-"Project-Id-Version: git 2.29\n"
+"Project-Id-Version: git 2.30\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2020-10-10 09:32+0800\n"
-"PO-Revision-Date: 2020-10-11 15:00+0200\n"
+"POT-Creation-Date: 2020-12-21 07:10+0800\n"
+"PO-Revision-Date: 2020-12-22 17:48+0100\n"
"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"Language: bg\n"
@@ -176,200 +177,200 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: add-interactive.c:368
+#: add-interactive.c:376
#, c-format
msgid "Huh (%s)?"
msgstr "Неуспешен анализ — „%s“."
-#: add-interactive.c:521 add-interactive.c:822 reset.c:65 sequencer.c:3250
-#: sequencer.c:3698 sequencer.c:3840 builtin/rebase.c:1526
-#: builtin/rebase.c:1944
+#: add-interactive.c:529 add-interactive.c:830 reset.c:65 sequencer.c:3284
+#: sequencer.c:3735 sequencer.c:3890 builtin/rebase.c:1532
+#: builtin/rebase.c:1955
msgid "could not read index"
msgstr "индексът не може да бъде прочетен"
-#: add-interactive.c:576 git-add--interactive.perl:269
+#: add-interactive.c:584 git-add--interactive.perl:269
#: git-add--interactive.perl:294
msgid "binary"
msgstr "двоично"
-#: add-interactive.c:634 git-add--interactive.perl:278
+#: add-interactive.c:642 git-add--interactive.perl:278
#: git-add--interactive.perl:332
msgid "nothing"
msgstr "нищо"
-#: add-interactive.c:635 git-add--interactive.perl:314
+#: add-interactive.c:643 git-add--interactive.perl:314
#: git-add--interactive.perl:329
msgid "unchanged"
msgstr "няма промени"
-#: add-interactive.c:672 git-add--interactive.perl:643
+#: add-interactive.c:680 git-add--interactive.perl:641
msgid "Update"
msgstr "Обновяване"
-#: add-interactive.c:689 add-interactive.c:877
+#: add-interactive.c:697 add-interactive.c:885
#, c-format
msgid "could not stage '%s'"
msgstr "неуспешно добавяне в индекса на „%s“"
-#: add-interactive.c:695 add-interactive.c:884 reset.c:89 sequencer.c:3444
+#: add-interactive.c:703 add-interactive.c:892 reset.c:89 sequencer.c:3478
msgid "could not write index"
msgstr "индексът не може да бъде записан"
-#: add-interactive.c:698 git-add--interactive.perl:628
+#: add-interactive.c:706 git-add--interactive.perl:626
#, c-format, perl-format
msgid "updated %d path\n"
msgid_plural "updated %d paths\n"
msgstr[0] "%d файл обновен\n"
msgstr[1] "%d файла обновени\n"
-#: add-interactive.c:716 git-add--interactive.perl:678
+#: add-interactive.c:724 git-add--interactive.perl:676
#, c-format, perl-format
msgid "note: %s is untracked now.\n"
msgstr "БЕЛЕЖКА: „%s“ вече не се следи.\n"
-#: add-interactive.c:721 apply.c:4127 builtin/checkout.c:295
+#: add-interactive.c:729 apply.c:4125 builtin/checkout.c:295
#: builtin/reset.c:145
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "неуспешно създаване на запис в кеша чрез „make_cache_entry“ за „%s“"
-#: add-interactive.c:751 git-add--interactive.perl:655
+#: add-interactive.c:759 git-add--interactive.perl:653
msgid "Revert"
msgstr "Отмяна"
-#: add-interactive.c:767
+#: add-interactive.c:775
msgid "Could not parse HEAD^{tree}"
msgstr "Указателят „HEAD^{tree}“ не може да бъде анализиран"
-#: add-interactive.c:805 git-add--interactive.perl:631
+#: add-interactive.c:813 git-add--interactive.perl:629
#, c-format, perl-format
msgid "reverted %d path\n"
msgid_plural "reverted %d paths\n"
msgstr[0] "%d файл с отменени промени\n"
msgstr[1] "%d файла с отменени промени\n"
-#: add-interactive.c:856 git-add--interactive.perl:695
+#: add-interactive.c:864 git-add--interactive.perl:693
#, c-format
msgid "No untracked files.\n"
msgstr "Няма неследени файлове.\n"
-#: add-interactive.c:860 git-add--interactive.perl:689
+#: add-interactive.c:868 git-add--interactive.perl:687
msgid "Add untracked"
msgstr "Добавяне на неследени"
-#: add-interactive.c:887 git-add--interactive.perl:625
+#: add-interactive.c:895 git-add--interactive.perl:623
#, c-format, perl-format
msgid "added %d path\n"
msgid_plural "added %d paths\n"
msgstr[0] "%d файл добавен\n"
msgstr[1] "%d файла добавени\n"
-#: add-interactive.c:917
+#: add-interactive.c:925
#, c-format
msgid "ignoring unmerged: %s"
msgstr "пренебрегване на неслятото: „%s“"
-#: add-interactive.c:929 add-patch.c:1738 git-add--interactive.perl:1371
+#: add-interactive.c:937 add-patch.c:1751 git-add--interactive.perl:1369
#, c-format
msgid "Only binary files changed.\n"
msgstr "Само двоични файлове са променени.\n"
-#: add-interactive.c:931 add-patch.c:1736 git-add--interactive.perl:1373
+#: add-interactive.c:939 add-patch.c:1749 git-add--interactive.perl:1371
#, c-format
msgid "No changes.\n"
msgstr "Няма промени.\n"
-#: add-interactive.c:935 git-add--interactive.perl:1381
+#: add-interactive.c:943 git-add--interactive.perl:1379
msgid "Patch update"
msgstr "Обновяване на кръпка"
-#: add-interactive.c:974 git-add--interactive.perl:1794
+#: add-interactive.c:982 git-add--interactive.perl:1792
msgid "Review diff"
msgstr "Преглед на разликата"
-#: add-interactive.c:1002
+#: add-interactive.c:1010
msgid "show paths with changes"
msgstr "извеждане на пътищата с промени"
-#: add-interactive.c:1004
+#: add-interactive.c:1012
msgid "add working tree state to the staged set of changes"
msgstr "добавяне на състоянието на работното дърво към промените в индекса"
-#: add-interactive.c:1006
+#: add-interactive.c:1014
msgid "revert staged set of changes back to the HEAD version"
msgstr "връщане на състоянието на индекса към соченото от „HEAD“"
-#: add-interactive.c:1008
+#: add-interactive.c:1016
msgid "pick hunks and update selectively"
msgstr "интерактивни избор и промяна на парчета код"
-#: add-interactive.c:1010
+#: add-interactive.c:1018
msgid "view diff between HEAD and index"
msgstr "разлика между соченото от „HEAD“ и индекса"
-#: add-interactive.c:1012
+#: add-interactive.c:1020
msgid "add contents of untracked files to the staged set of changes"
msgstr "добавяне на съдържанието на неследените файлове към индекса"
-#: add-interactive.c:1020 add-interactive.c:1069
+#: add-interactive.c:1028 add-interactive.c:1077
msgid "Prompt help:"
msgstr "Помощ:"
-#: add-interactive.c:1022
+#: add-interactive.c:1030
msgid "select a single item"
msgstr "избор на eдин елемент"
-#: add-interactive.c:1024
+#: add-interactive.c:1032
msgid "select a range of items"
msgstr "избор на поредица от елементи"
-#: add-interactive.c:1026
+#: add-interactive.c:1034
msgid "select multiple ranges"
msgstr "избор на няколко поредици от елементи"
-#: add-interactive.c:1028 add-interactive.c:1073
+#: add-interactive.c:1036 add-interactive.c:1081
msgid "select item based on unique prefix"
msgstr "избор на базата на уникален префикс"
-#: add-interactive.c:1030
+#: add-interactive.c:1038
msgid "unselect specified items"
msgstr "изваждане на указаното от избора"
-#: add-interactive.c:1032
+#: add-interactive.c:1040
msgid "choose all items"
msgstr "избор на всички елементи"
-#: add-interactive.c:1034
+#: add-interactive.c:1042
msgid "(empty) finish selecting"
msgstr "(празно) приключване на избирането"
-#: add-interactive.c:1071
+#: add-interactive.c:1079
msgid "select a numbered item"
msgstr "избор на номериран елемент"
-#: add-interactive.c:1075
+#: add-interactive.c:1083
msgid "(empty) select nothing"
msgstr "(празно) без избор на нищо"
-#: add-interactive.c:1083 builtin/clean.c:816 git-add--interactive.perl:1891
+#: add-interactive.c:1091 builtin/clean.c:816 git-add--interactive.perl:1896
msgid "*** Commands ***"
msgstr "●●● Команди ●●●"
-#: add-interactive.c:1084 builtin/clean.c:817 git-add--interactive.perl:1888
+#: add-interactive.c:1092 builtin/clean.c:817 git-add--interactive.perl:1893
msgid "What now"
msgstr "Избор на следващо действие"
-#: add-interactive.c:1136 git-add--interactive.perl:213
+#: add-interactive.c:1144 git-add--interactive.perl:213
msgid "staged"
msgstr "в индекса"
-#: add-interactive.c:1136 git-add--interactive.perl:213
+#: add-interactive.c:1144 git-add--interactive.perl:213
msgid "unstaged"
msgstr "извън индекса"
-#: add-interactive.c:1136 apply.c:4984 apply.c:4987 builtin/am.c:2270
-#: builtin/am.c:2273 builtin/bugreport.c:133 builtin/clone.c:123
-#: builtin/fetch.c:147 builtin/merge.c:275 builtin/pull.c:190
+#: add-interactive.c:1144 apply.c:4987 apply.c:4990 builtin/am.c:2257
+#: builtin/am.c:2260 builtin/bugreport.c:134 builtin/clone.c:124
+#: builtin/fetch.c:147 builtin/merge.c:284 builtin/pull.c:190
#: builtin/submodule--helper.c:409 builtin/submodule--helper.c:1818
#: builtin/submodule--helper.c:1821 builtin/submodule--helper.c:2326
#: builtin/submodule--helper.c:2329 builtin/submodule--helper.c:2572
@@ -377,32 +378,32 @@ msgstr "извън индекса"
msgid "path"
msgstr "път"
-#: add-interactive.c:1143
+#: add-interactive.c:1151
msgid "could not refresh index"
msgstr "индексът не може да бъде обновен"
#
-#: add-interactive.c:1157 builtin/clean.c:781 git-add--interactive.perl:1805
+#: add-interactive.c:1165 builtin/clean.c:781 git-add--interactive.perl:1803
#, c-format
msgid "Bye.\n"
msgstr "Изход.\n"
-#: add-patch.c:34 git-add--interactive.perl:1433
+#: add-patch.c:34 git-add--interactive.perl:1431
#, c-format, perl-format
msgid "Stage mode change [y,n,q,a,d%s,?]? "
msgstr "Добавяне на промяната на правата за достъп [y,n,q,a,d%s,?]? "
-#: add-patch.c:35 git-add--interactive.perl:1434
+#: add-patch.c:35 git-add--interactive.perl:1432
#, c-format, perl-format
msgid "Stage deletion [y,n,q,a,d%s,?]? "
msgstr "Добавяне на изтриването [y,n,q,a,d%s,?]? "
-#: add-patch.c:36 git-add--interactive.perl:1435
+#: add-patch.c:36 git-add--interactive.perl:1433
#, c-format, perl-format
msgid "Stage addition [y,n,q,a,d%s,?]? "
msgstr "Добавяне на добавянето [y,n,q,a,d%s,?]? "
-#: add-patch.c:37 git-add--interactive.perl:1436
+#: add-patch.c:37 git-add--interactive.perl:1434
#, c-format, perl-format
msgid "Stage this hunk [y,n,q,a,d%s,?]? "
msgstr "Добавяне на това парче [y,n,q,a,d%s,?]? "
@@ -429,22 +430,22 @@ msgstr ""
"a — добавяне на това и всички следващи парчета от файла в индекса\n"
"d — без добавяне на това и всички следващи парчета от файла в индекса\n"
-#: add-patch.c:56 git-add--interactive.perl:1439
+#: add-patch.c:56 git-add--interactive.perl:1437
#, c-format, perl-format
msgid "Stash mode change [y,n,q,a,d%s,?]? "
msgstr "Скатаване на промяната на правата за достъп [y,n,q,a,d%s,?]? "
-#: add-patch.c:57 git-add--interactive.perl:1440
+#: add-patch.c:57 git-add--interactive.perl:1438
#, c-format, perl-format
msgid "Stash deletion [y,n,q,a,d%s,?]? "
msgstr "Скатаване на изтриването [y,n,q,a,d%s,?]? "
-#: add-patch.c:58 git-add--interactive.perl:1441
+#: add-patch.c:58 git-add--interactive.perl:1439
#, c-format, perl-format
msgid "Stash addition [y,n,q,a,d%s,?]? "
msgstr "Скатаване на добавянето [y,n,q,a,d%s,?]? "
-#: add-patch.c:59 git-add--interactive.perl:1442
+#: add-patch.c:59 git-add--interactive.perl:1440
#, c-format, perl-format
msgid "Stash this hunk [y,n,q,a,d%s,?]? "
msgstr "Скатаване на това парче [y,n,q,a,d%s,?]? "
@@ -471,22 +472,22 @@ msgstr ""
"a — скатаване на това и всички следващи парчета от файла\n"
"d — без скатаване на това и всички следващи парчета от файла\n"
-#: add-patch.c:80 git-add--interactive.perl:1445
+#: add-patch.c:80 git-add--interactive.perl:1443
#, c-format, perl-format
msgid "Unstage mode change [y,n,q,a,d%s,?]? "
msgstr "Изваждане на промяната на правата за достъп [y,n,q,a,d%s,?]? "
-#: add-patch.c:81 git-add--interactive.perl:1446
+#: add-patch.c:81 git-add--interactive.perl:1444
#, c-format, perl-format
msgid "Unstage deletion [y,n,q,a,d%s,?]? "
msgstr "Изваждане на изтриването [y,n,q,a,d%s,?]? "
-#: add-patch.c:82 git-add--interactive.perl:1447
+#: add-patch.c:82 git-add--interactive.perl:1445
#, c-format, perl-format
msgid "Unstage addition [y,n,q,a,d%s,?]? "
msgstr "Изваждане на добавянето [y,n,q,a,d%s,?]? "
-#: add-patch.c:83 git-add--interactive.perl:1448
+#: add-patch.c:83 git-add--interactive.perl:1446
#, c-format, perl-format
msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
msgstr "Изваждане на това парче [y,n,q,a,d%s,?]? "
@@ -513,23 +514,23 @@ msgstr ""
"a — изваждане на това и всички следващи парчета от файла от индекса\n"
"d — без изваждане на това и всички следващи парчета от файла от индекса\n"
-#: add-patch.c:103 git-add--interactive.perl:1451
+#: add-patch.c:103 git-add--interactive.perl:1449
#, c-format, perl-format
msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
msgstr ""
"Прилагане на промяната на правата за достъп към индекса [y,n,q,a,d%s,?]? "
-#: add-patch.c:104 git-add--interactive.perl:1452
+#: add-patch.c:104 git-add--interactive.perl:1450
#, c-format, perl-format
msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
msgstr "Прилагане на изтриването към индекса [y,n,q,a,d%s,?]? "
-#: add-patch.c:105 git-add--interactive.perl:1453
+#: add-patch.c:105 git-add--interactive.perl:1451
#, c-format, perl-format
msgid "Apply addition to index [y,n,q,a,d%s,?]? "
msgstr "Прилагане на добавянето към индекса [y,n,q,a,d%s,?]? "
-#: add-patch.c:106 git-add--interactive.perl:1454
+#: add-patch.c:106 git-add--interactive.perl:1452
#, c-format, perl-format
msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
msgstr "Прилагане на това парче към индекса [y,n,q,a,d%s,?]? "
@@ -556,28 +557,28 @@ msgstr ""
"a — прилагане на това и всички следващи парчета от файла към индекса\n"
"d — без прилагане на това и всички следващи парчета от файла към индекса\n"
-#: add-patch.c:126 git-add--interactive.perl:1457
-#: git-add--interactive.perl:1475
+#: add-patch.c:126 git-add--interactive.perl:1455
+#: git-add--interactive.perl:1473
#, c-format, perl-format
msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Премахване на промяната в правата за достъп от работното дърво [y,n,q,a,d"
"%s,?]? "
-#: add-patch.c:127 git-add--interactive.perl:1458
-#: git-add--interactive.perl:1476
+#: add-patch.c:127 git-add--interactive.perl:1456
+#: git-add--interactive.perl:1474
#, c-format, perl-format
msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
msgstr "Премахване на изтриването от работното дърво [y,n,q,a,d%s,?]? "
-#: add-patch.c:128 git-add--interactive.perl:1459
-#: git-add--interactive.perl:1477
+#: add-patch.c:128 git-add--interactive.perl:1457
+#: git-add--interactive.perl:1475
#, c-format, perl-format
msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
msgstr "Премахване на добавянето от работното дърво [y,n,q,a,d%s,?]? "
-#: add-patch.c:129 git-add--interactive.perl:1460
-#: git-add--interactive.perl:1478
+#: add-patch.c:129 git-add--interactive.perl:1458
+#: git-add--interactive.perl:1476
#, c-format, perl-format
msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
msgstr "Премахване на парчето от работното дърво [y,n,q,a,d%s,?]? "
@@ -607,26 +608,26 @@ msgstr ""
"d — без премахване на това и всички следващи парчета от файла от работното "
"дърво\n"
-#: add-patch.c:149 add-patch.c:194 git-add--interactive.perl:1463
+#: add-patch.c:149 add-patch.c:194 git-add--interactive.perl:1461
#, c-format, perl-format
msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Премахване на промяната в правата за достъп от индекса и работното дърво [y,"
"n,q,a,d%s,?]? "
-#: add-patch.c:150 add-patch.c:195 git-add--interactive.perl:1464
+#: add-patch.c:150 add-patch.c:195 git-add--interactive.perl:1462
#, c-format, perl-format
msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Премахване на изтриването от индекса и работното дърво [y,n,q,a,d%s,?]? "
-#: add-patch.c:151 add-patch.c:196 git-add--interactive.perl:1465
+#: add-patch.c:151 add-patch.c:196 git-add--interactive.perl:1463
#, c-format, perl-format
msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Премахване на добавянето от индекса и работното дърво [y,n,q,a,d%s,?]? "
-#: add-patch.c:152 add-patch.c:197 git-add--interactive.perl:1466
+#: add-patch.c:152 add-patch.c:197 git-add--interactive.perl:1464
#, c-format, perl-format
msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
msgstr "Премахване на парчето от индекса и работното дърво [y,n,q,a,d%s,?]? "
@@ -648,25 +649,25 @@ msgstr ""
"d — без премахване на това и всички следващи парчета от файла от индекса и "
"работното дърво\n"
-#: add-patch.c:171 add-patch.c:216 git-add--interactive.perl:1469
+#: add-patch.c:171 add-patch.c:216 git-add--interactive.perl:1467
#, c-format, perl-format
msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Прилагане на промяната в правата за достъп от индекса и работното дърво [y,n,"
"q,a,d%s,?]? "
-#: add-patch.c:172 add-patch.c:217 git-add--interactive.perl:1470
+#: add-patch.c:172 add-patch.c:217 git-add--interactive.perl:1468
#, c-format, perl-format
msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Прилагане на изтриването от индекса и работното дърво [y,n,q,a,d%s,?]? "
-#: add-patch.c:173 add-patch.c:218 git-add--interactive.perl:1471
+#: add-patch.c:173 add-patch.c:218 git-add--interactive.perl:1469
#, c-format, perl-format
msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Прилагане на добавянето от индекса и работното дърво [y,n,q,a,d%s,?]? "
-#: add-patch.c:174 add-patch.c:219 git-add--interactive.perl:1472
+#: add-patch.c:174 add-patch.c:219 git-add--interactive.perl:1470
#, c-format, perl-format
msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Прилагане на парчето от индекса и работното дърво [y,n,q,a,d%s,?]? "
@@ -737,7 +738,7 @@ msgstr ""
"Обработените редове на изхода на ползвания филтър, трябва\n"
"да се отнасят едно към едно спрямо редовете на входа."
-#: add-patch.c:785
+#: add-patch.c:790
#, c-format
msgid ""
"expected context line #%d in\n"
@@ -746,7 +747,7 @@ msgstr ""
"очаква се ред №%d от контекста в\n"
"%.*s"
-#: add-patch.c:800
+#: add-patch.c:805
#, c-format
msgid ""
"hunks do not overlap:\n"
@@ -759,11 +760,11 @@ msgstr ""
" не завършва с:\n"
"%.*s"
-#: add-patch.c:1076 git-add--interactive.perl:1117
+#: add-patch.c:1081 git-add--interactive.perl:1115
msgid "Manual hunk edit mode -- see bottom for a quick guide.\n"
msgstr "Ръчно редактиране на парчета код — отдолу има подсказка.\n"
-#: add-patch.c:1080
+#: add-patch.c:1085
#, c-format
msgid ""
"---\n"
@@ -778,7 +779,7 @@ msgstr ""
"Редовете, които започват с „%c“ ще бъдат пропуснати.\n"
#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
-#: add-patch.c:1094 git-add--interactive.perl:1131
+#: add-patch.c:1099 git-add--interactive.perl:1129
msgid ""
"If it does not apply cleanly, you will be given an opportunity to\n"
"edit again. If all lines of the hunk are removed, then the edit is\n"
@@ -788,11 +789,11 @@ msgstr ""
"изтриете всички редове от парчето код, то ще бъде оставено непроменено, а\n"
"редактирането — отказано.\n"
-#: add-patch.c:1127
+#: add-patch.c:1132
msgid "could not parse hunk header"
msgstr "заглавната част парчето не може да се анализира"
-#: add-patch.c:1172
+#: add-patch.c:1177
msgid "'git apply --cached' failed"
msgstr "неуспешно изпълнение на „git apply --cached“"
@@ -808,7 +809,7 @@ msgstr "неуспешно изпълнение на „git apply --cached“"
#. Consider translating (saying "no" discards!) as
#. (saying "n" for "no" discards!) if the translation
#. of the word "no" does not start with n.
-#: add-patch.c:1241 git-add--interactive.perl:1244
+#: add-patch.c:1246 git-add--interactive.perl:1242
msgid ""
"Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
msgstr ""
@@ -816,19 +817,19 @@ msgstr ""
"редактирането? (текущите редакции ще се отменят при отказ!): „y“ (да)/ "
"„n“ (не)? "
-#: add-patch.c:1284
+#: add-patch.c:1289
msgid "The selected hunks do not apply to the index!"
msgstr "Избраните парчета не могат да се добавят в индекса!"
-#: add-patch.c:1285 git-add--interactive.perl:1348
+#: add-patch.c:1290 git-add--interactive.perl:1346
msgid "Apply them to the worktree anyway? "
msgstr "Да се приложат ли към работното дърво? "
-#: add-patch.c:1292 git-add--interactive.perl:1351
+#: add-patch.c:1297 git-add--interactive.perl:1349
msgid "Nothing was applied.\n"
msgstr "Нищо не е приложено.\n"
-#: add-patch.c:1349
+#: add-patch.c:1354
msgid ""
"j - leave this hunk undecided, see next undecided hunk\n"
"J - leave this hunk undecided, see next hunk\n"
@@ -850,73 +851,73 @@ msgstr ""
"e — ръчно редактиране на текущото парче\n"
"? — извеждане не помощта\n"
-#: add-patch.c:1511 add-patch.c:1521
+#: add-patch.c:1516 add-patch.c:1526
msgid "No previous hunk"
msgstr "Няма друго парче преди това"
-#: add-patch.c:1516 add-patch.c:1526
+#: add-patch.c:1521 add-patch.c:1531
msgid "No next hunk"
msgstr "Няма друго парче след това"
-#: add-patch.c:1532
+#: add-patch.c:1537
msgid "No other hunks to goto"
msgstr "Няма други парчета"
-#: add-patch.c:1543 git-add--interactive.perl:1608
+#: add-patch.c:1548 git-add--interactive.perl:1606
msgid "go to which hunk (<ret> to see more)? "
msgstr "към кое парче да се придвижи (за повече варианти натиснете „enter“)? "
-#: add-patch.c:1544 git-add--interactive.perl:1610
+#: add-patch.c:1549 git-add--interactive.perl:1608
msgid "go to which hunk? "
msgstr "към кое парче да се придвижи? "
-#: add-patch.c:1555
+#: add-patch.c:1560
#, c-format
msgid "Invalid number: '%s'"
msgstr "Неправилен номер: „%s“"
-#: add-patch.c:1560
+#: add-patch.c:1565
#, c-format
msgid "Sorry, only %d hunk available."
msgid_plural "Sorry, only %d hunks available."
msgstr[0] "Има само %d парче."
msgstr[1] "Има само %d парчета."
-#: add-patch.c:1569
+#: add-patch.c:1574
msgid "No other hunks to search"
msgstr "Няма други парчета за търсене"
-#: add-patch.c:1575 git-add--interactive.perl:1663
+#: add-patch.c:1580 git-add--interactive.perl:1661
msgid "search for regex? "
msgstr "да се търси с регулярен израз? "
-#: add-patch.c:1590
+#: add-patch.c:1595
#, c-format
msgid "Malformed search regexp %s: %s"
msgstr "Сгрешен регулярен израз „%s“: %s"
-#: add-patch.c:1607
+#: add-patch.c:1612
msgid "No hunk matches the given pattern"
msgstr "Никое парче не напасва на регулярния израз"
-#: add-patch.c:1614
+#: add-patch.c:1619
msgid "Sorry, cannot split this hunk"
msgstr "Това парче не може да бъде разделено"
-#: add-patch.c:1618
+#: add-patch.c:1623
#, c-format
msgid "Split into %d hunks."
msgstr "Разделяне на %d парчета."
-#: add-patch.c:1622
+#: add-patch.c:1627
msgid "Sorry, cannot edit this hunk"
msgstr "Това парче не може да бъде редактирано"
-#: add-patch.c:1674
+#: add-patch.c:1679
msgid "'git apply' failed"
msgstr "неуспешно изпълнение на „git apply“"
-#: advice.c:140
+#: advice.c:143
#, c-format
msgid ""
"\n"
@@ -926,37 +927,37 @@ msgstr ""
"За да изключите това предупреждение, изпълнете:\n"
" git config advice.%s false"
-#: advice.c:156
+#: advice.c:159
#, c-format
msgid "%shint: %.*s%s\n"
msgstr "%sподсказка: %.*s%s\n"
-#: advice.c:247
+#: advice.c:250
msgid "Cherry-picking is not possible because you have unmerged files."
msgstr "Отбирането на подавания е блокирано от неслети файлове."
-#: advice.c:249
+#: advice.c:252
msgid "Committing is not possible because you have unmerged files."
msgstr "Подаването е блокирано от неслети файлове."
-#: advice.c:251
+#: advice.c:254
msgid "Merging is not possible because you have unmerged files."
msgstr "Сливането е блокирано от неслети файлове."
-#: advice.c:253
+#: advice.c:256
msgid "Pulling is not possible because you have unmerged files."
msgstr "Издърпването е блокирано от неслети файлове."
-#: advice.c:255
+#: advice.c:258
msgid "Reverting is not possible because you have unmerged files."
msgstr "Отмяната е блокирана от неслети файлове."
-#: advice.c:257
+#: advice.c:260
#, c-format
msgid "It is not possible to %s because you have unmerged files."
msgstr "Действието „%s“ е блокирано от неслети файлове."
-#: advice.c:265
+#: advice.c:268
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."
@@ -964,23 +965,23 @@ msgstr ""
"Редактирайте ги в работното дърво, и тогава ползвайте „git add/rm ФАЙЛ“,\n"
"за да отбележите коригирането им. След това извършете подаването."
-#: advice.c:273
+#: advice.c:276
msgid "Exiting because of an unresolved conflict."
msgstr "Изход от програмата заради некоригиран конфликт."
-#: advice.c:278 builtin/merge.c:1349
+#: advice.c:281 builtin/merge.c:1369
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "Не сте завършили сливане. (Указателят „MERGE_HEAD“ съществува)."
-#: advice.c:280
+#: advice.c:283
msgid "Please, commit your changes before merging."
msgstr "Промените трябва да се подадат преди сливане."
-#: advice.c:281
+#: advice.c:284
msgid "Exiting because of unfinished merge."
msgstr "Изход от програмата заради незавършено сливане."
-#: advice.c:287
+#: advice.c:290
#, c-format
msgid ""
"Note: switching to '%s'.\n"
@@ -1284,7 +1285,7 @@ msgstr "неуспешно прилагане на кръпка: „%s:%ld“"
msgid "cannot checkout %s"
msgstr "„%s“ не може да се изтегли"
-#: apply.c:3405 apply.c:3416 apply.c:3462 midx.c:72 setup.c:308
+#: apply.c:3405 apply.c:3416 apply.c:3462 midx.c:73 setup.c:308
#, c-format
msgid "failed to read %s"
msgstr "файлът „%s“ не може да бъде прочетен"
@@ -1304,7 +1305,7 @@ msgstr "обектът с път „%s“ е преименуван или из
msgid "%s: does not exist in index"
msgstr "„%s“ не съществува в индекса"
-#: apply.c:3537 apply.c:3708 apply.c:3953
+#: apply.c:3537 apply.c:3708 apply.c:3952
#, c-format
msgid "%s: does not match index"
msgstr "„%s“ не съответства на индекса"
@@ -1365,174 +1366,174 @@ msgstr "неправилен път: „%s“"
msgid "%s: already exists in index"
msgstr "„%s“: вече съществува в индекса"
-#: apply.c:3956
+#: apply.c:3954
#, c-format
msgid "%s: already exists in working directory"
msgstr "„%s“: вече съществува в работното дърво"
-#: apply.c:3976
+#: apply.c:3974
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr "новите права за достъп (%o) на „%s“ не съвпадат със старите (%o)"
-#: apply.c:3981
+#: apply.c:3979
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
msgstr ""
"новите права за достъп (%o) на „%s“ не съвпадат със старите (%o) на „%s“"
-#: apply.c:4001
+#: apply.c:3999
#, c-format
msgid "affected file '%s' is beyond a symbolic link"
msgstr "засегнатият файл „%s“ е след символна връзка"
-#: apply.c:4005
+#: apply.c:4003
#, c-format
msgid "%s: patch does not apply"
msgstr "Кръпката „%s“ не може да бъде приложена"
-#: apply.c:4020
+#: apply.c:4018
#, c-format
msgid "Checking patch %s..."
msgstr "Проверяване на кръпката „%s“…"
-#: apply.c:4112
+#: apply.c:4110
#, c-format
msgid "sha1 information is lacking or useless for submodule %s"
msgstr ""
"информацията за сумата по SHA1 за подмодула липсва или не е достатъчна (%s)."
-#: apply.c:4119
+#: apply.c:4117
#, c-format
msgid "mode change for %s, which is not in current HEAD"
msgstr "смяна на режима на достъпа на „%s“, който не е в текущия връх „HEAD“"
-#: apply.c:4122
+#: apply.c:4120
#, c-format
msgid "sha1 information is lacking or useless (%s)."
msgstr "информацията за сумата по SHA1 липсва или не е достатъчна (%s)."
-#: apply.c:4131
+#: apply.c:4129
#, c-format
msgid "could not add %s to temporary index"
msgstr "„%s“ не може да се добави към временния индекс"
-#: apply.c:4141
+#: apply.c:4139
#, c-format
msgid "could not write temporary index to %s"
msgstr "временният индекс не може да се запази в „%s“"
-#: apply.c:4279
+#: apply.c:4277
#, c-format
msgid "unable to remove %s from index"
msgstr "„%s“ не може да се извади от индекса"
-#: apply.c:4313
+#: apply.c:4311
#, c-format
msgid "corrupt patch for submodule %s"
msgstr "повредена кръпка за модула „%s“"
-#: apply.c:4319
+#: apply.c:4317
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr ""
"не може да се получи информация чрез „stat“ за новосъздадения файл „%s“"
-#: apply.c:4327
+#: apply.c:4325
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr ""
"не може да се за създаде мястото за съхранение на новосъздадения файл „%s“"
-#: apply.c:4333 apply.c:4478
+#: apply.c:4331 apply.c:4476
#, c-format
msgid "unable to add cache entry for %s"
msgstr "не може да се добави запис в кеша за „%s“"
-#: apply.c:4376 builtin/bisect--helper.c:537
+#: apply.c:4374 builtin/bisect--helper.c:524
#, c-format
msgid "failed to write to '%s'"
msgstr "в „%s“ не може да се пише"
-#: apply.c:4380
+#: apply.c:4378
#, c-format
msgid "closing file '%s'"
msgstr "затваряне на файла „%s“"
-#: apply.c:4450
+#: apply.c:4448
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "файлът „%s“ не може да се запише с режим на достъп „%o“"
-#: apply.c:4548
+#: apply.c:4546
#, c-format
msgid "Applied patch %s cleanly."
msgstr "Кръпката „%s“ бе приложена чисто."
-#: apply.c:4556
+#: apply.c:4554
msgid "internal error"
msgstr "вътрешна грешка"
-#: apply.c:4559
+#: apply.c:4557
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
msgstr[0] "Прилагане на кръпката „%%s“ с %d отхвърлено парче…"
msgstr[1] "Прилагане на кръпката „%%s“ с %d отхвърлени парчета…"
-#: apply.c:4570
+#: apply.c:4568
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "съкращаване на името на файла с отхвърлените парчета на „ %.*s.rej“"
-#: apply.c:4578 builtin/fetch.c:927 builtin/fetch.c:1228
+#: apply.c:4576 builtin/fetch.c:927 builtin/fetch.c:1228
#, c-format
msgid "cannot open %s"
msgstr "„%s“ не може да бъде отворен"
-#: apply.c:4592
+#: apply.c:4590
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "%d-то парче бе успешно приложено."
-#: apply.c:4596
+#: apply.c:4594
#, c-format
msgid "Rejected hunk #%d."
msgstr "%d-то парче бе отхвърлено."
-#: apply.c:4715
+#: apply.c:4718
#, c-format
msgid "Skipped patch '%s'."
msgstr "Пропусната кръпка: „%s“"
-#: apply.c:4723
+#: apply.c:4726
msgid "unrecognized input"
msgstr "непознат вход"
-#: apply.c:4743
+#: apply.c:4746
msgid "unable to read index file"
msgstr "индексът не може да бъде записан"
-#: apply.c:4900
+#: apply.c:4903
#, c-format
msgid "can't open patch '%s': %s"
msgstr "кръпката „%s“ не може да бъде отворена: %s"
-#: apply.c:4927
+#: apply.c:4930
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] "пренебрегната е %d грешка в знаците за интервали"
msgstr[1] "пренебрегнати са %d грешки в знаците за интервали"
-#: apply.c:4933 apply.c:4948
+#: apply.c:4936 apply.c:4951
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
msgstr[0] "%d ред добавя грешки в знаците за интервали."
msgstr[1] "%d реда добавят грешки в знаците за интервали."
-#: apply.c:4941
+#: apply.c:4944
#, c-format
msgid "%d line applied after fixing whitespace errors."
msgid_plural "%d lines applied after fixing whitespace errors."
@@ -1541,135 +1542,135 @@ msgstr[0] ""
msgstr[1] ""
"Добавени са %d реда след корекцията на грешките в знаците за интервали."
-#: apply.c:4957 builtin/add.c:618 builtin/mv.c:304 builtin/rm.c:406
+#: apply.c:4960 builtin/add.c:618 builtin/mv.c:304 builtin/rm.c:406
msgid "Unable to write new index file"
msgstr "Новият индекс не може да бъде записан"
-#: apply.c:4985
+#: apply.c:4988
msgid "don't apply changes matching the given path"
msgstr "без прилагане на промените напасващи на дадения път"
-#: apply.c:4988
+#: apply.c:4991
msgid "apply changes matching the given path"
msgstr "прилагане на промените напасващи на дадения път"
-#: apply.c:4990 builtin/am.c:2279
+#: apply.c:4993 builtin/am.c:2266
msgid "num"
msgstr "БРОЙ"
-#: apply.c:4991
+#: apply.c:4994
msgid "remove <num> leading slashes from traditional diff paths"
msgstr "премахване на този БРОЙ водещи елементи от пътищата в разликата"
-#: apply.c:4994
+#: apply.c:4997
msgid "ignore additions made by the patch"
msgstr "игнориране на редовете добавени от тази кръпка"
-#: apply.c:4996
+#: apply.c:4999
msgid "instead of applying the patch, output diffstat for the input"
msgstr "извеждане на статистика на промените без прилагане на кръпката"
-#: apply.c:5000
+#: apply.c:5003
msgid "show number of added and deleted lines in decimal notation"
msgstr "извеждане на броя на добавените и изтритите редове"
-#: apply.c:5002
+#: apply.c:5005
msgid "instead of applying the patch, output a summary for the input"
msgstr "извеждане на статистика на входните данни без прилагане на кръпката"
-#: apply.c:5004
+#: apply.c:5007
msgid "instead of applying the patch, see if the patch is applicable"
msgstr "проверка дали кръпката може да се приложи, без действително прилагане"
-#: apply.c:5006
+#: apply.c:5009
msgid "make sure the patch is applicable to the current index"
msgstr "проверка дали кръпката може да бъде приложена към текущия индекс"
-#: apply.c:5008
+#: apply.c:5011
msgid "mark new files with `git add --intent-to-add`"
msgstr "отбелязване на новите файлове с „git add --intent-to-add“"
-#: apply.c:5010
+#: apply.c:5013
msgid "apply a patch without touching the working tree"
msgstr "прилагане на кръпката без промяна на работното дърво"
-#: apply.c:5012
+#: apply.c:5015
msgid "accept a patch that touches outside the working area"
msgstr "прилагане на кръпка, която променя и файлове извън работното дърво"
-#: apply.c:5015
+#: apply.c:5018
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr ""
"кръпката да бъде приложена. Опцията се комбинира с „--check“/„--stat“/„--"
"summary“"
-#: apply.c:5017
+#: apply.c:5020
msgid "attempt three-way merge if a patch does not apply"
msgstr "пробване с тройно сливане, ако кръпката не може да се приложи директно"
-#: apply.c:5019
+#: apply.c:5022
msgid "build a temporary index based on embedded index information"
msgstr ""
"създаване на временен индекс на база на включената информация за индекса"
-#: apply.c:5022 builtin/checkout-index.c:173 builtin/ls-files.c:525
+#: apply.c:5025 builtin/checkout-index.c:182 builtin/ls-files.c:525
msgid "paths are separated with NUL character"
msgstr "разделяне на пътищата с нулевия знак „NUL“"
-#: apply.c:5024
+#: apply.c:5027
msgid "ensure at least <n> lines of context match"
msgstr "да се осигури контекст от поне такъв БРОЙ съвпадащи редове"
-#: apply.c:5025 builtin/am.c:2258 builtin/interpret-trailers.c:98
+#: apply.c:5028 builtin/am.c:2245 builtin/interpret-trailers.c:98
#: builtin/interpret-trailers.c:100 builtin/interpret-trailers.c:102
-#: builtin/pack-objects.c:3562 builtin/rebase.c:1340
+#: builtin/pack-objects.c:3562 builtin/rebase.c:1346
msgid "action"
msgstr "действие"
-#: apply.c:5026
+#: apply.c:5029
msgid "detect new or modified lines that have whitespace errors"
msgstr "засичане на нови или променени редове с грешки в знаците за интервали"
-#: apply.c:5029 apply.c:5032
+#: apply.c:5032 apply.c:5035
msgid "ignore changes in whitespace when finding context"
msgstr ""
"игнориране на промените в знаците за интервали при откриване на контекста"
-#: apply.c:5035
+#: apply.c:5038
msgid "apply the patch in reverse"
msgstr "прилагане на кръпката в обратна посока"
-#: apply.c:5037
+#: apply.c:5040
msgid "don't expect at least one line of context"
msgstr "без изискване на дори и един ред контекст"
-#: apply.c:5039
+#: apply.c:5042
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr "оставяне на отхвърлените парчета във файлове с разширение „.rej“"
-#: apply.c:5041
+#: apply.c:5044
msgid "allow overlapping hunks"
msgstr "позволяване на застъпващи се парчета"
-#: apply.c:5042 builtin/add.c:329 builtin/check-ignore.c:22
+#: apply.c:5045 builtin/add.c:329 builtin/check-ignore.c:22
#: builtin/commit.c:1364 builtin/count-objects.c:98 builtin/fsck.c:775
-#: builtin/log.c:2270 builtin/mv.c:123 builtin/read-tree.c:128
+#: builtin/log.c:2287 builtin/mv.c:123 builtin/read-tree.c:128
msgid "be verbose"
msgstr "повече подробности"
-#: apply.c:5044
+#: apply.c:5047
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr "пренебрегване на неправилно липсващ знак за нов ред в края на файл"
-#: apply.c:5047
+#: apply.c:5050
msgid "do not trust the line counts in the hunk headers"
msgstr "без доверяване на номерата на редовете в заглавните части на парчетата"
-#: apply.c:5049 builtin/am.c:2267
+#: apply.c:5052 builtin/am.c:2254
msgid "root"
msgstr "НАЧАЛНА_ДИРЕКТОРИЯ"
-#: apply.c:5050
+#: apply.c:5053
msgid "prepend <root> to all filenames"
msgstr "добавяне на тази НАЧАЛНА_ДИРЕКТОРИЯ към имената на всички файлове"
@@ -1683,16 +1684,16 @@ msgstr "обектът-BLOB „%s“ не може да бъде обработ
msgid "unsupported file mode: 0%o (SHA1: %s)"
msgstr "неподдържани права за достъп до файл: 0%o (SHA1: %s)"
-#: archive-tar.c:449
+#: archive-tar.c:450
#, c-format
msgid "unable to start '%s' filter"
msgstr "филтърът „%s“ не може да бъде стартиран"
-#: archive-tar.c:452
+#: archive-tar.c:453
msgid "unable to redirect descriptor"
msgstr "дескрипторът не може да бъде пренасочен"
-#: archive-tar.c:459
+#: archive-tar.c:460
#, c-format
msgid "'%s' filter reported error"
msgstr "филтърът „%s“ върна грешка"
@@ -1741,9 +1742,9 @@ msgstr "git archive --remote ХРАНИЛИЩЕ [--exec КОМАНДА] --list"
msgid "cannot read %s"
msgstr "обектът „%s“ не може да бъде прочетен"
-#: archive.c:345 sequencer.c:445 sequencer.c:1706 sequencer.c:2852
-#: sequencer.c:3293 sequencer.c:3402 builtin/am.c:263 builtin/commit.c:786
-#: builtin/merge.c:1124
+#: archive.c:345 sequencer.c:459 sequencer.c:1736 sequencer.c:2886
+#: sequencer.c:3327 sequencer.c:3436 builtin/am.c:249 builtin/commit.c:786
+#: builtin/merge.c:1138
#, c-format
msgid "could not read '%s'"
msgstr "файлът „%s“ не може да бъде прочетен"
@@ -1782,118 +1783,110 @@ msgstr "Файлът „%s“ липсва"
msgid "Not a regular file: %s"
msgstr "„%s“ не е обикновен файл"
-#: archive.c:553
+#: archive.c:555
msgid "fmt"
msgstr "ФОРМАТ"
-#: archive.c:553
+#: archive.c:555
msgid "archive format"
msgstr "ФОРМАТ на архива"
-#: archive.c:554 builtin/log.c:1760
+#: archive.c:556 builtin/log.c:1765
msgid "prefix"
msgstr "ПРЕФИКС"
-#: archive.c:555
+#: archive.c:557
msgid "prepend prefix to each pathname in the archive"
msgstr "добавяне на този ПРЕФИКС към всеки път в архива"
-#: archive.c:556 archive.c:559 builtin/blame.c:884 builtin/blame.c:888
-#: builtin/blame.c:889 builtin/commit-tree.c:117 builtin/config.c:133
-#: builtin/fast-export.c:1208 builtin/fast-export.c:1210
-#: builtin/fast-export.c:1214 builtin/grep.c:908 builtin/hash-object.c:105
+#: archive.c:558 archive.c:561 builtin/blame.c:886 builtin/blame.c:890
+#: builtin/blame.c:891 builtin/commit-tree.c:117 builtin/config.c:135
+#: builtin/fast-export.c:1207 builtin/fast-export.c:1209
+#: builtin/fast-export.c:1213 builtin/grep.c:919 builtin/hash-object.c:105
#: builtin/ls-files.c:561 builtin/ls-files.c:564 builtin/notes.c:412
#: builtin/notes.c:578 builtin/read-tree.c:123 parse-options.h:190
msgid "file"
msgstr "ФАЙЛ"
-#: archive.c:557
+#: archive.c:559
msgid "add untracked file to archive"
msgstr "добавяне на неследените файлове към архива"
-#: archive.c:560 builtin/archive.c:90
+#: archive.c:562 builtin/archive.c:90
msgid "write the archive to this file"
msgstr "запазване на архива в този ФАЙЛ"
-#: archive.c:562
+#: archive.c:564
msgid "read .gitattributes in working directory"
msgstr "изчитане на „.gitattributes“ в работната директория"
-#: archive.c:563
+#: archive.c:565
msgid "report archived files on stderr"
msgstr "извеждане на архивираните файлове на стандартната грешка"
-#: archive.c:564
-msgid "store only"
-msgstr "съхранение без компресиране"
-
-#: archive.c:565
-msgid "compress faster"
-msgstr "бързо компресиране"
-
-#: archive.c:573
-msgid "compress better"
-msgstr "добро компресиране"
+#: archive.c:567
+msgid "set compression level"
+msgstr "задаване на нивото на компресиране"
-#: archive.c:576
+#: archive.c:570
msgid "list supported archive formats"
msgstr "извеждане на списъка с поддържаните формати"
-#: archive.c:578 builtin/archive.c:91 builtin/clone.c:113 builtin/clone.c:116
+#: archive.c:572 builtin/archive.c:91 builtin/clone.c:114 builtin/clone.c:117
#: builtin/submodule--helper.c:1830 builtin/submodule--helper.c:2335
msgid "repo"
msgstr "хранилище"
-#: archive.c:579 builtin/archive.c:92
+#: archive.c:573 builtin/archive.c:92
msgid "retrieve the archive from remote repository <repo>"
msgstr "получаване на архива от отдалеченото ХРАНИЛИЩЕ"
-#: archive.c:580 builtin/archive.c:93 builtin/difftool.c:715
+#: archive.c:574 builtin/archive.c:93 builtin/difftool.c:714
#: builtin/notes.c:498
msgid "command"
msgstr "команда"
-#: archive.c:581 builtin/archive.c:94
+#: archive.c:575 builtin/archive.c:94
msgid "path to the remote git-upload-archive command"
msgstr "път към отдалечената команда „git-upload-archive“"
-#: archive.c:588
+#: archive.c:582
msgid "Unexpected option --remote"
msgstr "Неочаквана опция „--remote“"
-#: archive.c:590
+#: archive.c:584
msgid "Option --exec can only be used together with --remote"
msgstr "Опцията „--exec“ изисква „--remote“"
-#: archive.c:592
+#: archive.c:586
msgid "Unexpected option --output"
msgstr "Неочаквана опция „--output“"
-#: archive.c:594
+#: archive.c:588
msgid "Options --add-file and --remote cannot be used together"
msgstr "Опциите „--add-file“ и „--remote“ са несъвместими"
-#: archive.c:616
+#: archive.c:610
#, c-format
msgid "Unknown archive format '%s'"
msgstr "Непознат формат на архив: „%s“"
-#: archive.c:623
+#: archive.c:619
#, c-format
msgid "Argument not supported for format '%s': -%d"
msgstr "Аргументът не се поддържа за форма̀та „%s“: -%d"
-#: attr.c:212
+#: attr.c:202
#, c-format
msgid "%.*s is not a valid attribute name"
msgstr "„%.*s“ е неправилно име за атрибут"
-#: attr.c:369
+#: attr.c:359
#, c-format
msgid "%s not allowed: %s:%d"
msgstr "%s: командата не е позволена: „%s:%d“"
-#: attr.c:409
+#: attr.c:399
msgid ""
"Negative patterns are ignored in git attributes\n"
"Use '\\!' for literal leading exclamation."
@@ -1901,22 +1894,22 @@ msgstr ""
"Отрицателните шаблони се игнорират в атрибутите на git.\n"
"Ако ви трябва начална удивителна, ползвайте „\\!“."
-#: bisect.c:476
+#: bisect.c:489
#, c-format
msgid "Badly quoted content in file '%s': %s"
msgstr "Неправилно цитирано съдържание във файла „%s“: %s"
-#: bisect.c:686
+#: bisect.c:699
#, c-format
msgid "We cannot bisect more!\n"
msgstr "Повече не може да се търси двоично!\n"
-#: bisect.c:753
+#: bisect.c:766
#, c-format
msgid "Not a valid commit name %s"
msgstr "Неправилно име на подаване „%s“"
-#: bisect.c:778
+#: bisect.c:791
#, c-format
msgid ""
"The merge base %s is bad.\n"
@@ -1925,7 +1918,7 @@ msgstr ""
"Неправилна база за сливане: %s.\n"
"Следователно грешката е коригирана между „%s“ и [%s].\n"
-#: bisect.c:783
+#: bisect.c:796
#, c-format
msgid ""
"The merge base %s is new.\n"
@@ -1934,7 +1927,7 @@ msgstr ""
"Нова база за сливане: %s.\n"
"Свойството е променено между „%s“ и [%s].\n"
-#: bisect.c:788
+#: bisect.c:801
#, c-format
msgid ""
"The merge base %s is %s.\n"
@@ -1943,7 +1936,7 @@ msgstr ""
"Базата за сливане „%s“ е %s.\n"
"Следователно първото %s подаване е между „%s“ и [%s].\n"
-#: bisect.c:796
+#: bisect.c:809
#, c-format
msgid ""
"Some %s revs are not ancestors of the %s rev.\n"
@@ -1954,7 +1947,7 @@ msgstr ""
"Двоичното търсене с git bisect няма да работи правилно.\n"
"Дали не сте объркали указателите „%s“ и „%s“?\n"
-#: bisect.c:809
+#: bisect.c:822
#, c-format
msgid ""
"the merge base between %s and [%s] must be skipped.\n"
@@ -1965,36 +1958,36 @@ msgstr ""
"Не може да сме сигурни, че първото %s подаване е между „%s“ и „%s“.\n"
"Двоичното търсене продължава."
-#: bisect.c:848
+#: bisect.c:861
#, c-format
msgid "Bisecting: a merge base must be tested\n"
msgstr "Двоично търсене: трябва да се провери база за сливане\n"
-#: bisect.c:898
+#: bisect.c:911
#, c-format
msgid "a %s revision is needed"
msgstr "необходима е версия „%s“"
-#: bisect.c:928 builtin/notes.c:177 builtin/tag.c:255
+#: bisect.c:941 builtin/notes.c:177 builtin/tag.c:255
#, c-format
msgid "could not create file '%s'"
msgstr "файлът „%s“ не може да бъде създаден"
-#: bisect.c:974 builtin/merge.c:150
+#: bisect.c:987 builtin/merge.c:152
#, c-format
msgid "could not read file '%s'"
msgstr "файлът „%s“ не може да бъде прочетен"
-#: bisect.c:1014
+#: bisect.c:1027
msgid "reading bisect refs failed"
msgstr "неуспешно прочитане на указателите за двоично търсене"
-#: bisect.c:1044
+#: bisect.c:1057
#, c-format
msgid "%s was both %s and %s\n"
msgstr "„%s“ e както „%s“, така и „%s“\n"
-#: bisect.c:1053
+#: bisect.c:1066
#, c-format
msgid ""
"No testable commit found.\n"
@@ -2003,7 +1996,7 @@ msgstr ""
"Липсва подходящо за тестване подаване.\n"
"Проверете параметрите за пътищата.\n"
-#: bisect.c:1082
+#: bisect.c:1095
#, c-format
msgid "(roughly %d step)"
msgid_plural "(roughly %d steps)"
@@ -2013,48 +2006,48 @@ msgstr[1] "(приблизително %d стъпки)"
#. TRANSLATORS: the last %s will be replaced with "(roughly %d
#. steps)" translation.
#.
-#: bisect.c:1088
+#: bisect.c:1101
#, c-format
msgid "Bisecting: %d revision left to test after this %s\n"
msgid_plural "Bisecting: %d revisions left to test after this %s\n"
msgstr[0] "Двоично търсене: остава %d версия след тази %s\n"
msgstr[1] "Двоично търсене: остават %d версии след тази %s\n"
-#: blame.c:2778
+#: blame.c:2777
msgid "--contents and --reverse do not blend well."
msgstr "Опциите „--contents“ и „--reverse“ са несъвместими"
-#: blame.c:2792
+#: blame.c:2791
msgid "cannot use --contents with final commit object name"
msgstr "Опцията „--contents“ е несъвместима с име на обект от крайно подаване"
-#: blame.c:2813
+#: blame.c:2812
msgid "--reverse and --first-parent together require specified latest commit"
msgstr ""
"Едновременното задаване на опциите „--reverse“ и „--first-parent“ изисква "
"указването на крайно подаване"
-#: blame.c:2822 bundle.c:213 ref-filter.c:2264 remote.c:2020 sequencer.c:2105
-#: sequencer.c:4606 submodule.c:855 builtin/commit.c:1045 builtin/log.c:404
-#: builtin/log.c:1020 builtin/log.c:1622 builtin/log.c:2029 builtin/log.c:2319
-#: builtin/merge.c:414 builtin/pack-objects.c:3380 builtin/pack-objects.c:3395
-#: builtin/shortlog.c:320
+#: blame.c:2821 bundle.c:213 ref-filter.c:2272 remote.c:2031 sequencer.c:2138
+#: sequencer.c:4633 submodule.c:855 builtin/commit.c:1045 builtin/log.c:409
+#: builtin/log.c:1023 builtin/log.c:1625 builtin/log.c:2046 builtin/log.c:2336
+#: builtin/merge.c:423 builtin/pack-objects.c:3380 builtin/pack-objects.c:3395
+#: builtin/shortlog.c:267
msgid "revision walk setup failed"
msgstr "неуспешно настройване на обхождането на версиите"
-#: blame.c:2840
+#: blame.c:2839
msgid ""
"--reverse --first-parent together require range along first-parent chain"
msgstr ""
"Едновременното задаване на опциите „--reverse“ и „--first-parent“ изисква "
"указването на диапазон по веригата на първите наследници"
-#: blame.c:2851
+#: blame.c:2850
#, c-format
msgid "no such path %s in %s"
msgstr "няма път на име „%s“ в „%s“"
-#: blame.c:2862
+#: blame.c:2861
#, c-format
msgid "cannot read blob %s for path %s"
msgstr "обектът-BLOB „%s“ в пътя %s не може да бъде прочетен"
@@ -2217,7 +2210,7 @@ msgstr "Файлът „%s“ не изглежда да е пратка на gi
msgid "unrecognized header: %s%s (%d)"
msgstr "непозната заглавна част: %s%s (%d)"
-#: bundle.c:136 rerere.c:480 rerere.c:690 sequencer.c:2357 sequencer.c:3142
+#: bundle.c:136 rerere.c:480 rerere.c:690 sequencer.c:2390 sequencer.c:3176
#: builtin/commit.c:814
#, c-format
msgid "could not open '%s'"
@@ -2281,7 +2274,7 @@ msgstr "неподдържана версия на индекса %d"
msgid "cannot write bundle version %d with algorithm %s"
msgstr "пратка %d не може да се запише с алгоритъм %s"
-#: bundle.c:522 builtin/log.c:207 builtin/log.c:1918 builtin/shortlog.c:461
+#: bundle.c:522 builtin/log.c:209 builtin/log.c:1927 builtin/shortlog.c:408
#, c-format
msgid "unrecognized argument: %s"
msgstr "непознат аргумент: %s"
@@ -2304,7 +2297,7 @@ msgstr "Командата „git index-pack“ не завърши успешн
msgid "invalid color value: %.*s"
msgstr "неправилна стойност за цвят: %.*s"
-#: commit-graph.c:188 midx.c:46
+#: commit-graph.c:188 midx.c:47
msgid "invalid hash version"
msgstr "неправилна версия на контролна сума"
@@ -2370,185 +2363,177 @@ msgstr ""
msgid "could not find commit %s"
msgstr "подаването „%s“ не може да бъде открито"
-#: commit-graph.c:1042 builtin/am.c:1306
+#: commit-graph.c:1036 builtin/am.c:1292
#, c-format
msgid "unable to parse commit %s"
msgstr "подаването не може да бъде анализирано: %s"
-#: commit-graph.c:1265 builtin/pack-objects.c:2864
+#: commit-graph.c:1252 builtin/pack-objects.c:2864
#, c-format
msgid "unable to get type of object %s"
msgstr "видът на обекта „%s“ не може да бъде определен"
-#: commit-graph.c:1301
+#: commit-graph.c:1283
msgid "Loading known commits in commit graph"
msgstr "Зареждане на познатите подавания в гра̀фа с подаванията"
-#: commit-graph.c:1318
+#: commit-graph.c:1300
msgid "Expanding reachable commits in commit graph"
msgstr "Разширяване на достижимите подавания в гра̀фа"
-#: commit-graph.c:1338
+#: commit-graph.c:1320
msgid "Clearing commit marks in commit graph"
msgstr "Изчистване на отбелязванията на подаванията в гра̀фа с подаванията"
-#: commit-graph.c:1357
+#: commit-graph.c:1339
msgid "Computing commit graph generation numbers"
msgstr "Изчисляване на номерата на поколенията в гра̀фа с подаванията"
-#: commit-graph.c:1424
+#: commit-graph.c:1406
msgid "Computing commit changed paths Bloom filters"
msgstr "Изчисляване на филтрите на Блум на пътищата с промяна при подаването"
-#: commit-graph.c:1501
+#: commit-graph.c:1483
msgid "Collecting referenced commits"
msgstr "Събиране на свързаните подавания"
-#: commit-graph.c:1526
+#: commit-graph.c:1508
#, c-format
msgid "Finding commits for commit graph in %d pack"
msgid_plural "Finding commits for commit graph in %d packs"
msgstr[0] "Откриване на подаванията в гра̀фа в %d пакетен файл"
msgstr[1] "Откриване на подаванията в гра̀фа в %d пакетни файла"
-#: commit-graph.c:1539
+#: commit-graph.c:1521
#, c-format
msgid "error adding pack %s"
msgstr "грешка при добавяне на пакетен файл „%s“"
-#: commit-graph.c:1543
+#: commit-graph.c:1525
#, c-format
msgid "error opening index for %s"
msgstr "грешка при отваряне на индекса на „%s“"
-#: commit-graph.c:1582
+#: commit-graph.c:1562
msgid "Finding commits for commit graph among packed objects"
msgstr "Откриване на подаванията в гра̀фа измежду пакетираните обекти"
-#: commit-graph.c:1597
-msgid "Counting distinct commits in commit graph"
-msgstr "Преброяване на различните подавания в гра̀фа"
-
-#: commit-graph.c:1629
+#: commit-graph.c:1580
msgid "Finding extra edges in commit graph"
msgstr "Откриване на още върхове в гра̀фа с подаванията"
-#: commit-graph.c:1678
+#: commit-graph.c:1628
msgid "failed to write correct number of base graph ids"
msgstr "правилният брой на базовите идентификатори не може да се запише"
-#: commit-graph.c:1720 midx.c:826
+#: commit-graph.c:1670 midx.c:819
#, c-format
msgid "unable to create leading directories of %s"
msgstr "родителските директории на „%s“ не могат да бъдат създадени"
-#: commit-graph.c:1733
+#: commit-graph.c:1683
msgid "unable to create temporary graph layer"
msgstr "не може да бъде създаден временен слой за гра̀фа с подаванията"
-#: commit-graph.c:1738
+#: commit-graph.c:1688
#, c-format
msgid "unable to adjust shared permissions for '%s'"
msgstr "правата за споделен достъп до „%s“ не могат да бъдат зададени"
-#: commit-graph.c:1808
+#: commit-graph.c:1758
#, c-format
msgid "Writing out commit graph in %d pass"
msgid_plural "Writing out commit graph in %d passes"
msgstr[0] "Запазване на гра̀фа с подаванията в %d пас"
msgstr[1] "Запазване на гра̀фа с подаванията в %d паса"
-#: commit-graph.c:1853
+#: commit-graph.c:1803
msgid "unable to open commit-graph chain file"
msgstr "файлът с веригата на гра̀фа с подаванията не може да се отвори"
-#: commit-graph.c:1869
+#: commit-graph.c:1819
msgid "failed to rename base commit-graph file"
msgstr "основният файл на гра̀фа с подаванията не може да бъде преименуван"
-#: commit-graph.c:1889
+#: commit-graph.c:1839
msgid "failed to rename temporary commit-graph file"
msgstr "временният файл на гра̀фа с подаванията не може да бъде преименуван"
-#: commit-graph.c:2015
+#: commit-graph.c:1965
msgid "Scanning merged commits"
msgstr "Търсене на подаванията със сливания"
-#: commit-graph.c:2026
-#, c-format
-msgid "unexpected duplicate commit id %s"
-msgstr "неочакван, повтарящ се идентификатор на подаване: %s"
-
-#: commit-graph.c:2049
+#: commit-graph.c:2009
msgid "Merging commit-graph"
msgstr "Сливане на гра̀фа с подаванията"
-#: commit-graph.c:2259
-#, c-format
-msgid "the commit graph format cannot write %d commits"
-msgstr "форматът на гра̀фа с подаванията не може да запише %d подавания"
+#: commit-graph.c:2115
+msgid "attempting to write a commit-graph, but 'core.commitGraph' is disabled"
+msgstr ""
+"опит за запис на гра̀фа с подаванията, но настройката „core.commitGraph“ е "
+"изключена"
-#: commit-graph.c:2270
+#: commit-graph.c:2214
msgid "too many commits to write graph"
msgstr "прекалено много подавания за записване на гра̀фа"
-#: commit-graph.c:2363
+#: commit-graph.c:2307
msgid "the commit-graph file has incorrect checksum and is likely corrupt"
msgstr "графът с подаванията е с грешна сума за проверка — вероятно е повреден"
-#: commit-graph.c:2373
+#: commit-graph.c:2317
#, c-format
msgid "commit-graph has incorrect OID order: %s then %s"
msgstr ""
"неправилна подредба на обектите по идентификатор в гра̀фа с подаванията: „%s“ "
"е преди „%s“, а не трябва"
-#: commit-graph.c:2383 commit-graph.c:2398
+#: commit-graph.c:2327 commit-graph.c:2342
#, c-format
msgid "commit-graph has incorrect fanout value: fanout[%d] = %u != %u"
msgstr ""
"неправилна стойност за откъс в гра̀фа с подаванията: fanout[%d] = %u, а "
"трябва да е %u"
-#: commit-graph.c:2390
+#: commit-graph.c:2334
#, c-format
msgid "failed to parse commit %s from commit-graph"
msgstr "подаване „%s“ в гра̀фа с подаванията не може да се анализира"
-#: commit-graph.c:2408
+#: commit-graph.c:2352
msgid "Verifying commits in commit graph"
msgstr "Проверка на подаванията в гра̀фа"
-#: commit-graph.c:2423
+#: commit-graph.c:2367
#, c-format
msgid "failed to parse commit %s from object database for commit-graph"
msgstr ""
"подаване „%s“ в базата от данни към гра̀фа с подаванията не може да се "
"анализира"
-#: commit-graph.c:2430
+#: commit-graph.c:2374
#, c-format
msgid "root tree OID for commit %s in commit-graph is %s != %s"
msgstr ""
"идентификаторът на обект за кореновото дърво за подаване „%s“ в гра̀фа с "
"подаванията е „%s“, а трябва да е „%s“"
-#: commit-graph.c:2440
+#: commit-graph.c:2384
#, c-format
msgid "commit-graph parent list for commit %s is too long"
msgstr "списъкът с родители на „%s“ в гра̀фа с подаванията е прекалено дълъг"
-#: commit-graph.c:2449
+#: commit-graph.c:2393
#, c-format
msgid "commit-graph parent for %s is %s != %s"
msgstr "родителят на „%s“ в гра̀фа с подаванията е „%s“, а трябва да е „%s“"
-#: commit-graph.c:2463
+#: commit-graph.c:2407
#, c-format
msgid "commit-graph parent list for commit %s terminates early"
msgstr "списъкът с родители на „%s“ в гра̀фа с подаванията е прекалено къс"
-#: commit-graph.c:2468
+#: commit-graph.c:2412
#, c-format
msgid ""
"commit-graph has generation number zero for commit %s, but non-zero elsewhere"
@@ -2556,7 +2541,7 @@ msgstr ""
"номерът на поколението на подаване „%s“ в гра̀фа с подаванията е 0, а другаде "
"не е"
-#: commit-graph.c:2472
+#: commit-graph.c:2416
#, c-format
msgid ""
"commit-graph has non-zero generation number for commit %s, but zero elsewhere"
@@ -2564,22 +2549,22 @@ msgstr ""
"номерът на поколението на подаване „%s“ в гра̀фа с подаванията не е 0, а "
"другаде е"
-#: commit-graph.c:2488
+#: commit-graph.c:2432
#, c-format
msgid "commit-graph generation for commit %s is %u != %u"
msgstr ""
"номерът на поколението на подаване „%s“ в гра̀фа с подаванията е %u, а "
"другаде е %u"
-#: commit-graph.c:2494
+#: commit-graph.c:2438
#, c-format
msgid "commit date for commit %s in commit-graph is %<PRIuMAX> != %<PRIuMAX>"
msgstr ""
"датата на подаване на „%s“ в гра̀фа с подаванията е %<PRIuMAX>, а трябва да е "
"%<PRIuMAX>"
-#: commit.c:52 sequencer.c:2845 builtin/am.c:373 builtin/am.c:417
-#: builtin/am.c:1385 builtin/am.c:2031 builtin/replace.c:457
+#: commit.c:52 sequencer.c:2879 builtin/am.c:359 builtin/am.c:403
+#: builtin/am.c:1371 builtin/am.c:2018 builtin/replace.c:457
#, c-format
msgid "could not parse %s"
msgstr "„%s“ не може да се анализира"
@@ -2686,7 +2671,7 @@ msgstr "ключът не съдържа раздел: „%s“"
msgid "key does not contain variable name: %s"
msgstr "ключът не съдържа име на променлива: „%s“"
-#: config.c:408 sequencer.c:2547
+#: config.c:408 sequencer.c:2580
#, c-format
msgid "invalid key: %s"
msgstr "неправилен ключ: „%s“"
@@ -2881,77 +2866,77 @@ msgstr "неразпозната стойност „%s“ от командни
msgid "bad config variable '%s' in file '%s' at line %d"
msgstr "неправилна настройка „%s“ във файла „%s“ на ред №%d"
-#: config.c:2470
+#: config.c:2473
#, c-format
msgid "invalid section name '%s'"
msgstr "неправилно име на раздел: „%s“"
-#: config.c:2502
+#: config.c:2505
#, c-format
msgid "%s has multiple values"
msgstr "зададени са няколко стойности за „%s“"
-#: config.c:2531
+#: config.c:2534
#, c-format
msgid "failed to write new configuration file %s"
msgstr "новият конфигурационен файл „%s“ не може да бъде запазен"
-#: config.c:2783 config.c:3107
+#: config.c:2786 config.c:3112
#, c-format
msgid "could not lock config file %s"
msgstr "конфигурационният файл „%s“ не може да бъде заключен"
-#: config.c:2794
+#: config.c:2797
#, c-format
msgid "opening %s"
msgstr "отваряне на „%s“"
-#: config.c:2829 builtin/config.c:354
+#: config.c:2834 builtin/config.c:361
#, c-format
msgid "invalid pattern: %s"
msgstr "неправилен шаблон: %s"
-#: config.c:2854
+#: config.c:2859
#, c-format
msgid "invalid config file %s"
msgstr "неправилен конфигурационен файл: „%s“"
-#: config.c:2867 config.c:3120
+#: config.c:2872 config.c:3125
#, c-format
msgid "fstat on %s failed"
msgstr "неуспешно изпълнение на „fstat“ върху „%s“"
-#: config.c:2878
+#: config.c:2883
#, c-format
msgid "unable to mmap '%s'"
msgstr "неуспешно изпълнение на „mmap“ върху „%s“"
-#: config.c:2887 config.c:3125
+#: config.c:2892 config.c:3130
#, c-format
msgid "chmod on %s failed"
msgstr "неуспешна смяна на права с „chmod“ върху „%s“"
-#: config.c:2972 config.c:3222
+#: config.c:2977 config.c:3227
#, c-format
msgid "could not write config file %s"
msgstr "конфигурационният файл „%s“ не може да бъде записан"
-#: config.c:3006
+#: config.c:3011
#, c-format
msgid "could not set '%s' to '%s'"
msgstr "„%s“ не може да се зададе да е „%s“"
-#: config.c:3008 builtin/remote.c:656 builtin/remote.c:850 builtin/remote.c:858
+#: config.c:3013 builtin/remote.c:657 builtin/remote.c:855 builtin/remote.c:863
#, c-format
msgid "could not unset '%s'"
msgstr "„%s“ не може да се премахне"
-#: config.c:3098
+#: config.c:3103
#, c-format
msgid "invalid section name: %s"
msgstr "неправилно име на раздел: %s"
-#: config.c:3265
+#: config.c:3270
#, c-format
msgid "missing value for '%s'"
msgstr "липсва стойност за „%s“"
@@ -3404,6 +3389,26 @@ msgstr ""
msgid "Marked %d islands, done.\n"
msgstr "Отбелязани са %d групи, работата приключи.\n"
+#: diff-lib.c:534
+msgid "--merge-base does not work with ranges"
+msgstr "опцията „--merge-base“ не работи с диапазони"
+
+#: diff-lib.c:536
+msgid "--merge-base only works with commits"
+msgstr "опцията „--merge-base“ работи само с подавания"
+
+#: diff-lib.c:553
+msgid "unable to get HEAD"
+msgstr "Указателят „HEAD“ не може да бъде получен"
+
+#: diff-lib.c:560
+msgid "no merge base found"
+msgstr "липсва база за сливане"
+
+#: diff-lib.c:562
+msgid "multiple merge bases found"
+msgstr "много бази за сливане"
+
#: diff-no-index.c:238
msgid "git diff --no-index [<options>] <path> <path>"
msgstr "git diff --no-index [ОПЦИЯ…] ПЪТ ПЪТ"
@@ -3472,38 +3477,38 @@ msgstr ""
"Грешки в настройката „diff.dirstat“:\n"
"%s"
-#: diff.c:4269
+#: diff.c:4276
#, c-format
msgid "external diff died, stopping at %s"
msgstr ""
"външната програма за разлики завърши неуспешно. Спиране на работата при „%s“"
-#: diff.c:4618
+#: diff.c:4625
msgid "--name-only, --name-status, --check and -s are mutually exclusive"
msgstr ""
"Опциите „--name-only“, „--name-status“, „--check“ и „-s“ са несъвместими "
"една с друга"
-#: diff.c:4621
+#: diff.c:4628
msgid "-G, -S and --find-object are mutually exclusive"
msgstr "Опциите „-G“, „-S“ и „--find-object“ са несъвместими една с друга"
-#: diff.c:4699
+#: diff.c:4707
msgid "--follow requires exactly one pathspec"
msgstr "Опцията „--follow“ изисква точно един път"
-#: diff.c:4747
+#: diff.c:4755
#, c-format
msgid "invalid --stat value: %s"
msgstr "неправилна стойност за „--stat“: %s"
-#: diff.c:4752 diff.c:4757 diff.c:4762 diff.c:4767 diff.c:5279
+#: diff.c:4760 diff.c:4765 diff.c:4770 diff.c:4775 diff.c:5303
#: parse-options.c:197 parse-options.c:201 builtin/commit-graph.c:180
#, c-format
msgid "%s expects a numerical value"
msgstr "опцията „%s“ очаква число за аргумент"
-#: diff.c:4784
+#: diff.c:4792
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -3512,44 +3517,44 @@ msgstr ""
"Неразпознат параметър към опцията „--dirstat/-X“:\n"
"%s"
-#: diff.c:4869
+#: diff.c:4877
#, c-format
msgid "unknown change class '%c' in --diff-filter=%s"
msgstr "непознат вид промяна: „%c“ в „--diff-filter=%s“"
-#: diff.c:4893
+#: diff.c:4901
#, c-format
msgid "unknown value after ws-error-highlight=%.*s"
msgstr "непозната стойност след „ws-error-highlight=%.*s“"
-#: diff.c:4907
+#: diff.c:4915
#, c-format
msgid "unable to resolve '%s'"
msgstr "„%s“ не може да се открие"
-#: diff.c:4957 diff.c:4963
+#: diff.c:4965 diff.c:4971
#, c-format
msgid "%s expects <n>/<m> form"
msgstr ""
"опцията „%s“ изисква стойности за МИНИМАЛЕН_%%_ПРОМЯНА_ЗА_ИЗТОЧНИК_/"
"МАКСИМАЛЕН_%%_ПРОМЯНА_ЗА_ЗАМЯНА от"
-#: diff.c:4975
+#: diff.c:4983
#, c-format
msgid "%s expects a character, got '%s'"
msgstr "опцията „%s“ изисква знак, а не: „%s“"
-#: diff.c:4996
+#: diff.c:5004
#, c-format
msgid "bad --color-moved argument: %s"
msgstr "неправилен аргумент за „--color-moved“: „%s“"
-#: diff.c:5015
+#: diff.c:5023
#, c-format
msgid "invalid mode '%s' in --color-moved-ws"
msgstr "неправилен режим „%s“ за „ --color-moved-ws“"
-#: diff.c:5055
+#: diff.c:5063
msgid ""
"option diff-algorithm accepts \"myers\", \"minimal\", \"patience\" and "
"\"histogram\""
@@ -3558,153 +3563,158 @@ msgstr ""
"Майерс), „minimal“ (минимизиране на разликите), „patience“ (пасианс) и "
"„histogram“ (хистограмен)"
-#: diff.c:5091 diff.c:5111
+#: diff.c:5099 diff.c:5119
#, c-format
msgid "invalid argument to %s"
msgstr "неправилен аргумент към „%s“"
-#: diff.c:5248
+#: diff.c:5223
+#, c-format
+msgid "invalid regex given to -I: '%s'"
+msgstr "неправилен регулярен израз подаден към „-I“: „%s“"
+
+#: diff.c:5272
#, c-format
msgid "failed to parse --submodule option parameter: '%s'"
msgstr "неразпознат параметър към опцията „--submodule“: „%s“"
-#: diff.c:5304
+#: diff.c:5328
#, c-format
msgid "bad --word-diff argument: %s"
msgstr "неправилен аргумент към „--word-diff“: „%s“"
-#: diff.c:5327
+#: diff.c:5351
msgid "Diff output format options"
msgstr "Формат на изхода за разликите"
-#: diff.c:5329 diff.c:5335
+#: diff.c:5353 diff.c:5359
msgid "generate patch"
msgstr "създаване на кръпки"
-#: diff.c:5332 builtin/log.c:176
+#: diff.c:5356 builtin/log.c:178
msgid "suppress diff output"
msgstr "без извеждане на разликите"
-#: diff.c:5337 diff.c:5451 diff.c:5458
+#: diff.c:5361 diff.c:5475 diff.c:5482
msgid "<n>"
msgstr "БРОЙ"
-#: diff.c:5338 diff.c:5341
+#: diff.c:5362 diff.c:5365
msgid "generate diffs with <n> lines context"
msgstr "файловете с разлики да са с контекст с такъв БРОЙ редове"
-#: diff.c:5343
+#: diff.c:5367
msgid "generate the diff in raw format"
msgstr "файловете с разлики да са в суров формат"
-#: diff.c:5346
+#: diff.c:5370
msgid "synonym for '-p --raw'"
msgstr "псевдоним на „-p --stat“"
-#: diff.c:5350
+#: diff.c:5374
msgid "synonym for '-p --stat'"
msgstr "псевдоним на „-p --stat“"
-#: diff.c:5354
+#: diff.c:5378
msgid "machine friendly --stat"
msgstr "„--stat“ във формат за четене от програма"
-#: diff.c:5357
+#: diff.c:5381
msgid "output only the last line of --stat"
msgstr "извеждане само на последния ред на „--stat“"
-#: diff.c:5359 diff.c:5367
+#: diff.c:5383 diff.c:5391
msgid "<param1,param2>..."
msgstr "ПАРАМЕТЪР_1, ПАРАМЕТЪР_2, …"
-#: diff.c:5360
+#: diff.c:5384
msgid ""
"output the distribution of relative amount of changes for each sub-directory"
msgstr "извеждане на разпределението на промените за всяка поддиректория"
-#: diff.c:5364
+#: diff.c:5388
msgid "synonym for --dirstat=cumulative"
msgstr "псевдоним на „--dirstat=cumulative“"
-#: diff.c:5368
+#: diff.c:5392
msgid "synonym for --dirstat=files,param1,param2..."
msgstr "псевдоним на „--dirstat=ФАЙЛОВЕ,ПАРАМЕТЪР_1,ПАРАМЕТЪР_2,…“"
-#: diff.c:5372
+#: diff.c:5396
msgid "warn if changes introduce conflict markers or whitespace errors"
msgstr ""
"предупреждаване, ако промените водят до маркери за конфликт или грешки в "
"празните знаци"
-#: diff.c:5375
+#: diff.c:5399
msgid "condensed summary such as creations, renames and mode changes"
msgstr ""
"съкратено резюме на създадените, преименуваните и файловете с промяна на "
"режима на достъп"
-#: diff.c:5378
+#: diff.c:5402
msgid "show only names of changed files"
msgstr "извеждане само на имената на променените файлове"
-#: diff.c:5381
+#: diff.c:5405
msgid "show only names and status of changed files"
msgstr "извеждане само на имената и статистиката за променените файлове"
-#: diff.c:5383
+#: diff.c:5407
msgid "<width>[,<name-width>[,<count>]]"
msgstr "ШИРОЧИНА[,ИМЕ-ШИРОЧИНА[,БРОЙ]]"
-#: diff.c:5384
+#: diff.c:5408
msgid "generate diffstat"
msgstr "извеждане на статистика за промените"
-#: diff.c:5386 diff.c:5389 diff.c:5392
+#: diff.c:5410 diff.c:5413 diff.c:5416
msgid "<width>"
msgstr "ШИРОЧИНА"
-#: diff.c:5387
+#: diff.c:5411
msgid "generate diffstat with a given width"
msgstr "статистика с такава ШИРОЧИНА за промените"
-#: diff.c:5390
+#: diff.c:5414
msgid "generate diffstat with a given name width"
msgstr "статистика за промените с такава ШИРОЧИНА на имената"
-#: diff.c:5393
+#: diff.c:5417
msgid "generate diffstat with a given graph width"
msgstr "статистика за промените с такава ШИРОЧИНА на гра̀фа"
-#: diff.c:5395
+#: diff.c:5419
msgid "<count>"
msgstr "БРОЙ"
-#: diff.c:5396
+#: diff.c:5420
msgid "generate diffstat with limited lines"
msgstr "ограничаване на БРОя на редовете в статистиката за промените"
-#: diff.c:5399
+#: diff.c:5423
msgid "generate compact summary in diffstat"
msgstr "кратко резюме в статистиката за промените"
-#: diff.c:5402
+#: diff.c:5426
msgid "output a binary diff that can be applied"
msgstr "извеждане на двоична разлика във вид за прилагане"
-#: diff.c:5405
+#: diff.c:5429
msgid "show full pre- and post-image object names on the \"index\" lines"
msgstr ""
"показване на пълните имена на обекти в редовете за индекса при вариантите "
"преди и след промяната"
-#: diff.c:5407
+#: diff.c:5431
msgid "show colored diff"
msgstr "разлики в цвят"
-#: diff.c:5408
+#: diff.c:5432
msgid "<kind>"
msgstr "ВИД"
-#: diff.c:5409
+#: diff.c:5433
msgid ""
"highlight whitespace errors in the 'context', 'old' or 'new' lines in the "
"diff"
@@ -3712,7 +3722,7 @@ msgstr ""
"грешките в празните знаци да се указват в редовете за контекста, вариантите "
"преди и след разликата,"
-#: diff.c:5412
+#: diff.c:5436
msgid ""
"do not munge pathnames and use NULs as output field terminators in --raw or "
"--numstat"
@@ -3720,257 +3730,261 @@ msgstr ""
"без преименуване на пътищата. Да се използват нулеви байтове за разделители "
"на полета в изхода при ползване на опцията „--raw“ или „--numstat“"
-#: diff.c:5415 diff.c:5418 diff.c:5421 diff.c:5527
+#: diff.c:5439 diff.c:5442 diff.c:5445 diff.c:5554
msgid "<prefix>"
msgstr "ПРЕФИКС"
-#: diff.c:5416
+#: diff.c:5440
msgid "show the given source prefix instead of \"a/\""
msgstr "префикс вместо „a/“ за източник"
-#: diff.c:5419
+#: diff.c:5443
msgid "show the given destination prefix instead of \"b/\""
msgstr "префикс вместо „b/“ за цел"
-#: diff.c:5422
+#: diff.c:5446
msgid "prepend an additional prefix to every line of output"
msgstr "добавяне на допълнителен префикс за всеки ред на изхода"
-#: diff.c:5425
+#: diff.c:5449
msgid "do not show any source or destination prefix"
msgstr "без префикс за източника и целта"
-#: diff.c:5428
+#: diff.c:5452
msgid "show context between diff hunks up to the specified number of lines"
msgstr ""
"извеждане на контекст между последователните парчета с разлики от указания "
"БРОЙ редове"
-#: diff.c:5432 diff.c:5437 diff.c:5442
+#: diff.c:5456 diff.c:5461 diff.c:5466
msgid "<char>"
msgstr "ЗНАК"
-#: diff.c:5433
+#: diff.c:5457
msgid "specify the character to indicate a new line instead of '+'"
msgstr "знак вместо „+“ за нов вариант на ред"
-#: diff.c:5438
+#: diff.c:5462
msgid "specify the character to indicate an old line instead of '-'"
msgstr "знак вместо „-“ за стар вариант на ред"
-#: diff.c:5443
+#: diff.c:5467
msgid "specify the character to indicate a context instead of ' '"
msgstr "знак вместо „ “ за контекст"
-#: diff.c:5446
+#: diff.c:5470
msgid "Diff rename options"
msgstr "Настройки за разлики с преименуване"
-#: diff.c:5447
+#: diff.c:5471
msgid "<n>[/<m>]"
msgstr "МИНИМАЛЕН_%_ПРОМЯНА_ЗА_ИЗТОЧНИК[/МАКСИМАЛEН_%_ПРОМЯНА_ЗА_ЗАМЯНА]"
-#: diff.c:5448
+#: diff.c:5472
msgid "break complete rewrite changes into pairs of delete and create"
msgstr ""
"заместване на пълните промени с последователност от изтриване и създаване"
-#: diff.c:5452
+#: diff.c:5476
msgid "detect renames"
msgstr "засичане на преименуванията"
-#: diff.c:5456
+#: diff.c:5480
msgid "omit the preimage for deletes"
msgstr "без предварителен вариант при изтриване"
-#: diff.c:5459
+#: diff.c:5483
msgid "detect copies"
msgstr "засичане на копиранията"
-#: diff.c:5463
+#: diff.c:5487
msgid "use unmodified files as source to find copies"
msgstr "търсене на копирано и от непроменените файлове"
-#: diff.c:5465
+#: diff.c:5489
msgid "disable rename detection"
msgstr "без търсене на преименувания"
-#: diff.c:5468
+#: diff.c:5492
msgid "use empty blobs as rename source"
msgstr "празни обекти като източник при преименувания"
-#: diff.c:5470
+#: diff.c:5494
msgid "continue listing the history of a file beyond renames"
msgstr ""
"продължаване на извеждането на историята — без отрязването при преименувания "
"на файл"
-#: diff.c:5473
+#: diff.c:5497
msgid ""
"prevent rename/copy detection if the number of rename/copy targets exceeds "
"given limit"
msgstr ""
"без засичане на преименувания/копирания, ако броят им надвишава тази стойност"
-#: diff.c:5475
+#: diff.c:5499
msgid "Diff algorithm options"
msgstr "Опции към алгоритъма за разлики"
-#: diff.c:5477
+#: diff.c:5501
msgid "produce the smallest possible diff"
msgstr "търсене на възможно най-малка разлика"
-#: diff.c:5480
+#: diff.c:5504
msgid "ignore whitespace when comparing lines"
msgstr "без промени в празните знаци при сравняване на редове"
-#: diff.c:5483
+#: diff.c:5507
msgid "ignore changes in amount of whitespace"
msgstr "без промени в празните знаци"
-#: diff.c:5486
+#: diff.c:5510
msgid "ignore changes in whitespace at EOL"
msgstr "без промени в празните знаци в края на редовете"
-#: diff.c:5489
+#: diff.c:5513
msgid "ignore carrier-return at the end of line"
msgstr "без промени в знаците за край на ред"
-#: diff.c:5492
+#: diff.c:5516
msgid "ignore changes whose lines are all blank"
msgstr "без промени в редовете, които са изцяло от празни знаци"
-#: diff.c:5495
+#: diff.c:5518 diff.c:5540 diff.c:5543 diff.c:5588
+msgid "<regex>"
+msgstr "РЕГУЛЯРЕН_ИЗРАЗ"
+
+#: diff.c:5519
+msgid "ignore changes whose all lines match <regex>"
+msgstr "без промени в редовете, които напасват РЕГУЛЯРНия_ИЗРАЗ"
+
+#: diff.c:5522
msgid "heuristic to shift diff hunk boundaries for easy reading"
msgstr ""
"евристика за преместване на границите на парчетата за улесняване на четенето"
-#: diff.c:5498
+#: diff.c:5525
msgid "generate diff using the \"patience diff\" algorithm"
msgstr "разлика чрез алгоритъм за подредба като пасианс"
-#: diff.c:5502
+#: diff.c:5529
msgid "generate diff using the \"histogram diff\" algorithm"
msgstr "разлика по хистограмния алгоритъм"
-#: diff.c:5504
+#: diff.c:5531
msgid "<algorithm>"
msgstr "АЛГОРИТЪМ"
-#: diff.c:5505
+#: diff.c:5532
msgid "choose a diff algorithm"
msgstr "избор на АЛГОРИТЪМа за разлики"
-#: diff.c:5507
+#: diff.c:5534
msgid "<text>"
msgstr "ТЕКСТ"
-#: diff.c:5508
+#: diff.c:5535
msgid "generate diff using the \"anchored diff\" algorithm"
msgstr "разлика чрез алгоритъма със закотвяне"
-#: diff.c:5510 diff.c:5519 diff.c:5522
+#: diff.c:5537 diff.c:5546 diff.c:5549
msgid "<mode>"
msgstr "РЕЖИМ"
-#: diff.c:5511
+#: diff.c:5538
msgid "show word diff, using <mode> to delimit changed words"
msgstr ""
"разлика по думи, като се ползва този РЕЖИМ за отделянето на променените думи"
-#: diff.c:5513 diff.c:5516 diff.c:5561
-msgid "<regex>"
-msgstr "РЕГУЛЯРЕН_ИЗРАЗ"
-
-#: diff.c:5514
+#: diff.c:5541
msgid "use <regex> to decide what a word is"
msgstr "РЕГУЛЯРЕН_ИЗРАЗ за разделяне по думи"
-#: diff.c:5517
+#: diff.c:5544
msgid "equivalent to --word-diff=color --word-diff-regex=<regex>"
msgstr "псевдоним на „--word-diff=color --word-diff-regex=РЕГУЛЯРЕН_ИЗРАЗ“"
-#: diff.c:5520
+#: diff.c:5547
msgid "moved lines of code are colored differently"
msgstr "различен цвят за извеждане на преместените редове"
-#: diff.c:5523
+#: diff.c:5550
msgid "how white spaces are ignored in --color-moved"
msgstr ""
"режим за прескачането на празните знаци при задаването на „--color-moved“"
-#: diff.c:5526
+#: diff.c:5553
msgid "Other diff options"
msgstr "Други опции за разлики"
-#: diff.c:5528
+#: diff.c:5555
msgid "when run from subdir, exclude changes outside and show relative paths"
msgstr ""
"при изпълнение от поддиректория да се пренебрегват разликите извън нея и да "
"се ползват относителни пътища"
-#: diff.c:5532
+#: diff.c:5559
msgid "treat all files as text"
msgstr "обработка на всички файлове като текстови"
-#: diff.c:5534
+#: diff.c:5561
msgid "swap two inputs, reverse the diff"
msgstr "размяна на двата входа — обръщане на разликата"
-#: diff.c:5536
+#: diff.c:5563
msgid "exit with 1 if there were differences, 0 otherwise"
msgstr ""
"завършване с код за състояние 1 при наличието на разлики, а в противен "
"случай — с 0"
-#: diff.c:5538
+#: diff.c:5565
msgid "disable all output of the program"
msgstr "без всякакъв изход от програмата"
-#: diff.c:5540
+#: diff.c:5567
msgid "allow an external diff helper to be executed"
msgstr "позволяване на изпълнение на външна помощна програма за разлики"
-#: diff.c:5542
+#: diff.c:5569
msgid "run external text conversion filters when comparing binary files"
msgstr ""
"изпълнение на външни програми-филтри при сравнението на двоични файлове"
-#: diff.c:5544
+#: diff.c:5571
msgid "<when>"
msgstr "КОГА"
-#: diff.c:5545
+#: diff.c:5572
msgid "ignore changes to submodules in the diff generation"
msgstr "игнориране на промените в подмодулите при извеждането на разликите"
-#: diff.c:5548
+#: diff.c:5575
msgid "<format>"
msgstr "ФОРМАТ"
-#: diff.c:5549
+#: diff.c:5576
msgid "specify how differences in submodules are shown"
msgstr "начин за извеждане на промените в подмодулите"
-#: diff.c:5553
+#: diff.c:5580
msgid "hide 'git add -N' entries from the index"
msgstr "без включване в индекса на записите, добавени с „git add -N“"
-#: diff.c:5556
+#: diff.c:5583
msgid "treat 'git add -N' entries as real in the index"
msgstr "включване в индекса на записите, добавени с „git add -N“"
-#: diff.c:5558
+#: diff.c:5585
msgid "<string>"
msgstr "НИЗ"
-#: diff.c:5559
+#: diff.c:5586
msgid ""
"look for differences that change the number of occurrences of the specified "
"string"
msgstr "търсене на разлики, които променят броя на поява на указаните низове"
-#: diff.c:5562
+#: diff.c:5589
msgid ""
"look for differences that change the number of occurrences of the specified "
"regex"
@@ -3978,57 +3992,57 @@ msgstr ""
"търсене на разлики, които променят броя на поява на низовете, които напасват "
"на регулярния израз"
-#: diff.c:5565
+#: diff.c:5592
msgid "show all changes in the changeset with -S or -G"
msgstr "извеждане на всички промени с „-G“/„-S“"
-#: diff.c:5568
+#: diff.c:5595
msgid "treat <string> in -S as extended POSIX regular expression"
msgstr "НИЗът към „-S“ да се тълкува като разширен регулярен израз по POSIX"
-#: diff.c:5571
+#: diff.c:5598
msgid "control the order in which files appear in the output"
msgstr "управление на подредбата на файловете в изхода"
-#: diff.c:5572
+#: diff.c:5599
msgid "<object-id>"
msgstr "ИДЕНТИФИКАТОР_НА_ОБЕКТ"
-#: diff.c:5573
+#: diff.c:5600
msgid ""
"look for differences that change the number of occurrences of the specified "
"object"
msgstr "търсене на разлики, които променят броя на поява на указания обект"
-#: diff.c:5575
+#: diff.c:5602
msgid "[(A|C|D|M|R|T|U|X|B)...[*]]"
msgstr "[(A|C|D|M|R|T|U|X|B)…[*]]"
-#: diff.c:5576
+#: diff.c:5603
msgid "select files by diff type"
msgstr "избор на файловете по вид разлика"
-#: diff.c:5578
+#: diff.c:5605
msgid "<file>"
msgstr "ФАЙЛ"
-#: diff.c:5579
+#: diff.c:5606
msgid "Output to a specific file"
msgstr "Изход към указания файл"
-#: diff.c:6236
+#: diff.c:6263
msgid "inexact rename detection was skipped due to too many files."
msgstr ""
"търсенето на преименувания на обекти съчетани с промени се прескача поради "
"многото файлове."
-#: diff.c:6239
+#: diff.c:6266
msgid "only found copies from modified paths due to too many files."
msgstr ""
"установени са само точните копия на променените пътища поради многото "
"файлове."
-#: diff.c:6242
+#: diff.c:6269
#, c-format
msgid ""
"you may want to set your %s variable to at least %d and retry the command."
@@ -4132,249 +4146,249 @@ msgstr "GIT_DIR не може да се зададе да е „%s“"
msgid "too many args to run %s"
msgstr "прекалено много аргументи за изпълнение „%s“"
-#: fetch-pack.c:176
+#: fetch-pack.c:177
msgid "git fetch-pack: expected shallow list"
msgstr "git fetch-pack: очаква се плитък списък"
-#: fetch-pack.c:179
+#: fetch-pack.c:180
msgid "git fetch-pack: expected a flush packet after shallow list"
msgstr "git fetch-pack: след плитък списък се очаква изчистващ пакет „flush“"
-#: fetch-pack.c:190
+#: fetch-pack.c:191
msgid "git fetch-pack: expected ACK/NAK, got a flush packet"
msgstr ""
"git fetch-pack: очаква се „ACK“/„NAK“, а бе получен изчистващ пакет „flush“"
-#: fetch-pack.c:210
+#: fetch-pack.c:211
#, c-format
msgid "git fetch-pack: expected ACK/NAK, got '%s'"
msgstr "git fetch-pack: очаква се „ACK“/„NAK“, а бе получено „%s“"
-#: fetch-pack.c:221
+#: fetch-pack.c:222
msgid "unable to write to remote"
msgstr "невъзможно писане към отдалечено хранилище"
-#: fetch-pack.c:282
+#: fetch-pack.c:283
msgid "--stateless-rpc requires multi_ack_detailed"
msgstr "опцията „--stateless-rpc“ изисква „multi_ack_detailed“"
-#: fetch-pack.c:375 fetch-pack.c:1397
+#: fetch-pack.c:378 fetch-pack.c:1406
#, c-format
msgid "invalid shallow line: %s"
msgstr "неправилен плитък ред: „%s“"
-#: fetch-pack.c:381 fetch-pack.c:1403
+#: fetch-pack.c:384 fetch-pack.c:1412
#, c-format
msgid "invalid unshallow line: %s"
msgstr "неправилен неплитък ред: „%s“"
-#: fetch-pack.c:383 fetch-pack.c:1405
+#: fetch-pack.c:386 fetch-pack.c:1414
#, c-format
msgid "object not found: %s"
msgstr "обектът „%s“ липсва"
-#: fetch-pack.c:386 fetch-pack.c:1408
+#: fetch-pack.c:389 fetch-pack.c:1417
#, c-format
msgid "error in object: %s"
msgstr "грешка в обекта: „%s“"
-#: fetch-pack.c:388 fetch-pack.c:1410
+#: fetch-pack.c:391 fetch-pack.c:1419
#, c-format
msgid "no shallow found: %s"
msgstr "не е открит плитък обект: %s"
-#: fetch-pack.c:391 fetch-pack.c:1414
+#: fetch-pack.c:394 fetch-pack.c:1423
#, c-format
msgid "expected shallow/unshallow, got %s"
msgstr "очаква се плитък или не обект, а бе получено: „%s“"
-#: fetch-pack.c:431
+#: fetch-pack.c:434
#, c-format
msgid "got %s %d %s"
msgstr "получено бе %s %d %s"
-#: fetch-pack.c:448
+#: fetch-pack.c:451
#, c-format
msgid "invalid commit %s"
msgstr "неправилно подаване: „%s“"
-#: fetch-pack.c:479
+#: fetch-pack.c:482
msgid "giving up"
msgstr "преустановяване"
-#: fetch-pack.c:492 progress.c:339
+#: fetch-pack.c:495 progress.c:339
msgid "done"
msgstr "действието завърши"
-#: fetch-pack.c:504
+#: fetch-pack.c:507
#, c-format
msgid "got %s (%d) %s"
msgstr "получено бе %s (%d) %s"
-#: fetch-pack.c:540
+#: fetch-pack.c:543
#, c-format
msgid "Marking %s as complete"
msgstr "Отбелязване на „%s“ като пълно"
-#: fetch-pack.c:755
+#: fetch-pack.c:758
#, c-format
msgid "already have %s (%s)"
msgstr "вече има „%s“ (%s)"
-#: fetch-pack.c:824
+#: fetch-pack.c:827
msgid "fetch-pack: unable to fork off sideband demultiplexer"
msgstr "fetch-pack: не може да се създаде процес за демултиплексора"
-#: fetch-pack.c:832
+#: fetch-pack.c:835
msgid "protocol error: bad pack header"
msgstr "протоколна грешка: неправилна заглавна част на пакет"
-#: fetch-pack.c:916
+#: fetch-pack.c:919
#, c-format
msgid "fetch-pack: unable to fork off %s"
msgstr "fetch-pack: не може да се създаде процес за „%s“"
-#: fetch-pack.c:933
+#: fetch-pack.c:937
#, c-format
msgid "%s failed"
msgstr "неуспешно изпълнение на „%s“"
-#: fetch-pack.c:935
+#: fetch-pack.c:939
msgid "error in sideband demultiplexer"
msgstr "грешка в демултиплексора"
-#: fetch-pack.c:978
+#: fetch-pack.c:982
#, c-format
msgid "Server version is %.*s"
msgstr "Версията на сървъра е: %.*s"
-#: fetch-pack.c:983 fetch-pack.c:989 fetch-pack.c:992 fetch-pack.c:998
-#: fetch-pack.c:1002 fetch-pack.c:1006 fetch-pack.c:1010 fetch-pack.c:1014
-#: fetch-pack.c:1018 fetch-pack.c:1022 fetch-pack.c:1026 fetch-pack.c:1030
-#: fetch-pack.c:1036 fetch-pack.c:1042 fetch-pack.c:1047 fetch-pack.c:1052
+#: fetch-pack.c:990 fetch-pack.c:996 fetch-pack.c:999 fetch-pack.c:1005
+#: fetch-pack.c:1009 fetch-pack.c:1013 fetch-pack.c:1017 fetch-pack.c:1021
+#: fetch-pack.c:1025 fetch-pack.c:1029 fetch-pack.c:1033 fetch-pack.c:1037
+#: fetch-pack.c:1043 fetch-pack.c:1049 fetch-pack.c:1054 fetch-pack.c:1059
#, c-format
msgid "Server supports %s"
msgstr "Сървърът поддържа „%s“"
-#: fetch-pack.c:985
+#: fetch-pack.c:992
msgid "Server does not support shallow clients"
msgstr "Сървърът не поддържа плитки клиенти"
-#: fetch-pack.c:1045
+#: fetch-pack.c:1052
msgid "Server does not support --shallow-since"
msgstr "Сървърът не поддържа опцията „--shallow-since“"
-#: fetch-pack.c:1050
+#: fetch-pack.c:1057
msgid "Server does not support --shallow-exclude"
msgstr "Сървърът не поддържа опцията „--shallow-exclude“"
-#: fetch-pack.c:1054
+#: fetch-pack.c:1061
msgid "Server does not support --deepen"
msgstr "Сървърът не поддържа опцията „--deepen“"
-#: fetch-pack.c:1056
+#: fetch-pack.c:1063
msgid "Server does not support this repository's object format"
msgstr "Сървърът не поддържа форма̀та на обектите на това хранилище"
-#: fetch-pack.c:1069
+#: fetch-pack.c:1076
msgid "no common commits"
msgstr "няма общи подавания"
-#: fetch-pack.c:1081 fetch-pack.c:1619
+#: fetch-pack.c:1088 fetch-pack.c:1628
msgid "git fetch-pack: fetch failed."
msgstr "git fetch-pack: неуспешно доставяне."
-#: fetch-pack.c:1205
+#: fetch-pack.c:1214
#, c-format
msgid "mismatched algorithms: client %s; server %s"
msgstr "различни алгоритми — на клиента: „%s“, на сървъра: „%s“"
-#: fetch-pack.c:1209
+#: fetch-pack.c:1218
#, c-format
msgid "the server does not support algorithm '%s'"
msgstr "сървърът не поддържа алгоритъм „%s“"
-#: fetch-pack.c:1229
+#: fetch-pack.c:1238
msgid "Server does not support shallow requests"
msgstr "Сървърът не поддържа плитки заявки"
-#: fetch-pack.c:1236
+#: fetch-pack.c:1245
msgid "Server supports filter"
msgstr "Сървърът поддържа филтри"
-#: fetch-pack.c:1275
+#: fetch-pack.c:1284
msgid "unable to write request to remote"
msgstr "невъзможно писане към отдалечено хранилище"
-#: fetch-pack.c:1293
+#: fetch-pack.c:1302
#, c-format
msgid "error reading section header '%s'"
msgstr "грешка при прочитане на заглавната част на раздел „%s“"
-#: fetch-pack.c:1299
+#: fetch-pack.c:1308
#, c-format
msgid "expected '%s', received '%s'"
msgstr "очаква се „%s“, а бе получено „%s“"
-#: fetch-pack.c:1360
+#: fetch-pack.c:1369
#, c-format
msgid "unexpected acknowledgment line: '%s'"
msgstr "неочакван ред за потвърждение: „%s“"
-#: fetch-pack.c:1365
+#: fetch-pack.c:1374
#, c-format
msgid "error processing acks: %d"
msgstr "грешка при обработка на потвържденията: %d"
-#: fetch-pack.c:1375
+#: fetch-pack.c:1384
msgid "expected packfile to be sent after 'ready'"
msgstr ""
"очакваше се пакетният файл да бъде изпратен след отговор за готовност (ready)"
-#: fetch-pack.c:1377
+#: fetch-pack.c:1386
msgid "expected no other sections to be sent after no 'ready'"
msgstr ""
"очакваше се след липса на отговор за готовност (ready) да не се се пращат "
"други раздели"
-#: fetch-pack.c:1419
+#: fetch-pack.c:1428
#, c-format
msgid "error processing shallow info: %d"
msgstr "грешка при обработка на информация за дълбочината/плиткостта: %d"
-#: fetch-pack.c:1466
+#: fetch-pack.c:1475
#, c-format
msgid "expected wanted-ref, got '%s'"
msgstr "очаква се искан указател, а бе получено: „%s“"
-#: fetch-pack.c:1471
+#: fetch-pack.c:1480
#, c-format
msgid "unexpected wanted-ref: '%s'"
msgstr "неочакван искан указател: „%s“"
-#: fetch-pack.c:1476
+#: fetch-pack.c:1485
#, c-format
msgid "error processing wanted refs: %d"
msgstr "грешка при обработката на исканите указатели: %d"
-#: fetch-pack.c:1506
+#: fetch-pack.c:1515
msgid "git fetch-pack: expected response end packet"
msgstr "git fetch-pack: очаква се пакет за край на отговора"
-#: fetch-pack.c:1887
+#: fetch-pack.c:1897
msgid "no matching remote head"
msgstr "не може да бъде открит подходящ връх от отдалеченото хранилище"
-#: fetch-pack.c:1910 builtin/clone.c:692
+#: fetch-pack.c:1920 builtin/clone.c:693
msgid "remote did not send all necessary objects"
msgstr "отдалеченото хранилище не изпрати всички необходими обекти."
-#: fetch-pack.c:1937
+#: fetch-pack.c:1947
#, c-format
msgid "no such remote ref %s"
msgstr "такъв отдалечен указател няма: %s"
-#: fetch-pack.c:1940
+#: fetch-pack.c:1950
#, c-format
msgid "Server does not allow request for unadvertised object %s"
msgstr "Сървърът не позволява заявка за необявен обект „%s“"
@@ -4397,7 +4411,7 @@ msgstr "Програмата „gpg“ не подписа данните."
msgid "ignore invalid color '%.*s' in log.graphColors"
msgstr "прескачане на неправилния цвят „%.*s“ в „log.graphColors“"
-#: grep.c:668
+#: grep.c:640
msgid ""
"given pattern contains NULL byte (via -f <file>). This is only supported "
"with -P under PCRE v2"
@@ -4405,18 +4419,18 @@ msgstr ""
"зададеният шаблон съдържа нулев знак (идва от -f „ФАЙЛ“). Това се поддържа "
"в комбинация с „-P“ само при ползването на „PCRE v2“"
-#: grep.c:2128
+#: grep.c:2100
#, c-format
msgid "'%s': unable to read %s"
msgstr "„%s“: файлът сочен от „%s“ не може да бъде прочетен"
-#: grep.c:2145 setup.c:176 builtin/clone.c:411 builtin/diff.c:89
+#: grep.c:2117 setup.c:176 builtin/clone.c:412 builtin/diff.c:89
#: builtin/rm.c:135
#, c-format
msgid "failed to stat '%s'"
msgstr "не може да бъде получена информация чрез „stat“ за „%s“"
-#: grep.c:2156
+#: grep.c:2128
#, c-format
msgid "'%s': short read"
msgstr "„%s“: изчитането върна по-малко байтове от очакваното"
@@ -4507,7 +4521,7 @@ msgstr "Външни команди"
msgid "Command aliases"
msgstr "Псевдоними на командите"
-#: help.c:513
+#: help.c:527
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -4516,36 +4530,36 @@ msgstr ""
"Изглежда, че „%s“ е команда на git, но тя не може да\n"
"бъде изпълнена. Вероятно пакетът „git-%s“ е повреден."
-#: help.c:572
+#: help.c:543 help.c:631
+#, c-format
+msgid "git: '%s' is not a git command. See 'git --help'."
+msgstr "git: „%s“ не е команда на git. Погледнете изхода от „git --help“."
+
+#: help.c:591
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "Странно, изглежда, че на системата ви няма нито една команда на git."
-#: help.c:594
+#: help.c:613
#, c-format
msgid "WARNING: You called a Git command named '%s', which does not exist."
msgstr ""
"ПРЕДУПРЕЖДЕНИЕ: Пробвахте да изпълните команда на Git на име „%s“, а такава "
"не съществува."
-#: help.c:599
+#: help.c:618
#, c-format
msgid "Continuing under the assumption that you meant '%s'."
msgstr ""
"Изпълнението автоматично продължава, като се счита, че имате предвид „%s“."
-#: help.c:604
+#: help.c:623
#, c-format
msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
msgstr ""
"Изпълнението автоматично ще продължи след %0.1f сек., като се счита, че "
"имате предвид „%s“."
-#: help.c:612
-#, c-format
-msgid "git: '%s' is not a git command. See 'git --help'."
-msgstr "git: „%s“ не е команда на git. Погледнете изхода от „git --help“."
-
-#: help.c:616
+#: help.c:635
msgid ""
"\n"
"The most similar command is"
@@ -4559,16 +4573,16 @@ msgstr[1] ""
"\n"
"Най-близките команди са"
-#: help.c:656
+#: help.c:675
msgid "git version [<options>]"
msgstr "git version [ОПЦИЯ…]"
-#: help.c:711
+#: help.c:730
#, c-format
msgid "%s: %s - %s"
msgstr "%s: %s — %s"
-#: help.c:715
+#: help.c:734
msgid ""
"\n"
"Did you mean this?"
@@ -4738,6 +4752,20 @@ msgstr "Файлът-ключалка „%s.lock“ не може да бъде
msgid "expected flush after ls-refs arguments"
msgstr "след аргументите към „ls-refs“ се очаква изчистване на буферите"
+#: merge-ort-wrappers.c:13 merge-recursive.c:3672
+#, c-format
+msgid ""
+"Your local changes to the following files would be overwritten by merge:\n"
+" %s"
+msgstr ""
+"Сливането ще презапише локалните промени на тези файлове:\n"
+" %s"
+
+#: merge-ort-wrappers.c:33 merge-recursive.c:3436
+#, c-format
+msgid "Already up to date!"
+msgstr "Вече е обновено!"
+
#: merge-recursive.c:356
msgid "(bad commit)\n"
msgstr "(лошо подаване)\n"
@@ -5140,10 +5168,6 @@ msgstr "Добавяне на „%s“"
msgid "CONFLICT (add/add): Merge conflict in %s"
msgstr "КОНФЛИКТ (добавяне/добавяне): Конфликт при сливане на „%s“"
-#: merge-recursive.c:3436
-msgid "Already up to date!"
-msgstr "Вече е обновено!"
-
#: merge-recursive.c:3445
#, c-format
msgid "merging of trees %s and %s failed"
@@ -5164,21 +5188,12 @@ msgstr[1] "открити са %u общи предшественици:"
msgid "merge returned no commit"
msgstr "сливането не върна подаване"
-#: merge-recursive.c:3672
-#, c-format
-msgid ""
-"Your local changes to the following files would be overwritten by merge:\n"
-" %s"
-msgstr ""
-"Сливането ще презапише локалните промени на тези файлове:\n"
-" %s"
-
#: merge-recursive.c:3769
#, c-format
msgid "Could not parse object '%s'"
msgstr "Неуспешен анализ на обекта „%s“"
-#: merge-recursive.c:3787 builtin/merge.c:702 builtin/merge.c:881
+#: merge-recursive.c:3787 builtin/merge.c:711 builtin/merge.c:895
msgid "Unable to write index."
msgstr "Индексът не може да бъде прочетен"
@@ -5186,131 +5201,125 @@ msgstr "Индексът не може да бъде прочетен"
msgid "failed to read the cache"
msgstr "кешът не може да бъде прочетен"
-#: merge.c:109 rerere.c:720 builtin/am.c:1896 builtin/am.c:1930
-#: builtin/checkout.c:560 builtin/checkout.c:816 builtin/clone.c:816
+#: merge.c:109 rerere.c:720 builtin/am.c:1883 builtin/am.c:1917
+#: builtin/checkout.c:573 builtin/checkout.c:829 builtin/clone.c:817
#: builtin/stash.c:265
msgid "unable to write new index file"
msgstr "неуспешно записване на новия индекс"
-#: midx.c:79
+#: midx.c:80
#, c-format
msgid "multi-pack-index file %s is too small"
msgstr "файлът с индекса за множество пакети „%s“ е твърде малък"
-#: midx.c:95
+#: midx.c:96
#, c-format
msgid "multi-pack-index signature 0x%08x does not match signature 0x%08x"
msgstr "отпечатъкът на индекса за множество пакети 0x%08x не съвпада с 0x%08x"
-#: midx.c:100
+#: midx.c:101
#, c-format
msgid "multi-pack-index version %d not recognized"
msgstr "непозната версия на индекс за множество пакети — %d"
-#: midx.c:105
+#: midx.c:106
#, c-format
msgid "multi-pack-index hash version %u does not match version %u"
msgstr ""
"версията на контролната сума на индекса за множество пакети %u не съвпада с "
"%u"
-#: midx.c:122
+#: midx.c:123
msgid "invalid chunk offset (too large)"
msgstr "неправилно (прекалено голямо) отместване на откъс"
-#: midx.c:146
+#: midx.c:147
msgid "terminating multi-pack-index chunk id appears earlier than expected"
msgstr ""
"идентификаторът за краен откъс на индекс за множество пакети се явява по-"
"рано от очакваното"
-#: midx.c:159
+#: midx.c:160
msgid "multi-pack-index missing required pack-name chunk"
msgstr "липсва откъс (pack-name) от индекс за множество пакети"
-#: midx.c:161
+#: midx.c:162
msgid "multi-pack-index missing required OID fanout chunk"
msgstr "липсва откъс (OID fanout) от индекс за множество пакети"
-#: midx.c:163
+#: midx.c:164
msgid "multi-pack-index missing required OID lookup chunk"
msgstr "липсва откъс (OID lookup) от индекс за множество пакети"
-#: midx.c:165
+#: midx.c:166
msgid "multi-pack-index missing required object offsets chunk"
msgstr "липсва откъс за отместванията на обекти от индекс за множество пакети"
-#: midx.c:179
+#: midx.c:180
#, c-format
msgid "multi-pack-index pack names out of order: '%s' before '%s'"
msgstr ""
"неправилна подредба на имената в индекс за множество пакети: „%s“ се появи "
"преди „%s“"
-#: midx.c:222
+#: midx.c:223
#, c-format
msgid "bad pack-int-id: %u (%u total packs)"
msgstr ""
"неправилен идентификатор на пакет (pack-int-id): %u (от общо %u пакети)"
-#: midx.c:272
+#: midx.c:273
msgid "multi-pack-index stores a 64-bit offset, but off_t is too small"
msgstr ""
"индексът за множество пакети съдържа 64-битови отмествания, но размерът на "
"„off_t“ е недостатъчен"
-#: midx.c:300
-msgid "error preparing packfile from multi-pack-index"
-msgstr ""
-"грешка при създаването на пакетен файл на базата на индекс за множество "
-"пакети"
-
-#: midx.c:485
+#: midx.c:480
#, c-format
msgid "failed to add packfile '%s'"
msgstr "пакетният файл „%s“ не може да бъде добавен"
-#: midx.c:491
+#: midx.c:486
#, c-format
msgid "failed to open pack-index '%s'"
msgstr "индексът за пакети „%s“ не може да бъде отворен"
-#: midx.c:551
+#: midx.c:546
#, c-format
msgid "failed to locate object %d in packfile"
msgstr "обект %d в пакетния файл липсва"
-#: midx.c:853
+#: midx.c:846
msgid "Adding packfiles to multi-pack-index"
msgstr "Добавяне на пакетни файлове към индекс за множество пакети"
-#: midx.c:886
+#: midx.c:879
#, c-format
msgid "did not see pack-file %s to drop"
msgstr "пакетният файл за триене „%s“ не може да се открие"
-#: midx.c:938
+#: midx.c:931
msgid "no pack files to index."
msgstr "няма пакетни файлове за индексиране"
-#: midx.c:990
+#: midx.c:982
msgid "Writing chunks to multi-pack-index"
msgstr "Запис на откъси към индекс за множество пакети"
-#: midx.c:1068
+#: midx.c:1060
#, c-format
msgid "failed to clear multi-pack-index at %s"
msgstr "индексът за множество пакети не може да бъде изчистен при „%s“"
-#: midx.c:1124
+#: midx.c:1116
msgid "multi-pack-index file exists, but failed to parse"
msgstr "файлът с индекса за множество пакети, но не може да бъде анализиран"
-#: midx.c:1132
+#: midx.c:1124
msgid "Looking for referenced packfiles"
msgstr "Търсене на указаните пакетни файлове"
-#: midx.c:1147
+#: midx.c:1139
#, c-format
msgid ""
"oid fanout out of order: fanout[%d] = %<PRIx32> > %<PRIx32> = fanout[%d]"
@@ -5318,58 +5327,58 @@ msgstr ""
"неправилна подредба на откъси (OID fanout): fanout[%d] = %<PRIx32> > "
"%<PRIx32> = fanout[%d]"
-#: midx.c:1152
+#: midx.c:1144
msgid "the midx contains no oid"
msgstr "във файла с индекса за множество пакети няма идентификатори на обекти"
-#: midx.c:1161
+#: midx.c:1153
msgid "Verifying OID order in multi-pack-index"
msgstr ""
"Проверка на подредбата на идентификатори на обекти във файл с индекс към "
"множество пакетни файлове"
-#: midx.c:1170
+#: midx.c:1162
#, c-format
msgid "oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"
msgstr ""
"неправилна подредба на откъси (OID lookup): oid[%d] = %s >= %s = oid[%d]"
-#: midx.c:1190
+#: midx.c:1182
msgid "Sorting objects by packfile"
msgstr "Подредба на обектите по пакетни файлове"
-#: midx.c:1197
+#: midx.c:1189
msgid "Verifying object offsets"
msgstr "Проверка на отместването на обекти"
-#: midx.c:1213
+#: midx.c:1205
#, c-format
msgid "failed to load pack entry for oid[%d] = %s"
msgstr "записът в пакета за обекта oid[%d] = %s не може да бъде зареден"
-#: midx.c:1219
+#: midx.c:1211
#, c-format
msgid "failed to load pack-index for packfile %s"
msgstr "индексът на пакета „%s“ не може да бъде зареден"
-#: midx.c:1228
+#: midx.c:1220
#, c-format
msgid "incorrect object offset for oid[%d] = %s: %<PRIx64> != %<PRIx64>"
msgstr "неправилно отместване на обект за oid[%d] = %s: %<PRIx64> != %<PRIx64>"
-#: midx.c:1253
+#: midx.c:1245
msgid "Counting referenced objects"
msgstr "Преброяване на свързаните обекти"
-#: midx.c:1263
+#: midx.c:1255
msgid "Finding and deleting unreferenced packfiles"
msgstr "Търсене и изтриване на несвързаните пакетни файлове"
-#: midx.c:1454
+#: midx.c:1446
msgid "could not start pack-objects"
msgstr "командата „pack-objects“ не може да бъде стартирана"
-#: midx.c:1474
+#: midx.c:1466
msgid "could not finish pack-objects"
msgstr "командата „pack-objects“ не може да бъде завършена"
@@ -5466,19 +5475,19 @@ msgstr "разлика в контролната сума: „%s“"
msgid "unable to get size of %s"
msgstr "размерът на „%s“ не може да бъде получен"
-#: packfile.c:630
+#: packfile.c:615
msgid "offset before end of packfile (broken .idx?)"
msgstr ""
"отместване преди края на пакетния файл (възможно е индексът да е повреден)"
-#: packfile.c:1922
+#: packfile.c:1907
#, c-format
msgid "offset before start of pack index for %s (corrupt index?)"
msgstr ""
"отместване преди началото на индекса на пакетния файл „%s“ (възможно е "
"индексът да е повреден)"
-#: packfile.c:1926
+#: packfile.c:1911
#, c-format
msgid "offset beyond end of pack index for %s (truncated index?)"
msgstr ""
@@ -5730,7 +5739,7 @@ msgstr "протоколна грешка: неправилeн знак за д
msgid "protocol error: bad line length %d"
msgstr "протоколна грешка: неправилна дължина на ред: %d"
-#: pkt-line.c:373 sideband.c:150
+#: pkt-line.c:373 sideband.c:165
#, c-format
msgid "remote error: %s"
msgstr "отдалечена грешка: %s"
@@ -5781,7 +5790,7 @@ msgid "could not read `log` output"
msgstr ""
"изходът от командата за журнала с подавания „log“ не може да се прочете"
-#: range-diff.c:98 sequencer.c:5283
+#: range-diff.c:98 sequencer.c:5310
#, c-format
msgid "could not parse commit '%s'"
msgstr "подаването „%s“ не може да бъде анализирано"
@@ -5800,11 +5809,11 @@ msgstr ""
msgid "could not parse git header '%.*s'"
msgstr "заглавната част на git „%.*s“ не може да се анализира"
-#: range-diff.c:301
+#: range-diff.c:299
msgid "failed to generate diff"
msgstr "неуспешно търсене на разлика"
-#: range-diff.c:534 range-diff.c:536
+#: range-diff.c:532 range-diff.c:534
#, c-format
msgid "could not parse log for '%s'"
msgstr "журналът с подаванията на „%s“ не може да бъде анализиран"
@@ -5925,8 +5934,8 @@ msgstr "неподредени записи за „%s“"
#: read-cache.c:1971 read-cache.c:2262 rerere.c:565 rerere.c:599 rerere.c:1111
#: submodule.c:1628 builtin/add.c:538 builtin/check-ignore.c:181
-#: builtin/checkout.c:489 builtin/checkout.c:675 builtin/clean.c:991
-#: builtin/commit.c:364 builtin/diff-tree.c:121 builtin/grep.c:507
+#: builtin/checkout.c:502 builtin/checkout.c:688 builtin/clean.c:991
+#: builtin/commit.c:364 builtin/diff-tree.c:122 builtin/grep.c:507
#: builtin/mv.c:146 builtin/reset.c:247 builtin/rm.c:290
#: builtin/submodule--helper.c:332
msgid "index file corrupt"
@@ -5984,12 +5993,12 @@ msgstr "споделеният индекс „%s“ не може да се о
msgid "broken index, expect %s in %s, got %s"
msgstr "грешки в индекса — в „%2$s“ се очаква „%1$s“, а бе получено „%3$s“"
-#: read-cache.c:3017 strbuf.c:1171 wrapper.c:633 builtin/merge.c:1126
+#: read-cache.c:3017 strbuf.c:1171 wrapper.c:633 builtin/merge.c:1140
#, c-format
msgid "could not close '%s'"
msgstr "„%s“ не може да се затвори"
-#: read-cache.c:3120 sequencer.c:2446 sequencer.c:4185
+#: read-cache.c:3120 sequencer.c:2479 sequencer.c:4231
#, c-format
msgid "could not stat '%s'"
msgstr "неуспешно изпълнение на „stat“ върху „%s“"
@@ -6128,14 +6137,14 @@ msgstr ""
"Ако изтриете всичко, пребазирането ще бъде преустановено.\n"
"\n"
-#: rebase-interactive.c:110 rerere.c:485 rerere.c:692 sequencer.c:3571
-#: sequencer.c:3597 sequencer.c:5389 builtin/fsck.c:347 builtin/rebase.c:264
+#: rebase-interactive.c:110 rerere.c:485 rerere.c:692 sequencer.c:3607
+#: sequencer.c:3633 sequencer.c:5416 builtin/fsck.c:347 builtin/rebase.c:270
#, c-format
msgid "could not write '%s'"
msgstr "„%s“ не може да се запише"
-#: rebase-interactive.c:116 builtin/rebase.c:196 builtin/rebase.c:222
-#: builtin/rebase.c:246
+#: rebase-interactive.c:116 builtin/rebase.c:202 builtin/rebase.c:228
+#: builtin/rebase.c:252
#, c-format
msgid "could not write '%s'."
msgstr "„%s“ не може да се запише."
@@ -6166,9 +6175,9 @@ msgstr ""
"предупреждение)\n"
"или „error“ (считане за грешка).\n"
-#: rebase-interactive.c:233 rebase-interactive.c:238 sequencer.c:2361
-#: builtin/rebase.c:182 builtin/rebase.c:207 builtin/rebase.c:233
-#: builtin/rebase.c:258
+#: rebase-interactive.c:233 rebase-interactive.c:238 sequencer.c:2394
+#: builtin/rebase.c:188 builtin/rebase.c:213 builtin/rebase.c:239
+#: builtin/rebase.c:264
#, c-format
msgid "could not read '%s'."
msgstr "от „%s“ не може да се чете."
@@ -6363,61 +6372,61 @@ msgstr "формат: лексемата %%(end) е използвана без
msgid "malformed format string %s"
msgstr "неправилен форматиращ низ „%s“"
-#: ref-filter.c:1541
+#: ref-filter.c:1549
#, c-format
msgid "no branch, rebasing %s"
msgstr "извън клон, пребазиране на „%s“"
-#: ref-filter.c:1544
+#: ref-filter.c:1552
#, c-format
msgid "no branch, rebasing detached HEAD %s"
msgstr "извън клон, пребазиране на несвързан указател „HEAD“ при „%s“"
-#: ref-filter.c:1547
+#: ref-filter.c:1555
#, c-format
msgid "no branch, bisect started on %s"
msgstr "извън клон, двоично търсене от „%s“"
-#: ref-filter.c:1557
+#: ref-filter.c:1565
msgid "no branch"
msgstr "извън клон"
-#: ref-filter.c:1591 ref-filter.c:1800
+#: ref-filter.c:1599 ref-filter.c:1808
#, c-format
msgid "missing object %s for %s"
msgstr "обектът „%s“ липсва за „%s“"
-#: ref-filter.c:1601
+#: ref-filter.c:1609
#, c-format
msgid "parse_object_buffer failed on %s for %s"
msgstr "неуспешно анализиране чрез „parse_object_buffer“ на „%s“ за „%s“"
-#: ref-filter.c:2054
+#: ref-filter.c:2062
#, c-format
msgid "malformed object at '%s'"
msgstr "обект със сгрешен формат при „%s“"
-#: ref-filter.c:2143
+#: ref-filter.c:2151
#, c-format
msgid "ignoring ref with broken name %s"
msgstr "игнориране на указателя с грешно име „%s“"
-#: ref-filter.c:2148 refs.c:657
+#: ref-filter.c:2156 refs.c:676
#, c-format
msgid "ignoring broken ref %s"
msgstr "игнориране на повредения указател „%s“"
-#: ref-filter.c:2464
+#: ref-filter.c:2472
#, c-format
msgid "format: %%(end) atom missing"
msgstr "грешка във форма̀та: липсва лексемата %%(end)"
-#: ref-filter.c:2563
+#: ref-filter.c:2571
#, c-format
msgid "malformed object name %s"
msgstr "неправилно име на обект „%s“"
-#: ref-filter.c:2568
+#: ref-filter.c:2576
#, c-format
msgid "option `%s' must point to a commit"
msgstr "опцията „%s“ не сочи към подаване"
@@ -6427,65 +6436,90 @@ msgstr "опцията „%s“ не сочи към подаване"
msgid "%s does not point to a valid object!"
msgstr "„%s“ не сочи към позволен обект!"
-#: refs.c:572
+#: refs.c:566
+#, c-format
+msgid ""
+"Using '%s' as the name for the initial branch. This default branch name\n"
+"is subject to change. To configure the initial branch name to use in all\n"
+"of your new repositories, which will suppress this warning, call:\n"
+"\n"
+"\tgit config --global init.defaultBranch <name>\n"
+"\n"
+"Names commonly chosen instead of 'master' are 'main', 'trunk' and\n"
+"'development'. The just-created branch can be renamed via this command:\n"
+"\n"
+"\tgit branch -m <name>\n"
+msgstr ""
+"Първоначалният клон ще се казва „%s“. Това може да се промени. Можете да "
+"зададете\n"
+"настройката и да спрете това съобщение. За това изпълнете:\n"
+"\n"
+" git config --global init.defaultBranch ИМЕ\n"
+"\n"
+"Често ползвани варианти вместо „master“ са „main“, „trunk“ и „development“.\n"
+"За да преименувата току що създаден клон, изпълнете:\n"
+"\n"
+" git branch -m ИМЕ\n"
+
+#: refs.c:588
#, c-format
msgid "could not retrieve `%s`"
msgstr "„%s“ не може да бъде получен"
-#: refs.c:579
+#: refs.c:598
#, c-format
msgid "invalid branch name: %s = %s"
msgstr "неправилно име на клон: „%s = %s“"
-#: refs.c:655
+#: refs.c:674
#, c-format
msgid "ignoring dangling symref %s"
msgstr "игнориране на указател на обект извън клон „%s“"
-#: refs.c:892
+#: refs.c:911
#, c-format
msgid "log for ref %s has gap after %s"
msgstr "има пропуски в журнала с подаванията за указателя „%s“ след „%s“"
-#: refs.c:898
+#: refs.c:917
#, c-format
msgid "log for ref %s unexpectedly ended on %s"
msgstr "журналът с подаванията за указателя „%s“ свършва неочаквано след „%s“"
-#: refs.c:957
+#: refs.c:976
#, c-format
msgid "log for %s is empty"
msgstr "журналът с подаванията за указателя „%s“ е празен"
-#: refs.c:1049
+#: refs.c:1068
#, c-format
msgid "refusing to update ref with bad name '%s'"
msgstr "указател не може да се обнови с грешно име „%s“"
-#: refs.c:1120
+#: refs.c:1139
#, c-format
msgid "update_ref failed for ref '%s': %s"
msgstr "неуспешно обновяване на указателя „%s“: %s"
-#: refs.c:1944
+#: refs.c:1963
#, c-format
msgid "multiple updates for ref '%s' not allowed"
msgstr "не са позволени повече от една промени на указателя „%s“"
-#: refs.c:2024
+#: refs.c:2043
msgid "ref updates forbidden inside quarantine environment"
msgstr "обновяванията на указатели са забранени в среди под карантина"
-#: refs.c:2035
+#: refs.c:2054
msgid "ref updates aborted by hook"
msgstr "обновяванията на указатели са преустановени от кука"
-#: refs.c:2135 refs.c:2165
+#: refs.c:2154 refs.c:2184
#, c-format
msgid "'%s' exists; cannot create '%s'"
msgstr "„%s“ съществува, не може да се създаде „%s“"
-#: refs.c:2141 refs.c:2176
+#: refs.c:2160 refs.c:2195
#, c-format
msgid "cannot process '%s' and '%s' at the same time"
msgstr "невъзможно е едновременно да се обработват „%s“ и „%s“"
@@ -6506,7 +6540,7 @@ msgstr "Указателят „%s“ не може да бъде изтрит:
msgid "could not delete references: %s"
msgstr "Указателите не може да бъдат изтрити: %s"
-#: refspec.c:167
+#: refspec.c:170
#, c-format
msgid "invalid refspec '%s'"
msgstr "неправилен указател: „%s“"
@@ -6652,96 +6686,96 @@ msgstr ""
"указателят на версия-цел „%s“ съответства и ще получава от повече от един "
"източник"
-#: remote.c:1703 remote.c:1804
+#: remote.c:1714 remote.c:1815
msgid "HEAD does not point to a branch"
msgstr "Указателят „HEAD“ не сочи към клон"
-#: remote.c:1712
+#: remote.c:1723
#, c-format
msgid "no such branch: '%s'"
msgstr "няма клон на име „%s“"
-#: remote.c:1715
+#: remote.c:1726
#, c-format
msgid "no upstream configured for branch '%s'"
msgstr "не е зададен клон-източник за клона „%s“"
-#: remote.c:1721
+#: remote.c:1732
#, c-format
msgid "upstream branch '%s' not stored as a remote-tracking branch"
msgstr "клонът-източник „%s“ не е съхранен като следящ клон"
-#: remote.c:1736
+#: remote.c:1747
#, c-format
msgid "push destination '%s' on remote '%s' has no local tracking branch"
msgstr ""
"липсва локален следящ клон за местоположението за изтласкване „%s“ в "
"хранилището „%s“"
-#: remote.c:1748
+#: remote.c:1759
#, c-format
msgid "branch '%s' has no remote for pushing"
msgstr "няма информация клонът „%s“ да следи някой друг"
-#: remote.c:1758
+#: remote.c:1769
#, c-format
msgid "push refspecs for '%s' do not include '%s'"
msgstr "указателят за изтласкване на „%s“ не включва „%s“"
-#: remote.c:1771
+#: remote.c:1782
msgid "push has no destination (push.default is 'nothing')"
msgstr "указателят за изтласкване не включва цел („push.default“ е „nothing“)"
-#: remote.c:1793
+#: remote.c:1804
msgid "cannot resolve 'simple' push to a single destination"
msgstr "простото (simple) изтласкване не съответства на една цел"
-#: remote.c:1922
+#: remote.c:1933
#, c-format
msgid "couldn't find remote ref %s"
msgstr "отдалеченият указател „%s“ не може да бъде открит"
-#: remote.c:1935
+#: remote.c:1946
#, c-format
msgid "* Ignoring funny ref '%s' locally"
msgstr "• прескачане на неочаквания локален указател „%s“"
-#: remote.c:2098
+#: remote.c:2109
#, c-format
msgid "Your branch is based on '%s', but the upstream is gone.\n"
msgstr "Този клон следи „%s“, но следеният клон е изтрит.\n"
-#: remote.c:2102
+#: remote.c:2113
msgid " (use \"git branch --unset-upstream\" to fixup)\n"
msgstr " (за да коригирате това, използвайте „git branch --unset-upstream“)\n"
-#: remote.c:2105
+#: remote.c:2116
#, c-format
msgid "Your branch is up to date with '%s'.\n"
msgstr "Клонът е обновен към „%s“.\n"
-#: remote.c:2109
+#: remote.c:2120
#, c-format
msgid "Your branch and '%s' refer to different commits.\n"
msgstr "Клонът ви и „%s“ сочат към различни подавания.\n"
-#: remote.c:2112
+#: remote.c:2123
#, c-format
msgid " (use \"%s\" for details)\n"
msgstr " (за повече информация ползвайте „%s“)\n"
-#: remote.c:2116
+#: remote.c:2127
#, c-format
msgid "Your branch is ahead of '%s' by %d commit.\n"
msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
msgstr[0] "Клонът ви е с %2$d подаване пред „%1$s“.\n"
msgstr[1] "Клонът ви е с %2$d подавания пред „%1$s“.\n"
-#: remote.c:2122
+#: remote.c:2133
msgid " (use \"git push\" to publish your local commits)\n"
msgstr " (публикувайте локалните си промени чрез „git push“)\n"
-#: remote.c:2125
+#: remote.c:2136
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
@@ -6749,11 +6783,11 @@ msgid_plural ""
msgstr[0] "Клонът ви е с %2$d подаване зад „%1$s“ и може да бъде превъртян.\n"
msgstr[1] "Клонът ви е с %2$d подавания зад „%1$s“ и може да бъде превъртян.\n"
-#: remote.c:2133
+#: remote.c:2144
msgid " (use \"git pull\" to update your local branch)\n"
msgstr " (обновете локалния си клон чрез „git pull“)\n"
-#: remote.c:2136
+#: remote.c:2147
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -6768,11 +6802,11 @@ msgstr[1] ""
"Текущият клон се е отделил от „%s“,\n"
"двата имат съответно по %d и %d несъвпадащи подавания.\n"
-#: remote.c:2146
+#: remote.c:2157
msgid " (use \"git pull\" to merge the remote branch into yours)\n"
msgstr " (слейте отдалечения клон в локалния чрез „git pull“)\n"
-#: remote.c:2337
+#: remote.c:2349
#, c-format
msgid "cannot parse expected object name '%s'"
msgstr "очакваното име на обект „%s“ не може да бъде анализирано"
@@ -6853,7 +6887,7 @@ msgstr "излишният обект „%s“ не може да се изтр
msgid "Recorded preimage for '%s'"
msgstr "Предварителният вариант на „%s“ е запазен"
-#: rerere.c:881 submodule.c:2082 builtin/log.c:1975
+#: rerere.c:881 submodule.c:2082 builtin/log.c:1992
#: builtin/submodule--helper.c:1878 builtin/submodule--helper.c:1890
#, c-format
msgid "could not create directory '%s'"
@@ -6892,45 +6926,45 @@ msgstr "директорията „rr-cache“ не може да се отво
msgid "could not determine HEAD revision"
msgstr "не може да се определи към какво да сочи указателят „HEAD“"
-#: reset.c:70 reset.c:76 sequencer.c:3426
+#: reset.c:70 reset.c:76 sequencer.c:3460
#, c-format
msgid "failed to find tree of %s"
msgstr "дървото, сочено от „%s“, не може да бъде открито"
-#: revision.c:2344
+#: revision.c:2336
msgid "--unpacked=<packfile> no longer supported"
msgstr "опцията „--unpacked=ПАКЕТЕН_ФАЙЛ“ вече не се поддържа"
-#: revision.c:2364
+#: revision.c:2356
#, c-format
msgid "unknown value for --diff-merges: %s"
msgstr "непозната стойност за опцията „--diff-merges“: „%s“"
-#: revision.c:2702
+#: revision.c:2694
msgid "your current branch appears to be broken"
msgstr "Текущият клон е повреден"
-#: revision.c:2705
+#: revision.c:2697
#, c-format
msgid "your current branch '%s' does not have any commits yet"
msgstr "Текущият клон „%s“ е без подавания "
-#: revision.c:2915
+#: revision.c:2907
msgid "-L does not yet support diff formats besides -p and -s"
msgstr ""
"опцията „-L“ поддържа единствено форматирането на разликите според опциите „-"
"p“ и „-s“"
-#: run-command.c:763
+#: run-command.c:764
msgid "open /dev/null failed"
msgstr "неуспешно отваряне на „/dev/null“"
-#: run-command.c:1270
+#: run-command.c:1271
#, c-format
msgid "cannot create async thread: %s"
msgstr "не може да се създаде асинхронна нишка: %s"
-#: run-command.c:1334
+#: run-command.c:1335
#, c-format
msgid ""
"The '%s' hook was ignored because it's not set as executable.\n"
@@ -6940,37 +6974,37 @@ msgstr ""
"За да изключите това предупреждение, изпълнете:\n"
" git config advice.ignoredHook false"
-#: send-pack.c:145
+#: send-pack.c:146
msgid "unexpected flush packet while reading remote unpack status"
msgstr ""
"неочакван изчистващ пакет „flush“ при изчитане на състоянието от "
"отдалеченото разпакетиране"
-#: send-pack.c:147
+#: send-pack.c:148
#, c-format
msgid "unable to parse remote unpack status: %s"
msgstr ""
"състоянието от отдалеченото разпакетиране не може да бъде анализирано: %s"
-#: send-pack.c:149
+#: send-pack.c:150
#, c-format
msgid "remote unpack failed: %s"
msgstr "неуспешно отдалечено разпакетиране: %s"
-#: send-pack.c:372
+#: send-pack.c:374
msgid "failed to sign the push certificate"
msgstr "сертификатът за изтласкване не може да бъде подписан"
-#: send-pack.c:460
+#: send-pack.c:467
msgid "the receiving end does not support this repository's hash algorithm"
msgstr ""
"отсрещната страна не поддържа алгоритъма за контролни суми на това хранилище"
-#: send-pack.c:469
+#: send-pack.c:476
msgid "the receiving end does not support --signed push"
msgstr "отсрещната страна не поддържа изтласкване с опцията „--signed“"
-#: send-pack.c:471
+#: send-pack.c:478
msgid ""
"not sending a push certificate since the receiving end does not support --"
"signed push"
@@ -6978,47 +7012,47 @@ msgstr ""
"отсрещната страна не поддържа изтласкване с опцията „--signed“, затова не се "
"използва сертификат"
-#: send-pack.c:483
+#: send-pack.c:490
msgid "the receiving end does not support --atomic push"
msgstr "получаващата страна не поддържа изтласкване с опцията „--atomic“"
-#: send-pack.c:488
+#: send-pack.c:495
msgid "the receiving end does not support push options"
msgstr "отсрещната страна не поддържа опции при изтласкване"
-#: sequencer.c:194
+#: sequencer.c:195
#, c-format
msgid "invalid commit message cleanup mode '%s'"
msgstr "несъществуващ режим на изчистване „%s“ на съобщение при подаване"
-#: sequencer.c:308
+#: sequencer.c:323
#, c-format
msgid "could not delete '%s'"
msgstr "„%s“ не може да бъде изтрит"
-#: sequencer.c:329 builtin/rebase.c:749 builtin/rebase.c:1590 builtin/rm.c:385
+#: sequencer.c:343 builtin/rebase.c:755 builtin/rebase.c:1596 builtin/rm.c:385
#, c-format
msgid "could not remove '%s'"
msgstr "„%s“ не може да бъде изтрит"
-#: sequencer.c:339
+#: sequencer.c:353
msgid "revert"
msgstr "отмяна"
-#: sequencer.c:341
+#: sequencer.c:355
msgid "cherry-pick"
msgstr "отбиране"
-#: sequencer.c:343
+#: sequencer.c:357
msgid "rebase"
msgstr "пребазиране"
-#: sequencer.c:345
+#: sequencer.c:359
#, c-format
msgid "unknown action: %d"
msgstr "неизвестно действие: %d"
-#: sequencer.c:404
+#: sequencer.c:418
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
@@ -7026,7 +7060,7 @@ msgstr ""
"след коригирането на конфликтите, отбележете съответните\n"
"пътища с „git add ПЪТ…“ или „git rm ПЪТ…“."
-#: sequencer.c:407
+#: sequencer.c:421
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'\n"
@@ -7036,43 +7070,43 @@ msgstr ""
"пътища с „git add ПЪТ…“ или „git rm ПЪТ…“, след което\n"
"подайте резултата с командата „git commit'“."
-#: sequencer.c:420 sequencer.c:3028
+#: sequencer.c:434 sequencer.c:3062
#, c-format
msgid "could not lock '%s'"
msgstr "„%s“ не може да се заключи"
-#: sequencer.c:422 sequencer.c:2827 sequencer.c:3032 sequencer.c:3046
-#: sequencer.c:3303 sequencer.c:5299 strbuf.c:1168 wrapper.c:631
+#: sequencer.c:436 sequencer.c:2861 sequencer.c:3066 sequencer.c:3080
+#: sequencer.c:3337 sequencer.c:5326 strbuf.c:1168 wrapper.c:631
#, c-format
msgid "could not write to '%s'"
msgstr "в „%s“ не може да се пише"
-#: sequencer.c:427
+#: sequencer.c:441
#, c-format
msgid "could not write eol to '%s'"
msgstr "краят на ред не може да се запише в „%s“"
-#: sequencer.c:432 sequencer.c:2832 sequencer.c:3034 sequencer.c:3048
-#: sequencer.c:3311
+#: sequencer.c:446 sequencer.c:2866 sequencer.c:3068 sequencer.c:3082
+#: sequencer.c:3345
#, c-format
msgid "failed to finalize '%s'"
msgstr "„%s“ не може да се завърши"
-#: sequencer.c:471
+#: sequencer.c:485
#, c-format
msgid "your local changes would be overwritten by %s."
msgstr "локалните ви промени ще бъдат презаписани при %s."
-#: sequencer.c:475
+#: sequencer.c:489
msgid "commit your changes or stash them to proceed."
msgstr "подайте или скатайте промените, за да продължите"
-#: sequencer.c:507
+#: sequencer.c:521
#, c-format
msgid "%s: fast-forward"
msgstr "%s: превъртане"
-#: sequencer.c:546 builtin/tag.c:566
+#: sequencer.c:560 builtin/tag.c:566
#, c-format
msgid "Invalid cleanup mode %s"
msgstr "Несъществуващ режим на изчистване „%s“"
@@ -7080,65 +7114,65 @@ msgstr "Несъществуващ режим на изчистване „%s“
#. TRANSLATORS: %s will be "revert", "cherry-pick" or
#. "rebase".
#.
-#: sequencer.c:640
+#: sequencer.c:670
#, c-format
msgid "%s: Unable to write new index file"
msgstr "%s: новият индекс не може да бъде запазен"
-#: sequencer.c:657
+#: sequencer.c:687
msgid "unable to update cache tree"
msgstr "дървото на кеша не може да бъде обновено"
-#: sequencer.c:671
+#: sequencer.c:701
msgid "could not resolve HEAD commit"
msgstr "подаването, сочено от указателя „HEAD“, не може да бъде открито"
-#: sequencer.c:751
+#: sequencer.c:781
#, c-format
msgid "no key present in '%.*s'"
msgstr "в „%.*s“ няма ключове"
-#: sequencer.c:762
+#: sequencer.c:792
#, c-format
msgid "unable to dequote value of '%s'"
msgstr "цитирането на стойността на „%s“ не може да бъде изчистено"
-#: sequencer.c:799 wrapper.c:201 wrapper.c:371 builtin/am.c:724
-#: builtin/am.c:816 builtin/merge.c:1121 builtin/rebase.c:902
+#: sequencer.c:829 wrapper.c:201 wrapper.c:371 builtin/am.c:710
+#: builtin/am.c:802 builtin/merge.c:1135 builtin/rebase.c:908
#, c-format
msgid "could not open '%s' for reading"
msgstr "файлът не може да бъде прочетен: „%s“"
-#: sequencer.c:809
+#: sequencer.c:839
msgid "'GIT_AUTHOR_NAME' already given"
msgstr "настройката за автор „GIT_AUTHOR_NAME“ вече е зададена"
-#: sequencer.c:814
+#: sequencer.c:844
msgid "'GIT_AUTHOR_EMAIL' already given"
msgstr "настройката за е-поща „GIT_AUTHOR_EMAIL“ вече е зададена"
-#: sequencer.c:819
+#: sequencer.c:849
msgid "'GIT_AUTHOR_DATE' already given"
msgstr "настройката за дата „GIT_AUTHOR_DATE“ вече е зададена"
-#: sequencer.c:823
+#: sequencer.c:853
#, c-format
msgid "unknown variable '%s'"
msgstr "непозната променлива „%s“"
-#: sequencer.c:828
+#: sequencer.c:858
msgid "missing 'GIT_AUTHOR_NAME'"
msgstr "настройката за автор „GIT_AUTHOR_NAME“ липсва"
-#: sequencer.c:830
+#: sequencer.c:860
msgid "missing 'GIT_AUTHOR_EMAIL'"
msgstr "настройката за е-поща „GIT_AUTHOR_EMAIL“ липсва"
-#: sequencer.c:832
+#: sequencer.c:862
msgid "missing 'GIT_AUTHOR_DATE'"
msgstr "настройката за дата „GIT_AUTHOR_DATE“ липсва"
-#: sequencer.c:897
+#: sequencer.c:927
#, c-format
msgid ""
"you have staged changes in your working tree\n"
@@ -7167,13 +7201,13 @@ msgstr ""
"\n"
" git rebase --continue\n"
-#: sequencer.c:1178
+#: sequencer.c:1208
msgid "'prepare-commit-msg' hook failed"
msgstr ""
"неуспешно изпълнение на куката при промяна на съобщението при подаване "
"(prepare-commit-msg)"
-#: sequencer.c:1184
+#: sequencer.c:1214
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
@@ -7202,7 +7236,7 @@ msgstr ""
"\n"
" git commit --amend --reset-author\n"
-#: sequencer.c:1197
+#: sequencer.c:1227
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
@@ -7228,351 +7262,351 @@ msgstr ""
"\n"
" git commit --amend --reset-author\n"
-#: sequencer.c:1239
+#: sequencer.c:1269
msgid "couldn't look up newly created commit"
msgstr "току що създаденото подаване не може да бъде открито"
-#: sequencer.c:1241
+#: sequencer.c:1271
msgid "could not parse newly created commit"
msgstr "току що създаденото подаване не може да бъде анализирано"
-#: sequencer.c:1287
+#: sequencer.c:1317
msgid "unable to resolve HEAD after creating commit"
msgstr ""
"състоянието сочено от указателя „HEAD“ не може да бъде открито след "
"подаването"
-#: sequencer.c:1289
+#: sequencer.c:1319
msgid "detached HEAD"
msgstr "несвързан връх „HEAD“"
-#: sequencer.c:1293
+#: sequencer.c:1323
msgid " (root-commit)"
msgstr " (начално подаване)"
-#: sequencer.c:1314
+#: sequencer.c:1344
msgid "could not parse HEAD"
msgstr "указателят „HEAD“ не може да бъде анализиран"
-#: sequencer.c:1316
+#: sequencer.c:1346
#, c-format
msgid "HEAD %s is not a commit!"
msgstr "указателят „HEAD“ „%s“ сочи към нещо, което не е подаване!"
-#: sequencer.c:1320 sequencer.c:1395 builtin/commit.c:1577
+#: sequencer.c:1350 sequencer.c:1425 builtin/commit.c:1577
msgid "could not parse HEAD commit"
msgstr "върховото подаване „HEAD“ не може да бъде прочетено"
-#: sequencer.c:1373 sequencer.c:2067
+#: sequencer.c:1403 sequencer.c:2100
msgid "unable to parse commit author"
msgstr "авторът на подаването не може да бъде анализиран"
-#: sequencer.c:1384 builtin/am.c:1580 builtin/merge.c:692
+#: sequencer.c:1414 builtin/am.c:1566 builtin/merge.c:701
msgid "git write-tree failed to write a tree"
msgstr "Командата „git write-tree“ не успя да запише обект-дърво"
-#: sequencer.c:1417 sequencer.c:1535
+#: sequencer.c:1447 sequencer.c:1565
#, c-format
msgid "unable to read commit message from '%s'"
msgstr "съобщението за подаване не може да бъде прочетено от „%s“"
-#: sequencer.c:1446 sequencer.c:1478
+#: sequencer.c:1476 sequencer.c:1508
#, c-format
msgid "invalid author identity '%s'"
msgstr "неправилна самоличност за автор: „%s“"
-#: sequencer.c:1452
+#: sequencer.c:1482
msgid "corrupt author: missing date information"
msgstr "повредена информация за автор: липсва дата"
-#: sequencer.c:1491 builtin/am.c:1606 builtin/commit.c:1678 builtin/merge.c:890
-#: builtin/merge.c:915
+#: sequencer.c:1521 builtin/am.c:1593 builtin/commit.c:1678 builtin/merge.c:904
+#: builtin/merge.c:929 t/helper/test-fast-rebase.c:78
msgid "failed to write commit object"
msgstr "обектът за подаването не може да бъде записан"
-#: sequencer.c:1518 sequencer.c:4237
+#: sequencer.c:1548 sequencer.c:4283 t/helper/test-fast-rebase.c:198
#, c-format
msgid "could not update %s"
msgstr "„%s“ не може да се обнови"
-#: sequencer.c:1567
+#: sequencer.c:1597
#, c-format
msgid "could not parse commit %s"
msgstr "подаването „%s“ не може да бъде анализирано"
-#: sequencer.c:1572
+#: sequencer.c:1602
#, c-format
msgid "could not parse parent commit %s"
msgstr "родителското подаване „%s“ не може да бъде анализирано"
-#: sequencer.c:1655 sequencer.c:1766
+#: sequencer.c:1685 sequencer.c:1796
#, c-format
msgid "unknown command: %d"
msgstr "непозната команда: %d"
-#: sequencer.c:1713 sequencer.c:1738
+#: sequencer.c:1743 sequencer.c:1768
#, c-format
msgid "This is a combination of %d commits."
msgstr "Това е обединение от %d подавания"
-#: sequencer.c:1723
+#: sequencer.c:1753
msgid "need a HEAD to fixup"
msgstr "За вкарване в предходното подаване ви трябва указател „HEAD“"
-#: sequencer.c:1725 sequencer.c:3338
+#: sequencer.c:1755 sequencer.c:3372
msgid "could not read HEAD"
msgstr "указателят „HEAD“ не може да се прочете"
-#: sequencer.c:1727
+#: sequencer.c:1757
msgid "could not read HEAD's commit message"
msgstr ""
"съобщението за подаване към указателя „HEAD“ не може да бъде прочетено: %s"
-#: sequencer.c:1733
+#: sequencer.c:1763
#, c-format
msgid "cannot write '%s'"
msgstr "„%s“ не може да се запази"
-#: sequencer.c:1740 git-rebase--preserve-merges.sh:486
+#: sequencer.c:1770 git-rebase--preserve-merges.sh:486
msgid "This is the 1st commit message:"
msgstr "Това е 1-то съобщение при подаване:"
-#: sequencer.c:1748
+#: sequ