summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/RelNotes/2.4.4.txt35
-rw-r--r--Documentation/RelNotes/2.4.5.txt28
-rw-r--r--Documentation/RelNotes/2.4.6.txt23
-rw-r--r--Documentation/RelNotes/2.4.7.txt53
-rw-r--r--Documentation/RelNotes/2.5.0.txt232
-rw-r--r--Documentation/config.txt5
-rw-r--r--Documentation/fmt-merge-msg-config.txt10
-rw-r--r--Documentation/git-blame.txt2
-rw-r--r--Documentation/git-branch.txt8
-rw-r--r--Documentation/git-checkout.txt78
-rw-r--r--Documentation/git-describe.txt2
-rw-r--r--Documentation/git-fmt-merge-msg.txt12
-rw-r--r--Documentation/git-format-patch.txt2
-rw-r--r--Documentation/git-prune.txt3
-rw-r--r--Documentation/git-pull.txt3
-rw-r--r--Documentation/git-rebase.txt7
-rw-r--r--Documentation/git-rev-list.txt1
-rw-r--r--Documentation/git-send-email.txt31
-rw-r--r--Documentation/git-verify-commit.txt4
-rw-r--r--Documentation/git-verify-tag.txt4
-rw-r--r--Documentation/git-worktree.txt176
-rw-r--r--Documentation/git.txt26
-rw-r--r--Documentation/gitattributes.txt5
-rw-r--r--Documentation/gitweb.conf.txt2
-rw-r--r--Documentation/i18n.txt33
-rw-r--r--Documentation/merge-config.txt6
-rw-r--r--Documentation/pretty-options.txt5
-rw-r--r--Documentation/technical/api-argv-array.txt3
-rw-r--r--Documentation/technical/api-parse-options.txt19
-rw-r--r--Documentation/technical/pack-protocol.txt6
-rw-r--r--Documentation/technical/racy-git.txt8
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile62
-rw-r--r--advice.c8
-rw-r--r--advice.h1
-rw-r--r--argv-array.c6
-rw-r--r--argv-array.h1
-rw-r--r--builtin.h2
-rw-r--r--builtin/add.c1
-rw-r--r--builtin/apply.c3
-rw-r--r--builtin/blame.c10
-rw-r--r--builtin/checkout.c174
-rw-r--r--builtin/clean.c30
-rw-r--r--builtin/clone.c19
-rw-r--r--builtin/for-each-ref.c1108
-rw-r--r--builtin/fsck.c34
-rw-r--r--builtin/gc.c2
-rw-r--r--builtin/index-pack.c26
-rw-r--r--builtin/log.c12
-rw-r--r--builtin/pack-objects.c25
-rw-r--r--builtin/prune.c99
-rw-r--r--builtin/pull.c882
-rw-r--r--builtin/replace.c6
-rw-r--r--builtin/rev-list.c3
-rw-r--r--builtin/verify-commit.c25
-rw-r--r--builtin/verify-tag.c30
-rw-r--r--builtin/worktree.c332
-rw-r--r--cache.h26
-rw-r--r--command-list.txt1
-rw-r--r--commit.c21
-rw-r--r--commit.h2
-rw-r--r--config.c3
-rw-r--r--config.mak.uname3
-rw-r--r--configure.ac6
-rw-r--r--contrib/completion/git-completion.bash2
-rw-r--r--contrib/completion/git-completion.tcsh2
-rw-r--r--contrib/completion/git-prompt.sh4
-rwxr-xr-xcontrib/examples/git-pull.sh (renamed from git-pull.sh)128
-rw-r--r--contrib/hooks/multimail/CHANGES53
-rw-r--r--contrib/hooks/multimail/README279
-rw-r--r--contrib/hooks/multimail/README.Git4
-rwxr-xr-xcontrib/hooks/multimail/git_multimail.py973
-rwxr-xr-xcontrib/hooks/multimail/migrate-mailhook-config18
-rwxr-xr-xcontrib/hooks/multimail/post-receive.example (renamed from contrib/hooks/multimail/post-receive)27
-rwxr-xr-xcontrib/hooks/pre-auto-gc-battery2
-rwxr-xr-xcontrib/subtree/t/t7900-subtree.sh302
-rw-r--r--diff-lib.c12
-rw-r--r--diff.c7
-rw-r--r--environment.c8
-rw-r--r--ewah/bitmap.c24
-rw-r--r--ewah/ewah_bitmap.c22
-rw-r--r--ewah/ewok.h2
-rw-r--r--fetch-pack.c2
-rw-r--r--fsck.c17
-rwxr-xr-xgit-am.sh44
-rw-r--r--git-compat-util.h8
-rwxr-xr-xgit-cvsimport.perl2
-rw-r--r--git-mergetool--lib.sh1
-rwxr-xr-xgit-p4.py85
-rw-r--r--git-rebase--am.sh2
-rw-r--r--git-rebase--interactive.sh26
-rwxr-xr-xgit-send-email.perl83
-rwxr-xr-xgit-stash.sh2
-rw-r--r--git.c4
-rw-r--r--gpg-interface.c37
-rw-r--r--gpg-interface.h6
-rw-r--r--help.c2
-rw-r--r--http.c4
-rw-r--r--ll-merge.c10
-rw-r--r--lockfile.c31
-rw-r--r--log-tree.c5
-rw-r--r--pack-bitmap.c10
-rw-r--r--pager.c1
-rw-r--r--parse-options-cb.c69
-rw-r--r--parse-options.c17
-rw-r--r--parse-options.h9
-rw-r--r--perl/Git.pm67
-rw-r--r--pkt-line.c60
-rw-r--r--po/bg.po2581
-rw-r--r--po/ca.po2524
-rw-r--r--po/de.po2703
-rw-r--r--po/fr.po2557
-rw-r--r--po/git.pot2465
-rw-r--r--po/ru.po2531
-rw-r--r--po/sv.po2548
-rw-r--r--po/vi.po2597
-rw-r--r--po/zh_CN.po2503
-rw-r--r--read-cache.c3
-rw-r--r--ref-filter.c1106
-rw-r--r--ref-filter.h74
-rw-r--r--refs.c32
-rw-r--r--revision.c4
-rw-r--r--setup.c101
-rw-r--r--sha1_file.c21
-rw-r--r--strbuf.c5
-rw-r--r--strbuf.h2
-rwxr-xr-xt/perf/p5310-pack-bitmaps.sh6
-rwxr-xr-xt/perf/p7300-clean.sh31
-rwxr-xr-xt/t0002-gitfile.sh17
-rwxr-xr-xt/t0040-parse-options.sh47
-rwxr-xr-xt/t0302-credential-store.sh2
-rwxr-xr-xt/t1510-repo-setup.sh24
-rwxr-xr-xt/t2019-checkout-ambiguous-ref.sh26
-rwxr-xr-xt/t2025-checkout-to.sh129
-rwxr-xr-xt/t2025-worktree-add.sh162
-rwxr-xr-xt/t2026-prune-linked-checkouts.sh24
-rwxr-xr-xt/t2203-add-intent.sh23
-rwxr-xr-xt/t3404-rebase-interactive.sh21
-rwxr-xr-xt/t3415-rebase-autosquash.sh21
-rwxr-xr-xt/t3903-stash.sh7
-rwxr-xr-xt/t4011-diff-symlink.sh10
-rwxr-xr-xt/t4014-format-patch.sh8
-rwxr-xr-xt/t4136-apply-check.sh13
-rwxr-xr-xt/t4150-am.sh108
-rwxr-xr-xt/t4151-am-abort.sh81
-rwxr-xr-xt/t5304-prune.sh1
-rwxr-xr-xt/t5310-pack-bitmaps.sh6
-rwxr-xr-xt/t5520-pull.sh20
-rwxr-xr-xt/t5521-pull-options.sh14
-rwxr-xr-xt/t5601-clone.sh7
-rwxr-xr-xt/t6026-merge-attr.sh14
-rwxr-xr-xt/t6301-for-each-ref-errors.sh56
-rwxr-xr-xt/t7030-verify-tag.sh115
-rwxr-xr-xt/t7300-clean.sh140
-rwxr-xr-xt/t7410-submodule-checkout-to.sh4
-rwxr-xr-xt/t7502-commit.sh24
-rwxr-xr-xt/t7510-signed-commit.sh38
-rwxr-xr-xt/t8002-blame.sh62
-rwxr-xr-xt/t9000-addresses.sh27
-rwxr-xr-xt/t9000/test.pl67
-rwxr-xr-xt/t9001-send-email.sh228
-rwxr-xr-xt/t9800-git-p4-basic.sh38
-rwxr-xr-xt/t9818-git-p4-block.sh73
-rw-r--r--t/test-lib.sh99
-rw-r--r--test-parse-options.c5
-rw-r--r--trace.c7
-rw-r--r--trace.h1
-rw-r--r--utf8.h4
-rw-r--r--wrapper.c5
-rw-r--r--wt-status.c9
171 files changed, 19503 insertions, 12949 deletions
diff --git a/.gitignore b/.gitignore
index 422c538..a685ec1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -171,6 +171,7 @@
/git-verify-tag
/git-web--browse
/git-whatchanged
+/git-worktree
/git-write-tree
/git-core-*/?*
/gitweb/GITWEB-BUILD-OPTIONS
diff --git a/Documentation/RelNotes/2.4.4.txt b/Documentation/RelNotes/2.4.4.txt
new file mode 100644
index 0000000..f1ccd00
--- /dev/null
+++ b/Documentation/RelNotes/2.4.4.txt
@@ -0,0 +1,35 @@
+Git v2.4.4 Release Notes
+========================
+
+Fixes since v2.4.3
+------------------
+
+ * l10n updates for German.
+
+ * An earlier leakfix to bitmap testing code was incomplete.
+
+ * "git clean pathspec..." tried to lstat(2) and complain even for
+ paths outside the given pathspec.
+
+ * Communication between the HTTP server and http_backend process can
+ lead to a dead-lock when relaying a large ref negotiation request.
+ Diagnose the situation better, and mitigate it by reading such a
+ request first into core (to a reasonable limit).
+
+ * The clean/smudge interface did not work well when filtering an
+ empty contents (failed and then passed the empty input through).
+ It can be argued that a filter that produces anything but empty for
+ an empty input is nonsense, but if the user wants to do strange
+ things, then why not?
+
+ * Make "git stash something --help" error out, so that users can
+ safely say "git stash drop --help".
+
+ * Clarify that "log --raw" and "log --format=raw" are unrelated
+ concepts.
+
+ * Catch a programmer mistake to feed a pointer not an array to
+ ARRAY_SIZE() macro, by using a couple of GCC extensions.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.5.txt b/Documentation/RelNotes/2.4.5.txt
new file mode 100644
index 0000000..568297c
--- /dev/null
+++ b/Documentation/RelNotes/2.4.5.txt
@@ -0,0 +1,28 @@
+Git v2.4.5 Release Notes
+========================
+
+Fixes since v2.4.4
+------------------
+
+ * The setup code used to die when core.bare and core.worktree are set
+ inconsistently, even for commands that do not need working tree.
+
+ * There was a dead code that used to handle "git pull --tags" and
+ show special-cased error message, which was made irrelevant when
+ the semantics of the option changed back in Git 1.9 days.
+
+ * "color.diff.plain" was a misnomer; give it 'color.diff.context' as
+ a more logical synonym.
+
+ * The configuration reader/writer uses mmap(2) interface to access
+ the files; when we find a directory, it barfed with "Out of memory?".
+
+ * Recent "git prune" traverses young unreachable objects to safekeep
+ old objects in the reachability chain from them, which sometimes
+ showed unnecessary error messages that are alarming.
+
+ * "git rebase -i" fired post-rewrite hook when it shouldn't (namely,
+ when it was told to stop sequencing with 'exec' insn).
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.6.txt b/Documentation/RelNotes/2.4.6.txt
new file mode 100644
index 0000000..b53f353
--- /dev/null
+++ b/Documentation/RelNotes/2.4.6.txt
@@ -0,0 +1,23 @@
+Git v2.4.6 Release Notes
+========================
+
+Fixes since v2.4.5
+------------------
+
+ * "git fetch --depth=<depth>" and "git clone --depth=<depth>" issued
+ a shallow transfer request even to an upload-pack that does not
+ support the capability.
+
+ * "git fsck" used to ignore missing or invalid objects recorded in reflog.
+
+ * The tcsh completion writes a bash scriptlet but that would have
+ failed for users with noclobber set.
+
+ * Recent Mac OS X updates breaks the logic to detect that the machine
+ is on the AC power in the sample pre-auto-gc script.
+
+ * "git format-patch --ignore-if-upstream A..B" did not like to be fed
+ tags as boundary commits.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.7.txt b/Documentation/RelNotes/2.4.7.txt
new file mode 100644
index 0000000..b3ac412
--- /dev/null
+++ b/Documentation/RelNotes/2.4.7.txt
@@ -0,0 +1,53 @@
+Git v2.4.7 Release Notes
+========================
+
+Fixes since v2.4.6
+------------------
+
+ * A minor regression to "git fsck" in v2.2 era was fixed; it
+ complained about a body-less tag object when it lacked a
+ separator empty line after its header to separate it with a
+ non-existent body.
+
+ * We used to ask libCURL to use the most secure authentication method
+ available when talking to an HTTP proxy only when we were told to
+ talk to one via configuration variables. We now ask libCURL to
+ always use the most secure authentication method, because the user
+ can tell libCURL to use an HTTP proxy via an environment variable
+ without using configuration variables.
+
+ * When you say "!<ENTER>" while running say "git log", you'd confuse
+ yourself in the resulting shell, that may look as if you took
+ control back to the original shell you spawned "git log" from but
+ that isn't what is happening. To that new shell, we leaked
+ GIT_PAGER_IN_USE environment variable that was meant as a local
+ communication between the original "Git" and subprocesses that was
+ spawned by it after we launched the pager, which caused many
+ "interesting" things to happen, e.g. "git diff | cat" still paints
+ its output in color by default.
+
+ Stop leaking that environment variable to the pager's half of the
+ fork; we only need it on "Git" side when we spawn the pager.
+
+ * Avoid possible ssize_t to int truncation.
+
+ * "git config" failed to update the configuration file when the
+ underlying filesystem is incapable of renaming a file that is still
+ open.
+
+ * A minor bugfix when pack bitmap is used with "rev-list --count".
+
+ * An ancient test framework enhancement to allow color was not
+ entirely correct; this makes it work even when tput needs to read
+ from the ~/.terminfo under the user's real HOME directory.
+
+ * Fix a small bug in our use of umask() return value.
+
+ * "git rebase" did not exit with failure when format-patch it invoked
+ failed for whatever reason.
+
+ * Disable "have we lost a race with competing repack?" check while
+ receiving a huge object transfer that runs index-pack.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.5.0.txt b/Documentation/RelNotes/2.5.0.txt
index e33b0ac..8704450 100644
--- a/Documentation/RelNotes/2.5.0.txt
+++ b/Documentation/RelNotes/2.5.0.txt
@@ -4,9 +4,6 @@ Git 2.5 Release Notes
Updates since v2.4
------------------
-Ports
-
-
UI, Workflows & Features
* The bash completion script (in contrib/) learned a few options that
@@ -28,6 +25,8 @@ UI, Workflows & Features
chunks from Perforce, instead of making one call to "p4 changes"
that may trigger "too many rows scanned" error from Perforce.
+ * More workaround for Perforce's row number limit in "git p4".
+
* Unlike "$EDITOR" and "$GIT_EDITOR" that can hold the path to the
command and initial options (e.g. "/path/to/emacs -nw"), 'git p4'
did not let the shell interpolate the contents of the environment
@@ -47,11 +46,14 @@ UI, Workflows & Features
rely on symbolic links and make sharing of objects and refs safer
by making the borrowee and borrowers aware of each other.
+ Consider this as still an experimental feature; its UI is still
+ likely to change.
+
* Tweak the sample "store" backend of the credential helper to honor
XDG configuration file locations when specified.
- * A heuristic to help the "git <cmd> <revs> <pathspec>" command line
- convention to catch mistyped paths is to make sure all the non-rev
+ * A heuristic we use to catch mistyped paths on the command line
+ "git <cmd> <revs> <pathspec>" is to make sure that all the non-rev
parameters in the later part of the command line are names of the
files in the working tree, but that means "git grep $str -- \*.c"
must always be disambiguated with "--", because nobody sane will
@@ -64,25 +66,18 @@ UI, Workflows & Features
that are not marked as "not-for-merge"; this allows us to lose an
old style invocation "git merge <msg> HEAD $commits..." in the
implementation of "git pull" script; the old style syntax can now
- be deprecated.
-
- * Help us to find broken test script that splits the body part of the
- test by mistaken use of wrong kind of quotes.
- (merge d93d5d5 jc/test-prereq-validate later to maint).
-
- * Developer support to automatically detect broken &&-chain in the
- test scripts is now turned on by default.
- (merge 92b269f jk/test-chain-lint later to maint).
+ be deprecated (but not removed yet).
* Filter scripts were run with SIGPIPE disabled on the Git side,
expecting that they may not read what Git feeds them to filter.
We however treated a filter that does not read its input fully
- before exiting as an error.
+ before exiting as an error. We no longer do and ignore EPIPE
+ when writing to feed the filter scripts.
This changes semantics, but arguably in a good way. If a filter
- can produce its output without consuming its input using whatever
- magic, we now let it do so, instead of diagnosing it as a
- programming error.
+ can produce its output without fully consuming its input using
+ whatever magic, we now let it do so, instead of diagnosing it
+ as a programming error.
* Instead of dying immediately upon failing to obtain a lock, the
locking (of refs etc) retries after a short while with backoff.
@@ -98,8 +93,8 @@ UI, Workflows & Features
when pushing, but the documentation and help text pretended as if
it did.
- * The Git subcommand completion (in contrib/) listed credential
- helpers among candidates, which is not something the end user would
+ * The Git subcommand completion (in contrib/) no longer lists credential
+ helpers among candidates; they are not something the end user would
invoke interactively.
* The index file can be taught with "update-index --untracked-cache"
@@ -120,6 +115,40 @@ UI, Workflows & Features
behaves as if HEAD:Documentation/RelNotes/2.5.0.txt was given as
input instead.
+ Consider this as still an experimental and incomplete feature:
+
+ - We may want to do the same for in-index objects, e.g.
+ asking for :RelNotes with this option should give
+ :Documentation/RelNotes/2.5.0.txt, too
+
+ - "git cat-file --follow-symlinks blob HEAD:RelNotes"
+ may also be something we want to allow in the future.
+
+ * "git send-email" learned the alias file format used by the sendmail
+ program (in a simplified form; we obviously do not feed pipes).
+
+ * Traditionally, external low-level 3-way merge drivers are expected
+ to produce their results based solely on the contents of the three
+ variants given in temporary files named by %O, %A and %B on their
+ command line. Additionally allow them to look at the final path
+ (given by %P).
+
+ * "git blame" learned blame.showEmail configuration variable.
+
+ * "git apply" cannot diagnose a patch corruption when the breakage is
+ to mark the length of the hunk shorter than it really is on the
+ hunk header line "@@ -l,k +m,n @@"; one special case it could is
+ when the hunk becomes no-op (e.g. k == n == 2 for two-line context
+ patch output), and it learned to do so in this special case.
+
+ * Add the "--allow-unknown-type" option to "cat-file" to allow
+ inspecting loose objects of an experimental or a broken type.
+
+ * Many long-running operations show progress eye-candy, even when
+ they are later backgrounded. Hide the eye-candy when the process
+ is sent to the background instead.
+ (merge a4fb76c lm/squelch-bg-progress later to maint).
+
Performance, Internal Implementation, Development Support etc.
@@ -129,9 +158,11 @@ Performance, Internal Implementation, Development Support etc.
but hopefully will give us one extra level of abstraction in the
end, when completed.
+ * for_each_ref() callback functions were taught to name the objects
+ not with "unsigned char sha1[20]" but with "struct object_id".
+
* Catch a programmer mistake to feed a pointer not an array to
ARRAY_SIZE() macro, by using a couple of GCC extensions.
- (merge 89c855e ep/do-not-feed-a-pointer-to-array-size later to maint).
* Some error messages in "git config" were emitted without calling
the usual error() facility.
@@ -149,33 +180,36 @@ Performance, Internal Implementation, Development Support etc.
* An earlier rewrite to use strbuf_getwholeline() instead of fgets(3)
to read packed-refs file revealed that the former is unacceptably
- inefficient.
+ inefficient. It has been optimized by using getdelim(3) when
+ available.
* The refs API uses ref_lock struct which had its own "int fd", even
though the same file descriptor was in the lock struct it contains.
Clean-up the code to lose this redundant field.
- * Add the "--allow-unknown-type" option to "cat-file" to allow
- inspecting loose objects of an experimental or a broken type.
-
- * Many long-running operations show progress eye-candy, even when
- they are later backgrounded. Hide the eye-candy when the process
- is sent to the background instead.
- (merge 9a9a41d lm/squelch-bg-progress later to maint).
-
* There was a dead code that used to handle "git pull --tags" and
show special-cased error message, which was made irrelevant when
the semantics of the option changed back in Git 1.9 days.
(merge 19d122b pt/pull-tags-error-diag later to maint).
- * for_each_ref() callback functions were taught to name the objects
- not with "unsigned char sha1[20]" but with "struct object_id".
+ * Help us to find broken test script that splits the body part of the
+ test by mistaken use of wrong kind of quotes.
+ (merge d93d5d5 jc/test-prereq-validate later to maint).
+
+ * Developer support to automatically detect broken &&-chain in the
+ test scripts is now turned on by default.
+ (merge 92b269f jk/test-chain-lint later to maint).
* Error reporting mechanism used in "refs" API has been made more
consistent.
* "git pull" has more test coverage now.
+ * "git pull" has become more aware of the options meant for
+ underlying "git fetch" and then learned to use parse-options
+ parser.
+
+ * Clarify in the Makefile a guideline to decide use of USE_NSEC.
Also contains various documentation updates and code clean-ups.
@@ -197,7 +231,7 @@ notes for details).
* Memory usage of "git index-pack" has been trimmed by tens of
per-cent.
- (merge c6458e6 nd/slim-index-pack-memory-usage later to maint).
+ (merge f0e7f11 nd/slim-index-pack-memory-usage later to maint).
* "git rev-list --objects $old --not --all" to see if everything that
is reachable from $old is already connected to the existing refs
@@ -286,12 +320,6 @@ notes for details).
anywhere in the path (e.g. "/home/me/bin/uplink/ssh").
(merge baaf233 bc/connect-plink later to maint).
- * "git stash pop/apply" forgot to make sure that not just the working
- tree is clean but also the index is clean. The latter is important
- as a stash application can conflict and the index will be used for
- conflict resolution.
- (merge ed178ef jk/stash-require-clean-index later to maint).
-
* We have prepended $GIT_EXEC_PATH and the path "git" is installed in
(typically "/usr/bin") to $PATH when invoking subprograms and hooks
for almost eternity, but the original use case the latter tried to
@@ -311,19 +339,6 @@ notes for details).
the order was swapped from the beginning. This belatedly fixes it.
(merge 099d2d8 jc/gitignore-precedence later to maint).
- * After "git add -N", the path appeared in output of "git diff HEAD"
- and "git diff --cached HEAD", leading "git status" to classify it
- as "Changes to be committed". Such a path, however, is not yet to
- be scheduled to be committed. "git diff" showed the change to the
- path as modification, not as a "new file", in the header of its
- output.
-
- Treat such paths as "yet to be added to the index but Git already
- know about them"; "git diff HEAD" and "git diff --cached HEAD"
- should not talk about them, and "git diff" should show them as new
- files yet to be added to the index.
- (merge d95d728 nd/diff-i-t-a later to maint).
-
* There was a commented-out (instead of being marked to expect
failure) test that documented a breakage that was fixed since the
test was written; turn it into a proper test.
@@ -415,6 +430,102 @@ notes for details).
a more logical synonym.
(merge 8dbf3eb jk/color-diff-plain-is-context later to maint).
+ * The setup code used to die when core.bare and core.worktree are set
+ inconsistently, even for commands that do not need working tree.
+ (merge fada767 jk/die-on-bogus-worktree-late later to maint).
+
+ * Recent Mac OS X updates breaks the logic to detect that the machine
+ is on the AC power in the sample pre-auto-gc script.
+ (merge c54c7b3 pa/auto-gc-mac-osx later to maint).
+
+ * "git commit --cleanup=scissors" was not careful enough to protect
+ against getting fooled by a line that looked like scissors.
+ (merge fbfa097 sg/commit-cleanup-scissors later to maint).
+
+ * "Have we lost a race with competing repack?" check was too
+ expensive, especially while receiving a huge object transfer
+ that runs index-pack (e.g. "clone" or "fetch").
+ (merge 0eeb077 jk/index-pack-reduce-recheck later to maint).
+
+ * The tcsh completion writes a bash scriptlet but that would have
+ failed for users with noclobber set.
+ (merge 0b1f688 af/tcsh-completion-noclobber later to maint).
+
+ * "git for-each-ref" reported "missing object" for 0{40} when it
+ encounters a broken ref. The lack of object whose name is 0{40} is
+ not the problem; the ref being broken is.
+ (merge 501cf47 mh/reporting-broken-refs-from-for-each-ref later to maint).
+
+ * Various fixes around "git am" that applies a patch to a history
+ that is not there yet.
+ (merge 6ea3b67 pt/am-abort-fix later to maint).
+
+ * "git fsck" used to ignore missing or invalid objects recorded in reflog.
+ (merge 19bf6c9 mh/fsck-reflog-entries later to maint).
+
+ * "git format-patch --ignore-if-upstream A..B" did not like to be fed
+ tags as boundary commits.
+ (merge 9b7a61d jc/do-not-feed-tags-to-clear-commit-marks later to maint).
+
+ * "git fetch --depth=<depth>" and "git clone --depth=<depth>" issued
+ a shallow transfer request even to an upload-pack that does not
+ support the capability.
+ (merge eb86a50 me/fetch-into-shallow-safety later to maint).
+
+ * "git rebase" did not exit with failure when format-patch it invoked
+ failed for whatever reason.
+ (merge 60d708b cb/rebase-am-exit-code later to maint).
+
+ * Fix a small bug in our use of umask() return value.
+ (merge 3096b2e jk/fix-refresh-utime later to maint).
+
+ * An ancient test framework enhancement to allow color was not
+ entirely correct; this makes it work even when tput needs to read
+ from the ~/.terminfo under the user's real HOME directory.
+ (merge d5c1b7c rh/test-color-avoid-terminfo-in-original-home later to maint).
+
+ * A minor bugfix when pack bitmap is used with "rev-list --count".
+ (merge c8a70d3 jk/rev-list-no-bitmap-while-pruning later to maint).
+
+ * "git config" failed to update the configuration file when the
+ underlying filesystem is incapable of renaming a file that is still
+ open.
+ (merge 7a64592 kb/config-unmap-before-renaming later to maint).
+
+ * Avoid possible ssize_t to int truncation.
+ (merge 6c8afe4 mh/strbuf-read-file-returns-ssize-t later to maint).
+
+ * When you say "!<ENTER>" while running say "git log", you'd confuse
+ yourself in the resulting shell, that may look as if you took
+ control back to the original shell you spawned "git log" from but
+ that isn't what is happening. To that new shell, we leaked
+ GIT_PAGER_IN_USE environment variable that was meant as a local
+ communication between the original "Git" and subprocesses that was
+ spawned by it after we launched the pager, which caused many
+ "interesting" things to happen, e.g. "git diff | cat" still paints
+ its output in color by default.
+
+ Stop leaking that environment variable to the pager's half of the
+ fork; we only need it on "Git" side when we spawn the pager.
+ (merge 124b519 jc/unexport-git-pager-in-use-in-pager later to maint).
+
+ * Abandoning an already applied change in "git rebase -i" with
+ "--continue" left CHERRY_PICK_HEAD and confused later steps.
+ (merge 0e0aff4 js/rebase-i-clean-up-upon-continue-to-skip later to maint).
+
+ * We used to ask libCURL to use the most secure authentication method
+ available when talking to an HTTP proxy only when we were told to
+ talk to one via configuration variables. We now ask libCURL to
+ always use the most secure authentication method, because the user
+ can tell libCURL to use an HTTP proxy via an environment variable
+ without using configuration variables.
+ (merge 5841520 et/http-proxyauth later to maint).
+
+ * A fix to a minor regression to "git fsck" in v2.2 era that started
+ complaining about a body-less tag object when it lacks a separator
+ empty line after its header to separate it with a non-existent body.
+ (merge 84d18c0 jc/fsck-retire-require-eoh later to maint).
+
* Code cleanups and documentation updates.
(merge 0269f96 mm/usage-log-l-can-take-regex later to maint).
(merge 64f2589 nd/t1509-chroot-test later to maint).
@@ -433,3 +544,20 @@ notes for details).
(merge e6a268c sb/glossary-submodule later to maint).
(merge ec48a76 sb/submodule-doc-intro later to maint).
(merge 14f8b9b jk/clone-dissociate later to maint).
+ (merge 055c7e9 sb/pack-protocol-mention-smart-http later to maint).
+ (merge 7c37a5d jk/make-fix-dependencies later to maint).
+ (merge fc0aa39 sg/merge-summary-config later to maint).
+ (merge 329af6c pt/t0302-needs-sanity later to maint).
+ (merge d614f07 fk/doc-format-patch-vn later to maint).
+ (merge 72dbb36 sg/completion-commit-cleanup later to maint).
+ (merge e654eb2 es/utf8-stupid-compiler-workaround later to maint).
+ (merge 34b935c es/osx-header-pollutes-mask-macro later to maint).
+ (merge ab7fade jc/prompt-document-ps1-state-separator later to maint).
+ (merge 25f600e mm/describe-doc later to maint).
+ (merge 83fe167 mm/branch-doc-updates later to maint).
+ (merge 75d2e5a ls/hint-rev-list-count later to maint).
+ (merge edc8f71 cb/subtree-tests-update later to maint).
+ (merge 5330e6e sb/p5310-and-chain later to maint).
+ (merge c4ac525 tb/checkout-doc later to maint).
+ (merge e479c5f jk/pretty-encoding-doc later to maint).
+ (merge 7e837c6 ss/clone-guess-dir-name-simplify later to maint).
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 43bb53c..75c3722 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2161,6 +2161,11 @@ rebase.autoStash::
successful rebase might result in non-trivial conflicts.
Defaults to false.
+rebase.instructionFormat
+ A format string, as specified in linkgit:git-log[1], to be used for
+ the instruction list during an interactive rebase. The format will automatically
+ have the long commit hash prepended to the format.
+
receive.advertiseAtomic::
By default, git-receive-pack will advertise the atomic push
capability to its clients. If you don't want to this capability
diff --git a/Documentation/fmt-merge-msg-config.txt b/Documentation/fmt-merge-msg-config.txt
new file mode 100644
index 0000000..c73cfa9
--- /dev/null
+++ b/Documentation/fmt-merge-msg-config.txt
@@ -0,0 +1,10 @@
+merge.branchdesc::
+ In addition to branch names, populate the log message with
+ the branch description text associated with them. Defaults
+ to false.
+
+merge.log::
+ In addition to branch names, populate the log message with at
+ most the specified number of one-line descriptions from the
+ actual commits that are being merged. Defaults to false, and
+ true is a synonym for 20.
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 9f23a86..e6e947c 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -76,6 +76,8 @@ include::blame-options.txt[]
-e::
--show-email::
Show the author email instead of author name (Default: off).
+ This can also be controlled via the `blame.showEmail` config
+ option.
-w::
Ignore whitespace when comparing the parent's version and
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 359619b..a67138a 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -81,7 +81,7 @@ OPTIONS
`--track` or `--set-upstream`.
-D::
- Delete a branch irrespective of its merged status.
+ Shortcut for `--delete --force`.
-l::
--create-reflog::
@@ -95,13 +95,17 @@ OPTIONS
--force::
Reset <branchname> to <startpoint> if <branchname> exists
already. Without `-f` 'git branch' refuses to change an existing branch.
+ In combination with `-d` (or `--delete`), allow deleting the
+ branch irrespective of its merged status. In combination with
+ `-m` (or `--move`), allow renaming the branch even if the new
+ branch name already exists.
-m::
--move::
Move/rename a branch and the corresponding reflog.
-M::
- Move/rename a branch even if the new branch name already exists.
+ Shortcut for `--move --force`.
--color[=<when>]::
Color branches to highlight current, local, and
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index d263a56..63b739c 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -3,7 +3,7 @@ git-checkout(1)
NAME
----
-git-checkout - Checkout a branch or paths to the working tree
+git-checkout - Switch branches or restore working tree files
SYNOPSIS
--------
@@ -89,6 +89,10 @@ Omitting <branch> detaches HEAD at the tip of the current branch.
(i.e. commit, tag or tree) to update the index for the given
paths before updating the working tree.
+
+'git checkout' with <paths> or `--patch` is used to restore modified or
+deleted paths to their original contents from the index or replace paths
+with the contents from a named <tree-ish> (most often a commit-ish).
++
The index may contain unmerged entries because of a previous failed merge.
By default, if you try to check out such an entry from the index, the
checkout operation will fail and nothing will be checked out.
@@ -225,13 +229,6 @@ This means that you can use `git checkout -p` to selectively discard
edits from your current working tree. See the ``Interactive Mode''
section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
---to=<path>::
- Check out a branch in a separate working directory at
- `<path>`. A new working directory is linked to the current
- repository, sharing everything except working directory
- specific files such as HEAD, index... See "MULTIPLE WORKING
- TREES" section for more information.
-
--ignore-other-worktrees::
`git checkout` refuses when the wanted ref is already checked
out by another worktree. This option makes it check the ref
@@ -401,71 +398,6 @@ $ git reflog -2 HEAD # or
$ git log -g -2 HEAD
------------
-MULTIPLE WORKING TREES
-----------------------
-
-A git repository can support multiple working trees, allowing you to check
-out more than one branch at a time. With `git checkout --to` a new working
-tree is associated with the repository. This new working tree is called a
-"linked working tree" as opposed to the "main working tree" prepared by "git
-init" or "git clone". A repository has one main working tree (if it's not a
-bare repository) and zero or more linked working trees.
-
-Each linked working tree has a private sub-directory in the repository's
-$GIT_DIR/worktrees directory. The private sub-directory's name is usually
-the base name of the linked working tree's path, possibly appended with a
-number to make it unique. For example, when `$GIT_DIR=/path/main/.git` the
-command `git checkout --to /path/other/test-next next` creates the linked
-working tree in `/path/other/test-next` and also creates a
-`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
-if `test-next` is already taken).
-
-Within a linked working tree, $GIT_DIR is set to point to this private
-directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
-$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
-(e.g. `/path/main/.git`). These settings are made in a `.git` file located at
-the top directory of the linked working tree.
-
-Path resolution via `git rev-parse --git-path` uses either
-$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
-linked working tree `git rev-parse --git-path HEAD` returns
-`/path/main/.git/worktrees/test-next/HEAD` (not
-`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
-rev-parse --git-path refs/heads/master` uses
-$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
-since refs are shared across all working trees.
-
-See linkgit:gitrepository-layout[5] for more information. The rule of
-thumb is do not make any assumption about whether a path belongs to
-$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
-inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
-
-When you are done with a linked working tree you can simply delete it.
-The working tree's entry in the repository's $GIT_DIR/worktrees
-directory will eventually be removed automatically (see
-`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
-`git prune --worktrees` in the main or any linked working tree to
-clean up any stale entries in $GIT_DIR/worktrees.
-
-If you move a linked working directory to another file system, or
-within a file system that does not support hard links, you need to run
-at least one git command inside the linked working directory
-(e.g. `git status`) in order to update its entry in $GIT_DIR/worktrees
-so that it does not get automatically removed.
-
-To prevent a $GIT_DIR/worktrees entry from from being pruned (which
-can be useful in some situations, such as when the
-entry's working tree is stored on a portable device), add a file named
-'locked' to the entry's directory. The file contains the reason in
-plain text. For example, if a linked working tree's `.git` file points
-to `/path/main/.git/worktrees/test-next` then a file named
-`/path/main/.git/worktrees/test-next/locked` will prevent the
-`test-next` entry from being pruned. See
-linkgit:gitrepository-layout[5] for details.
-
-Multiple checkout support for submodules is incomplete. It is NOT
-recommended to make multiple checkouts of a superproject.
-
EXAMPLES
--------
diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index d20ca40..e045fc7 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -3,7 +3,7 @@ git-describe(1)
NAME
----
-git-describe - Show the most recent tag that is reachable from a commit
+git-describe - Describe a commit using the most recent tag reachable from it
SYNOPSIS
diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt
index bb1232a..55a9a4b 100644
--- a/Documentation/git-fmt-merge-msg.txt
+++ b/Documentation/git-fmt-merge-msg.txt
@@ -51,17 +51,7 @@ OPTIONS
CONFIGURATION
-------------
-
-merge.branchdesc::
- In addition to branch names, populate the log message with
- the branch description text associated with them. Defaults
- to false.
-
-merge.log::
- In addition to branch names, populate the log message with at
- most the specified number of one-line descriptions from the
- actual commits that are being merged. Defaults to false, and
- true is a synonym for 20.
+include::fmt-merge-msg-config.txt[]
merge.summary::
Synonym to `merge.log`; this is deprecated and will be removed in
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index bb3ea93..0dac4e9 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -170,7 +170,7 @@ will want to ensure that threading is disabled for `git send-email`.
-v <n>::
--reroll-count=<n>::
Mark the series as the <n>-th iteration of the topic. The
- output filenames have `v<n>` pretended to them, and the
+ output filenames have `v<n>` prepended to them, and the
subject prefix ("PATCH" by default, but configurable via the
`--subject-prefix` option) has ` v<n>` appended to it. E.g.
`--reroll-count=4` may produce `v4-0001-add-makefile.patch`
diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt
index 1cf3bed..7a493c8 100644
--- a/Documentation/git-prune.txt
+++ b/Documentation/git-prune.txt
@@ -48,9 +48,6 @@ OPTIONS
--expire <time>::
Only expire loose objects older than <time>.
---worktrees::
- Prune dead working tree information in $GIT_DIR/worktrees.
-
<head>...::
In addition to objects
reachable from any of our references, keep objects
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 712ab4b..93c72a2 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -74,9 +74,6 @@ pulling or stash them away with linkgit:git-stash[1].
OPTIONS
-------
-Options meant for 'git pull' itself and the underlying 'git merge'
-must be given before the options meant for 'git fetch'.
-
-q::
--quiet::
This is passed to both underlying git-fetch to squelch reporting of
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 1d01baa..7dc613c 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -213,6 +213,9 @@ rebase.autoSquash::
rebase.autoStash::
If set to true enable '--autostash' option by default.
+rebase.instructionFormat::
+ Custom commit list format to use during an '--interactive' rebase.
+
OPTIONS
-------
--onto <newbase>::
@@ -359,6 +362,10 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.
Make a list of the commits which are about to be rebased. Let the
user edit that list before rebasing. This mode can also be used to
split commits (see SPLITTING COMMITS below).
++
+The commit list format can be changed by setting the configuration option
+rebase.instructionFormat. A customized instruction format will automatically
+have the long commit hash prepended to the format.
-p::
--preserve-merges::
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index b10ea60..7b49c85 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -56,6 +56,7 @@ SYNOPSIS
[ --reverse ]
[ --walk-reflogs ]
[ --no-walk ] [ --do-walk ]
+ [ --count ]
[ --use-bitmap-index ]
<commit>... [ \-- <paths>... ]
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 8045546..f14705e 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -49,17 +49,17 @@ Composing
of 'sendemail.annotate'. See the CONFIGURATION section for
'sendemail.multiEdit'.
---bcc=<address>::
+--bcc=<address>,...::
Specify a "Bcc:" value for each email. Default is the value of
'sendemail.bcc'.
+
-The --bcc option must be repeated for each user you want on the bcc list.
+This option may be specified multiple times.
---cc=<address>::
+--cc=<address>,...::
Specify a starting "Cc:" value for each email.
Default is the value of 'sendemail.cc'.
+
-The --cc option must be repeated for each user you want on the cc list.
+This option may be specified multiple times.
--compose::
Invoke a text editor (see GIT_EDITOR in linkgit:git-var[1])
@@ -110,13 +110,13 @@ is not set, this will be prompted for.
Only necessary if --compose is also set. If --compose
is not set, this will be prompted for.
---to=<address>::
+--to=<address>,...::
Specify the primary recipient of the emails generated. Generally, this
will be the upstream maintainer of the project involved. Default is the
value of the 'sendemail.to' configuration value; if that is unspecified,
and --to-cmd is not specified, this will be prompted for.
+
-The --to option must be repeated for each user you want on the to list.
+This option may be specified multiple times.
--8bit-encoding=<encoding>::
When encountering a non-ASCII message or subject that does not
@@ -383,7 +383,24 @@ sendemail.aliasesFile::
sendemail.aliasFileType::
Format of the file(s) specified in sendemail.aliasesFile. Must be
- one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus'.
+ one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus', or 'sendmail'.
++
+What an alias file in each format looks like can be found in
+the documentation of the email program of the same name. The
+differences and limitations from the standard formats are
+described below:
++
+--
+sendmail;;
+* Quoted aliases and quoted addresses are not supported: lines that
+ contain a `"` symbol are ignored.
+* Redirection to a file (`/path/name`) or pipe (`|command`) is not
+ supported.
+* File inclusion (`:include: /path/name`) is not supported.
+* Warnings are printed on the standard error output for any
+ explicitly unsupported constructs, and any other lines that are not
+ recognized by the parser.
+--
sendemail.multiEdit::
If true (default), a single editor instance will be spawned to edit
diff --git a/Documentation/git-verify-commit.txt b/Documentation/git-verify-commit.txt
index 9413e28..ecf4da1 100644
--- a/Documentation/git-verify-commit.txt
+++ b/Documentation/git-verify-commit.txt
@@ -16,6 +16,10 @@ Validates the gpg signature created by 'git commit -S'.
OPTIONS
-------
+--raw::
+ Print the raw gpg status output to standard error instead of the normal
+ human-readable output.
+
-v::
--verbose::
Print the contents of the commit object before validating it.
diff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.txt
index f88ba96..d590edc 100644
--- a/Documentation/git-verify-tag.txt
+++ b/Documentation/git-verify-tag.txt
@@ -16,6 +16,10 @@ Validates the gpg signature created by 'git tag'.
OPTIONS
-------
+--raw::
+ Print the raw gpg status output to standard error instead of the normal
+ human-readable output.
+
-v::
--verbose::
Print the contents of the tag object before validating it.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
new file mode 100644
index 0000000..3387e2f
--- /dev/null
+++ b/Documentation/git-worktree.txt
@@ -0,0 +1,176 @@
+git-worktree(1)
+===============
+
+NAME
+----
+git-worktree - Manage multiple worktrees
+
+
+SYNOPSIS
+--------
+[verse]
+'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]
+'git worktree prune' [-n] [-v] [--expire <expire>]
+
+DESCRIPTION
+-----------
+
+Manage multiple worktrees attached to the same repository.
+
+A git repository can support multiple working trees, allowing you to check
+out more than one branch at a time. With `git worktree add` a new working
+tree is associated with the repository. This new working tree is called a
+"linked working tree" as opposed to the "main working tree" prepared by "git
+init" or "git clone". A repository has one main working tree (if it's not a
+bare repository) and zero or more linked working trees.
+
+When you are done with a linked working tree you can simply delete it.
+The working tree's administrative files in the repository (see
+"DETAILS" below) will eventually be removed automatically (see
+`gc.pruneworktreesexpire` in linkgit::git-config[1]), or you can run
+`git worktree prune` in the main or any linked working tree to
+clean up any stale administrative files.
+
+If you move a linked working directory to another file system, or
+within a file system that does not support hard links, you need to run
+at least one git command inside the linked working directory
+(e.g. `git status`) in order to update its administrative files in the
+repository so that they do not get automatically pruned.
+
+If a linked working tree is stored on a portable device or network share
+which is not always mounted, you can prevent its administrative files from
+being pruned by creating a file named 'lock' alongside the other
+administrative files, optionally containing a plain text reason that
+pruning should be suppressed. See section "DETAILS" for more information.
+
+COMMANDS
+--------
+add <path> [<branch>]::
+
+Create `<path>` and checkout `<branch>` into it. The new working directory
+is linked to the current repository, sharing everything except working
+directory specific files such as HEAD, index, etc.
++
+If `<branch>` is omitted and neither `-b` nor `-B` is used, then, as a
+convenience, a new branch based at HEAD is created automatically, as if
+`-b $(basename <path>)` was specified.
+
+prune::
+
+Prune working tree information in $GIT_DIR/worktrees.
+
+OPTIONS
+-------
+
+-f::
+--force::
+ By default, `add` refuses to create a new worktree when `<branch>`
+ is already checked out by another worktree. This option overrides
+ that safeguard.
+
+-b <new-branch>::
+-B <new-branch>::
+ With `add`, create a new branch named `<new-branch>` starting at
+ `<branch>`, and check out `<new-branch>` into the new worktree.
+ If `<branch>` is omitted, it defaults to HEAD.
+ By default, `-b` refuses to create a new branch if it already
+ exists. `-B` overrides this safeguard, resetting `<new-branch>` to
+ `<branch>`.
+
+--detach::
+ With `add`, detach HEAD in the new worktree. See "DETACHED HEAD" in
+ linkgit:git-checkout[1].
+
+-n::
+--dry-run::
+ With `prune`, do not remove anything; just report what it would
+ remove.
+
+-v::
+--verbose::
+ With `prune`, report all removals.
+
+--expire <time>::
+ With `prune`, only expire unused worktrees older than <time>.
+
+DETAILS
+-------
+Each linked working tree has a private sub-directory in the repository's
+$GIT_DIR/worktrees directory. The private sub-directory's name is usually
+the base name of the linked working tree's path, possibly appended with a
+number to make it unique. For example, when `$GIT_DIR=/path/main/.git` the
+command `git worktree add /path/other/test-next next` creates the linked
+working tree in `/path/other/test-next` and also creates a
+`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
+if `test-next` is already taken).
+
+Within a linked working tree, $GIT_DIR is set to point to this private
+directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
+$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR
+(e.g. `/path/main/.git`). These settings are made in a `.git` file located at
+the top directory of the linked working tree.
+
+Path resolution via `git rev-parse --git-path` uses either
+$GIT_DIR or $GIT_COMMON_DIR depending on the path. For example, in the
+linked working tree `git rev-parse --git-path HEAD` returns
+`/path/main/.git/worktrees/test-next/HEAD` (not
+`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
+rev-parse --git-path refs/heads/master` uses
+$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
+since refs are shared across all working trees.
+
+See linkgit:gitrepository-layout[5] for more information. The rule of
+thumb is do not make any assumption about whether a path belongs to
+$GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
+inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
+
+To prevent a $GIT_DIR/worktrees entry from from being pruned (which
+can be useful in some situations, such as when the
+entry's working tree is stored on a portable device), add a file named
+'locked' to the entry's directory. The file contains the reason in
+plain text. For example, if a linked working tree's `.git` file points
+to `/path/main/.git/worktrees/test-next` then a file named
+`/path/main/.git/worktrees/test-next/locked` will prevent the
+`test-next` entry from being pruned. See
+linkgit:gitrepository-layout[5] for details.
+
+EXAMPLES
+--------
+You are in the middle of a refactoring session and your boss comes in and
+demands that you fix something immediately. You might typically use
+linkgit:git-stash[1] to store your changes away temporarily, however, your
+worktree is in such a state of disarray (with new, moved, and removed files,
+and other bits and pieces strewn around) that you don't want to risk
+disturbing any of it. Instead, you create a temporary linked worktree to
+make the emergency fix, remove it when done, and then resume your earlier
+refactoring session.
+
+------------
+$ git worktree add -b emergency-fix ../temp master
+$ pushd ../temp
+# ... hack hack hack ...
+$ git commit -a -m 'emergency fix for boss'
+$ popd
+$ rm -rf ../temp
+$ git worktree prune
+------------
+
+BUGS
+----
+Multiple checkout in general is still experimental, and the support
+for submodules is incomplete. It is NOT recommended to make multiple
+checkouts of a superproject.
+
+git-worktree could provide more automation for tasks currently
+performed manually, such as:
+
+- `remove` to remove a linked worktree and its administrative files (and
+ warn if the worktree is dirty)
+- `mv` to move or rename a worktree and update its administrative files
+- `list` to list linked worktrees
+- `lock` to prevent automatic pruning of administrative files (for instance,
+ for a worktree on a portable device)
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 45b64a7..f87d332 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,18 @@ unreleased) version of Git, that is available from the 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v2.4.3/git.html[documentation for release 2.4.3]
+* link:v2.5.0/git.html[documentation for release 2.5]
* release notes for
+ link:RelNotes/2.5.0.txt[2.5],
+
+* link:v2.4.7/git.html[documentation for release 2.4.7]
+
+* release notes for
+ link:RelNotes/2.4.7.txt[2.4.7],
+ link:RelNotes/2.4.6.txt[2.4.6],
+ link:RelNotes/2.4.5.txt[2.4.5],
+ link:RelNotes/2.4.4.txt[2.4.4],
link:RelNotes/2.4.3.txt[2.4.3],
link:RelNotes/2.4.2.txt[2.4.2],
link:RelNotes/2.4.1.txt[2.4.1],
@@ -842,7 +851,7 @@ Git so take care if using Cogito etc.
normally in $GIT_DIR will be taken from this path
instead. Worktree-specific files such as HEAD or index are
taken from $GIT_DIR. See linkgit:gitrepository-layout[5] and
- the section 'MULTIPLE CHECKOUT MODE' in linkgit:checkout[1]
+ linkgit:git-worktree[1] for
details. This variable has lower precedence than other path
variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY...
@@ -1000,9 +1009,20 @@ Unsetting the variable, or setting it to empty, "0" or
Enables trace messages for all packets coming in or out of a
given program. This can help with debugging object negotiation
or other protocol issues. Tracing is turned off at a packet
- starting with "PACK".
+ starting with "PACK" (but see 'GIT_TRACE_PACKFILE' below).
See 'GIT_TRACE' for available trace output options.
+'GIT_TRACE_PACKFILE'::
+ Enables tracing of packfiles sent or received by a
+ given program. Unlike other trace output, this trace is
+ verbatim: no headers, and no quoting of binary data. You almost
+ certainly want to direct into a file (e.g.,
+ `GIT_TRACE_PACKFILE=/tmp/my.pack`) rather than displaying it on
+ the terminal or mixing it with other trace output.
++
+Note that this is currently only implemented for the client side
+of clones and fetches.
+
'GIT_TRACE_PERFORMANCE'::
Enables performance related trace messages, e.g. total execution
time of each Git command.
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 70899b3..81fe586 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -774,7 +774,7 @@ To define a custom merge driver `filfre`, add a section to your
----------------------------------------------------------------
[merge "filfre"]
name = feel-free merge driver
- driver = filfre %O %A %B
+ driver = filfre %O %A %B %L %P
recursive = binary
----------------------------------------------------------------
@@ -800,6 +800,9 @@ merge between common ancestors, when there are more than one.
When left unspecified, the driver itself is used for both
internal merge and the final merge.
+The merge driver can learn the pathname in which the merged result
+will be stored via placeholder `%P`.
+
`conflict-marker-size`
^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt
index a096e7d..8a42270 100644
--- a/Documentation/gitweb.conf.txt
+++ b/Documentation/gitweb.conf.txt
@@ -487,7 +487,7 @@ By default it is set to (), i.e. an empty list. This means that gitweb
would not try to create project URL (to fetch) from project name.
$projects_list_group_categories::
- Whether to enables the grouping of projects by category on the project
+ Whether to enable the grouping of projects by category on the project
list page. The category of a project is determined by the
`$GIT_DIR/category` file or the `gitweb.category` variable in each
repository's configuration. Disabled by default (set to 0).
diff --git a/Documentation/i18n.txt b/Documentation/i18n.txt
index e9a1d5d..2dd79db 100644
--- a/Documentation/i18n.txt
+++ b/Documentation/i18n.txt
@@ -1,18 +1,31 @@
-At the core level, Git is character encoding agnostic.
-
- - The pathnames recorded in the index and in the tree objects
- are treated as uninterpreted sequences of non-NUL bytes.
- What readdir(2) returns are what are recorded and compared
- with the data Git keeps track of, which in turn are expected
- to be what lstat(2) and creat(2) accepts. There is no such
- thing as pathname encoding translation.
+Git is to some extent character encoding agnostic.
- The contents of the blob objects are uninterpreted sequences
of bytes. There is no encoding translation at the core
level.
- - The commit log messages are uninterpreted sequences of non-NUL
- bytes.
+ - Path names are encoded in UTF-8 normalization form C. This
+ applies to tree objects, the index file, ref names, as well as
+ path names in command line arguments, environment variables
+ and config files (`.git/config` (see linkgit:git-config[1]),
+ linkgit:gitignore[5], linkgit:gitattributes[5] and
+ linkgit:gitmodules[5]).
++
+Note that Git at the core level treats path names simply as
+sequences of non-NUL bytes, there are no path name encoding
+conversions (except on Mac and Windows). Therefore, using
+non-ASCII path names will mostly work even on platforms and file
+systems that use legacy extended ASCII encodings. However,
+repositories created on such systems will not work properly on
+UTF-8-based systems (e.g. Linux, Mac, Windows) and vice versa.
+Additionally, many Git-based tools simply assume path names to
+be UTF-8 and will fail to display other encodings correctly.
+
+ - Commit log messages are typically encoded in UTF-8, but other
+ extended ASCII encodings are also supported. This includes
+ ISO-8859-x, CP125x and many others, but _not_ UTF-16/32,
+ EBCDIC and CJK multi-byte encodings (GBK, Shift-JIS, Big5,
+ EUC-x, CP9xx etc.).
Although we encourage that the commit log messages are encoded
in UTF-8, both the core and Git Porcelain are designed not to
diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt
index 8a0e52f..002ca58 100644
--- a/Documentation/merge-config.txt
+++ b/Documentation/merge-config.txt
@@ -26,11 +26,7 @@ merge.ff::
allowed (equivalent to giving the `--ff-only` option from the
command line).
-merge.log::
- In addition to branch names, populate the log message with at
- most the specified number of one-line descriptions from the
- actual commits that are being merged. Defaults to false, and
- true is a synonym for 20.
+include::fmt-merge-msg-config.txt[]
merge.renameLimit::
The number of files to consider when performing rename detection
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 74aa01a..642af6e 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -37,7 +37,10 @@ people using 80-column terminals.
in their encoding header; this option can be used to tell the
command to re-code the commit log message in the encoding
preferred by the user. For non plumbing commands this
- defaults to UTF-8.
+ defaults to UTF-8. Note that if an object claims to be encoded
+ in `X` and we are outputting in `X`, we will output the object
+ verbatim; this means that invalid sequences in the original
+ commit may be copied to the output.
--notes[=<ref>]::
Show the notes (see linkgit:git-notes[1]) that annotate the
diff --git a/Documentation/technical/api-argv-array.txt b/Documentation/technical/api-argv-array.txt
index 1a79781..8076172 100644
--- a/Documentation/technical/api-argv-array.txt
+++ b/Documentation/technical/api-argv-array.txt
@@ -46,6 +46,9 @@ Functions
Format a string and push it onto the end of the array. This is a
convenience wrapper combining `strbuf_addf` and `argv_array_push`.
+`argv_array_pushv`::
+ Push a null-terminated array of strings onto the end of the array.
+
`argv_array_pop`::
Remove the final element from the array. If there are no
elements in the array, do nothing.
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 1f2db31..5f0757d 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -168,6 +168,12 @@ There are some macros to easily define options:
Introduce an option with integer argument.
The integer is put into `int_var`.
+`OPT_MAGNITUDE(short, long, &unsigned_long_var, description)`::
+ Introduce an option with a size argument. The argument must be a
+ non-negative integer and may include a suffix of 'k', 'm' or 'g' to
+ scale the provided value by 1024, 1024^2 or 1024^3 respectively.
+ The scaled value is put into `unsigned_long_var`.
+
`OPT_DATE(short, long, &int_var, description)`::
Introduce an option with date argument, see `approxidate()`.
The timestamp is put into `int_var`.
@@ -212,6 +218,19 @@ There are some macros to easily define options:
Use it to hide deprecated options that are still to be recognized
and ignored silently.
+`OPT_PASSTHRU(short, long, &char_var, arg_str, description, flags)`::
+ Introduce an option that will be reconstructed into a char* string,
+ which must be initialized to NULL. This is useful when you need to
+ pass the command-line option to another command. Any previous value
+ will be overwritten, so this should only be used for options where
+ the last one specified on the command line wins.
+
+`OPT_PASSTHRU_ARGV(short, long, &argv_array_var, arg_str, description, flags)`::
+ Introduce an option where all instances of it on the command-line will
+ be reconstructed into an argv_array. This is useful when you need to
+ pass the command-line option, which can be specified multiple times,
+ to another command.
+
The last element of the array must be `OPT_END()`.
diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt
index fc09c63..4064fc7 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -1,11 +1,11 @@
Packfile transfer protocols
===========================
-Git supports transferring data in packfiles over the ssh://, git:// and
+Git supports transferring data in packfiles over the ssh://, git://, http:// and
file:// transports. There exist two sets of protocols, one for pushing
data from a client to a server and another for fetching data from a
-server to a client. All three transports (ssh, git, file) use the same
-protocol to transfer data.
+server to a client. The three transports (ssh, git, file) use the same
+protocol to transfer data. http is documented in http-protocol.txt.
The processes invoked in the canonical Git implementation are 'upload-pack'
on the server side and 'fetch-pack' on the client side for fetching data;
diff --git a/Documentation/technical/racy-git.txt b/Documentation/technical/racy-git.txt
index 242a044..4a8be4d 100644
--- a/Documentation/technical/racy-git.txt
+++ b/Documentation/technical/racy-git.txt
@@ -41,13 +41,17 @@ With a `USE_STDEV` compile-time option, `st_dev` is also
compared, but this is not enabled by default because this member
is not stable on network filesystems. With `USE_NSEC`
compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
-members are also compared, but this is not enabled by default
+members are also compared. On Linux, this is not enabled by default
because in-core timestamps can have finer granularity than
on-disk timestamps, resulting in meaningless changes when an
inode is evicted from the inode cache. See commit 8ce13b0
of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
([PATCH] Sync in core time granularity with filesystems,
-2005-01-04).
+2005-01-04). This patch is included in kernel 2.6.11 and newer, but
+only fixes the issue for file systems with exactly 1 ns or 1 s
+resolution. Other file systems are still broken in current Linux
+kernels (e.g. CEPH, CIFS, NTFS, UDF), see
+https://lkml.org/lkml/2015/6/9/714
Racy Git
--------
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index bfb715d..cd96820 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.4.0.GIT
+DEF_VER=v2.5.0
LF='
'
diff --git a/Makefile b/Makefile
index 54ec511..7efedbe 100644
--- a/Makefile
+++ b/Makefile
@@ -217,10 +217,11 @@ all::
# as the compiler can crash (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
#
# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
-# randomly break unless your underlying filesystem supports those sub-second
-# times (my ext3 doesn't).
+# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On
+# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times
+# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git
+# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See
+# Documentation/technical/racy-git.txt for details.
#
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
# "st_ctim"
@@ -474,7 +475,6 @@ SCRIPT_SH += git-merge-octopus.sh
SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
SCRIPT_SH += git-mergetool.sh
-SCRIPT_SH += git-pull.sh
SCRIPT_SH += git-quiltimport.sh
SCRIPT_SH += git-rebase.sh
SCRIPT_SH += git-remote-testgit.sh
@@ -762,6 +762,7 @@ LIB_OBJS += reachable.o
LIB_OBJS += read-cache.o
LIB_OBJS += reflog-walk.o
LIB_OBJS += refs.o
+LIB_OBJS += ref-filter.o
LIB_OBJS += remote.o
LIB_OBJS += replace_object.o
LIB_OBJS += rerere.o
@@ -877,6 +878,7 @@ BUILTIN_OBJS += builtin/pack-refs.o
BUILTIN_OBJS += builtin/patch-id.o
BUILTIN_OBJS += builtin/prune-packed.o
BUILTIN_OBJS += builtin/prune.o
+BUILTIN_OBJS += builtin/pull.o
BUILTIN_OBJS += builtin/push.o
BUILTIN_OBJS += builtin/read-tree.o
BUILTIN_OBJS += builtin/receive-pack.o
@@ -909,6 +911,7 @@ BUILTIN_OBJS += builtin/var.o
BUILTIN_OBJS += builtin/verify-commit.o
BUILTIN_OBJS += builtin/verify-pack.o
BUILTIN_OBJS += builtin/verify-tag.o
+BUILTIN_OBJS += builtin/worktree.o
BUILTIN_OBJS += builtin/write-tree.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
@@ -1747,7 +1750,7 @@ $(SCRIPT_PERL_GEN): perl/perl.mak
perl/perl.mak: perl/PM.stamp
perl/PM.stamp: FORCE
- $(QUIET_GEN)$(FIND) perl -type f -name '*.pm' | sort >$@+ && \
+ @$(FIND) perl -type f -name '*.pm' | sort >$@+ && \
{ cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@; } && \
$(RM) $@+
@@ -1784,7 +1787,7 @@ GIT-PERL-DEFINES: FORCE
gitweb:
$(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
-git-instaweb: git-instaweb.sh gitweb GIT-SCRIPT-DEFINES
+git-instaweb: git-instaweb.sh GIT-SCRIPT-DEFINES
$(QUIET_GEN)$(cmd_munge_script) && \
chmod +x $@+ && \
mv $@+ $@
@@ -2103,46 +2106,47 @@ GIT-LDFLAGS: FORCE
# that runs GIT-BUILD-OPTIONS, and then again to protect it
# and the first level quoting from the shell that runs "echo".
GIT-BUILD-OPTIONS: FORCE
- @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
- @echo PERL_PATH=\''$(subst ','\'',$(PERL_PATH_SQ))'\' >>$@
- @echo DIFF=\''$(subst ','\'',$(subst ','\'',$(DIFF)))'\' >>$@
- @echo PYTHON_PATH=\''$(subst ','\'',$(PYTHON_PATH_SQ))'\' >>$@
- @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
- @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
- @echo NO_EXPAT=\''$(subst ','\'',$(subst ','\'',$(NO_EXPAT)))'\' >>$@
- @echo USE_LIBPCRE=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE)))'\' >>$@
- @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
- @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@
- @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@
+ @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@+
+ @echo PERL_PATH=\''$(subst ','\'',$(PERL_PATH_SQ))'\' >>$@+
+ @echo DIFF=\''$(subst ','\'',$(subst ','\'',$(DIFF)))'\' >>$@+
+ @echo PYTHON_PATH=\''$(subst ','\'',$(PYTHON_PATH_SQ))'\' >>$@+
+ @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@+
+ @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@+
+ @echo NO_EXPAT=\''$(subst ','\'',$(subst ','\'',$(NO_EXPAT)))'\' >>$@+
+ @echo USE_LIBPCRE=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE)))'\' >>$@+
+ @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+
+ @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+
+ @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+
ifdef TEST_OUTPUT_DIRECTORY
- @echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@
+ @echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+
endif
ifdef GIT_TEST_OPTS
- @echo GIT_TEST_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_OPTS)))'\' >>$@
+ @echo GIT_TEST_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_OPTS)))'\' >>$@+
endif
ifdef GIT_TEST_CMP
- @echo GIT_TEST_CMP=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_CMP)))'\' >>$@
+ @echo GIT_TEST_CMP=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_CMP)))'\' >>$@+
endif
ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
- @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@
+ @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@+
endif
- @echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@
- @echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@
+ @echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@+
+ @echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@+
ifdef GIT_PERF_REPEAT_COUNT
- @echo GIT_PERF_REPEAT_COUNT=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPEAT_COUNT)))'\' >>$@
+ @echo GIT_PERF_REPEAT_COUNT=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPEAT_COUNT)))'\' >>$@+
endif
ifdef GIT_PERF_REPO
- @echo GIT_PERF_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPO)))'\' >>$@
+ @echo GIT_PERF_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPO)))'\' >>$@+
endif
ifdef GIT_PERF_LARGE_REPO
- @echo GIT_PERF_LARGE_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_LARGE_REPO)))'\' >>$@
+ @echo GIT_PERF_LARGE_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_LARGE_REPO)))'\' >>$@+
endif
ifdef GIT_PERF_MAKE_OPTS
- @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@
+ @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@+
endif
ifdef TEST_GIT_INDEX_VERSION
- @echo TEST_GIT_INDEX_VERSION=\''$(subst ','\'',$(subst ','\'',$(TEST_GIT_INDEX_VERSION)))'\' >>$@
+ @echo TEST_GIT_INDEX_VERSION=\''$(subst ','\'',$(subst ','\'',$(TEST_GIT_INDEX_VERSION)))'\' >>$@+
endif
+ @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
### Detect Python interpreter path changes
ifndef NO_PYTHON
diff --git a/advice.c b/advice.c
index 575bec2..4965686 100644
--- a/advice.c
+++ b/advice.c
@@ -96,6 +96,14 @@ void NORETURN die_resolve_conflict(const char *me)
die("Exiting because of an unresolved conflict.");
}
+void NORETURN die_conclude_merge(void)
+{
+ error(_("You have not concluded your merge (MERGE_HEAD exists)."));
+ if (advice_resolve_conflict)
+ advise(_("Please, commit your changes before you can merge."));
+ die(_("Exiting because of unfinished merge."));
+}
+
void detach_advice(const char *new_name)
{
const char fmt[] =
diff --git a/advice.h b/advice.h
index 5ecc6c1..b341a55 100644
--- a/advice.h
+++ b/advice.h
@@ -24,6 +24,7 @@ __attribute__((format (printf, 1, 2)))
void advise(const char *advice, ...);
int error_resolve_conflict(const char *me);
extern void NORETURN die_resolve_conflict(const char *me);
+void NORETURN die_conclude_merge(void);
void detach_advice(const char *new_name);
#endif /* ADVICE_H */
diff --git a/argv-array.c b/argv-array.c
index 256741d..eaed477 100644
--- a/argv-array.c
+++ b/argv-array.c
@@ -49,6 +49,12 @@ void argv_array_pushl(struct argv_array *array, ...)
va_end(ap);
}
+void argv_array_pushv(struct argv_array *array, const char **argv)
+{
+ for (; *argv; argv++)
+ argv_array_push(array, *argv);
+}
+
void argv_array_pop(struct argv_array *array)
{
if (!array->argc)
diff --git a/argv-array.h b/argv-array.h
index c65e6e8..a2fa0aa 100644
--- a/argv-array.h
+++ b/argv-array.h
@@ -17,6 +17,7 @@ __attribute__((format (printf,2,3)))
void argv_array_pushf(struct argv_array *, const char *fmt, ...);
LAST_ARG_MUST_BE_NULL
void argv_array_pushl(struct argv_array *, ...);
+void argv_array_pushv(struct argv_array *, const char **);
void argv_array_pop(struct argv_array *);
void argv_array_clear(struct argv_array *);
diff --git a/builtin.h b/builtin.h
index b87df70..839483d 100644
--- a/builtin.h
+++ b/builtin.h
@@ -98,6 +98,7 @@ extern int cmd_pack_redundant(int argc, const char **argv, const char *prefix);
extern int cmd_patch_id(int argc, const char **argv, const char *prefix);
extern int cmd_prune(int argc, const char **argv, const char *prefix);
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
+extern int cmd_pull(int argc, const char **argv, const char *prefix);
extern int cmd_push(int argc, const char **argv, const char *prefix);
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);
@@ -133,6 +134,7 @@ extern int cmd_verify_commit(int argc, const char **argv, const char *prefix);
extern int cmd_verify_tag(int argc, const char **argv, const char *prefix);
extern int cmd_version(int argc, const char **argv, const char *prefix);
extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
+extern int cmd_worktree(int argc, const char **argv, const char *prefix);
extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index df5135b..4bd98b7 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -63,7 +63,6 @@ static void update_callback(struct diff_queue_struct *q,
switch (fix_unmerged_status(p, data)) {
default:
die(_("unexpected diff status %c"), p->status);
- case DIFF_STATUS_ADDED:
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
if (add_file_to_index(&the_index, path, data->flags)) {
diff --git a/builtin/apply.c b/builtin/apply.c
index 146be97..54aba4e 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1638,6 +1638,9 @@ static int parse_fragment(const char *line, unsigned long size,
}
if (oldlines || newlines)
return -1;
+ if (!deleted && !added)
+ return -1;
+
fragment->leading = leading;
fragment->trailing = trailing;
diff --git a/builtin/blame.c b/builtin/blame.c
index 1c998cb..272a222 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -2177,6 +2177,14 @@ static int git_blame_config(const char *var, const char *value, void *cb)
blank_boundary = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "blame.showemail")) {
+ int *output_option = cb;
+ if (git_config_bool(var, value))
+ *output_option |= OUTPUT_SHOW_EMAIL;
+ else
+ *output_option &= ~OUTPUT_SHOW_EMAIL;
+ return 0;
+ }
if (!strcmp(var, "blame.date")) {
if (!value)
return config_error_nonbool(var);
@@ -2521,7 +2529,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
unsigned int range_i;
long anchor;
- git_config(git_blame_config, NULL);
+ git_config(git_blame_config, &output_option);
init_revisions(&revs, NULL);
revs.date_mode = blame_date_mode;
DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 9b49f0e..f71844a 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -19,8 +19,6 @@
#include "ll-merge.h"
#include "resolve-undo.h"
#include "submodule.h"
-#include "argv-array.h"
-#include "sigchain.h"
static const char * const checkout_usage[] = {
N_("git checkout [<options>] <branch>"),
@@ -51,8 +49,6 @@ struct checkout_opts {
struct pathspec pathspec;
struct tree *source_tree;
- const char *new_worktree;
- const char **saved_argv;
int new_worktree_mode;
};
@@ -273,9 +269,6 @@ static int checkout_paths(const struct checkout_opts *opts,
die(_("Cannot update paths and switch to branch '%s' at the same time."),
opts->new_branch);
- if (opts->new_worktree)
- die(_("'%s' cannot be used with updating paths"), "--to");
-
if (opts->patch_mode)
return run_add_interactive(revision, "--patch=checkout",
&opts->pathspec);
@@ -850,138 +843,6 @@ static int switch_branches(const struct checkout_opts *opts,
return ret || writeout_error;
}
-static char *junk_work_tree;
-static char *junk_git_dir;
-static int is_junk;
-static pid_t junk_pid;
-
-static void remove_junk(void)
-{
- struct strbuf sb = STRBUF_INIT;
- if (!is_junk || getpid() != junk_pid)
- return;
- if (junk_git_dir) {
- strbuf_addstr(&sb, junk_git_dir);
- remove_dir_recursively(&sb, 0);
- strbuf_reset(&sb);
- }
- if (junk_work_tree) {
- strbuf_addstr(&sb, junk_work_tree);
- remove_dir_recursively(&sb, 0);
- }
- strbuf_release(&sb);
-}
-
-static void remove_junk_on_signal(int signo)
-{
- remove_junk();
- sigchain_pop(signo);
- raise(signo);
-}
-
-static int prepare_linked_checkout(const struct checkout_opts *opts,
- struct branch_info *new)
-{
- struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
- struct strbuf sb = STRBUF_INIT;
- const char *path = opts->new_worktree, *name;
- struct stat st;
- struct child_process cp;
- int counter = 0, len, ret;
-
- if (!new->commit)
- die(_("no branch specified"));
- if (file_exists(path) && !is_empty_dir(path))
- die(_("'%s' already exists"), path);
-
- len = strlen(path);
- while (len && is_dir_sep(path[len - 1]))
- len--;
-
- for (name = path + len - 1; name > path; name--)
- if (is_dir_sep(*name)) {
- name++;
- break;
- }
- strbuf_addstr(&sb_repo,
- git_path("worktrees/%.*s", (int)(path + len - name), name));
- len = sb_repo.len;
- if (safe_create_leading_directories_const(sb_repo.buf))
- die_errno(_("could not create leading directories of '%s'"),
- sb_repo.buf);
- while (!stat(sb_repo.buf, &st)) {
- counter++;
- strbuf_setlen(&sb_repo, len);
- strbuf_addf(&sb_repo, "%d", counter);
- }
- name = strrchr(sb_repo.buf, '/') + 1;
-
- junk_pid = getpid();
- atexit(remove_junk);
- sigchain_push_common(remove_junk_on_signal);
-
- if (mkdir(sb_repo.buf, 0777))
- die_errno(_("could not create directory of '%s'"), sb_repo.buf);
- junk_git_dir = xstrdup(sb_repo.buf);
- is_junk = 1;
-
- /*
- * lock the incomplete repo so prune won't delete it, unlock
- * after the preparation is over.
- */
- strbuf_addf(&sb, "%s/locked", sb_repo.buf);
- write_file(sb.buf, 1, "initializing\n");
-
- strbuf_addf(&sb_git, "%s/.git", path);
- if (safe_create_leading_directories_const(sb_git.buf))
- die_errno(_("could not create leading directories of '%s'"),
- sb_git.buf);
- junk_work_tree = xstrdup(path);
-
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
- write_file(sb.buf, 1, "%s\n", real_path(sb_git.buf));
- write_file(sb_git.buf, 1, "gitdir: %s/worktrees/%s\n",
- real_path(get_git_common_dir()), name);
- /*
- * This is to keep resolve_ref() happy. We need a valid HEAD
- * or is_git_directory() will reject the directory. Any valid
- * value would do because this value will be ignored and
- * replaced at the next (real) checkout.
- */
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
- write_file(sb.buf, 1, "%s\n", sha1_to_hex(new->commit->object.sha1));
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
- write_file(sb.buf, 1, "../..\n");
-
- if (!opts->quiet)
- fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
-
- setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
- setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);
- setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
- memset(&cp, 0, sizeof(cp));
- cp.git_cmd = 1;
- cp.argv = opts->saved_argv;
- ret = run_command(&cp);
- if (!ret) {
- is_junk = 0;
- free(junk_work_tree);
- free(junk_git_dir);
- junk_work_tree = NULL;
- junk_git_dir = NULL;
- }
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%s/locked", sb_repo.buf);
- unlink_or_warn(sb.buf);
- strbuf_release(&sb);
- strbuf_release(&sb_repo);
- strbuf_release(&sb_git);
- return ret;
-}
-
static int git_checkout_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "diff.ignoresubmodules")) {
@@ -1110,7 +971,6 @@ static int parse_branchname_arg(int argc, const char **argv,
{
struct tree **source_tree = &opts->source_tree;
const char **new_branch = &opts->new_branch;
- int force_detach = opts->force_detach;
int argcount = 0;
unsigned char branch_rev[20];
const char *arg;
@@ -1231,17 +1091,6 @@ static int parse_branchname_arg(int argc, const char **argv,
else
new->path = NULL; /* not an existing branch */
- if (new->path && !force_detach && !*new_branch) {
- unsigned char sha1[20];
- int flag;
- char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
- if (head_ref &&
- (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) &&
- !opts->ignore_other_worktrees)
- check_linked_checkouts(new);
- free(head_ref);
- }
-
new->commit = lookup_commit_reference_gently(rev, 1);
if (!new->commit) {
/* not a commit */
@@ -1321,8 +1170,16 @@ static int checkout_branch(struct checkout_opts *opts,
die(_("Cannot switch branch to a non-commit '%s'"),
new->name);
- if (opts->new_worktree)
- return prepare_linked_checkout(opts, new);
+ if (new->path && !opts->force_detach && !opts->new_branch) {
+ unsigned char sha1[20];
+ int flag;
+ char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
+ if (head_ref &&
+ (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) &&
+ !opts->ignore_other_worktrees)
+ check_linked_checkouts(new);
+ free(head_ref);
+ }
if (!new->commit && opts->new_branch) {
unsigned char rev[20];
@@ -1366,8 +1223,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
N_("do not limit pathspecs to sparse entries only")),
OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
N_("second guess 'git checkout <no-such-branch>'")),
- OPT_FILENAME(0, "to", &opts.new_worktree,
- N_("check a branch out in a separate working directory")),
OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
N_("do not check if another worktree is holding the given ref")),
OPT_END(),
@@ -1378,9 +1233,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.overwrite_ignore = 1;
opts.prefix = prefix;
- opts.saved_argv = xmalloc(sizeof(const char *) * (argc + 2));
- memcpy(opts.saved_argv, argv, sizeof(const char *) * (argc + 1));
-
gitmodules_config();
git_config(git_checkout_config, &opts);
@@ -1389,13 +1241,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, checkout_usage,
PARSE_OPT_KEEP_DASHDASH);
- /* recursive execution from checkout_new_worktree() */
opts.new_worktree_mode = getenv("GIT_CHECKOUT_NEW_WORKTREE") != NULL;
- if (opts.new_worktree_mode)
- opts.new_worktree = NULL;
-
- if (!opts.new_worktree)
- setup_work_tree();
if (conflict_style) {
opts.merge = 1; /* implied */
diff --git a/builtin/clean.c b/builtin/clean.c
index 6dcb72e..df53def 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -10,7 +10,6 @@
#include "cache.h"
#include "dir.h"
#include "parse-options.h"
-#include "refs.h"
#include "string-list.h"
#include "quote.h"
#include "column.h"
@@ -148,6 +147,31 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
return 0;
}
+/*
+ * Return 1 if the given path is the root of a git repository or
+ * submodule else 0. Will not return 1 for bare repositories with the
+ * exception of creating a bare repository in "foo/.git" and calling
+ * is_git_repository("foo").
+ */
+static int is_git_repository(struct strbuf *path)
+{
+ int ret = 0;
+ int gitfile_error;
+ size_t orig_path_len = path->len;
+ assert(orig_path_len != 0);
+ if (path->buf[orig_path_len - 1] != '/')
+ strbuf_addch(path, '/');
+ strbuf_addstr(path, ".git");
+ if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
+ ret = 1;
+ if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
+ gitfile_error == READ_GITFILE_ERR_READ_FAILED)
+ ret = 1; /* This could be a real .git file, take the
+ * safe option and avoid cleaning */
+ strbuf_setlen(path, orig_path_len);
+ return ret;
+}
+
static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
int dry_run, int quiet, int *dir_gone)
{
@@ -155,13 +179,11 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
struct strbuf quoted = STRBUF_INIT;
struct dirent *e;
int res = 0, ret = 0, gone = 1, original_len = path->len, len;
- unsigned char submodule_head[20];
struct string_list dels = STRING_LIST_INIT_DUP;
*dir_gone = 1;
- if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
- !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
+ if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_git_repository(path)) {
if (!quiet) {
quote_path_relative(path->buf, prefix, &quoted);
printf(dry_run ? _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
diff --git a/builtin/clone.c b/builtin/clone.c
index 8539b8d..303a3a7 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -147,6 +147,7 @@ static char *get_repo_path(const char *repo, int *is_bundle)
static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
{
const char *end = repo + strlen(repo), *start;
+ size_t len;
char *dir;
/*
@@ -173,20 +174,12 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
/*
* Strip .{bundle,git}.
*/
- if (is_bundle) {
- if (end - start > 7 && !strncmp(end - 7, ".bundle", 7))
- end -= 7;
- } else {
- if (end - start > 4 && !strncmp(end - 4, ".git", 4))
- end -= 4;
- }
+ strip_suffix(start, is_bundle ? ".bundle" : ".git" , &len);
- if (is_bare) {
- struct strbuf result = STRBUF_INIT;
- strbuf_addf(&result, "%.*s.git", (int)(end - start), start);
- dir = strbuf_detach(&result, NULL);
- } else
- dir = xstrndup(start, end - start);
+ if (is_bare)
+ dir = xstrfmt("%.*s.git", (int)len, start);
+ else
+ dir = xstrndup(start, len);
/*
* Replace sequences of 'control' characters and whitespace
* with one ascii space, remove leading and trailing spaces.
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index f7e51a7..7919206 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -2,1077 +2,8 @@
#include "cache.h"
#include "refs.h"
#include "object.h"
-#include "tag.h"
-#include "commit.h"
-#include "tree.h"
-#include "blob.h"
-#include "quote.h"
#include "parse-options.h"
-#include "remote.h"
-#include "color.h"
-
-/* Quoting styles */
-#define QUOTE_NONE 0
-#define QUOTE_SHELL 1
-#define QUOTE_PERL 2
-#define QUOTE_PYTHON 4
-#define QUOTE_TCL 8
-
-typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
-
-struct atom_value {
- const char *s;
- unsigned long ul; /* used for sorting when not FIELD_STR */
-};
-
-struct ref_sort {
- struct ref_sort *next;
- int atom; /* index into used_atom array */
- unsigned reverse : 1;
-};
-
-struct refinfo {
- char *refname;
- unsigned char objectname[20];
- int flag;
- const char *symref;
- struct atom_value *value;
-};
-
-static struct {
- const char *name;
- cmp_type cmp_type;
-} valid_atom[] = {
- { "refname" },
- { "objecttype" },
- { "objectsize", FIELD_ULONG },
- { "objectname" },
- { "tree" },
- { "parent" },
- { "numparent", FIELD_ULONG },
- { "object" },
- { "type" },
- { "tag" },
- { "author" },
- { "authorname" },
- { "authoremail" },
- { "authordate", FIELD_TIME },
- { "committer" },
- { "committername" },
- { "committeremail" },
- { "committerdate", FIELD_TIME },
- { "tagger" },
- { "taggername" },
- { "taggeremail" },
- { "taggerdate", FIELD_TIME },
- { "creator" },
- { "creatordate", FIELD_TIME },
- { "subject" },
- { "body" },
- { "contents" },
- { "contents:subject" },
- { "contents:body" },
- { "contents:signature" },
- { "upstream" },
- { "push" },
- { "symref" },
- { "flag" },
- { "HEAD" },
- { "color" },
-};
-
-/*
- * An atom is a valid field atom listed above, possibly prefixed with
- * a "*" to denote deref_tag().
- *
- * We parse given format string and sort specifiers, and make a list
- * of properties that we need to extract out of objects. refinfo
- * structure will hold an array of values extracted that can be
- * indexed with the "atom number", which is an index into this
- * array.
- */
-static const char **used_atom;
-static cmp_type *used_atom_type;
-static int used_atom_cnt, need_tagged, need_symref;
-static int need_color_reset_at_eol;
-
-/*
- * Used to parse format string and sort specifiers
- */
-static int parse_atom(const char *atom, const char *ep)
-{
- const char *sp;
- int i, at;
-
- sp = atom;
- if (*sp == '*' && sp < ep)
- sp++; /* deref */
- if (ep <= sp)
- die("malformed field name: %.*s", (int)(ep-atom), atom);
-
- /* Do we have the atom already used elsewhere? */
- for (i = 0; i < used_atom_cnt; i++) {
- int len = strlen(used_atom[i]);
- if (len == ep - atom && !memcmp(used_atom[i], atom, len))
- return i;
- }
-
- /* Is the atom a valid one? */
- for (i = 0; i < ARRAY_SIZE(valid_atom); i++) {
- int len = strlen(valid_atom[i].name);
- /*
- * If the atom name has a colon, strip it and everything after
- * it off - it specifies the format for this entry, and
- * shouldn't be used for checking against the valid_atom
- * table.
- */
- const char *formatp = strchr(sp, ':');
- if (!formatp || ep < formatp)
- formatp = ep;
- if (len == formatp - sp && !memcmp(valid_atom[i].name, sp, len))
- break;
- }
-
- if (ARRAY_SIZE(valid_atom) <= i)
- die("unknown field name: %.*s", (int)(ep-atom), atom);
-
- /* Add it in, including the deref prefix */
- at = used_atom_cnt;
- used_atom_cnt++;
- REALLOC_ARRAY(used_atom, used_atom_cnt);
- REALLOC_ARRAY(used_atom_type, used_atom_cnt);
- used_atom[at] = xmemdupz(atom, ep - atom);
- used_atom_type[at] = valid_atom[i].cmp_type;
- if (*atom == '*')
- need_tagged = 1;
- if (!strcmp(used_atom[at], "symref"))
- need_symref = 1;
- return at;
-}
-
-/*
- * In a format string, find the next occurrence of %(atom).
- */
-static const char *find_next(const char *cp)
-{
- while (*cp) {
- if (*cp == '%') {
- /*
- * %( is the start of an atom;
- * %% is a quoted per-cent.
- */
- if (cp[1] == '(')
- return cp;
- else if (cp[1] == '%')
- cp++; /* skip over two % */
- /* otherwise this is a singleton, literal % */
- }
- cp++;
- }
- return NULL;
-}
-
-/*
- * Make sure the format string is well formed, and parse out
- * the used atoms.
- */
-static int verify_format(const char *format)
-{
- const char *cp, *sp;
-
- need_color_reset_at_eol = 0;
- for (cp = format; *cp && (sp = find_next(cp)); ) {
- const char *color, *ep = strchr(sp, ')');
- int at;
-
- if (!ep)
- return error("malformed format string %s", sp);
- /* sp points at "%(" and ep points at the closing ")" */
- at = parse_atom(sp + 2, ep);
- cp = ep + 1;
-
- if (skip_prefix(used_atom[at], "color:", &color))
- need_color_reset_at_eol = !!strcmp(color, "reset");
- }
- return 0;
-}
-
-/*
- * Given an object name, read the object data and size, and return a
- * "struct object". If the object data we are returning is also borrowed
- * by the "struct object" representation, set *eaten as well---it is a
- * signal from parse_object_buffer to us not to free the buffer.
- */
-static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)
-{
- enum object_type type;
- void *buf = read_sha1_file(sha1, &type, sz);
-
- if (buf)
- *obj = parse_object_buffer(sha1, type, *sz, buf, eaten);
- else
- *obj = NULL;
- return buf;
-}
-
-static int grab_objectname(const char *name, const unsigned char *sha1,
- struct atom_value *v)
-{
- if (!strcmp(name, "objectname")) {
- char *s = xmalloc(41);
- strcpy(s, sha1_to_hex(sha1));
- v->s = s;
- return 1;
- }
- if (!strcmp(name, "objectname:short")) {
- v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
- return 1;
- }
- return 0;
-}
-
-/* See grab_values */
-static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
-{
- int i;
-
- for (i = 0; i < used_atom_cnt; i++) {
- const char *name = used_atom[i];
- struct atom_value *v = &val[i];
- if (!!deref != (*name == '*'))
- continue;
- if (deref)
- name++;
- if (!strcmp(name, "objecttype"))
- v->s = typename(obj->type);
- else if (!strcmp(name, "objectsize")) {
- char *s = xmalloc(40);
- sprintf(s, "%lu", sz);
- v->ul = sz;
- v->s = s;
- }
- else if (deref)
- grab_objectname(name, obj->sha1, v);
- }
-}
-
-/* See grab_values */
-static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
-{
- int i;
- struct tag *tag = (struct tag *) obj;
-
- for (i = 0; i < used_atom_cnt; i++) {
- const char *name = used_atom[i];
- struct atom_value *v = &val[i];
- if (!!deref != (*name == '*'))
- continue;
- if (deref)
- name++;
- if (!strcmp(name, "tag"))
- v->s = tag->tag;
- else if (!strcmp(name, "type") && tag->tagged)
- v->s = typename(tag->tagged->type);
- else if (!strcmp(name, "object") && tag->tagged) {
- char *s = xmalloc(41);
- strcpy(s, sha1_to_hex(tag->tagged->sha1));
- v->s = s;
- }
- }
-}
-
-/* See grab_values */
-static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
-{
- int i;
- struct commit *commit = (struct commit *) obj;
-
- for (i = 0; i < used_atom_cnt; i++) {
- const char *name = used_atom[i];
- struct atom_value *v = &val[i];
- if (!!deref != (*name == '*'))
- continue;
- if (deref)
- name++;
- if (!strcmp(name, "tree")) {
- char *s = xmalloc(41);
- strcpy(s, sha1_to_hex(commit->tree->object.sha1));
- v->s = s;
- }
- if (!strcmp(name, "numparent")) {
- char *s = xmalloc(40);
- v->ul = commit_list_count(commit->parents);
- sprintf(s, "%lu", v->ul);
- v->s = s;
- }
- else if (!strcmp(name, "parent")) {
- int num = commit_list_count(commit->parents);
- int i;
- struct commit_list *parents;
- char *s = xmalloc(41 * num + 1);
- v->s = s;
- for (i = 0, parents = commit->parents;
- parents;
- parents = parents->next, i = i + 41) {
- struct commit *parent = parents->item;
- strcpy(s+i, sha1_to_hex(parent->object.sha1));
- if (parents->next)
- s[i+40] = ' ';
- }
- if (!i)
- *s = '\0';
- }
- }
-}
-
-static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz)
-{
- const char *eol;
- while (*buf) {
- if (!strncmp(buf, who, wholen) &&
- buf[wholen] == ' ')
- return buf + wholen + 1;
- eol = strchr(buf, '\n');
- if (!eol)
- return "";
- eol++;
- if (*eol == '\n')
- return ""; /* end of header */
- buf = eol;
- }
- return "";
-}
-
-static const char *copy_line(const char *buf)
-{
- const char *eol = strchrnul(buf, '\n');
- return xmemdupz(buf, eol - buf);
-}
-
-static const char *copy_name(const char *buf)
-{
- const char *cp;
- for (cp = buf; *cp && *cp != '\n'; cp++) {
- if (!strncmp(cp, " <", 2))
- return xmemdupz(buf, cp - buf);
- }
- return "";
-}
-
-static const char *copy_email(const char *buf)
-{
- const char *email = strchr(buf, '<');
- const char *eoemail;
- if (!email)
- return "";
- eoemail = strchr(email, '>');
- if (!eoemail)
- return "";
- return xmemdupz(email, eoemail + 1 - email);
-}
-
-static char *copy_subject(const char *buf, unsigned long len)
-{
- char *r = xmemdupz(buf, len);
- int i;
-
- for (i = 0; i < len; i++)
- if (r[i] == '\n')
- r[i] = ' ';
-
- return r;
-}
-
-static void grab_date(const char *buf, struct atom_value *v, const char *atomname)
-{
- const char *eoemail = strstr(buf, "> ");
- char *zone;
- unsigned long timestamp;
- long tz;
- enum date_mode date_mode = DATE_NORMAL;
- const char *formatp;
-
- /*
- * We got here because atomname ends in "date" or "date<something>";
- * it's not possible that <something> is not ":<format>" because
- * parse_atom() wouldn't have allowed it, so we can assume that no
- * ":" means no format is specified, and use the default.
- */
- formatp = strchr(atomname, ':');
- if (formatp != NULL) {
- formatp++;
- date_mode = parse_date_format(formatp);
- }
-
- if (!eoemail)
- goto bad;
- timestamp = strtoul(eoemail + 2, &zone, 10);
- if (timestamp == ULONG_MAX)
- goto bad;
- tz = strtol(zone, NULL, 10);
- if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE)
- goto bad;
- v->s = xstrdup(show_date(timestamp, tz, date_mode));
- v->ul = timestamp;
- return;
- bad:
- v->s = "";
- v->ul = 0;
-}
-
-/* See grab_values */
-static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
-{
- int i;
- int wholen = strlen(who);
- const char *wholine = NULL;
-
- for (i = 0; i < used_atom_cnt; i++) {
- const char *name = used_atom[i];
- struct atom_value *v = &val[i];
- if (!!deref != (*name == '*'))
- continue;
- if (deref)
- name++;
- if (strncmp(who, name, wholen))
- continue;
- if (name[wholen] != 0 &&
- strcmp(name + wholen, "name") &&
- strcmp(name + wholen, "email") &&
- !starts_with(name + wholen, "date"))
- continue;
- if (!wholine)
- wholine = find_wholine(who, wholen, buf, sz);
- if (!wholine)
- return; /* no point looking for it */
- if (name[wholen] == 0)
- v->s = copy_line(wholine);
- else if (!strcmp(name + wholen, "name"))
- v->s = copy_name(wholine);
- else if (!strcmp(name + wholen, "email"))
- v->s = copy_email(wholine);
- else if (starts_with(name + wholen, "date"))
- grab_date(wholine, v, name);
- }
-
- /*
- * For a tag or a commit object, if "creator" or "creatordate" is
- * requested, do something special.
- */
- if (strcmp(who, "tagger") && strcmp(who, "committer"))
- return; /* "author" for commit object is not wanted */
- if (!wholine)
- wholine = find_wholine(who, wholen, buf, sz);
- if (!wholine)
- return;
- for (i = 0; i < used_atom_cnt; i++) {
- const char *name = used_atom[i];
- struct atom_value *v = &val[i];
- if (!!deref != (*name == '*'))
- continue;
- if (deref)
- name++;
-
- if (starts_with(name, "creatordate"))
- grab_date(wholine, v, name);
- else if (!strcmp(name, "creator"))
- v->s = copy_line(wholine);
- }
-}
-
-static void find_subpos(const char *buf, unsigned long sz,
- const char **sub, unsigned long *sublen,
- const char **body, unsigned long *bodylen,
- unsigned long *nonsiglen,
- const char **sig, unsigned long *siglen)
-{
- const char *eol;
- /* skip past header until we hit empty line */
- while (*buf && *buf != '\n') {
- eol = strchrnul(buf, '\n');
- if (*eol)
- eol++;
- buf = eol;
- }
- /* skip any empty lines */
- while (*buf == '\n')
- buf++;
-
- /* parse signature first; we might not even have a subject line */
- *sig = buf + parse_signature(buf, strlen(buf));
- *siglen = strlen(*sig);
-
- /* subject is first non-empty line */
- *sub = buf;
- /* subject goes to first empty line */
- while (buf < *sig && *buf && *buf != '\n') {
- eol = strchrnul(buf, '\n');
- if (*eol)
- eol++;
- buf = eol;
- }
- *sublen = buf - *sub;
- /* drop trailing newline, if present */
- if (*sublen && (*sub)[*sublen - 1] == '\n')
- *sublen -= 1;
-
- /* skip any empty lines */
- while (*buf == '\n')
- buf++;
- *body = buf;
- *bodylen = strlen(buf);
- *nonsiglen = *sig - buf;
-}
-
-/* See grab_values */
-static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
-{
- int i;
- const char *subpos = NULL, *bodypos = NULL, *sigpos = NULL;
- unsigned long sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0;
-
- for (i = 0; i < used_atom_cnt; i++) {
- const char *name = used_atom[i];
- struct atom_value *v = &val[i];
- if (!!deref != (*name == '*'))
- continue;
- if (deref)
- name++;
- if (strcmp(name, "subject") &&
- strcmp(name, "body") &&
- strcmp(name, "contents") &&
- strcmp(name, "contents:subject") &&
- strcmp(name, "contents:body") &&
- strcmp(name, "contents:signature"))
- continue;
- if (!subpos)
- find_subpos(buf, sz,
- &subpos, &sublen,
- &bodypos, &bodylen, &nonsiglen,
- &sigpos, &siglen);
-
- if (!strcmp(name, "subject"))
- v->s = copy_subject(subpos, sublen);
- else if (!strcmp(name, "contents:subject"))
- v->s = copy_subject(subpos, sublen);
- else if (!strcmp(name, "body"))
- v->s = xmemdupz(bodypos, bodylen);
- else if (!strcmp(name, "contents:body"))
- v->s = xmemdupz(bodypos, nonsiglen);
- else if (!strcmp(name, "contents:signature"))
- v->s = xmemdupz(sigpos, siglen);
- else if (!strcmp(name, "contents"))
- v->s = xstrdup(subpos);
- }
-}
-
-/*
- * We want to have empty print-string for field requests
- * that do not apply (e.g. "authordate" for a tag object)
- */
-static void fill_missing_values(struct atom_value *val)
-{
- int i;
- for (i = 0; i < used_atom_cnt; i++) {
- struct atom_value *v = &val[i];
- if (v->s == NULL)
- v->s = "";
- }
-}
-
-/*
- * val is a list of atom_value to hold returned values. Extract
- * the values for atoms in used_atom array out of (obj, buf, sz).
- * when deref is false, (obj, buf, sz) is the object that is
- * pointed at by the ref itself; otherwise it is the object the
- * ref (which is a tag) refers to.
- */
-static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
-{
- grab_common_values(val, deref, obj, buf, sz);
- switch (obj->type) {
- case OBJ_TAG:
- grab_tag_values(val, deref, obj, buf, sz);
- grab_sub_body_contents(val, deref, obj, buf, sz);
- grab_person("tagger", val, deref, obj, buf, sz);
- break;
- case OBJ_COMMIT:
- grab_commit_values(val, deref, obj, buf, sz);
- grab_sub_body_contents(val, deref, obj, buf, sz);
- grab_person("author", val, deref, obj, buf, sz);
- grab_person("committer", val, deref, obj, buf, sz);
- break;
- case OBJ_TREE:
- /* grab_tree_values(val, deref, obj, buf, sz); */
- break;
- case OBJ_BLOB:
- /* grab_blob_values(val, deref, obj, buf, sz); */
- break;
- default:
- die("Eh? Object of type %d?", obj->type);
- }
-}
-
-static inline char *copy_advance(char *dst, const char *src)
-{
- while (*src)
- *dst++ = *src++;
- return dst;
-}
-
-/*
- * Parse the object referred by ref, and grab needed value.
- */
-static void populate_value(struct refinfo *ref)
-{
- void *buf;
- struct object *obj;
- int eaten, i;
- unsigned long size;
- const unsigned char *tagged;
-
- ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));
-
- if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
- unsigned char unused1[20];
- ref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING,
- unused1, NULL);
- if (!ref->symref)
- ref->symref = "";
- }
-
- /* Fill in specials first */
- for (i = 0; i < used_atom_cnt; i++) {
- const char *name = used_atom[i];
- struct atom_value *v = &ref->value[i];
- int deref = 0;
- const char *refname;
- const char *formatp;
- struct branch *branch = NULL;
-
- if (*name == '*') {
- deref = 1;
- name++;
- }
-
- if (starts_with(name, "refname"))
- refname = ref->refname;
- else if (starts_with(name, "symref"))
- refname = ref->symref ? ref->symref : "";
- else if (starts_with(name, "upstream")) {
- const char *branch_name;
- /* only local branches may have an upstream */
- if (!skip_prefix(ref->refname, "refs/heads/",
- &branch_name))
- continue;
- branch = branch_get(branch_name);
-
- refname = branch_get_upstream(branch, NULL);
- if (!refname)
- continue;
- } else if (starts_with(name, "push")) {
- const char *branch_name;
- if (!skip_prefix(ref->refname, "refs/heads/",
- &branch_name))
- continue;
- branch = branch_get(branch_name);
-
- refname = branch_get_push(branch, NULL);
- if (!refname)
- continue;
- } else if (starts_with(name, "color:")) {
- char color[COLOR_MAXLEN] = "";
-
- if (color_parse(name + 6, color) < 0)
- die(_("unable to parse format"));
- v->s = xstrdup(color);
- continue;
- } else if (!strcmp(name, "flag")) {
- char buf[256], *cp = buf;
- if (ref->flag & REF_ISSYMREF)
- cp = copy_advance(cp, ",symref");
- if (ref->flag & REF_ISPACKED)
- cp = copy_advance(cp, ",packed");
- if (cp == buf)
- v->s = "";
- else {
- *cp = '\0';
- v->s = xstrdup(buf + 1);
- }
- continue;
- } else if (!deref && grab_objectname(name, ref->objectname, v)) {
- continue;
- } else if (!strcmp(name, "HEAD")) {
- const char *head;
- unsigned char sha1[20];
-
- head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
- sha1, NULL);
- if (!strcmp(ref->refname, head))
- v->s = "*";
- else
- v->s = " ";
- continue;
- } else
- continue;
-
- formatp = strchr(name, ':');
- if (formatp) {
- int num_ours, num_theirs;
-
- formatp++;
- if (!strcmp(formatp, "short"))
- refname = shorten_unambiguous_ref(refname,
- warn_ambiguous_refs);
- else if (!strcmp(formatp, "track") &&
- (starts_with(name, "upstream") ||
- starts_with(name, "push"))) {
- char buf[40];
-
- if (stat_tracking_info(branch, &num_ours,
- &num_theirs, NULL))
- continue;
-
- if (!num_ours && !num_theirs)
- v->s = "";
- else if (!num_ours) {
- sprintf(buf, "[behind %d]", num_theirs);
- v->s = xstrdup(buf);
- } else if (!num_theirs) {
- sprintf(buf, "[ahead %d]", num_ours);
- v->s = xstrdup(buf);
- } else {
- sprintf(buf, "[ahead %d, behind %d]",
- num_ours, num_theirs);
- v->s = xstrdup(buf);
- }
- continue;
- } else if (!strcmp(formatp, "trackshort") &&
- (starts_with(name, "upstream") ||
- starts_with(name, "push"))) {
- assert(branch);
-
- if (stat_tracking_info(branch, &num_ours,
- &num_theirs, NULL))
- continue;
-
- if (!num_ours && !num_theirs)
- v->s = "=";
- else if (!num_ours)
- v->s = "<";
- else if (!num_theirs)
- v->s = ">";
- else
- v->s = "<>";
- continue;
- } else
- die("unknown %.*s format %s",
- (int)(formatp - name), name, formatp);
- }
-
- if (!deref)
- v->s = refname;
- else {
- int len = strlen(refname);
- char *s = xmalloc(len + 4);
- sprintf(s, "%s^{}", refname);
- v->s = s;
- }
- }
-
- for (i = 0; i < used_atom_cnt; i++) {
- struct atom_value *v = &ref->value[i];
- if (v->s == NULL)
- goto need_obj;
- }
- return;
-
- need_obj:
- buf = get_obj(ref->objectname, &obj, &size, &eaten);
- if (!buf)
- die("missing object %s for %s",
- sha1_to_hex(ref->objectname), ref->refname);
- if (!obj)
- die("parse_object_buffer failed on %s for %s",
- sha1_to_hex(ref->objectname), ref->refname);
-
- grab_values(ref->value, 0, obj, buf, size);
- if (!eaten)
- free(buf);
-
- /*
- * If there is no atom that wants to know about tagged
- * object, we are done.
- */
- if (!need_tagged || (obj->type != OBJ_TAG))
- return;
-
- /*
- * If it is a tag object, see if we use a value that derefs
- * the object, and if we do grab the object it refers to.
- */
- tagged = ((struct tag *)obj)->tagged->sha1;
-
- /*
- * NEEDSWORK: This derefs tag only once, which
- * is good to deal with chains of trust, but
- * is not consistent with what deref_tag() does
- * which peels the onion to the core.
- */
- buf = get_obj(tagged, &obj, &size, &eaten);
- if (!buf)
- die("missing object %s for %s",
- sha1_to_hex(tagged), ref->refname);
- if (!obj)
- die("parse_object_buffer failed on %s for %s",
- sha1_to_hex(tagged), ref->refname);
- grab_values(ref->value, 1, obj, buf, size);
- if (!eaten)
- free(buf);
-}
-
-/*
- * Given a ref, return the value for the atom. This lazily gets value
- * out of the object by calling populate value.
- */
-static void get_value(struct refinfo *ref, int atom, struct atom_value **v)
-{
- if (!ref->value) {
- populate_value(ref);
- fill_missing_values(ref->value);
- }
- *v = &ref->value[atom];
-}
-
-struct grab_ref_cbdata {
- struct refinfo **grab_array;
- const char **grab_pattern;
- int grab_cnt;
-};
-
-/*
- * A call-back given to for_each_ref(). Filter refs and keep them for
- * later object processing.
- */
-static int grab_single_ref(const char *refname, const struct object_id *oid,
- int flag, void *cb_data)
-{
- struct grab_ref_cbdata *cb = cb_data;
- struct refinfo *ref;
- int cnt;
-
- if (flag & REF_BAD_NAME) {
- warning("ignoring ref with broken name %s", refname);
- return 0;
- }
-
- if (*cb->grab_pattern) {
- const char **pattern;
- int namelen = strlen(refname);
- for (pattern = cb->grab_pattern; *pattern; pattern++) {
- const char *p = *pattern;
- int plen = strlen(p);
-
- if ((plen <= namelen) &&
- !strncmp(refname, p, plen) &&
- (refname[plen] == '\0' ||
- refname[plen] == '/' ||
- p[plen-1] == '/'))
- break;
- if (!wildmatch(p, refname, WM_PATHNAME, NULL))
- break;
- }
- if (!*pattern)
- return 0;
- }
-
- /*
- * We do not open the object yet; sort may only need refname
- * to do its job and the resulting list may yet to be pruned
- * by maxcount logic.
- */
- ref = xcalloc(1, sizeof(*ref));
- ref->refname = xstrdup(refname);
- hashcpy(ref->objectname, oid->hash);
- ref->flag = flag;
-
- cnt = cb->grab_cnt;
- REALLOC_ARRAY(cb->grab_array, cnt + 1);
- cb->grab_array[cnt++] = ref;
- cb->grab_cnt = cnt;
- return 0;
-}
-
-static int cmp_ref_sort(struct ref_sort *s, struct refinfo *a, struct refinfo *b)
-{
- struct atom_value *va, *vb;
- int cmp;
- cmp_type cmp_type = used_atom_type[s->atom];
-
- get_value(a, s->atom, &va);
- get_value(b, s->atom, &vb);
- switch (cmp_type) {
- case FIELD_STR:
- cmp = strcmp(va->s, vb->s);
- break;
- default:
- if (va->ul < vb->ul)
- cmp = -1;
- else if (va->ul == vb->ul)
- cmp = 0;
- else
- cmp = 1;
- break;
- }
- return (s->reverse) ? -cmp : cmp;
-}
-
-static struct ref_sort *ref_sort;
-static int compare_refs(const void *a_, const void *b_)
-{
- struct refinfo *a = *((struct refinfo **)a_);
- struct refinfo *b = *((struct refinfo **)b_);
- struct ref_sort *s;
-
- for (s = ref_sort; s; s = s->next) {
- int cmp = cmp_ref_sort(s, a, b);
- if (cmp)
- return cmp;
- }
- return 0;
-}
-
-static void sort_refs(struct ref_sort *sort, struct refinfo **refs, int num_refs)
-{
- ref_sort = sort;
- qsort(refs, num_refs, sizeof(struct refinfo *), compare_refs);
-}
-
-static void print_value(struct atom_value *v, int quote_style)
-{
- struct strbuf sb = STRBUF_INIT;
- switch (quote_style) {
- case QUOTE_NONE:
- fputs(v->s, stdout);
- break;
- case QUOTE_SHELL:
- sq_quote_buf(&sb, v->s);
- break;
- case QUOTE_PERL:
- perl_quote_buf(&sb, v->s);
- break;
- case QUOTE_PYTHON:
- python_quote_buf(&sb, v->s);
- break;
- case QUOTE_TCL:
- tcl_quote_buf(&sb, v->s);
- break;
- }
- if (quote_style != QUOTE_NONE) {
- fputs(sb.buf, stdout);
- strbuf_release(&sb);
- }
-}
-
-static int hex1(char ch)
-{
- if ('0' <= ch && ch <= '9')
- return ch - '0';
- else if ('a' <= ch && ch <= 'f')
- return ch - 'a' + 10;
- else if ('A' <= ch && ch <= 'F')
- return ch - 'A' + 10;
- return -1;
-}
-static int hex2(const char *cp)
-{
- if (cp[0] && cp[1])
- return (hex1(cp[0]) << 4) | hex1(cp[1]);
- else
- return -1;
-}
-
-static void emit(const char *cp, const char *ep)
-{
- while (*cp && (!ep || cp < ep)) {
- if (*cp == '%') {
- if (cp[1] == '%')
- cp++;
- else {
- int ch = hex2(cp + 1);
- if (0 <= ch) {
- putchar(ch);
- cp += 3;
- continue;
- }
- }
- }
- putchar(*cp);
- cp++;
- }
-}
-
-static void show_ref(struct refinfo *info, const char *format, int quote_style)
-{
- const char *cp, *sp, *ep;
-
- for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
- struct atom_value *atomv;
-
- ep = strchr(sp, ')');
- if (cp < sp)
- emit(cp, sp);
- get_value(info, parse_atom(sp + 2, ep), &atomv);
- print_value(atomv, quote_style);
- }
- if (*cp) {
- sp = cp + strlen(cp);
- emit(cp, sp);
- }
- if (need_color_reset_at_eol) {
- struct atom_value resetv;
- char color[COLOR_MAXLEN] = "";
-
- if (color_parse("reset", color) < 0)
- die("BUG: couldn't parse 'reset' as a color");
- resetv.s = color;
- print_value(&resetv, quote_style);
- }
- putchar('\n');
-}
-
-static struct ref_sort *default_sort(void)
-{
- static const char cstr_name[] = "refname";
-
- struct ref_sort *sort = xcalloc(1, sizeof(*sort));
-
- sort->next = NULL;
- sort->atom = parse_atom(cstr_name, cstr_name + strlen(cstr_name));
- return sort;
-}
-
-static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
-{
- struct ref_sort **sort_tail = opt->value;
- struct ref_sort *s;
- int len;
-
- if (!arg) /* should --no-sort void the list ? */
- return -1;
-
- s = xcalloc(1, sizeof(*s));
- s->next = *sort_tail;
- *sort_tail = s;
-
- if (*arg == '-') {
- s->reverse = 1;
- arg++;
- }
- len = strlen(arg);
- s->atom = parse_atom(arg, arg+len);
- return 0;
-}
+#include "ref-filter.h"
static char const * const for_each_ref_usage[] = {
N_("git for-each-ref [<options>] [<pattern>]"),
@@ -1081,12 +12,12 @@ static char const * const for_each_ref_usage[] = {
int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
{
- int i, num_refs;
+ int i;
const char *format = "%(objectname) %(objecttype)\t%(refname)";
- struct ref_sort *sort = NULL, **sort_tail = &sort;
+ struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
int maxcount = 0, quote_style = 0;
- struct refinfo **refs;
- struct grab_ref_cbdata cbdata;
+ struct ref_array array;
+ struct ref_filter filter;
struct option opts[] = {
OPT_BIT('s', "shell", &quote_style,
@@ -1101,8 +32,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
OPT_GROUP(""),
OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
- OPT_CALLBACK(0 , "sort", sort_tail, N_("key"),
- N_("field name to sort on"), &opt_parse_sort),
+ OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
+ N_("field name to sort on"), &parse_opt_ref_sorting),
OPT_END(),
};
@@ -1115,26 +46,25 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
error("more than one quoting style?");
usage_with_options(for_each_ref_usage, opts);
}
- if (verify_format(format))
+ if (verify_ref_format(format))
usage_with_options(for_each_ref_usage, opts);
- if (!sort)
- sort = default_sort();
+ if (!sorting)
+ sorting = ref_default_sorting();
/* for warn_ambiguous_refs */
git_config(git_default_config, NULL);
- memset(&cbdata, 0, sizeof(cbdata));
- cbdata.grab_pattern = argv;
- for_each_rawref(grab_single_ref, &cbdata);
- refs = cbdata.grab_array;
- num_refs = cbdata.grab_cnt;
-
- sort_refs(sort, refs, num_refs);
+ memset(&array, 0, sizeof(array));
+ memset(&filter, 0, sizeof(filter));
+ filter.name_patterns = argv;
+ filter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN);
+ ref_array_sort(sorting, &array);
- if (!maxcount || num_refs < maxcount)
- maxcount = num_refs;
+ if (!maxcount || array.nr < maxcount)
+ maxcount = array.nr;
for (i = 0; i < maxcount; i++)
- show_ref(refs[i], format, quote_style);
+ show_ref_array_item(array.items[i], format, quote_style);
+ ref_array_clear(&array);
return 0;
}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 4e8e2ee..2679793 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -451,35 +451,41 @@ static void fsck_dir(int i, char *path)
static int default_refs;
+static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1)
+{
+ struct object *obj;
+
+ if (!is_null_sha1(sha1)) {
+ obj = lookup_object(sha1);
+ if (obj) {
+ obj->used = 1;
+ mark_object_reachable(obj);
+ } else {
+ error("%s: invalid reflog entry %s", refname, sha1_to_hex(sha1));
+ errors_found |= ERROR_REACHABLE;
+ }
+ }
+}
+
static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
const char *email, unsigned long timestamp, int tz,
const char *message, void *cb_data)
{
- struct object *obj;
+ const char *refname = cb_data;
if (verbose)
fprintf(stderr, "Checking reflog %s->%s\n",
sha1_to_hex(osha1), sha1_to_hex(nsha1));
- if (!is_null_sha1(osha1)) {
- obj = lookup_object(osha1);
- if (obj) {
- obj->used = 1;
- mark_object_reachable(obj);
- }
- }
- obj = lookup_object(nsha1);
- if (obj) {
- obj->used = 1;
- mark_object_reachable(obj);
- }
+ fsck_handle_reflog_sha1(refname, osha1);
+ fsck_handle_reflog_sha1(refname, nsha1);
return 0;
}
static int fsck_handle_reflog(const char *logname, const struct object_id *oid,
int flag, void *cb_data)
{
- for_each_reflog_ent(logname, fsck_handle_reflog_ent, NULL);
+ for_each_reflog_ent(logname, fsck_handle_reflog_ent, (void *)logname);
return 0;
}
diff --git a/builtin/gc.c b/builtin/gc.c
index 36fe333..4957c39 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -293,7 +293,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
argv_array_pushl(&reflog, "reflog", "expire", "--all", NULL);
argv_array_pushl(&repack, "repack", "-d", "-l", NULL);
argv_array_pushl(&prune, "prune", "--expire", NULL);
- argv_array_pushl(&prune_worktrees, "prune", "--worktrees", "--expire", NULL);
+ argv_array_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL);
argv_array_pushl(&rerere, "rerere", "gc", NULL);
gc_config();
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 7ea2020..f07bc66 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -616,7 +616,9 @@ static int compare_ofs_delta_bases(off_t offset1, off_t offset2,
int cmp = type1 - type2;
if (cmp)
return cmp;
- return offset1 - offset2;
+ return offset1 < offset2 ? -1 :
+ offset1 > offset2 ? 1 :
+ 0;
}
static int find_ofs_delta(const off_t offset, enum object_type type)
@@ -784,7 +786,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
assert(data || obj_entry);
read_lock();
- collision_test_needed = has_sha1_file(sha1);
+ collision_test_needed = has_sha1_file_with_flags(sha1, HAS_SHA1_QUICK);
read_unlock();
if (collision_test_needed && !data) {
@@ -1051,7 +1053,9 @@ static int compare_ofs_delta_entry(const void *a, const void *b)
const struct ofs_delta_entry *delta_a = a;
const struct ofs_delta_entry *delta_b = b;
- return delta_a->offset - delta_b->offset;
+ return delta_a->offset < delta_b->offset ? -1 :
+ delta_a->offset > delta_b->offset ? 1 :
+ 0;
}
static int compare_ref_delta_entry(const void *a, const void *b)
@@ -1223,7 +1227,7 @@ static void resolve_deltas(void)
* - append objects to convert thin pack to full pack if required
* - write the final 20-byte SHA-1
*/
-static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved);
+static void fix_unresolved_deltas(struct sha1file *f);
static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1)
{
if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) {
@@ -1245,7 +1249,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
memset(objects + nr_objects + 1, 0,
nr_unresolved * sizeof(*objects));
f = sha1fd(output_fd, curr_pack);
- fix_unresolved_deltas(f, nr_unresolved);
+ fix_unresolved_deltas(f);
strbuf_addf(&msg, _("completed with %d local objects"),
nr_objects - nr_objects_initial);
stop_progress_msg(&progress, msg.buf);
@@ -1327,10 +1331,10 @@ static int delta_pos_compare(const void *_a, const void *_b)
return a->obj_no - b->obj_no;
}
-static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)
+static void fix_unresolved_deltas(struct sha1file *f)
{
struct ref_delta_entry **sorted_by_pos;
- int i, n = 0;
+ int i;
/*
* Since many unresolved deltas may well be themselves base objects
@@ -1342,12 +1346,12 @@ static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)
* before deltas depending on them, a good heuristic is to start
* resolving deltas in the same order as their position in the pack.
*/
- sorted_by_pos = xmalloc(nr_unresolved * sizeof(*sorted_by_pos));
+ sorted_by_pos = xmalloc(nr_ref_deltas * sizeof(*sorted_by_pos));
for (i = 0; i < nr_ref_deltas; i++)
- sorted_by_pos[n++] = &ref_deltas[i];
- qsort(sorted_by_pos, n, sizeof(*sorted_by_pos), delta_pos_compare);
+ sorted_by_pos[i] = &ref_deltas[i];
+ qsort(sorted_by_pos, nr_ref_deltas, sizeof(*sorted_by_pos), delta_pos_compare);
- for (i = 0; i < n; i++) {
+ for (i = 0; i < nr_ref_deltas; i++) {
struct ref_delta_entry *d = sorted_by_pos[i];
enum object_type type;
struct base_data *base_obj = alloc_base_data();
diff --git a/builtin/log.c b/builtin/log.c
index 3caa917..93025d0 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -796,7 +796,7 @@ static int reopen_stdout(struct commit *commit, const char *subject,
static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
{
struct rev_info check_rev;
- struct commit *commit;
+ struct commit *commit, *c1, *c2;
struct object *o1, *o2;
unsigned flags1, flags2;
@@ -804,9 +804,11 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
die(_("Need exactly one range."));
o1 = rev->pending.objects[0].item;
- flags1 = o1->flags;
o2 = rev->pending.objects[1].item;
+ flags1 = o1->flags;
flags2 = o2->flags;
+ c1 = lookup_commit_reference(o1->sha1);
+ c2 = lookup_commit_reference(o2->sha1);
if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
die(_("Not a range."));
@@ -828,10 +830,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
}
/* reset for next revision walk */
- clear_commit_marks((struct commit *)o1,
- SEEN | UNINTERESTING | SHOWN | ADDED);
- clear_commit_marks((struct commit *)o2,
- SEEN | UNINTERESTING | SHOWN | ADDED);
+ clear_commit_marks(c1, SEEN | UNINTERESTING | SHOWN | ADDED);
+ clear_commit_marks(c2, SEEN | UNINTERESTING | SHOWN | ADDED);
o1->flags = flags1;
o2->flags = flags2;
}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 80fe8c7..62cc16d 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2588,23 +2588,6 @@ static int option_parse_unpack_unreachable(const struct option *opt,
return 0;
}
-static int option_parse_ulong(const struct option *opt,
- const char *arg, int unset)
-{
- if (unset)
- die(_("option %s does not accept negative form"),
- opt->long_name);
-
- if (!git_parse_ulong(arg, opt->value))
- die(_("unable to parse value '%s' for option %s"),
- arg, opt->long_name);
- return 0;
-}
-
-#define OPT_ULONG(s, l, v, h) \
- { OPTION_CALLBACK, (s), (l), (v), "n", (h), \
- PARSE_OPT_NONEG, option_parse_ulong }
-
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
@@ -2627,16 +2610,16 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{ OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"),
N_("write the pack index file in the specified idx format version"),
0, option_parse_index_version },
- OPT_ULONG(0, "max-pack-size", &pack_size_limit,
- N_("maximum size of each output pack file")),
+ OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
+ N_("maximum size of each output pack file")),
OPT_BOOL(0, "local", &local,
N_("ignore borrowed objects from alternate object store")),
OPT_BOOL(0, "incremental", &incremental,
N_("ignore packed objects")),
OPT_INTEGER(0, "window", &window,
N_("limit pack window by objects")),
- OPT_ULONG(0, "window-memory", &window_memory_limit,
- N_("limit pack window by memory in addition to object limit")),
+ OPT_MAGNITUDE(0, "window-memory", &window_memory_limit,
+ N_("limit pack window by memory in addition to object limit")),
OPT_INTEGER(0, "depth", &depth,
N_("maximum length of delta chain allowed in the resulting pack")),
OPT_BOOL(0, "reuse-delta", &reuse_delta,
diff --git a/builtin/prune.c b/builtin/prune.c
index 0c73246..10b03d3 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -6,7 +6,6 @@
#include "reachable.h"
#include "parse-options.h"
#include "progress.h"
-#include "dir.h"
static const char * const prune_usage[] = {
N_("git prune [-n] [-v] [--expire <time>] [--] [<head>...]"),
@@ -76,95 +75,6 @@ static int prune_subdir(int nr, const char *path, void *data)
return 0;
}
-static int prune_worktree(const char *id, struct strbuf *reason)
-{
- struct stat st;
- char *path;
- int fd, len;
-
- if (!is_directory(git_path("worktrees/%s", id))) {
- strbuf_addf(reason, _("Removing worktrees/%s: not a valid directory"), id);
- return 1;
- }
- if (file_exists(git_path("worktrees/%s/locked", id)))
- return 0;
- if (stat(git_path("worktrees/%s/gitdir", id), &st)) {
- strbuf_addf(reason, _("Removing worktrees/%s: gitdir file does not exist"), id);
- return 1;
- }
- fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY);
- if (fd < 0) {
- strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"),
- id, strerror(errno));
- return 1;
- }
- len = st.st_size;
- path = xmalloc(len + 1);
- read_in_full(fd, path, len);
- close(fd);
- while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
- len--;
- if (!len) {
- strbuf_addf(reason, _("Removing worktrees/%s: invalid gitdir file"), id);
- free(path);
- return 1;
- }
- path[len] = '\0';
- if (!file_exists(path)) {
- struct stat st_link;
- free(path);
- /*
- * the repo is moved manually and has not been
- * accessed since?
- */
- if (!stat(git_path("worktrees/%s/link", id), &st_link) &&
- st_link.st_nlink > 1)
- return 0;
- if (st.st_mtime <= expire) {
- strbuf_addf(reason, _("Removing worktrees/%s: gitdir file points to non-existent location"), id);
- return 1;
- } else {
- return 0;
- }
- }
- free(path);
- return 0;
-}
-
-static void prune_worktrees(void)
-{
- struct strbuf reason = STRBUF_INIT;
- struct strbuf path = STRBUF_INIT;
- DIR *dir = opendir(git_path("worktrees"));
- struct dirent *d;
- int ret;
- if (!dir)
- return;
- while ((d = readdir(dir)) != NULL) {
- if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
- continue;
- strbuf_reset(&reason);
- if (!prune_worktree(d->d_name, &reason))
- continue;
- if (show_only || verbose)
- printf("%s\n", reason.buf);
- if (show_only)
- continue;
- strbuf_reset(&path);
- strbuf_addstr(&path, git_path("worktrees/%s", d->d_name));
- ret = remove_dir_recursively(&path, 0);
- if (ret < 0 && errno == ENOTDIR)
- ret = unlink(path.buf);
- if (ret)
- error(_("failed to remove: %s"), strerror(errno));
- }
- closedir(dir);
- if (!show_only)
- rmdir(git_path("worktrees"));
- strbuf_release(&reason);
- strbuf_release(&path);
-}
-
/*
* Write errors (particularly out of space) can result in
* failed temporary packs (and more rarely indexes and other
@@ -191,12 +101,10 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
struct progress *progress = NULL;
- int do_prune_worktrees = 0;
const struct option options[] = {
OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
OPT__VERBOSE(&verbose, N_("report pruned objects")),
OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
- OPT_BOOL(0, "worktrees", &do_prune_worktrees, N_("prune .git/worktrees")),
OPT_EXPIRY_DATE(0, "expire", &expire,
N_("expire objects older than <time>")),
OPT_END()
@@ -211,13 +119,6 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, prune_usage, 0);
- if (do_prune_worktrees) {
- if (argc)
- die(_("--worktrees does not take extra arguments"));
- prune_worktrees();
- return 0;
- }
-
while (argc--) {
unsigned char sha1[20];
const char *name = *argv++;
diff --git a/builtin/pull.c b/builtin/pull.c
new file mode 100644
index 0000000..722a83c
--- /dev/null
+++ b/builtin/pull.c
@@ -0,0 +1,882 @@
+/*
+ * Builtin "git pull"
+ *
+ * Based on git-pull.sh by Junio C Hamano
+ *
+ * Fetch one or more remote refs and merge it/them into the current HEAD.
+ */
+#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+#include "exec_cmd.h"
+#include "run-command.h"
+#include "sha1-array.h"
+#include "remote.h"
+#include "dir.h"
+#include "refs.h"
+#include "revision.h"
+#include "lockfile.h"
+
+enum rebase_type {
+ REBASE_INVALID = -1,
+ REBASE_FALSE = 0,
+ REBASE_TRUE,
+ REBASE_PRESERVE
+};
+
+/**
+ * Parses the value of --rebase. If value is a false value, returns
+ * REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
+ * "preserve", returns REBASE_PRESERVE. If value is a invalid value, dies with
+ * a fatal error if fatal is true, otherwise returns REBASE_INVALID.
+ */
+static enum rebase_type parse_config_rebase(const char *key, const char *value,
+ int fatal)
+{
+ int v = git_config_maybe_bool("pull.rebase", value);
+
+ if (!v)
+ return REBASE_FALSE;
+ else if (v > 0)
+ return REBASE_TRUE;
+ else if (!strcmp(value, "preserve"))
+ return REBASE_PRESERVE;
+
+ if (fatal)
+ die(_("Invalid value for %s: %s"), key, value);
+ else
+ error(_("Invalid value for %s: %s"), key, value);
+
+ return REBASE_INVALID;
+}
+
+/**
+ * Callback for --rebase, which parses arg with parse_config_rebase().
+ */
+static int parse_opt_rebase(const struct option *opt, const char *arg, int unset)
+{
+ enum rebase_type *value = opt->value;
+
+ if (arg)
+ *value = parse_config_rebase("--rebase", arg, 0);
+ else
+ *value = unset ? REBASE_FALSE : REBASE_TRUE;
+ return *value == REBASE_INVALID ? -1 : 0;
+}
+
+static const char * const pull_usage[] = {
+ N_("git pull [options] [<repository> [<refspec>...]]"),
+ NULL
+};
+
+/* Shared options */
+static int opt_verbosity;
+static char *opt_progress;
+
+/* Options passed to git-merge or git-rebase */
+static enum rebase_type opt_rebase = -1;
+static char *opt_diffstat;
+static char *opt_log;
+static char *opt_squash;
+static char *opt_commit;
+static char *opt_edit;
+static char *opt_ff;
+static char *opt_verify_signatures;
+static struct argv_array opt_strategies = ARGV_ARRAY_INIT;
+static struct argv_array opt_strategy_opts = ARGV_ARRAY_INIT;
+static char *opt_gpg_sign;
+
+/* Options passed to git-fetch */
+static char *opt_all;
+static char *opt_append;
+static char *opt_upload_pack;
+static int opt_force;
+static char *opt_tags;
+static char *opt_prune;
+static char *opt_recurse_submodules;
+static int opt_dry_run;
+static char *opt_keep;
+static char *opt_depth;
+static char *opt_unshallow;
+static char *opt_update_shallow;
+static char *opt_refmap;
+
+static struct option pull_options[] = {
+ /* Shared options */
+ OPT__VERBOSITY(&opt_verbosity),
+ OPT_PASSTHRU(0, "progress", &opt_progress, NULL,
+ N_("force progress reporting"),
+ PARSE_OPT_NOARG),
+
+ /* Options passed to git-merge or git-rebase */
+ OPT_GROUP(N_("Options related to merging")),
+ { OPTION_CALLBACK, 'r', "rebase", &opt_rebase,
+ N_("false|true|preserve"),
+ N_("incorporate changes by rebasing rather than merging"),
+ PARSE_OPT_OPTARG, parse_opt_rebase },
+ OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL,
+ N_("do not show a diffstat at the end of the merge"),
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG),
+ OPT_PASSTHRU(0, "stat", &opt_diffstat, NULL,
+ N_("show a diffstat at the end of the merge"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "summary", &opt_diffstat, NULL,
+ N_("(synonym to --stat)"),
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
+ OPT_PASSTHRU(0, "log", &opt_log, N_("n"),
+ N_("add (at most <n>) entries from shortlog to merge commit message"),
+ PARSE_OPT_OPTARG),
+ OPT_PASSTHRU(0, "squash", &opt_squash, NULL,
+ N_("create a single commit instead of doing a merge"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "commit", &opt_commit, NULL,
+ N_("perform a commit if the merge succeeds (default)"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
+ N_("edit message before committing"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
+ N_("allow fast-forward"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "ff-only", &opt_ff, NULL,
+ N_("abort if fast-forward is not possible"),
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG),
+ OPT_PASSTHRU(0, "verify-signatures", &opt_verify_signatures, NULL,
+ N_("verify that the named commit has a valid GPG signature"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU_ARGV('s', "strategy", &opt_strategies, N_("strategy"),
+ N_("merge strategy to use"),
+ 0),
+ OPT_PASSTHRU_ARGV('X', "strategy-option", &opt_strategy_opts,
+ N_("option=value"),
+ N_("option for selected merge strategy"),
+ 0),
+ OPT_PASSTHRU('S', "gpg-sign", &opt_gpg_sign, N_("key-id"),
+ N_("GPG sign commit"),
+ PARSE_OPT_OPTARG),
+
+ /* Options passed to git-fetch */
+ OPT_GROUP(N_("Options related to fetching")),
+ OPT_PASSTHRU(0, "all", &opt_all, NULL,
+ N_("fetch from all remotes"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU('a', "append", &opt_append, NULL,
+ N_("append to .git/FETCH_HEAD instead of overwriting"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "upload-pack", &opt_upload_pack, N_("path"),
+ N_("path to upload pack on remote end"),
+ 0),
+ OPT__FORCE(&opt_force, N_("force overwrite of local branch")),
+ OPT_PASSTHRU('t', "tags", &opt_tags, NULL,
+ N_("fetch all tags and associated objects"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU('p', "prune", &opt_prune, NULL,
+ N_("prune remote-tracking branches no longer on remote"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "recurse-submodules", &opt_recurse_submodules,
+ N_("on-demand"),
+ N_("control recursive fetching of submodules"),
+ PARSE_OPT_OPTARG),
+ OPT_BOOL(0, "dry-run", &opt_dry_run,
+ N_("dry run")),
+ OPT_PASSTHRU('k', "keep", &opt_keep, NULL,
+ N_("keep downloaded pack"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "depth", &opt_depth, N_("depth"),
+ N_("deepen history of shallow clone"),
+ 0),
+ OPT_PASSTHRU(0, "unshallow", &opt_unshallow, NULL,
+ N_("convert to a complete repository"),
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "update-shallow", &opt_update_shallow, NULL,
+ N_("accept refs that update .git/shallow"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "refmap", &opt_refmap, N_("refmap"),
+ N_("specify fetch refmap"),
+ PARSE_OPT_NONEG),
+
+ OPT_END()
+};
+
+/**
+ * Pushes "-q" or "-v" switches into arr to match the opt_verbosity level.
+ */
+static void argv_push_verbosity(struct argv_array *arr)
+{
+ int verbosity;
+
+ for (verbosity = opt_verbosity; verbosity > 0; verbosity--)
+ argv_array_push(arr, "-v");
+
+ for (verbosity = opt_verbosity; verbosity < 0; verbosity++)
+ argv_array_push(arr, "-q");
+}
+
+/**
+ * Pushes "-f" switches into arr to match the opt_force level.
+ */
+static void argv_push_force(struct argv_array *arr)
+{
+ int force = opt_force;
+ while (force-- > 0)
+ argv_array_push(arr, "-f");
+}
+
+/**
+ * Sets the GIT_REFLOG_ACTION environment variable to the concatenation of argv
+ */
+static void set_reflog_message(int argc, const char **argv)
+{
+ int i;
+ struct strbuf msg = STRBUF_INIT;
+
+ for (i = 0; i < argc; i++) {
+ if (i)
+ strbuf_addch(&msg, ' ');
+ strbuf_addstr(&msg, argv[i]);
+ }
+
+ setenv("GIT_REFLOG_ACTION", msg.buf, 0);
+
+ strbuf_release(&msg);
+}
+
+/**
+ * If pull.ff is unset, returns NULL. If pull.ff is "true", returns "--ff". If
+ * pull.ff is "false", returns "--no-ff". If pull.ff is "only", returns
+ * "--ff-only". Otherwise, if pull.ff is set to an invalid value, die with an
+ * error.
+ */
+static const char *config_get_ff(void)
+{
+ const char *value;
+
+ if (git_config_get_value("pull.ff", &value))
+ return NULL;
+
+ switch (git_config_maybe_bool("pull.ff", value)) {
+ case 0:
+ return "--no-ff";
+ case 1:
+ return "--ff";
+ }
+
+ if (!strcmp(value, "only"))
+ return "--ff-only";
+
+ die(_("Invalid value for pull.ff: %s"), value);
+}
+
+/**
+ * Returns the default configured value for --rebase. It first looks for the
+ * value of "branch.$curr_branch.rebase", where $curr_branch is the current
+ * branch, and if HEAD is detached or the configuration key does not exist,
+ * 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)
+{
+ struct branch *curr_branch = branch_get("HEAD");
+ const char *value;
+
+ if (curr_branch) {
+ char *key = xstrfmt("branch.%s.rebase", curr_branch->name);
+
+ if (!git_config_get_value(key, &value)) {
+ enum rebase_type ret = parse_config_rebase(key, value, 1);
+ free(key);
+ return ret;
+ }
+
+ free(key);
+ }
+
+ if (!git_config_get_value("pull.rebase", &value))
+ return parse_config_rebase("pull.rebase", value, 1);
+
+ return REBASE_FALSE;
+}
+
+/**
+ * Returns 1 if there are unstaged changes, 0 otherwise.
+ */
+static int has_unstaged_changes(const char *prefix)
+{
+ struct rev_info rev_info;
+ int result;
+
+ init_revisions(&rev_info, prefix);
+ DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
+ DIFF_OPT_SET(&rev_info.diffopt, QUICK);
+ diff_setup_done(&rev_info.diffopt);
+ result = run_diff_files(&rev_info, 0);
+ return diff_result_code(&rev_info.diffopt, result);
+}
+
+/**
+ * Returns 1 if there are uncommitted changes, 0 otherwise.
+ */
+static int has_uncommitted_changes(const char *prefix)
+{
+ struct rev_info rev_info;
+ int result;
+
+ if (is_cache_unborn())
+ return 0;
+
+ init_revisions(&rev_info, prefix);
+ DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
+ DIFF_OPT_SET(&rev_info.diffopt, QUICK);
+ add_head_to_pending(&rev_info);
+ diff_setup_done(&rev_info.diffopt);
+ result = run_diff_index(&rev_info, 1);
+ return diff_result_code(&rev_info.diffopt, result);
+}
+
+/**
+ * If the work tree has unstaged or uncommitted changes, dies with the
+ * appropriate message.
+ */
+static void die_on_unclean_work_tree(const char *prefix)
+{
+ struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file));
+ int do_die = 0;
+
+ hold_locked_index(lock_file, 0);
+ refresh_cache(REFRESH_QUIET);
+ update_index_if_able(&the_index, lock_file);
+ rollback_lock_file(lock_file);
+
+ if (has_unstaged_changes(prefix)) {
+ error(_("Cannot pull with rebase: You have unstaged changes."));
+ do_die = 1;
+ }
+
+ if (has_uncommitted_changes(prefix)) {
+ if (do_die)
+ error(_("Additionally, your index contains uncommitted changes."));
+ else
+ error(_("Cannot pull with rebase: Your index contains uncommitted changes."));
+ do_die = 1;
+ }
+
+ if (do_die)
+ exit(1);
+}
+
+/**
+ * Appends merge candidates from FETCH_HEAD that are not marked not-for-merge
+ * into merge_heads.
+ */
+static void get_merge_heads(struct sha1_array *merge_heads)
+{
+ const char *filename = git_path("FETCH_HEAD");
+ FILE *fp;
+ struct strbuf sb = STRBUF_INIT;
+ unsigned char sha1[GIT_SHA1_RAWSZ];
+
+ if (!(fp = fopen(filename, "r")))
+ die_errno(_("could not open '%s' for reading"), filename);
+ while (strbuf_getline(&sb, fp, '\n') != EOF) {
+ if (get_sha1_hex(sb.buf, sha1))
+ continue; /* invalid line: does not start with SHA1 */
+ if (starts_with(sb.buf + GIT_SHA1_HEXSZ, "\tnot-for-merge\t"))
+ continue; /* ref is not-for-merge */
+ sha1_array_append(merge_heads, sha1);
+ }
+ fclose(fp);
+ strbuf_release(&sb);
+}
+
+/**
+ * Used by die_no_merge_candidates() as a for_each_remote() callback to
+ * retrieve the name of the remote if the repository only has one remote.
+ */
+static int get_only_remote(struct remote *remote, void *cb_data)
+{
+ const char **remote_name = cb_data;
+
+ if (*remote_name)
+ return -1;
+
+ *remote_name = remote->name;
+ return 0;
+}
+
+/**
+ * Dies with the appropriate reason for why there are no merge candidates:
+ *
+ * 1. We fetched from a specific remote, and a refspec was given, but it ended
+ * up not fetching anything. This is usually because the user provided a
+ * wildcard refspec which had no matches on the remote end.
+ *
+ * 2. We fetched from a non-default remote, but didn't specify a branch to
+ * merge. We can't use the configured one because it applies to the default
+ * remote, thus the user must specify the branches to merge.
+ *
+ * 3. We fetched from the branch's or repo's default remote, but:
+ *
+ * a. We are not on a branch, so there will never be a configured branch to
+ * merge with.
+ *
+ * b. We are on a branch, but there is no configured branch to merge with.
+ *
+ * 4. We fetched from the branch's or repo's default remote, but the configured
+ * branch to merge didn't get fetched. (Either it doesn't exist, or wasn't
+ * part of the configured fetch refspec.)
+ */
+static void NORETURN die_no_merge_candidates(const char *repo, const char **refspecs)
+{
+ struct branch *curr_branch = branch_get("HEAD");
+ const char *remote = curr_branch ? curr_branch->remote_name : NULL;
+
+ if (*refspecs) {
+ if (opt_rebase)
+ fprintf_ln(stderr, _("There is no candidate for rebasing against among the refs that you just fetched."));
+ else
+ fprintf_ln(stderr, _("There are no candidates for merging among the refs that you just fetched."));
+ fprintf_ln(stderr, _("Generally this means that you provided a wildcard refspec which had no\n"
+ "matches on the remote end."));
+ } else if (repo && curr_branch && (!remote || strcmp(repo, remote))) {
+ fprintf_ln(stderr, _("You asked to pull from the remote '%s', but did not specify\n"
+ "a branch. Because this is not the default configured remote\n"
+ "for your current branch, you must specify a branch on the command line."),
+ repo);
+ } else if (!curr_branch) {
+ fprintf_ln(stderr, _("You are not currently on a branch."));
+ if (opt_rebase)
+ fprintf_ln(stderr, _("Please specify which branch you want to rebase against."));
+ else
+ fprintf_ln(stderr, _("Please specify which branch you want to merge with."));
+ fprintf_ln(stderr, _("See git-pull(1) for details."));
+ fprintf(stderr, "\n");
+ fprintf_ln(stderr, " git pull <remote> <branch>");
+ fprintf(stderr, "\n");
+ } else if (!curr_branch->merge_nr) {
+ const char *remote_name = NULL;
+
+ if (for_each_remote(get_only_remote, &remote_name) || !remote_name)
+ remote_name = "<remote>";
+
+ fprintf_ln(stderr, _("There is no tracking information for the current branch."));
+ if (opt_rebase)
+ fprintf_ln(stderr, _("Please specify which branch you want to rebase against."));
+ else
+ fprintf_ln(stderr, _("Please specify which branch you want to merge with."));
+ fprintf_ln(stderr, _("See git-pull(1) for details."));
+ fprintf(stderr, "\n");
+ fprintf_ln(stderr, " git pull <remote> <branch>");
+ fprintf(stderr, "\n");
+ fprintf_ln(stderr, _("If you wish to set tracking information for this branch you can do so with:\n"
+ "\n"
+ " git branch --set-upstream-to=%s/<branch> %s\n"),
+ remote_name, curr_branch->name);
+ } else
+ fprintf_ln(stderr, _("Your configuration specifies to merge with the ref '%s'\n"
+ "from the remote, but no such ref was fetched."),
+ *curr_branch->merge_name);
+ exit(1);
+}
+
+/**
+ * Parses argv into [<repo> [<refspecs>...]], returning their values in `repo`
+ * as a string and `refspecs` as a null-terminated array of strings. If `repo`
+ * is not provided in argv, it is set to NULL.
+ */
+static void parse_repo_refspecs(int argc, const char **argv, const char **repo,
+ const char ***refspecs)
+{
+ if (argc > 0) {
+ *repo = *argv++;
+ argc--;
+ } else
+ *repo = NULL;
+ *refspecs = argv;
+}
+
+/**
+ * Runs git-fetch, returning its exit status. `repo` and `refspecs` are the
+ * repository and refspecs to fetch, or NULL if they are not provided.
+ */
+static int run_fetch(const char *repo, const char **refspecs)
+{
+ struct argv_array args = ARGV_ARRAY_INIT;
+ int ret;
+
+ argv_array_pushl(&args, "fetch", "--update-head-ok", NULL);
+
+ /* Shared options */
+ argv_push_verbosity(&args);
+ if (opt_progress)
+ argv_array_push(&args, opt_progress);
+
+ /* Options passed to git-fetch */
+ if (opt_all)
+ argv_array_push(&args, opt_all);
+ if (opt_append)
+ argv_array_push(&args, opt_append);
+ if (opt_upload_pack)
+ argv_array_push(&args, opt_upload_pack);
+ argv_push_force(&args);
+ if (opt_tags)
+ argv_array_push(&args, opt_tags);
+ if (opt_prune)
+ argv_array_push(&args, opt_prune);
+ if (opt_recurse_submodules)
+ argv_array_push(&args, opt_recurse_submodules);
+ if (opt_dry_run)
+ argv_array_push(&args, "--dry-run");
+ if (opt_keep)
+ argv_array_push(&args, opt_keep);
+ if (opt_depth)
+ argv_array_push(&args, opt_depth);
+ if (opt_unshallow)
+ argv_array_push(&args, opt_unshallow);
+ if (opt_update_shallow)
+ argv_array_push(&args, opt_update_shallow);
+ if (opt_refmap)
+ argv_array_push(&args, opt_refmap);
+
+ if (repo) {
+ argv_array_push(&args, repo);
+ argv_array_pushv(&args, refspecs);
+ } else if (*refspecs)
+ die("BUG: refspecs without repo?");
+ ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
+ argv_array_clear(&args);
+ return ret;
+}
+
+/**
+ * "Pulls into void" by branching off merge_head.
+ */
+static int pull_into_void(const unsigned char *merge_head,
+ const unsigned char *curr_head)
+{
+ /*
+ * Two-way merge: we treat the index as based on an empty tree,
+ * and try to fast-forward to HEAD. This ensures we will not lose
+ * index/worktree changes that the user already made on the unborn
+ * branch.
+ */
+ if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0))
+ return 1;
+
+ if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Runs git-merge, returning its exit status.
+ */
+static int run_merge(void)
+{
+ int ret;
+ struct argv_array args = ARGV_ARRAY_INIT;
+
+ argv_array_pushl(&args, "merge", NULL);
+
+ /* Shared options */
+ argv_push_verbosity(&args);
+ if (opt_progress)
+ argv_array_push(&args, opt_progress);
+
+ /* Options passed to git-merge */
+ if (opt_diffstat)
+ argv_array_push(&args, opt_diffstat);
+ if (opt_log)
+ argv_array_push(&args, opt_log);
+ if (opt_squash)
+ argv_array_push(&args, opt_squash);
+ if (opt_commit)
+ argv_array_push(&args, opt_commit);
+ if (opt_edit)
+ argv_array_push(&args, opt_edit);
+ if (opt_ff)
+ argv_array_push(&args, opt_ff);
+ if (opt_verify_signatures)
+ argv_array_push(&args, opt_verify_signatures);
+ argv_array_pushv(&args, opt_strategies.argv);
+ argv_array_pushv(&args, opt_strategy_opts.argv);
+ if (opt_gpg_sign)
+ argv_array_push(&args, opt_gpg_sign);
+
+ argv_array_push(&args, "FETCH_HEAD");
+ ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
+ argv_array_clear(&args);
+ return ret;
+}
+
+/**
+ * Returns remote's upstream branch for the current branch. If remote is NULL,
+ * the current branch's configured default remote is used. Returns NULL if
+ * `remote` does not name a valid remote, HEAD does not point to a branch,
+ * remote is not the branch's configured remote or the branch does not have any
+ * configured upstream branch.
+ */
+static const char *get_upstream_branch(const char *remote)
+{
+ struct remote *rm;
+ struct branch *curr_branch;
+ const char *curr_branch_remote;
+
+ rm = remote_get(remote);
+ if (!rm)
+ return NULL;
+
+ curr_branch = branch_get("HEAD");
+ if (!curr_branch)
+ return NULL;
+
+ curr_branch_remote = remote_for_branch(curr_branch, NULL);
+ assert(curr_branch_remote);
+
+ if (strcmp(curr_branch_remote, rm->name))
+ return NULL;
+
+ return branch_get_upstream(curr_branch, NULL);
+}
+
+/**
+ * Derives the remote tracking branch from the remote and refspec.
+ *
+ * FIXME: The current implementation assumes the default mapping of
+ * refs/heads/<branch_name> to refs/remotes/<remote_name>/<branch_name>.
+ */
+static const char *get_tracking_branch(const char *remote, const char *refspec)
+{
+ struct refspec *spec;
+ const char *spec_src;
+ const char *merge_branch;
+
+ spec = parse_fetch_refspec(1, &refspec);
+ spec_src = spec->src;
+ if (!*spec_src || !strcmp(spec_src, "HEAD"))
+ spec_src = "HEAD";
+ else if (skip_prefix(spec_src, "heads/", &spec_src))
+ ;
+ else if (skip_prefix(spec_src, "refs/heads/", &spec_src))
+ ;
+ else if (starts_with(spec_src, "refs/") ||
+ starts_with(spec_src, "tags/") ||
+ starts_with(spec_src, "remotes/"))
+ spec_src = "";
+
+ if (*spec_src) {
+ if (!strcmp(remote, "."))
+ merge_branch = mkpath("refs/heads/%s", spec_src);
+ else
+ merge_branch = mkpath("refs/remotes/%s/%s", remote, spec_src);
+ } else
+ merge_branch = NULL;
+
+ free_refspec(1, spec);
+ return merge_branch;
+}
+
+/**
+ * Given the repo and refspecs, sets fork_point to the point at which the
+ * current branch forked from its remote tracking branch. Returns 0 on success,
+ * -1 on failure.
+ */
+static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
+ const char *refspec)
+{
+ int ret;
+ struct branch *curr_branch;
+ const char *remote_branch;
+ struct child_process cp = CHILD_PROCESS_INIT;
+ struct strbuf sb = STRBUF_INIT;
+
+ curr_branch = branch_get("HEAD");
+ if (!curr_branch)
+ return -1;
+
+ if (refspec)
+ remote_branch = get_tracking_branch(repo, refspec);
+ else
+ remote_branch = get_upstream_branch(repo);
+
+ if (!remote_branch)
+ return -1;
+
+ argv_array_pushl(&cp.args, "merge-base", "--fork-point",
+ remote_branch, curr_branch->name, NULL);
+ cp.no_stdin = 1;
+ cp.no_stderr = 1;
+ cp.git_cmd = 1;
+
+ ret = capture_command(&cp, &sb, GIT_SHA1_HEXSZ);
+ if (ret)
+ goto cleanup;
+
+ ret = get_sha1_hex(sb.buf, fork_point);
+ if (ret)
+ goto cleanup;
+
+cleanup:
+ strbuf_release(&sb);
+ return ret ? -1 : 0;
+}
+
+/**
+ * Sets merge_base to the octopus merge base of curr_head, merge_head and
+ * fork_point. Returns 0 if a merge base is found, 1 otherwise.
+ */
+static int get_octopus_merge_base(unsigned char *merge_base,
+ const unsigned char *curr_head,
+ const unsigned char *merge_head,
+ const unsigned char *fork_point)
+{
+ struct commit_list *revs = NULL, *result;
+
+ commit_list_insert(lookup_commit_reference(curr_head), &revs);
+ commit_list_insert(lookup_commit_reference(merge_head), &revs);
+ if (!is_null_sha1(fork_point))
+ commit_list_insert(lookup_commit_reference(fork_point), &revs);
+
+ result = reduce_heads(get_octopus_merge_bases(revs));
+ free_commit_list(revs);
+ if (!result)
+ return 1;
+
+ hashcpy(merge_base, result->item->object.sha1);
+ return 0;
+}
+
+/**
+ * Given the current HEAD SHA1, the merge head returned from git-fetch and the
+ * fork point calculated by get_rebase_fork_point(), runs git-rebase with the
+ * appropriate arguments and returns its exit status.
+ */
+static int run_rebase(const unsigned char *curr_head,
+ const unsigned char *merge_head,
+ const unsigned char *fork_point)
+{
+ int ret;
+ unsigned char oct_merge_base[GIT_SHA1_RAWSZ];
+ struct argv_array args = ARGV_ARRAY_INIT;
+
+ if (!get_octopus_merge_base(oct_merge_base, curr_head, merge_head, fork_point))
+ if (!is_null_sha1(fork_point) && !hashcmp(oct_merge_base, fork_point))
+ fork_point = NULL;
+
+ argv_array_push(&args, "rebase");
+
+ /* Shared options */
+ argv_push_verbosity(&args);
+
+ /* Options passed to git-rebase */
+ if (opt_rebase == REBASE_PRESERVE)
+ argv_array_push(&args, "--preserve-merges");
+ if (opt_diffstat)
+ argv_array_push(&args, opt_diffstat);
+ argv_array_pushv(&args, opt_strategies.argv);
+ argv_array_pushv(&args, opt_strategy_opts.argv);
+ if (opt_gpg_sign)
+ argv_array_push(&args, opt_gpg_sign);
+
+ argv_array_push(&args, "--onto");
+ argv_array_push(&args, sha1_to_hex(merge_head));
+
+ if (fork_point && !is_null_sha1(fork_point))
+ argv_array_push(&args, sha1_to_hex(fork_point));
+ else
+ argv_array_push(&args, sha1_to_hex(merge_head));
+
+ ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
+ argv_array_clear(&args);
+ return ret;
+}
+
+int cmd_pull(int argc, const char **argv, const char *prefix)
+{
+ const char *repo, **refspecs;
+ struct sha1_array merge_heads = SHA1_ARRAY_INIT;
+ unsigned char orig_head[GIT_SHA1_RAWSZ], curr_head[GIT_SHA1_RAWSZ];
+ unsigned char rebase_fork_point[GIT_SHA1_RAWSZ];
+
+ if (!getenv("GIT_REFLOG_ACTION"))
+ set_reflog_message(argc, argv);
+
+ argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
+
+ parse_repo_refspecs(argc, argv, &repo, &refspecs);
+
+ if (!opt_ff)
+ opt_ff = xstrdup_or_null(config_get_ff());
+
+ if (opt_rebase < 0)
+ opt_rebase = config_get_rebase();
+
+ git_config(git_default_config, NULL);
+
+ if (read_cache_unmerged())
+ die_resolve_conflict("Pull");
+
+ if (file_exists(git_path("MERGE_HEAD")))
+ die_conclude_merge();
+
+ if (get_sha1("HEAD", orig_head))
+ hashclr(orig_head);
+
+ if (opt_rebase) {
+ if (is_null_sha1(orig_head) && !is_cache_unborn())
+ die(_("Updating an unborn branch with changes added to the index."));
+
+ die_on_unclean_work_tree(prefix);
+
+ if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs))
+ hashclr(rebase_fork_point);
+ }
+
+ if (run_fetch(repo, refspecs))
+ return 1;
+
+ if (opt_dry_run)
+ return 0;
+
+ if (get_sha1("HEAD", curr_head))
+ hashclr(curr_head);
+
+ if (!is_null_sha1(orig_head) && !is_null_sha1(curr_head) &&
+ hashcmp(orig_head, curr_head)) {
+ /*
+ * The fetch involved updating the current branch.
+ *
+ * The working tree and the index file are still based on
+ * orig_head commit, but we are merging into curr_head.
+ * Update the working tree to match curr_head.
+ */
+
+ warning(_("fetch updated the current branch head.\n"
+ "fast-forwarding your working tree from\n"
+ "commit %s."), sha1_to_hex(orig_head));
+
+ if (checkout_fast_forward(orig_head, curr_head, 0))
+ die(_("Cannot fast-forward your working tree.\n"
+ "After making sure that you saved anything precious from\n"
+ "$ git diff %s\n"
+ "output, run\n"
+ "$ git reset --hard\n"
+ "to recover."), sha1_to_hex(orig_head));
+ }
+
+ get_merge_heads(&merge_heads);
+
+ if (!merge_heads.nr)
+ die_no_merge_candidates(repo, refspecs);
+
+ if (is_null_sha1(orig_head)) {
+ if (merge_heads.nr > 1)
+ die(_("Cannot merge multiple branches into empty head."));
+ return pull_into_void(*merge_heads.sha1, curr_head);
+ } else if (opt_rebase) {
+ if (merge_heads.nr > 1)
+ die(_("Cannot rebase onto multiple branches."));
+ return run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point);
+ } else
+ return run_merge();
+}
diff --git a/builtin/replace.c b/builtin/replace.c
index 0d52e7f..6b3c469 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -104,9 +104,9 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
continue;
}
full_hex = sha1_to_hex(sha1);
- snprintf(ref, sizeof(ref), "refs/replace/%s", full_hex);
+ snprintf(ref, sizeof(ref), "%s%s", git_replace_ref_base, full_hex);
/* read_ref() may reuse the buffer */
- full_hex = ref + strlen("refs/replace/");
+ full_hex = ref + strlen(git_replace_ref_base);
if (read_ref(ref, sha1)) {
error("replace ref '%s' not found.", full_hex);
had_error = 1;
@@ -134,7 +134,7 @@ static void check_ref_valid(unsigned char object[20],
int force)
{
if (snprintf(ref, ref_size,
- "refs/replace/%s",
+ "%s%s", git_replace_ref_base,
sha1_to_hex(object)) > ref_size - 1)
die("replace ref name too long: %.*s...", 50, ref);
if (check_refname_format(ref, 0))
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index ff84a82..c0b4b53 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -42,6 +42,7 @@ static const char rev_list_usage[] =
" --abbrev=<n> | --no-abbrev\n"
" --abbrev-commit\n"
" --left-right\n"
+" --count\n"
" special purpose:\n"
" --bisect\n"
" --bisect-vars\n"
@@ -355,7 +356,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (bisect_list)
revs.limited = 1;
- if (use_bitmap_index) {
+ if (use_bitmap_index && !revs.prune) {
if (revs.count && !revs.left_right && !revs.cherry_mark) {
uint32_t commit_count;
if (!prepare_bitmap_walk(&revs)) {
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index ec0c4e3..38bedf8 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -18,25 +18,21 @@ static const char * const verify_commit_usage[] = {
NULL
};
-static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, int verbose)
+static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, unsigned flags)
{
struct signature_check signature_check;
+ int ret;
memset(&signature_check, 0, sizeof(signature_check));
- check_commit_signature(lookup_commit(sha1), &signature_check);
-
- if (verbose && signature_check.payload)
- fputs(signature_check.payload, stdout);
-
- if (signature_check.gpg_output)
- fputs(signature_check.gpg_output, stderr);
+ ret = check_commit_signature(lookup_commit(sha1), &signature_check);
+ print_signature_buffer(&signature_check, flags);
signature_check_clear(&signature_check);
- return signature_check.result != 'G';
+ return ret;
}
-static int verify_commit(const char *name, int verbose)
+static int verify_commit(const char *name, unsigned flags)
{
enum object_type type;
unsigned char sha1[20];
@@ -54,7 +50,7 @@ static int verify_commit(const char *name, int verbose)
return error("%s: cannot verify a non-commit object of type %s.",
name, typename(type));
- ret = run_gpg_verify(sha1, buf, size, verbose);
+ ret = run_gpg_verify(sha1, buf, size, flags);
free(buf);
return ret;
@@ -71,8 +67,10 @@ static int git_verify_commit_config(const char *var, const char *value, void *cb
int cmd_verify_commit(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
+ unsigned flags = 0;
const struct option verify_commit_options[] = {
OPT__VERBOSE(&verbose, N_("print commit contents")),
+ OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
OPT_END()
};
@@ -83,11 +81,14 @@ int cmd_verify_commit(int argc, const char **argv, const char *prefix)
if (argc <= i)
usage_with_options(verify_commit_usage, verify_commit_options);
+ if (verbose)
+ flags |= GPG_VERIFY_VERBOSE;
+
/* sometimes the program was terminated because this signal
* was received in the process of writing the gpg input: */
signal(SIGPIPE, SIG_IGN);
while (i < argc)
- if (verify_commit(argv[i++], verbose))
+ if (verify_commit(argv[i++], flags))
had_error = 1;
return had_error;
}
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index 53c68fc..00663f6 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -18,21 +18,30 @@ static const char * const verify_tag_usage[] = {
NULL
};
-static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
+static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)
{
+ struct signature_check sigc;
int len;
+ int ret;
+
+ memset(&sigc, 0, sizeof(sigc));
len = parse_signature(buf, size);
- if (verbose)
- write_in_full(1, buf, len);
- if (size == len)
+ if (size == len) {
+ if (flags & GPG_VERIFY_VERBOSE)
+ write_in_full(1, buf, len);
return error("no signature found");
+ }
+
+ ret = check_signature(buf, len, buf + len, size - len, &sigc);
+ print_signature_buffer(&sigc, flags);
- return verify_signed_buffer(buf, len, buf + len, size - len, NULL, NULL);
+ signature_check_clear(&sigc);
+ return ret;
}
-static int verify_tag(const char *name, int verbose)
+static int verify_tag(const char *name, unsigned flags)
{
enum object_type type;
unsigned char sha1[20];
@@ -52,7 +61,7 @@ static int verify_tag(const char *name, int verbose)
if (!buf)
return error("%s: unable to read file.", name);
- ret = run_gpg_verify(buf, size, verbose);
+ ret = run_gpg_verify(buf, size, flags);
free(buf);
return ret;
@@ -69,8 +78,10 @@ static int git_verify_tag_config(const char *var, const char *value, void *cb)
int cmd_verify_tag(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
+ unsigned flags = 0;
const struct option verify_tag_options[] = {
OPT__VERBOSE(&verbose, N_("print tag contents")),
+ OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
OPT_END()
};
@@ -81,11 +92,14 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
if (argc <= i)
usage_with_options(verify_tag_usage, verify_tag_options);
+ if (verbose)
+ flags |= GPG_VERIFY_VERBOSE;
+
/* sometimes the program was terminated because this signal
* was received in the process of writing the gpg input: */
signal(SIGPIPE, SIG_IGN);
while (i < argc)
- if (verify_tag(argv[i++], verbose))
+ if (verify_tag(argv[i++], flags))
had_error = 1;
return had_error;
}
diff --git a/builtin/worktree.c b/builtin/worktree.c
new file mode 100644
index 0000000..6a264ee
--- /dev/null
+++ b/builtin/worktree.c
@@ -0,0 +1,332 @@
+#include "cache.h"
+#include "builtin.h"
+#include "dir.h"
+#include "parse-options.h"
+#include "argv-array.h"
+#include "run-command.h"
+#include "sigchain.h"
+#include "refs.h"
+
+static const char * const worktree_usage[] = {
+ N_("git worktree add [<options>] <path> <branch>"),
+ N_("git worktree prune [<options>]"),
+ NULL
+};
+
+static int show_only;
+static int verbose;
+static unsigned long expire;
+
+static int prune_worktree(const char *id, struct strbuf *reason)
+{
+ struct stat st;
+ char *path;
+ int fd, len;
+
+ if (!is_directory(git_path("worktrees/%s", id))) {
+ strbuf_addf(reason, _("Removing worktrees/%s: not a valid directory"), id);
+ return 1;
+ }
+ if (file_exists(git_path("worktrees/%s/locked", id)))
+ return 0;
+ if (stat(git_path("worktrees/%s/gitdir", id), &st)) {
+ strbuf_addf(reason, _("Removing worktrees/%s: gitdir file does not exist"), id);
+ return 1;
+ }
+ fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY);
+ if (fd < 0) {
+ strbuf_addf(reason, _("Removing worktrees/%s: unable to read gitdir file (%s)"),
+ id, strerror(errno));
+ return 1;
+ }
+ len = st.st_size;
+ path = xmalloc(len + 1);
+ read_in_full(fd, path, len);
+ close(fd);
+ while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
+ len--;
+ if (!len) {
+ strbuf_addf(reason, _("Removing worktrees/%s: invalid gitdir file"), id);
+ free(path);
+ return 1;
+ }
+ path[len] = '\0';
+ if (!file_exists(path)) {
+ struct stat st_link;
+ free(path);
+ /*
+ * the repo is moved manually and has not been
+ * accessed since?
+ */
+ if (!stat(git_path("worktrees/%s/link", id), &st_link) &&
+ st_link.st_nlink > 1)
+ return 0;
+ if (st.st_mtime <= expire) {
+ strbuf_addf(reason, _("Removing worktrees/%s: gitdir file points to non-existent location"), id);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ free(path);
+ return 0;
+}
+
+static void prune_worktrees(void)
+{
+ struct strbuf reason = STRBUF_INIT;
+ struct strbuf path = STRBUF_INIT;
+ DIR *dir = opendir(git_path("worktrees"));
+ struct dirent *d;
+ int ret;
+ if (!dir)
+ return;
+ while ((d = readdir(dir)) != NULL) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+ strbuf_reset(&reason);
+ if (!prune_worktree(d->d_name, &reason))
+ continue;
+ if (show_only || verbose)
+ printf("%s\n", reason.buf);
+ if (show_only)
+ continue;
+ strbuf_reset(&path);
+ strbuf_addstr(&path, git_path("worktrees/%s", d->d_name));
+ ret = remove_dir_recursively(&path, 0);
+ if (ret < 0 && errno == ENOTDIR)
+ ret = unlink(path.buf);
+ if (ret)
+ error(_("failed to remove: %s"), strerror(errno));
+ }
+ closedir(dir);
+ if (!show_only)
+ rmdir(git_path("worktrees"));
+ strbuf_release(&reason);
+ strbuf_release(&path);
+}
+
+static int prune(int ac, const char **av, const char *prefix)
+{
+ struct option options[] = {
+ OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
+ OPT__VERBOSE(&verbose, N_("report pruned objects")),
+ OPT_EXPIRY_DATE(0, "expire", &expire,
+ N_("expire objects older than <time>")),
+ OPT_END()
+ };
+
+ expire = ULONG_MAX;
+ ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ if (ac)
+ usage_with_options(worktree_usage, options);
+ prune_worktrees();
+ return 0;
+}
+
+static char *junk_work_tree;
+static char *junk_git_dir;
+static int is_junk;
+static pid_t junk_pid;
+
+static void remove_junk(void)
+{
+ struct strbuf sb = STRBUF_INIT;
+ if (!is_junk || getpid() != junk_pid)
+ return;
+ if (junk_git_dir) {
+ strbuf_addstr(&sb, junk_git_dir);
+ remove_dir_recursively(&sb, 0);
+ strbuf_reset(&sb);
+ }
+ if (junk_work_tree) {
+ strbuf_addstr(&sb, junk_work_tree);
+ remove_dir_recursively(&sb, 0);
+ }
+ strbuf_release(&sb);
+}
+
+static void remove_junk_on_signal(int signo)
+{
+ remove_junk();
+ sigchain_pop(signo);
+ raise(signo);
+}
+
+static const char *worktree_basename(const char *path, int *olen)
+{
+ const char *name;
+ int len;
+
+ len = strlen(path);
+ while (len && is_dir_sep(path[len - 1]))
+ len--;
+
+ for (name = path + len - 1; name > path; name--)
+ if (is_dir_sep(*name)) {
+ name++;
+ break;
+ }
+
+ *olen = len;
+ return name;
+}
+
+static int add_worktree(const char *path, const char **child_argv)
+{
+ struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
+ struct strbuf sb = STRBUF_INIT;
+ const char *name;
+ struct stat st;
+ struct child_process cp;
+ int counter = 0, len, ret;
+ unsigned char rev[20];
+
+ if (file_exists(path) && !is_empty_dir(path))
+ die(_("'%s' already exists"), path);
+
+ name = worktree_basename(path, &len);
+ strbuf_addstr(&sb_repo,
+ git_path("worktrees/%.*s", (int)(path + len - name), name));
+ len = sb_repo.len;
+ if (safe_create_leading_directories_const(sb_repo.buf))
+ die_errno(_("could not create leading directories of '%s'"),
+ sb_repo.buf);
+ while (!stat(sb_repo.buf, &st)) {
+ counter++;
+ strbuf_setlen(&sb_repo, len);
+ strbuf_addf(&sb_repo, "%d", counter);
+ }
+ name = strrchr(sb_repo.buf, '/') + 1;
+
+ junk_pid = getpid();
+ atexit(remove_junk);
+ sigchain_push_common(remove_junk_on_signal);
+
+ if (mkdir(sb_repo.buf, 0777))
+ die_errno(_("could not create directory of '%s'"), sb_repo.buf);
+ junk_git_dir = xstrdup(sb_repo.buf);
+ is_junk = 1;
+
+ /*
+ * lock the incomplete repo so prune won't delete it, unlock
+ * after the preparation is over.
+ */
+ strbuf_addf(&sb, "%s/locked", sb_repo.buf);
+ write_file(sb.buf, 1, "initializing\n");
+
+ strbuf_addf(&sb_git, "%s/.git", path);
+ if (safe_create_leading_directories_const(sb_git.buf))
+ die_errno(_("could not create leading directories of '%s'"),
+ sb_git.buf);
+ junk_work_tree = xstrdup(path);
+
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
+ write_file(sb.buf, 1, "%s\n", real_path(sb_git.buf));
+ write_file(sb_git.buf, 1, "gitdir: %s/worktrees/%s\n",
+ real_path(get_git_common_dir()), name);
+ /*
+ * This is to keep resolve_ref() happy. We need a valid HEAD
+ * or is_git_directory() will reject the directory. Moreover, HEAD
+ * in the new worktree must resolve to the same value as HEAD in
+ * the current tree since the command invoked to populate the new
+ * worktree will be handed the branch/ref specified by the user.
+ * For instance, if the user asks for the new worktree to be based
+ * at HEAD~5, then the resolved HEAD~5 in the new worktree must
+ * match the resolved HEAD~5 in the current tree in order to match
+ * the user's expectation.
+ */
+ if (!resolve_ref_unsafe("HEAD", 0, rev, NULL))
+ die(_("unable to resolve HEAD"));
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
+ write_file(sb.buf, 1, "%s\n", sha1_to_hex(rev));
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
+ write_file(sb.buf, 1, "../..\n");
+
+ fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
+
+ setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
+ setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);
+ setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
+ memset(&cp, 0, sizeof(cp));
+ cp.git_cmd = 1;
+ cp.argv = child_argv;
+ ret = run_command(&cp);
+ if (!ret) {
+ is_junk = 0;
+ free(junk_work_tree);
+ free(junk_git_dir);
+ junk_work_tree = NULL;
+ junk_git_dir = NULL;
+ }
+ strbuf_reset(&sb);
+ strbuf_addf(&sb, "%s/locked", sb_repo.buf);
+ unlink_or_warn(sb.buf);
+ strbuf_release(&sb);
+ strbuf_release(&sb_repo);
+ strbuf_release(&sb_git);
+ return ret;
+}
+
+static int add(int ac, const char **av, const char *prefix)
+{
+ int force = 0, detach = 0;
+ const char *new_branch = NULL, *new_branch_force = NULL;
+ const char *path, *branch;
+ struct argv_array cmd = ARGV_ARRAY_INIT;
+ struct option options[] = {
+ OPT__FORCE(&force, N_("checkout <branch> even if already checked out in other worktree")),
+ OPT_STRING('b', NULL, &new_branch, N_("branch"),
+ N_("create a new branch")),
+ OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
+ N_("create or reset a branch")),
+ OPT_BOOL(0, "detach", &detach, N_("detach HEAD at named commit")),
+ OPT_END()
+ };
+
+ ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ if (new_branch && new_branch_force)
+ die(_("-b and -B are mutually exclusive"));
+ if (ac < 1 || ac > 2)
+ usage_with_options(worktree_usage, options);
+
+ path = prefix ? prefix_filename(prefix, strlen(prefix), av[0]) : av[0];
+ branch = ac < 2 ? "HEAD" : av[1];
+
+ if (ac < 2 && !new_branch && !new_branch_force) {
+ int n;
+ const char *s = worktree_basename(path, &n);
+ new_branch = xstrndup(s, n);
+ }
+
+ argv_array_push(&cmd, "checkout");
+ if (force)
+ argv_array_push(&cmd, "--ignore-other-worktrees");
+ if (new_branch)
+ argv_array_pushl(&cmd, "-b", new_branch, NULL);
+ if (new_branch_force)
+ argv_array_pushl(&cmd, "-B", new_branch_force, NULL);
+ if (detach)
+ argv_array_push(&cmd, "--detach");
+ argv_array_push(&cmd, branch);
+
+ return add_worktree(path, cmd.argv);
+}
+
+int cmd_worktree(int ac, const char **av, const char *prefix)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+
+ if (ac < 2)
+ usage_with_options(worktree_usage, options);
+ if (!strcmp(av[1], "add"))
+ return add(ac - 1, av + 1, prefix);
+ if (!strcmp(av[1], "prune"))
+ return prune(ac - 1, av + 1, prefix);
+ usage_with_options(worktree_usage, options);
+}
diff --git a/cache.h b/cache.h
index 1c00098..6997b2c 100644
--- a/cache.h
+++ b/cache.h
@@ -397,6 +397,7 @@ static inline enum object_type object_type(unsigned int mode)
#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
#define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
#define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
+#define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE"
#define GITATTRIBUTES_FILE ".gitattributes"
#define INFOATTRIBUTES_FILE "info/attributes"
#define ATTRIBUTE_MACRO_PREFIX "[attr]"
@@ -446,7 +447,17 @@ extern int get_common_dir(struct strbuf *sb, const char *gitdir);
extern const char *get_git_namespace(void);
extern const char *strip_namespace(const char *namespaced_ref);
extern const char *get_git_work_tree(void);
-extern const char *read_gitfile(const char *path);
+
+#define READ_GITFILE_ERR_STAT_FAILED 1
+#define READ_GITFILE_ERR_NOT_A_FILE 2
+#define READ_GITFILE_ERR_OPEN_FAILED 3
+#define READ_GITFILE_ERR_READ_FAILED 4
+#define READ_GITFILE_ERR_INVALID_FORMAT 5
+#define READ_GITFILE_ERR_NO_PATH 6
+#define READ_GITFILE_ERR_NOT_A_REPO 7
+#define READ_GITFILE_ERR_TOO_LARGE 8
+extern const char *read_gitfile_gently(const char *path, int *return_error_code);
+#define read_gitfile(path) read_gitfile_gently((path), NULL)
extern const char *resolve_gitdir(const char *suspect);
extern void set_git_work_tree(const char *tree);
@@ -620,6 +631,7 @@ extern unsigned long pack_size_limit_cfg;
* been sought but there were none.
*/
extern int check_replace_refs;
+extern char *git_replace_ref_base;
extern int fsync_object_files;
extern int core_preload_index;
@@ -941,8 +953,17 @@ extern int has_sha1_pack(const unsigned char *sha1);
* Return true iff we have an object named sha1, whether local or in
* an alternate object database, and whether packed or loose. This
* function does not respect replace references.
+ *
+ * If the QUICK flag is set, do not re-check the pack directory
+ * when we cannot find the object (this means we may give a false
+ * negative answer if another process is simultaneously repacking).
*/
-extern int has_sha1_file(const unsigned char *sha1);
+#define HAS_SHA1_QUICK 0x1
+extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags);
+static inline int has_sha1_file(const unsigned char *sha1)
+{
+ return has_sha1_file_with_flags(sha1, 0);
+}
/*
* Return true iff an alternate object database has a loose object
@@ -1630,5 +1651,6 @@ int stat_validity_check(struct stat_validity *sv, const char *path);
void stat_validity_update(struct stat_validity *sv, int fd);
int versioncmp(const char *s1, const char *s2);
+void sleep_millisec(int millisec);
#endif /* CACHE_H */
diff --git a/command-list.txt b/command-list.txt
index b17c011..2a94137 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -148,4 +148,5 @@ git-verify-pack plumbinginterrogators
git-verify-tag ancillaryinterrogators
gitweb ancillaryinterrogators
git-whatchanged ancillaryinterrogators
+git-worktree mainporcelain
git-write-tree plumbingmanipulators
diff --git a/commit.c b/commit.c
index 6e2103c..62223a3 100644
--- a/commit.c
+++ b/commit.c
@@ -1232,33 +1232,24 @@ free_return:
free(buf);
}
-void check_commit_signature(const struct commit *commit, struct signature_check *sigc)
+int check_commit_signature(const struct commit *commit, struct signature_check *sigc)
{
struct strbuf payload = STRBUF_INIT;
struct strbuf signature = STRBUF_INIT;
- struct strbuf gpg_output = STRBUF_INIT;
- struct strbuf gpg_status = STRBUF_INIT;
- int status;
+ int ret = 1;
sigc->result = 'N';
if (parse_signed_commit(commit, &payload, &signature) <= 0)
goto out;
- status = verify_signed_buffer(payload.buf, payload.len,
- signature.buf, signature.len,
- &gpg_output, &gpg_status);
- if (status && !gpg_output.len)
- goto out;
- sigc->payload = strbuf_detach(&payload, NULL);
- sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
- sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
- parse_gpg_output(sigc);
+ ret = check_signature(payload.buf, payload.len, signature.buf,
+ signature.len, sigc);
out:
- strbuf_release(&gpg_status);
- strbuf_release(&gpg_output);
strbuf_release(&payload);
strbuf_release(&signature);
+
+ return ret;
}
diff --git a/commit.h b/commit.h
index 9a1fa96..4983bdd 100644
--- a/commit.h
+++ b/commit.h
@@ -379,7 +379,7 @@ extern void print_commit_list(struct commit_list *list,
* at all. This may allocate memory for sig->gpg_output, sig->gpg_status,
* sig->signer and sig->key.
*/
-extern void check_commit_signature(const struct commit *commit, struct signature_check *sigc);
+extern int check_commit_signature(const struct commit *commit, struct signature_check *sigc);
int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused);
diff --git a/config.c b/config.c
index 29fa012..9fd275f 100644
--- a/config.c
+++ b/config.c
@@ -2118,6 +2118,9 @@ int git_config_set_multivar_in_file(const char *config_filename,
contents_sz - copy_begin) <
contents_sz - copy_begin)
goto write_err_out;
+
+ munmap(contents, contents_sz);
+ contents = NULL;
}
if (commit_lock_file(lock) < 0) {
diff --git a/config.mak.uname b/config.mak.uname
index d26665f..943c439 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -102,6 +102,9 @@ ifeq ($(uname_S),Darwin)
ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2)
NO_STRLCPY = YesPlease
endif
+ ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 11 && echo 1),1)
+ HAVE_GETDELIM = YesPlease
+ endif
NO_MEMMEM = YesPlease
USE_ST_TIMESPEC = YesPlease
HAVE_DEV_TTY = YesPlease
diff --git a/configure.ac b/configure.ac
index bbdde85..14012fa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1041,6 +1041,12 @@ GIT_CHECK_FUNC(initgroups,
[NO_INITGROUPS=YesPlease])
GIT_CONF_SUBST([NO_INITGROUPS])
#
+# Define HAVE_GETDELIM if you have getdelim in the C library.
+GIT_CHECK_FUNC(getdelim,
+[HAVE_GETDELIM=YesPlease],
+[HAVE_GETDELIM=])
+GIT_CONF_SUBST([HAVE_GETDELIM])
+#
#
# Define NO_MMAP if you want to avoid mmap.
#
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 3c00acd..c97c648 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1108,7 +1108,7 @@ _git_commit ()
case "$cur" in
--cleanup=*)
- __gitcomp "default strip verbatim whitespace
+ __gitcomp "default scissors strip verbatim whitespace
" "" "${cur##--cleanup=}"
return
;;
diff --git a/contrib/completion/git-completion.tcsh b/contrib/completion/git-completion.tcsh
index 6104a42..4a790d8 100644
--- a/contrib/completion/git-completion.tcsh
+++ b/contrib/completion/git-completion.tcsh
@@ -41,7 +41,7 @@ if ( ! -e ${__git_tcsh_completion_original_script} ) then
exit
endif
-cat << EOF > ${__git_tcsh_completion_script}
+cat << EOF >! ${__git_tcsh_completion_script}
#!bash
#
# This script is GENERATED and will be overwritten automatically.
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index f18aedc..366f0bc 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -66,6 +66,10 @@
# git always compare HEAD to @{upstream}
# svn always compare HEAD to your SVN upstream
#
+# You can change the separator between the branch name and the above
+# state symbols by setting GIT_PS1_STATESEPARATOR. The default separator
+# is SP.
+#
# By default, __git_ps1 will compare HEAD to your SVN upstream if it can
# find one, or @{upstream} otherwise. Once you have set
# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
diff --git a/git-pull.sh b/contrib/examples/git-pull.sh
index 0917d0d..a814bf6 100755
--- a/git-pull.sh
+++ b/contrib/examples/git-pull.sh
@@ -4,13 +4,53 @@
#
# Fetch one or more remote refs and merge it/them into the current HEAD.
-USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff|--ff-only] [--[no-]rebase|--rebase=preserve] [-s strategy]... [<fetch-options>] <repo> <head>...'
-LONG_USAGE='Fetch one or more remote refs and integrate it/them with the current HEAD.'
SUBDIRECTORY_OK=Yes
-OPTIONS_SPEC=
+OPTIONS_KEEPDASHDASH=
+OPTIONS_STUCKLONG=Yes
+OPTIONS_SPEC="\
+git pull [options] [<repository> [<refspec>...]]
+
+Fetch one or more remote refs and integrate it/them with the current HEAD.
+--
+v,verbose be more verbose
+q,quiet be more quiet
+progress force progress reporting
+
+ Options related to merging
+r,rebase?false|true|preserve incorporate changes by rebasing rather than merging
+n! do not show a diffstat at the end of the merge
+stat show a diffstat at the end of the merge
+summary (synonym to --stat)
+log?n add (at most <n>) entries from shortlog to merge commit message
+squash create a single commit instead of doing a merge
+commit perform a commit if the merge succeeds (default)
+e,edit edit message before committing
+ff allow fast-forward
+ff-only! abort if fast-forward is not possible
+verify-signatures verify that the named commit has a valid GPG signature
+s,strategy=strategy merge strategy to use
+X,strategy-option=option option for selected merge strategy
+S,gpg-sign?key-id GPG sign commit
+
+ Options related to fetching
+all fetch from all remotes
+a,append append to .git/FETCH_HEAD instead of overwriting
+upload-pack=path path to upload pack on remote end
+f,force force overwrite of local branch
+t,tags fetch all tags and associated objects
+p,prune prune remote-tracking branches no longer on remote
+recurse-submodules?on-demand control recursive fetching of submodules
+dry-run dry run
+k,keep keep downloaded pack
+depth=depth deepen history of shallow clone
+unshallow convert to a complete repository
+update-shallow accept refs that update .git/shallow
+refmap=refmap specify fetch refmap
+"
+test $# -gt 0 && args="$*"
. git-sh-setup
. git-sh-i18n
-set_reflog_action "pull${1+ $*}"
+set_reflog_action "pull${args+ $args}"
require_work_tree_exists
cd_to_toplevel
@@ -44,7 +84,8 @@ bool_or_string_config () {
strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
log_arg= verbosity= progress= recurse_submodules= verify_signatures=
-merge_args= edit= rebase_args=
+merge_args= edit= rebase_args= all= append= upload_pack= force= tags= prune=
+keep= depth= unshallow= update_shallow= refmap=
curr_branch=$(git symbolic-ref -q HEAD)
curr_branch_short="${curr_branch#refs/heads/}"
rebase=$(bool_or_string_config branch.$curr_branch_short.rebase)
@@ -86,17 +127,17 @@ do
diffstat=--stat ;;
--log|--log=*|--no-log)
log_arg="$1" ;;
- --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)
+ --no-commit)
no_commit=--no-commit ;;
- --c|--co|--com|--comm|--commi|--commit)
+ --commit)
no_commit=--commit ;;
-e|--edit)
edit=--edit ;;
--no-edit)
edit=--no-edit ;;
- --sq|--squ|--squa|--squas|--squash)
+ --squash)
squash=--squash ;;
- --no-sq|--no-squ|--no-squa|--no-squas|--no-squash)
+ --no-squash)
squash=--no-squash ;;
--ff)
no_ff=--ff ;;
@@ -104,39 +145,19 @@ do
no_ff=--no-ff ;;
--ff-only)
ff_only=--ff-only ;;
- -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
- --strateg=*|--strategy=*|\
- -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
- case "$#,$1" in
- *,*=*)
- strategy=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
- 1,*)
- usage ;;
- *)
- strategy="$2"
- shift ;;
- esac
- strategy_args="${strategy_args}-s $strategy "
+ -s*|--strategy=*)
+ strategy_args="$strategy_args $1"
;;
- -X*)
- case "$#,$1" in
- 1,-X)
- usage ;;
- *,-X)
- xx="-X $(git rev-parse --sq-quote "$2")"
- shift ;;
- *,*)
- xx=$(git rev-parse --sq-quote "$1") ;;
- esac
- merge_args="$merge_args$xx "
+ -X*|--strategy-option=*)
+ merge_args="$merge_args $(git rev-parse --sq-quote "$1")"
;;
- -r=*|--r=*|--re=*|--reb=*|--reba=*|--rebas=*|--rebase=*)
+ -r*|--rebase=*)
rebase="${1#*=}"
;;
- -r|--r|--re|--reb|--reba|--rebas|--rebase)
+ --rebase)
rebase=true
;;
- --no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
+ --no-rebase)
rebase=false
;;
--recurse-submodules)
@@ -163,16 +184,41 @@ do
-S*)
gpg_sign_args=$(git rev-parse --sq-quote "$1")
;;
- --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)
+ --dry-run)
dry_run=--dry-run
;;
+ --all|--no-all)
+ all=$1 ;;
+ -a|--append|--no-append)
+ append=$1 ;;
+ --upload-pack=*|--no-upload-pack)
+ upload_pack=$1 ;;
+ -f|--force|--no-force)
+ force="$force $1" ;;
+ -t|--tags|--no-tags)
+ tags=$1 ;;
+ -p|--prune|--no-prune)
+ prune=$1 ;;
+ -k|--keep|--no-keep)
+ keep=$1 ;;
+ --depth=*|--no-depth)
+ depth=$1 ;;
+ --unshallow|--no-unshallow)
+ unshallow=$1 ;;
+ --update-shallow|--no-update-shallow)
+ update_shallow=$1 ;;
+ --refmap=*|--no-refmap)
+ refmap=$1 ;;
-h|--help-all)
usage
;;
- *)
- # Pass thru anything that may be meant for fetch.
+ --)
+ shift
break
;;
+ *)
+ usage
+ ;;
esac
shift
done
@@ -248,7 +294,9 @@ test true = "$rebase" && {
oldremoteref=$(git merge-base --fork-point "$remoteref" $curr_branch 2>/dev/null)
}
orig_head=$(git rev-parse -q --verify HEAD)
-git fetch $verbosity $progress $dry_run $recurse_submodules --update-head-ok "$@" || exit 1
+git fetch $verbosity $progress $dry_run $recurse_submodules $all $append \
+$upload_pack $force $tags $prune $keep $depth $unshallow $update_shallow \
+$refmap --update-head-ok "$@" || exit 1
test -z "$dry_run" || exit 0
curr_head=$(git rev-parse -q --verify HEAD)
diff --git a/contrib/hooks/multimail/CHANGES b/contrib/hooks/multimail/CHANGES
index 3603d56..6bb1230 100644
--- a/contrib/hooks/multimail/CHANGES
+++ b/contrib/hooks/multimail/CHANGES
@@ -1,3 +1,56 @@
+Release 1.1.1 (bugfix-only release)
+===================================
+
+* The SMTP mailer was not working with Python 2.4.
+
+Release 1.1.0
+=============
+
+* When a single commit is pushed, omit the reference changed email.
+ Set multimailhook.combineWhenSingleCommit to false to disable this
+ new feature.
+
+* In gitolite environments, the pusher's email address can be used as
+ the From address by creating a specially formatted comment block in
+ gitolite.conf (see multimailhook.from in README).
+
+* Support for SMTP authentication and SSL/TLS encryption was added,
+ see smtpUser, smtpPass, smtpEncryption in README.
+
+* A new option scanCommitForCc was added to allow git-multimail to
+ search the commit message for 'Cc: ...' lines, and add the
+ corresponding emails in Cc.
+
+* If $USER is not set, use the variable $USERNAME. This is needed on
+ Windows platform to recognize the pusher.
+
+* The emailPrefix variable can now be set to an empty string to remove
+ the prefix.
+
+* A short tutorial was added in doc/gitolite.rst to set up
+ git-multimail with gitolite.
+
+* The post-receive file was renamed to post-receive.example. It has
+ always been an example (the standard way to call git-multimail is to
+ call git_multimail.py), but it was unclear to many users.
+
+* A new refchangeShowGraph option was added to make it possible to
+ include both a graph and a log in the summary emails. The options
+ to control the graph formatting can be set via the new graphOpts
+ option.
+
+* New option --force-send was added to disable new commit detection
+ for update hook. One use-case is to run git_multimail.py after
+ running "git fetch" to send emails about commits that have just been
+ fetched (the detection of new commits was unreliable in this mode).
+
+* The testing infrastructure was considerably improved (continuous
+ integration with travis-ci, automatic check of PEP8 and RST syntax,
+ many improvements to the test scripts).
+
+This version has been tested with Python 2.4 to 2.7, and Git 1.7.1 to
+2.4.
+
Release 1.0.0
=============
diff --git a/contrib/hooks/multimail/README b/contrib/hooks/multimail/README
index 6efa4ff..e552c90 100644
--- a/contrib/hooks/multimail/README
+++ b/contrib/hooks/multimail/README
@@ -1,5 +1,8 @@
- git-multimail
- =============
+git-multimail Version 1.1.1
+===========================
+
+.. image:: https://travis-ci.org/git-multimail/git-multimail.svg?branch=master
+ :target: https://travis-ci.org/git-multimail/git-multimail
git-multimail is a tool for sending notification emails on pushes to a
Git repository. It includes a Python module called git_multimail.py,
@@ -38,17 +41,17 @@ By default, for each push received by the repository, git-multimail:
list) makes it easy to scan through the emails, jump to patches
that need further attention, and write comments about specific
commits. Commits are handled in reverse topological order (i.e.,
- parents shown before children). For example,
-
- [git] branch master updated
- + [git] 01/08: doc: fix xref link from api docs to manual pages
- + [git] 02/08: api-credentials.txt: show the big picture first
- + [git] 03/08: api-credentials.txt: mention credential.helper explicitly
- + [git] 04/08: api-credentials.txt: add "see also" section
- + [git] 05/08: t3510 (cherry-pick-sequence): add missing '&&'
- + [git] 06/08: Merge branch 'rr/maint-t3510-cascade-fix'
- + [git] 07/08: Merge branch 'mm/api-credentials-doc'
- + [git] 08/08: Git 1.7.11-rc2
+ parents shown before children). For example::
+
+ [git] branch master updated
+ + [git] 01/08: doc: fix xref link from api docs to manual pages
+ + [git] 02/08: api-credentials.txt: show the big picture first
+ + [git] 03/08: api-credentials.txt: mention credential.helper explicitly
+ + [git] 04/08: api-credentials.txt: add "see also" section
+ + [git] 05/08: t3510 (cherry-pick-sequence): add missing '&&'
+ + [git] 06/08: Merge branch 'rr/maint-t3510-cascade-fix'
+ + [git] 07/08: Merge branch 'mm/api-credentials-doc'
+ + [git] 08/08: Git 1.7.11-rc2
Each commit appears in exactly one commit email, the first time
that it is pushed to the repository. If a commit is later merged
@@ -74,19 +77,19 @@ Requirements
3.x.
The example scripts invoke Python using the following shebang line
- (following PEP 394 [1]):
+ (following PEP 394 [1]_)::
#! /usr/bin/env python2
If your system's Python2 interpreter is not in your PATH or is not
- called "python2", you can change the lines accordingly. Or you can
+ called ``python2``, you can change the lines accordingly. Or you can
invoke the Python interpreter explicitly, for example via a tiny
- shell script like
+ shell script like::
#! /bin/sh
/usr/local/bin/python /path/to/git_multimail.py "$@"
-* The "git" command must be in your PATH. git-multimail is known to
+* The ``git`` command must be in your PATH. git-multimail is known to
work with Git versions back to 1.7.1. (Earlier versions have not
been tested; if you do so, please report your results.)
@@ -101,7 +104,7 @@ Requirements
Invocation
----------
-git_multimail.py is designed to be used as a "post-receive" hook in a
+git_multimail.py is designed to be used as a ``post-receive`` hook in a
Git repository (see githooks(5)). Link or copy it to
$GIT_DIR/hooks/post-receive within the repository for which email
notifications are desired. Usually it should be installed on the
@@ -109,10 +112,10 @@ central repository for a project, to which all commits are eventually
pushed.
For use on pre-v1.5.1 Git servers, git_multimail.py can also work as
-an "update" hook, taking its arguments on the command line. To use
+an ``update`` hook, taking its arguments on the command line. To use
this script in this manner, link or copy it to $GIT_DIR/hooks/update.
Please note that the script is not completely reliable in this mode
-[2].
+[2]_.
Alternatively, git_multimail.py can be imported as a Python module
into your own Python post-receive script. This method is a bit more
@@ -129,7 +132,7 @@ arbitrary Python code. For example, you can use a custom environment
only about changes affecting particular files or subdirectories)
Or you can change how emails are sent by writing your own Mailer
-class. The "post-receive" script in this directory demonstrates how
+class. The ``post-receive`` script in this directory demonstrates how
to use git_multimail.py as a Python module. (If you make interesting
changes of this type, please consider sharing them with the
community.)
@@ -139,18 +142,26 @@ Configuration
-------------
By default, git-multimail mostly takes its configuration from the
-following "git config" settings:
+following ``git config`` settings:
multimailhook.environment
This describes the general environment of the repository.
Currently supported values:
- "generic" -- the username of the pusher is read from $USER and the
- repository name is derived from the repository's path.
+ * generic
+
+ the username of the pusher is read from $USER or $USERNAME and
+ the repository name is derived from the repository's path.
+
+ * gitolite
- "gitolite" -- the username of the pusher is read from $GL_USER and
- the repository name from $GL_REPO.
+ the username of the pusher is read from $GL_USER, the repository
+ name is read from $GL_REPO, and the From: header value is
+ optionally read from gitolite.conf (see multimailhook.from).
+
+ For more information about gitolite and git-multimail, read
+ doc/gitolite.rst
If neither of these environments is suitable for your setup, then
you can implement a Python class that inherits from Environment
@@ -160,8 +171,8 @@ multimailhook.environment
The environment value can be specified on the command line using
the --environment option. If it is not specified on the command
line or by multimailhook.environment, then it defaults to
- "gitolite" if the environment contains variables $GL_USER and
- $GL_REPO; otherwise "generic".
+ ``gitolite`` if the environment contains variables $GL_USER and
+ $GL_REPO; otherwise ``generic``.
multimailhook.repoName
@@ -219,61 +230,109 @@ multimailhook.announceShortlog
not so straightforward, then the shortlog might be confusing
rather than useful. Default is false.
+multimailhook.refchangeShowGraph
+
+ If this option is set to true, then summary emails about reference
+ changes will additionally include:
+
+ * a graph of the added commits (if any)
+
+ * a graph of the discarded commits (if any)
+
+ The log is generated by running ``git log --graph`` with the options
+ specified in graphOpts. The default is false.
+
multimailhook.refchangeShowLog
If this option is set to true, then summary emails about reference
changes will include a detailed log of the added commits in
addition to the one line summary. The log is generated by running
- "git log" with the options specified in multimailhook.logOpts.
+ ``git log`` with the options specified in multimailhook.logOpts.
Default is false.
multimailhook.mailer
This option changes the way emails are sent. Accepted values are:
- - sendmail (the default): use the command /usr/sbin/sendmail or
- /usr/lib/sendmail (or sendmailCommand, if configured). This
+ - sendmail (the default): use the command ``/usr/sbin/sendmail`` or
+ ``/usr/lib/sendmail`` (or sendmailCommand, if configured). This
mode can be further customized via the following options:
- multimailhook.sendmailCommand
+ * multimailhook.sendmailCommand
- The command used by mailer "sendmail" to send emails. Shell
- quoting is allowed in the value of this setting, but remember that
- Git requires double-quotes to be escaped; e.g.,
+ The command used by mailer ``sendmail`` to send emails. Shell
+ quoting is allowed in the value of this setting, but remember that
+ Git requires double-quotes to be escaped; e.g.::
git config multimailhook.sendmailcommand '/usr/sbin/sendmail -oi -t -F \"Git Repo\"'
- Default is '/usr/sbin/sendmail -oi -t' or
- '/usr/lib/sendmail -oi -t' (depending on which file is
- present and executable).
+ Default is '/usr/sbin/sendmail -oi -t' or
+ '/usr/lib/sendmail -oi -t' (depending on which file is
+ present and executable).
- multimailhook.envelopeSender
+ * multimailhook.envelopeSender
- If set then pass this value to sendmail via the -f option to set
- the envelope sender address.
+ If set then pass this value to sendmail via the -f option to set
+ the envelope sender address.
- smtp: use Python's smtplib. This is useful when the sendmail
command is not available on the system. This mode can be
further customized via the following options:
- multimailhook.smtpServer
+ * multimailhook.smtpServer
+
+ The name of the SMTP server to connect to. The value can
+ also include a colon and a port number; e.g.,
+ ``mail.example.com:25``. Default is 'localhost' using port 25.
+
+ * multimailhook.smtpUser
+ * multimailhook.smtpPass
+
+ Server username and password. Required if smtpEncryption is 'ssl'.
+ Note that the username and password currently need to be
+ set cleartext in the configuration file, which is not
+ recommended. If you need to use this option, be sure your
+ configuration file is read-only.
+
+ * multimailhook.envelopeSender
+
+ The sender address to be passed to the SMTP server. If
+ unset, then the value of multimailhook.from is used.
+
+ * multimailhook.smtpServerTimeout
+
+ Timeout in seconds.
- The name of the SMTP server to connect to. The value can
- also include a colon and a port number; e.g.,
- "mail.example.com:25". Default is 'localhost' using port
- 25.
+ * multimailhook.smtpEncryption
- multimailhook.envelopeSender
+ Set the security type. Allowed values: none, ssl.
+ Default=none.
- The sender address to be passed to the SMTP server. If
- unset, then the value of multimailhook.from is used.
+ * multimailhook.smtpServerDebugLevel
+
+ Integer number. Set to greater than 0 to activate debugging.
multimailhook.from
- If set then use this value in the From: field of generated emails.
- If unset, then use the repository's user configuration (user.name
- and user.email). If user.email is also unset, then use
- multimailhook.envelopeSender.
+ If set, use this value in the From: field of generated emails. If
+ unset, the value of the From: header is determined as follows:
+
+ 1. (gitolite environment only) Parse gitolite.conf, looking for a
+ block of comments that looks like this::
+
+ # BEGIN USER EMAILS
+ # username Firstname Lastname <email@example.com>
+ # END USER EMAILS
+
+ If that block exists, and there is a line between the BEGIN
+ USER EMAILS and END USER EMAILS lines where the first field
+ matches the gitolite username ($GL_USER), use the rest of the
+ line for the From: header.
+
+ 2. If the user.email configuration setting is set, use its value
+ (and the value of user.name, if set).
+
+ 3. Use the value of multimailhook.envelopeSender.
multimailhook.administrator
@@ -287,7 +346,8 @@ multimailhook.emailPrefix
All emails have this string prepended to their subjects, to aid
email filtering (though filtering based on the X-Git-* email
headers is probably more robust). Default is the short name of
- the repository in square brackets; e.g., "[myrepo]".
+ the repository in square brackets; e.g., ``[myrepo]``. Set this
+ value to the empty string to suppress the email prefix.
multimailhook.emailMaxLines
@@ -299,7 +359,7 @@ multimailhook.emailMaxLines
multimailhook.emailMaxLineLength
The maximum length of a line in the email body. Lines longer than
- this limit are truncated to this length with a trailing " [...]"
+ this limit are truncated to this length with a trailing `` [...]``
added to indicate the missing text. The default is 500, because
(a) diffs with longer lines are probably from binary files, for
which a diff is useless, and (b) even if a text file has such long
@@ -316,54 +376,62 @@ multimailhook.maxCommitEmails
multimailhook.emailStrictUTF8
- If this boolean option is set to "true", then the main part of the
+ If this boolean option is set to `true`, then the main part of the
email body is forced to be valid UTF-8. Any characters that are
not valid UTF-8 are converted to the Unicode replacement
- character, U+FFFD. The default is "true".
+ character, U+FFFD. The default is `true`.
multimailhook.diffOpts
- Options passed to "git diff-tree" when generating the summary
- information for ReferenceChange emails. Default is "--stat
- --summary --find-copies-harder". Add -p to those options to
+ Options passed to ``git diff-tree`` when generating the summary
+ information for ReferenceChange emails. Default is ``--stat
+ --summary --find-copies-harder``. Add -p to those options to
include a unified diff of changes in addition to the usual summary
output. Shell quoting is allowed; see multimailhook.logOpts for
details.
+multimailhook.graphOpts
+
+ Options passed to ``git log --graph`` when generating graphs for the
+ reference change summary emails (used only if refchangeShowGraph
+ is true). The default is '--oneline --decorate'.
+
+ Shell quoting is allowed; see logOpts for details.
+
multimailhook.logOpts
- Options passed to "git log" to generate additional info for
+ Options passed to ``git log`` to generate additional info for
reference change emails (used only if refchangeShowLog is set).
- For example, adding --graph will show the graph of revisions, -p
- will show the complete diff, etc. The default is empty.
+ For example, adding -p will show each commit's complete diff. The
+ default is empty.
Shell quoting is allowed; for example, a log format that contains
- spaces can be specified using something like:
+ spaces can be specified using something like::
git config multimailhook.logopts '--pretty=format:"%h %aN <%aE>%n%s%n%n%b%n"'
If you want to set this by editing your configuration file
directly, remember that Git requires double-quotes to be escaped
- (see git-config(1) for more information):
+ (see git-config(1) for more information)::
[multimailhook]
logopts = --pretty=format:\"%h %aN <%aE>%n%s%n%n%b%n\"
multimailhook.commitLogOpts
- Options passed to "git log" to generate additional info for
+ Options passed to ``git log`` to generate additional info for
revision change emails. For example, adding --ignore-all-spaces
- will suppress whitespace changes. The default options are "-C
- --stat -p --cc". Shell quoting is allowed; see
+ will suppress whitespace changes. The default options are ``-C
+ --stat -p --cc``. Shell quoting is allowed; see
multimailhook.logOpts for details.
multimailhook.emailDomain
Domain name appended to the username of the person doing the push
- to convert it into an email address (via "%s@%s" % (username,
- emaildomain)). More complicated schemes can be implemented by
- overriding Environment and overriding its get_pusher_email()
- method.
+ to convert it into an email address
+ (via ``"%s@%s" % (username, emaildomain)``). More complicated
+ schemes can be implemented by overriding Environment and
+ overriding its get_pusher_email() method.
multimailhook.replyTo
multimailhook.replyToCommit
@@ -377,26 +445,48 @@ multimailhook.replyToRefchange
- An email address, which will be used directly.
- - The value "pusher", in which case the pusher's address (if
+ - The value `pusher`, in which case the pusher's address (if
available) will be used. This is the default for refchange
emails.
- - The value "author" (meaningful only for replyToCommit), in which
+ - The value `author` (meaningful only for replyToCommit), in which
case the commit author's address will be used. This is the
default for commit emails.
- - The value "none", in which case the Reply-To: field will be
+ - The value `none`, in which case the Reply-To: field will be
omitted.
+multimailhook.quiet
+
+ Do not output the list of email recipients from the hook
+
+multimailhook.stdout
+
+ For debugging, send emails to stdout rather than to the
+ mailer. Equivalent to the --stdout command line option
+
+multimailhook.scanCommitForCc
+
+ If this option is set to true, than recipients from lines in commit body
+ that starts with ``CC:`` will be added to CC list.
+ Default: false
+
+multimailhook.combineWhenSingleCommit
+
+ If this option is set to true and a single new commit is pushed to
+ a branch, combine the summary and commit email messages into a
+ single email.
+ Default: true
+
Email filtering aids
--------------------
All emails include extra headers to enable fine tuned filtering and
give information for debugging. All emails include the headers
-"X-Git-Host", "X-Git-Repo", "X-Git-Refname", and "X-Git-Reftype".
-ReferenceChange emails also include headers "X-Git-Oldrev" and "X-Git-Newrev";
-Revision emails also include header "X-Git-Rev".
+``X-Git-Host``, ``X-Git-Repo``, ``X-Git-Refname``, and ``X-Git-Reftype``.
+ReferenceChange emails also include headers ``X-Git-Oldrev`` and ``X-Git-Newrev``;
+Revision emails also include header ``X-Git-Rev``.
Customizing email contents
@@ -420,16 +510,17 @@ environment are built in:
* GenericEnvironment: a stand-alone Git repository.
* GitoliteEnvironment: a Git repository that is managed by gitolite
- [3]. For such repositories, the identity of the pusher is read from
- environment variable $GL_USER, and the name of the repository is
- read from $GL_REPO (if it is not overridden by
- multimailhook.reponame).
+ [3]_. For such repositories, the identity of the pusher is read from
+ environment variable $GL_USER, the name of the repository is read
+ from $GL_REPO (if it is not overridden by multimailhook.reponame),
+ and the From: header value is optionally read from gitolite.conf
+ (see multimailhook.from).
By default, git-multimail assumes GitoliteEnvironment if $GL_USER and
$GL_REPO are set, and otherwise assumes GenericEnvironment.
Alternatively, you can choose one of these two environments explicitly
-by setting a "multimailhook.environment" config setting (which can
-have the value "generic" or "gitolite") or by passing an --environment
+by setting a ``multimailhook.environment`` config setting (which can
+have the value `generic` or `gitolite`) or by passing an --environment
option to the script.
If you need to customize the script in ways that are not supported by
@@ -439,8 +530,8 @@ git_multimail.py as a Python module, as demonstrated by the example
post-receive script. Then implement your environment class; it should
usually inherit from one of the existing Environment classes and
possibly one or more of the EnvironmentMixin classes. Then set the
-"environment" variable to an instance of your own environment class
-and pass it to run_as_post_receive_hook().
+``environment`` variable to an instance of your own environment class
+and pass it to ``run_as_post_receive_hook()``.
The standard environment classes, GenericEnvironment and
GitoliteEnvironment, are in fact themselves put together out of a
@@ -490,12 +581,14 @@ don't overlook them.
Footnotes
---------
-[1] http://www.python.org/dev/peps/pep-0394/
+.. [1] http://www.python.org/dev/peps/pep-0394/
-[2] Because of the way information is passed to update hooks, the
- script's method of determining whether a commit has already been
- seen does not work when it is used as an "update" script. In
- particular, no notification email will be generated for a new
- commit that is added to multiple references in the same push.
+.. [2] Because of the way information is passed to update hooks, the
+ script's method of determining whether a commit has already
+ been seen does not work when it is used as an ``update`` script.
+ In particular, no notification email will be generated for a
+ new commit that is added to multiple references in the same
+ push. A workaround is to use --force-send to force sending the
+ emails.
-[3] https://github.com/sitaramc/gitolite
+.. [3] https://github.com/sitaramc/gitolite
diff --git a/contrib/hooks/multimail/README.Git b/contrib/hooks/multimail/README.Git
index ab3ece5..f5d59a8 100644
--- a/contrib/hooks/multimail/README.Git
+++ b/contrib/hooks/multimail/README.Git
@@ -6,10 +6,10 @@ website:
https://github.com/git-multimail/git-multimail
The version in this directory was obtained from the upstream project
-on 2015-04-27 and consists of the "git-multimail" subdirectory from
+on July 03 2015 and consists of the "git-multimail" subdirectory from
revision
- 8c3aaafa873bf10de8dddf1d202c449b3eff3b42 refs/tags/1.0.2
+ 6d6c9eb62a054143322cfaecde3949189c065b46 refs/tags/1.1.1
Please see the README file in this directory for information about how
to report bugs or contribute to git-multimail.
diff --git a/contrib/hooks/multimail/git_multimail.py b/contrib/hooks/multimail/git_multimail.py
index 8b58ed6..c06ce7a 100755
--- a/contrib/hooks/multimail/git_multimail.py
+++ b/contrib/hooks/multimail/git_multimail.py
@@ -1,5 +1,6 @@
#! /usr/bin/env python2
+# Copyright (c) 2015 Matthieu Moy and others
# Copyright (c) 2012-2014 Michael Haggerty and others
# Derived from contrib/hooks/post-receive-email, which is
# Copyright (c) 2007 Andy Parkins
@@ -99,6 +100,10 @@ REF_DELETED_SUBJECT_TEMPLATE = (
' (was %(oldrev_short)s)'
)
+COMBINED_REFCHANGE_REVISION_SUBJECT_TEMPLATE = (
+ '%(emailprefix)s%(refname_type)s %(short_refname)s updated: %(oneline)s'
+ )
+
REFCHANGE_HEADER_TEMPLATE = """\
Date: %(send_date)s
To: %(recipients)s
@@ -230,6 +235,7 @@ how to provide full information about this reference change.
REVISION_HEADER_TEMPLATE = """\
Date: %(send_date)s
To: %(recipients)s
+Cc: %(cc_recipients)s
Subject: %(emailprefix)s%(num)02d/%(tot)02d: %(oneline)s
MIME-Version: 1.0
Content-Type: text/plain; charset=%(charset)s
@@ -258,6 +264,38 @@ in repository %(repo_shortname)s.
REVISION_FOOTER_TEMPLATE = FOOTER_TEMPLATE
+# Combined, meaning refchange+revision email (for single-commit additions)
+COMBINED_HEADER_TEMPLATE = """\
+Date: %(send_date)s
+To: %(recipients)s
+Subject: %(subject)s
+MIME-Version: 1.0
+Content-Type: text/plain; charset=%(charset)s
+Content-Transfer-Encoding: 8bit
+Message-ID: %(msgid)s
+From: %(fromaddr)s
+Reply-To: %(reply_to)s
+X-Git-Host: %(fqdn)s
+X-Git-Repo: %(repo_shortname)s
+X-Git-Refname: %(refname)s
+X-Git-Reftype: %(refname_type)s
+X-Git-Oldrev: %(oldrev)s
+X-Git-Newrev: %(newrev)s
+X-Git-Rev: %(rev)s
+Auto-Submitted: auto-generated
+"""
+
+COMBINED_INTRO_TEMPLATE = """\
+This is an automated email from the git hooks/post-receive script.
+
+%(pusher)s pushed a commit to %(refname_type)s %(short_refname)s
+in repository %(repo_shortname)s.
+
+"""
+
+COMBINED_FOOTER_TEMPLATE = FOOTER_TEMPLATE
+
+
class CommandError(Exception):
def __init__(self, cmd, retcode):
self.cmd = cmd
@@ -336,6 +374,47 @@ def read_git_lines(args, keepends=False, **kw):
return read_git_output(args, keepends=True, **kw).splitlines(keepends)
+def git_rev_list_ish(cmd, spec, args=None, **kw):
+ """Common functionality for invoking a 'git rev-list'-like command.
+
+ Parameters:
+ * cmd is the Git command to run, e.g., 'rev-list' or 'log'.
+ * spec is a list of revision arguments to pass to the named
+ command. If None, this function returns an empty list.
+ * args is a list of extra arguments passed to the named command.
+ * All other keyword arguments (if any) are passed to the
+ underlying read_git_lines() function.
+
+ Return the output of the Git command in the form of a list, one
+ entry per output line.
+ """
+ if spec is None:
+ return []
+ if args is None:
+ args = []
+ args = [cmd, '--stdin'] + args
+ spec_stdin = ''.join(s + '\n' for s in spec)
+ return read_git_lines(args, input=spec_stdin, **kw)
+
+
+def git_rev_list(spec, **kw):
+ """Run 'git rev-list' with the given list of revision arguments.
+
+ See git_rev_list_ish() for parameter and return value
+ documentation.
+ """
+ return git_rev_list_ish('rev-list', spec, **kw)
+
+
+def git_log(spec, **kw):
+ """Run 'git log' with the given list of revision arguments.
+
+ See git_rev_list_ish() for parameter and return value
+ documentation.
+ """
+ return git_rev_list_ish('log', spec, **kw)
+
+
def header_encode(text, header_name=None):
"""Encode and line-wrap the value of an email header field."""
@@ -388,9 +467,9 @@ class Config(object):
def get(self, name, default=None):
try:
values = self._split(read_git_output(
- ['config', '--get', '--null', '%s.%s' % (self.section, name)],
- env=self.env, keepends=True,
- ))
+ ['config', '--get', '--null', '%s.%s' % (self.section, name)],
+ env=self.env, keepends=True,
+ ))
assert len(values) == 1
return values[0]
except CommandError:
@@ -449,9 +528,14 @@ class Config(object):
env=self.env,
)
- def has_key(self, name):
+ def __contains__(self, name):
return self.get_all(name, default=None) is not None
+ # We don't use this method anymore internally, but keep it here in
+ # case somebody is calling it from their own code:
+ def has_key(self, name):
+ return name in self
+
def unset_all(self, name):
try:
read_git_output(
@@ -579,7 +663,7 @@ class Change(object):
self._values = None
def _compute_values(self):
- """Return a dictionary {keyword : expansion} for this Change.
+ """Return a dictionary {keyword: expansion} for this Change.
Derived classes overload this method to add more entries to
the return value. This method is used internally by
@@ -589,7 +673,7 @@ class Change(object):
return self.environment.get_values()
def get_values(self, **extra_values):
- """Return a dictionary {keyword : expansion} for this Change.
+ """Return a dictionary {keyword: expansion} for this Change.
Return a dictionary mapping keywords to the values that they
should be expanded to for this Change (used when interpolating
@@ -636,7 +720,7 @@ class Change(object):
value = value % values
except KeyError, e:
if DEBUG:
- sys.stderr.write(
+ self.environment.log_warning(
'Warning: unknown variable %r in the following line; line skipped:\n'
' %s\n'
% (e.args[0], line,)
@@ -711,6 +795,8 @@ class Change(object):
class Revision(Change):
"""A Change consisting of a single git commit."""
+ CC_RE = re.compile(r'^\s*C[Cc]:\s*(?P<to>[^#]+@[^\s#]*)\s*(#.*)?$')
+
def __init__(self, reference_change, rev, num, tot):
Change.__init__(self, reference_change.environment)
self.reference_change = reference_change
@@ -722,6 +808,24 @@ class Revision(Change):
self.author = read_git_output(['log', '--no-walk', '--format=%aN <%aE>', self.rev.sha1])
self.recipients = self.environment.get_revision_recipients(self)
+ self.cc_recipients = ''
+ if self.environment.get_scancommitforcc():
+ self.cc_recipients = ', '.join(to.strip() for to in self._cc_recipients())
+ if self.cc_recipients:
+ self.environment.log_msg(
+ 'Add %s to CC for %s\n' % (self.cc_recipients, self.rev.sha1))
+
+ def _cc_recipients(self):
+ cc_recipients = []
+ message = read_git_output(['log', '--no-walk', '--format=%b', self.rev.sha1])
+ lines = message.strip().split('\n')
+ for line in lines:
+ m = re.match(self.CC_RE, line)
+ if m:
+ cc_recipients.append(m.group('to'))
+
+ return cc_recipients
+
def _compute_values(self):
values = Change._compute_values(self)
@@ -739,6 +843,8 @@ class Revision(Change):
values['num'] = self.num
values['tot'] = self.tot
values['recipients'] = self.recipients
+ if self.cc_recipients:
+ values['cc_recipients'] = self.cc_recipients
values['oneline'] = oneline
values['author'] = self.author
@@ -750,8 +856,8 @@ class Revision(Change):
def generate_email_header(self, **extra_values):
for line in self.expand_header_lines(
- REVISION_HEADER_TEMPLATE, **extra_values
- ):
+ REVISION_HEADER_TEMPLATE, **extra_values
+ ):
yield line
def generate_email_intro(self):
@@ -822,26 +928,26 @@ class ReferenceChange(Change):
klass = BranchChange
elif area == 'remotes':
# Tracking branch:
- sys.stderr.write(
+ environment.log_warning(
'*** Push-update of tracking branch %r\n'
'*** - incomplete email generated.\n'
- % (refname,)
+ % (refname,)
)
klass = OtherReferenceChange
else:
# Some other reference namespace:
- sys.stderr.write(
+ environment.log_warning(
'*** Push-update of strange reference %r\n'
'*** - incomplete email generated.\n'
- % (refname,)
+ % (refname,)
)
klass = OtherReferenceChange
else:
# Anything else (is there anything else?)
- sys.stderr.write(
+ environment.log_warning(
'*** Unknown type of update to %r (%s)\n'
'*** - incomplete email generated.\n'
- % (refname, rev.type,)
+ % (refname, rev.type,)
)
klass = OtherReferenceChange
@@ -854,9 +960,9 @@ class ReferenceChange(Change):
def __init__(self, environment, refname, short_refname, old, new, rev):
Change.__init__(self, environment)
self.change_type = {
- (False, True) : 'create',
- (True, True) : 'update',
- (True, False) : 'delete',
+ (False, True): 'create',
+ (True, True): 'update',
+ (True, False): 'delete',
}[bool(old), bool(new)]
self.refname = refname
self.short_refname = short_refname
@@ -865,10 +971,16 @@ class ReferenceChange(Change):
self.rev = rev
self.msgid = make_msgid()
self.diffopts = environment.diffopts
+ self.graphopts = environment.graphopts
self.logopts = environment.logopts
self.commitlogopts = environment.commitlogopts
+ self.showgraph = environment.refchange_showgraph
self.showlog = environment.refchange_showlog
+ self.header_template = REFCHANGE_HEADER_TEMPLATE
+ self.intro_template = REFCHANGE_INTRO_TEMPLATE
+ self.footer_template = FOOTER_TEMPLATE
+
def _compute_values(self):
values = Change._compute_values(self)
@@ -894,11 +1006,39 @@ class ReferenceChange(Change):
return values
+ def send_single_combined_email(self, known_added_sha1s):
+ """Determine if a combined refchange/revision email should be sent
+
+ If there is only a single new (non-merge) commit added by a
+ change, it is useful to combine the ReferenceChange and
+ Revision emails into one. In such a case, return the single
+ revision; otherwise, return None.
+
+ This method is overridden in BranchChange."""
+
+ return None
+
+ def generate_combined_email(self, push, revision, body_filter=None, extra_header_values={}):
+ """Generate an email describing this change AND specified revision.
+
+ Iterate over the lines (including the header lines) of an
+ email describing this change. If body_filter is not None,
+ then use it to filter the lines that are intended for the
+ email body.
+
+ The extra_header_values field is received as a dict and not as
+ **kwargs, to allow passing other keyword arguments in the
+ future (e.g. passing extra values to generate_email_intro()
+
+ This method is overridden in BranchChange."""
+
+ raise NotImplementedError
+
def get_subject(self):
template = {
- 'create' : REF_CREATED_SUBJECT_TEMPLATE,
- 'update' : REF_UPDATED_SUBJECT_TEMPLATE,
- 'delete' : REF_DELETED_SUBJECT_TEMPLATE,
+ 'create': REF_CREATED_SUBJECT_TEMPLATE,
+ 'update': REF_UPDATED_SUBJECT_TEMPLATE,
+ 'delete': REF_DELETED_SUBJECT_TEMPLATE,
}[self.change_type]
return self.expand(template)
@@ -907,12 +1047,12 @@ class ReferenceChange(Change):
extra_values['subject'] = self.get_subject()
for line in self.expand_header_lines(
- REFCHANGE_HEADER_TEMPLATE, **extra_values
- ):
+ self.header_template, **extra_values
+ ):
yield line
def generate_email_intro(self):
- for line in self.expand_lines(REFCHANGE_INTRO_TEMPLATE):
+ for line in self.expand_lines(self.intro_template):
yield line
def generate_email_body(self, push):
@@ -922,9 +1062,9 @@ class ReferenceChange(Change):
generate_update_summary() / generate_delete_summary()."""
change_summary = {
- 'create' : self.generate_create_summary,
- 'delete' : self.generate_delete_summary,
- 'update' : self.generate_update_summary,
+ 'create': self.generate_create_summary,
+ 'delete': self.generate_delete_summary,
+ 'update': self.generate_update_summary,
}[self.change_type](push)
for line in change_summary:
yield line
@@ -933,7 +1073,23 @@ class ReferenceChange(Change):
yield line
def generate_email_footer(self):
- return self.expand_lines(FOOTER_TEMPLATE)
+ return self.expand_lines(self.footer_template)
+
+ def generate_revision_change_graph(self, push):
+ if self.showgraph:
+ args = ['--graph'] + self.graphopts
+ for newold in ('new', 'old'):
+ has_newold = False
+ spec = push.get_commits_spec(newold, self)
+ for line in git_log(spec, args=args, keepends=True):
+ if not has_newold:
+ has_newold = True
+ yield '\n'
+ yield 'Graph of %s commits:\n\n' % (
+ {'new': 'new', 'old': 'discarded'}[newold],)
+ yield ' ' + line
+ if has_newold:
+ yield '\n'
def generate_revision_change_log(self, new_commits_list):
if self.showlog:
@@ -945,9 +1101,17 @@ class ReferenceChange(Change):
+ new_commits_list
+ ['--'],
keepends=True,
- ):
+ ):
yield line
+ def generate_new_revision_summary(self, tot, new_commits_list, push):
+ for line in self.expand_lines(NEW_REVISIONS_TEMPLATE, tot=tot):
+ yield line
+ for line in self.generate_revision_change_graph(push):
+ yield line
+ for line in self.generate_revision_change_log(new_commits_list):
+ yield line
+
def generate_revision_change_summary(self, push):
"""Generate a summary of the revisions added/removed by this change."""
@@ -960,7 +1124,7 @@ class ReferenceChange(Change):
sha1s.reverse()
tot = len(sha1s)
new_revisions = [
- Revision(self, GitObject(sha1), num=i+1, tot=tot)
+ Revision(self, GitObject(sha1), num=i + 1, tot=tot)
for (i, sha1) in enumerate(sha1s)
]
@@ -973,9 +1137,8 @@ class ReferenceChange(Change):
BRIEF_SUMMARY_TEMPLATE, action='new', text=subject,
)
yield '\n'
- for line in self.expand_lines(NEW_REVISIONS_TEMPLATE, tot=tot):
- yield line
- for line in self.generate_revision_change_log([r.rev.sha1 for r in new_revisions]):
+ for line in self.generate_new_revision_summary(
+ tot, [r.rev.sha1 for r in new_revisions], push):
yield line
else:
for line in self.expand_lines(NO_NEW_REVISIONS_TEMPLATE):
@@ -993,16 +1156,16 @@ class ReferenceChange(Change):
# revisions in the summary even though we will not send
# new notification emails for them.
adds = list(generate_summaries(
- '--topo-order', '--reverse', '%s..%s'
- % (self.old.commit_sha1, self.new.commit_sha1,)
- ))
+ '--topo-order', '--reverse', '%s..%s'
+ % (self.old.commit_sha1, self.new.commit_sha1,)
+ ))
# List of the revisions that were removed from the branch
# by this update. This will be empty except for
# non-fast-forward updates.
discards = list(generate_summaries(
- '%s..%s' % (self.new.commit_sha1, self.old.commit_sha1,)
- ))
+ '%s..%s' % (self.new.commit_sha1, self.old.commit_sha1,)
+ ))
if adds:
new_commits_list = push.get_new_commits(self)
@@ -1071,13 +1234,14 @@ class ReferenceChange(Change):
yield '\n'
if new_commits:
- for line in self.expand_lines(NEW_REVISIONS_TEMPLATE, tot=len(new_commits)):
- yield line
- for line in self.generate_revision_change_log(new_commits_list):
+ for line in self.generate_new_revision_summary(
+ len(new_commits), new_commits_list, push):
yield line
else:
for line in self.expand_lines(NO_NEW_REVISIONS_TEMPLATE):
yield line
+ for line in self.generate_revision_change_graph(push):
+ yield line
# The diffstat is shown from the old revision to the new
# revision. This is to show the truth of what happened in
@@ -1089,11 +1253,11 @@ class ReferenceChange(Change):
yield '\n'
yield 'Summary of changes:\n'
for line in read_git_lines(
- ['diff-tree']
- + self.diffopts
- + ['%s..%s' % (self.old.commit_sha1, self.new.commit_sha1,)],
- keepends=True,
- ):
+ ['diff-tree']
+ + self.diffopts
+ + ['%s..%s' % (self.old.commit_sha1, self.new.commit_sha1,)],
+ keepends=True,
+ ):
yield line
elif self.old.commit_sha1 and not self.new.commit_sha1:
@@ -1103,7 +1267,7 @@ class ReferenceChange(Change):
sha1s = list(push.get_discarded_commits(self))
tot = len(sha1s)
discarded_revisions = [
- Revision(self, GitObject(sha1), num=i+1, tot=tot)
+ Revision(self, GitObject(sha1), num=i + 1, tot=tot)
for (i, sha1) in enumerate(sha1s)
]
@@ -1116,6 +1280,8 @@ class ReferenceChange(Change):
yield r.expand(
BRIEF_SUMMARY_TEMPLATE, action='discards', text=subject,
)
+ for line in self.generate_revision_change_graph(push):
+ yield line
else:
for line in self.expand_lines(NO_DISCARDED_REVISIONS_TEMPLATE):
yield line
@@ -1161,6 +1327,150 @@ class BranchChange(ReferenceChange):
old=old, new=new, rev=rev,
)
self.recipients = environment.get_refchange_recipients(self)
+ self._single_revision = None
+
+ def send_single_combined_email(self, known_added_sha1s):
+ if not self.environment.combine_when_single_commit:
+ return None
+
+ # In the sadly-all-too-frequent usecase of people pushing only
+ # one of their commits at a time to a repository, users feel
+ # the reference change summary emails are noise rather than
+ # important signal. This is because, in this particular
+ # usecase, there is a reference change summary email for each
+ # new commit, and all these summaries do is point out that
+ # there is one new commit (which can readily be inferred by
+ # the existence of the individual revision email that is also
+ # sent). In such cases, our users prefer there to be a combined
+ # reference change summary/new revision email.
+ #
+ # So, if the change is an update and it doesn't discard any
+ # commits, and it adds exactly one non-merge commit (gerrit
+ # forces a workflow where every commit is individually merged
+ # and the git-multimail hook fired off for just this one
+ # change), then we send a combined refchange/revision email.
+ try:
+ # If this change is a reference update that doesn't discard
+ # any commits...
+ if self.change_type != 'update':
+ return None
+
+ if read_git_lines(
+ ['merge-base', self.old.sha1, self.new.sha1]
+ ) != [self.old.sha1]:
+ return None
+
+ # Check if this update introduced exactly one non-merge
+ # commit:
+
+ def split_line(line):
+ """Split line into (sha1, [parent,...])."""
+
+ words = line.split()
+ return (words[0], words[1:])
+
+ # Get the new commits introduced by the push as a list of
+ # (sha1, [parent,...])
+ new_commits = [
+ split_line(line)
+ for line in read_git_lines(
+ [
+ 'log', '-3', '--format=%H %P',
+ '%s..%s' % (self.old.sha1, self.new.sha1),
+ ]
+ )
+ ]
+
+ if not new_commits:
+ return None
+
+ # If the newest commit is a merge, save it for a later check
+ # but otherwise ignore it
+ merge = None
+ tot = len(new_commits)
+ if len(new_commits[0][1]) > 1:
+ merge = new_commits[0][0]
+ del new_commits[0]
+
+ # Our primary check: we can't combine if more than one commit
+ # is introduced. We also currently only combine if the new
+ # commit is a non-merge commit, though it may make sense to
+ # combine if it is a merge as well.
+ if not (
+ len(new_commits) == 1
+ and len(new_commits[0][1]) == 1
+ and new_commits[0][0] in known_added_sha1s
+ ):
+ return None
+
+ # We do not want to combine revision and refchange emails if
+ # those go to separate locations.
+ rev = Revision(self, GitObject(new_commits[0][0]), 1, tot)
+ if rev.recipients != self.recipients:
+ return None
+
+ # We ignored the newest commit if it was just a merge of the one
+ # commit being introduced. But we don't want to ignore that
+ # merge commit it it involved conflict resolutions. Check that.
+ if merge and merge != read_git_output(['diff-tree', '--cc', merge]):
+ return None
+
+ # We can combine the refchange and one new revision emails
+ # into one. Return the Revision that a combined email should
+ # be sent about.
+ return rev
+ except CommandError:
+ # Cannot determine number of commits in old..new or new..old;
+ # don't combine reference/revision emails:
+ return None
+
+ def generate_combined_email(self, push, revision, body_filter=None, extra_header_values={}):
+ values = revision.get_values()
+ if extra_header_values:
+ values.update(extra_header_values)
+ if 'subject' not in extra_header_values:
+ values['subject'] = self.expand(COMBINED_REFCHANGE_REVISION_SUBJECT_TEMPLATE, **values)
+
+ self._single_revision = revision
+ self.header_template = COMBINED_HEADER_TEMPLATE
+ self.intro_template = COMBINED_INTRO_TEMPLATE
+ self.footer_template = COMBINED_FOOTER_TEMPLATE
+ for line in self.generate_email(push, body_filter, values):
+ yield line
+
+ def generate_email_body(self, push):
+ '''Call the appropriate body generation routine.
+
+ If this is a combined refchange/revision email, the special logic
+ for handling this combined email comes from this function. For
+ other cases, we just use the normal handling.'''
+
+ # If self._single_revision isn't set; don't override
+ if not self._single_revision:
+ for line in super(BranchChange, self).generate_email_body(push):
+ yield line
+ return
+
+ # This is a combined refchange/revision email; we first provide
+ # some info from the refchange portion, and then call the revision
+ # generate_email_body function to handle the revision portion.
+ adds = list(generate_summaries(
+ '--topo-order', '--reverse', '%s..%s'
+ % (self.old.commit_sha1, self.new.commit_sha1,)
+ ))
+
+ yield self.expand("The following commit(s) were added to %(refname)s by this push:\n")
+ for (sha1, subject) in adds:
+ yield self.expand(
+ BRIEF_SUMMARY_TEMPLATE, action='new',
+ rev_short=sha1, text=subject,
+ )
+
+ yield self._single_revision.rev.short + " is described below\n"
+ yield '\n'
+
+ for line in self._single_revision.generate_email_body(push):
+ yield line
class AnnotatedTagChange(ReferenceChange):
@@ -1390,13 +1700,17 @@ class SendMailer(Mailer):
sys.exit(1)
try:
p.stdin.writelines(lines)
- except:
+ except Exception, e:
sys.stderr.write(
'*** Error while generating commit email\n'
'*** - mail sending aborted.\n'
)
- p.terminate()
- raise
+ try:
+ # subprocess.terminate() is not available in Python 2.4
+ p.terminate()
+ except AttributeError:
+ pass
+ raise e
else:
p.stdin.close()
retcode = p.wait()
@@ -1407,34 +1721,78 @@ class SendMailer(Mailer):
class SMTPMailer(Mailer):
"""Send emails using Python's smtplib."""
- def __init__(self, envelopesender, smtpserver):
+ def __init__(self, envelopesender, smtpserver,
+ smtpservertimeout=10.0, smtpserverdebuglevel=0,
+ smtpencryption='none',
+ smtpuser='', smtppass='',
+ ):
if not envelopesender:
sys.stderr.write(
'fatal: git_multimail: cannot use SMTPMailer without a sender address.\n'
'please set either multimailhook.envelopeSender or user.email\n'
)
sys.exit(1)
+ if smtpencryption == 'ssl' and not (smtpuser and smtppass):
+ raise ConfigurationException(
+ 'Cannot use SMTPMailer with security option ssl '
+ 'without options username and password.'
+ )
self.envelopesender = envelopesender
self.smtpserver = smtpserver
+ self.smtpservertimeout = smtpservertimeout
+ self.smtpserverdebuglevel = smtpserverdebuglevel
+ self.security = smtpencryption
+ self.username = smtpuser
+ self.password = smtppass
try:
- self.smtp = smtplib.SMTP(self.smtpserver)
+ def call(klass, server, timeout):
+ try:
+ return klass(server, timeout=timeout)
+ except TypeError:
+ # Old Python versions do not have timeout= argument.
+ return klass(server)
+ if self.security == 'none':
+ self.smtp = call(smtplib.SMTP, self.smtpserver, timeout=self.smtpservertimeout)
+ elif self.security == 'ssl':
+ self.smtp = call(smtplib.SMTP_SSL, self.smtpserver, timeout=self.smtpservertimeout)
+ elif self.security == 'tls':
+ if ':' not in self.smtpserver:
+ self.smtpserver += ':587' # default port for TLS
+ self.smtp = call(smtplib.SMTP, self.smtpserver, timeout=self.smtpservertimeout)
+ self.smtp.ehlo()
+ self.smtp.starttls()
+ self.smtp.ehlo()
+ else:
+ sys.stdout.write('*** Error: Control reached an invalid option. ***')
+ sys.exit(1)
+ if self.smtpserverdebuglevel > 0:
+ sys.stdout.write(
+ "*** Setting debug on for SMTP server connection (%s) ***\n"
+ % self.smtpserverdebuglevel)
+ self.smtp.set_debuglevel(self.smtpserverdebuglevel)
except Exception, e:
- sys.stderr.write('*** Error establishing SMTP connection to %s***\n' % self.smtpserver)
+ sys.stderr.write(
+ '*** Error establishing SMTP connection to %s ***\n'
+ % self.smtpserver)
sys.stderr.write('*** %s\n' % str(e))
sys.exit(1)
def __del__(self):
- self.smtp.quit()
+ if hasattr(self, 'smtp'):
+ self.smtp.quit()
def send(self, lines, to_addrs):
try:
+ if self.username or self.password:
+ sys.stderr.write("*** Authenticating as %s ***\n" % self.username)
+ self.smtp.login(self.username, self.password)
msg = ''.join(lines)
# turn comma-separated list into Python list if needed.
if isinstance(to_addrs, basestring):
to_addrs = [email for (name, email) in getaddresses([to_addrs])]
self.smtp.sendmail(self.envelopesender, to_addrs, msg)
except Exception, e:
- sys.stderr.write('*** Error sending email***\n')
+ sys.stderr.write('*** Error sending email ***\n')
sys.stderr.write('*** %s\n' % str(e))
self.smtp.quit()
sys.exit(1)
@@ -1549,6 +1907,10 @@ class Environment(object):
True iff announce emails should include a shortlog.
+ refchange_showgraph (bool)
+
+ True iff refchanges emails should include a detailed graph.
+
refchange_showlog (bool)
True iff refchanges emails should include a detailed log.
@@ -1559,6 +1921,12 @@ class Environment(object):
summary email. The value should be a list of strings
representing words to be passed to the command.
+ graphopts (list of strings)
+
+ Analogous to diffopts, but contains options passed to
+ 'git log --graph' when generating the detailed graph for
+ a set of commits (see refchange_showgraph)
+
logopts (list of strings)
Analogous to diffopts, but contains options passed to
@@ -1571,6 +1939,17 @@ class Environment(object):
commit mail. The value should be a list of strings
representing words to be passed to the command.
+ quiet (bool)
+ On success do not write to stderr
+
+ stdout (bool)
+ Write email to stdout rather than emailing. Useful for debugging
+
+ combine_when_single_commit (bool)
+
+ True if a combined email should be produced when a single
+ new commit is pushed to a branch, False otherwise.
+
"""
REPO_NAME_RE = re.compile(r'^(?P<name>.+?)(?:\.git)$')
@@ -1580,9 +1959,14 @@ class Environment(object):
self.announce_show_shortlog = False
self.maxcommitemails = 500
self.diffopts = ['--stat', '--summary', '--find-copies-harder']
+ self.graphopts = ['--oneline', '--decorate']
self.logopts = []
+ self.refchange_showgraph = False
self.refchange_showlog = False
self.commitlogopts = ['-C', '--stat', '-p', '--cc']
+ self.quiet = False
+ self.stdout = False
+ self.combine_when_single_commit = True
self.COMPUTED_KEYS = [
'administrator',
@@ -1614,6 +1998,14 @@ class Environment(object):
def get_pusher_email(self):
return None
+ def get_fromaddr(self):
+ config = Config('user')
+ fromname = config.get('name', default='')
+ fromemail = config.get('email', default='')
+ if fromemail:
+ return formataddr([fromname, fromemail])
+ return self.get_sender()
+
def get_administrator(self):
return 'the administrator of this repository'
@@ -1631,7 +2023,7 @@ class Environment(object):
return CHARSET
def get_values(self):
- """Return a dictionary {keyword : expansion} for this Environment.
+ """Return a dictionary {keyword: expansion} for this Environment.
This method is called by Change._compute_values(). The keys
in the returned dictionary are available to be used in any of
@@ -1699,6 +2091,24 @@ class Environment(object):
return lines
+ def log_msg(self, msg):
+ """Write the string msg on a log file or on stderr.
+
+ Sends the text to stderr by default, override to change the behavior."""
+ sys.stderr.write(msg)
+
+ def log_warning(self, msg):
+ """Write the string msg on a log file or on stderr.
+
+ Sends the text to stderr by default, override to change the behavior."""
+ sys.stderr.write(msg)
+
+ def log_error(self, msg):
+ """Write the string msg on a log file or on stderr.
+
+ Sends the text to stderr by default, override to change the behavior."""
+ sys.stderr.write(msg)
+
class ConfigEnvironmentMixin(Environment):
"""A mixin that sets self.config to its constructor's config argument.
@@ -1723,20 +2133,23 @@ class ConfigOptionsEnvironmentMixin(ConfigEnvironmentMixin):
config=config, **kw
)
- self.announce_show_shortlog = config.get_bool(
- 'announceshortlog', default=self.announce_show_shortlog
- )
-
- self.refchange_showlog = config.get_bool(
- 'refchangeshowlog', default=self.refchange_showlog
- )
+ for var, cfg in (
+ ('announce_show_shortlog', 'announceshortlog'),
+ ('refchange_showgraph', 'refchangeShowGraph'),
+ ('refchange_showlog', 'refchangeshowlog'),
+ ('quiet', 'quiet'),
+ ('stdout', 'stdout'),
+ ):
+ val = config.get_bool(cfg)
+ if val is not None:
+ setattr(self, var, val)
maxcommitemails = config.get('maxcommitemails')
if maxcommitemails is not None:
try:
self.maxcommitemails = int(maxcommitemails)
except ValueError:
- sys.stderr.write(
+ self.log_warning(
'*** Malformed value for multimailhook.maxCommitEmails: %s\n' % maxcommitemails
+ '*** Expected a number. Ignoring.\n'
)
@@ -1745,6 +2158,10 @@ class ConfigOptionsEnvironmentMixin(ConfigEnvironmentMixin):
if diffopts is not None:
self.diffopts = shlex.split(diffopts)
+ graphopts = config.get('graphOpts')
+ if graphopts is not None:
+ self.graphopts = shlex.split(graphopts)
+
logopts = config.get('logopts')
if logopts is not None:
self.logopts = shlex.split(logopts)
@@ -1756,14 +2173,18 @@ class ConfigOptionsEnvironmentMixin(ConfigEnvironmentMixin):
reply_to = config.get('replyTo')
self.__reply_to_refchange = config.get('replyToRefchange', default=reply_to)
if (
- self.__reply_to_refchange is not None
- and self.__reply_to_refchange.lower() == 'author'
- ):
+ self.__reply_to_refchange is not None
+ and self.__reply_to_refchange.lower() == 'author'
+ ):
raise ConfigurationException(
'"author" is not an allowed setting for replyToRefchange'
)
self.__reply_to_commit = config.get('replyToCommit', default=reply_to)
+ combine = config.get_bool('combineWhenSingleCommit')
+ if combine is not None:
+ self.combine_when_single_commit = combine
+
def get_administrator(self):
return (
self.config.get('administrator')
@@ -1779,8 +2200,12 @@ class ConfigOptionsEnvironmentMixin(ConfigEnvironmentMixin):
def get_emailprefix(self):
emailprefix = self.config.get('emailprefix')
- if emailprefix and emailprefix.strip():
- return emailprefix.strip() + ' '
+ if emailprefix is not None:
+ emailprefix = emailprefix.strip()
+ if emailprefix:
+ return emailprefix + ' '
+ else:
+ return ''
else:
return '[%s] ' % (self.get_repo_shortname(),)
@@ -1791,14 +2216,7 @@ class ConfigOptionsEnvironmentMixin(ConfigEnvironmentMixin):
fromaddr = self.config.get('from')
if fromaddr:
return fromaddr
- else:
- config = Config('user')
- fromname = config.get('name', default='')
- fromemail = config.get('email', default='')
- if fromemail:
- return formataddr([fromname, fromemail])
- else:
- return self.get_sender()
+ return super(ConfigOptionsEnvironmentMixin, self).get_fromaddr()
def get_reply_to_refchange(self, refchange):
if self.__reply_to_refchange is None:
@@ -1814,7 +2232,7 @@ class ConfigOptionsEnvironmentMixin(ConfigEnvironmentMixin):
if self.__reply_to_commit is None:
return super(ConfigOptionsEnvironmentMixin, self).get_reply_to_commit(revision)
elif self.__reply_to_commit.lower() == 'author':
- return revision.get_author()
+ return revision.author
elif self.__reply_to_commit.lower() == 'pusher':
return self.get_pusher_email()
elif self.__reply_to_commit.lower() == 'none':
@@ -1822,6 +2240,9 @@ class ConfigOptionsEnvironmentMixin(ConfigEnvironmentMixin):
else:
return self.__reply_to_commit
+ def get_scancommitforcc(self):
+ return self.config.get('scancommitforcc')
+
class FilterLinesEnvironmentMixin(Environment):
"""Handle encoding and maximum line length of body lines.
@@ -1862,9 +2283,9 @@ class FilterLinesEnvironmentMixin(Environment):
class ConfigFilterLinesEnvironmentMixin(
- ConfigEnvironmentMixin,
- FilterLinesEnvironmentMixin,
- ):
+ ConfigEnvironmentMixin,
+ FilterLinesEnvironmentMixin,
+ ):
"""Handle encoding and maximum line length based on config."""
def __init__(self, config, **kw):
@@ -1896,9 +2317,9 @@ class MaxlinesEnvironmentMixin(Environment):
class ConfigMaxlinesEnvironmentMixin(
- ConfigEnvironmentMixin,
- MaxlinesEnvironmentMixin,
- ):
+ ConfigEnvironmentMixin,
+ MaxlinesEnvironmentMixin,
+ ):
"""Limit the email body to the number of lines specified in config."""
def __init__(self, config, **kw):
@@ -1927,9 +2348,9 @@ class FQDNEnvironmentMixin(Environment):
class ConfigFQDNEnvironmentMixin(
- ConfigEnvironmentMixin,
- FQDNEnvironmentMixin,
- ):
+ ConfigEnvironmentMixin,
+ FQDNEnvironmentMixin,
+ ):
"""Read the FQDN from the config."""
def __init__(self, config, **kw):
@@ -1970,10 +2391,10 @@ class StaticRecipientsEnvironmentMixin(Environment):
"""Set recipients statically based on constructor parameters."""
def __init__(
- self,
- refchange_recipients, announce_recipients, revision_recipients,
- **kw
- ):
+ self,
+ refchange_recipients, announce_recipients, revision_recipients, scancommitforcc,
+ **kw
+ ):
super(StaticRecipientsEnvironmentMixin, self).__init__(**kw)
# The recipients for various types of notification emails, as
@@ -1985,7 +2406,8 @@ class StaticRecipientsEnvironmentMixin(Environment):
# compute them once and for all:
if not (refchange_recipients
or announce_recipients
- or revision_recipients):
+ or revision_recipients
+ or scancommitforcc):
raise ConfigurationException('No email recipients configured!')
self.__refchange_recipients = refchange_recipients
self.__announce_recipients = announce_recipients
@@ -2002,9 +2424,9 @@ class StaticRecipientsEnvironmentMixin(Environment):
class ConfigRecipientsEnvironmentMixin(
- ConfigEnvironmentMixin,
- StaticRecipientsEnvironmentMixin
- ):
+ ConfigEnvironmentMixin,
+ StaticRecipientsEnvironmentMixin
+ ):
"""Determine recipients statically based on config."""
def __init__(self, config, **kw):
@@ -2019,6 +2441,7 @@ class ConfigRecipientsEnvironmentMixin(
revision_recipients=self._get_recipients(
config, 'commitlist', 'mailinglist',
),
+ scancommitforcc=config.get('scancommitforcc'),
**kw
)
@@ -2067,20 +2490,20 @@ class ProjectdescEnvironmentMixin(Environment):
class GenericEnvironmentMixin(Environment):
def get_pusher(self):
- return self.osenv.get('USER', 'unknown user')
+ return self.osenv.get('USER', self.osenv.get('USERNAME', 'unknown user'))
class GenericEnvironment(
- ProjectdescEnvironmentMixin,
- ConfigMaxlinesEnvironmentMixin,
- ComputeFQDNEnvironmentMixin,
- ConfigFilterLinesEnvironmentMixin,
- ConfigRecipientsEnvironmentMixin,
- PusherDomainEnvironmentMixin,
- ConfigOptionsEnvironmentMixin,
- GenericEnvironmentMixin,
- Environment,
- ):
+ ProjectdescEnvironmentMixin,
+ ConfigMaxlinesEnvironmentMixin,
+ ComputeFQDNEnvironmentMixin,
+ ConfigFilterLinesEnvironmentMixin,
+ ConfigRecipientsEnvironmentMixin,
+ PusherDomainEnvironmentMixin,
+ ConfigOptionsEnvironmentMixin,
+ GenericEnvironmentMixin,
+ Environment,
+ ):
pass
@@ -2097,6 +2520,45 @@ class GitoliteEnvironmentMixin(Environment):
def get_pusher(self):
return self.osenv.get('GL_USER', 'unknown user')
+ def get_fromaddr(self):
+ GL_USER = self.osenv.get('GL_USER')
+ if GL_USER is not None:
+ # Find the path to gitolite.conf. Note that gitolite v3
+ # did away with the GL_ADMINDIR and GL_CONF environment
+ # variables (they are now hard-coded).
+ GL_ADMINDIR = self.osenv.get(
+ 'GL_ADMINDIR',
+ os.path.expanduser(os.path.join('~', '.gitolite')))
+ GL_CONF = self.osenv.get(
+ 'GL_CONF',
+ os.path.join(GL_ADMINDIR, 'conf', 'gitolite.conf'))
+ if os.path.isfile(GL_CONF):
+ f = open(GL_CONF, 'rU')
+ try:
+ in_user_emails_section = False
+ re_template = r'^\s*#\s*{}\s*$'
+ re_begin, re_user, re_end = (
+ re.compile(re_template.format(x))
+ for x in (
+ r'BEGIN\s+USER\s+EMAILS',
+ re.escape(GL_USER) + r'\s+(.*)',
+ r'END\s+USER\s+EMAILS',
+ ))
+ for l in f:
+ l = l.rstrip('\n')
+ if not in_user_emails_section:
+ if re_begin.match(l):
+ in_user_emails_section = True
+ continue
+ if re_end.match(l):
+ break
+ m = re_user.match(l)
+ if m:
+ return m.group(1)
+ finally:
+ f.close()
+ return super(GitoliteEnvironmentMixin, self).get_fromaddr()
+
class IncrementalDateTime(object):
"""Simple wrapper to give incremental date/times.
@@ -2116,16 +2578,16 @@ class IncrementalDateTime(object):
class GitoliteEnvironment(
- ProjectdescEnvironmentMixin,
- ConfigMaxlinesEnvironmentMixin,
- ComputeFQDNEnvironmentMixin,
- ConfigFilterLinesEnvironmentMixin,
- ConfigRecipientsEnvironmentMixin,
- PusherDomainEnvironmentMixin,
- ConfigOptionsEnvironmentMixin,
- GitoliteEnvironmentMixin,
- Environment,
- ):
+ ProjectdescEnvironmentMixin,
+ ConfigMaxlinesEnvironmentMixin,
+ ComputeFQDNEnvironmentMixin,
+ ConfigFilterLinesEnvironmentMixin,
+ ConfigRecipientsEnvironmentMixin,
+ PusherDomainEnvironmentMixin,
+ ConfigOptionsEnvironmentMixin,
+ GitoliteEnvironmentMixin,
+ Environment,
+ ):
pass
@@ -2149,9 +2611,9 @@ class Push(object):
references.
The first step is to determine the "other" references--those
- unaffected by the current push. They are computed by
- Push._compute_other_ref_sha1s() by listing all references then
- removing any affected by this push.
+ unaffected by the current push. They are computed by listing all
+ references then removing any affected by this push. The results
+ are stored in Push._other_ref_sha1s.
The commits contained in the repository before this push were
@@ -2187,7 +2649,7 @@ class Push(object):
possible and working with SHA1s thereafter (because SHA1s are
immutable)."""
- # A map {(changeclass, changetype) : integer} specifying the order
+ # A map {(changeclass, changetype): integer} specifying the order
# that reference changes will be processed if multiple reference
# changes are included in a single push. The order is significant
# mostly because new commit notifications are threaded together
@@ -2211,66 +2673,134 @@ class Push(object):
])
)
- def __init__(self, changes):
+ def __init__(self, changes, ignore_other_refs=False):
self.changes = sorted(changes, key=self._sort_key)
+ self.__other_ref_sha1s = None
+ self.__cached_commits_spec = {}
- # The SHA-1s of commits referred to by references unaffected
- # by this push:
- other_ref_sha1s = self._compute_other_ref_sha1s()
+ if ignore_other_refs:
+ self.__other_ref_sha1s = set()
- self._old_rev_exclusion_spec = self._compute_rev_exclusion_spec(
- other_ref_sha1s.union(
- change.old.sha1
+ @classmethod
+ def _sort_key(klass, change):
+ return (klass.SORT_ORDER[change.__class__, change.change_type], change.refname,)
+
+ @property
+ def _other_ref_sha1s(self):
+ """The GitObjects referred to by references unaffected by this push.
+ """
+ if self.__other_ref_sha1s is None:
+ # The refnames being changed by this push:
+ updated_refs = set(
+ change.refname
for change in self.changes
- if change.old.type in ['commit', 'tag']
)
- )
- self._new_rev_exclusion_spec = self._compute_rev_exclusion_spec(
- other_ref_sha1s.union(
- change.new.sha1
- for change in self.changes
- if change.new.type in ['commit', 'tag']
+
+ # The SHA-1s of commits referred to by all references in this
+ # repository *except* updated_refs:
+ sha1s = set()
+ fmt = (
+ '%(objectname) %(objecttype) %(refname)\n'
+ '%(*objectname) %(*objecttype) %(refname)'
)
- )
+ for line in read_git_lines(
+ ['for-each-ref', '--format=%s' % (fmt,)]):
+ (sha1, type, name) = line.split(' ', 2)
+ if sha1 and type == 'commit' and name not in updated_refs:
+ sha1s.add(sha1)
- @classmethod
- def _sort_key(klass, change):
- return (klass.SORT_ORDER[change.__class__, change.change_type], change.refname,)
+ self.__other_ref_sha1s = sha1s
+
+ return self.__other_ref_sha1s
+
+ def _get_commits_spec_incl(self, new_or_old, reference_change=None):
+ """Get new or old SHA-1 from one or each of the changed refs.
- def _compute_other_ref_sha1s(self):
- """Return the GitObjects referred to by references unaffected by this push."""
+ Return a list of SHA-1 commit identifier strings suitable as
+ arguments to 'git rev-list' (or 'git log' or ...). The
+ returned identifiers are either the old or new values from one
+ or all of the changed references, depending on the values of
+ new_or_old and reference_change.
- # The refnames being changed by this push:
- updated_refs = set(
- change.refname
+ new_or_old is either the string 'new' or the string 'old'. If
+ 'new', the returned SHA-1 identifiers are the new values from
+ each changed reference. If 'old', the SHA-1 identifiers are
+ the old values from each changed reference.
+
+ If reference_change is specified and not None, only the new or
+ old reference from the specified reference is included in the
+ return value.
+
+ This function returns None if there are no matching revisions
+ (e.g., because a branch was deleted and new_or_old is 'new').
+ """
+
+ if not reference_change:
+ incl_spec = sorted(
+ getattr(change, new_or_old).sha1
+ for change in self.changes
+ if getattr(change, new_or_old)
+ )
+ if not incl_spec:
+ incl_spec = None
+ elif not getattr(reference_change, new_or_old).commit_sha1:
+ incl_spec = None
+ else:
+ incl_spec = [getattr(reference_change, new_or_old).commit_sha1]
+ return incl_spec
+
+ def _get_commits_spec_excl(self, new_or_old):
+ """Get exclusion revisions for determining new or discarded commits.
+
+ Return a list of strings suitable as arguments to 'git
+ rev-list' (or 'git log' or ...) that will exclude all
+ commits that, depending on the value of new_or_old, were
+ either previously in the repository (useful for determining
+ which commits are new to the repository) or currently in the
+ repository (useful for determining which commits were
+ discarded from the repository).
+
+ new_or_old is either the string 'new' or the string 'old'. If
+ 'new', the commits to be excluded are those that were in the
+ repository before the push. If 'old', the commits to be
+ excluded are those that are currently in the repository. """
+
+ old_or_new = {'old': 'new', 'new': 'old'}[new_or_old]
+ excl_revs = self._other_ref_sha1s.union(
+ getattr(change, old_or_new).sha1
for change in self.changes
+ if getattr(change, old_or_new).type in ['commit', 'tag']
)
+ return ['^' + sha1 for sha1 in sorted(excl_revs)]
- # The SHA-1s of commits referred to by all references in this
- # repository *except* updated_refs:
- sha1s = set()
- fmt = (
- '%(objectname) %(objecttype) %(refname)\n'
- '%(*objectname) %(*objecttype) %(refname)'
- )
- for line in read_git_lines(['for-each-ref', '--format=%s' % (fmt,)]):
- (sha1, type, name) = line.split(' ', 2)
- if sha1 and type == 'commit' and name not in updated_refs:
- sha1s.add(sha1)
+ def get_commits_spec(self, new_or_old, reference_change=None):
+ """Get rev-list arguments for added or discarded commits.
- return sha1s
+ Return a list of strings suitable as arguments to 'git
+ rev-list' (or 'git log' or ...) that select those commits
+ that, depending on the value of new_or_old, are either new to
+ the repository or were discarded from the repository.
- def _compute_rev_exclusion_spec(self, sha1s):
- """Return an exclusion specification for 'git rev-list'.
+ new_or_old is either the string 'new' or the string 'old'. If
+ 'new', the returned list is used to select commits that are
+ new to the repository. If 'old', the returned value is used
+ to select the commits that have been discarded from the
+ repository.
- git_objects is an iterable over GitObject instances. Return a
- string that can be passed to the standard input of 'git
- rev-list --stdin' to exclude all of the commits referred to by
- git_objects."""
+ If reference_change is specified and not None, the new or
+ discarded commits are limited to those that are reachable from
+ the new or old value of the specified reference.
- return ''.join(
- ['^%s\n' % (sha1,) for sha1 in sorted(sha1s)]
- )
+ This function returns None if there are no added (or discarded)
+ revisions.
+ """
+ key = (new_or_old, reference_change)
+ if key not in self.__cached_commits_spec:
+ ret = self._get_commits_spec_incl(new_or_old, reference_change)
+ if ret is not None:
+ ret.extend(self._get_commits_spec_excl(new_or_old))
+ self.__cached_commits_spec[key] = ret
+ return self.__cached_commits_spec[key]
def get_new_commits(self, reference_change=None):
"""Return a list of commits added by this push.
@@ -2280,19 +2810,8 @@ class Push(object):
reference_change is None, then return a list of *all* commits
added by this push."""
- if not reference_change:
- new_revs = sorted(
- change.new.sha1
- for change in self.changes
- if change.new
- )
- elif not reference_change.new.commit_sha1:
- return []
- else:
- new_revs = [reference_change.new.commit_sha1]
-
- cmd = ['rev-list', '--stdin'] + new_revs
- return read_git_lines(cmd, input=self._old_rev_exclusion_spec)
+ spec = self.get_commits_spec('new', reference_change)
+ return git_rev_list(spec)
def get_discarded_commits(self, reference_change):
"""Return a list of commits discarded by this push.
@@ -2301,13 +2820,8 @@ class Push(object):
entirely discarded from the repository by the part of this
push represented by reference_change."""
- if not reference_change.old.commit_sha1:
- return []
- else:
- old_revs = [reference_change.old.commit_sha1]
-
- cmd = ['rev-list', '--stdin'] + old_revs
- return read_git_lines(cmd, input=self._new_rev_exclusion_spec)
+ spec = self.get_commits_spec('old', reference_change)
+ return git_rev_list(spec)
def send_emails(self, mailer, body_filter=None):
"""Use send all of the notification emails needed for this push.
@@ -2325,30 +2839,43 @@ class Push(object):
unhandled_sha1s = set(self.get_new_commits())
send_date = IncrementalDateTime()
for change in self.changes:
+ sha1s = []
+ for sha1 in reversed(list(self.get_new_commits(change))):
+ if sha1 in unhandled_sha1s:
+ sha1s.append(sha1)
+ unhandled_sha1s.remove(sha1)
+
# Check if we've got anyone to send to
if not change.recipients:
- sys.stderr.write(
+ change.environment.log_warning(
'*** no recipients configured so no email will be sent\n'
'*** for %r update %s->%s\n'
% (change.refname, change.old.sha1, change.new.sha1,)
)
else:
- sys.stderr.write('Sending notification emails to: %s\n' % (change.recipients,))
- extra_values = {'send_date' : send_date.next()}
- mailer.send(
- change.generate_email(self, body_filter, extra_values),
- change.recipients,
- )
+ if not change.environment.quiet:
+ change.environment.log_msg(
+ 'Sending notification emails to: %s\n' % (change.recipients,))
+ extra_values = {'send_date': send_date.next()}
- sha1s = []
- for sha1 in reversed(list(self.get_new_commits(change))):
- if sha1 in unhandled_sha1s:
- sha1s.append(sha1)
- unhandled_sha1s.remove(sha1)
+ rev = change.send_single_combined_email(sha1s)
+ if rev:
+ mailer.send(
+ change.generate_combined_email(self, rev, body_filter, extra_values),
+ rev.recipients,
+ )
+ # This change is now fully handled; no need to handle
+ # individual revisions any further.
+ continue
+ else:
+ mailer.send(
+ change.generate_email(self, body_filter, extra_values),
+ change.recipients,
+ )
max_emails = change.environment.maxcommitemails
if max_emails and len(sha1s) > max_emails:
- sys.stderr.write(
+ change.environment.log_warning(
'*** Too many new commits (%d), not sending commit emails.\n' % len(sha1s)
+ '*** Try setting multimailhook.maxCommitEmails to a greater value\n'
+ '*** Currently, multimailhook.maxCommitEmails=%d\n' % max_emails
@@ -2356,9 +2883,13 @@ class Push(object):
return
for (num, sha1) in enumerate(sha1s):
- rev = Revision(change, GitObject(sha1), num=num+1, tot=len(sha1s))
+ rev = Revision(change, GitObject(sha1), num=num + 1, tot=len(sha1s))
+ if not rev.recipients and rev.cc_recipients:
+ change.environment.log_msg('*** Replacing Cc: with To:\n')
+ rev.recipients = rev.cc_recipients
+ rev.cc_recipients = None
if rev.recipients:
- extra_values = {'send_date' : send_date.next()}
+ extra_values = {'send_date': send_date.next()}
mailer.send(
rev.generate_email(self, body_filter, extra_values),
rev.recipients,
@@ -2366,7 +2897,7 @@ class Push(object):
# Consistency check:
if unhandled_sha1s:
- sys.stderr.write(
+ change.environment.log_error(
'ERROR: No emails were sent for the following new commits:\n'
' %s\n'
% ('\n '.join(sorted(unhandled_sha1s)),)
@@ -2384,7 +2915,7 @@ def run_as_post_receive_hook(environment, mailer):
push.send_emails(mailer, body_filter=environment.filter_body)
-def run_as_update_hook(environment, mailer, refname, oldrev, newrev):
+def run_as_update_hook(environment, mailer, refname, oldrev, newrev, force_send=False):
changes = [
ReferenceChange.create(
environment,
@@ -2393,7 +2924,7 @@ def run_as_update_hook(environment, mailer, refname, oldrev, newrev):
refname,
),
]
- push = Push(changes)
+ push = Push(changes, force_send)
push.send_emails(mailer, body_filter=environment.filter_body)
@@ -2402,9 +2933,18 @@ def choose_mailer(config, environment):
if mailer == 'smtp':
smtpserver = config.get('smtpserver', default='localhost')
+ smtpservertimeout = float(config.get('smtpservertimeout', default=10.0))
+ smtpserverdebuglevel = int(config.get('smtpserverdebuglevel', default=0))
+ smtpencryption = config.get('smtpencryption', default='none')
+ smtpuser = config.get('smtpuser', default='')
+ smtppass = config.get('smtppass', default='')
mailer = SMTPMailer(
envelopesender=(environment.get_sender() or environment.get_fromaddr()),
- smtpserver=smtpserver,
+ smtpserver=smtpserver, smtpservertimeout=smtpservertimeout,
+ smtpserverdebuglevel=smtpserverdebuglevel,
+ smtpencryption=smtpencryption,
+ smtpuser=smtpuser,
+ smtppass=smtppass,
)
elif mailer == 'sendmail':
command = config.get('sendmailcommand')
@@ -2412,7 +2952,7 @@ def choose_mailer(config, environment):
command = shlex.split(command)
mailer = SendMailer(command=command, envelopesender=environment.get_sender())
else:
- sys.stderr.write(
+ environment.log_error(
'fatal: multimailhook.mailer is set to an incorrect value: "%s"\n' % mailer
+ 'please use one of "smtp" or "sendmail".\n'
)
@@ -2421,8 +2961,8 @@ def choose_mailer(config, environment):
KNOWN_ENVIRONMENTS = {
- 'generic' : GenericEnvironmentMixin,
- 'gitolite' : GitoliteEnvironmentMixin,
+ 'generic': GenericEnvironmentMixin,
+ 'gitolite': GitoliteEnvironmentMixin,
}
@@ -2439,8 +2979,8 @@ def choose_environment(config, osenv=None, env=None, recipients=None):
ConfigOptionsEnvironmentMixin,
]
environment_kw = {
- 'osenv' : osenv,
- 'config' : config,
+ 'osenv': osenv,
+ 'config': config,
}
if not env:
@@ -2459,6 +2999,7 @@ def choose_environment(config, osenv=None, env=None, recipients=None):
environment_kw['refchange_recipients'] = recipients
environment_kw['announce_recipients'] = recipients
environment_kw['revision_recipients'] = recipients
+ environment_kw['scancommitforcc'] = config.get('scancommitforcc')
else:
environment_mixins.insert(0, ConfigRecipientsEnvironmentMixin)
@@ -2499,6 +3040,14 @@ def main(args):
'(intended for debugging purposes).'
),
)
+ parser.add_option(
+ '--force-send', action='store_true', default=False,
+ help=(
+ 'Force sending refchange email when using as an update hook. '
+ 'This is useful to work around the unreliable new commits '
+ 'detection in this mode.'
+ ),
+ )
(options, args) = parser.parse_args(args)
@@ -2513,11 +3062,11 @@ def main(args):
if options.show_env:
sys.stderr.write('Environment values:\n')
- for (k,v) in sorted(environment.get_values().items()):
- sys.stderr.write(' %s : %r\n' % (k,v))
+ for (k, v) in sorted(environment.get_values().items()):
+ sys.stderr.write(' %s : %r\n' % (k, v))
sys.stderr.write('\n')
- if options.stdout:
+ if options.stdout or environment.stdout:
mailer = OutputMailer(sys.stdout)
else:
mailer = choose_mailer(config, environment)
@@ -2528,7 +3077,7 @@ def main(args):
if len(args) != 3:
parser.error('Need zero or three non-option arguments')
(refname, oldrev, newrev) = args
- run_as_update_hook(environment, mailer, refname, oldrev, newrev)
+ run_as_update_hook(environment, mailer, refname, oldrev, newrev, options.force_send)
else:
run_as_post_receive_hook(environment, mailer)
except ConfigurationException, e:
diff --git a/contrib/hooks/multimail/migrate-mailhook-config b/contrib/hooks/multimail/migrate-mailhook-config
index 04eeaac..d0e9b39 100755
--- a/contrib/hooks/multimail/migrate-mailhook-config
+++ b/contrib/hooks/multimail/migrate-mailhook-config
@@ -22,6 +22,7 @@ OLD_NAMES = [
'showrev',
'emailmaxlines',
'diffopts',
+ 'scancommitforcc',
]
NEW_NAMES = [
@@ -38,6 +39,7 @@ NEW_NAMES = [
'emailmaxlines',
'diffopts',
'emaildomain',
+ 'scancommitforcc',
]
@@ -61,7 +63,7 @@ def _check_old_config_exists(old):
"""Check that at least one old configuration value is set."""
for name in OLD_NAMES:
- if old.has_key(name):
+ if name in old:
return True
return False
@@ -72,7 +74,7 @@ def _check_new_config_clear(new):
retval = True
for name in NEW_NAMES:
- if new.has_key(name):
+ if name in new:
if retval:
sys.stderr.write('INFO: The following configuration values already exist:\n\n')
sys.stderr.write(' "%s.%s"\n' % (new.section, name))
@@ -83,7 +85,7 @@ def _check_new_config_clear(new):
def erase_values(config, names):
for name in names:
- if config.has_key(name):
+ if name in config:
try:
sys.stderr.write('...unsetting "%s.%s"\n' % (config.section, name))
config.unset_all(name)
@@ -170,7 +172,7 @@ def migrate_config(strict=False, retain=False, overwrite=False):
)
name = 'showrev'
- if old.has_key(name):
+ if name in old:
msg = 'git-multimail does not support "%s.%s"' % (old.section, name,)
if strict:
sys.exit(
@@ -182,7 +184,7 @@ def migrate_config(strict=False, retain=False, overwrite=False):
sys.stderr.write('\nWARNING: %s (ignoring).\n\n' % (msg,))
for name in ['mailinglist', 'announcelist']:
- if old.has_key(name):
+ if name in old:
sys.stderr.write(
'...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
)
@@ -198,15 +200,15 @@ def migrate_config(strict=False, retain=False, overwrite=False):
)
new.set('announceshortlog', 'true')
- for name in ['envelopesender', 'emailmaxlines', 'diffopts']:
- if old.has_key(name):
+ for name in ['envelopesender', 'emailmaxlines', 'diffopts', 'scancommitforcc']:
+ if name in old:
sys.stderr.write(
'...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
)
new.set(name, old.get(name))
name = 'emailprefix'
- if old.has_key(name):
+ if name in old:
sys.stderr.write(
'...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
)
diff --git a/contrib/hooks/multimail/post-receive b/contrib/hooks/multimail/post-receive.example
index 4d46828..43f7b6b 100755
--- a/contrib/hooks/multimail/post-receive
+++ b/contrib/hooks/multimail/post-receive.example
@@ -2,16 +2,18 @@
"""Example post-receive hook based on git-multimail.
-This script is a simple example of a post-receive hook implemented
-using git_multimail.py as a Python module. It is intended to be
-customized before use; see the comments in the script to help you get
-started.
+The simplest way to use git-multimail is to use the script
+git_multimail.py directly as a post-receive hook, and to configure it
+using Git's configuration files and command-line parameters. You can
+also write your own Python wrapper for more advanced configurability,
+using git_multimail.py as a Python module.
-It is possible to use git_multimail.py itself as a post-receive or
-update hook, configured via git config settings and/or command-line
-parameters. But for more flexibility, it can also be imported as a
-Python module by a custom post-receive script as done here. The
-latter has the following advantages:
+This script is a simple example of such a post-receive hook. It is
+intended to be customized before use; see the comments in the script
+to help you get started.
+
+Using git-multimail as a Python module as done here provides more
+flexibility. It has the following advantages:
* The tool's behavior can be customized using arbitrary Python code,
without having to edit git_multimail.py.
@@ -56,8 +58,11 @@ config = git_multimail.Config('multimailhook')
# Select the type of environment:
-environment = git_multimail.GenericEnvironment(config=config)
-#environment = git_multimail.GitoliteEnvironment(config=config)
+try:
+ environment = git_multimail.GenericEnvironment(config=config)
+ #environment = git_multimail.GitoliteEnvironment(config=config)
+except git_multimail.ConfigurationException, e:
+ sys.exit(str(e))
# Choose the method of sending emails based on the git config:
diff --git a/contrib/hooks/pre-auto-gc-battery b/contrib/hooks/pre-auto-gc-battery
index 9d0c2d1..6a2cdeb 100755
--- a/contrib/hooks/pre-auto-gc-battery
+++ b/contrib/hooks/pre-auto-gc-battery
@@ -33,7 +33,7 @@ elif grep -q "AC Power \+: 1" /proc/pmu/info 2>/dev/null
then
exit 0
elif test -x /usr/bin/pmset && /usr/bin/pmset -g batt |
- grep -q "Currently drawing from 'AC Power'"
+ grep -q "drawing from 'AC Power'"
then
exit 0
fi
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 6309d12..bd3df97 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -62,17 +62,17 @@ last_commit_message()
}
test_expect_success 'init subproj' '
- test_create_repo subproj
+ test_create_repo subproj
'
# To the subproject!
cd subproj
test_expect_success 'add sub1' '
- create sub1 &&
- git commit -m "sub1" &&
- git branch sub1 &&
- git branch -m master subproj
+ create sub1 &&
+ git commit -m "sub1" &&
+ git branch sub1 &&
+ git branch -m master subproj
'
# Save this hash for testing later.
@@ -80,133 +80,134 @@ test_expect_success 'add sub1' '
subdir_hash=$(git rev-parse HEAD)
test_expect_success 'add sub2' '
- create sub2 &&
- git commit -m "sub2" &&
- git branch sub2
+ create sub2 &&
+ git commit -m "sub2" &&
+ git branch sub2
'
test_expect_success 'add sub3' '
- create sub3 &&
- git commit -m "sub3" &&
- git branch sub3
+ create sub3 &&
+ git commit -m "sub3" &&
+ git branch sub3
'
# Back to mainline
cd ..
test_expect_success 'add main4' '
- create main4 &&
- git commit -m "main4" &&
- git branch -m master mainline &&
- git branch subdir
+ create main4 &&
+ git commit -m "main4" &&
+ git branch -m master mainline &&
+ git branch subdir
'
test_expect_success 'fetch subproj history' '
- git fetch ./subproj sub1 &&
- git branch sub1 FETCH_HEAD
+ git fetch ./subproj sub1 &&
+ git branch sub1 FETCH_HEAD
'
test_expect_success 'no subtree exists in main tree' '
- test_must_fail git subtree merge --prefix=subdir sub1
+ test_must_fail git subtree merge --prefix=subdir sub1
'
test_expect_success 'no pull from non-existant subtree' '
- test_must_fail git subtree pull --prefix=subdir ./subproj sub1
+ test_must_fail git subtree pull --prefix=subdir ./subproj sub1
'
test_expect_success 'check if --message works for add' '
- git subtree add --prefix=subdir --message="Added subproject" sub1 &&
- check_equal ''"$(last_commit_message)"'' "Added subproject" &&
- undo
+ git subtree add --prefix=subdir --message="Added subproject" sub1 &&
+ check_equal ''"$(last_commit_message)"'' "Added subproject" &&
+ undo
'
test_expect_success 'check if --message works as -m and --prefix as -P' '
- git subtree add -P subdir -m "Added subproject using git subtree" sub1 &&
- check_equal ''"$(last_commit_message)"'' "Added subproject using git subtree" &&
- undo
+ git subtree add -P subdir -m "Added subproject using git subtree" sub1 &&
+ check_equal ''"$(last_commit_message)"'' "Added subproject using git subtree" &&
+ undo
'
test_expect_success 'check if --message works with squash too' '
- git subtree add -P subdir -m "Added subproject with squash" --squash sub1 &&
- check_equal ''"$(last_commit_message)"'' "Added subproject with squash" &&
- undo
+ git subtree add -P subdir -m "Added subproject with squash" --squash sub1 &&
+ check_equal ''"$(last_commit_message)"'' "Added subproject with squash" &&
+ undo
'
test_expect_success 'add subproj to mainline' '
- git subtree add --prefix=subdir/ FETCH_HEAD &&
- check_equal ''"$(last_commit_message)"'' "Add '"'subdir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'"
+ git subtree add --prefix=subdir/ FETCH_HEAD &&
+ check_equal ''"$(last_commit_message)"'' "Add '"'subdir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'"
'
# this shouldn't actually do anything, since FETCH_HEAD is already a parent
test_expect_success 'merge fetched subproj' '
- git merge -m "merge -s -ours" -s ours FETCH_HEAD
+ git merge -m "merge -s -ours" -s ours FETCH_HEAD
'
test_expect_success 'add main-sub5' '
- create subdir/main-sub5 &&
- git commit -m "main-sub5"
+ create subdir/main-sub5 &&
+ git commit -m "main-sub5"
'
test_expect_success 'add main6' '
- create main6 &&
- git commit -m "main6 boring"
+ create main6 &&
+ git commit -m "main6 boring"
'
test_expect_success 'add main-sub7' '
- create subdir/main-sub7 &&
- git commit -m "main-sub7"
+ create subdir/main-sub7 &&
+ git commit -m "main-sub7"
'
test_expect_success 'fetch new subproj history' '
- git fetch ./subproj sub2 &&
- git branch sub2 FETCH_HEAD
+ git fetch ./subproj sub2 &&
+ git branch sub2 FETCH_HEAD
'
test_expect_success 'check if --message works for merge' '
- git subtree merge --prefix=subdir -m "Merged changes from subproject" sub2 &&
- check_equal ''"$(last_commit_message)"'' "Merged changes from subproject" &&
- undo
+ git subtree merge --prefix=subdir -m "Merged changes from subproject" sub2 &&
+ check_equal ''"$(last_commit_message)"'' "Merged changes from subproject" &&
+ undo
'
test_expect_success 'check if --message for merge works with squash too' '
- git subtree merge --prefix subdir -m "Merged changes from subproject using squash" --squash sub2 &&
- check_equal ''"$(last_commit_message)"'' "Merged changes from subproject using squash" &&
- undo
+ git subtree merge --prefix subdir -m "Merged changes from subproject using squash" --squash sub2 &&
+ check_equal ''"$(last_commit_message)"'' "Merged changes from subproject using squash" &&
+ undo
'
test_expect_success 'merge new subproj history into subdir' '
- git subtree merge --prefix=subdir FETCH_HEAD &&
- git branch pre-split &&
- check_equal ''"$(last_commit_message)"'' "Merge commit '"'"'"$(git rev-parse sub2)"'"'"' into mainline"
+ git subtree merge --prefix=subdir FETCH_HEAD &&
+ git branch pre-split &&
+ check_equal ''"$(last_commit_message)"'' "Merge commit '"'"'"$(git rev-parse sub2)"'"'"' into mainline" &&
+ undo
'
test_expect_success 'Check that prefix argument is required for split' '
- echo "You must provide the --prefix option." > expected &&
- test_must_fail git subtree split > actual 2>&1 &&
+ echo "You must provide the --prefix option." > expected &&
+ test_must_fail git subtree split > actual 2>&1 &&
test_debug "printf '"'"'expected: '"'"'" &&
- test_debug "cat expected" &&
+ test_debug "cat expected" &&
test_debug "printf '"'"'actual: '"'"'" &&
- test_debug "cat actual" &&
- test_cmp expected actual &&
- rm -f expected actual
+ test_debug "cat actual" &&
+ test_cmp expected actual &&
+ rm -f expected actual
'
test_expect_success 'Check that the <prefix> exists for a split' '
- echo "'"'"'non-existent-directory'"'"'" does not exist\; use "'"'"'git subtree add'"'"'" > expected &&
- test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
+ echo "'"'"'non-existent-directory'"'"'" does not exist\; use "'"'"'git subtree add'"'"'" > expected &&
+ test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
test_debug "printf '"'"'expected: '"'"'" &&
- test_debug "cat expected" &&
+ test_debug "cat expected" &&
test_debug "printf '"'"'actual: '"'"'" &&
- test_debug "cat actual" &&
- test_cmp expected actual
-# rm -f expected actual
+ test_debug "cat actual" &&
+ test_cmp expected actual
+# rm -f expected actual
'
test_expect_success 'check if --message works for split+rejoin' '
- spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
- git branch spl1 "$spl1" &&
- check_equal ''"$(last_commit_message)"'' "Split & rejoin" &&
- undo
+ spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
+ git branch spl1 "$spl1" &&
+ check_equal ''"$(last_commit_message)"'' "Split & rejoin" &&
+ undo
'
test_expect_success 'check split with --branch' '
@@ -218,79 +219,76 @@ test_expect_success 'check split with --branch' '
test_expect_success 'check hash of split' '
spl1=$(git subtree split --prefix subdir) &&
- undo &&
git subtree split --prefix subdir --branch splitbr1test &&
- check_equal ''"$(git rev-parse splitbr1test)"'' "$spl1"
- git checkout splitbr1test &&
- new_hash=$(git rev-parse HEAD~2) &&
- git checkout mainline &&
+ check_equal ''"$(git rev-parse splitbr1test)"'' "$spl1" &&
+ new_hash=$(git rev-parse splitbr1test~2) &&
check_equal ''"$new_hash"'' "$subdir_hash"
'
test_expect_success 'check split with --branch for an existing branch' '
- spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
- undo &&
- git branch splitbr2 sub1 &&
- git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr2 &&
- check_equal ''"$(git rev-parse splitbr2)"'' "$spl1"
+ spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
+ undo &&
+ git branch splitbr2 sub1 &&
+ git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr2 &&
+ check_equal ''"$(git rev-parse splitbr2)"'' "$spl1"
'
test_expect_success 'check split with --branch for an incompatible branch' '
- test_must_fail git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir
+ test_must_fail git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir
'
test_expect_success 'check split+rejoin' '
- spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
- undo &&
- git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --rejoin &&
- check_equal ''"$(last_commit_message)"'' "Split '"'"'subdir/'"'"' into commit '"'"'"$spl1"'"'"'"
+ spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
+ undo &&
+ git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --rejoin &&
+ check_equal ''"$(last_commit_message)"'' "Split '"'"'subdir/'"'"' into commit '"'"'"$spl1"'"'"'"
'
test_expect_success 'add main-sub8' '
- create subdir/main-sub8 &&
- git commit -m "main-sub8"
+ create subdir/main-sub8 &&
+ git commit -m "main-sub8"
'
# To the subproject!
cd ./subproj
test_expect_success 'merge split into subproj' '
- git fetch .. spl1 &&
- git branch spl1 FETCH_HEAD &&
- git merge FETCH_HEAD
+ git fetch .. spl1 &&
+ git branch spl1 FETCH_HEAD &&
+ git merge FETCH_HEAD
'
test_expect_success 'add sub9' '
- create sub9 &&
- git commit -m "sub9"
+ create sub9 &&
+ git commit -m "sub9"
'
# Back to mainline
cd ..
test_expect_success 'split for sub8' '
- split2=''"$(git subtree split --annotate='"'*'"' --prefix subdir/ --rejoin)"''
- git branch split2 "$split2"
+ split2=''"$(git subtree split --annotate='"'*'"' --prefix subdir/ --rejoin)"'' &&
+ git branch split2 "$split2"
'
test_expect_success 'add main-sub10' '
- create subdir/main-sub10 &&
- git commit -m "main-sub10"
+ create subdir/main-sub10 &&
+ git commit -m "main-sub10"
'
test_expect_success 'split for sub10' '
- spl3=''"$(git subtree split --annotate='"'*'"' --prefix subdir --rejoin)"'' &&
- git branch spl3 "$spl3"
+ spl3=''"$(git subtree split --annotate='"'*'"' --prefix subdir --rejoin)"'' &&
+ git branch spl3 "$spl3"
'
# To the subproject!
cd ./subproj
test_expect_success 'merge split into subproj' '
- git fetch .. spl3 &&
- git branch spl3 FETCH_HEAD &&
- git merge FETCH_HEAD &&
- git branch subproj-merge-spl3
+ git fetch .. spl3 &&
+ git branch spl3 FETCH_HEAD &&
+ git merge FETCH_HEAD &&
+ git branch subproj-merge-spl3
'
chkm="main4 main6"
@@ -300,44 +298,44 @@ chks="sub1 sub2 sub3 sub9"
chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl)
test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
- subfiles=''"$(git ls-files | fixnl)"'' &&
- check_equal "$subfiles" "$chkms $chks"
+ subfiles=''"$(git ls-files | fixnl)"'' &&
+ check_equal "$subfiles" "$chkms $chks"
'
test_expect_success 'make sure the subproj history *only* contains commits that affect the subdir' '
- allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' &&
- check_equal "$allchanges" "$chkms $chks"
+ allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' &&
+ check_equal "$allchanges" "$chkms $chks"
'
# Back to mainline
cd ..
test_expect_success 'pull from subproj' '
- git fetch ./subproj subproj-merge-spl3 &&
- git branch subproj-merge-spl3 FETCH_HEAD &&
- git subtree pull --prefix=subdir ./subproj subproj-merge-spl3
+ git fetch ./subproj subproj-merge-spl3 &&
+ git branch subproj-merge-spl3 FETCH_HEAD &&
+ git subtree pull --prefix=subdir ./subproj subproj-merge-spl3
'
test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
- mainfiles=''"$(git ls-files | fixnl)"'' &&
- check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
+ mainfiles=''"$(git ls-files | fixnl)"'' &&
+ check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
'
test_expect_success 'make sure each filename changed exactly once in the entire history' '
- # main-sub?? and /subdir/main-sub?? both change, because those are the
- # changes that were split into their own history. And subdir/sub?? never
- # change, since they were *only* changed in the subtree branch.
- allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' &&
- check_equal "$allchanges" ''"$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"''
+ # main-sub?? and /subdir/main-sub?? both change, because those are the
+ # changes that were split into their own history. And subdir/sub?? never
+ # change, since they were *only* changed in the subtree branch.
+ allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' &&
+ check_equal "$allchanges" ''"$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"''
'
test_expect_success 'make sure the --rejoin commits never make it into subproj' '
- check_equal ''"$(git log --pretty=format:'"'%s'"' HEAD^2 | grep -i split)"'' ""
+ check_equal ''"$(git log --pretty=format:'"'%s'"' HEAD^2 | grep -i split)"'' ""
'
test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
- # They are meaningless to subproj since one side of the merge refers to the mainline
- check_equal ''"$(git log --pretty=format:'"'%s%n%b'"' HEAD^2 | grep "git-subtree.*:")"'' ""
+ # They are meaningless to subproj since one side of the merge refers to the mainline
+ check_equal ''"$(git log --pretty=format:'"'%s%n%b'"' HEAD^2 | grep "git-subtree.*:")"'' ""
'
# prepare second pair of repositories
@@ -345,27 +343,27 @@ mkdir test2
cd test2
test_expect_success 'init main' '
- test_create_repo main
+ test_create_repo main
'
cd main
test_expect_success 'add main1' '
- create main1 &&
- git commit -m "main1"
+ create main1 &&
+ git commit -m "main1"
'
cd ..
test_expect_success 'init sub' '
- test_create_repo sub
+ test_create_repo sub
'
cd sub
test_expect_success 'add sub2' '
- create sub2 &&
- git commit -m "sub2"
+ create sub2 &&
+ git commit -m "sub2"
'
cd ../main
@@ -373,33 +371,33 @@ cd ../main
# check if split can find proper base without --onto
test_expect_success 'add sub as subdir in main' '
- git fetch ../sub master &&
- git branch sub2 FETCH_HEAD &&
- git subtree add --prefix subdir sub2
+ git fetch ../sub master &&
+ git branch sub2 FETCH_HEAD &&
+ git subtree add --prefix subdir sub2
'
cd ../sub
test_expect_success 'add sub3' '
- create sub3 &&
- git commit -m "sub3"
+ create sub3 &&
+ git commit -m "sub3"
'
cd ../main
test_expect_success 'merge from sub' '
- git fetch ../sub master &&
- git branch sub3 FETCH_HEAD &&
- git subtree merge --prefix subdir sub3
+ git fetch ../sub master &&
+ git branch sub3 FETCH_HEAD &&
+ git subtree merge --prefix subdir sub3
'
test_expect_success 'add main-sub4' '
- create subdir/main-sub4 &&
- git commit -m "main-sub4"
+ create subdir/main-sub4 &&
+ git commit -m "main-sub4"
'
test_expect_success 'split for main-sub4 without --onto' '
- git subtree split --prefix subdir --branch mainsub4
+ git subtree split --prefix subdir --branch mainsub4
'
# at this point, the new commit parent should be sub3 if it is not,
@@ -408,21 +406,21 @@ test_expect_success 'split for main-sub4 without --onto' '
# itself)
test_expect_success 'check that the commit parent is sub3' '
- check_equal ''"$(git log --pretty=format:%P -1 mainsub4)"'' ''"$(git rev-parse sub3)"''
+ check_equal ''"$(git log --pretty=format:%P -1 mainsub4)"'' ''"$(git rev-parse sub3)"''
'
test_expect_success 'add main-sub5' '
- mkdir subdir2 &&
- create subdir2/main-sub5 &&
- git commit -m "main-sub5"
+ mkdir subdir2 &&
+ create subdir2/main-sub5 &&
+ git commit -m "main-sub5"
'
test_expect_success 'split for main-sub5 without --onto' '
- # also test that we still can split out an entirely new subtree
- # if the parent of the first commit in the tree is not empty,
+ # also test that we still can split out an entirely new subtree
+ # if the parent of the first commit in the tree is not empty,
# then the new subtree has accidentally been attached to something
- git subtree split --prefix subdir2 --branch mainsub5 &&
- check_equal ''"$(git log --pretty=format:%P -1 mainsub5)"'' ""
+ git subtree split --prefix subdir2 --branch mainsub5 &&
+ check_equal ''"$(git log --pretty=format:%P -1 mainsub5)"'' ""
'
# make sure no patch changes more than one file. The original set of commits
@@ -450,20 +448,20 @@ joincommits()
}
test_expect_success 'verify one file change per commit' '
- x= &&
- list=''"$(git log --pretty=format:'"'commit: %H'"' | joincommits)"'' &&
-# test_debug "echo HERE" &&
-# test_debug "echo ''"$list"''" &&
- (git log --pretty=format:'"'commit: %H'"' | joincommits |
- ( while read commit a b; do
- test_debug "echo Verifying commit "''"$commit"''
- test_debug "echo a: "''"$a"''
- test_debug "echo b: "''"$b"''
- check_equal "$b" ""
- x=1
- done
- check_equal "$x" 1
- ))
+ x= &&
+ list=''"$(git log --pretty=format:'"'commit: %H'"' | joincommits)"'' &&
+# test_debug "echo HERE" &&
+# test_debug "echo ''"$list"''" &&
+ (git log --pretty=format:'"'commit: %H'"' | joincommits |
+ ( while read commit a b; do
+ test_debug "echo Verifying commit "''"$commit"''
+ test_debug "echo a: "''"$a"''
+ test_debug "echo b: "''"$b"''
+ check_equal "$b" ""
+ x=1
+ done
+ check_equal "$x" 1
+ ))
'
test_done
diff --git a/diff-lib.c b/diff-lib.c
index 0d8c535..241a843 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -212,11 +212,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
ce->sha1, !is_null_sha1(ce->sha1),
ce->name, 0);
continue;
- } else if (ce->ce_flags & CE_INTENT_TO_ADD) {
- diff_addremove(&revs->diffopt, '+', ce->ce_mode,
- EMPTY_BLOB_SHA1_BIN, 0,
- ce->name, 0);
- continue;
}
changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
@@ -381,13 +376,6 @@ static void do_oneway_diff(struct unpack_trees_options *o,
struct rev_info *revs = o->unpack_data;
int match_missing, cached;
- /* i-t-a entries do not actually exist in the index */
- if (idx && (idx->ce_flags & CE_INTENT_TO_ADD)) {
- idx = NULL;
- if (!tree)
- return; /* nothing to diff.. */
- }
-
/* if the entry is not checked out, don't examine work tree */
cached = o->index_only ||
(idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx)));
diff --git a/diff.c b/diff.c
index 87b16d5..0f17ec5 100644
--- a/diff.c
+++ b/diff.c
@@ -3653,7 +3653,12 @@ static void enable_patch_output(int *fmt) {
static int parse_one_token(const char **arg, const char *token)
{
- return skip_prefix(*arg, token, arg) && (!**arg || **arg == ',');
+ const char *rest;
+ if (skip_prefix(*arg, token, &rest) && (!*rest || *rest == ',')) {
+ *arg = rest;
+ return 1;
+ }
+ return 0;
}
static int parse_ws_error_highlight(struct diff_options *opt, const char *arg)
diff --git a/environment.c b/environment.c
index 61c685b..a533aed 100644
--- a/environment.c
+++ b/environment.c
@@ -47,6 +47,7 @@ const char *askpass_program;
const char *excludes_file;
enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
int check_replace_refs = 1;
+char *git_replace_ref_base;
enum eol core_eol = EOL_UNSET;
enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
@@ -110,6 +111,7 @@ const char * const local_repo_env[] = {
GRAFT_ENVIRONMENT,
INDEX_ENVIRONMENT,
NO_REPLACE_OBJECTS_ENVIRONMENT,
+ GIT_REPLACE_REF_BASE_ENVIRONMENT,
GIT_PREFIX_ENVIRONMENT,
GIT_SHALLOW_FILE_ENVIRONMENT,
GIT_COMMON_DIR_ENVIRONMENT,
@@ -156,6 +158,7 @@ static void setup_git_env(void)
struct strbuf sb = STRBUF_INIT;
const char *gitfile;
const char *shallow_file;
+ const char *replace_ref_base;
git_dir = getenv(GIT_DIR_ENVIRONMENT);
if (!git_dir)
@@ -173,6 +176,9 @@ static void setup_git_env(void)
"info/grafts", &git_graft_env);
if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
check_replace_refs = 0;
+ replace_ref_base = getenv(GIT_REPLACE_REF_BASE_ENVIRONMENT);
+ git_replace_ref_base = xstrdup(replace_ref_base ? replace_ref_base
+ : "refs/replace/");
namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
namespace_len = strlen(namespace);
shallow_file = getenv(GIT_SHALLOW_FILE_ENVIRONMENT);
@@ -231,6 +237,8 @@ void set_git_work_tree(const char *new_work_tree)
}
git_work_tree_initialized = 1;
work_tree = xstrdup(real_path(new_work_tree));
+ if (setenv(GIT_WORK_TREE_ENVIRONMENT, work_tree, 1))
+ die("could not set GIT_WORK_TREE to '%s'", work_tree);
}
const char *get_git_work_tree(void)
diff --git a/ewah/bitmap.c b/ewah/bitmap.c
index 710e58c..47ad674 100644
--- a/ewah/bitmap.c
+++ b/ewah/bitmap.c
@@ -20,8 +20,8 @@
#include "git-compat-util.h"
#include "ewok.h"
-#define MASK(x) ((eword_t)1 << (x % BITS_IN_WORD))
-#define BLOCK(x) (x / BITS_IN_WORD)
+#define EWAH_MASK(x) ((eword_t)1 << (x % BITS_IN_EWORD))
+#define EWAH_BLOCK(x) (x / BITS_IN_EWORD)
struct bitmap *bitmap_new(void)
{
@@ -33,7 +33,7 @@ struct bitmap *bitmap_new(void)
void bitmap_set(struct bitmap *self, size_t pos)
{
- size_t block = BLOCK(pos);
+ size_t block = EWAH_BLOCK(pos);
if (block >= self->word_alloc) {
size_t old_size = self->word_alloc;
@@ -45,22 +45,22 @@ void bitmap_set(struct bitmap *self, size_t pos)
(self->word_alloc - old_size) * sizeof(eword_t));
}
- self->words[block] |= MASK(pos);
+ self->words[block] |= EWAH_MASK(pos);
}
void bitmap_clear(struct bitmap *self, size_t pos)
{
- size_t block = BLOCK(pos);
+ size_t block = EWAH_BLOCK(pos);
if (block < self->word_alloc)
- self->words[block] &= ~MASK(pos);
+ self->words[block] &= ~EWAH_MASK(pos);
}
int bitmap_get(struct bitmap *self, size_t pos)
{
- size_t block = BLOCK(pos);
+ size_t block = EWAH_BLOCK(pos);
return block < self->word_alloc &&
- (self->words[block] & MASK(pos)) != 0;
+ (self->words[block] & EWAH_MASK(pos)) != 0;
}
struct ewah_bitmap *bitmap_to_ewah(struct bitmap *bitmap)
@@ -127,7 +127,7 @@ void bitmap_and_not(struct bitmap *self, struct bitmap *other)
void bitmap_or_ewah(struct bitmap *self, struct ewah_bitmap *other)
{
size_t original_size = self->word_alloc;
- size_t other_final = (other->bit_size / BITS_IN_WORD) + 1;
+ size_t other_final = (other->bit_size / BITS_IN_EWORD) + 1;
size_t i = 0;
struct ewah_iterator it;
eword_t word;
@@ -155,17 +155,17 @@ void bitmap_each_bit(struct bitmap *self, ewah_callback callback, void *data)
uint32_t offset;
if (word == (eword_t)~0) {
- for (offset = 0; offset < BITS_IN_WORD; ++offset)
+ for (offset = 0; offset < BITS_IN_EWORD; ++offset)
callback(pos++, data);
} else {
- for (offset = 0; offset < BITS_IN_WORD; ++offset) {
+ for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
if ((word >> offset) == 0)
break;
offset += ewah_bit_ctz64(word >> offset);
callback(pos + offset, data);
}
- pos += BITS_IN_WORD;
+ pos += BITS_IN_EWORD;
}
}
}
diff --git a/ewah/ewah_bitmap.c b/ewah/ewah_bitmap.c
index fccb42b..b522437 100644
--- a/ewah/ewah_bitmap.c
+++ b/ewah/ewah_bitmap.c
@@ -102,7 +102,7 @@ size_t ewah_add_empty_words(struct ewah_bitmap *self, int v, size_t number)
if (number == 0)
return 0;
- self->bit_size += number * BITS_IN_WORD;
+ self->bit_size += number * BITS_IN_EWORD;
return add_empty_words(self, v, number);
}
@@ -152,7 +152,7 @@ void ewah_add_dirty_words(
self->buffer_size += can_add;
}
- self->bit_size += can_add * BITS_IN_WORD;
+ self->bit_size += can_add * BITS_IN_EWORD;
if (number - can_add == 0)
break;
@@ -197,7 +197,7 @@ static size_t add_empty_word(struct ewah_bitmap *self, int v)
size_t ewah_add(struct ewah_bitmap *self, eword_t word)
{
- self->bit_size += BITS_IN_WORD;
+ self->bit_size += BITS_IN_EWORD;
if (word == 0)
return add_empty_word(self, 0);
@@ -211,8 +211,8 @@ size_t ewah_add(struct ewah_bitmap *self, eword_t word)
void ewah_set(struct ewah_bitmap *self, size_t i)
{
const size_t dist =
- (i + BITS_IN_WORD) / BITS_IN_WORD -
- (self->bit_size + BITS_IN_WORD - 1) / BITS_IN_WORD;
+ (i + BITS_IN_EWORD) / BITS_IN_EWORD -
+ (self->bit_size + BITS_IN_EWORD - 1) / BITS_IN_EWORD;
assert(i >= self->bit_size);
@@ -222,19 +222,19 @@ void ewah_set(struct ewah_bitmap *self, size_t i)
if (dist > 1)
add_empty_words(self, 0, dist - 1);
- add_literal(self, (eword_t)1 << (i % BITS_IN_WORD));
+ add_literal(self, (eword_t)1 << (i % BITS_IN_EWORD));
return;
}
if (rlw_get_literal_words(self->rlw) == 0) {
rlw_set_running_len(self->rlw,
rlw_get_running_len(self->rlw) - 1);
- add_literal(self, (eword_t)1 << (i % BITS_IN_WORD));
+ add_literal(self, (eword_t)1 << (i % BITS_IN_EWORD));
return;
}
self->buffer[self->buffer_size - 1] |=
- ((eword_t)1 << (i % BITS_IN_WORD));
+ ((eword_t)1 << (i % BITS_IN_EWORD));
/* check if we just completed a stream of 1s */
if (self->buffer[self->buffer_size - 1] == (eword_t)(~0)) {
@@ -255,11 +255,11 @@ void ewah_each_bit(struct ewah_bitmap *self, void (*callback)(size_t, void*), vo
eword_t *word = &self->buffer[pointer];
if (rlw_get_run_bit(word)) {
- size_t len = rlw_get_running_len(word) * BITS_IN_WORD;
+ size_t len = rlw_get_running_len(word) * BITS_IN_EWORD;
for (k = 0; k < len; ++k, ++pos)
callback(pos, payload);
} else {
- pos += rlw_get_running_len(word) * BITS_IN_WORD;
+ pos += rlw_get_running_len(word) * BITS_IN_EWORD;
}
++pointer;
@@ -268,7 +268,7 @@ void ewah_each_bit(struct ewah_bitmap *self, void (*callback)(size_t, void*), vo
int c;
/* todo: zero count optimization */
- for (c = 0; c < BITS_IN_WORD; ++c, ++pos) {
+ for (c = 0; c < BITS_IN_EWORD; ++c, ++pos) {
if ((self->buffer[pointer] & ((eword_t)1 << c)) != 0)
callback(pos, payload);
}
diff --git a/ewah/ewok.h b/ewah/ewok.h
index e732525..6e2c5e1 100644
--- a/ewah/ewok.h
+++ b/ewah/ewok.h
@@ -32,7 +32,7 @@
struct strbuf;
typedef uint64_t eword_t;
-#define BITS_IN_WORD (sizeof(eword_t) * 8)
+#define BITS_IN_EWORD (sizeof(eword_t) * 8)
/**
* Do not use __builtin_popcountll. The GCC implementation
diff --git a/fetch-pack.c b/fetch-pack.c
index a912935..a136772 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -809,7 +809,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
sort_ref_list(&ref, ref_compare_name);
qsort(sought, nr_sought, sizeof(*sought), cmp_ref_by_name);
- if (is_repository_shallow() && !server_supports("shallow"))
+ if ((args->depth > 0 || is_repository_shallow()) && !server_supports("shallow"))
die("Server does not support shallow clients");
if (server_supports("multi_ack_detailed")) {
if (args->verbose)
diff --git a/fsck.c b/fsck.c
index 10bcb65..24b2a5f 100644
--- a/fsck.c
+++ b/fsck.c
@@ -241,8 +241,8 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
return retval;
}
-static int require_end_of_header(const void *data, unsigned long size,
- struct object *obj, fsck_error error_func)
+static int verify_headers(const void *data, unsigned long size,
+ struct object *obj, fsck_error error_func)
{
const char *buffer = (const char *)data;
unsigned long i;
@@ -258,6 +258,15 @@ static int require_end_of_header(const void *data, unsigned long size,
}
}
+ /*
+ * We did not find double-LF that separates the header
+ * and the body. Not having a body is not a crime but
+ * we do want to see the terminating LF for the last header
+ * line.
+ */
+ if (size && buffer[size - 1] == '\n')
+ return 0;
+
return error_func(obj, FSCK_ERROR, "unterminated header");
}
@@ -308,7 +317,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
unsigned parent_count, parent_line_count = 0;
int err;
- if (require_end_of_header(buffer, size, &commit->object, error_func))
+ if (verify_headers(buffer, size, &commit->object, error_func))
return -1;
if (!skip_prefix(buffer, "tree ", &buffer))
@@ -387,7 +396,7 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
}
}
- if (require_end_of_header(buffer, size, &tag->object, error_func))
+ if (verify_headers(buffer, size, &tag->object, error_func))
goto done;
if (!skip_prefix(buffer, "object ", &buffer)) {
diff --git a/git-am.sh b/git-am.sh
index 761befb..3b77028 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -69,6 +69,8 @@ then
cmdline="$cmdline -3"
fi
+empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+
sq () {
git rev-parse --sq-quote "$@"
}
@@ -85,7 +87,7 @@ safe_to_abort () {
return 1
fi
- if ! test -s "$dotest/abort-safety"
+ if ! test -f "$dotest/abort-safety"
then
return 0
fi
@@ -177,7 +179,8 @@ It does not apply to blobs recorded in its index.")"
then
GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY
fi
- git-merge-recursive $orig_tree -- HEAD $his_tree || {
+ our_tree=$(git rev-parse --verify -q HEAD || echo $empty_tree)
+ git-merge-recursive $orig_tree -- $our_tree $his_tree || {
git rerere $allow_rerere_autoupdate
die "$(gettext "Failed to merge in the changes.")"
}
@@ -297,6 +300,7 @@ split_patches () {
;;
stgit)
this=0
+ test 0 -eq "$#" && set -- -
for stgit in "$@"
do
this=$(expr "$this" + 1)
@@ -318,7 +322,7 @@ split_patches () {
print "Subject: ", $_ ;
$subject = 1;
}
- ' < "$stgit" > "$dotest/$msgnum" || clean_abort
+ ' -- "$stgit" >"$dotest/$msgnum" || clean_abort
done
echo "$this" > "$dotest/last"
this=
@@ -326,6 +330,7 @@ split_patches () {
;;
hg)
this=0
+ test 0 -eq "$#" && set -- -
for hg in "$@"
do
this=$(( $this + 1 ))
@@ -342,17 +347,17 @@ split_patches () {
elsif (/^\# User /) { s/\# User/From:/ ; print ; }
elsif (/^\# Date /) {
my ($hashsign, $str, $time, $tz) = split ;
- $tz = sprintf "%+05d", (0-$tz)/36;
+ $tz_str = sprintf "%+05d", (0-$tz)/36;
print "Date: " .
strftime("%a, %d %b %Y %H:%M:%S ",
- localtime($time))
- . "$tz\n";
+ gmtime($time-$tz))
+ . "$tz_str\n";
} elsif (/^\# /) { next ; }
else {
print "\n", $_ ;
$subject = 1;
}
- ' <"$hg" >"$dotest/$msgnum" || clean_abort
+ ' -- "$hg" >"$dotest/$msgnum" || clean_abort
done
echo "$this" >"$dotest/last"
this=
@@ -378,6 +383,7 @@ committer_date_is_author_date=
ignore_date=
allow_rerere_autoupdate=
gpg_sign_opt=
+threeway=
if test "$(git config --bool --get am.messageid)" = true
then
@@ -502,10 +508,11 @@ then
;;
t,)
git rerere clear
- git read-tree --reset -u HEAD HEAD
- orig_head=$(cat "$GIT_DIR/ORIG_HEAD")
- git reset HEAD
- git update-ref ORIG_HEAD $orig_head
+ head_tree=$(git rev-parse --verify -q HEAD || echo $empty_tree) &&
+ git read-tree --reset -u $head_tree $head_tree &&
+ index_tree=$(git write-tree) &&
+ git read-tree -m -u $index_tree $head_tree
+ git read-tree $head_tree
;;
,t)
if test -f "$dotest/rebasing"
@@ -515,8 +522,19 @@ then
git rerere clear
if safe_to_abort
then
- git read-tree --reset -u HEAD ORIG_HEAD
- git reset ORIG_HEAD
+ head_tree=$(git rev-parse --verify -q HEAD || echo $empty_tree) &&
+ git read-tree --reset -u $head_tree $head_tree &&
+ index_tree=$(git write-tree) &&
+ orig_head=$(git rev-parse --verify -q ORIG_HEAD || echo $empty_tree) &&
+ git read-tree -m -u $index_tree $orig_head
+ if git rev-parse --verify -q ORIG_HEAD >/dev/null 2>&1
+ then
+ git reset ORIG_HEAD
+ else
+ git read-tree $empty_tree
+ curr_branch=$(git symbolic-ref HEAD 2>/dev/null) &&
+ git update-ref -d $curr_branch
+ fi
fi
rm -fr "$dotest"
exit ;;
diff --git a/git-compat-util.h b/git-compat-util.h
index 0cc7ae8..c6d391f 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -58,15 +58,13 @@
#define BUILD_ASSERT_OR_ZERO(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)
-#if defined(__GNUC__) && (__GNUC__ >= 3)
-# if GIT_GNUC_PREREQ(3, 1)
+#if GIT_GNUC_PREREQ(3, 1)
/* &arr[0] degrades to a pointer: a different type from an array */
# define BARF_UNLESS_AN_ARRAY(arr) \
BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(__typeof__(arr), \
__typeof__(&(arr)[0])))
-# else
-# define BARF_UNLESS_AN_ARRAY(arr) 0
-# endif
+#else
+# define BARF_UNLESS_AN_ARRAY(arr) 0
#endif
/*
* ARRAY_SIZE - get the number of elements in a visible array
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 82ecb03..1e4e65a 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -921,7 +921,7 @@ sub commit {
# (See check_refname_component in refs.c.)
1 while $xtag =~ s/
(?: \.\. # Tag cannot contain '..'.
- | \@{ # Tag cannot contain '@{'.
+ | \@\{ # Tag cannot contain '@{'.
| ^ - # Tag cannot begin with '-'.
| \.lock $ # Tag cannot end with '.lock'.
| ^ \. # Tag cannot begin...
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index 14b039d..54ac8e4 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -305,6 +305,7 @@ guess_merge_tool () {
EOF
# Loop over each candidate and stop when a valid merge tool is found.
+ IFS=' '
for tool in $tools
do
is_available "$tool" && echo "$tool" && return 0
diff --git a/git-p4.py b/git-p4.py
index 26ad4bc..073f87b 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -43,6 +43,9 @@ verbose = False
# Only labels/tags matching this will be imported/exported
defaultLabelRegexp = r'[a-zA-Z0-9_\-.]+$'
+# Grab changes in blocks of this many revisions, unless otherwise requested
+defaultBlockSize = 512
+
def p4_build_cmd(cmd):
"""Build a suitable p4 command line.
@@ -249,6 +252,10 @@ def p4_reopen(type, f):
def p4_move(src, dest):
p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
+def p4_last_change():
+ results = p4CmdList(["changes", "-m", "1"])
+ return int(results[0]['change'])
+
def p4_describe(change):
"""Make sure it returns a valid result by checking for
the presence of field "time". Return a dict of the
@@ -742,43 +749,77 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent
def originP4BranchesExist():
return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
-def p4ChangesForPaths(depotPaths, changeRange, block_size):
+
+def p4ParseNumericChangeRange(parts):
+ changeStart = int(parts[0][1:])
+ if parts[1] == '#head':
+ changeEnd = p4_last_change()
+ else:
+ changeEnd = int(parts[1])
+
+ return (changeStart, changeEnd)
+
+def chooseBlockSize(blockSize):
+ if blockSize:
+ return blockSize
+ else:
+ return defaultBlockSize
+
+def p4ChangesForPaths(depotPaths, changeRange, requestedBlockSize):
assert depotPaths
- assert block_size
- # Parse the change range into start and end
+ # Parse the change range into start and end. Try to find integer
+ # revision ranges as these can be broken up into blocks to avoid
+ # hitting server-side limits (maxrows, maxscanresults). But if
+ # that doesn't work, fall back to using the raw revision specifier
+ # strings, without using block mode.
+
if changeRange is None or changeRange == '':
- changeStart = '@1'
- changeEnd = '#head'
+ changeStart = 1
+ changeEnd = p4_last_change()
+ block_size = chooseBlockSize(requestedBlockSize)
else:
parts = changeRange.split(',')
assert len(parts) == 2
- changeStart = parts[0]
- changeEnd = parts[1]
+ try:
+ (changeStart, changeEnd) = p4ParseNumericChangeRange(parts)
+ block_size = chooseBlockSize(requestedBlockSize)
+ except:
+ changeStart = parts[0][1:]
+ changeEnd = parts[1]
+ if requestedBlockSize:
+ die("cannot use --changes-block-size with non-numeric revisions")
+ block_size = None
# Accumulate change numbers in a dictionary to avoid duplicates
changes = {}
for p in depotPaths:
# Retrieve changes a block at a time, to prevent running
- # into a MaxScanRows error from the server.
- start = changeStart
- end = changeEnd
- get_another_block = True
- while get_another_block:
- new_changes = []
+ # into a MaxResults/MaxScanRows error from the server.
+
+ while True:
cmd = ['changes']
- cmd += ['-m', str(block_size)]
- cmd += ["%s...%s,%s" % (p, start, end)]
+
+ if block_size:
+ end = min(changeEnd, changeStart + block_size)
+ revisionRange = "%d,%d" % (changeStart, end)
+ else:
+ revisionRange = "%s,%s" % (changeStart, changeEnd)
+
+ cmd += ["%s...@%s" % (p, revisionRange)]
+
for line in p4_read_pipe_lines(cmd):
changeNum = int(line.split(" ")[1])
- new_changes.append(changeNum)
changes[changeNum] = True
- if len(new_changes) == block_size:
- get_another_block = True
- end = '@' + str(min(new_changes))
- else:
- get_another_block = False
+
+ if not block_size:
+ break
+
+ if end >= changeEnd:
+ break
+
+ changeStart = end + 1
changelist = changes.keys()
changelist.sort()
@@ -1974,7 +2015,7 @@ class P4Sync(Command, P4UserMap):
self.syncWithOrigin = True
self.importIntoRemotes = True
self.maxChanges = ""
- self.changes_block_size = 500
+ self.changes_block_size = None
self.keepRepoPath = False
self.depotPaths = None
self.p4BranchesInGit = []
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index f923732..9ae898b 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -78,7 +78,7 @@ else
As a result, git cannot rebase them.
EOF
- return $?
+ return $ret
fi
git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" \
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index dc3133f..2f6ce55 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -740,10 +740,15 @@ collapse_todo_ids() {
# "pick sha1 fixup!/squash! msg" appears in it so that the latter
# comes immediately after the former, and change "pick" to
# "fixup"/"squash".
+#
+# Note that if the config has specified a custom instruction format
+# each log message will be re-retrieved in order to normalize the
+# autosquash arrangement
rearrange_squash () {
# extract fixup!/squash! lines and resolve any referenced sha1's
while read -r pick sha1 message
do
+ test -z "${format}" || message=$(git log -n 1 --format="%s" ${sha1})
case "$message" in
"squash! "*|"fixup! "*)
action="${message%%!*}"
@@ -785,6 +790,7 @@ rearrange_squash () {
*" $sha1 "*) continue ;;
esac
printf '%s\n' "$pick $sha1 $message"
+ test -z "${format}" || message=$(git log -n 1 --format="%s" ${sha1})
used="$used$sha1 "
while read -r squash action msg_prefix msg_content
do
@@ -802,8 +808,13 @@ rearrange_squash () {
case "$message" in "$msg_content"*) emit=1;; esac ;;
esac
if test $emit = 1; then
- real_prefix=$(echo "$msg_prefix" | sed "s/,/! /g")
- printf '%s\n' "$action $squash ${real_prefix}$msg_content"
+ if test -n "${format}"
+ then
+ msg_content=$(git log -n 1 --format="${format}" ${squash})
+ else
+ msg_content="$(echo "$msg_prefix" | sed "s/,/! /g")$msg_content"
+ fi
+ printf '%s\n' "$action $squash $msg_content"
used="$used$squash "
fi
done <"$1.sq"
@@ -849,7 +860,11 @@ continue)
# do we have anything to commit?
if git diff-index --cached --quiet HEAD --
then
- : Nothing to commit -- skip this
+ # Nothing to commit -- skip this commit
+
+ test ! -f "$GIT_DIR"/CHERRY_PICK_HEAD ||
+ rm "$GIT_DIR"/CHERRY_PICK_HEAD ||
+ die "Could not remove CHERRY_PICK_HEAD"
else
if ! test -f "$author_script"
then
@@ -977,7 +992,10 @@ else
revisions=$onto...$orig_head
shortrevisions=$shorthead
fi
-git rev-list $merges_option --pretty=oneline --reverse --left-right --topo-order \
+format=$(git config --get rebase.instructionFormat)
+# the 'rev-list .. | sed' requires %m to parse; the instruction requires %H to parse
+git rev-list $merges_option --format="%m%H ${format:-%s}" \
+ --reverse --left-right --topo-order \
$revisions ${restrict_revision+^$restrict_revision} | \
sed -n "s/^>//p" |
while read -r sha1 rest
diff --git a/git-send-email.perl b/git-send-email.perl
index e1e9b14..b660cc2 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -460,25 +460,11 @@ my ($repoauthor, $repocommitter);
($repoauthor) = Git::ident_person(@repo, 'author');
($repocommitter) = Git::ident_person(@repo, 'committer');
-# Verify the user input
-
-foreach my $entry (@initial_to) {
- die "Comma in --to entry: $entry'\n" unless $entry !~ m/,/;
-}
-
-foreach my $entry (@initial_cc) {
- die "Comma in --cc entry: $entry'\n" unless $entry !~ m/,/;
-}
-
-foreach my $entry (@bcclist) {
- die "Comma in --bcclist entry: $entry'\n" unless $entry !~ m/,/;
-}
-
sub parse_address_line {
if ($have_mail_address) {
return map { $_->format } Mail::Address->parse($_[0]);
} else {
- return split_addrs($_[0]);
+ return Git::parse_mailboxes($_[0]);
}
}
@@ -487,6 +473,37 @@ sub split_addrs {
}
my %aliases;
+
+sub parse_sendmail_alias {
+ local $_ = shift;
+ if (/"/) {
+ print STDERR "warning: sendmail alias with quotes is not supported: $_\n";
+ } elsif (/:include:/) {
+ print STDERR "warning: `:include:` not supported: $_\n";
+ } elsif (/[\/|]/) {
+ print STDERR "warning: `/file` or `|pipe` redirection not supported: $_\n";
+ } elsif (/^(\S+?)\s*:\s*(.+)$/) {
+ my ($alias, $addr) = ($1, $2);
+ $aliases{$alias} = [ split_addrs($addr) ];
+ } else {
+ print STDERR "warning: sendmail line is not recognized: $_\n";
+ }
+}
+
+sub parse_sendmail_aliases {
+ my $fh = shift;
+ my $s = '';
+ while (<$fh>) {
+ chomp;
+ next if /^\s*$/ || /^\s*#/;
+ $s .= $_, next if $s =~ s/\\$// || s/^\s+//;
+ parse_sendmail_alias($s) if $s;
+ $s = $_;
+ }
+ $s =~ s/\\$//; # silently tolerate stray '\' on last line
+ parse_sendmail_alias($s) if $s;
+}
+
my %parse_alias = (
# multiline formats can be supported in the future
mutt => sub { my $fh = shift; while (<$fh>) {
@@ -515,7 +532,7 @@ my %parse_alias = (
$aliases{$alias} = [ split_addrs($addr) ];
}
} },
-
+ sendmail => \&parse_sendmail_aliases,
gnus => sub { my $fh = shift; while (<$fh>) {
if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
$aliases{$1} = [ $2 ];
@@ -530,8 +547,6 @@ if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
}
}
-($sender) = expand_aliases($sender) if defined $sender;
-
# is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
# $f is a revision list specification to be passed to format-patch.
sub is_format_patch_arg {
@@ -776,7 +791,10 @@ if (!$force) {
}
}
-if (!defined $sender) {
+if (defined $sender) {
+ $sender =~ s/^\s+|\s+$//g;
+ ($sender) = expand_aliases($sender);
+} else {
$sender = $repoauthor || $repocommitter || '';
}
@@ -808,12 +826,9 @@ sub expand_one_alias {
return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;
}
-@initial_to = expand_aliases(@initial_to);
-@initial_to = validate_address_list(sanitize_address_list(@initial_to));
-@initial_cc = expand_aliases(@initial_cc);
-@initial_cc = validate_address_list(sanitize_address_list(@initial_cc));
-@bcclist = expand_aliases(@bcclist);
-@bcclist = validate_address_list(sanitize_address_list(@bcclist));
+@initial_to = process_address_list(@initial_to);
+@initial_cc = process_address_list(@initial_cc);
+@bcclist = process_address_list(@bcclist);
if ($thread && !defined $initial_reply_to && $prompting) {
$initial_reply_to = ask(
@@ -1006,15 +1021,17 @@ sub sanitize_address {
return $recipient;
}
+ # remove non-escaped quotes
+ $recipient_name =~ s/(^|[^\\])"/$1/g;
+
# rfc2047 is needed if a non-ascii char is included
if ($recipient_name =~ /[^[:ascii:]]/) {
- $recipient_name =~ s/^"(.*)"$/$1/;
$recipient_name = quote_rfc2047($recipient_name);
}
# double quotes are needed if specials or CTLs are included
elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
- $recipient_name =~ s/(["\\\r])/\\$1/g;
+ $recipient_name =~ s/([\\\r])/\\$1/g;
$recipient_name = qq["$recipient_name"];
}
@@ -1026,6 +1043,14 @@ sub sanitize_address_list {
return (map { sanitize_address($_) } @_);
}
+sub process_address_list {
+ my @addr_list = map { parse_address_line($_) } @_;
+ @addr_list = expand_aliases(@addr_list);
+ @addr_list = sanitize_address_list(@addr_list);
+ @addr_list = validate_address_list(@addr_list);
+ return @addr_list;
+}
+
# Returns the local Fully Qualified Domain Name (FQDN) if available.
#
# Tightly configured MTAa require that a caller sends a real DNS
@@ -1535,8 +1560,8 @@ foreach my $t (@files) {
($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
$needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
- @to = validate_address_list(sanitize_address_list(@to));
- @cc = validate_address_list(sanitize_address_list(@cc));
+ @to = process_address_list(@to);
+ @cc = process_address_list(@cc);
@to = (@initial_to, @to);
@cc = (@initial_cc, @cc);
diff --git a/git-stash.sh b/git-stash.sh
index 1f5ea87..8e9e2cd 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -457,8 +457,6 @@ apply_stash () {
assert_stash_like "$@"
git update-index -q --refresh || die "$(gettext "unable to refresh index")"
- git diff-index --cached --quiet --ignore-submodules HEAD -- ||
- die "$(gettext "Cannot apply stash: Your index contains uncommitted changes.")"
# current index state
c_tree=$(git write-tree) ||
diff --git a/git.c b/git.c
index 44374b1..55c327c 100644
--- a/git.c
+++ b/git.c
@@ -382,7 +382,7 @@ static struct cmd_struct commands[] = {
{ "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
{ "check-mailmap", cmd_check_mailmap, RUN_SETUP },
{ "check-ref-format", cmd_check_ref_format },
- { "checkout", cmd_checkout, RUN_SETUP },
+ { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
{ "checkout-index", cmd_checkout_index,
RUN_SETUP | NEED_WORK_TREE},
{ "cherry", cmd_cherry, RUN_SETUP },
@@ -445,6 +445,7 @@ static struct cmd_struct commands[] = {
{ "pickaxe", cmd_blame, RUN_SETUP },
{ "prune", cmd_prune, RUN_SETUP },
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
+ { "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
{ "push", cmd_push, RUN_SETUP },
{ "read-tree", cmd_read_tree, RUN_SETUP },
{ "receive-pack", cmd_receive_pack },
@@ -483,6 +484,7 @@ static struct cmd_struct commands[] = {
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
{ "version", cmd_version },
{ "whatchanged", cmd_whatchanged, RUN_SETUP },
+ { "worktree", cmd_worktree, RUN_SETUP },
{ "write-tree", cmd_write_tree, RUN_SETUP },
};
diff --git a/gpg-interface.c b/gpg-interface.c
index 68b0c81..3dc2fe3 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -60,6 +60,43 @@ void parse_gpg_output(struct signature_check *sigc)
}
}
+int check_signature(const char *payload, size_t plen, const char *signature,
+ size_t slen, struct signature_check *sigc)
+{
+ struct strbuf gpg_output = STRBUF_INIT;
+ struct strbuf gpg_status = STRBUF_INIT;
+ int status;
+
+ sigc->result = 'N';
+
+ status = verify_signed_buffer(payload, plen, signature, slen,
+ &gpg_output, &gpg_status);
+ if (status && !gpg_output.len)
+ goto out;
+ sigc->payload = xmemdupz(payload, plen);
+ sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
+ sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
+ parse_gpg_output(sigc);
+
+ out:
+ strbuf_release(&gpg_status);
+ strbuf_release(&gpg_output);
+
+ return sigc->result != 'G' && sigc->result != 'U';
+}
+
+void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
+{
+ const char *output = flags & GPG_VERIFY_RAW ?
+ sigc->gpg_status : sigc->gpg_output;
+
+ if (flags & GPG_VERIFY_VERBOSE && sigc->payload)
+ fputs(sigc->payload, stdout);
+
+ if (output)
+ fputs(output, stderr);
+}
+
/*
* Look at GPG signed content (e.g. a signed tag object), whose
* payload is followed by a detached signature on it. Return the
diff --git a/gpg-interface.h b/gpg-interface.h
index 87a4f2e..ea68885 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -1,6 +1,9 @@
#ifndef GPG_INTERFACE_H
#define GPG_INTERFACE_H
+#define GPG_VERIFY_VERBOSE 1
+#define GPG_VERIFY_RAW 2
+
struct signature_check {
char *payload;
char *gpg_output;
@@ -27,5 +30,8 @@ extern int verify_signed_buffer(const char *payload, size_t payload_size, const
extern int git_gpg_config(const char *, const char *, void *);
extern void set_signing_key(const char *);
extern const char *get_signing_key(void);
+extern int check_signature(const char *payload, size_t plen,
+ const char *signature, size_t slen, struct signature_check *sigc);
+void print_signature_buffer(const struct signature_check *sigc, unsigned flags);
#endif
diff --git a/help.c b/help.c
index 80ca8ee..d996b34 100644
--- a/help.c
+++ b/help.c
@@ -394,7 +394,7 @@ const char *help_unknown_cmd(const char *cmd)
if (autocorrect > 0) {
fprintf_ln(stderr, _("in %0.1f seconds automatically..."),
(float)autocorrect/10.0);
- poll(NULL, 0, autocorrect * 100);
+ sleep_millisec(autocorrect * 100);
}
return assumed;
}
diff --git a/http.c b/http.c
index f0c5bbc..e9c6fdd 100644
--- a/http.c
+++ b/http.c
@@ -416,10 +416,10 @@ static CURL *get_curl_handle(void)
if (curl_http_proxy) {
curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
+ }
#if LIBCURL_VERSION_NUM >= 0x070a07
- curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+ curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
#endif
- }
set_curl_keepalive(result);
diff --git a/ll-merge.c b/ll-merge.c
index 8ea03e5..fc3c049 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -9,6 +9,7 @@
#include "xdiff-interface.h"
#include "run-command.h"
#include "ll-merge.h"
+#include "quote.h"
struct ll_merge_driver;
@@ -166,17 +167,20 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
{
char temp[4][50];
struct strbuf cmd = STRBUF_INIT;
- struct strbuf_expand_dict_entry dict[5];
+ struct strbuf_expand_dict_entry dict[6];
+ struct strbuf path_sq = STRBUF_INIT;
const char *args[] = { NULL, NULL };
int status, fd, i;
struct stat st;
assert(opts);
+ sq_quote_buf(&path_sq, path);
dict[0].placeholder = "O"; dict[0].value = temp[0];
dict[1].placeholder = "A"; dict[1].value = temp[1];
dict[2].placeholder = "B"; dict[2].value = temp[2];
dict[3].placeholder = "L"; dict[3].value = temp[3];
- dict[4].placeholder = NULL; dict[4].value = NULL;
+ dict[4].placeholder = "P"; dict[4].value = path_sq.buf;
+ dict[5].placeholder = NULL; dict[5].value = NULL;
if (fn->cmdline == NULL)
die("custom merge driver %s lacks command line.", fn->name);
@@ -210,6 +214,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
for (i = 0; i < 3; i++)
unlink_or_warn(temp[i]);
strbuf_release(&cmd);
+ strbuf_release(&path_sq);
return status;
}
@@ -269,6 +274,7 @@ static int read_merge_config(const char *var, const char *value, void *cb)
* %A - temporary file name for our version.
* %B - temporary file name for the other branches' version.
* %L - conflict marker length
+ * %P - the original path (safely quoted for the shell)
*
* The external merge driver should write the results in the
* file named by %A, and signal that it has done with zero exit
diff --git a/lockfile.c b/lockfile.c
index 5a93bc7..993bb82 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -157,14 +157,6 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
return lk->fd;
}
-static int sleep_microseconds(long us)
-{
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = us;
- return select(0, NULL, NULL, NULL, &tv);
-}
-
/*
* Constants defining the gaps between attempts to lock a file. The
* first backoff period is approximately INITIAL_BACKOFF_MS
@@ -184,27 +176,22 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
{
int n = 1;
int multiplier = 1;
- long remaining_us = 0;
+ long remaining_ms = 0;
static int random_initialized = 0;
if (timeout_ms == 0)
return lock_file(lk, path, flags);
if (!random_initialized) {
- srandom((unsigned int)getpid());
+ srand((unsigned int)getpid());
random_initialized = 1;
}
- if (timeout_ms > 0) {
- /* avoid overflow */
- if (timeout_ms <= LONG_MAX / 1000)
- remaining_us = timeout_ms * 1000;
- else
- remaining_us = LONG_MAX;
- }
+ if (timeout_ms > 0)
+ remaining_ms = timeout_ms;
while (1) {
- long backoff_ms, wait_us;
+ long backoff_ms, wait_ms;
int fd;
fd = lock_file(lk, path, flags);
@@ -213,14 +200,14 @@ static int lock_file_timeout(struct lock_file *lk, const char *path,
return fd; /* success */
else if (errno != EEXIST)
return -1; /* failure other than lock held */
- else if (timeout_ms > 0 && remaining_us <= 0)
+ else if (timeout_ms > 0 && remaining_ms <= 0)
return -1; /* failure due to timeout */
backoff_ms = multiplier * INITIAL_BACKOFF_MS;
/* back off for between 0.75*backoff_ms and 1.25*backoff_ms */
- wait_us = (750 + random() % 500) * backoff_ms;
- sleep_microseconds(wait_us);
- remaining_us -= wait_us;
+ wait_ms = (750 + rand() % 500) * backoff_ms / 1000;
+ sleep_millisec(wait_ms);
+ remaining_ms -= wait_ms;
/* Recursion: (n+1)^2 = n^2 + 2n + 1 */
multiplier += 2*n + 1;
diff --git a/log-tree.c b/log-tree.c
index 01beb11..e2f6de7 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -97,11 +97,12 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
assert(cb_data == NULL);
- if (starts_with(refname, "refs/replace/")) {
+ if (starts_with(refname, git_replace_ref_base)) {
struct object_id original_oid;
if (!check_replace_refs)
return 0;
- if (get_oid_hex(refname + 13, &original_oid)) {
+ if (get_oid_hex(refname + strlen(git_replace_ref_base),
+ &original_oid)) {
warning("invalid replace ref %s", refname);
return 0;
}
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 2b3ff23..637770a 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -622,7 +622,7 @@ static void show_objects_for_type(
while (i < objects->word_alloc && ewah_iterator_next(&filter, &it)) {
eword_t word = objects->words[i] & filter;
- for (offset = 0; offset < BITS_IN_WORD; ++offset) {
+ for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
const unsigned char *sha1;
struct revindex_entry *entry;
uint32_t hash = 0;
@@ -644,7 +644,7 @@ static void show_objects_for_type(
show_reach(sha1, object_type, 0, hash, bitmap_git.pack, entry->offset);
}
- pos += BITS_IN_WORD;
+ pos += BITS_IN_EWORD;
i++;
}
}
@@ -776,7 +776,7 @@ int reuse_partial_packfile_from_bitmap(struct packed_git **packfile,
break;
}
- reuse_objects += BITS_IN_WORD;
+ reuse_objects += BITS_IN_EWORD;
}
#ifdef GIT_BITMAP_DEBUG
@@ -1001,7 +1001,7 @@ static int rebuild_bitmap(uint32_t *reposition,
while (ewah_iterator_next(&word, &it)) {
uint32_t offset, bit_pos;
- for (offset = 0; offset < BITS_IN_WORD; ++offset) {
+ for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
if ((word >> offset) == 0)
break;
@@ -1014,7 +1014,7 @@ static int rebuild_bitmap(uint32_t *reposition,
return -1;
}
- pos += BITS_IN_WORD;
+ pos += BITS_IN_EWORD;
}
return 0;
}
diff --git a/pager.c b/pager.c
index 98b2682..070dc11 100644
--- a/pager.c
+++ b/pager.c
@@ -78,6 +78,7 @@ void setup_pager(void)
argv_array_push(&pager_process.env_array, "LESS=FRX");
if (!getenv("LV"))
argv_array_push(&pager_process.env_array, "LV=-c");
+ argv_array_push(&pager_process.env_array, "GIT_PAGER_IN_USE");
if (start_command(&pager_process))
return;
diff --git a/parse-options-cb.c b/parse-options-cb.c
index be8c413..5ab6ed6 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -4,6 +4,7 @@
#include "commit.h"
#include "color.h"
#include "string-list.h"
+#include "argv-array.h"
/*----- some often used options -----*/
@@ -134,3 +135,71 @@ int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
{
return 0;
}
+
+/**
+ * Recreates the command-line option in the strbuf.
+ */
+static int recreate_opt(struct strbuf *sb, const struct option *opt,
+ const char *arg, int unset)
+{
+ strbuf_reset(sb);
+
+ if (opt->long_name) {
+ strbuf_addstr(sb, unset ? "--no-" : "--");
+ strbuf_addstr(sb, opt->long_name);
+ if (arg) {
+ strbuf_addch(sb, '=');
+ strbuf_addstr(sb, arg);
+ }
+ } else if (opt->short_name && !unset) {
+ strbuf_addch(sb, '-');
+ strbuf_addch(sb, opt->short_name);
+ if (arg)
+ strbuf_addstr(sb, arg);
+ } else
+ return -1;
+
+ return 0;
+}
+
+/**
+ * For an option opt, recreates the command-line option in opt->value which
+ * must be an char* initialized to NULL. This is useful when we need to pass
+ * the command-line option to another command. Since any previous value will be
+ * overwritten, this callback should only be used for options where the last
+ * one wins.
+ */
+int parse_opt_passthru(const struct option *opt, const char *arg, int unset)
+{
+ static struct strbuf sb = STRBUF_INIT;
+ char **opt_value = opt->value;
+
+ if (recreate_opt(&sb, opt, arg, unset) < 0)
+ return -1;
+
+ if (*opt_value)
+ free(*opt_value);
+
+ *opt_value = strbuf_detach(&sb, NULL);
+
+ return 0;
+}
+
+/**
+ * For an option opt, recreate the command-line option, appending it to
+ * opt->value which must be a argv_array. This is useful when we need to pass
+ * the command-line option, which can be specified multiple times, to another
+ * command.
+ */
+int parse_opt_passthru_argv(const struct option *opt, const char *arg, int unset)
+{
+ static struct strbuf sb = STRBUF_INIT;
+ struct argv_array *opt_value = opt->value;
+
+ if (recreate_opt(&sb, opt, arg, unset) < 0)
+ return -1;
+
+ argv_array_push(opt_value, sb.buf);
+
+ return 0;
+}
diff --git a/parse-options.c b/parse-options.c
index 80106c0..3eceba4 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -180,6 +180,23 @@ static int get_value(struct parse_opt_ctx_t *p,
return opterror(opt, "expects a numerical value", flags);
return 0;
+ case OPTION_MAGNITUDE:
+ if (unset) {
+ *(unsigned long *)opt->value = 0;
+ return 0;
+ }
+ if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+ *(unsigned long *)opt->value = opt->defval;
+ return 0;
+ }
+ if (get_arg(p, opt, flags, &arg))
+ return -1;
+ if (!git_parse_ulong(arg, opt->value))
+ return opterror(opt,
+ "expects a non-negative integer value with an optional k/m/g suffix",
+ flags);
+ return 0;
+
default:
die("should not happen, someone must be hit on the forehead");
}
diff --git a/parse-options.h b/parse-options.h
index c71e9da..6ca8388 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -16,6 +16,7 @@ enum parse_opt_type {
/* options with arguments (usually) */
OPTION_STRING,
OPTION_INTEGER,
+ OPTION_MAGNITUDE,
OPTION_CALLBACK,
OPTION_LOWLEVEL_CALLBACK,
OPTION_FILENAME
@@ -129,6 +130,8 @@ struct option {
#define OPT_CMDMODE(s, l, v, h, i) { OPTION_CMDMODE, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) }
#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), N_("n"), (h) }
+#define OPT_MAGNITUDE(s, l, v, h) { OPTION_MAGNITUDE, (s), (l), (v), \
+ N_("n"), (h), PARSE_OPT_NONEG }
#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
#define OPT_STRING_LIST(s, l, v, a, h) \
{ OPTION_CALLBACK, (s), (l), (v), (a), \
@@ -224,6 +227,8 @@ extern int parse_opt_with_commit(const struct option *, const char *, int);
extern int parse_opt_tertiary(const struct option *, const char *, int);
extern int parse_opt_string_list(const struct option *, const char *, int);
extern int parse_opt_noop_cb(const struct option *, const char *, int);
+extern int parse_opt_passthru(const struct option *, const char *, int);
+extern int parse_opt_passthru_argv(const struct option *, const char *, int);
#define OPT__VERBOSE(var, h) OPT_COUNTUP('v', "verbose", (var), (h))
#define OPT__QUIET(var, h) OPT_COUNTUP('q', "quiet", (var), (h))
@@ -242,5 +247,9 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int);
OPT_COLOR_FLAG(0, "color", (var), (h))
#define OPT_COLUMN(s, l, v, h) \
{ OPTION_CALLBACK, (s), (l), (v), N_("style"), (h), PARSE_OPT_OPTARG, parseopt_column_callback }
+#define OPT_PASSTHRU(s, l, v, a, h, f) \
+ { OPTION_CALLBACK, (s), (l), (v), (a), (h), (f), parse_opt_passthru }
+#define OPT_PASSTHRU_ARGV(s, l, v, a, h, f) \
+ { OPTION_CALLBACK, (s), (l), (v), (a), (h), (f), parse_opt_passthru_argv }
#endif
diff --git a/perl/Git.pm b/perl/Git.pm
index 9026a7b..19ef081 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -864,6 +864,73 @@ sub ident_person {
return "$ident[0] <$ident[1]>";
}
+=item parse_mailboxes
+
+Return an array of mailboxes extracted from a string.
+
+=cut
+
+sub parse_mailboxes {
+ my $re_comment = qr/\((?:[^)]*)\)/;
+ my $re_quote = qr/"(?:[^\"\\]|\\.)*"/;
+ my $re_word = qr/(?:[^]["\s()<>:;@\\,.]|\\.)+/;
+
+ # divide the string in tokens of the above form
+ my $re_token = qr/(?:$re_quote|$re_word|$re_comment|\S)/;
+ my @tokens = map { $_ =~ /\s*($re_token)\s*/g } @_;
+
+ # add a delimiter to simplify treatment for the last mailbox
+ push @tokens, ",";
+
+ my (@addr_list, @phrase, @address, @comment, @buffer) = ();
+ foreach my $token (@tokens) {
+ if ($token =~ /^[,;]$/) {
+ # if buffer still contains undeterminated strings
+ # append it at the end of @address or @phrase
+ if (@address) {
+ push @address, @buffer;
+ } else {
+ push @phrase, @buffer;
+ }
+
+ my $str_phrase = join ' ', @phrase;
+ my $str_address = join '', @address;
+ my $str_comment = join ' ', @comment;
+
+ # quote are necessary if phrase contains
+ # special characters
+ if ($str_phrase =~ /[][()<>:;@\\,.\000-\037\177]/) {
+ $str_phrase =~ s/(^|[^\\])"/$1/g;
+ $str_phrase = qq["$str_phrase"];
+ }
+
+ # add "<>" around the address if necessary
+ if ($str_address ne "" && $str_phrase ne "") {
+ $str_address = qq[<$str_address>];
+ }
+
+ my $str_mailbox = "$str_phrase $str_address $str_comment";
+ $str_mailbox =~ s/^\s*|\s*$//g;
+ push @addr_list, $str_mailbox if ($str_mailbox);
+
+ @phrase = @address = @comment = @buffer = ();
+ } elsif ($token =~ /^\(/) {
+ push @comment, $token;
+ } elsif ($token eq "<") {
+ push @phrase, (splice @address), (splice @buffer);
+ } elsif ($token eq ">") {
+ push @address, (splice @buffer);
+ } elsif ($token eq "@") {
+ push @address, (splice @buffer), "@";
+ } elsif ($token eq ".") {
+ push @address, (splice @buffer), ".";
+ } else {
+ push @buffer, $token;
+ }
+ }
+
+ return @addr_list;
+}
=item hash_object ( TYPE, FILENAME )
diff --git a/pkt-line.c b/pkt-line.c
index 187a229..08a1427 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -4,16 +4,51 @@
char packet_buffer[LARGE_PACKET_MAX];
static const char *packet_trace_prefix = "git";
static struct trace_key trace_packet = TRACE_KEY_INIT(PACKET);
+static struct trace_key trace_pack = TRACE_KEY_INIT(PACKFILE);
void packet_trace_identity(const char *prog)
{
packet_trace_prefix = xstrdup(prog);
}
+static int packet_trace_pack(const char *buf, unsigned int len, int sideband)
+{
+ if (!sideband) {
+ trace_verbatim(&trace_pack, buf, len);
+ return 1;
+ } else if (len && *buf == '\1') {
+ trace_verbatim(&trace_pack, buf + 1, len - 1);
+ return 1;
+ } else {
+ /* it's another non-pack sideband */
+ return 0;
+ }
+}
+
static void packet_trace(const char *buf, unsigned int len, int write)
{
int i;
struct strbuf out;
+ static int in_pack, sideband;
+
+ if (!trace_want(&trace_packet) && !trace_want(&trace_pack))
+ return;
+
+ if (in_pack) {
+ if (packet_trace_pack(buf, len, sideband))
+ return;
+ } else if (starts_with(buf, "PACK") || starts_with(buf, "\1PACK")) {
+ in_pack = 1;
+ sideband = *buf == '\1';
+ packet_trace_pack(buf, len, sideband);
+
+ /*
+ * Make a note in the human-readable trace that the pack data
+ * started.
+ */
+ buf = "PACK ...";
+ len = strlen(buf);
+ }
if (!trace_want(&trace_packet))
return;
@@ -24,22 +59,15 @@ static void packet_trace(const char *buf, unsigned int len, int write)
strbuf_addf(&out, "packet: %12s%c ",
packet_trace_prefix, write ? '>' : '<');
- if ((len >= 4 && starts_with(buf, "PACK")) ||
- (len >= 5 && starts_with(buf+1, "PACK"))) {
- strbuf_addstr(&out, "PACK ...");
- trace_disable(&trace_packet);
- }
- else {
- /* XXX we should really handle printable utf8 */
- for (i = 0; i < len; i++) {
- /* suppress newlines */
- if (buf[i] == '\n')
- continue;
- if (buf[i] >= 0x20 && buf[i] <= 0x7e)
- strbuf_addch(&out, buf[i]);
- else
- strbuf_addf(&out, "\\%o", buf[i]);
- }
+ /* XXX we should really handle printable utf8 */
+ for (i = 0; i < len; i++) {
+ /* suppress newlines */
+ if (buf[i] == '\n')
+ continue;
+ if (buf[i] >= 0x20 && buf[i] <= 0x7e)
+ strbuf_addch(&out, buf[i]);
+ else
+ strbuf_addf(&out, "\\%o", buf[i]);
}
strbuf_addch(&out, '\n');
diff --git a/po/bg.po b/po/bg.po
index 171f813..164a766 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -1,7 +1,7 @@
# Bulgarian translation of git po-file.
-# Copyright (C) 2014 Alexander Shopov <ash@kambanaria.org>.
+# Copyright (C) 2014, 2015 Alexander Shopov <ash@kambanaria.org>.
# This file is distributed under the same license as the git package.
-# Alexander Shopov <ash@kambanaria.org>, 2014.
+# Alexander Shopov <ash@kambanaria.org>, 2014, 2015.
#
# ========================
# DICTIONARY TO MERGE IN GIT GUI
@@ -21,8 +21,8 @@
# git bundle пратка на git
# bisect двоично търсене
# am прилагам поредица от кръпки
-# working directory/tree — винаги работно дърво, git следи цялото дърво, а не директории
-# switch to branch прехвърлям се/преминавам към клон
+# working directory/tree — винаги работно дърво, git следи цялото дърво, а не директории, работна директория за cwd
+# switch to branch преминавам към клон
# sparse entry частично изтеглена директория/път
# revision range диапазон на версиите
# cover letter придружаващо писмо
@@ -56,6 +56,10 @@
# mainline базово подаване - при cherry-pick на merge - към коя версия да се изчислява разликата
# token лексема
# trailer епилог/завършек на съобщение
+# cwd текуща работна директория
+# untracked cache кеш за неследените файлове
+# broken/corrupt повреден
+# restore възстановявам
# ----
# FAILED to parse неуспешен анализ на... -> неразпозната стойност на
# blob обект BLOB
@@ -91,11 +95,6 @@
# grep ^#: new.po | cut -c4- |tr ' ' '\n'| sed -e 's/:[0-9][0-9]*//' -e 's%.*/%%' -e 's/[.][^.]*$//' | sort -u
#
# ========================
-# STRINGS statistics
-# ------------------------
-# 2228t
-#
-# ========================
# MOST IMPORTANT name asc ordering
# ------------------------
# add, blame, branch, checkout, clone, commit, common-cmds, config, diff, fetch, fsck, gc, git-rebase, git-stash, grep, log, mv, parse-options, push, reflog, remote, reset, revert, rm, wt-status
@@ -105,33 +104,12 @@
# ------------------------
# apply, archive, check-ignore, clean, date, describe, git-am, git-bisect, git-submodule, hash-object, init-db, ls-tree, merge, merge-base, merge-file, merge-recursive, name-rev, pathspec, show-ref, tag
#
-# ========================
-# WHOLE STATISTICS strings desc, name asc ordering
-# ------------------------
-# 144 [remote] 47 [push] 26 [revert] 12 [checkout-index] 6 [prune] 2 [verify-tag]
-# 137 [commit] 46 [pack-objects] 24 [mv] 11 [date] 6 [gpg-interface] 2 [update-server-info]
-# 114 [branch] 41 [help] 23 [repack] 11 [column] 6 [check-attr] 2 [run-command]
-# 111 [apply] 39 [init-db] 21 [rm] 10 [urlmatch] 5 [write-tree] 2 [rerere]
-# 101 [notes] 36 [add] 21 [common-cmds] 10 [shortlog] 5 [sha1_name] 2 [read-cache]
-# 100 [wt-status] 35 [reset] 19 [show-branch] 10 [merge-file] 5 [rev-parse] 2 [obstack]
-# 97 [merge] 35 [archive] 19 [read-tree] 10 [merge-base] 4 [wrapper] 2 [advice]
-# 78 [checkout] 34 [config] 19 [bundle] 10 [ls-tree] 4 [prune-packed] 1 [unpack-trees]
-# 77 [log] 32 [clean] 16 [parse-options] 10 [hash-object] 4 [notes-utils] 1 [unpack-objects]
-# 69 [clone] 30 [git-am] 15 [fsck] 10 [for-each-ref] 4 [mktree] 1 [progress]
-# 68 [index-pack] 30 [describe] 14 [show-ref] 10 [cat-file] 4 [check-mailmap] 1 [precompose_utf8]
-# 68 [fetch] 29 [git-stash] 14 [gc] 9 [update-ref] 3 [verify-pack] 1 [object]
-# 64 [tag] 29 [git-bisect] 14 [fast-export] 9 [submodule] 3 [reflog] 1 [git]
-# 64 [grep] 28 [update-index] 13 [diff] 8 [replace] 3 [pack-refs] 1 [diffcore-rename]
-# 56 [sequencer] 28 [blame] 13 [check-ignore] 8 [git-pull] 3 [count-objects] 1 [diffcore-order]
-# 55 [merge-recursive] 27 [ls-files] 12 [pathspec] 8 [fmt-merge-msg] 3 [connected] 1 [attr]
-# 54 [git-submodule] 27 [git-rebase] 12 [name-rev] 7 [symbolic-ref] 3 [bisect--helper]
-#
msgid ""
msgstr ""
"Project-Id-Version: git master\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2015-04-03 08:13+0800\n"
-"PO-Revision-Date: 2015-04-07 11:21+0300\n"
+"POT-Creation-Date: 2015-07-14 07:19+0800\n"
+"PO-Revision-Date: 2015-07-14 19:05+0300\n"
"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"Language: bg\n"
@@ -173,7 +151,7 @@ msgstr ""
msgid "git archive --remote <repo> [--exec <cmd>] --list"
msgstr "git archive --remote ХРАНИЛИЩЕ [--exec КОМАНДА] --list"
-#: archive.c:342 builtin/add.c:137 builtin/add.c:427 builtin/rm.c:328
+#: archive.c:342 builtin/add.c:137 builtin/add.c:428 builtin/rm.c:327
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "пътят „%s“ не съвпада с никой файл"
@@ -196,9 +174,9 @@ msgstr "добавяне на този префикс към всеки път
#: archive.c:430 builtin/archive.c:88 builtin/blame.c:2516
#: builtin/blame.c:2517 builtin/config.c:57 builtin/fast-export.c:986
-#: builtin/fast-export.c:988 builtin/grep.c:712 builtin/hash-object.c:101
+#: builtin/fast-export.c:988 builtin/grep.c:712 builtin/hash-object.c:99
#: builtin/ls-files.c:446 builtin/ls-files.c:449 builtin/notes.c:394
-#: builtin/notes.c:557 builtin/read-tree.c:109 parse-options.h:151
+#: builtin/notes.c:557 builtin/read-tree.c:109 parse-options.h:150
msgid "file"
msgstr "файл"
@@ -230,7 +208,7 @@ msgstr "добро компресиране"
msgid "list supported archive formats"
msgstr "извеждане на списъка с поддържаните формати"
-#: archive.c:449 builtin/archive.c:90 builtin/clone.c:86
+#: archive.c:449 builtin/archive.c:90 builtin/clone.c:77
msgid "repo"
msgstr "хранилище"
@@ -246,7 +224,7 @@ msgstr "команда"
msgid "path to the remote git-upload-archive command"
msgstr "път към отдалечената команда „git-upload-archive“"
-#: attr.c:264
+#: attr.c:265
msgid ""
"Negative patterns are ignored in git attributes\n"
"Use '\\!' for literal leading exclamation."
@@ -386,8 +364,8 @@ msgid "Repository lacks these prerequisite commits:"
msgstr "В хранилището липсват следните необходими подавания:"
#: bundle.c:163 sequencer.c:650 sequencer.c:1105 builtin/blame.c:2705
-#: builtin/branch.c:659 builtin/commit.c:1045 builtin/log.c:330
-#: builtin/log.c:823 builtin/log.c:1432 builtin/log.c:1669 builtin/merge.c:358
+#: builtin/branch.c:651 builtin/commit.c:1045 builtin/log.c:330
+#: builtin/log.c:825 builtin/log.c:1432 builtin/log.c:1666 builtin/merge.c:358
#: builtin/shortlog.c:158
msgid "revision walk setup failed"
msgstr "неуспешно настройване на обхождането на версиите"
@@ -639,17 +617,17 @@ msgstr ""
"Грешки в настройката „diff.dirstat“:\n"
"%s"
-#: diff.c:2956
+#: diff.c:2997
#, c-format
msgid "external diff died, stopping at %s"
msgstr ""
"външната програма за разлики завърши неуспешно. Спиране на работата при „%s“"
-#: diff.c:3351
+#: diff.c:3393
msgid "--follow requires exactly one pathspec"
msgstr "Опцията „--follow“ изисква точно един път"
-#: diff.c:3514
+#: diff.c:3556
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
@@ -658,11 +636,19 @@ msgstr ""
"Неразпознат параметър към опцията „--dirstat/-X“:\n"
"%s"
-#: diff.c:3528
+#: diff.c:3570
#, c-format
msgid "Failed to parse --submodule option parameter: '%s'"
msgstr "Неразпознат параметър към опцията „--submodule“: „%s“"
+#: dir.c:1852
+msgid "failed to get kernel name and information"
+msgstr "името и версията на ядрото не бяха получени"
+
+#: dir.c:1945
+msgid "Untracked cache is disabled on this system."
+msgstr "Кеша за неследените файлове е изключен на тази система"
+
#: gpg-interface.c:129 gpg-interface.c:200
msgid "could not run gpg."
msgstr "Програмата „gpg“ не може да бъде стартирана."
@@ -709,11 +695,11 @@ msgstr "налични команди на git от „%s“"
msgid "git commands available from elsewhere on your $PATH"
msgstr "команди на git от други директории от „$PATH“"
-#: help.c:230
-msgid "The most commonly used git commands are:"
-msgstr "Най-често употребяваните команди на git са:"
+#: help.c:246
+msgid "These are common Git commands used in various situations:"
+msgstr "Това са най-често използваните команди на Git:"
-#: help.c:289
+#: help.c:311
#, c-format
msgid ""
"'%s' appears to be a git command, but we were not\n"
@@ -723,11 +709,11 @@ msgstr ""
"бъде изпълнена. Вероятно пакетът „git-%s“ е повреден."
# FIXME bad message
-#: help.c:346
+#: help.c:368
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "Странно, изглежда, че на системата ви няма нито една команда на git."
-#: help.c:368
+#: help.c:390
#, c-format
msgid ""
"WARNING: You called a Git command named '%s', which does not exist.\n"
@@ -738,17 +724,17 @@ msgstr ""
"съществува. Изпълнението автоматично продължава, като се счита, че имате "
"предвид „%s“"
-#: help.c:373
+#: help.c:395
#, c-format
msgid "in %0.1f seconds automatically..."
msgstr "след %0.1f секунди…"
-#: help.c:380
+#: help.c:402
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
-msgstr "git: „%s“ не е команда на git. Вижте изхода от „git --help“."
+msgstr "git: „%s“ не е команда на git. Погледнете изхода от „git --help“."
-#: help.c:384 help.c:444
+#: help.c:406 help.c:466
msgid ""
"\n"
"Did you mean this?"
@@ -762,16 +748,16 @@ msgstr[1] ""
"\n"
"Команди с подобно име са:"
-#: help.c:440
+#: help.c:462
#, c-format
msgid "%s: %s - %s"
msgstr "%s: %s — %s"
-#: lockfile.c:283
+#: lockfile.c:345
msgid "BUG: reopen a lockfile that is still open"
msgstr "ГРЕШКА В GIT: преотваряне на файл-ключалка"
-#: lockfile.c:285
+#: lockfile.c:347
msgid "BUG: reopen a lockfile that has been committed"
msgstr "ГРЕШКА В GIT: преотваряне на файл-ключалка, който е подаден"
@@ -779,8 +765,8 @@ msgstr "ГРЕШКА В GIT: преотваряне на файл-ключалк
msgid "failed to read the cache"
msgstr "кешът не може да бъде прочетен"
-#: merge.c:94 builtin/checkout.c:374 builtin/checkout.c:580
-#: builtin/clone.c:662
+#: merge.c:94 builtin/checkout.c:376 builtin/checkout.c:587
+#: builtin/clone.c:647
msgid "unable to write new index file"
msgstr "неуспешно записване на новия индекс"
@@ -798,67 +784,67 @@ msgstr "неуспешно изпълнение на „addinfo_cache“ за п
msgid "error building trees"
msgstr "грешка при изграждане на дърветата"
-#: merge-recursive.c:688
+#: merge-recursive.c:687
#, c-format
msgid "failed to create path '%s'%s"
msgstr "грешка при създаването на пътя „%s“%s"
-#: merge-recursive.c:699
+#: merge-recursive.c:698
#, c-format
msgid "Removing %s to make room for subdirectory\n"
msgstr "Изтриване на „%s“, за да се освободи място за поддиректория\n"
# FIXME better message
-#: merge-recursive.c:713 merge-recursive.c:734
+#: merge-recursive.c:712 merge-recursive.c:733
msgid ": perhaps a D/F conflict?"
msgstr ": възможно е да има конфликт директория/файл."
-#: merge-recursive.c:724
+#: merge-recursive.c:723
#, c-format
msgid "refusing to lose untracked file at '%s'"
msgstr ""
"преустановяване на действието, за да не се изтрие неследеният файл „%s“"
-#: merge-recursive.c:764
+#: merge-recursive.c:763
#, c-format
msgid "cannot read object %s '%s'"
msgstr "обектът „%s“ (%s) не може да бъде прочетен"
-#: merge-recursive.c:766
+#: merge-recursive.c:765
#, c-format
msgid "blob expected for %s '%s'"
msgstr "обектът „%s“ (%s) се очакваше да е BLOB, а не е"
-#: merge-recursive.c:789 builtin/clone.c:321
+#: merge-recursive.c:788 builtin/clone.c:306
#, c-format
msgid "failed to open '%s'"
msgstr "директорията „%s“ не може да бъде отворена"
-#: merge-recursive.c:797
+#: merge-recursive.c:796
#, c-format
msgid "failed to symlink '%s'"
msgstr "неуспешно създаване на символната връзка „%s“"
-#: merge-recursive.c:800
+#: merge-recursive.c:799
#, c-format
msgid "do not know what to do with %06o %s '%s'"
msgstr ""
"не е ясно какво да се прави с обекта „%2$s“ (%3$s) с права за достъп „%1$06o“"
-#: merge-recursive.c:938
+#: merge-recursive.c:937
msgid "Failed to execute internal merge"
msgstr "Неуспешно вътрешно сливане"
-#: merge-recursive.c:942
+#: merge-recursive.c:941
#, c-format
msgid "Unable to add %s to database"
msgstr "„%s“ не може да се добави в базата с данни"
-#: merge-recursive.c:958
+#: merge-recursive.c:957
msgid "unsupported object type in the tree"
msgstr "в дървото има неподдържан вид обект"
-#: merge-recursive.c:1033 merge-recursive.c:1047
+#: merge-recursive.c:1032 merge-recursive.c:1046
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -867,7 +853,7 @@ msgstr ""
"КОНФЛИКТ (%s/изтриване): „%s“ е изтрит в %s, а „%s“ в %s. Версия %s на „%s“ "
"е оставена в дървото."
-#: merge-recursive.c:1039 merge-recursive.c:1052
+#: merge-recursive.c:1038 merge-recursive.c:1051
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
@@ -876,20 +862,20 @@ msgstr ""
"КОНФЛИКТ (%s/изтриване): „%s“ е изтрит в %s, а „%s“ в %s. Версия %s на „%s“ "
"е оставена в дървото: %s."
-#: merge-recursive.c:1093
+#: merge-recursive.c:1092
msgid "rename"
msgstr "преименуване"
-#: merge-recursive.c:1093
+#: merge-recursive.c:1092
msgid "renamed"
msgstr "преименуван"
-#: merge-recursive.c:1149
+#: merge-recursive.c:1148
#, c-format
msgid "%s is a directory in %s adding as %s instead"
msgstr "„%s“ е директория в „%s“, затова се добавя като „%s“"
-#: merge-recursive.c:1171
+#: merge-recursive.c:1170
#, c-format
msgid ""
"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
@@ -898,151 +884,151 @@ msgstr ""
"КОНФЛИКТ (преименуване/преименуване): „%s“ е преименуван на „%s“ в клон "
"„%s“, а „%s“ е преименуван на „%s“ в „%s“/%s."
-#: merge-recursive.c:1176
+#: merge-recursive.c:1175
msgid " (left unresolved)"
msgstr " (некоригиран конфликт)"
-#: merge-recursive.c:1230
+#: merge-recursive.c:1229
#, c-format
msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
msgstr ""
"КОНФЛИКТ (преименуване/преименуване): „%s“ е преименуван на „%s“ в клон "
"„%s“, а „%s“ е преименуван на „%s“ в „%s“"
-#: merge-recursive.c:1260
+#: merge-recursive.c:1259
#, c-format
msgid "Renaming %s to %s and %s to %s instead"
msgstr "Преименуване на „%s“ на „%s“, а „%s“ на „%s“"
-#: merge-recursive.c:1459
+#: merge-recursive.c:1458
#, c-format
msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
msgstr ""
"КОНФЛИКТ (преименуване/добавяне): „%s“ е преименуван на „%s“ в клон „%s“, а "
"„%s“ е добавен в „%s“"
-#: merge-recursive.c:1469
+#: merge-recursive.c:1468
#, c-format
msgid "Adding merged %s"
msgstr "Добавяне на слетия „%s“"
-#: merge-recursive.c:1474 merge-recursive.c:1672
+#: merge-recursive.c:1473 merge-recursive.c:1671
#, c-format
msgid "Adding as %s instead"
msgstr "Добавяне като „%s“"
-#: merge-recursive.c:1525
+#: merge-recursive.c:1524
#, c-format
msgid "cannot read object %s"
msgstr "обектът „%s“ не може да се прочете"
-#: merge-recursive.c:1528
+#: merge-recursive.c:1527
#, c-format
msgid "object %s is not a blob"
msgstr "обектът „%s“ не е BLOB"
-#: merge-recursive.c:1576
+#: merge-recursive.c:1575
msgid "modify"
msgstr "промяна"
-#: merge-recursive.c:1576
+#: merge-recursive.c:1575
msgid "modified"
msgstr "променен"
-#: merge-recursive.c:1586
+#: merge-recursive.c:1585
msgid "content"
msgstr "съдържание"
-#: merge-recursive.c:1593
+#: merge-recursive.c:1592
msgid "add/add"
msgstr "добавяне/добавяне"
-#: merge-recursive.c:1627
+#: merge-recursive.c:1626
#, c-format
msgid "Skipped %s (merged same as existing)"
msgstr "Прескачане на „%s“ (слетият резултат е идентичен със сегашния)"
-#: merge-recursive.c:1641
+#: merge-recursive.c:1640
#, c-format
msgid "Auto-merging %s"
msgstr "Автоматично сливане на „%s“"
-#: merge-recursive.c:1645 git-submodule.sh:1150
+#: merge-recursive.c:1644 git-submodule.sh:1150
msgid "submodule"
msgstr "ПОДМОДУЛ"
-#: merge-recursive.c:1646
+#: merge-recursive.c:1645
#, c-format
msgid "CONFLICT (%s): Merge conflict in %s"
msgstr "КОНФЛИКТ (%s): Конфликт при сливане на „%s“"
-#: merge-recursive.c:1732
+#: merge-recursive.c:1731
#, c-format
msgid "Removing %s"
msgstr "Изтриване на „%s“"
-#: merge-recursive.c:1757
+#: merge-recursive.c:1756
msgid "file/directory"
msgstr "файл/директория"
-#: merge-recursive.c:1763
+#: merge-recursive.c:1762
msgid "directory/file"
msgstr "директория/файл"
-#: merge-recursive.c:1768
+#: merge-recursive.c:1767
#, c-format
msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
msgstr ""
"КОНФЛИКТ (%s): Съществува директория на име „%s“ в „%s“. Добавяне на „%s“ "
"като „%s“"
-#: merge-recursive.c:1778
+#: merge-recursive.c:1777
#, c-format
msgid "Adding %s"
msgstr "Добавяне на „%s“"
-#: merge-recursive.c:1795
+#: merge-recursive.c:1794
msgid "Fatal merge failure, shouldn't happen."
msgstr "Фатална грешка при сливане, а такава не трябва да възниква!"
-#: merge-recursive.c:1814
+#: merge-recursive.c:1813
msgid "Already up-to-date!"
msgstr "Вече е обновено!"
-#: merge-recursive.c:1823
+#: merge-recursive.c:1822
#, c-format
msgid "merging of trees %s and %s failed"
msgstr "неуспешно сливане на дърветата „%s“ и „%s“"
# FIXME message
-#: merge-recursive.c:1853
+#: merge-recursive.c:1852
#, c-format
msgid "Unprocessed path??? %s"
msgstr ""
"Пътят „%s“ не е обработен, това е грешка в Git, докладвайте я на "
"разработчиците, като пратите е-писмо на адрес: „git@vger.kernel.org“."
-#: merge-recursive.c:1901
+#: merge-recursive.c:1900
msgid "Merging:"
msgstr "Сливане:"
-#: merge-recursive.c:1914
+#: merge-recursive.c:1913
#, c-format
msgid "found %u common ancestor:"
msgid_plural "found %u common ancestors:"
msgstr[0] "открит е %u общ предшественик:"
msgstr[1] "открити са %u общи предшественици:"
-#: merge-recursive.c:1951
+#: merge-recursive.c:1950
msgid "merge returned no commit"
msgstr "сливането не върна подаване"
-#: merge-recursive.c:2008
+#: merge-recursive.c:2007
#, c-format
msgid "Could not parse object '%s'"
msgstr "Неуспешен анализ на обекта „%s“"
-#: merge-recursive.c:2019 builtin/merge.c:667
+#: merge-recursive.c:2018 builtin/merge.c:645
msgid "Unable to write index."
msgstr "Индексът не може да бъде прочетен"
@@ -1069,7 +1055,7 @@ msgstr ""
msgid "Bad %s value: '%s'"
msgstr "Зададена е лоша стойност на променливата „%s“: „%s“"
-#: object.c:241
+#: object.c:242
#, c-format
msgid "unable to parse object: %s"
msgstr "обектът „%s“ не може да бъде анализиран"
@@ -1167,11 +1153,11 @@ msgstr ""
msgid "unable to parse --pretty format"
msgstr "аргументът към опцията „--pretty“ не може да се анализира"
-#: progress.c:225
+#: progress.c:236
msgid "done"
msgstr "действието завърши"
-#: read-cache.c:1275
+#: read-cache.c:1295
#, c-format
msgid ""
"index.version set, but the value is invalid.\n"
@@ -1180,7 +1166,7 @@ msgstr ""
"Зададена е неправилна стойност на настройката „index.version“.\n"
"Ще се ползва версия %i"
-#: read-cache.c:1285
+#: read-cache.c:1305
#, c-format
msgid ""
"GIT_INDEX_VERSION set, but the value is invalid.\n"
@@ -1190,65 +1176,109 @@ msgstr ""
"„GIT_INDEX_VERSION“.\n"
"Ще се ползва версия %i"
-#: remote.c:782
+#: remote.c:792
#, c-format
msgid "Cannot fetch both %s and %s to %s"
msgstr "Невъзможно е да се доставят едновременно и „%s“, и „%s“ към „%s“"
-#: remote.c:786
+#: remote.c:796
#, c-format
msgid "%s usually tracks %s, not %s"
msgstr "„%s“ обикновено следи „%s“, а не „%s“"
-#: remote.c:790
+#: remote.c:800
#, c-format
msgid "%s tracks both %s and %s"
msgstr "„%s“ следи както „%s“, така и „%s“"
-#: remote.c:798
+#: remote.c:808
msgid "Internal error"
msgstr "Вътрешна грешка"
-#: remote.c:1980
+#: remote.c:1723 remote.c:1766
+msgid "HEAD does not point to a branch"
+msgstr "Указателят „HEAD“ не сочи към клон"
+
+#: remote.c:1732
+#, c-format
+msgid "no such branch: '%s'"
+msgstr "няма клон на име „%s“"
+
+#: remote.c:1735
+#, c-format
+msgid "no upstream configured for branch '%s'"
+msgstr "не е зададен клон-източник за клона „%s“"
+
+#: remote.c:1741
+#, c-format
+msgid "upstream branch '%s' not stored as a remote-tracking branch"
+msgstr "клонът-източник „%s“ не е съхранен като следящ клон"
+
+#: remote.c:1756
+#, c-format
+msgid "push destination '%s' on remote '%s' has no local tracking branch"
+msgstr ""
+"липсва локален следящ клон за местоположението за изтласкване „%s“ в "
+"хранилището „%s“"
+
+#: remote.c:1771
+#, c-format
+msgid "branch '%s' has no remote for pushing"
+msgstr "няма информация клонът „%s“ да следи някой друг"
+
+#: remote.c:1782
+#, c-format
+msgid "push refspecs for '%s' do not include '%s'"
+msgstr "указателят за изтласкване на „%s“ не включва „%s“"
+
+#: remote.c:1795
+msgid "push has no destination (push.default is 'nothing')"
+msgstr "указателят за изтласкване не включва цел („push.default“ е „nothing“)"
+
+#: remote.c:1817
+msgid "cannot resolve 'simple' push to a single destination"
+msgstr "простото (simple) изтласкване не съответства на една цел"
+
+#: remote.c:2124
#, c-format
msgid "Your branch is based on '%s', but the upstream is gone.\n"
msgstr "Този клон следи „%s“, но следеният клон е изтрит.\n"
-#: remote.c:1984
+#: remote.c:2128
msgid " (use \"git branch --unset-upstream\" to fixup)\n"
msgstr " (за да коригирате това, използвайте „git branch --unset-upstream“)\n"
-#: remote.c:1987
+#: remote.c:2131
#, c-format
msgid "Your branch is up-to-date with '%s'.\n"
msgstr "Клонът е актуализиран към „%s“.\n"
-#: remote.c:1991
+#: remote.c:2135
#, 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:1997
+#: remote.c:2141
msgid " (use \"git push\" to publish your local commits)\n"
msgstr " (публикувайте локалните си промени чрез „git push“)\n"
-#: remote.c:2000
+#: remote.c:2144
#, c-format
msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n"
msgid_plural ""
"Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n"
msgstr[0] ""
-"Клонът ви е с %2$d подаване след „%1$s“ и може да бъде тривиално слят.\n"
+"Клонът ви е с %2$d подаване зад „%1$s“ и може да бъде тривиално слят.\n"
msgstr[1] ""
-"Клонът ви е с %2$d подавания след „%1$s“ и може да бъде тривиално слят.\n"
+"Клонът ви е с %2$d подавания зад „%1$s“ и може да бъде тривиално слят.\n"
-#: remote.c:2008
+#: remote.c:2152
msgid " (use \"git pull\" to update your local branch)\n"
msgstr " (обновете локалния си клон чрез „git pull“)\n"
-#: remote.c:2011
+#: remote.c:2155
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
@@ -1263,11 +1293,11 @@ msgstr[1] ""
"Текущият клон се е отделил от „%s“,\n"
"двата имат съответно по %d и %d несъвпадащи подавания.\n"
-#: remote.c:2021
+#: remote.c:2165
msgid " (use \"git pull\" to merge the remote branch into yours)\n"
msgstr " (слейте отдалечения клон в локалния чрез „git pull“)\n"
-#: revision.c:2348
+#: revision.c:2366
msgid "--first-parent is incompatible with --bisect"
msgstr "опциите „--first-parent“ и „--bisect“ са несъвместими"
@@ -1284,22 +1314,22 @@ msgstr "неуспешно изпълнение на dup2(%d,%d)"
msgid "failed to sign the push certificate"
msgstr "сертификатът за изтласкване не може да бъде подписан"
-#: send-pack.c:356
+#: send-pack.c:378
msgid "the receiving end does not support --signed push"
msgstr "отсрещната страна не поддържа изтласкване с опцията „--signed“"
-#: send-pack.c:366
+#: send-pack.c:389
msgid "the receiving end does not support --atomic push"
msgstr "получаващата страна не поддържа изтласкване с опцията „--atomic“"
-#: sequencer.c:172 builtin/merge.c:782 builtin/merge.c:893 builtin/merge.c:995
-#: builtin/merge.c:1005
+#: sequencer.c:172 builtin/merge.c:760 builtin/merge.c:871 builtin/merge.c:973
+#: builtin/merge.c:983
#, c-format
msgid "Could not open '%s' for writing"
msgstr "„%s“ не може да бъде отворен за запис"
-#: sequencer.c:174 builtin/merge.c:344 builtin/merge.c:785 builtin/merge.c:997
-#: builtin/merge.c:1010
+#: sequencer.c:174 builtin/merge.c:344 builtin/merge.c:763 builtin/merge.c:975
+#: builtin/merge.c:988
#, c-format
msgid "Could not write to '%s'"
msgstr "„%s“ не може да бъде записан"
@@ -1505,7 +1535,7 @@ msgstr ""
"действието не може да бъде преустановено, когато сте на клон, който тепърва "
"предстои да бъде създаден"
-#: sequencer.c:908 builtin/apply.c:4288
+#: sequencer.c:908 builtin/apply.c:4291
#, c-format
msgid "cannot open %s: %s"
msgstr "файлът „%s“ не може да бъде отворен: %s"
@@ -1549,7 +1579,12 @@ msgstr "Първоначалното подаване не може да бъд
msgid "Can't cherry-pick into empty head"
msgstr "При празен връх не могат да се отбират подавания"
-#: sha1_name.c:440
+#: setup.c:243
+#, c-format
+msgid "failed to read %s"
+msgstr "файлът „%s“ не може да бъде прочетен"
+
+#: sha1_name.c:453
msgid ""
"Git normally never creates a ref that ends with 40 hex characters\n"
"because it will be ignored when you just specify 40-hex. These refs\n"
@@ -1573,25 +1608,6 @@ msgstr ""
"спрете това съобщение като изпълните командата:\n"
"„git config advice.objectNameWarning false“"
-#: sha1_name.c:1068
-msgid "HEAD does not point to a branch"
-msgstr "Указателят „HEAD“ не сочи към клон"
-
-#: sha1_name.c:1071
-#, c-format
-msgid "No such branch: '%s'"
-msgstr "Не съществува клон на име „%s“"
-
-#: sha1_name.c:1073
-#, c-format
-msgid "No upstream configured for branch '%s'"
-msgstr "Не е зададен клон-източник за клона „%s“"
-
-#: sha1_name.c:1077
-#, c-format
-msgid "Upstream branch '%s' not stored as a remote-tracking branch"
-msgstr "Клонът-източник „%s“ не е съхранен като следящ клон"
-
#: submodule.c:64 submodule.c:98
msgid "Cannot change unmerged .gitmodules, resolve merge conflicts first"
msgstr ""
@@ -1617,12 +1633,7 @@ msgstr "Записът „%s“ във файла „.gitmodules“ не мож
msgid "staging updated .gitmodules failed"
msgstr "неуспешно добавяне на променения файл „.gitmodules“ в индекса"
-#: submodule.c:1109 builtin/init-db.c:371
-#, c-format
-msgid "Could not create git link %s"
-msgstr "Връзката в Git „%s“ не може да бъде създадена"
-
-#: submodule.c:1120
+#: submodule.c:1115
#, c-format
msgid "Could not set core.worktree in %s"
msgstr "Настройката „core.worktree“ не може да се зададе в „%s“"
@@ -1652,7 +1663,7 @@ msgstr "входният файл „%s“ не може да бъде проч
msgid "could not read from stdin"
msgstr "от стандартния вход не може да се чете"
-#: unpack-trees.c:202
+#: unpack-trees.c:203
msgid "Checking out files"
msgstr "Изтегляне на файлове"
@@ -1708,6 +1719,22 @@ msgstr "такъв потребител не съществува"
msgid "unable to get current working directory"
msgstr "текущата работна директория е недостъпна"
+#: wrapper.c:575
+#, c-format
+msgid "could not open %s for writing"
+msgstr "„%s“ не може да бъде отворен за запис"
+
+# FIXME - must be the same as Could not write to '%s' above
+#: wrapper.c:587
+#, c-format
+msgid "could not write to %s"
+msgstr "„%s“ не може да бъде записан"
+
+#: wrapper.c:593
+#, c-format
+msgid "could not close %s"
+msgstr "„%s“ не може да се затвори"
+
#: wt-status.c:150
msgid "Unmerged paths:"
msgstr "Неслети пътища:"
@@ -1738,11 +1765,11 @@ msgid " (use \"git rm <file>...\" to mark resolution)"
msgstr ""
" (използвайте „git rm ФАЙЛ…“, за да укажете разрешаването на конфликта)"
-#: wt-status.c:198 wt-status.c:878
+#: wt-status.c:198 wt-status.c:881
msgid "Changes to be committed:"
msgstr "Промени, които ще бъдат подадени:"
-#: wt-status.c:216 wt-status.c:887
+#: wt-status.c:216 wt-status.c:890
msgid "Changes not staged for commit:"
msgstr "Промени, които не са в индекса за подаване:"
@@ -1857,15 +1884,15 @@ msgstr "неследено съдържание, "
msgid "bug: unhandled diff status %c"
msgstr "грешка: състоянието на промяната „%c“ не може да бъде обработено"
-#: wt-status.c:753
+#: wt-status.c:755
msgid "Submodules changed but not updated:"
msgstr "Подмодулите са променени, но не са обновени:"
-#: wt-status.c:755
+#: wt-status.c:757
msgid "Submodule changes to be committed:"
msgstr "Промени в подмодулите за подаване:"
-#: wt-status.c:835
+#: wt-status.c:838
msgid ""
"Do not touch the line above.\n"
"Everything below will be removed."
@@ -1873,193 +1900,193 @@ msgstr ""
"Не променяйте горния ред.\n"
"Всичко отдолу ще бъде изтрито."
-#: wt-status.c:946
+#: wt-status.c:949
msgid "You have unmerged paths."
msgstr "Някои пътища не са слети."
-#: wt-status.c:949
+#: wt-status.c:952
msgid " (fix conflicts and run \"git commit\")"
msgstr " (коригирайте конфликтите и изпълнете „git commit“)"
-#: wt-status.c:952
+#: wt-status.c:955
msgid "All conflicts fixed but you are still merging."
msgstr "Всички конфликти са решени, но продължавате сливането."
-#: wt-status.c:955
+#: wt-status.c:958
msgid " (use \"git commit\" to conclude merge)"
msgstr " (използвайте „git commit“, за да завършите сливането)"
-#: wt-status.c:965
+#: wt-status.c:968
msgid "You are in the middle of an am session."
msgstr "В момента прилагате поредица от кръпки чрез „git am“."
-#: wt-status.c:968
+#: wt-status.c:971
msgid "The current patch is empty."
msgstr "Текущата кръпка е празна."
-#: wt-status.c:972
+#: wt-status.c:975
msgid " (fix conflicts and then run \"git am --continue\")"
msgstr " (коригирайте конфликтите и изпълнете „git am --continue“)"
-#: wt-status.c:974
+#: wt-status.c:977
msgid " (use \"git am --skip\" to skip this patch)"
msgstr " (използвайте „git am --skip“, за да пропуснете тази кръпка)"
-#: wt-status.c:976
+#: wt-status.c:979
msgid " (use \"git am --abort\" to restore the original branch)"
msgstr ""
" (използвайте „git am --abort“, за да възстановите първоначалния клон)"
-#: wt-status.c:1036 wt-status.c:1053
+#: wt-status.c:1039 wt-status.c:1056
#, c-format
msgid "You are currently rebasing branch '%s' on '%s'."
msgstr "В момента пребазирате клона „%s“ върху „%s“."
-#: wt-status.c:1041 wt-status.c:1058
+#: wt-status.c:1044 wt-status.c:1061
msgid "You are currently rebasing."
msgstr "В момента пребазирате."
-#: wt-status.c:1044
+#: wt-status.c:1047
msgid " (fix conflicts and then run \"git rebase --continue\")"
msgstr " (коригирайте конфликтите и използвайте „git rebase --continue“)"
-#: wt-status.c:1046
+#: wt-status.c:1049
msgid " (use \"git rebase --skip\" to skip this patch)"
msgstr " (използвайте „git rebase --skip“, за да пропуснете тази кръпка)"
-#: wt-status.c:1048
+#: wt-status.c:1051
msgid " (use \"git rebase --abort\" to check out the original branch)"
msgstr ""
" (използвайте „git rebase --abort“, за да възстановите първоначалния клон)"
-#: wt-status.c:1061
+#: wt-status.c:1064
msgid " (all conflicts fixed: run \"git rebase --continue\")"
msgstr " (всички конфликти са коригирани: изпълнете „git rebase --continue“)"
-#: wt-status.c:1065
+#: wt-status.c:1068
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
msgstr "В момента разделяте подаване докато пребазирате клона „%s“ върху „%s“."
-#: wt-status.c:1070
+#: wt-status.c:1073
msgid "You are currently splitting a commit during a rebase."
msgstr "В момента разделяте подаване докато пребазирате."
-#: wt-status.c:1073
+#: wt-status.c:1076
msgid " (Once your working directory is clean, run \"git rebase --continue\")"
msgstr ""
" (След като работното ви дърво стане чисто, използвайте „git rebase --"
"continue“)"
-#: wt-status.c:1077
+#: wt-status.c:1080
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
msgstr ""
"В момента редактирате подаване докато пребазирате клона „%s“ върху „%s“."
-#: wt-status.c:1082
+#: wt-status.c:1085
msgid "You are currently editing a commit during a rebase."
msgstr "В момента редактирате подаване докато пребазирате."
-#: wt-status.c:1085
+#: wt-status.c:1088
msgid " (use \"git commit --amend\" to amend the current commit)"
msgstr ""
" (използвайте „git commit --amend“, за да редактирате текущото подаване)"
-#: wt-status.c:1087
+#: wt-status.c:1090
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
msgstr ""
" (използвайте „git rebase --continue“, след като завършите промените си)"
-#: wt-status.c:1097
+#: wt-status.c:1100
#, c-format
msgid "You are currently cherry-picking commit %s."
msgstr "В момента отбирате подаването „%s“."
-#: wt-status.c:1102
+#: wt-status.c:1105
msgid " (fix conflicts and run \"git cherry-pick --continue\")"
msgstr " (коригирайте конфликтите и изпълнете „git cherry-pick --continue“)"
-#: wt-status.c:1105
+#: wt-status.c:1108
msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
msgstr ""
" (всички конфликти са коригирани, изпълнете „git cherry-pick --continue“)"
-#: wt-status.c:1107
+#: wt-status.c:1110
msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
msgstr ""
" (използвайте „git cherry-pick --abort“, за да отмените всички действия с "
"отбиране)"
-#: wt-status.c:1116
+#: wt-status.c:1119
#, c-format
msgid "You are currently reverting commit %s."
msgstr "В момента отменяте подаване „%s“."
-#: wt-status.c:1121
+#: wt-status.c:1124
msgid " (fix conflicts and run \"git revert --continue\")"
msgstr " (коригирайте конфликтите и изпълнете „git revert --continue“)"
-#: wt-status.c:1124
+#: wt-status.c:1127
msgid " (all conflicts fixed: run \"git revert --continue\")"
msgstr " (всички конфликти са коригирани, изпълнете „git revert --continue“)"
-#: wt-status.c:1126
+#: wt-status.c:1129
msgid " (use \"git revert --abort\" to cancel the revert operation)"
msgstr ""
" (използвайте „git revert --abort“, за да преустановите отмяната на "
"подаване)"
-#: wt-status.c:1137
+#: wt-status.c:1140
#, c-format
msgid "You are currently bisecting, started from branch '%s'."
msgstr "В момента търсите двоично, като сте стартирали от клон „%s“."
-#: wt-status.c:1141
+#: wt-status.c:1144
msgid "You are currently bisecting."
msgstr "В момента търсите двоично."
-#: wt-status.c:1144
+#: wt-status.c:1147
msgid " (use \"git bisect reset\" to get back to the original branch)"
msgstr ""
" (използвайте „git bisect reset“, за да се върнете към първоначалното "
"състояние и клон)"
-#: wt-status.c:1321
+#: wt-status.c:1324
msgid "On branch "
msgstr "На клон "
-#: wt-status.c:1328
+#: wt-status.c:1331
msgid "rebase in progress; onto "
msgstr "извършвате пребазиране върху "
-#: wt-status.c:1333
+#: wt-status.c:1336
msgid "HEAD detached at "
msgstr "Указателят „HEAD“ не е свързан и е при "
-#: wt-status.c:1335
+#: wt-status.c:1338
msgid "HEAD detached from "
msgstr "Указателят „HEAD“ не е свързан и е отделѐн от "
-#: wt-status.c:1338
+#: wt-status.c:1341
msgid "Not currently on any branch."
msgstr "Извън всички клони."
-#: wt-status.c:1355
+#: wt-status.c:1358
msgid "Initial commit"
msgstr "Първоначално подаване"
-#: wt-status.c:1369
+#: wt-status.c:1372
msgid "Untracked files"
msgstr "Неследени файлове"
-#: wt-status.c:1371
+#: wt-status.c:1374
msgid "Ignored files"
msgstr "Игнорирани файлове"
-#: wt-status.c:1375
+#: wt-status.c:1378
#, c-format
msgid ""
"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
@@ -2071,32 +2098,32 @@ msgstr ""
"изпълнението, но не трябва да забравяте ръчно да добавяте новите файлове.\n"
"За повече подробности погледнете „git status help“."
-#: wt-status.c:1381
+#: wt-status.c:1384
#, c-format
msgid "Untracked files not listed%s"
msgstr "Неследените файлове не са изведени%s"
-#: wt-status.c:1383
+#: wt-status.c:1386
msgid " (use -u option to show untracked files)"
msgstr " (използвайте опцията „-u“, за да изведете неследените файлове)"
-#: wt-status.c:1389
+#: wt-status.c:1392
msgid "No changes"
msgstr "Няма промени"
-#: wt-status.c:1394
+#: wt-status.c:1397
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
msgstr ""
"към индекса за подаване не са добавени промени (използвайте „git add“ и/или "
"„git commit -a“)\n"
-#: wt-status.c:1397
+#: wt-status.c:1400
#, c-format
msgid "no changes added to commit\n"
msgstr "към индекса за подаване не са добавени промени\n"
-#: wt-status.c:1400
+#: wt-status.c:1403
#, c-format
msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
@@ -2105,52 +2132,52 @@ msgstr ""
"към индекса за подаване не са добавени промени, но има нови файлове "
"(използвайте „git add“, за да започне тяхното следене)\n"
-#: wt-status.c:1403
+#: wt-status.c:1406
#, c-format
msgid "nothing added to commit but untracked files present\n"
msgstr "към индекса за подаване не са добавени промени, но има нови файлове\n"
-#: wt-status.c:1406
+#: wt-status.c:1409
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
msgstr ""
"липсват каквито и да е промени (създайте или копирайте файлове и използвайте "
"„git add“, за да започне тяхното следене)\n"
-#: wt-status.c:1409 wt-status.c:1414
+#: wt-status.c:1412 wt-status.c:1417
#, c-format
msgid "nothing to commit\n"
msgstr "липсват каквито и да е промени\n"
-#: wt-status.c:1412
+#: wt-status.c:1415
#, c-format
msgid "nothing to commit (use -u to show untracked files)\n"
msgstr ""
"липсват каквито и да е промени (използвайте опцията „-u“, за да се изведат и "
"неследените файлове)\n"
-#: wt-status.c:1416
+#: wt-status.c:1419
#, c-format
msgid "nothing to commit, working directory clean\n"
msgstr "липсват каквито и да е промени, работното дърво е чисто\n"
-#: wt-status.c:1525
+#: wt-status.c:1528
msgid "HEAD (no branch)"
msgstr "HEAD (извън клон)"
-#: wt-status.c:1531
+#: wt-status.c:1534
msgid "Initial commit on "
msgstr "Първоначално подаване на клон"
-#: wt-status.c:1563
+#: wt-status.c:1561
msgid "gone"
msgstr "изтрит"
-#: wt-status.c:1565 wt-status.c:1573
+#: wt-status.c:1563 wt-status.c:1571
msgid "behind "
msgstr "назад с "
-#: compat/precompose_utf8.c:55 builtin/clone.c:360
+#: compat/precompose_utf8.c:55 builtin/clone.c:345
#, c-format
msgid "failed to unlink '%s'"
msgstr "неуспешно изтриване на „%s“"
@@ -2177,7 +2204,7 @@ msgstr "изтриване на „%s“\n"
msgid "Unstaged changes after refreshing the index:"
msgstr "Промени, които и след обновяването на индекса не са добавени към него:"
-#: builtin/add.c:194 builtin/rev-parse.c:785
+#: builtin/add.c:194 builtin/rev-parse.c:796
msgid "Could not read the index"
msgstr "Индексът не може да бъде прочетен"
@@ -2190,119 +2217,123 @@ msgstr "Файлът „%s“ не може да бъде отворен за з
msgid "Could not write patch"
msgstr "Кръпката не може да бъде записана"
-#: builtin/add.c:214
+#: builtin/add.c:212
+msgid "editing patch failed"
+msgstr "неуспешно редактиране на кръпка"
+
+#: builtin/add.c:215
#, c-format
msgid "Could not stat '%s'"
msgstr "Не може да се получи информация чрез „stat“ за файла „%s“"
-#: builtin/add.c:216
+#: builtin/add.c:217
msgid "Empty patch. Aborted."
msgstr "Празна кръпка, преустановяване на действието."
-#: builtin/add.c:221
+#: builtin/add.c:222
#, c-format
msgid "Could not apply '%s'"
msgstr "Кръпката „%s“ не може да бъде приложена"
-#: builtin/add.c:231
+#: builtin/add.c:232
msgid "The following paths are ignored by one of your .gitignore files:\n"
msgstr ""
"Следните пътища ще бъдат игнорирани според някой от файловете „.gitignore“:\n"
-#: builtin/add.c:248 builtin/clean.c:876 builtin/fetch.c:107 builtin/mv.c:110
-#: builtin/prune-packed.c:55 builtin/push.c:508 builtin/remote.c:1372
-#: builtin/rm.c:269
+#: builtin/add.c:249 builtin/clean.c:874 builtin/fetch.c:107 builtin/mv.c:110
+#: builtin/prune-packed.c:55 builtin/push.c:508 builtin/remote.c:1369
+#: builtin/rm.c:268
msgid "dry run"
msgstr "пробно изпълнeние"
-#: builtin/add.c:249 builtin/apply.c:4577 builtin/check-ignore.c:19
-#: builtin/commit.c:1322 builtin/count-objects.c:63 builtin/fsck.c:608
+#: builtin/add.c:250 builtin/apply.c:4580 builtin/check-ignore.c:19
+#: builtin/commit.c:1322 builtin/count-objects.c:63 builtin/fsck.c:616
#: builtin/log.c:1617 builtin/mv.c:109 builtin/read-tree.c:114
msgid "be verbose"
msgstr "повече подробности"
-#: builtin/add.c:251
+#: builtin/add.c:252
msgid "interactive picking"
msgstr "интерактивно отбиране на промени"
-#: builtin/add.c:252 builtin/checkout.c:1126 builtin/reset.c:286
+#: builtin/add.c:253 builtin/checkout.c:1221 builtin/reset.c:286
msgid "select hunks interactively"
msgstr "интерактивен избор на парчета код"
-#: builtin/add.c:253
+#: builtin/add.c:254
msgid "edit current diff and apply"
msgstr "редактиране на текущата разлика и прилагане"
-#: builtin/add.c:254
+#: builtin/add.c:255
msgid "allow adding otherwise ignored files"
msgstr "добавяне и на иначе игнорираните файлове"
-#: builtin/add.c:255
+#: builtin/add.c:256
msgid "update tracked files"
msgstr "обновяване на следените файлове"
-#: builtin/add.c:256
+#: builtin/add.c:257
msgid "record only the fact that the path will be added later"
msgstr "отбелязване само на факта, че пътят ще бъде добавен по-късно"
-#: builtin/add.c:257
+#: builtin/add.c:258
msgid "add changes from all tracked and untracked files"
msgstr "добавяне на всички промени в следените и неследените файлове"
-#: builtin/add.c:260
+#: builtin/add.c:261
msgid "ignore paths removed in the working tree (same as --no-all)"
msgstr ""
"игнориране на пътищата, които са изтрити от работното дърво (същото като „--"
"no-all“)"
-#: builtin/add.c:262
+#: builtin/add.c:263
msgid "don't add, only refresh the index"
msgstr "без добавяне на нови файлове, само обновяване на индекса"
-#: builtin/add.c:263
+#: builtin/add.c:264
msgid "just skip files which cannot be added because of errors"
msgstr ""
"прескачане на файловете, които не могат да бъдат добавени поради грешки"
-#: builtin/add.c:264
+#: builtin/add.c:265
msgid "check if - even missing - files are ignored in dry run"
msgstr ""
"проверка, че при пробно изпълнение всички файлове, дори и изтритите, се "
"игнорират"
-#: builtin/add.c:286
+#: builtin/add.c:287
#, c-format
msgid "Use -f if you really want to add them.\n"
msgstr "Използвайте опцията „-f“, за да ги добавите наистина.\n"
-#: builtin/add.c:293
+#: builtin/add.c:294
msgid "adding files failed"
msgstr "неуспешно добавяне на файлове"
-#: builtin/add.c:329
+#: builtin/add.c:330
msgid "-A and -u are mutually incompatible"
msgstr "опциите „-A“ и „-u“ са несъвместими"
-#: builtin/add.c:336
+#: builtin/add.c:337
msgid "Option --ignore-missing can only be used together with --dry-run"
msgstr "Опцията „--ignore-missing“ е съвместима само с „--dry-run“"
-#: builtin/add.c:357
+#: builtin/add.c:358
#, c-format
msgid "Nothing specified, nothing added.\n"
msgstr "Нищо не е зададено и нищо не е добавено.\n"
-#: builtin/add.c:358
+#: builtin/add.c:359
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
msgstr "Вероятно искахте да използвате „git add .“?\n"
-#: builtin/add.c:363 builtin/check-ignore.c:172 builtin/clean.c:920
-#: builtin/commit.c:335 builtin/mv.c:130 builtin/reset.c:235 builtin/rm.c:299
+#: builtin/add.c:364 builtin/check-ignore.c:172 builtin/clean.c:918
+#: builtin/commit.c:335 builtin/mv.c:130 builtin/reset.c:235 builtin/rm.c:298
msgid "index file corrupt"
msgstr "файлът с индекса е повреден"
-#: builtin/add.c:446 builtin/apply.c:4675 builtin/mv.c:279 builtin/rm.c:431
+#: builtin/add.c:447 builtin/apply.c:4678 builtin/mv.c:279 builtin/rm.c:430
msgid "Unable to write new index file"
msgstr "Новият индекс не може да бъде записан"
@@ -2388,66 +2419,66 @@ msgstr[1] ""
"След съкращаването на първите %d части от компонентите на пътя, в заглавната "
"част на „git diff“ липсва информация за име на файл (ред: %d)"
-#: builtin/apply.c:1656
+#: builtin/apply.c:1659
msgid "new file depends on old contents"
msgstr "новият файл зависи от старото съдържание на файла"
-#: builtin/apply.c:1658
+#: builtin/apply.c:1661
msgid "deleted file still has contents"
msgstr "изтритият файл не е празен"
-#: builtin/apply.c:1684
+#: builtin/apply.c:1687
#, c-format
msgid "corrupt patch at line %d"
msgstr "грешка в кръпката на ред %d"
-#: builtin/apply.c:1720
+#: builtin/apply.c:1723
#, c-format
msgid "new file %s depends on old contents"
msgstr "новият файл „%s“ зависи от старото съдържание на файла"
-#: builtin/apply.c:1722
+#: builtin/apply.c:1725
#, c-format
msgid "deleted file %s still has contents"
msgstr "изтритият файл „%s“ не е празен"
# FIXME - double **??
-#: builtin/apply.c:1725
+#: builtin/apply.c:1728
#, c-format
msgid "** warning: file %s becomes empty but is not deleted"
msgstr "●● предупреждение: файлът „%s“ вече е празен, но не е изтрит"
-#: builtin/apply.c:1871
+#: builtin/apply.c:1874
#, c-format
msgid "corrupt binary patch at line %d: %.*s"
msgstr "грешка в двоичната кръпка на ред %d: %.*s"
-#: builtin/apply.c:1900
+#: builtin/apply.c:1903
#, c-format
msgid "unrecognized binary patch at line %d"
msgstr "неразпозната двоичната кръпка на ред %d"
-#: builtin/apply.c:2051
+#: builtin/apply.c:2054
#, c-format
msgid "patch with only garbage at line %d"
msgstr "кръпката е с изцяло повредени данни на ред %d"
-#: builtin/apply.c:2141
+#: builtin/apply.c:2144
#, c-format
msgid "unable to read symlink %s"
msgstr "символната връзка „%s“ не може да бъде прочетена"
-#: builtin/apply.c:2145
+#: builtin/apply.c:2148
#, c-format
msgid "unable to open or read %s"
msgstr "файлът „%s“ не може да бъде отворен или прочетен"
-#: builtin/apply.c:2778
+#: builtin/apply.c:2781
#, c-format
msgid "invalid start of line: '%c'"
msgstr "неправилно начало на ред: „%c“"
-#: builtin/apply.c:2897
+#: builtin/apply.c:2900
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
@@ -2456,13 +2487,13 @@ msgstr[0] ""
msgstr[1] ""
"%d-то парче код бе успешно приложено на ред %d (отместване от %d реда)."
-#: builtin/apply.c:2909
+#: builtin/apply.c:2912
#, c-format
msgid "Context reduced to (%ld/%ld) to apply fragment at %d"
msgstr ""
"Контекстът е намален на (%ld/%ld) за прилагането на парчето код на ред %d"
-#: builtin/apply.c:2915
+#: builtin/apply.c:2918
#, c-format
msgid ""
"while searching for:\n"
@@ -2471,345 +2502,345 @@ msgstr ""
"при търсене за:\n"
"%.*s"
-#: builtin/apply.c:2935
+#: builtin/apply.c:2938
#, c-format
msgid "missing binary patch data for '%s'"
msgstr "липсват данните за двоичната кръпка за „%s“"
-#: builtin/apply.c:3036
+#: builtin/apply.c:3039
#, c-format
msgid "binary patch does not apply to '%s'"
msgstr "двоичната кръпка не може да бъде приложена върху „%s“"
-#: builtin/apply.c:3042
+#: builtin/apply.c:3045
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
msgstr ""
"двоичната кръпка за „%s“ води до неправилни резултати (очакваше се SHA1: "
"„%s“, а бе получено: „%s“)"
-#: builtin/apply.c:3063
+#: builtin/apply.c:3066
#, c-format
msgid "patch failed: %s:%ld"
msgstr "неуспешно прилагане на кръпка: „%s:%ld“"
-#: builtin/apply.c:3187
+#: builtin/apply.c:3190
#, c-format
msgid "cannot checkout %s"
msgstr "„%s“ не може да се изтегли"
-#: builtin/apply.c:3232 builtin/apply.c:3243 builtin/apply.c:3288
+#: builtin/apply.c:3235 builtin/apply.c:3246 builtin/apply.c:3291
#, c-format
msgid "read of %s failed"
msgstr "неуспешно прочитане на „%s“"
-#: builtin/apply.c:3240
+#: builtin/apply.c:3243
#, c-format
msgid "reading from '%s' beyond a symbolic link"
msgstr "изчитане на „%s“ след проследяване на символна връзка"
-#: builtin/apply.c:3268 builtin/apply.c:3490
+#: builtin/apply.c:3271 builtin/apply.c:3493
#, c-format
msgid "path %s has been renamed/deleted"
msgstr "обектът с път „%s“ е преименуван или изтрит"
-#: builtin/apply.c:3349 builtin/apply.c:3504
+#: builtin/apply.c:3352 builtin/apply.c:3507
#, c-format
msgid "%s: does not exist in index"
msgstr "„%s“ не съществува в индекса"
-#: builtin/apply.c:3353 builtin/apply.c:3496 builtin/apply.c:3518
+#: builtin/apply.c:3356 builtin/apply.c:3499 builtin/apply.c:3521
#, c-format
msgid "%s: %s"
msgstr "„%s“: %s"
-#: builtin/apply.c:3358 builtin/apply.c:3512
+#: builtin/apply.c:3361 builtin/apply.c:3515
#, c-format
msgid "%s: does not match index"
msgstr "„%s“ не съответства на индекса"
-#: builtin/apply.c:3460
+#: builtin/apply.c:3463
msgid "removal patch leaves file contents"
msgstr "изтриващата кръпка оставя файла непразен"
-#: builtin/apply.c:3529
+#: builtin/apply.c:3532
#, c-format
msgid "%s: wrong type"
msgstr "„%s“: неправилен вид"
-#: builtin/apply.c:3531
+#: builtin/apply.c:3534
#, c-format
msgid "%s has type %o, expected %o"
msgstr "„%s“ е от вид „%o“, а се очакваше „%o“"
-#: builtin/apply.c:3690 builtin/apply.c:3692
+#: builtin/apply.c:3693 builtin/apply.c:3695
#, c-format
msgid "invalid path '%s'"
msgstr "неправилен път: „%s“"
-#: builtin/apply.c:3747
+#: builtin/apply.c:3750
#, c-format
msgid "%s: already exists in index"
msgstr "„%s“: вече съществува в индекса"
-#: builtin/apply.c:3750
+#: builtin/apply.c:3753
#, c-format
msgid "%s: already exists in working directory"
-msgstr "„%s“: вече съществува в работната директория"
+msgstr "„%s“: вече съществува в работното дърво"
-#: builtin/apply.c:3770
+#: builtin/apply.c:3773
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr "новите права за достъп (%o) на „%s“ не съвпадат със старите (%o)"
-#: builtin/apply.c:3775
+#: builtin/apply.c:3778
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
msgstr ""
"новите права за достъп (%o) на „%s“ не съвпадат със старите (%o) на „%s“"
-#: builtin/apply.c:3795
+#: builtin/apply.c:3798
#, c-format
msgid "affected file '%s' is beyond a symbolic link"
msgstr "засегнатият файл „%s“ е след символна връзка"
-#: builtin/apply.c:3799
+#: builtin/apply.c:3802
#, c-format
msgid "%s: patch does not apply"
msgstr "Кръпката „%s“ не може да бъде приложена"
-#: builtin/apply.c:3813
+#: builtin/apply.c:3816
#, c-format
msgid "Checking patch %s..."
msgstr "Проверяване на кръпката „%s“…"
-#: builtin/apply.c:3906 builtin/checkout.c:231 builtin/reset.c:135
+#: builtin/apply.c:3909 builtin/checkout.c:233 builtin/reset.c:135
#, c-format
msgid "make_cache_entry failed for path '%s'"
msgstr "неуспешно създаване на запис в кеша чрез „make_cache_entry“ за „%s“"
-#: builtin/apply.c:4049
+#: builtin/apply.c:4052
#, c-format
msgid "unable to remove %s from index"
msgstr "„%s“ не може да се извади от индекса"
-#: builtin/apply.c:4078
+#: builtin/apply.c:4081
#, c-format
msgid "corrupt patch for submodule %s"
msgstr "повредена кръпка за модула „%s“"
-#: builtin/apply.c:4082
+#: builtin/apply.c:4085
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr ""
"не може да се получи информация чрез „stat“ за новосъздадения файл „%s“"
-#: builtin/apply.c:4087
+#: builtin/apply.c:4090
#, c-format
msgid "unable to create backing store for newly created file %s"
msgstr ""
"не може да се за създаде мястото за съхранение на новосъздадения файл „%s“"
-#: builtin/apply.c:4090 builtin/apply.c:4198
+#: builtin/apply.c:4093 builtin/apply.c:4201
#, c-format
msgid "unable to add cache entry for %s"
msgstr "не може да се добави запис в кеша за „%s“"
-#: builtin/apply.c:4123
+#: builtin/apply.c:4126
#, c-format
msgid "closing file '%s'"
msgstr "затваряне на файла „%s“"
-#: builtin/apply.c:4172
+#: builtin/apply.c:4175
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "файлът „%s“ не може да се запише с режим на достъп „%o“"
-#: builtin/apply.c:4259
+#: builtin/apply.c:4262
#, c-format
msgid "Applied patch %s cleanly."
msgstr "Кръпката „%s“ бе приложена чисто."
-#: builtin/apply.c:4267
+#: builtin/apply.c:4270
msgid "internal error"
msgstr "вътрешна грешка"
-#: builtin/apply.c:4270
+#: builtin/apply.c:4273
#, 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 отхвърлени парчета…"
-#: builtin/apply.c:4280
+#: builtin/apply.c:4283
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "съкращаване на името на файла с отхвърлените парчета на „ %.*s.rej“"
-#: builtin/apply.c:4301
+#: builtin/apply.c:4304
#, c-format
msgid "Hunk #%d applied cleanly."
msgstr "%d-то парче бе успешно приложено."
-#: builtin/apply.c:4304
+#: builtin/apply.c:4307
#, c-format
msgid "Rejected hunk #%d."
msgstr "%d-то парче бе отхвърлено."
-#: builtin/apply.c:4394
+#: builtin/apply.c:4397
msgid "unrecognized input"
msgstr "непознат вход"
-#: builtin/apply.c:4405
+#: builtin/apply.c:4408
msgid "unable to read index file"
msgstr "индексът не може да бъде записан"
-#: builtin/apply.c:4522 builtin/apply.c:4525 builtin/clone.c:92
+#: builtin/apply.c:4525 builtin/apply.c:4528 builtin/clone.c:85
#: builtin/fetch.c:92
msgid "path"
msgstr "път"
-#: builtin/apply.c:4523
+#: builtin/apply.c:4526
msgid "don't apply changes matching the given path"
msgstr "без прилагане на промените напасващи на дадения път"
-#: builtin/apply.c:4526
+#: builtin/apply.c:4529
msgid "apply changes matching the given path"
msgstr "прилагане на промените напасващи на дадения път"
-#: builtin/apply.c:4528
+#: builtin/apply.c:4531
msgid "num"
msgstr "БРОЙ"
-#: builtin/apply.c:4529
+#: builtin/apply.c:4532
msgid "remove <num> leading slashes from traditional diff paths"
msgstr "премахване на този БРОЙ водещи елементи от пътищата в разликата"
-#: builtin/apply.c:4532
+#: builtin/apply.c:4535
msgid "ignore additions made by the patch"
msgstr "игнориране на редовете добавени от тази кръпка"
-#: builtin/apply.c:4534
+#: builtin/apply.c:4537
msgid "instead of applying the patch, output diffstat for the input"
msgstr "извеждане на статистика на промените без прилагане на кръпката"
-#: builtin/apply.c:4538
+#: builtin/apply.c:4541
msgid "show number of added and deleted lines in decimal notation"
msgstr "извеждане на броя на добавените и изтритите редове"
-#: builtin/apply.c:4540
+#: builtin/apply.c:4543
msgid "instead of applying the patch, output a summary for the input"
msgstr "извеждане на статистика на входните данни без прилагане на кръпката"
-#: builtin/apply.c:4542
+#: builtin/apply.c:4545
msgid "instead of applying the patch, see if the patch is applicable"
msgstr "проверка дали кръпката може да се приложи, без действително прилагане"
-#: builtin/apply.c:4544
+#: builtin/apply.c:4547
msgid "make sure the patch is applicable to the current index"
msgstr "проверка дали кръпката може да бъде приложена към текущия индекс"
-#: builtin/apply.c:4546
+#: builtin/apply.c:4549
msgid "apply a patch without touching the working tree"
msgstr "прилагане на кръпката без промяна на работното дърво"
-#: builtin/apply.c:4548
+#: builtin/apply.c:4551
msgid "accept a patch that touches outside the working area"
msgstr "прилагане на кръпка, която променя и файлове извън работното дърво"
-#: builtin/apply.c:4550
+#: builtin/apply.c:4553
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr ""
"кръпката да бъде приложена. Опцията се комбинира с „--check“/„--stat“/„--"
"summary“"
-#: builtin/apply.c:4552
+#: builtin/apply.c:4555
msgid "attempt three-way merge if a patch does not apply"
msgstr "пробване с тройно сливане, ако кръпката не може да се приложи директно"
-#: builtin/apply.c:4554
+#: builtin/apply.c:4557
msgid "build a temporary index based on embedded index information"
msgstr ""
"създаване на временен индекс на база на включената информация за индекса"
-#: builtin/apply.c:4556 builtin/checkout-index.c:198 builtin/ls-files.c:412
+#: builtin/apply.c:4559 builtin/checkout-index.c:198 builtin/ls-files.c:412
msgid "paths are separated with NUL character"
msgstr "разделяне на пътищата с нулевия знак „NUL“"
-#: builtin/apply.c:4559
+#: builtin/apply.c:4562
msgid "ensure at least <n> lines of context match"
msgstr "да се осигури контекст от поне такъв БРОЙ съвпадащи редове"
-#: builtin/apply.c:4560
+#: builtin/apply.c:4563
msgid "action"
msgstr "действие"
-#: builtin/apply.c:4561
+#: builtin/apply.c:4564
msgid "detect new or modified lines that have whitespace errors"
msgstr "засичане на нови или променени редове с грешки в знаците за интервали"
-#: builtin/apply.c:4564 builtin/apply.c:4567
+#: builtin/apply.c:4567 builtin/apply.c:4570
msgid "ignore changes in whitespace when finding context"
msgstr ""
"игнориране на промените в знаците за интервали при откриване на контекста"
-#: builtin/apply.c:4570
+#: builtin/apply.c:4573
msgid "apply the patch in reverse"
msgstr "прилагане на кръпката в обратна посока"
-#: builtin/apply.c:4572
+#: builtin/apply.c:4575
msgid "don't expect at least one line of context"
msgstr "без изискване на дори и един ред контекст"
-#: builtin/apply.c:4574
+#: builtin/apply.c:4577
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr "оставяне на отхвърлените парчета във файлове с разширение „.rej“"
-#: builtin/apply.c:4576
+#: builtin/apply.c:4579
msgid "allow overlapping hunks"
msgstr "позволяване на застъпващи се парчета"
-#: builtin/apply.c:4579
+#: builtin/apply.c:4582
msgid "tolerate incorrectly detected missing new-line at the end of file"
msgstr "пренебрегване на неправилно липсващ знак за нов ред в края на файл"
-#: builtin/apply.c:4582
+#: builtin/apply.c:4585
msgid "do not trust the line counts in the hunk headers"
msgstr "без доверяване на номерата на редовете в заглавните части на парчетата"
-#: builtin/apply.c:4584
+#: builtin/apply.c:4587
msgid "root"
msgstr "НАЧАЛНА_ДИРЕКТОРИЯ"
-#: builtin/apply.c:4585
+#: builtin/apply.c:4588
msgid "prepend <root> to all filenames"
msgstr "добавяне на тази НАЧАЛНА_ДИРЕКТОРИЯ към имената на всички файлове"
-#: builtin/apply.c:4607
+#: builtin/apply.c:4610
msgid "--3way outside a repository"
msgstr "като „--3way“, но извън хранилище"
-#: builtin/apply.c:4615
+#: builtin/apply.c:4618
msgid "--index outside a repository"
msgstr "като „--index“, но извън хранилище"
-#: builtin/apply.c:4618
+#: builtin/apply.c:4621
msgid "--cached outside a repository"
msgstr "като „--cached“, но извън хранилище"
-#: builtin/apply.c:4637
+#: builtin/apply.c:4640
#, c-format
msgid "can't open patch '%s'"
msgstr "кръпката „%s“ не може да бъде отворена"
-#: builtin/apply.c:4651
+#: builtin/apply.c:4654
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] "пренебрегната е %d грешка в знаците за интервали"
msgstr[1] "пренебрегнати са %d грешки в знаците за интервали"
-#: builtin/apply.c:4657 builtin/apply.c:4667
+#: builtin/apply.c:4660 builtin/apply.c:4670
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
@@ -2864,11 +2895,11 @@ msgid "update BISECT_HEAD instead of checking out the current commit"
msgstr ""
"обновяване на указателя „BISECT_HEAD“ вместо да се използва текущото подаване"
-#: builtin/blame.c:30
-msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] file"
+#: builtin/blame.c:31
+msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
msgstr "git blame [ОПЦИЯ…] [ОПЦИЯ_ЗА_ВЕРСИЯТА…] [ВЕРСИЯ] [--] ФАЙЛ"
-#: builtin/blame.c:35
+#: builtin/blame.c:36
msgid "<rev-opts> are documented in git-rev-list(1)"
msgstr "ОПЦИИте_ЗА_ВЕРСИЯТА са документирани в ръководството git-rev-list(1)"
@@ -3009,7 +3040,7 @@ msgstr "git branch [ОПЦИЯ…] [-r] (-d | -D) ИМЕ_НА_КЛОН…"
msgid "git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"
msgstr "git branch [ОПЦИЯ…] (-m | -M) [СТАР_КЛОН] НОВ_КЛОН"
-#: builtin/branch.c:152
+#: builtin/branch.c:150
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
@@ -3018,7 +3049,7 @@ msgstr ""
"изтриване на клона „%s“, който е слят към „%s“,\n"
" но още не е слят към върха „HEAD“."
-#: builtin/branch.c:156
+#: builtin/branch.c:154
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
@@ -3027,12 +3058,12 @@ msgstr ""
"отказване на изтриване на клона „%s“, който не е слят към\n"
" „%s“, но е слят към върха „HEAD“."
-#: builtin/branch.c:170
+#: builtin/branch.c:168
#, c-format
msgid "Couldn't look up commit object for '%s'"
msgstr "Обектът-подаване за „%s“ не може да бъде открит"
-#: builtin/branch.c:174
+#: builtin/branch.c:172
#, c-format
msgid ""
"The branch '%s' is not fully merged.\n"
@@ -3041,310 +3072,310 @@ msgstr ""
"Клонът „%s“ не е слят напълно. Ако сте сигурни, че искате\n"
"да го изтриете, изпълнете „git branch -D %s“."
-#: builtin/branch.c:187
+#: builtin/branch.c:185
msgid "Update of config-file failed"
msgstr "Неуспешно обновяване на конфигурационния файл"
-#: builtin/branch.c:215
+#: builtin/branch.c:213
msgid "cannot use -a with -d"
msgstr "Опцията „-a“ е несъвместима с опцията „-d“"
-#: builtin/branch.c:221
+#: builtin/branch.c:219
msgid "Couldn't look up commit object for HEAD"
msgstr "Обектът-подаване, сочен от указателя „HEAD“, не може да бъде открит"
-#: builtin/branch.c:229
+#: builtin/branch.c:227
#, c-format
msgid "Cannot delete the branch '%s' which you are currently on."
msgstr "Не можете да изтриете клона „%s“, защото в момента е текущ."
-#: builtin/branch.c:245
+#: builtin/branch.c:243
#, c-format
-msgid "remote branch '%s' not found."
-msgstr "отдалеченият клон „%s“ не може да бъде открит."
+msgid "remote-tracking branch '%s' not found."
+msgstr "следящият клон „%s“ не може да бъде открит."
-#: builtin/branch.c:246
+#: builtin/branch.c:244
#, c-format
msgid "branch '%s' not found."
msgstr "клонът „%s“ не може да бъде открит."
-#: builtin/branch.c:260
+#: builtin/branch.c:258
#, c-format
-msgid "Error deleting remote branch '%s'"
-msgstr "Грешка при изтриването на отдалечения клон „%s“"
+msgid "Error deleting remote-tracking branch '%s'"
+msgstr "Грешка при изтриването на следящия клон „%s“"
-#: builtin/branch.c:261
+#: builtin/branch.c:259
#, c-format
msgid "Error deleting branch '%s'"
msgstr "Грешка при изтриването на клона „%s“"
-#: builtin/branch.c:268
+#: builtin/branch.c:266
#, c-format
-msgid "Deleted remote branch %s (was %s).\n"
-msgstr "Изтрит отдалечен клон „%s“ (той сочеше към „%s“).\n"
+msgid "Deleted remote-tracking branch %s (was %s).\n"
+msgstr "Изтрит следящ клон „%s“ (той сочеше към „%s“).\n"
-#: builtin/branch.c:269
+#: builtin/branch.c:267
#, c-format
msgid "Deleted branch %s (was %s).\n"
msgstr "Изтрит клон „%s“ (той сочеше към „%s“).\n"
-#: builtin/branch.c:370
+#: builtin/branch.c:368
#, c-format
msgid "branch '%s' does not point at a commit"
msgstr "клонът „%s“ не сочи към подаване"
-#: builtin/branch.c:459
+#: builtin/branch.c:451
#, c-format
msgid "[%s: gone]"
msgstr "[%s: изтрит]"
-#: builtin/branch.c:464
+#: builtin/branch.c:456
#, c-format
msgid "[%s]"
msgstr "[%s]"
-#: builtin/branch.c:469
+#: builtin/branch.c:461
#, c-format
msgid "[%s: behind %d]"
msgstr "[%s: назад с %d]"
-#: builtin/branch.c:471
+#: builtin/branch.c:463
#, c-format
msgid "[behind %d]"
msgstr "[назад с %d]"
-#: builtin/branch.c:475
+#: builtin/branch.c:467
#, c-format
msgid "[%s: ahead %d]"
msgstr "[%s: напред с %d]"
-#: builtin/branch.c:477
+#: builtin/branch.c:469
#, c-format
msgid "[ahead %d]"
msgstr "[напред с %d]"
-#: builtin/branch.c:480
+#: builtin/branch.c:472
#, c-format
msgid "[%s: ahead %d, behind %d]"
msgstr "[%s: напред с %d, назад с %d]"
-#: builtin/branch.c:483
+#: builtin/branch.c:475
#, c-format
msgid "[ahead %d, behind %d]"
msgstr "[напред с %d, назад с %d]"
# FIXME ** how many??
-#: builtin/branch.c:496
+#: builtin/branch.c:488
msgid " **** invalid ref ****"
msgstr " ●●●● неправилен указател ●●●●"
-#: builtin/branch.c:587
+#: builtin/branch.c:579
#, c-format
msgid "(no branch, rebasing %s)"
msgstr "(извън клон, пребазиране на „%s“)"
-#: builtin/branch.c:590
+#: builtin/branch.c:582
#, c-format
msgid "(no branch, bisect started on %s)"
msgstr "(извън клон, двоично търсене от „%s“)"
-#: builtin/branch.c:596
+#: builtin/branch.c:588
#, c-format
msgid "(HEAD detached at %s)"
msgstr "(Указателят „HEAD“ не е свързан и е при „%s“)"
-#: builtin/branch.c:599
+#: builtin/branch.c:591
#, c-format
msgid "(HEAD detached from %s)"
msgstr "Указателят „HEAD“ не е свързан и е отделѐн от „%s“"
-#: builtin/branch.c:603
+#: builtin/branch.c:595
msgid "(no branch)"
msgstr "(извън клон)"
-#: builtin/branch.c:650
+#: builtin/branch.c:642
#, c-format
msgid "object '%s' does not point to a commit"
msgstr "обектът „%s“ не сочи към подаване"
-#: builtin/branch.c:698
+#: builtin/branch.c:690
msgid "some refs could not be read"
msgstr "някои указатели не могат да бъдат прочетени"
-#: builtin/branch.c:711
+#: builtin/branch.c:703
msgid "cannot rename the current branch while not on any."
msgstr ""
"не можете да преименувате текущия клон, защото сте извън който и да е клон"
-#: builtin/branch.c:721
+#: builtin/branch.c:713
#, c-format
msgid "Invalid branch name: '%s'"
msgstr "Неправилно име на клон: „%s“"
-#: builtin/branch.c:736
+#: builtin/branch.c:728
msgid "Branch rename failed"
msgstr "Неуспешно преименуване на клон"
-#: builtin/branch.c:740
+#: builtin/branch.c:732
#, c-format
msgid "Renamed a misnamed branch '%s' away"
msgstr "На клона с неправилно име „%s“ е дадено служебно име"
-#: builtin/branch.c:744
+#: builtin/branch.c:736
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
msgstr "Клонът е преименуван на „%s“, но указателят „HEAD“ не е обновен"
-#: builtin/branch.c:751
+#: builtin/branch.c:743
msgid "Branch is renamed, but update of config-file failed"
msgstr "Клонът е преименуван, но конфигурационният файл не е обновен"
-#: builtin/branch.c:766
+#: builtin/branch.c:758
#, c-format
msgid "malformed object name %s"
msgstr "неправилно име на обект „%s“"
-#: builtin/branch.c:790
+#: builtin/branch.c:780
#, c-format
msgid "could not write branch description template: %s"
msgstr "шаблонът за описание на клон не бе записан: „%s“"
-#: builtin/branch.c:820
+#: builtin/branch.c:810
msgid "Generic options"
msgstr "Общи настройки"
-#: builtin/branch.c:822
+#: builtin/branch.c:812
msgid "show hash and subject, give twice for upstream branch"
msgstr ""
"извеждане на хеша и темата. Повтарянето на опцията прибавя отдалечените клони"
-#: builtin/branch.c:823
+#: builtin/branch.c:813
msgid "suppress informational messages"
msgstr "без информационни съобщения"
-#: builtin/branch.c:824
+#: builtin/branch.c:814
msgid "set up tracking mode (see git-pull(1))"
msgstr "задаване на режима на следене (виж git-pull(1))"
-#: builtin/branch.c:826
+#: builtin/branch.c:816
msgid "change upstream info"
msgstr "смяна на следения клон"
-#: builtin/branch.c:830
+#: builtin/branch.c:820
msgid "use colored output"
msgstr "цветен изход"
-#: builtin/branch.c:831
+#: builtin/branch.c:821
msgid "act on remote-tracking branches"
msgstr "действие върху следящите клони"
-#: builtin/branch.c:834 builtin/branch.c:840 builtin/branch.c:861
-#: builtin/branch.c:867 builtin/commit.c:1582 builtin/commit.c:1583
-#: builtin/commit.c:1584 builtin/commit.c:1585 builtin/tag.c:616
+#: builtin/branch.c:824 builtin/branch.c:830 builtin/branch.c:851
+#: builtin/branch.c:857 builtin/commit.c:1581 builtin/commit.c:1582
+#: builtin/commit.c:1583 builtin/commit.c:1584 builtin/tag.c:616
#: builtin/tag.c:622
msgid "commit"
msgstr "подаване"
-#: builtin/branch.c:835 builtin/branch.c:841
+#: builtin/branch.c:825 builtin/branch.c:831
msgid "print only branches that contain the commit"
msgstr "извеждане само на клоните, които съдържат това подаване"
-#: builtin/branch.c:847
+#: builtin/branch.c:837
msgid "Specific git-branch actions:"
msgstr "Специални действия на „git-branch“:"
-#: builtin/branch.c:848
+#: builtin/branch.c:838
msgid "list both remote-tracking and local branches"
msgstr "извеждане както на следящите, така и на локалните клони"
-#: builtin/branch.c:850
+#: builtin/branch.c:840
msgid "delete fully merged branch"
msgstr "изтриване на клони, които са напълно слети"
-#: builtin/branch.c:851
+#: builtin/branch.c:841
msgid "delete branch (even if not merged)"
msgstr "изтриване и на клони, които не са напълно слети"
-#: builtin/branch.c:852
+#: builtin/branch.c:842
msgid "move/rename a branch and its reflog"
msgstr ""
"преместване/преименуване на клон и принадлежащият му журнал на указателите"
-#: builtin/branch.c:853
+#: builtin/branch.c:843
msgid "move/rename a branch, even if target exists"
msgstr "преместване/преименуване на клон, дори ако има вече клон с такова име"
-#: builtin/branch.c:854
+#: builtin/branch.c:844
msgid "list branch names"
msgstr "извеждане на имената на клоните"
-#: builtin/branch.c:855
+#: builtin/branch.c:845
msgid "create the branch's reflog"
msgstr "създаване на журнала на указателите на клона"
-#: builtin/branch.c:857
+#: builtin/branch.c:847
msgid "edit the description for the branch"
msgstr "редактиране на описанието на клона"
-#: builtin/branch.c:858
+#: builtin/branch.c:848
msgid "force creation, move/rename, deletion"
msgstr "принудително създаване, преместване, преименуване, изтриване"
-#: builtin/branch.c:861
+#: builtin/branch.c:851
msgid "print only not merged branches"
msgstr "извеждане само на неслетите клони"
-#: builtin/branch.c:867
+#: builtin/branch.c:857
msgid "print only merged branches"
msgstr "извеждане само на слетите клони"
-#: builtin/branch.c:871
+#: builtin/branch.c:861
msgid "list branches in columns"
msgstr "извеждане по колони"
-#: builtin/branch.c:884
+#: builtin/branch.c:874
msgid "Failed to resolve HEAD as a valid ref."
msgstr "Не може да се открие към какво сочи указателят „HEAD“"
-#: builtin/branch.c:888 builtin/clone.c:637
+#: builtin/branch.c:878 builtin/clone.c:622
msgid "HEAD not found below refs/heads!"
msgstr "В директорията „refs/heads“ липсва файл „HEAD“"
-#: builtin/branch.c:910
+#: builtin/branch.c:900
msgid "--column and --verbose are incompatible"
msgstr "Опциите „--column“ и „--verbose“ са несъвместими"
-#: builtin/branch.c:921 builtin/branch.c:960
+#: builtin/branch.c:911 builtin/branch.c:950
msgid "branch name required"
msgstr "Необходимо е име на клон"
-#: builtin/branch.c:936
+#: builtin/branch.c:926
msgid "Cannot give description to detached HEAD"
msgstr "Не може да зададете описание на „HEAD“ извън клон"
-#: builtin/branch.c:941
+#: builtin/branch.c:931
msgid "cannot edit description of more than one branch"
msgstr "Не може да редактирате описанието на повече от един клон едновременно"
-#: builtin/branch.c:948
+#: builtin/branch.c:938
#, c-format
msgid "No commit on branch '%s' yet."
msgstr "В клона „%s“ все още няма подавания."
-#: builtin/branch.c:951
+#: builtin/branch.c:941
#, c-format
msgid "No branch named '%s'."
msgstr "Липсва клон на име „%s“."
-#: builtin/branch.c:966
+#: builtin/branch.c:956
msgid "too many branches for a rename operation"
msgstr "Прекалено много клони за преименуване"
-#: builtin/branch.c:971
+#: builtin/branch.c:961
msgid "too many branches to set new upstream"
msgstr "Прекалено много клони за задаване на следене"
-#: builtin/branch.c:975
+#: builtin/branch.c:965
#, c-format
msgid ""
"could not set upstream of HEAD to %s when it does not point to any branch."
@@ -3352,39 +3383,39 @@ msgstr ""
"Следеното от „HEAD“ не може да се зададе да е „%s“, защото то не сочи към "
"никой клон."
-#: builtin/branch.c:978 builtin/branch.c:1000 builtin/branch.c:1021
+#: builtin/branch.c:968 builtin/branch.c:990 builtin/branch.c:1011
#, c-format
msgid "no such branch '%s'"
msgstr "Няма клон на име „%s“."
-#: builtin/branch.c:982
+#: builtin/branch.c:972
#, c-format
msgid "branch '%s' does not exist"
msgstr "Не съществува клон на име „%s“."
-#: builtin/branch.c:994
+#: builtin/branch.c:984
msgid "too many branches to unset upstream"
msgstr "Прекалено много клони за махане на следене"
-#: builtin/branch.c:998
+#: builtin/branch.c:988
msgid "could not unset upstream of HEAD when it does not point to any branch."
msgstr ""
"Следеното от „HEAD“ не може да махне, защото то не сочи към никой клон."
-#: builtin/branch.c:1004
+#: builtin/branch.c:994
#, c-format
msgid "Branch '%s' has no upstream information"
msgstr "Няма информация клонът „%s“ да следи някой друг"
-#: builtin/branch.c:1018
+#: builtin/branch.c:1008
msgid "it does not make sense to create 'HEAD' manually"
msgstr "Няма никакъв смисъл ръчно да създавате „HEAD“."
-#: builtin/branch.c:1024
+#: builtin/branch.c:1014
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
msgstr "Опциите „-a“ и „-r“ на „git branch“ са несъвместими с име на клон"
-#: builtin/branch.c:1027
+#: builtin/branch.c:1017
#, c-format
msgid ""
"The --set-upstream flag is deprecated and will be removed. Consider using --"
@@ -3393,7 +3424,7 @@ msgstr ""
"Опцията „--set-upstream“ вече е остаряла и предстои да бъде махната. "
"Използвайте „--track“ или „--set-upstream-to“\n"
-#: builtin/branch.c:1044
+#: builtin/branch.c:1034
#, c-format
msgid ""
"\n"
@@ -3404,74 +3435,91 @@ msgstr ""
"За да накарате „%s“ да следи „%s“, изпълнете следната команда:\n"
"\n"
-#: builtin/branch.c:1045
+#: builtin/branch.c:1035
#, c-format
msgid " git branch -d %s\n"
msgstr " git branch -d %s\n"
-#: builtin/branch.c:1046
+#: builtin/branch.c:1036
#, c-format
msgid " git branch --set-upstream-to %s\n"
msgstr " git branch --set-upstream-to %s\n"
-#: builtin/bundle.c:47
+#: builtin/bundle.c:51
#, c-format
msgid "%s is okay\n"
msgstr "Пратката „%s“ е наред\n"
-#: builtin/bundle.c:56
+#: builtin/bundle.c:64
msgid "Need a repository to create a bundle."
msgstr "За създаването на пратка е необходимо хранилище."
-#: builtin/bundle.c:60
+#: builtin/bundle.c:68
msgid "Need a repository to unbundle."
msgstr "За приемането на пратка е необходимо хранилище."
-#: builtin/cat-file.c:326
-msgid "git cat-file (-t | -s | -e | -p | <type> | --textconv) <object>"
-msgstr "git cat-file (-t | -s | -e | -p | ВИД | --textconv) ОБЕКТ"
+#: builtin/cat-file.c:369
+msgid ""
+"git cat-file (-t [--allow-unknown-type]|-s [--allow-unknown-type]|-e|-p|"
+"<type>|--textconv) <object>"
+msgstr ""
+"git cat-file (-t [--allow-unknown-type] | -s [--allow-unknown-type] | -e | -"
+"p | ВИД | --textconv) ОБЕКТ"
-#: builtin/cat-file.c:327
-msgid "git cat-file (--batch | --batch-check) < <list-of-objects>"
-msgstr "git cat-file (--batch | --batch-check) < СПИСЪК_С_ОБЕКТИ"
+#: builtin/cat-file.c:370
+msgid ""
+"git cat-file (--batch | --batch-check) [--follow-symlinks] < <list-of-"
+"objects>"
+msgstr ""
+"git cat-file (--batch | --batch-check) [--follow-symlinks] < СПИСЪК_С_ОБЕКТИ"
-#: builtin/cat-file.c:364
+#: builtin/cat-file.c:407
msgid "<type> can be one of: blob, tree, commit, tag"
msgstr ""
"ВИДът може да е: „blob“ (обект BLOB), „tree“ (дърво), „commit“ (подаване), "
"„tag“ (етикет)"
-#: builtin/cat-file.c:365
+#: builtin/cat-file.c:408
msgid "show object type"
msgstr "извеждане на вида на обект"
-#: builtin/cat-file.c:366
+#: builtin/cat-file.c:409
msgid "show object size"
msgstr "извеждане на размера на обект"
-#: builtin/cat-file.c:368
+#: builtin/cat-file.c:411
msgid "exit with zero when there's no error"
msgstr "изход с 0, когато няма грешка"
-#: builtin/cat-file.c:369
+#: builtin/cat-file.c:412
msgid "pretty-print object's content"
msgstr "форматирано извеждане на съдържанието на обекта"
-#: builtin/cat-file.c:371
+#: builtin/cat-file.c:414
msgid "for blob objects, run textconv on object's content"
msgstr ""
"да се стартира програмата зададена в настройката „textconv“ за преобразуване "
"на съдържанието на обекта"
-#: builtin/cat-file.c:373
+#: builtin/cat-file.c:416
+msgid "allow -s and -t to work with broken/corrupt objects"
+msgstr "позволяване на опциите „-s“ и „-t“ да работят с повредени обекти"
+
+#: builtin/cat-file.c:418
msgid "show info and content of objects fed from the standard input"
msgstr ""
"извеждане на информация и съдържание на обектите подадени на стандартния вход"
-#: builtin/cat-file.c:376
+#: builtin/cat-file.c:421
msgid "show info about objects fed from the standard input"
msgstr "извеждане на информация за обектите подадени на стандартния вход"
+#: builtin/cat-file.c:424
+msgid "follow in-tree symlinks (used with --batch or --batch-check)"
+msgstr ""
+"следване на символните връзки сочещи в дървото (ползва се с „--batch“ или „--"
+"batch-check“)"
+
#: builtin/check-attr.c:11
msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
msgstr "git check-attr [-a | --all | АТРИБУТ…] [--] ПЪТ…"
@@ -3488,7 +3536,7 @@ msgstr "извеждане на всички атрибути, зададени
msgid "use .gitattributes only from the index"
msgstr "използване на файла „.gitattributes“ само от индекса"
-#: builtin/check-attr.c:21 builtin/check-ignore.c:22 builtin/hash-object.c:98
+#: builtin/check-attr.c:21 builtin/check-ignore.c:22 builtin/hash-object.c:96
msgid "read file names from stdin"
msgstr "изчитане на имената на файловете от стандартния вход"
@@ -3496,7 +3544,7 @@ msgstr "изчитане на имената на файловете от ста
msgid "terminate input and output records by a NUL character"
msgstr "разделяне на входните и изходните записи с нулевия знак „NUL“"
-#: builtin/check-ignore.c:18 builtin/checkout.c:1107 builtin/gc.c:274
+#: builtin/check-ignore.c:18 builtin/checkout.c:1202 builtin/gc.c:279
msgid "suppress progress reporting"
msgstr "без показване на напредъка"
@@ -3596,117 +3644,116 @@ msgstr "при създаването на нови файлове да се д
msgid "copy out the files from named stage"
msgstr "копиране на файловете от това състояние на сливане"
-#: builtin/checkout.c:25
+#: builtin/checkout.c:24
msgid "git checkout [<options>] <branch>"
msgstr "git checkout [ОПЦИЯ…] КЛОН"
-#: builtin/checkout.c:26
+#: builtin/checkout.c:25
msgid "git checkout [<options>] [<branch>] -- <file>..."
msgstr "git checkout [ОПЦИЯ…] [КЛОН] -- ФАЙЛ…"
-#: builtin/checkout.c:132 builtin/checkout.c:165
+#: builtin/checkout.c:134 builtin/checkout.c:167
#, c-format
msgid "path '%s' does not have our version"
msgstr "вашата версия липсва в пътя „%s“"
-#: builtin/checkout.c:134 builtin/checkout.c:167
+#: builtin/checkout.c:136 builtin/checkout.c:169
#, c-format
msgid "path '%s' does not have their version"
msgstr "чуждата версия липсва в пътя „%s“"
# FIXME SAME AS [1]
-#: builtin/checkout.c:150
+#: builtin/checkout.c:152
#, c-format
msgid "path '%s' does not have all necessary versions"
msgstr "някоя от необходимите версии липсва в пътя „%s“"
# FIXME SAME AS [1]
-#: builtin/checkout.c:194
+#: builtin/checkout.c:196
#, c-format
msgid "path '%s' does not have necessary versions"
msgstr "някоя от необходимите версии липсва в пътя „%s“"
-#: builtin/checkout.c:211
+#: builtin/checkout.c:213
#, c-format
msgid "path '%s': cannot merge"
msgstr "пътят „%s“ не може да бъде слян"
-#: builtin/checkout.c:228
+#: builtin/checkout.c:230
#, c-format
msgid "Unable to add merge result for '%s'"
msgstr "Резултатът за „%s“ не може да бъде слян"
-#: builtin/checkout.c:249 builtin/checkout.c:252 builtin/checkout.c:255
-#: builtin/checkout.c:258
+#: builtin/checkout.c:251 builtin/checkout.c:254 builtin/checkout.c:257
+#: builtin/checkout.c:260
#, c-format
msgid "'%s' cannot be used with updating paths"
msgstr "Опцията „%s“ е несъвместима с обновяването на пътища"
-#: builtin/checkout.c:261 builtin/checkout.c:264
+#: builtin/checkout.c:263 builtin/checkout.c:266
#, c-format
msgid "'%s' cannot be used with %s"
msgstr "Опцията „%s“ е несъвместима с „%s“"
-#: builtin/checkout.c:267
+#: builtin/checkout.c:269
#, c-format
msgid "Cannot update paths and switch to branch '%s' at the same time."
msgstr ""
-"Невъзможно е едновременно да обновявате пътища и да се прехвърлите към клона "
-"„%s“."
+"Невъзможно е едновременно да обновявате пътища и да преминете към клона „%s“."
-#: builtin/checkout.c:278 builtin/checkout.c:467
+#: builtin/checkout.c:280 builtin/checkout.c:474
msgid "corrupt index file"
msgstr "повреден файл на индекса"
-#: builtin/checkout.c:338 builtin/checkout.c:345
+#: builtin/checkout.c:340 builtin/checkout.c:347
#, c-format
msgid "path '%s' is unmerged"
msgstr "пътят „%s“ не е слят"
-#: builtin/checkout.c:489
+#: builtin/checkout.c:496
msgid "you need to resolve your current index first"
msgstr "първо трябва да коригирате индекса си"
-#: builtin/checkout.c:615
+#: builtin/checkout.c:627
#, c-format
msgid "Can not do reflog for '%s'\n"
msgstr "Журналът на указателите за „%s“ не може да бъде създаден\n"
-#: builtin/checkout.c:653
+#: builtin/checkout.c:663
msgid "HEAD is now at"
msgstr "Указателят „HEAD“ в момента сочи към"
-#: builtin/checkout.c:660
+#: builtin/checkout.c:670
#, c-format
msgid "Reset branch '%s'\n"
msgstr "Зануляване на клона „%s“\n"
-#: builtin/checkout.c:663
+#: builtin/checkout.c:673
#, c-format
msgid "Already on '%s'\n"
msgstr "Вече сте на „%s“\n"
-#: builtin/checkout.c:667
+#: builtin/checkout.c:677
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr "Преминаване към клона „%s“ и зануляване на промените\n"
-#: builtin/checkout.c:669 builtin/checkout.c:1050
+#: builtin/checkout.c:679 builtin/checkout.c:1134
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr "Преминахте към новия клон „%s“\n"
-#: builtin/checkout.c:671
+#: builtin/checkout.c:681
#, c-format
msgid "Switched to branch '%s'\n"
msgstr "Преминахте към клона „%s“\n"
-#: builtin/checkout.c:723
+#: builtin/checkout.c:733
#, c-format
msgid " ... and %d more.\n"
msgstr "… и още %d.\n"
-#: builtin/checkout.c:729
+#: builtin/checkout.c:739
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
@@ -3728,158 +3775,180 @@ msgstr[1] ""
"\n"
"%s\n"
-#: builtin/checkout.c:747
+#: builtin/checkout.c:758
#, c-format
msgid ""
+"If you want to keep it by creating a new branch, this may be a good time\n"
+"to do so with:\n"
+"\n"
+" git branch <new-branch-name> %s\n"
+"\n"
+msgid_plural ""
"If you want to keep them by creating a new branch, this may be a good time\n"
"to do so with:\n"
"\n"
" git branch <new-branch-name> %s\n"
"\n"
-msgstr ""
+msgstr[0] ""
+"Ако все пак искате да запазите тази промяна чрез създаване на клон,\n"
+"сега е най-подходящият за това чрез командата:\n"
+"\n"
+" git branch ИМЕ_НА_НОВИЯ_КЛОН %s\n"
+"\n"
+msgstr[1] ""
"Ако все пак искате да запазите тези промени чрез създаване на клон,\n"
"сега е най-подходящият за това чрез командата:\n"
"\n"
" git branch ИМЕ_НА_НОВИЯ_КЛОН %s\n"
"\n"
-#: builtin/checkout.c:777
+#: builtin/checkout.c:794
msgid "internal error in revision walk"
msgstr "вътрешна грешка при обхождането на версиите"
-#: builtin/checkout.c:781
+#: builtin/checkout.c:798
msgid "Previous HEAD position was"
msgstr "Преди това „HEAD“ сочеше към"
-#: builtin/checkout.c:808 builtin/checkout.c:1045
+#: builtin/checkout.c:825 builtin/checkout.c:1129
msgid "You are on a branch yet to be born"
msgstr "В момента сте на клон, който предстои да бъде създаден"
-#: builtin/checkout.c:952
+#: builtin/checkout.c:931
+#, c-format
+msgid "'%s' is already checked out at '%s'"
+msgstr "„%s“ вече е изтеглен в „%s“"
+
+#: builtin/checkout.c:1036
#, c-format
msgid "only one reference expected, %d given."
msgstr "очакваше се един указател, а сте подали %d."
-#: builtin/checkout.c:991
+#: builtin/checkout.c:1075
#, c-format
msgid "invalid reference: %s"
msgstr "неправилен указател: %s"
-#: builtin/checkout.c:1020
+#: builtin/checkout.c:1104
#, c-format
msgid "reference is not a tree: %s"
msgstr "указателят не сочи към обект-дърво: %s"
-#: builtin/checkout.c:1059
+#: builtin/checkout.c:1143
msgid "paths cannot be used with switching branches"
msgstr "задаването на път е несъвместимо с преминаването от един клон към друг"
-#: builtin/checkout.c:1062 builtin/checkout.c:1066
+#: builtin/checkout.c:1146 builtin/checkout.c:1150
#, c-format
msgid "'%s' cannot be used with switching branches"
msgstr "опцията „%s“ е несъвместима с преминаването от един клон към друг"
-#: builtin/checkout.c:1070 builtin/checkout.c:1073 builtin/checkout.c:1078
-#: builtin/checkout.c:1081
+#: builtin/checkout.c:1154 builtin/checkout.c:1157 builtin/checkout.c:1162
+#: builtin/checkout.c:1165
#, c-format
msgid "'%s' cannot be used with '%s'"
msgstr "опцията „%s“ е несъвместима с „%s“"
-#: builtin/checkout.c:1086
+#: builtin/checkout.c:1170
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
msgstr ""
"За да преминете към клон, подайте указател, който сочи към подаване. „%s“ не "
"е такъв"
-#: builtin/checkout.c:1108 builtin/checkout.c:1110 builtin/clone.c:90
-#: builtin/remote.c:159 builtin/remote.c:161
+#: builtin/checkout.c:1203 builtin/checkout.c:1205 builtin/clone.c:83
+#: builtin/remote.c:159 builtin/remote.c:161 builtin/worktree.c:282
+#: builtin/worktree.c:284
msgid "branch"
msgstr "клон"
-#: builtin/checkout.c:1109
+#: builtin/checkout.c:1204
msgid "create and checkout a new branch"
msgstr "създаване и преминаване към нов клон"
-#: builtin/checkout.c:1111
+#: builtin/checkout.c:1206
msgid "create/reset and checkout a branch"
msgstr "създаване/зануляване на клон и преминаване към него"
-#: builtin/checkout.c:1112
+#: builtin/checkout.c:1207
msgid "create reflog for new branch"
msgstr "създаване на журнал на указателите за нов клон"
-#: builtin/checkout.c:1113
+#: builtin/checkout.c:1208
msgid "detach the HEAD at named commit"
msgstr "отделяне на указателя „HEAD“ към указаното подаване"
-#: builtin/checkout.c:1114
+#: builtin/checkout.c:1209
msgid "set upstream info for new branch"
msgstr "задаване на кой клон бива следен при създаването на новия клон"
-#: builtin/checkout.c:1116
+#: builtin/checkout.c:1211
msgid "new-branch"
msgstr "НОВ_КЛОН"
-#: builtin/checkout.c:1116
+#: builtin/checkout.c:1211
msgid "new unparented branch"
msgstr "нов клон без родител"
-#: builtin/checkout.c:1117
+#: builtin/checkout.c:1212
msgid "checkout our version for unmerged files"
msgstr "изтегляне на вашата версия на неслетите файлове"
-#: builtin/checkout.c:1119
+#: builtin/checkout.c:1214
msgid "checkout their version for unmerged files"
msgstr "изтегляне на чуждата версия на неслетите файлове"
-#: builtin/checkout.c:1121
+#: builtin/checkout.c:1216
msgid "force checkout (throw away local modifications)"
msgstr "принудително изтегляне (вашите промени ще бъдат занулени)"
-#: builtin/checkout.c:1122
+#: builtin/checkout.c:1217
msgid "perform a 3-way merge with the new branch"
msgstr "извършване на тройно сливане с новия клон"
-#: builtin/checkout.c:1123 builtin/merge.c:227
+#: builtin/checkout.c:1218 builtin/merge.c:227
msgid "update ignored files (default)"
msgstr "обновяване на игнорираните файлове (стандартно)"
-#: builtin/checkout.c:1124 builtin/log.c:1239 parse-options.h:245
+#: builtin/checkout.c:1219 builtin/log.c:1239 parse-options.h:244
msgid "style"
msgstr "стил"
-#: builtin/checkout.c:1125
+#: builtin/checkout.c:1220
msgid "conflict style (merge or diff3)"
msgstr "действие при конфликт (сливане или тройна разлика)"
-#: builtin/checkout.c:1128
+#: builtin/checkout.c:1223
msgid "do not limit pathspecs to sparse entries only"
msgstr "без ограничаване на изброените пътища само до частично изтеглените"
-#: builtin/checkout.c:1130
+#: builtin/checkout.c:1225
msgid "second guess 'git checkout <no-such-branch>'"
msgstr ""
"опит за отгатване на име на клон след неуспешен опит с „git checkout "
"НЕСЪЩЕСТВУВАЩ_КЛОН“"
-#: builtin/checkout.c:1153
+#: builtin/checkout.c:1227
+msgid "do not check if another worktree is holding the given ref"
+msgstr "без проверка дали друго работно дърво държи указателя"
+
+#: builtin/checkout.c:1252
msgid "-b, -B and --orphan are mutually exclusive"
msgstr "Опциите „-b“, „-B“ и „--orphan“ са несъвместими една с друга"
-#: builtin/checkout.c:1170
+#: builtin/checkout.c:1269
msgid "--track needs a branch name"
msgstr "опцията „--track“ изисква име на клон"
-#: builtin/checkout.c:1175
+#: builtin/checkout.c:1274
msgid "Missing branch name; try -b"
msgstr "Липсва име на клон, използвайте опцията „-b“"
-#: builtin/checkout.c:1212
+#: builtin/checkout.c:1310
msgid "invalid path specification"
msgstr "указан е неправилен път"
-#: builtin/checkout.c:1219
+#: builtin/checkout.c:1317
#, c-format
msgid ""
"Cannot update paths and switch to branch '%s' at the same time.\n"
@@ -3888,12 +3957,12 @@ msgstr ""
"Не можете едновременно да обновявате пътища и да преминете към клона „%s“.\n"
"Дали не искате да изтеглите „%s“, който не сочи към подаване?"
-#: builtin/checkout.c:1224
+#: builtin/checkout.c:1322
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
msgstr "git checkout: опцията „--detach“ не приема аргумент-път „%s“"
-#: builtin/checkout.c:1228
+#: builtin/checkout.c:1326
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
@@ -3964,38 +4033,38 @@ msgstr ""
" — (празно) завършване на избирането"
# FIXME WTF does this mean
-#: builtin/clean.c:517
+#: builtin/clean.c:515
#, c-format
msgid "Huh (%s)?"
msgstr "Неправилен избор (%s). Изберете отново."
# FIXME - should we use >> or sth else
-#: builtin/clean.c:659
+#: builtin/clean.c:657
#, c-format
msgid "Input ignore patterns>> "
msgstr "Шаблони за игнорирани елементи≫ "
-#: builtin/clean.c:696
+#: builtin/clean.c:694
#, c-format
msgid "WARNING: Cannot find items matched by: %s"
msgstr "ПРЕДУПРЕЖДЕНИЕ: Никой обект не напасва на „%s“"
-#: builtin/clean.c:717
+#: builtin/clean.c:715
msgid "Select items to delete"
msgstr "Избиране на обекти за изтриване"
#. TRANSLATORS: Make sure to keep [y/N] as is
-#: builtin/clean.c:758
+#: builtin/clean.c:756
#, c-format
msgid "Remove %s [y/N]? "
msgstr "Да се изтрие ли „%s“? „y“ — да, „N“ — НЕ"
# FIXME improve message
-#: builtin/clean.c:783
+#: builtin/clean.c:781
msgid "Bye."
msgstr "Изход."
-#: builtin/clean.c:791
+#: builtin/clean.c:789
msgid ""
"clean - start cleaning\n"
"filter by pattern - exclude items from deletion\n"
@@ -4014,63 +4083,63 @@ msgstr ""
"? — подсказка за шаблоните"
# FIXME how many ***
-#: builtin/clean.c:818
+#: builtin/clean.c:816
msgid "*** Commands ***"
msgstr "●●● Команди ●●●"
# FIXME improve message
-#: builtin/clean.c:819
+#: builtin/clean.c:817
msgid "What now"
msgstr "Избор на следващо действие"
-#: builtin/clean.c:827
+#: builtin/clean.c:825
msgid "Would remove the following item:"
msgid_plural "Would remove the following items:"
msgstr[0] "Следният обект ще бъде изтрит:"
msgstr[1] "Следните обекти ще бъдат изтрити:"
-#: builtin/clean.c:844
+#: builtin/clean.c:842
msgid "No more files to clean, exiting."
msgstr "Файловете за изчистване свършиха. Изход от програмата."
-#: builtin/clean.c:875
+#: builtin/clean.c:873
msgid "do not print names of files removed"
msgstr "без извеждане на имената на файловете, които ще бъдат изтрити"
-#: builtin/clean.c:877
+#: builtin/clean.c:875
msgid "force"
msgstr "принудително изтриване"
-#: builtin/clean.c:878
+#: builtin/clean.c:876
msgid "interactive cleaning"
msgstr "интерактивно изтриване"
-#: builtin/clean.c:880
+#: builtin/clean.c:878
msgid "remove whole directories"
msgstr "изтриване на цели директории"
-#: builtin/clean.c:881 builtin/describe.c:407 builtin/grep.c:714
-#: builtin/ls-files.c:443 builtin/name-rev.c:311 builtin/show-ref.c:185
+#: builtin/clean.c:879 builtin/describe.c:407 builtin/grep.c:714
+#: builtin/ls-files.c:443 builtin/name-rev.c:311 builtin/show-ref.c:187
msgid "pattern"
msgstr "шаблон"
-#: builtin/clean.c:882
+#: builtin/clean.c:880
msgid "add <pattern> to ignore rules"
msgstr "добавяне на ШАБЛОН от файлове, които да не се трият"
-#: builtin/clean.c:883
+#: builtin/clean.c:881
msgid "remove ignored files, too"
msgstr "изтриване и на игнорираните файлове"
-#: builtin/clean.c:885
+#: builtin/clean.c:883
msgid "remove only ignored files"
msgstr "изтриване само на игнорирани файлове"
-#: builtin/clean.c:903
+#: builtin/clean.c:901
msgid "-x and -X cannot be used together"
msgstr "опциите „-x“ и „-X“ са несъвместими"
-#: builtin/clean.c:907
+#: builtin/clean.c:905
msgid ""
"clean.requireForce set to true and neither -i, -n, nor -f given; refusing to "
"clean"
@@ -4078,7 +4147,7 @@ msgstr ""
"Настройката „clean.requireForce“ е зададена като истина, което изисква някоя "
"от опциите „-i“, „-n“ или „-f“. Няма да се извърши изчистване"
-#: builtin/clean.c:910
+#: builtin/clean.c:908
msgid ""
"clean.requireForce defaults to true and neither -i, -n, nor -f given; "
"refusing to clean"
@@ -4091,153 +4160,153 @@ msgstr ""
msgid "git clone [<options>] [--] <repo> [<dir>]"
msgstr "git clone [ОПЦИЯ…] [--] ХРАНИЛИЩЕ [ДИРЕКТОРИЯ]"
-#: builtin/clone.c:66 builtin/fetch.c:111 builtin/merge.c:224
+#: builtin/clone.c:57 builtin/fetch.c:111 builtin/merge.c:224
#: builtin/push.c:523
msgid "force progress reporting"
msgstr "извеждане на напредъка"
-#: builtin/clone.c:68
+#: builtin/clone.c:59
msgid "don't create a checkout"
msgstr "без създаване на работно дърво"
-#: builtin/clone.c:69 builtin/clone.c:71 builtin/init-db.c:496
+#: builtin/clone.c:60 builtin/clone.c:62 builtin/init-db.c:503
msgid "create a bare repository"
msgstr "създаване на голо хранилище"
-#: builtin/clone.c:73
+#: builtin/clone.c:64
msgid "create a mirror repository (implies bare)"
msgstr ""
"създаване на хранилище-огледало (включва опцията „--bare“ за голо хранилище)"
-#: builtin/clone.c:75
+#: builtin/clone.c:66
msgid "to clone from a local repository"
msgstr "клониране от локално хранилище"
-#: builtin/clone.c:77
+#: builtin/clone.c:68
msgid "don't use local hardlinks, always copy"
msgstr "без твърди връзки, файловете винаги да се копират"
-#: builtin/clone.c:79
+#: builtin/clone.c:70
msgid "setup as shared repository"
msgstr "настройване за споделено хранилище"
-#: builtin/clone.c:81 builtin/clone.c:83
+#: builtin/clone.c:72 builtin/clone.c:74
msgid "initialize submodules in the clone"
msgstr "инициализиране на подмодулите при това клониране"
-#: builtin/clone.c:84 builtin/init-db.c:493
+#: builtin/clone.c:75 builtin/init-db.c:500
msgid "template-directory"
msgstr "директория с шаблони"
-#: builtin/clone.c:85 builtin/init-db.c:494
+#: builtin/clone.c:76 builtin/init-db.c:501
msgid "directory from which templates will be used"
msgstr "директория, която съдържа шаблоните, които да се ползват"
-#: builtin/clone.c:87
+#: builtin/clone.c:78
msgid "reference repository"
msgstr "еталонно хранилище"
-#: builtin/clone.c:88 builtin/column.c:26 builtin/merge-file.c:44
+#: builtin/clone.c:80
+msgid "use --reference only while cloning"
+msgstr "опцията „--reference“ може да се използва само при клониране"
+
+#: builtin/clone.c:81 builtin/column.c:26 builtin/merge-file.c:44
msgid "name"
msgstr "ИМЕ"
-#: builtin/clone.c:89
+#: builtin/clone.c:82
msgid "use <name> instead of 'origin' to track upstream"
msgstr "използване на това ИМЕ вместо „origin“ при проследяване на клони"
-#: builtin/clone.c:91
+#: builtin/clone.c:84
msgid "checkout <branch> instead of the remote's HEAD"
msgstr "изтегляне на този КЛОН, а не соченият от отдалечения указател „HEAD“"
-#: builtin/clone.c:93
+#: builtin/clone.c:86
msgid "path to git-upload-pack on the remote"
msgstr "път към командата „git-upload-pack“ на отдалеченото хранилище"
-#: builtin/clone.c:94 builtin/fetch.c:112 builtin/grep.c:659
+#: builtin/clone.c:87 builtin/fetch.c:112 builtin/grep.c:659
msgid "depth"
msgstr "ДЪЛБОЧИНА"
-#: builtin/clone.c:95
+#: builtin/clone.c:88
msgid "create a shallow clone of that depth"
msgstr "плитко клониране до тази ДЪЛБОЧИНА"
-#: builtin/clone.c:97
+#: builtin/clone.c:90
msgid "clone only one branch, HEAD or --branch"
msgstr ""
"клониране само на един клон — или сочения от отдалечения „HEAD“, или изрично "
"зададения с „--branch“"
-#: builtin/clone.c:99
-msgid "use --reference only while cloning"
-msgstr "опцията „--reference“ може да се използва само при клониране"
-
-#: builtin/clone.c:100 builtin/init-db.c:502
+#: builtin/clone.c:91 builtin/init-db.c:509
msgid "gitdir"
msgstr "СЛУЖЕБНА_ДИРЕКТОРИЯ"
-#: builtin/clone.c:101 builtin/init-db.c:503
+#: builtin/clone.c:92 builtin/init-db.c:510
msgid "separate git dir from working tree"
msgstr "отделна СЛУЖЕБНА_ДИРЕКТОРИЯ за git извън работното дърво"
-#: builtin/clone.c:102
+#: builtin/clone.c:93
msgid "key=value"
msgstr "КЛЮЧ=СТОЙНОСТ"
-#: builtin/clone.c:103
+#: builtin/clone.c:94
msgid "set config inside the new repository"
msgstr "задаване на настройките на новото хранилище"
-#: builtin/clone.c:256
+#: builtin/clone.c:240
#, c-format
msgid "reference repository '%s' is not a local repository."
msgstr "еталонното хранилище „%s“ не е локално"
-#: builtin/clone.c:260
+#: builtin/clone.c:244
#, c-format
msgid "reference repository '%s' is shallow"
msgstr "еталонното хранилище „%s“ е плитко"
-#: builtin/clone.c:263
+#: builtin/clone.c:247
#, c-format
msgid "reference repository '%s' is grafted"
msgstr "еталонното хранилище „%s“ е с присаждане"
-#: builtin/clone.c:325
+#: builtin/clone.c:310
#, c-format
msgid "failed to create directory '%s'"
msgstr "директорията „%s“ не може да бъде създадена"
-#: builtin/clone.c:327 builtin/diff.c:84
+#: builtin/clone.c:312 builtin/diff.c:84
#, c-format
msgid "failed to stat '%s'"
msgstr "не може да бъде получена информация чрез „stat“ за „%s“"
-#: builtin/clone.c:329
+#: builtin/clone.c:314
#, c-format
msgid "%s exists and is not a directory"
msgstr "„%s“ съществува и не е директория"
-#: builtin/clone.c:343
+#: builtin/clone.c:328
#, c-format
msgid "failed to stat %s\n"
msgstr "не може да бъде получена информация чрез „stat“ за „%s“\n"
-#: builtin/clone.c:365
+#: builtin/clone.c:350
#, c-format
msgid "failed to create link '%s'"
msgstr "връзката „%s“ не може да бъде създадена"
-#: builtin/clone.c:369
+#: builtin/clone.c:354
#, c-format
msgid "failed to copy file to '%s'"
msgstr "файлът не може да бъде копиран като „%s“"
-#: builtin/clone.c:392 builtin/clone.c:566
+#: builtin/clone.c:377 builtin/clone.c:551
#, c-format
msgid "done.\n"
msgstr "действието завърши.\n"
-#: builtin/clone.c:404
+#: builtin/clone.c:389
msgid ""
"Clone succeeded, but checkout failed.\n"
"You can inspect what was checked out with 'git status'\n"
@@ -4248,7 +4317,7 @@ msgstr ""
"клон в момента са изтеглени с командата „git status“. Можете да\n"
"завършите изтеглянето на клона с командата „git checkout -f HEAD“.\n"
-#: builtin/clone.c:481
+#: builtin/clone.c:466
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr ""
@@ -4256,119 +4325,120 @@ msgstr ""
"и който следва да бъде изтеглен, не съществува."
# FIXME translator note that the space at end is necesssary
-#: builtin/clone.c:561
+#: builtin/clone.c:546
#, c-format
msgid "Checking connectivity... "
msgstr "Проверка на връзката… "
-#: builtin/clone.c:564
+#: builtin/clone.c:549
msgid "remote did not send all necessary objects"
msgstr "отдалеченото хранилище не изпрати всички необходими обекти."
-#: builtin/clone.c:628
+#: builtin/clone.c:613
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
msgstr ""
"указателят „HEAD“ от отдалеченото хранилище сочи към нещо,\n"
"което не съществува. Не може да се изтегли определен клон.\n"
-#: builtin/clone.c:659
+#: builtin/clone.c:644
msgid "unable to checkout working tree"
msgstr "работното дърво не може да бъде подготвено"
-#: builtin/clone.c:746
+#: builtin/clone.c:731
msgid "cannot repack to clean up"
msgstr "не може да се извърши пакетиране за изчистване на файловете"
-#: builtin/clone.c:748
+#: builtin/clone.c:733
msgid "cannot unlink temporary alternates file"
msgstr "временният файл за алтернативни обекти не може да бъде изтрит"
-#: builtin/clone.c:778
+#: builtin/clone.c:763
msgid "Too many arguments."
msgstr "Прекалено много аргументи."
-#: builtin/clone.c:782
+#: builtin/clone.c:767
msgid "You must specify a repository to clone."
msgstr "Трябва да укажете кое хранилище искате да клонирате."
-#: builtin/clone.c:793
+#: builtin/clone.c:778
#, c-format
msgid "--bare and --origin %s options are incompatible."
msgstr "опциите „--bare“ и „--origin %s“ са несъвместими."
-#: builtin/clone.c:796
+#: builtin/clone.c:781
msgid "--bare and --separate-git-dir are incompatible."
msgstr "опциите „--bare“ и „--separate-git-dir“ са несъвместими."
-#: builtin/clone.c:809
+#: builtin/clone.c:794
#, c-format
msgid "repository '%s' does not exist"
msgstr "не съществува хранилище „%s“"
-#: builtin/clone.c:815 builtin/fetch.c:1156
+#: builtin/clone.c:800 builtin/fetch.c:1160
#, c-format
msgid "depth %s is not a positive number"
msgstr "дълбочината трябва да е положително цяло число, а не „%s“"
-#: builtin/clone.c:825
+#: builtin/clone.c:810
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
msgstr "целевият път „%s“ съществува и не е празна директория."
-#: builtin/clone.c:835
+#: builtin/clone.c:820
#, c-format
msgid "working tree '%s' already exists."
msgstr "в „%s“ вече съществува работно дърво."
-#: builtin/clone.c:850 builtin/clone.c:861
+#: builtin/clone.c:835 builtin/clone.c:846 builtin/worktree.c:193
+#: builtin/worktree.c:220
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "родителските директории на „%s“ не могат да бъдат създадени"
-#: builtin/clone.c:853
+#: builtin/clone.c:838
#, c-format
msgid "could not create work tree dir '%s'"
msgstr "работното дърво в „%s“ не може да бъде създадено."
-#: builtin/clone.c:871
+#: builtin/clone.c:856
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "Клониране и създаване на голо хранилище в „%s“…\n"
-#: builtin/clone.c:873
+#: builtin/clone.c:858
#, c-format
msgid "Cloning into '%s'...\n"
msgstr "Клониране и създаване на хранилище в „%s“…\n"
-#: builtin/clone.c:898
+#: builtin/clone.c:883
msgid "--dissociate given, but there is no --reference"
msgstr "Опцията „--dissociate“ е несъвместима с „--reference“"
-#: builtin/clone.c:913
+#: builtin/clone.c:900
msgid "--depth is ignored in local clones; use file:// instead."
msgstr ""
"При локално клониране опцията „--depth“ се игнорира. Ползвайте схемата "
"„file://“."
-#: builtin/clone.c:916
+#: builtin/clone.c:903
msgid "source repository is shallow, ignoring --local"
msgstr "клонираното хранилище е плитко, затова опцията „--local“ се игнорира"
-#: builtin/clone.c:921
+#: builtin/clone.c:908
msgid "--local is ignored"
msgstr "опцията „--local“ се игнорира"
-#: builtin/clone.c:925
+#: builtin/clone.c:912
#, c-format
msgid "Don't know how to clone %s"
msgstr "Не се поддържа клониране на връзки от вида „%s“ "
-#: builtin/clone.c:976 builtin/clone.c:984
+#: builtin/clone.c:961 builtin/clone.c:969
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "Отдалеченият клон „%s“ липсва в клонираното хранилище „%s“"
-#: builtin/clone.c:987
+#: builtin/clone.c:972
msgid "You appear to have cloned an empty repository."
msgstr "Изглежда клонирахте празно хранилище."
@@ -4610,7 +4680,7 @@ msgstr "съобщението за сливане MERGE_MSG не може да
msgid "could not read SQUASH_MSG"
msgstr "съобщението за смачкване SQUASH_MSG не може да бъде прочетено"
-#: builtin/commit.c:738
+#: builtin/commit.c:738 builtin/merge.c:1079
#, c-format
msgid "could not read '%s'"
msgstr "файлът „%s“ не може да бъде прочетен"
@@ -4785,32 +4855,32 @@ msgstr "Несъществуващ режим на изчистване „%s“
msgid "Paths with -a does not make sense."
msgstr "Опцията „-a“ е несъвместима със задаването на пътища."
-#: builtin/commit.c:1324 builtin/commit.c:1604
+#: builtin/commit.c:1324 builtin/commit.c:1603
msgid "show status concisely"
msgstr "кратка информация за състоянието"
-#: builtin/commit.c:1326 builtin/commit.c:1606
+#: builtin/commit.c:1326 builtin/commit.c:1605
msgid "show branch information"
msgstr "информация за клоните"
-#: builtin/commit.c:1328 builtin/commit.c:1608 builtin/push.c:509
+#: builtin/commit.c:1328 builtin/commit.c:1607 builtin/push.c:509
msgid "machine-readable output"
msgstr "формат на изхода за четене от програма"
-#: builtin/commit.c:1331 builtin/commit.c:1610
+#: builtin/commit.c:1331 builtin/commit.c:1609
msgid "show status in long format (default)"
msgstr "подробна информация за състоянието (стандартно)"
-#: builtin/commit.c:1334 builtin/commit.c:1613
+#: builtin/commit.c:1334 builtin/commit.c:1612
msgid "terminate entries with NUL"
msgstr "разделяне на елементите с нулевия знак „NUL“"
-#: builtin/commit.c:1336 builtin/commit.c:1616 builtin/fast-export.c:980
+#: builtin/commit.c:1336 builtin/commit.c:1615 builtin/fast-export.c:980
#: builtin/fast-export.c:983 builtin/tag.c:603
msgid "mode"
msgstr "режим"
-#: builtin/commit.c:1337 builtin/commit.c:1616
+#: builtin/commit.c:1337 builtin/commit.c:1615
msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
msgstr ""
"извеждане на неследените файлове. Възможните режими са „all“ (подробна\n"
@@ -4821,7 +4891,7 @@ msgstr ""
msgid "show ignored files"
msgstr "извеждане на игнорираните файлове"
-#: builtin/commit.c:1341 parse-options.h:153
+#: builtin/commit.c:1341 parse-options.h:152
msgid "when"
msgstr "кога"
@@ -4838,209 +4908,209 @@ msgstr ""
msgid "list untracked files in columns"
msgstr "извеждане на неследените файлове в колони"
-#: builtin/commit.c:1431
+#: builtin/commit.c:1430
msgid "couldn't look up newly created commit"
msgstr "току що създаденото подаване не може да бъде открито"
-#: builtin/commit.c:1433
+#: builtin/commit.c:1432
msgid "could not parse newly created commit"
msgstr "току що създаденото подаване не може да бъде анализирано"
-#: builtin/commit.c:1478
+#: builtin/commit.c:1477
msgid "detached HEAD"
msgstr "несвързан връх „HEAD“"
-#: builtin/commit.c:1481
+#: builtin/commit.c:1480
msgid " (root-commit)"
msgstr " (начално подаване)"
-#: builtin/commit.c:1574
+#: builtin/commit.c:1573
msgid "suppress summary after successful commit"
msgstr "без информация след успешно подаване"
-#: builtin/commit.c:1575
+#: builtin/commit.c:1574
msgid "show diff in commit message template"
msgstr "добавяне на разликата към шаблона за съобщението при подаване"
-#: builtin/commit.c:1577
+#: builtin/commit.c:1576
msgid "Commit message options"
msgstr "Опции за съобщението при подаване"
-#: builtin/commit.c:1578 builtin/tag.c:601
+#: builtin/commit.c:1577 builtin/tag.c:601
msgid "read message from file"
msgstr "взимане на съобщението от файл"
-#: builtin/commit.c:1579
+#: builtin/commit.c:1578
msgid "author"
msgstr "автор"
-#: builtin/commit.c:1579
+#: builtin/commit.c:1578
msgid "override author for commit"
msgstr "задаване на автор за подаването"
-#: builtin/commit.c:1580 builtin/gc.c:275
+#: builtin/commit.c:1579 builtin/gc.c:280
msgid "date"
msgstr "дата"
-#: builtin/commit.c:1580
+#: builtin/commit.c:1579
msgid "override date for commit"
msgstr "задаване на дата за подаването"
-#: builtin/commit.c:1581 builtin/merge.c:218 builtin/notes.c:391
+#: builtin/commit.c:1580 builtin/merge.c:218 builtin/notes.c:391
#: builtin/notes.c:554 builtin/tag.c:599
msgid "message"
msgstr "съобщение"
-#: builtin/commit.c:1581
+#: builtin/commit.c:1580
msgid "commit message"
msgstr "съобщение при подаване"
-#: builtin/commit.c:1582
+#: builtin/commit.c:1581
msgid "reuse and edit message from specified commit"
msgstr "преизползване и редактиране на съобщението от указаното подаване"
-#: builtin/commit.c:1583
+#: builtin/commit.c:1582
msgid "reuse message from specified commit"
msgstr "преизползване на съобщението от указаното подаване"
-#: builtin/commit.c:1584
+#: builtin/commit.c:1583
msgid "use autosquash formatted message to fixup specified commit"
msgstr ""
"използване на автоматичното съобщение при смачкване за вкарване на "
"указаното\n"
"подаване в предното без следа"
-#: builtin/commit.c:1585
+#: builtin/commit.c:1584
msgid "use autosquash formatted message to squash specified commit"
msgstr ""
"използване на автоматичното съобщение при смачкване за смачкване на "
"указаното\n"
"подаване в предното"
-#: builtin/commit.c:1586
+#: builtin/commit.c:1585
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr ""
"смяна на автора да съвпада с подаващия (използва се с „-C“/„-c“/„--amend“)"
-#: builtin/commit.c:1587 builtin/log.c:1191 builtin/revert.c:86
+#: builtin/commit.c:1586 builtin/log.c:1191 builtin/revert.c:86
msgid "add Signed-off-by:"
msgstr "добавяне на поле за подпис — „Signed-off-by:“"
-#: builtin/commit.c:1588
+#: builtin/commit.c:1587
msgid "use specified template file"
msgstr "използване на указания шаблонен файл"
-#: builtin/commit.c:1589
+#: builtin/commit.c:1588
msgid "force edit of commit"
msgstr "редактиране на подаване"
-#: builtin/commit.c:1590
+#: builtin/commit.c:1589
msgid "default"
msgstr "стандартно"
-#: builtin/commit.c:1590 builtin/tag.c:604
+#: builtin/commit.c:1589 builtin/tag.c:604
msgid "how to strip spaces and #comments from message"
msgstr "кои празни знаци и #коментари да се махат от съобщенията"
-#: builtin/commit.c:1591
+#: builtin/commit.c:1590
msgid "include status in commit message template"
msgstr "вмъкване на състоянието в шаблона за съобщението при подаване"
-#: builtin/commit.c:1592 builtin/merge.c:225 builtin/revert.c:92
+#: builtin/commit.c:1591 builtin/merge.c:225 builtin/revert.c:92
#: builtin/tag.c:605
msgid "key-id"
msgstr "ИДЕНТИФИКАТОР_НА_КЛЮЧ"
-#: builtin/commit.c:1593 builtin/merge.c:226 builtin/revert.c:93
+#: builtin/commit.c:1592 builtin/merge.c:226 builtin/revert.c:93
msgid "GPG sign commit"
msgstr "подписване на подаването с GPG"
-#: builtin/commit.c:1596
+#: builtin/commit.c:1595
msgid "Commit contents options"
msgstr "Опции за избор на файлове при подаване"
-#: builtin/commit.c:1597
+#: builtin/commit.c:1596
msgid "commit all changed files"
msgstr "подаване на всички променени файлове"
-#: builtin/commit.c:1598
+#: builtin/commit.c:1597
msgid "add specified files to index for commit"
msgstr "добавяне на указаните файлове към индекса за подаване"
-#: builtin/commit.c:1599
+#: builtin/commit.c:1598
msgid "interactively add files"
msgstr "интерактивно добавяне на файлове"
-#: builtin/commit.c:1600
+#: builtin/commit.c:1599
msgid "interactively add changes"
msgstr "интерактивно добавяне на промени"
-#: builtin/commit.c:1601
+#: builtin/commit.c:1600
msgid "commit only specified files"
msgstr "подаване само на указаните файлове"
-#: builtin/commit.c:1602
+#: builtin/commit.c:1601
msgid "bypass pre-commit hook"
msgstr "без изпълнение на куката преди подаване (pre-commit)"
-#: builtin/commit.c:1603
+#: builtin/commit.c:1602
msgid "show what would be committed"
msgstr "отпечатване на това, което би било подадено"
-#: builtin/commit.c:1614
+#: builtin/commit.c:1613
msgid "amend previous commit"
msgstr "поправяне на предишното подаване"
-#: builtin/commit.c:1615
+#: builtin/commit.c:1614
msgid "bypass post-rewrite hook"
msgstr "без изпълнение на куката след презаписване (post-rewrite)"
-#: builtin/commit.c:1620
+#: builtin/commit.c:1619
msgid "ok to record an empty change"
msgstr "позволяване на празни подавания"
-#: builtin/commit.c:1622
+#: builtin/commit.c:1621
msgid "ok to record a change with an empty message"
msgstr "позволяване на подавания с празни съобщения"
-#: builtin/commit.c:1651
+#: builtin/commit.c:1650
msgid "could not parse HEAD commit"
msgstr "върховото подаване „HEAD“ не може да бъде прочетено"
-#: builtin/commit.c:1690 builtin/merge.c:519
+#: builtin/commit.c:1689 builtin/merge.c:1076
#, c-format
msgid "could not open '%s' for reading"
msgstr "файлът не може да бъде прочетен: „%s“"
-#: builtin/commit.c:1697
+#: builtin/commit.c:1696
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
msgstr "Повреден файл за върха за сливането „MERGE_HEAD“ (%s)"
-#: builtin/commit.c:1704
+#: builtin/commit.c:1703
msgid "could not read MERGE_MODE"
msgstr "режимът на сливане „MERGE_MODE“ не може да бъде прочетен"
-#: builtin/commit.c:1723
+#: builtin/commit.c:1722
#, c-format
msgid "could not read commit message: %s"
msgstr "съобщението за подаване не може да бъде прочетено: %s"
-#: builtin/commit.c:1734
+#: builtin/commit.c:1733
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
msgstr "Неизвършване на подаване поради нередактирано съобщение.\n"
-#: builtin/commit.c:1739
+#: builtin/commit.c:1738
#, c-format
msgid "Aborting commit due to empty commit message.\n"
msgstr "Неизвършване на подаване поради празно съобщение.\n"
-#: builtin/commit.c:1754 builtin/merge.c:851 builtin/merge.c:876
+#: builtin/commit.c:1753 builtin/merge.c:829 builtin/merge.c:854
msgid "failed to write commit object"
msgstr "обектът за подаването не може да бъде записан"
-#: builtin/commit.c:1787
+#: builtin/commit.c:1786
msgid ""
"Repository has been updated, but unable to write\n"
"new_index file. Check that disk is not full and quota is\n"
@@ -5188,18 +5258,18 @@ msgstr "неразпозната стойност на стандартния ц
#, c-format
msgid ""
"# This is Git's per-user configuration file.\n"
-"[core]\n"
+"[user]\n"
"# Please adapt and uncomment the following lines:\n"
-"#\tuser = %s\n"
+"#\tname = %s\n"
"#\temail = %s\n"
msgstr ""
"# Това е потребителският ви конфигурационен файл за Git.\n"
-"[core]\n"
+"[user]\n"
"# Проверете и разкоментирайте следните два реда:\n"
-"#\tuser = %s\n"
+"#\tname = %s\n"
"#\temail = %s\n"
-#: builtin/config.c:589
+#: builtin/config.c:587
#, c-format
msgid "cannot create configuration file %s"
msgstr "конфигурационният файл „%s“ не може да бъде създаден"
@@ -5533,84 +5603,84 @@ msgstr "карта с указатели"
msgid "specify fetch refmap"
msgstr "указване на картата с указатели за доставяне"
-#: builtin/fetch.c:375
+#: builtin/fetch.c:377
msgid "Couldn't find remote ref HEAD"
msgstr "Указателят „HEAD“ в отдалеченото хранилище не може да бъде открит"
-#: builtin/fetch.c:455
+#: builtin/fetch.c:457
#, c-format
msgid "object %s not found"
msgstr "обектът „%s“ липсва"
-#: builtin/fetch.c:460
+#: builtin/fetch.c:462
msgid "[up to date]"
msgstr "[актуализиран]"
-#: builtin/fetch.c:474
+#: builtin/fetch.c:476
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
msgstr "! %-*s %-*s → %s (в текущия клон не може да се доставя)"
-#: builtin/fetch.c:475 builtin/fetch.c:561
+#: builtin/fetch.c:477 builtin/fetch.c:563
msgid "[rejected]"
msgstr "[отхвърлен]"
-#: builtin/fetch.c:486
+#: builtin/fetch.c:488
msgid "[tag update]"
msgstr "[обновяване на етикетите]"
-#: builtin/fetch.c:488 builtin/fetch.c:523 builtin/fetch.c:541
+#: builtin/fetch.c:490 builtin/fetch.c:525 builtin/fetch.c:543
msgid " (unable to update local ref)"
msgstr " (локалните указатели не могат да бъдат обновени)"
-#: builtin/fetch.c:506
+#: builtin/fetch.c:508
msgid "[new tag]"
msgstr "[нов етикет]"
-#: builtin/fetch.c:509
+#: builtin/fetch.c:511
msgid "[new branch]"
msgstr "[нов клон]"
-#: builtin/fetch.c:512
+#: builtin/fetch.c:514
msgid "[new ref]"
msgstr "[нов указател]"
-#: builtin/fetch.c:557
+#: builtin/fetch.c:559
msgid "unable to update local ref"
msgstr "локален указател не може да бъде обновен"
-#: builtin/fetch.c:557
+#: builtin/fetch.c:559
msgid "forced update"
msgstr "принудително обновяване"
-#: builtin/fetch.c:563
+#: builtin/fetch.c:565
msgid "(non-fast-forward)"
msgstr "(сливането не е тривиално)"
-#: builtin/fetch.c:596 builtin/fetch.c:829
+#: builtin/fetch.c:599 builtin/fetch.c:832
#, c-format
msgid "cannot open %s: %s\n"
msgstr "файлът „%s“ не може да бъде отворен: %s\n"
-#: builtin/fetch.c:605
+#: builtin/fetch.c:608
#, c-format
msgid "%s did not send all necessary objects\n"
msgstr "хранилището „%s“ не изпрати всички необходими обекти\n"
-#: builtin/fetch.c:623
+#: builtin/fetch.c:626
#, c-format
msgid "reject %s because shallow roots are not allowed to be updated"
msgstr ""
"отхвърляне на върха „%s“, защото плитките хранилища не могат да бъдат "
"обновявани"
-#: builtin/fetch.c:711 builtin/fetch.c:794
+#: builtin/fetch.c:714 builtin/fetch.c:797
#, c-format
msgid "From %.*s\n"
msgstr "От %.*s\n"
# FIXME - is the space necessary
-#: builtin/fetch.c:722
+#: builtin/fetch.c:725
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
@@ -5620,55 +5690,55 @@ msgstr ""
"„git remote prune %s“, за да премахнете остарелите клони, които\n"
"предизвикват конфликта"
-#: builtin/fetch.c:774
+#: builtin/fetch.c:777
#, c-format
msgid " (%s will become dangling)"
msgstr " (обектът „%s“ ще се окаже извън клон)"
-#: builtin/fetch.c:775
+#: builtin/fetch.c:778
#, c-format
msgid " (%s has become dangling)"
msgstr " (обектът „%s“ вече е извън клон)"
-#: builtin/fetch.c:799
+#: builtin/fetch.c:802
msgid "[deleted]"
msgstr "[изтрит]"
-#: builtin/fetch.c:800 builtin/remote.c:1060
+#: builtin/fetch.c:803 builtin/remote.c:1057
msgid "(none)"
msgstr "(нищо)"
-#: builtin/fetch.c:819
+#: builtin/fetch.c:822
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
msgstr "Не може да изтегляте в текущия клон „%s“ на хранилище, което не е голо"
-#: builtin/fetch.c:838
+#: builtin/fetch.c:841
#, c-format
msgid "Option \"%s\" value \"%s\" is not valid for %s"
msgstr "Стойността „%2$s“ за опцията „%1$s“ не е съвместима с „%3$s“"
-#: builtin/fetch.c:841
+#: builtin/fetch.c:844
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
msgstr "Опцията „%s“ се игнорира при „%s“\n"
-#: builtin/fetch.c:897
+#: builtin/fetch.c:900
#, c-format
msgid "Don't know how to fetch from %s"
msgstr "Не се поддържа доставяне от „%s“"
-#: builtin/fetch.c:1059
+#: builtin/fetch.c:1063
#, c-format
msgid "Fetching %s\n"
msgstr "Доставяне на „%s“\n"
-#: builtin/fetch.c:1061 builtin/remote.c:90
+#: builtin/fetch.c:1065 builtin/remote.c:90
#, c-format
msgid "Could not fetch %s"
msgstr "„%s“ не може да се достави"
-#: builtin/fetch.c:1079
+#: builtin/fetch.c:1083
msgid ""
"No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."
@@ -5676,33 +5746,33 @@ msgstr ""
"Не сте указали отдалечено хранилище. Задайте или адрес, или име\n"
"на отдалечено хранилище, откъдето да се доставят новите версии."
-#: builtin/fetch.c:1102
+#: builtin/fetch.c:1106
msgid "You need to specify a tag name."
msgstr "Трябва да укажете име на етикет."
-#: builtin/fetch.c:1144
+#: builtin/fetch.c:1148
msgid "--depth and --unshallow cannot be used together"
msgstr "опциите „--depth“ и „--unshallow“ са несъвместими"
-#: builtin/fetch.c:1146
+#: builtin/fetch.c:1150
msgid "--unshallow on a complete repository does not make sense"
msgstr "не можете да използвате опцията „--unshallow“ върху пълно хранилище"
-#: builtin/fetch.c:1169
+#: builtin/fetch.c:1173
msgid "fetch --all does not take a repository argument"
msgstr "към „git fetch --all“ не можете да добавите аргумент — хранилище"
-#: builtin/fetch.c:1171
+#: builtin/fetch.c:1175
msgid "fetch --all does not make sense with refspecs"
msgstr ""
"към „git fetch --all“ не можете да добавите аргумент — указател на версия"
-#: builtin/fetch.c:1182
+#: builtin/fetch.c:1186
#, c-format
msgid "No such remote or remote group: %s"
msgstr "Няма нито отдалечено хранилище, нито група от хранилища на име „%s“"
-#: builtin/fetch.c:1190
+#: builtin/fetch.c:1194
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr "Указването на група и указването на версия са несъвместими"
@@ -5712,76 +5782,76 @@ msgid ""
msgstr ""
"git fmt-merge-msg [-m СЪОБЩЕНИЕ] [--log[=БРОЙ] | --no-log] [--file ФАЙЛ]"
-#: builtin/fmt-merge-msg.c:662 builtin/fmt-merge-msg.c:665 builtin/grep.c:698
+#: builtin/fmt-merge-msg.c:668 builtin/fmt-merge-msg.c:671 builtin/grep.c:698
#: builtin/merge.c:198 builtin/repack.c:178 builtin/repack.c:182
-#: builtin/show-branch.c:657 builtin/show-ref.c:178 builtin/tag.c:590
-#: parse-options.h:132 parse-options.h:239
+#: builtin/show-branch.c:664 builtin/show-ref.c:180 builtin/tag.c:590
+#: parse-options.h:131 parse-options.h:238
msgid "n"
msgstr "БРОЙ"
-#: builtin/fmt-merge-msg.c:663
+#: builtin/fmt-merge-msg.c:669
msgid "populate log with at most <n> entries from shortlog"
msgstr ""
"вмъкване на журнал състоящ се от не повече от БРОЙ записа от съкратения "
"журнал"
-#: builtin/fmt-merge-msg.c:666
+#: builtin/fmt-merge-msg.c:672
msgid "alias for --log (deprecated)"
msgstr "синоним на „--log“ (остаряло)"
-#: builtin/fmt-merge-msg.c:669
+#: builtin/fmt-merge-msg.c:675
msgid "text"
msgstr "ТЕКСТ"
-#: builtin/fmt-merge-msg.c:670
+#: builtin/fmt-merge-msg.c:676
msgid "use <text> as start of message"
msgstr "за начало на съобщението да се ползва ТЕКСТ"
-#: builtin/fmt-merge-msg.c:671
+#: builtin/fmt-merge-msg.c:677
msgid "file to read from"
msgstr "файл, от който да се чете"
-#: builtin/for-each-ref.c:675
+#: builtin/for-each-ref.c:687
msgid "unable to parse format"
msgstr "форматът не може да бъде анализиран"
-#: builtin/for-each-ref.c:1063
+#: builtin/for-each-ref.c:1083
msgid "git for-each-ref [<options>] [<pattern>]"
msgstr "git for-each-ref [ОПЦИЯ…] [ШАБЛОН]"
-#: builtin/for-each-ref.c:1078
+#: builtin/for-each-ref.c:1098
msgid "quote placeholders suitably for shells"
msgstr "цитиране подходящо за командни интерпретатори на обвивката"
-#: builtin/for-each-ref.c:1080
+#: builtin/for-each-ref.c:1100
msgid "quote placeholders suitably for perl"
msgstr "цитиране подходящо за perl"
-#: builtin/for-each-ref.c:1082
+#: builtin/for-each-ref.c:1102
msgid "quote placeholders suitably for python"
msgstr "цитиране подходящо за python"
-#: builtin/for-each-ref.c:1084
+#: builtin/for-each-ref.c:1104
msgid "quote placeholders suitably for Tcl"
msgstr "цитиране подходящо за tcl"
-#: builtin/for-each-ref.c:1087
+#: builtin/for-each-ref.c:1107
msgid "show only <n> matched refs"
msgstr "извеждане само на този БРОЙ напаснати указатели"
-#: builtin/for-each-ref.c:1088 builtin/replace.c:438
+#: builtin/for-each-ref.c:1108 builtin/replace.c:438
msgid "format"
msgstr "ФОРМАТ"
-#: builtin/for-each-ref.c:1088
+#: builtin/for-each-ref.c:1108
msgid "format to use for the output"
msgstr "ФОРМАТ за изхода"
-#: builtin/for-each-ref.c:1089
+#: builtin/for-each-ref.c:1109
msgid "key"
msgstr "ключ"
-#: builtin/for-each-ref.c:1090
+#: builtin/for-each-ref.c:1110
msgid "field name to sort on"
msgstr "име на полето, по което да е подредбата"
@@ -5789,56 +5859,56 @@ msgstr "име на полето, по което да е подредбата"
msgid "Checking connectivity"
msgstr "Проверка на връзката"
-#: builtin/fsck.c:540
+#: builtin/fsck.c:548
msgid "Checking object directories"
msgstr "Проверка на директориите с обекти"
-#: builtin/fsck.c:603
+#: builtin/fsck.c:611
msgid "git fsck [<options>] [<object>...]"
msgstr "git fsck [ОПЦИЯ…] [ОБЕКТ…]"
-#: builtin/fsck.c:609
+#: builtin/fsck.c:617
msgid "show unreachable objects"
msgstr "показване на недостижимите обекти"
-#: builtin/fsck.c:610
+#: builtin/fsck.c:618
msgid "show dangling objects"
msgstr "показване на обектите извън клоните"
-#: builtin/fsck.c:611
+#: builtin/fsck.c:619
msgid "report tags"
msgstr "показване на етикетите"
-#: builtin/fsck.c:612
+#: builtin/fsck.c:620
msgid "report root nodes"
msgstr "показване на кореновите възли"
-#: builtin/fsck.c:613
+#: builtin/fsck.c:621
msgid "make index objects head nodes"
msgstr "задаване на обекти от индекса да са коренови"
# FIXME bad message
-#: builtin/fsck.c:614
+#: builtin/fsck.c:622
msgid "make reflogs head nodes (default)"
msgstr "проследяване на указателите от журнала като глави (стандартно)"
-#: builtin/fsck.c:615
+#: builtin/fsck.c:623
msgid "also consider packs and alternate objects"
msgstr "допълнително да се проверяват пакетите и алтернативните обекти"
-#: builtin/fsck.c:616
+#: builtin/fsck.c:624
msgid "enable more strict checking"
msgstr "по-строги проверки"
-#: builtin/fsck.c:618
+#: builtin/fsck.c:626
msgid "write dangling objects in .git/lost-found"
msgstr "запазване на обектите извън клоните в директорията „.git/lost-found“"
-#: builtin/fsck.c:619 builtin/prune.c:108
+#: builtin/fsck.c:627 builtin/prune.c:107
msgid "show progress"
msgstr "показване на напредъка"
-#: builtin/fsck.c:669
+#: builtin/fsck.c:677
msgid "Checking objects"
msgstr "Проверка на обектите"
@@ -5847,53 +5917,54 @@ msgstr "Проверка на обектите"
msgid "git gc [<options>]"
msgstr "git gc [ОПЦИЯ…]"
-#: builtin/gc.c:79
+#: builtin/gc.c:67
#, c-format
-msgid "Invalid gc.pruneexpire: '%s'"
-msgstr "Неправилна стойност за настройката „gc.pruneexpire“: %s"
+msgid "Invalid %s: '%s'"
+msgstr "Неправилен %s: „%s“"
-#: builtin/gc.c:107
+#: builtin/gc.c:112
#, c-format
msgid "insanely long object directory %.*s"
msgstr "прекалено дълга директория с обекти „%.*s“"
-#: builtin/gc.c:276
+#: builtin/gc.c:281
msgid "prune unreferenced objects"
msgstr "окастряне на обектите, към които нищо не сочи"
-#: builtin/gc.c:278
+#: builtin/gc.c:283
msgid "be more thorough (increased runtime)"
msgstr "изчерпателно търсене на боклука (за сметка на повече време работа)"
-#: builtin/gc.c:279
+#: builtin/gc.c:284
msgid "enable auto-gc mode"
msgstr "включване на автоматичното събиране на боклука (auto-gc)"
-#: builtin/gc.c:280
+#: builtin/gc.c:285
msgid "force running gc even if there may be another gc running"
msgstr ""
"изрично стартиране на събирането на боклука, дори и ако вече работи друго "
"събиране"
-#: builtin/gc.c:321
+#: builtin/gc.c:327
#, c-format
msgid "Auto packing the repository in background for optimum performance.\n"
msgstr ""
"Автоматично пакетиране на заден фон на хранилището за по-добра "
"производителност.\n"
-#: builtin/gc.c:323
+#: builtin/gc.c:329
#, c-format
msgid "Auto packing the repository for optimum performance.\n"
msgstr "Автоматично пакетиране на хранилището за по-добра производителност.\n"
-#: builtin/gc.c:324
+#: builtin/gc.c:330
#, c-format
msgid "See \"git help gc\" for manual housekeeping.\n"
msgstr ""
-"Вижте ръководството за повече информация как да изпълните „git help gc“.\n"
+"Погледнете ръководството за повече информация как да изпълните „git help "
+"gc“.\n"
-#: builtin/gc.c:342
+#: builtin/gc.c:348
#, c-format
msgid ""
"gc is already running on machine '%s' pid %<PRIuMAX> (use --force if not)"
@@ -5902,7 +5973,7 @@ msgstr ""
"процеса: %<PRIuMAX> (ако сте сигурни, че това не е вярно, това използвайте\n"
"опцията „--force“)"
-#: builtin/gc.c:364
+#: builtin/gc.c:376
msgid ""
"There are too many unreachable loose objects; run 'git prune' to remove them."
msgstr ""
@@ -6118,7 +6189,7 @@ msgstr ""
"позволяване на стартирането на grep(1) (текущият компилат пренебрегва тази "
"опция)"
-#: builtin/grep.c:741 builtin/show-ref.c:187
+#: builtin/grep.c:741 builtin/show-ref.c:189
msgid "show usage"
msgstr "извеждане на начина на употреба на командата"
@@ -6150,7 +6221,7 @@ msgstr ""
msgid "both --cached and trees are given."
msgstr "опцията „--cached“ е несъвместима със задаване на дърво."
-#: builtin/hash-object.c:82
+#: builtin/hash-object.c:80
msgid ""
"git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] "
"[--] <file>..."
@@ -6159,38 +6230,38 @@ msgstr ""
"ФАЙЛ…"
# FIXME - list of paths or path...
-#: builtin/hash-object.c:83
+#: builtin/hash-object.c:81
msgid "git hash-object --stdin-paths < <list-of-paths>"
msgstr "git hash-object --stdin-paths < ПЪТ…"
-#: builtin/hash-object.c:94 builtin/tag.c:612
+#: builtin/hash-object.c:92 builtin/tag.c:612
msgid "type"
msgstr "ВИД"
-#: builtin/hash-object.c:94
+#: builtin/hash-object.c:92
msgid "object type"
msgstr "вид на обекта"
-#: builtin/hash-object.c:95
+#: builtin/hash-object.c:93
msgid "write the object into the object database"
msgstr "записване на обекта в базата от данни за обектите"
-#: builtin/hash-object.c:97
+#: builtin/hash-object.c:95
msgid "read the object from stdin"
msgstr "изчитане на обекта от стандартния вход"
-#: builtin/hash-object.c:99
+#: builtin/hash-object.c:97
msgid "store file as is without filters"
msgstr "запазване на файла както е — без филтри"
-#: builtin/hash-object.c:100
+#: builtin/hash-object.c:98
msgid ""
"just hash any random garbage to create corrupt objects for debugging Git"
msgstr ""
"създаване и хеширане на произволни данни за повредени обекти за трасиране на "
"Git"
-#: builtin/hash-object.c:101
+#: builtin/hash-object.c:99
msgid "process file as it were from this path"
msgstr "обработване на файла все едно е с този път"
@@ -6321,281 +6392,281 @@ msgid "`git %s' is aliased to `%s'"
msgstr "„git %s“ е синоним на „%s“"
# FIXME merge with next?
-#: builtin/index-pack.c:150
+#: builtin/index-pack.c:151
#, c-format
msgid "unable to open %s"
msgstr "обектът „%s“ не може да бъде отворен"
-#: builtin/index-pack.c:200
+#: builtin/index-pack.c:201
#, c-format
msgid "object type mismatch at %s"
msgstr "неправилен вид на обекта „%s“"
-#: builtin/index-pack.c:220
+#: builtin/index-pack.c:221
#, c-format
msgid "did not receive expected object %s"
msgstr "очакваният обект „%s“ не бе получен"
-#: builtin/index-pack.c:223
+#: builtin/index-pack.c:224
#, c-format
msgid "object %s: expected type %s, found %s"
msgstr "неправилен вид на обекта „%s“: очакваше се „%s“, а бе получен „%s“"
-#: builtin/index-pack.c:265
+#: builtin/index-pack.c:266
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
msgstr[0] "не може да се запълни %d байт"
msgstr[1] "не може да се запълнят %d байта"
-#: builtin/index-pack.c:275
+#: builtin/index-pack.c:276
msgid "early EOF"
msgstr "неочакван край на файл"
-#: builtin/index-pack.c:276
+#: builtin/index-pack.c:277
msgid "read error on input"
msgstr "грешка при четене на входните данни"
-#: builtin/index-pack.c:288
+#: builtin/index-pack.c:289
msgid "used more bytes than were available"
msgstr "използвани са повече от наличните байтове"
-#: builtin/index-pack.c:295
+#: builtin/index-pack.c:296
msgid "pack too large for current definition of off_t"
msgstr "пакетният файл е прекалено голям за текущата стойност на типа „off_t“"
-#: builtin/index-pack.c:311
+#: builtin/index-pack.c:312
#, c-format
msgid "unable to create '%s'"
msgstr "пакетният файл „%s“ не може да бъде създаден"
-#: builtin/index-pack.c:316
+#: builtin/index-pack.c:317
#, c-format
msgid "cannot open packfile '%s'"
msgstr "пакетният файл „%s“ не може да бъде отворен"
-#: builtin/index-pack.c:330
+#: builtin/index-pack.c:331
msgid "pack signature mismatch"
msgstr "несъответствие в подписа към пакетния файл"
-#: builtin/index-pack.c:332
+#: builtin/index-pack.c:333
#, c-format
msgid "pack version %<PRIu32> unsupported"
msgstr "не се поддържа пакетиране вeрсия „%<PRIu32>“"
-#: builtin/index-pack.c:350
+#: builtin/index-pack.c:351
#, c-format
msgid "pack has bad object at offset %lu: %s"
msgstr "повреден обект в пакетния файл при отместване %lu: %s"
-#: builtin/index-pack.c:471
+#: builtin/index-pack.c:472
#, c-format
msgid "inflate returned %d"
msgstr "декомпресирането с „inflate“ върна %d"
-#: builtin/index-pack.c:520
+#: builtin/index-pack.c:521
msgid "offset value overflow for delta base object"
msgstr "стойността на отместването за обекта-разлика води до препълване"
-#: builtin/index-pack.c:528
+#: builtin/index-pack.c:529
msgid "delta base offset is out of bound"
msgstr "стойността на отместването за обекта-разлика е извън диапазона"
-#: builtin/index-pack.c:536
+#: builtin/index-pack.c:537
#, c-format
msgid "unknown object type %d"
msgstr "непознат вид обект %d"
-#: builtin/index-pack.c:567
+#: builtin/index-pack.c:568
msgid "cannot pread pack file"
msgstr "пакетният файл не може да бъде прочетен"
-#: builtin/index-pack.c:569
+#: builtin/index-pack.c:570
#, c-format
msgid "premature end of pack file, %lu byte missing"
msgid_plural "premature end of pack file, %lu bytes missing"
msgstr[0] "неочакван край на файл, липсва %lu байт"
msgstr[1] "неочакван край на файл, липсват %lu байта"
-#: builtin/index-pack.c:595
+#: builtin/index-pack.c:596
msgid "serious inflate inconsistency"
msgstr "сериозна грешка при декомпресиране с „inflate“"
-#: builtin/index-pack.c:686 builtin/index-pack.c:692 builtin/index-pack.c:715
-#: builtin/index-pack.c:749 builtin/index-pack.c:758
+#: builtin/index-pack.c:742 builtin/index-pack.c:748 builtin/index-pack.c:771
+#: builtin/index-pack.c:805 builtin/index-pack.c:814
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
msgstr ""
"СЪВПАДЕНИЕ НА СТОЙНОСТИТЕ ЗА СУМИТЕ ЗА SHA1: „%s“ НА ДВА РАЗЛИЧНИ ОБЕКТА!"
# FIXME merge with next?
-#: builtin/index-pack.c:689 builtin/pack-objects.c:162
+#: builtin/index-pack.c:745 builtin/pack-objects.c:162
#: builtin/pack-objects.c:254
#, c-format
msgid "unable to read %s"
msgstr "обектът „%s“ не може да бъде прочетен"
-#: builtin/index-pack.c:755
+#: builtin/index-pack.c:811
#, c-format
msgid "cannot read existing object %s"
msgstr "съществуващият обект „%s“ не може да бъде прочетен"
-#: builtin/index-pack.c:769
+#: builtin/index-pack.c:825
#, c-format
msgid "invalid blob object %s"
msgstr "неправилен обект BLOB „%s“"
# FIXME perhaps invalid object
-#: builtin/index-pack.c:783
+#: builtin/index-pack.c:839
#, c-format
msgid "invalid %s"
msgstr "неправилен обект „%s“"
-#: builtin/index-pack.c:787
+#: builtin/index-pack.c:843
msgid "Error in object"
msgstr "Грешка в обекта"
-#: builtin/index-pack.c:789
+#: builtin/index-pack.c:845
#, c-format
msgid "Not all child objects of %s are reachable"
msgstr "Някои обекти, наследници на „%s“, не могат да бъдат достигнати"
-#: builtin/index-pack.c:861 builtin/index-pack.c:890
+#: builtin/index-pack.c:917 builtin/index-pack.c:948
msgid "failed to apply delta"
msgstr "разликата не може да бъде приложена"
-#: builtin/index-pack.c:1055
+#: builtin/index-pack.c:1118
msgid "Receiving objects"
msgstr "Получаване на обекти"
-#: builtin/index-pack.c:1055
+#: builtin/index-pack.c:1118
msgid "Indexing objects"
msgstr "Индексиране на обекти"
-#: builtin/index-pack.c:1081
+#: builtin/index-pack.c:1150
msgid "pack is corrupted (SHA1 mismatch)"
msgstr "пакетният файл е повреден (нееднакви суми по SHA1)"
-#: builtin/index-pack.c:1086
+#: builtin/index-pack.c:1155
msgid "cannot fstat packfile"
msgstr "не може да се получи информация за пакетния файл с „fstat“"
-#: builtin/index-pack.c:1089
+#: builtin/index-pack.c:1158
msgid "pack has junk at the end"
msgstr "в края на пакетния файл има повредени данни"
# FIXME WTF message
-#: builtin/index-pack.c:1100
+#: builtin/index-pack.c:1169
msgid "confusion beyond insanity in parse_pack_objects()"
msgstr ""
"фатална грешка във функцията „parse_pack_objects“. Това е грешка в Git, "
"докладвайте я на разработчиците, като пратите е-писмо на адрес: „git@vger."
"kernel.org“."
-#: builtin/index-pack.c:1123
+#: builtin/index-pack.c:1194
msgid "Resolving deltas"
msgstr "Откриване на съответните разлики"
-#: builtin/index-pack.c:1133
+#: builtin/index-pack.c:1205
#, c-format
msgid "unable to create thread: %s"
msgstr "не може да се създаде нишка: %s"
# FIXME WTF message
-#: builtin/index-pack.c:1175
+#: builtin/index-pack.c:1247
msgid "confusion beyond insanity"
msgstr ""
"фатална грешка във функцията „conclude_pack“. Това е грешка в Git, "
"докладвайте я на разработчиците, като пратите е-писмо на адрес: „git@vger."
"kernel.org“."
-#: builtin/index-pack.c:1181
+#: builtin/index-pack.c:1253
#, c-format
msgid "completed with %d local objects"
msgstr "действието завърши с %d локални обекта"
-#: builtin/index-pack.c:1191
+#: builtin/index-pack.c:1263
#, c-format
msgid "Unexpected tail checksum for %s (disk corruption?)"
msgstr ""
"Неочаквана последваща сума за грешки за „%s“ (причината може да е грешка в "
"диска)"
-#: builtin/index-pack.c:1195
+#: builtin/index-pack.c:1267
#, c-format
msgid "pack has %d unresolved delta"
msgid_plural "pack has %d unresolved deltas"
msgstr[0] "в пакета има %d ненапасваща разлика"
msgstr[1] "в пакета има %d ненапасващи разлики"
-#: builtin/index-pack.c:1219
+#: builtin/index-pack.c:1291
#, c-format
msgid "unable to deflate appended object (%d)"
msgstr "добавеният обект не може да се компресира с „deflate“: %d"
-#: builtin/index-pack.c:1298
+#: builtin/index-pack.c:1367
#, c-format
msgid "local object %s is corrupt"
msgstr "локалният обект „%s“ е повреден"
-#: builtin/index-pack.c:1322
+#: builtin/index-pack.c:1391
msgid "error while closing pack file"
msgstr "грешка при затварянето на пакетния файл"
-#: builtin/index-pack.c:1335
+#: builtin/index-pack.c:1404
#, c-format
msgid "cannot write keep file '%s'"
msgstr ""
"грешка при записването на файла „%s“, осигуряващ запазване на директория"
-#: builtin/index-pack.c:1343
+#: builtin/index-pack.c:1412
#, c-format
msgid "cannot close written keep file '%s'"
msgstr ""
"грешка при затварянето на записания файл „%s“, осигуряващ запазване на "
"директория"
-#: builtin/index-pack.c:1356
+#: builtin/index-pack.c:1425
msgid "cannot store pack file"
msgstr "пакетният файл не може да бъде запазен"
-#: builtin/index-pack.c:1367
+#: builtin/index-pack.c:1436
msgid "cannot store index file"
msgstr "файлът за индекса не може да бъде съхранен"
-#: builtin/index-pack.c:1400
+#: builtin/index-pack.c:1469
#, c-format
msgid "bad pack.indexversion=%<PRIu32>"
msgstr "зададена е неправилна версия пакетиране: „pack.indexversion=%<PRIu32>“"
-#: builtin/index-pack.c:1406
+#: builtin/index-pack.c:1475
#, c-format
msgid "invalid number of threads specified (%d)"
msgstr "зададен е неправилен брой нишки: %d"
-#: builtin/index-pack.c:1410 builtin/index-pack.c:1589
+#: builtin/index-pack.c:1479 builtin/index-pack.c:1658
#, c-format
msgid "no threads support, ignoring %s"
msgstr "липсва поддръжка за нишки. „%s“ ще се пренебрегне"
-#: builtin/index-pack.c:1468
+#: builtin/index-pack.c:1537
#, c-format
msgid "Cannot open existing pack file '%s'"
msgstr "Съществуващият пакетен файл „%s“ не може да бъде отворен"
-#: builtin/index-pack.c:1470
+#: builtin/index-pack.c:1539
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
msgstr "Съществуващият индекс за пакетния файл „%s“ не може да бъде отворен"
-#: builtin/index-pack.c:1517
+#: builtin/index-pack.c:1586
#, c-format
msgid "non delta: %d object"
msgid_plural "non delta: %d objects"
msgstr[0] "%d обект не е разлика"
msgstr[1] "%d обекта не са разлика"
-#: builtin/index-pack.c:1524
+#: builtin/index-pack.c:1593
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
@@ -6603,26 +6674,26 @@ msgstr[0] "дължината на веригата е %d: %lu обект"
msgstr[1] "дължината на веригата е %d: %lu обекта"
# FIXME it is not the cwd it is the previous cwd
-#: builtin/index-pack.c:1553
+#: builtin/index-pack.c:1622
msgid "Cannot come back to cwd"
msgstr "Процесът не може да се върне към предишната работна директория"
-#: builtin/index-pack.c:1601 builtin/index-pack.c:1604
-#: builtin/index-pack.c:1616 builtin/index-pack.c:1620
+#: builtin/index-pack.c:1670 builtin/index-pack.c:1673
+#: builtin/index-pack.c:1685 builtin/index-pack.c:1689
#, c-format
msgid "bad %s"
msgstr "неправилна стойност „%s“"
-#: builtin/index-pack.c:1634
+#: builtin/index-pack.c:1703
msgid "--fix-thin cannot be used without --stdin"
msgstr "опцията „--fix-thin“ изисква „--stdin“"
-#: builtin/index-pack.c:1638 builtin/index-pack.c:1647
+#: builtin/index-pack.c:1707 builtin/index-pack.c:1716
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
msgstr "името на пакетния файл „%s“ не завършва на „.pack“"
-#: builtin/index-pack.c:1655
+#: builtin/index-pack.c:1724
msgid "--verify with no packfile name given"
msgstr "опцията „--verify“ изисква име на пакетен файл"
@@ -6695,22 +6766,22 @@ msgid "not copying templates of a wrong format version %d from '%s'"
msgstr ""
"шаблоните с неправилен номер на формата %d няма да бъдат копирани от „%s“"
-#: builtin/init-db.c:197
+#: builtin/init-db.c:211
#, c-format
msgid "insane git directory %s"
msgstr "твърде дълго име на директория на Git: „%s“"
-#: builtin/init-db.c:331 builtin/init-db.c:334
+#: builtin/init-db.c:343 builtin/init-db.c:346
#, c-format
msgid "%s already exists"
msgstr "Директорията „%s“ вече съществува"
-#: builtin/init-db.c:363
+#: builtin/init-db.c:374
#, c-format
msgid "unable to handle file type %d"
msgstr "файлове от вид %d не се поддържат"
-#: builtin/init-db.c:366
+#: builtin/init-db.c:377
#, c-format
msgid "unable to move %s to %s"
msgstr "„%s“ не може да се премести в „%s“"
@@ -6718,24 +6789,24 @@ msgstr "„%s“ не може да се премести в „%s“"
#. TRANSLATORS: The first '%s' is either "Reinitialized
#. existing" or "Initialized empty", the second " shared" or
#. "", and the last '%s%s' is the verbatim directory name.
-#: builtin/init-db.c:426
+#: builtin/init-db.c:433
#, c-format
msgid "%s%s Git repository in %s%s\n"
msgstr "%s%s хранилище на Git в „%s%s“\n"
-#: builtin/init-db.c:427
+#: builtin/init-db.c:434
msgid "Reinitialized existing"
msgstr "Наново инициализирано, съществуващо"
-#: builtin/init-db.c:427
+#: builtin/init-db.c:434
msgid "Initialized empty"
msgstr "Инициализирано празно"
-#: builtin/init-db.c:428
+#: builtin/init-db.c:435
msgid " shared"
msgstr ", споделено"
-#: builtin/init-db.c:475
+#: builtin/init-db.c:482
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--"
"shared[=<permissions>]] [<directory>]"
@@ -6743,31 +6814,31 @@ msgstr ""
"git init [-q | --quiet] [--bare] [--template=ДИРЕКТОРИЯ_С_ШАБЛОНИ] [--"
"shared[=ПРАВА]] [ДИРЕКТОРИЯ]"
-#: builtin/init-db.c:498
+#: builtin/init-db.c:505
msgid "permissions"
msgstr "права"
-#: builtin/init-db.c:499
+#: builtin/init-db.c:506
msgid "specify that the git repository is to be shared amongst several users"
msgstr ""
"указване, че хранилището на Git ще бъде споделено от повече от един "
"потребител"
-#: builtin/init-db.c:501 builtin/prune-packed.c:57 builtin/repack.c:171
+#: builtin/init-db.c:508 builtin/prune-packed.c:57 builtin/repack.c:171
msgid "be quiet"
msgstr "без извеждане на информация"
-#: builtin/init-db.c:533 builtin/init-db.c:538
+#: builtin/init-db.c:540 builtin/init-db.c:545
#, c-format
msgid "cannot mkdir %s"
msgstr "директорията „%s“ не може да бъде създадена"
-#: builtin/init-db.c:542
+#: builtin/init-db.c:549
#, c-format
msgid "cannot chdir to %s"
msgstr "не може да се влезе в директорията „%s“"
-#: builtin/init-db.c:563
+#: builtin/init-db.c:570
#, c-format
msgid ""
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
@@ -6776,7 +6847,7 @@ msgstr ""
"%s (или --work-tree=ДИРЕКТОРИЯ) изисква указването на %s (или --git-"
"dir=ДИРЕКТОРИЯ)"
-#: builtin/init-db.c:591
+#: builtin/init-db.c:598
#, c-format
msgid "Cannot access work tree '%s'"
msgstr "Работното дърво в „%s“ е недостъпно"
@@ -6802,7 +6873,7 @@ msgid "trailer(s) to add"
msgstr "епилог(зи) за добавяне"
#: builtin/log.c:41
-msgid "git log [<options>] [<revision range>] [[--] <path>...]"
+msgid "git log [<options>] [<revision-range>] [[--] <path>...]"
msgstr "git log [ОПЦИЯ…] [ДИАПАЗОН_НА_ВЕРСИИТЕ] [[--] ПЪТ…]"
#: builtin/log.c:42
@@ -6875,7 +6946,7 @@ msgstr "Файлът-кръпка „%s“ не може да бъде отво
msgid "Need exactly one range."
msgstr "Трябва да зададете точно един диапазон."
-#: builtin/log.c:811
+#: builtin/log.c:813
msgid "Not a range."
msgstr "Не е диапазон."
@@ -7085,7 +7156,7 @@ msgstr "Изходните файлове не могат да бъдат съз
msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
msgstr "git cherry [-v] [ОТДАЛЕЧЕН_КЛОН [ВРЪХ [ПРЕДЕЛ]]]"
-#: builtin/log.c:1638
+#: builtin/log.c:1637
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
@@ -7093,7 +7164,7 @@ msgstr ""
"Следеният отдалечен клон не бе открит, затова изрично задайте "
"ОТДАЛЕЧЕН_КЛОН.\n"
-#: builtin/log.c:1651 builtin/log.c:1653 builtin/log.c:1665
+#: builtin/log.c:1648 builtin/log.c:1650 builtin/log.c:1662
#, c-format
msgid "Unknown commit %s"
msgstr "Непознато подаване „%s“"
@@ -7374,42 +7445,42 @@ msgstr ""
msgid "'%s' does not point to a commit"
msgstr "„%s“ не сочи към подаване"
-#: builtin/merge.c:559
+#: builtin/merge.c:537
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
msgstr "Неправилен низ за настройката „branch.%s.mergeoptions“: „%s“"
-#: builtin/merge.c:654
+#: builtin/merge.c:632
msgid "git write-tree failed to write a tree"
msgstr "Командата „git write-tree“ не успя да запише обект-дърво"
-#: builtin/merge.c:678
+#: builtin/merge.c:656
msgid "Not handling anything other than two heads merge."
msgstr "Поддържа се само сливане на точно две истории."
-#: builtin/merge.c:692
+#: builtin/merge.c:670
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
msgstr "Непозната опция за рекурсивното сливане „merge-recursive“: „-X%s“"
-#: builtin/merge.c:705
+#: builtin/merge.c:683
#, c-format
msgid "unable to write %s"
msgstr "„%s“ не може да бъде записан"
-#: builtin/merge.c:794
+#: builtin/merge.c:772
#, c-format
msgid "Could not read from '%s'"
msgstr "От „%s“ не може да се чете"
-#: builtin/merge.c:803
+#: builtin/merge.c:781
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
"Сливането няма да бъде подадено. За завършването му и подаването му "
"използвайте командата „git commit“.\n"
-#: builtin/merge.c:809
+#: builtin/merge.c:787
#, c-format
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
@@ -7424,50 +7495,55 @@ msgstr ""
"Редовете, които започват с „%c“ ще бъдат пропуснати, а празно съобщение\n"
"преустановява подаването.\n"
-#: builtin/merge.c:833
+#: builtin/merge.c:811
msgid "Empty commit message."
msgstr "Празно съобщение при подаване."
# FIXME - WTF is wonderful.
-#: builtin/merge.c:845
+#: builtin/merge.c:823
#, c-format
msgid "Wonderful.\n"
msgstr "Първият етап на тривиалното сливане завърши.\n"
-#: builtin/merge.c:900
+#: builtin/merge.c:878
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr "Неуспешно сливане — коригирайте конфликтите и подайте резултата.\n"
-#: builtin/merge.c:916
+#: builtin/merge.c:894
#, c-format
msgid "'%s' is not a commit"
msgstr "„%s“ не е подаване"
-#: builtin/merge.c:957
+#: builtin/merge.c:935
msgid "No current branch."
msgstr "Няма текущ клон."
-#: builtin/merge.c:959
+#: builtin/merge.c:937
msgid "No remote for the current branch."
msgstr "Текущият клон не следи никой."
-#: builtin/merge.c:961
+#: builtin/merge.c:939
msgid "No default upstream defined for the current branch."
msgstr "Текущият клон не следи никой клон."
-#: builtin/merge.c:966
+#: builtin/merge.c:944
#, c-format
msgid "No remote-tracking branch for %s from %s"
msgstr "Никой клон не следи клона „%s“ от хранилището „%s“"
-#: builtin/merge.c:1122
+#: builtin/merge.c:1081
+#, c-format
+msgid "could not close '%s'"
+msgstr "„%s“ не може да се затвори"
+
+#: builtin/merge.c:1208
msgid "There is no merge to abort (MERGE_HEAD missing)."
msgstr ""
"Не може да преустановите сливане, защото в момента не се извършва такова "
"(липсва указател „MERGE_HEAD“)."
-#: builtin/merge.c:1138
+#: builtin/merge.c:1224
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you merge."
@@ -7475,11 +7551,11 @@ msgstr ""
"Не сте завършили сливане. (Указателят „MERGE_HEAD“ съществува).\n"
"Подайте промените си, преди да започнете ново сливане."
-#: builtin/merge.c:1141 git-pull.sh:34
+#: builtin/merge.c:1227 git-pull.sh:74
msgid "You have not concluded your merge (MERGE_HEAD exists)."
msgstr "Не сте завършили сливане. (Указателят „MERGE_HEAD“ съществува)."
-#: builtin/merge.c:1145
+#: builtin/merge.c:1231
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge."
@@ -7487,111 +7563,111 @@ msgstr ""
"Не сте завършили отбиране на подаване (указателят „CHERRY_PICK_HEAD“\n"
"съществува). Подайте промените си, преди да започнете ново сливане."
-#: builtin/merge.c:1148
+#: builtin/merge.c:1234
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
msgstr ""
"Не сте завършили отбиране на подаване (указателят „CHERRY_PICK_HEAD“\n"
"съществува)."
-#: builtin/merge.c:1157
+#: builtin/merge.c:1243
msgid "You cannot combine --squash with --no-ff."
msgstr "Опцията „--squash“ е несъвместима с „--no-ff“."
-#: builtin/merge.c:1166
+#: builtin/merge.c:1251
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr ""
"Не е указано подаване и настройката „merge.defaultToUpstream“ не е зададена."
-#: builtin/merge.c:1198
-msgid "Can merge only exactly one commit into empty head"
-msgstr "Можете да слеете точно едно подаване във връх без история"
-
-#: builtin/merge.c:1201
+#: builtin/merge.c:1268
msgid "Squash commit into empty head not supported yet"
msgstr "Подаване със смачкване във връх без история все още не се поддържа"
-#: builtin/merge.c:1203
+#: builtin/merge.c:1270
msgid "Non-fast-forward commit does not make sense into an empty head"
msgstr ""
"Понеже върхът е без история, всички сливания са тривиални, не може да се "
"извърши нетривиално сливане изисквано от опцията „--no-ff“"
-#: builtin/merge.c:1208
+#: builtin/merge.c:1276
#, c-format
msgid "%s - not something we can merge"
msgstr "„%s“ — не е нещо, което може да се слее"
-#: builtin/merge.c:1259
+#: builtin/merge.c:1278
+msgid "Can merge only exactly one commit into empty head"
+msgstr "Можете да слеете точно едно подаване във връх без история"
+
+#: builtin/merge.c:1333
#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
msgstr ""
"Подаването „%s“ е с недоверен подпис от GPG, който твърди, че е на „%s“."
-#: builtin/merge.c:1262
+#: builtin/merge.c:1336
#, c-format
msgid "Commit %s has a bad GPG signature allegedly by %s."
msgstr ""
"Подаването „%s“ е с неправилен подпис от GPG, който твърди, че е на „%s“."
-#: builtin/merge.c:1265
+#: builtin/merge.c:1339
#, c-format
msgid "Commit %s does not have a GPG signature."
msgstr "Подаването „%s“ е без подпис от GPG."
-#: builtin/merge.c:1268
+#: builtin/merge.c:1342
#, c-format
msgid "Commit %s has a good GPG signature by %s\n"
msgstr "Подаването „%s“ е с коректен подпис от GPG на „%s“.\n"
-#: builtin/merge.c:1349
+#: builtin/merge.c:1423
#, c-format
msgid "Updating %s..%s\n"
msgstr "Обновяване „%s..%s“\n"
-#: builtin/merge.c:1388
+#: builtin/merge.c:1462
#, c-format
msgid "Trying really trivial in-index merge...\n"
msgstr "Проба с най-тривиалното сливане в рамките на индекса…\n"
# FIXME WTF message
-#: builtin/merge.c:1395
+#: builtin/merge.c:1469
#, c-format
msgid "Nope.\n"
msgstr "Неуспешно сливане.\n"
-#: builtin/merge.c:1427
+#: builtin/merge.c:1501
msgid "Not possible to fast-forward, aborting."
msgstr ""
"Не може да се извърши тривиално сливане, преустановяване на действието."
-#: builtin/merge.c:1450 builtin/merge.c:1529
+#: builtin/merge.c:1524 builtin/merge.c:1603
#, c-format
msgid "Rewinding the tree to pristine...\n"
msgstr "Привеждане на дървото към първоначалното…\n"
-#: builtin/merge.c:1454
+#: builtin/merge.c:1528
#, c-format
msgid "Trying merge strategy %s...\n"
msgstr "Пробване със стратегията за сливане „%s“…\n"
-#: builtin/merge.c:1520
+#: builtin/merge.c:1594
#, c-format
msgid "No merge strategy handled the merge.\n"
msgstr "Никоя стратегия за сливане не може да извърши сливането.\n"
-#: builtin/merge.c:1522
+#: builtin/merge.c:1596
#, c-format
msgid "Merge with strategy %s failed.\n"
msgstr "Неуспешно сливане със стратегия „%s“.\n"
-#: builtin/merge.c:1531
+#: builtin/merge.c:1605
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
msgstr ""
"Ползва се стратегията „%s“, която ще подготви дървото за коригиране на "
"ръка.\n"
-#: builtin/merge.c:1543
+#: builtin/merge.c:1617
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
@@ -7786,7 +7862,7 @@ msgstr "%s, обект: „%s“, цел: „%s“"
msgid "Renaming %s to %s\n"
msgstr "Преименуване на „%s“ на „%s“\n"
-#: builtin/mv.c:256 builtin/remote.c:728 builtin/repack.c:359
+#: builtin/mv.c:256 builtin/remote.c:725 builtin/repack.c:361
#, c-format
msgid "renaming '%s' failed"
msgstr "неуспешно преименуване на „%s“"
@@ -8173,7 +8249,7 @@ msgstr "УКАЗАТЕЛ_ЗА_БЕЛЕЖКА"
msgid "use notes from <notes-ref>"
msgstr "да се използва бележката сочена от този УКАЗАТЕЛ_ЗА_БЕЛЕЖКА"
-#: builtin/notes.c:989 builtin/remote.c:1621
+#: builtin/notes.c:989 builtin/remote.c:1618
#, c-format
msgid "Unknown subcommand: %s"
msgstr "Непозната подкоманда: %s"
@@ -8199,187 +8275,187 @@ msgstr "грешка при декомпресиране с „deflate“ (%d)"
msgid "Writing objects"
msgstr "Записване на обектите"
-#: builtin/pack-objects.c:1013
+#: builtin/pack-objects.c:1011
msgid "disabling bitmap writing, as some objects are not being packed"
msgstr ""
"изключване на записването на битовата маска, защото някои обекти няма да се "
"пакетират"
-#: builtin/pack-objects.c:2173
+#: builtin/pack-objects.c:2171
msgid "Compressing objects"
msgstr "Компресиране на обектите"
-#: builtin/pack-objects.c:2570
+#: builtin/pack-objects.c:2568
#, c-format
msgid "unsupported index version %s"
msgstr "неподдържана версия на индекса „%s“"
-#: builtin/pack-objects.c:2574
+#: builtin/pack-objects.c:2572
#, c-format
msgid "bad index version '%s'"
msgstr "неправилна версия на индекса „%s“"
-#: builtin/pack-objects.c:2597
+#: builtin/pack-objects.c:2595
#, c-format
msgid "option %s does not accept negative form"
msgstr "опцията „%s“ не притежава отрицателна версия"
-#: builtin/pack-objects.c:2601
+#: builtin/pack-objects.c:2599
#, c-format
msgid "unable to parse value '%s' for option %s"
msgstr "неразпозната стойност „%s“ за опцията „%s“"
-#: builtin/pack-objects.c:2621
+#: builtin/pack-objects.c:2619
msgid "do not show progress meter"
msgstr "без извеждане на напредъка"
-#: builtin/pack-objects.c:2623
+#: builtin/pack-objects.c:2621
msgid "show progress meter"
msgstr "извеждане на напредъка"
-#: builtin/pack-objects.c:2625
+#: builtin/pack-objects.c:2623
msgid "show progress meter during object writing phase"
msgstr "извеждане на напредъка във фазата на запазване на обектите"
-#: builtin/pack-objects.c:2628
+#: builtin/pack-objects.c:2626
msgid "similar to --all-progress when progress meter is shown"
msgstr ""
"същото действие като опцията „--all-progress“ при извеждането на напредъка"
-#: builtin/pack-objects.c:2629
+#: builtin/pack-objects.c:2627
msgid "version[,offset]"
msgstr "ВЕРСИЯ[,ОТМЕСТВАНЕ]"
-#: builtin/pack-objects.c:2630
+#: builtin/pack-objects.c:2628
msgid "write the pack index file in the specified idx format version"
msgstr ""
"запазване на индекса на пакетните файлове във форма̀та с указаната версия"
-#: builtin/pack-objects.c:2633
+#: builtin/pack-objects.c:2631
msgid "maximum size of each output pack file"
msgstr "максимален размер на всеки пакетен файл"
-#: builtin/pack-objects.c:2635
+#: builtin/pack-objects.c:2633
msgid "ignore borrowed objects from alternate object store"
msgstr "игнориране на обектите заети от други хранилища на обекти"
-#: builtin/pack-objects.c:2637
+#: builtin/pack-objects.c:2635
msgid "ignore packed objects"
msgstr "игнориране на пакетираните обекти"
-#: builtin/pack-objects.c:2639
+#: builtin/pack-objects.c:2637
msgid "limit pack window by objects"
msgstr "ограничаване на прозореца за пакетиране по брой обекти"
-#: builtin/pack-objects.c:2641
+#: builtin/pack-objects.c:2639
msgid "limit pack window by memory in addition to object limit"
msgstr ""
"ограничаване на прозореца за пакетиране и по памет освен по брой обекти"
-#: builtin/pack-objects.c:2643
+#: builtin/pack-objects.c:2641
msgid "maximum length of delta chain allowed in the resulting pack"
msgstr ""
"максимална дължина на веригата от разлики, която е позволена в пакетния файл"
-#: builtin/pack-objects.c:2645
+#: builtin/pack-objects.c:2643
msgid "reuse existing deltas"
msgstr "преизползване на съществуващите разлики"
-#: builtin/pack-objects.c:2647
+#: builtin/pack-objects.c:2645
msgid "reuse existing objects"
msgstr "преизползване на съществуващите обекти"
-#: builtin/pack-objects.c:2649
+#: builtin/pack-objects.c:2647
msgid "use OFS_DELTA objects"
msgstr "използване на обекти „OFS_DELTA“"
-#: builtin/pack-objects.c:2651
+#: builtin/pack-objects.c:2649
msgid "use threads when searching for best delta matches"
msgstr ""
"стартиране на нишки за претърсване на най-добрите съвпадения на разликите"
-#: builtin/pack-objects.c:2653
+#: builtin/pack-objects.c:2651
msgid "do not create an empty pack output"
msgstr "без създаване на празен пакетен файл"
-#: builtin/pack-objects.c:2655
+#: builtin/pack-objects.c:2653
msgid "read revision arguments from standard input"
msgstr "изчитане на версиите от стандартния вход"
-#: builtin/pack-objects.c:2657
+#: builtin/pack-objects.c:2655
msgid "limit the objects to those that are not yet packed"
msgstr "ограничаване до все още непакетираните обекти"
-#: builtin/pack-objects.c:2660
+#: builtin/pack-objects.c:2658
msgid "include objects reachable from any reference"
msgstr ""
"включване на всички обекти, които могат да се достигнат от произволен "
"указател"
-#: builtin/pack-objects.c:2663
+#: builtin/pack-objects.c:2661
msgid "include objects referred by reflog entries"
msgstr "включване и на обектите сочени от записите в журнала на указателите"
-#: builtin/pack-objects.c:2666
+#: builtin/pack-objects.c:2664
msgid "include objects referred to by the index"
msgstr "включване и на обектите сочени от индекса"
-#: builtin/pack-objects.c:2669
+#: builtin/pack-objects.c:2667
msgid "output pack to stdout"
msgstr "извеждане на пакета на стандартния изход"
-#: builtin/pack-objects.c:2671
+#: builtin/pack-objects.c:2669
msgid "include tag objects that refer to objects to be packed"
msgstr ""
"включване и на обектите-етикети, които сочат към обектите, които ще бъдат "
"пакетирани"
-#: builtin/pack-objects.c:2673
+#: builtin/pack-objects.c:2671
msgid "keep unreachable objects"
msgstr "запазване на недостижимите обекти"
-#: builtin/pack-objects.c:2674 parse-options.h:140
+#: builtin/pack-objects.c:2672 parse-options.h:139
msgid "time"
msgstr "ВРЕМЕ"
-#: builtin/pack-objects.c:2675
+#: builtin/pack-objects.c:2673
msgid "unpack unreachable objects newer than <time>"
msgstr "разпакетиране на недостижимите обекти, които са по-нови от това ВРЕМЕ"
-#: builtin/pack-objects.c:2678
+#: builtin/pack-objects.c:2676
msgid "create thin packs"
msgstr "създаване на съкратени пакети"
-#: builtin/pack-objects.c:2680
+#: builtin/pack-objects.c:2678
msgid "create packs suitable for shallow fetches"
msgstr "пакетиране подходящо за плитко доставяне"
-#: builtin/pack-objects.c:2682
+#: builtin/pack-objects.c:2680
msgid "ignore packs that have companion .keep file"
msgstr "игнориране на пакетите, които са придружени от файл „.keep“"
-#: builtin/pack-objects.c:2684
+#: builtin/pack-objects.c:2682
msgid "pack compression level"
msgstr "ниво на компресиране при пакетиране"
-#: builtin/pack-objects.c:2686
+#: builtin/pack-objects.c:2684
msgid "do not hide commits by grafts"
msgstr ""
"извеждане на всички родители — дори и тези, които нормално са скрити при "
"присажданията"
-#: builtin/pack-objects.c:2688
+#: builtin/pack-objects.c:2686
msgid "use a bitmap index if available to speed up counting objects"
msgstr ""
"използване на съществуващи индекси на база битови маски за ускоряване на "
"преброяването на обектите"
-#: builtin/pack-objects.c:2690
+#: builtin/pack-objects.c:2688
msgid "write a bitmap index together with the pack index"
msgstr ""
"запазване и на индекс на база побитова маска, заедно с индекса за пакета"
-#: builtin/pack-objects.c:2781
+#: builtin/pack-objects.c:2779
msgid "Counting objects"
msgstr "Преброяване на обектите"
@@ -8403,19 +8479,19 @@ msgstr "git prune-packed [-n | --dry-run] [-q | --quiet]"
msgid "Removing duplicate objects"
msgstr "Изтриване на повтарящите се обекти"
-#: builtin/prune.c:12
+#: builtin/prune.c:11
msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
msgstr "git prune [-n] [-v] [--expire ВРЕМЕ] [--] [ВРЪХ…]"
-#: builtin/prune.c:106
+#: builtin/prune.c:105 builtin/worktree.c:112
msgid "do not remove, show only"
msgstr "само извеждане без действително окастряне"
-#: builtin/prune.c:107
+#: builtin/prune.c:106 builtin/worktree.c:113
msgid "report pruned objects"
msgstr "информация за окастрените обекти"
-#: builtin/prune.c:110
+#: builtin/prune.c:109 builtin/worktree.c:115
msgid "expire objects older than <time>"
msgstr "окастряне на обектите по-стари от това ВРЕМЕ"
@@ -8437,8 +8513,8 @@ msgid ""
"To choose either option permanently, see push.default in 'git help config'."
msgstr ""
"\n"
-"За да включите тази опция за постоянно, вижте документацията за настройката "
-"„push.default“ в „git help config“."
+"За да включите тази опция за постоянно, погледнете документацията за "
+"настройката „push.default“ в „git help config“."
#: builtin/push.c:142
#, c-format
@@ -8596,7 +8672,7 @@ msgstr ""
"Обновяването е отхвърлено, защото върхът на изтласквания клон е преди върха\n"
"на отдалечения клон. Проверете клона и внесете отдалечените промени (напр.\n"
"с командата „git pull…“), преди отново да изтласкате промените. За повече\n"
-"информация вижте раздела „Note about fast-forwards“ в страницата от\n"
+"информация погледнете раздела „Note about fast-forwards“ в страницата от\n"
"ръководството „git push --help“."
#: builtin/push.c:291
@@ -8614,9 +8690,9 @@ msgstr ""
"че някой друг е изтласквал към същия клон. Първо внесете отдалечените "
"промени\n"
"(напр. с командата „git pull…“), преди отново да изтласкате промените.\n"
-"За повече информация вижте раздела „Note about fast-forwards“ в страницата "
-"от\n"
-"ръководството „git push --help“."
+"За повече информация погледнете раздела „Note about fast-forwards“ в "
+"страницата\n"
+"от ръководството „git push --help“."
#: builtin/push.c:298
msgid "Updates were rejected because the tag already exists in the remote."
@@ -8848,12 +8924,12 @@ msgid "debug unpack-trees"
msgstr "изчистване на грешки в командата „unpack-trees“"
# FIXME
-#: builtin/reflog.c:429
+#: builtin/reflog.c:430
#, c-format
msgid "%s' for '%s' is not a valid timestamp"
msgstr "„%s“ не е правилна стойност за време за „%s“"
-#: builtin/reflog.c:546 builtin/reflog.c:551
+#: builtin/reflog.c:547 builtin/reflog.c:552
#, c-format
msgid "'%s' is not a valid timestamp"
msgstr "„%s“ не е правилна стойност за време"
@@ -8996,12 +9072,12 @@ msgstr ""
"указването на следени клони е смислено само за отдалечени хранилища, от "
"които се доставя"
-#: builtin/remote.c:187 builtin/remote.c:643
+#: builtin/remote.c:187 builtin/remote.c:640
#, c-format
msgid "remote %s already exists."
msgstr "вече съществува отдалечено хранилище с име „%s“."
-#: builtin/remote.c:191 builtin/remote.c:647
+#: builtin/remote.c:191 builtin/remote.c:644
#, c-format
msgid "'%s' is not a valid remote name"
msgstr "„%s“ е неправилно име за отдалечено хранилище"
@@ -9024,28 +9100,28 @@ msgstr "(съвпадащи)"
msgid "(delete)"
msgstr "(за изтриване)"
-#: builtin/remote.c:592 builtin/remote.c:598 builtin/remote.c:604
+#: builtin/remote.c:589 builtin/remote.c:595 builtin/remote.c:601
#, c-format
msgid "Could not append '%s' to '%s'"
msgstr "„%s“ не може да се добави към „%s“"
-#: builtin/remote.c:636 builtin/remote.c:795 builtin/remote.c:895
+#: builtin/remote.c:633 builtin/remote.c:792 builtin/remote.c:892
#, c-format
msgid "No such remote: %s"
msgstr "Такова отдалечено хранилище няма: %s"
-#: builtin/remote.c:653
+#: builtin/remote.c:650
#, c-format
msgid "Could not rename config section '%s' to '%s'"
msgstr "Разделът „%s“ в настройките не може да бъде преименуван на „%s“"
-#: builtin/remote.c:659 builtin/remote.c:847
+#: builtin/remote.c:656 builtin/remote.c:844
#, c-format
msgid "Could not remove config section '%s'"
msgstr "Разделът „%s“ в настройките не може да бъде изтрит"
# FIXME tabulator
-#: builtin/remote.c:674
+#: builtin/remote.c:671
#, c-format
msgid ""
"Not updating non-default fetch refspec\n"
@@ -9056,32 +9132,32 @@ msgstr ""
" %s\n"
" Променете настройките ръчно, ако е необходимо."
-#: builtin/remote.c:680
+#: builtin/remote.c:677
#, c-format
msgid "Could not append '%s'"
msgstr "Разделът „%s“ не може да бъде добавен в настройките"
-#: builtin/remote.c:691
+#: builtin/remote.c:688
#, c-format
msgid "Could not set '%s'"
msgstr "Разделът „%s“ не може да бъде зададен в настройките"
-#: builtin/remote.c:713
+#: builtin/remote.c:710
#, c-format
msgid "deleting '%s' failed"
msgstr "неуспешно изтриване на „%s“"
-#: builtin/remote.c:747
+#: builtin/remote.c:744
#, c-format
msgid "creating '%s' failed"
msgstr "неуспешно създаване на „%s“"
-#: builtin/remote.c:766
+#: builtin/remote.c:763
#, c-format
msgid "Could not remove branch %s"
msgstr "Клонът „%s“ не може да бъде изтрит"
-#: builtin/remote.c:833
+#: builtin/remote.c:830
msgid ""
"Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
"to delete it, use:"
@@ -9095,125 +9171,125 @@ msgstr[1] ""
"Бележка: Няколко клона извън йерархията „refs/remotes/“ не бяха изтрити.\n"
"Изтрийте ги чрез командата:"
-#: builtin/remote.c:948
+#: builtin/remote.c:945
#, c-format
msgid " new (next fetch will store in remotes/%s)"
msgstr " нов (следващото доставяне ще го разположи в „remotes/%s“)"
-#: builtin/remote.c:951
+#: builtin/remote.c:948
msgid " tracked"
msgstr " следен"
-#: builtin/remote.c:953
+#: builtin/remote.c:950
msgid " stale (use 'git remote prune' to remove)"
msgstr " стар (изтрийте чрез „git remote prune“)"
# FIXME
-#: builtin/remote.c:955
+#: builtin/remote.c:952
msgid " ???"
msgstr " неясно състояние"
# CHECK
-#: builtin/remote.c:996
+#: builtin/remote.c:993
#, c-format
msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
msgstr ""
"неправилен клон за сливане „%s“. Невъзможно е да пребазирате върху повече от "
"1 клон"
-#: builtin/remote.c:1003
+#: builtin/remote.c:1000
#, c-format
msgid "rebases onto remote %s"
msgstr "пребазиране върху отдалечения клон „%s“"
-#: builtin/remote.c:1006
+#: builtin/remote.c:1003
#, c-format
msgid " merges with remote %s"
msgstr " сливане с отдалечения клон „%s“"
-#: builtin/remote.c:1007
+#: builtin/remote.c:1004
msgid " and with remote"
msgstr " и с отдалечения клон"
-#: builtin/remote.c:1009
+#: builtin/remote.c:1006
#, c-format
msgid "merges with remote %s"
msgstr "сливане с отдалечения клон „%s“"
-#: builtin/remote.c:1010
+#: builtin/remote.c:1007
msgid " and with remote"
msgstr " и с отдалечения клон"
-#: builtin/remote.c:1056
+#: builtin/remote.c:1053
msgid "create"
msgstr "създаден"
-#: builtin/remote.c:1059
+#: builtin/remote.c:1056
msgid "delete"
msgstr "изтрит"
-#: builtin/remote.c:1063
+#: builtin/remote.c:1060
msgid "up to date"
msgstr "актуален"
-#: builtin/remote.c:1066
+#: builtin/remote.c:1063
msgid "fast-forwardable"
msgstr "може да се слее тривиално"
-#: builtin/remote.c:1069
+#: builtin/remote.c:1066
msgid "local out of date"
msgstr "локалният е изостанал"
-#: builtin/remote.c:1076
+#: builtin/remote.c:1073
#, c-format
msgid " %-*s forces to %-*s (%s)"
msgstr " %-*s принудително изтласква към %-*s (%s)"
-#: builtin/remote.c:1079
+#: builtin/remote.c:1076
#, c-format
msgid " %-*s pushes to %-*s (%s)"
msgstr " %-*s изтласква към %-*s (%s)"
-#: builtin/remote.c:1083
+#: builtin/remote.c:1080
#, c-format
msgid " %-*s forces to %s"
msgstr " %-*s принудително изтласква към %s"
-#: builtin/remote.c:1086
+#: builtin/remote.c:1083
#, c-format
msgid " %-*s pushes to %s"
msgstr " %-*s изтласква към %s"
-#: builtin/remote.c:1154
+#: builtin/remote.c:1151
msgid "do not query remotes"
msgstr "без заявки към отдалечените хранилища"
-#: builtin/remote.c:1181
+#: builtin/remote.c:1178
#, c-format
msgid "* remote %s"
msgstr "● отдалечено хранилище „%s“"
-#: builtin/remote.c:1182
+#: builtin/remote.c:1179
#, c-format
msgid " Fetch URL: %s"
msgstr " Адрес за доставяне: %s"
-#: builtin/remote.c:1183 builtin/remote.c:1334
+#: builtin/remote.c:1180 builtin/remote.c:1331
msgid "(no URL)"
msgstr "(без адрес)"
# FIXME spaces betwen Push and URL
-#: builtin/remote.c:1192 builtin/remote.c:1194
+#: builtin/remote.c:1189 builtin/remote.c:1191
#, c-format
msgid " Push URL: %s"
msgstr " Адрес за изтласкване: %s"
-#: builtin/remote.c:1196 builtin/remote.c:1198 builtin/remote.c:1200
+#: builtin/remote.c:1193 builtin/remote.c:1195 builtin/remote.c:1197
#, c-format
msgid " HEAD branch: %s"
msgstr " клон сочен от HEAD: %s"
-#: builtin/remote.c:1202
+#: builtin/remote.c:1199
#, c-format
msgid ""
" HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
@@ -9222,146 +9298,146 @@ msgstr ""
"хранилище е\n"
" нееднозначен и е някой от следните):\n"
-#: builtin/remote.c:1214
+#: builtin/remote.c:1211
#, c-format
msgid " Remote branch:%s"
msgid_plural " Remote branches:%s"
msgstr[0] " Отдалечен клон:%s"
msgstr[1] " Отдалечени клони:%s"
-#: builtin/remote.c:1217 builtin/remote.c:1244
+#: builtin/remote.c:1214 builtin/remote.c:1241
msgid " (status not queried)"
msgstr " (състоянието не бе проверено)"
-#: builtin/remote.c:1226
+#: builtin/remote.c:1223
msgid " Local branch configured for 'git pull':"
msgid_plural " Local branches configured for 'git pull':"
msgstr[0] " Локален клон настроен за издърпване чрез „git pull“:"
msgstr[1] " Локални клони настроени за издърпване чрез „git pull“:"
-#: builtin/remote.c:1234
+#: builtin/remote.c:1231
msgid " Local refs will be mirrored by 'git push'"
msgstr " Локалните указатели ще бъдат пренесени чрез „ push“"
-#: builtin/remote.c:1241
+#: builtin/remote.c:1238
#, c-format
msgid " Local ref configured for 'git push'%s:"
msgid_plural " Local refs configured for 'git push'%s:"
msgstr[0] " Локалният указател, настроен за „git push“%s:"
msgstr[1] " Локалните указатели, настроени за „git push“%s:"
-#: builtin/remote.c:1262
+#: builtin/remote.c:1259
msgid "set refs/remotes/<name>/HEAD according to remote"
msgstr "задаване на refs/remotes/ИМЕ/HEAD според отдалеченото хранилище"
-#: builtin/remote.c:1264
+#: builtin/remote.c:1261
msgid "delete refs/remotes/<name>/HEAD"
msgstr "изтриване на refs/remotes/ИМЕ/HEAD"
-#: builtin/remote.c:1279
+#: builtin/remote.c:1276
msgid "Cannot determine remote HEAD"
msgstr "Не може да се установи отдалеченият връх"
-#: builtin/remote.c:1281
+#: builtin/remote.c:1278
msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
msgstr ""
"Множество клони с върхове. Изберете изрично някой от тях чрез командата:"
-#: builtin/remote.c:1291
+#: builtin/remote.c:1288
#, c-format
msgid "Could not delete %s"
msgstr "„%s“ не може да бъде изтрит"
-#: builtin/remote.c:1299
+#: builtin/remote.c:1296
#, c-format
msgid "Not a valid ref: %s"
msgstr "Неправилен указател: %s"
-#: builtin/remote.c:1301
+#: builtin/remote.c:1298
#, c-format
msgid "Could not setup %s"
msgstr "„%s“ не може да се настрои"
-#: builtin/remote.c:1319
+#: builtin/remote.c:1316
#, c-format
msgid " %s will become dangling!"
msgstr "„%s“ ще се превърне в обект извън клоните!"
-#: builtin/remote.c:1320
+#: builtin/remote.c:1317
#, c-format
msgid " %s has become dangling!"
msgstr "„%s“ се превърна в обект извън клоните!"
-#: builtin/remote.c:1330
+#: builtin/remote.c:1327
#, c-format
msgid "Pruning %s"
msgstr "Окастряне на „%s“"
-#: builtin/remote.c:1331
+#: builtin/remote.c:1328
#, c-format
msgid "URL: %s"
msgstr "адрес: %s"
-#: builtin/remote.c:1354
+#: builtin/remote.c:1351
#, c-format
msgid " * [would prune] %s"
msgstr " ● [ще бъде окастрено] %s"
-#: builtin/remote.c:1357
+#: builtin/remote.c:1354
#, c-format
msgid " * [pruned] %s"
msgstr " ● [окастрено] %s"
-#: builtin/remote.c:1402
+#: builtin/remote.c:1399
msgid "prune remotes after fetching"
msgstr "окастряне на огледалата на отдалечените хранилища след доставяне"
-#: builtin/remote.c:1468 builtin/remote.c:1542
+#: builtin/remote.c:1465 builtin/remote.c:1539
#, c-format
msgid "No such remote '%s'"
msgstr "Няма отдалечено хранилище на име „%s“"
-#: builtin/remote.c:1488
+#: builtin/remote.c:1485
msgid "add branch"
msgstr "добавяне на клон"
-#: builtin/remote.c:1495
+#: builtin/remote.c:1492
msgid "no remote specified"
msgstr "не е указано отдалечено хранилище"
-#: builtin/remote.c:1517
+#: builtin/remote.c:1514
msgid "manipulate push URLs"
msgstr "промяна на адресите за изтласкване"
-#: builtin/remote.c:1519
+#: builtin/remote.c:1516
msgid "add URL"
msgstr "добавяне на адреси"
-#: builtin/remote.c:1521
+#: builtin/remote.c:1518
msgid "delete URLs"
msgstr "изтриване на адреси"
# FIXME message - incompatible
-#: builtin/remote.c:1528
+#: builtin/remote.c:1525
msgid "--add --delete doesn't make sense"
msgstr "опциите „--add“ и „--delete“ са несъвместими"
-#: builtin/remote.c:1568
+#: builtin/remote.c:1565
#, c-format
msgid "Invalid old URL pattern: %s"
msgstr "Неправилен (стар) формат за адрес: %s"
-#: builtin/remote.c:1576
+#: builtin/remote.c:1573
#, c-format
msgid "No such URL found: %s"
msgstr "Такъв адрес не е открит: %s"
# FIXME CHECK MEANING
-#: builtin/remote.c:1578
+#: builtin/remote.c:1575
msgid "Will not delete all non-push URLs"
msgstr "Никой от адресите, които не са за изтласкване, няма да се изтрие"
-#: builtin/remote.c:1592
+#: builtin/remote.c:1589
msgid "be verbose; must be placed before a subcommand"
msgstr "повече подробности. Поставя се пред подкоманда"
@@ -9442,7 +9518,7 @@ msgstr "максимален размер на всеки пакет"
msgid "repack objects in packs marked with .keep"
msgstr "препакетиране на обектите в пакети белязани с „.keep“"
-#: builtin/repack.c:375
+#: builtin/repack.c:377
#, c-format
msgid "removing '%s' failed"
msgstr "неуспешно изтриване на „%s“"
@@ -9826,7 +9902,7 @@ msgstr ""
"\n"
"(ако искате да ги изтриете заедно с цялата им история, използвайте „rm -rf“)"
-#: builtin/rm.c:231
+#: builtin/rm.c:230
msgid ""
"the following file has staged content different from both the\n"
"file and the HEAD:"
@@ -9842,7 +9918,7 @@ msgstr[1] ""
"съдържание и\n"
"различно от съответстващото на HEAD:"
-#: builtin/rm.c:236
+#: builtin/rm.c:235
msgid ""
"\n"
"(use -f to force removal)"
@@ -9850,13 +9926,13 @@ msgstr ""
"\n"
"(за принудително изтриване използвайте опцията „-f“)"
-#: builtin/rm.c:240
+#: builtin/rm.c:239
msgid "the following file has changes staged in the index:"
msgid_plural "the following files have changes staged in the index:"
msgstr[0] "следният файл е с променено съдържание в индекса:"
msgstr[1] "следните файлове са с променено съдържание в индекса:"
-#: builtin/rm.c:244 builtin/rm.c:255
+#: builtin/rm.c:243 builtin/rm.c:254
msgid ""
"\n"
"(use --cached to keep the file, or -f to force removal)"
@@ -9865,46 +9941,46 @@ msgstr ""
"(за запазване на файла използвайте опцията „--cached“, а за принудително\n"
"изтриване — „-f“)"
-#: builtin/rm.c:252
+#: builtin/rm.c:251
msgid "the following file has local modifications:"
msgid_plural "the following files have local modifications:"
msgstr[0] "следният файл е с променено съдържание"
msgstr[1] "следните файлове са с променено съдържание"
-#: builtin/rm.c:270
+#: builtin/rm.c:269
msgid "do not list removed files"
msgstr "да не се извеждат изтритите файлове"
-#: builtin/rm.c:271
+#: builtin/rm.c:270
msgid "only remove from the index"
msgstr "изтриване само от индекса"
-#: builtin/rm.c:272
+#: builtin/rm.c:271
msgid "override the up-to-date check"
msgstr "въпреки проверката за актуалността на съдържанието"
-#: builtin/rm.c:273
+#: builtin/rm.c:272
msgid "allow recursive removal"
msgstr "рекурсивно изтриване"
-#: builtin/rm.c:275
+#: builtin/rm.c:274
msgid "exit with a zero status even if nothing matched"
msgstr ""
"изходният код да е 0, дори ако никой файл нe e напаснал с шаблона за "
"изтриване"
-#: builtin/rm.c:318
+#: builtin/rm.c:317
msgid "Please, stage your changes to .gitmodules or stash them to proceed"
msgstr ""
"За да продължите, или вкарайте промените по файла „.gitmodules“ в индекса,\n"
"или ги скатайте"
-#: builtin/rm.c:336
+#: builtin/rm.c:335
#, c-format
msgid "not removing '%s' recursively without -r"
msgstr "без използването на опцията „-r“ „%s“ няма да се изтрие рекурсивно"
-#: builtin/rm.c:375
+#: builtin/rm.c:374
#, c-format
msgid "git rm: unable to remove %s"
msgstr "git rm: „%s“ не може да се изтрие"
@@ -9957,69 +10033,69 @@ msgstr ""
msgid "git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"
msgstr "git show-branch (-g | --reflog)[=БРОЙ[,БАЗА]] [--list] [УКАЗАТЕЛ]"
-#: builtin/show-branch.c:652
+#: builtin/show-branch.c:659
msgid "show remote-tracking and local branches"
msgstr "извеждане на следящите и локалните клони"
-#: builtin/show-branch.c:654
+#: builtin/show-branch.c:661
msgid "show remote-tracking branches"
msgstr "извеждане на следящите клони"
-#: builtin/show-branch.c:656
+#: builtin/show-branch.c:663
msgid "color '*!+-' corresponding to the branch"
msgstr "оцветяване на „*!+-“ според клоните"
-#: builtin/show-branch.c:658
+#: builtin/show-branch.c:665
msgid "show <n> more commits after the common ancestor"
msgstr "извеждане на такъв БРОЙ подавания от общия предшественик"
-#: builtin/show-branch.c:660
+#: builtin/show-branch.c:667
msgid "synonym to more=-1"
msgstr "синоним на „more=-1“"
-#: builtin/show-branch.c:661
+#: builtin/show-branch.c:668
msgid "suppress naming strings"
msgstr "без низове за имената на клоните"
-#: builtin/show-branch.c:663
+#: builtin/show-branch.c:670
msgid "include the current branch"
msgstr "включване и на текущия клон"
-#: builtin/show-branch.c:665
+#: builtin/show-branch.c:672
msgid "name commits with their object names"
msgstr "именуване на подаванията с имената им на обекти"
-#: builtin/show-branch.c:667
+#: builtin/show-branch.c:674
msgid "show possible merge bases"
msgstr "извеждане на възможните бази за сливания"
-#: builtin/show-branch.c:669
+#: builtin/show-branch.c:676
msgid "show refs unreachable from any other ref"
msgstr "извеждане на недостижимите указатели"
-#: builtin/show-branch.c:671
+#: builtin/show-branch.c:678
msgid "show commits in topological order"
msgstr "извеждане на подаванията в топологическа подредба"
-#: builtin/show-branch.c:674
+#: builtin/show-branch.c:681
msgid "show only commits not on the first branch"
msgstr "извеждане само на подаванията, които не са от първия клон"
-#: builtin/show-branch.c:676
+#: builtin/show-branch.c:683
msgid "show merges reachable from only one tip"
msgstr "извеждане на сливанията, които могат да се достигнат само от един връх"
-#: builtin/show-branch.c:678
+#: builtin/show-branch.c:685
msgid "topologically sort, maintaining date order where possible"
msgstr ""
"топологическа подредба, при запазване на подредбата по дата, доколкото е\n"
"възможно"
-#: builtin/show-branch.c:681
+#: builtin/show-branch.c:688
msgid "<n>[,<base>]"
msgstr "БРОЙ[,БАЗА]"
-#: builtin/show-branch.c:682
+#: builtin/show-branch.c:689
msgid "show <n> most recent ref-log entries starting at base"
msgstr "показване на най-много БРОЙ журнални записа с начало съответната БАЗА"
@@ -10037,37 +10113,37 @@ msgstr ""
msgid "git show-ref --exclude-existing[=pattern] < ref-list"
msgstr "git show-ref --exclude-existing[=ШАБЛОН] < СПИСЪК_С_УКАЗАТЕЛИ"
-#: builtin/show-ref.c:168
+#: builtin/show-ref.c:170
msgid "only show tags (can be combined with heads)"
msgstr "извеждане на етикетите (може да се комбинира с върховете)"
-#: builtin/show-ref.c:169
+#: builtin/show-ref.c:171
msgid "only show heads (can be combined with tags)"
msgstr "извеждане на върховете (може да се комбинира с етикетите)"
-#: builtin/show-ref.c:170
+#: builtin/show-ref.c:172
msgid "stricter reference checking, requires exact ref path"
msgstr "строга проверка на указателите, изисква се указател с пълен път"
-#: builtin/show-ref.c:173 builtin/show-ref.c:175
+#: builtin/show-ref.c:175 builtin/show-ref.c:177
msgid "show the HEAD reference, even if it would be filtered out"
msgstr "задължително извеждане и на указателя HEAD"
-#: builtin/show-ref.c:177
+#: builtin/show-ref.c:179
msgid "dereference tags into object IDs"
msgstr "да се извеждат идентификаторите на обектите-етикети"
-#: builtin/show-ref.c:179
+#: builtin/show-ref.c:181
msgid "only show SHA1 hash using <n> digits"
msgstr "извеждане само на този БРОЙ цифри от всяка сума по SHA1"
-#: builtin/show-ref.c:183
+#: builtin/show-ref.c:185
msgid "do not print results to stdout (useful with --verify)"
msgstr ""
"без извеждане на резултатите на стандартния вход (полезно с опцията „--"
"verify“)"
-#: builtin/show-ref.c:185
+#: builtin/show-ref.c:187
msgid "show refs from stdin that aren't in local repository"
msgstr ""
"извеждане на указателите приети от стандартния вход, които липсват в "
@@ -10333,131 +10409,210 @@ msgstr "Обновен етикет „%s“ (бе „%s“)\n"
msgid "Unpacking objects"
msgstr "Разпакетиране на обектите"
-#: builtin/update-index.c:403
+#: builtin/update-index.c:70
+#, c-format
+msgid "failed to create directory %s"
+msgstr "директорията „%s“ не може да бъде създадена"
+
+#: builtin/update-index.c:76
+#, c-format
+msgid "failed to stat %s"
+msgstr "не може да бъде получена информация чрез „stat“ за „%s“"
+
+#: builtin/update-index.c:86
+#, c-format
+msgid "failed to create file %s"
+msgstr "файлът „%s“ не може да бъде създаден"
+
+#: builtin/update-index.c:94
+#, c-format
+msgid "failed to delete file %s"
+msgstr "файлът „%s“ не може да бъде изтрит"
+
+#: builtin/update-index.c:101 builtin/update-index.c:203
+#, c-format
+msgid "failed to delete directory %s"
+msgstr "директорията „%s“ не може да бъде изтрита"
+
+#: builtin/update-index.c:124
+#, c-format
+msgid "Testing "
+msgstr "Проба"
+
+#: builtin/update-index.c:136
+msgid "directory stat info does not change after adding a new file"
+msgstr ""
+"информацията получена чрез „stat“ за директорията не се променя след "
+"добавянето на нов файл"
+
+#: builtin/update-index.c:149
+msgid "directory stat info does not change after adding a new directory"
+msgstr ""
+"информацията получена чрез „stat“ за директорията не се променя след "
+"добавянето на нова директория"
+
+#: builtin/update-index.c:162
+msgid "directory stat info changes after updating a file"
+msgstr ""
+"информацията получена чрез „stat“ за директорията се променя след "
+"обновяването на нов файл"
+
+#: builtin/update-index.c:173
+msgid "directory stat info changes after adding a file inside subdirectory"
+msgstr ""
+"информацията получена чрез „stat“ за директорията се променя след добавянето "
+"на файл в поддиректория"
+
+#: builtin/update-index.c:184
+msgid "directory stat info does not change after deleting a file"
+msgstr ""
+"информацията получена чрез „stat“ за директорията не се променя след "
+"изтриването на файл"
+
+#: builtin/update-index.c:197
+msgid "directory stat info does not change after deleting a directory"
+msgstr ""
+"информацията получена чрез „stat“ за директорията не се променя след "
+"изтриването на директория"
+
+#: builtin/update-index.c:204
+msgid " OK"
+msgstr " Добре"
+
+#: builtin/update-index.c:564
msgid "git update-index [<options>] [--] [<file>...]"
msgstr "git update-index [ОПЦИЯ…] [--] [ФАЙЛ…]"
-#: builtin/update-index.c:757
+#: builtin/update-index.c:918
msgid "continue refresh even when index needs update"
msgstr ""
"продължаване с обновяването, дори когато индексът трябва да бъде обновен"
-#: builtin/update-index.c:760
+#: builtin/update-index.c:921
msgid "refresh: ignore submodules"
msgstr "подмодулите да се игнорират при обновяването"
-#: builtin/update-index.c:763
+#: builtin/update-index.c:924
msgid "do not ignore new files"
msgstr "новите файлове да не се игнорират"
-#: builtin/update-index.c:765
+#: builtin/update-index.c:926
msgid "let files replace directories and vice-versa"
msgstr "файлове да могат да заменят директории и обратно"
-#: builtin/update-index.c:767
+#: builtin/update-index.c:928
msgid "notice files missing from worktree"
msgstr "предупреждаване при липсващи в работното дърво файлове"
-#: builtin/update-index.c:769
+#: builtin/update-index.c:930
msgid "refresh even if index contains unmerged entries"
msgstr "обновяване дори и индексът да съдържа неслети обекти"
-#: builtin/update-index.c:772
+#: builtin/update-index.c:933
msgid "refresh stat information"
msgstr "обновяване на информацията от функцията „stat“"
-#: builtin/update-index.c:776
+#: builtin/update-index.c:937
msgid "like --refresh, but ignore assume-unchanged setting"
msgstr ""
"като опцията „--refresh“, но да се проверят и обектите, които са били приети "
"за непроменени"
-#: builtin/update-index.c:780
+#: builtin/update-index.c:941
msgid "<mode>,<object>,<path>"
msgstr "РЕЖИМ,ОБЕКТ,ПЪТ"
-#: builtin/update-index.c:781
+#: builtin/update-index.c:942
msgid "add the specified entry to the index"
msgstr "добавяне на изброените обекти към индекса"
-#: builtin/update-index.c:785
+#: builtin/update-index.c:946
msgid "(+/-)x"
msgstr "(+/-)x"
-#: builtin/update-index.c:786
+#: builtin/update-index.c:947
msgid "override the executable bit of the listed files"
msgstr "изрично задаване на стойността на флага дали файлът е изпълним"
-#: builtin/update-index.c:790
+#: builtin/update-index.c:951
msgid "mark files as \"not changing\""
msgstr "задаване на флаг, че файлът не се променя"
-#: builtin/update-index.c:793
+#: builtin/update-index.c:954
msgid "clear assumed-unchanged bit"
msgstr "изчистване на флага, че файлът не се променя"
-#: builtin/update-index.c:796
+#: builtin/update-index.c:957
msgid "mark files as \"index-only\""
msgstr "задаване на флаг, че файловете са само за индекса"
-#: builtin/update-index.c:799
+#: builtin/update-index.c:960
msgid "clear skip-worktree bit"
msgstr "изчистване на флага, че файловете са само за индекса"
-#: builtin/update-index.c:802
+#: builtin/update-index.c:963
msgid "add to index only; do not add content to object database"
msgstr "добавяне само към индекса без добавяне към базата от данни за обектите"
-#: builtin/update-index.c:804
+#: builtin/update-index.c:965
msgid "remove named paths even if present in worktree"
msgstr "изтриване на указаните пътища, дори и да съществуват в работното дърво"
-#: builtin/update-index.c:806
+#: builtin/update-index.c:967
msgid "with --stdin: input lines are terminated by null bytes"
msgstr ""
"при комбиниране с опцията „--stdin“ — входните редове са разделени с нулевия "
"байт"
-#: builtin/update-index.c:808
+#: builtin/update-index.c:969
msgid "read list of paths to be updated from standard input"
msgstr "изчитане на списъка с пътища за обновяване от стандартния вход"
-#: builtin/update-index.c:812
+#: builtin/update-index.c:973
msgid "add entries from standard input to the index"
msgstr "добавяне на елементите от стандартния вход към индекса"
-#: builtin/update-index.c:816
+#: builtin/update-index.c:977
msgid "repopulate stages #2 and #3 for the listed paths"
msgstr ""
"възстановяване на състоянието преди сливане или нужда от обновяване за "
"изброените пътища"
-#: builtin/update-index.c:820
+#: builtin/update-index.c:981
msgid "only update entries that differ from HEAD"
msgstr "добавяне само на съдържанието, което се различава от това в „HEAD“"
-#: builtin/update-index.c:824
+#: builtin/update-index.c:985
msgid "ignore files missing from worktree"
msgstr "игнориране на файловете, които липсват в работното дърво"
-#: builtin/update-index.c:827
+#: builtin/update-index.c:988
msgid "report actions to standard output"
msgstr "извеждане на действията на стандартния изход"
-#: builtin/update-index.c:829
+#: builtin/update-index.c:990
msgid "(for porcelains) forget saved unresolved conflicts"
msgstr ""
"забравяне на записаната информация за неразрешени конфликти — за командите "
"от потребителско ниво"
-#: builtin/update-index.c:833
+#: builtin/update-index.c:994
msgid "write index in this format"
msgstr "записване на индекса в този формат"
-#: builtin/update-index.c:835
+#: builtin/update-index.c:996
msgid "enable or disable split index"
msgstr "включване или изключване на разделянето на индекса"
+#: builtin/update-index.c:998
+msgid "enable/disable untracked cache"
+msgstr "включване/изключване на кеша за неследените файлове"
+
+#: builtin/update-index.c:1000
+msgid "enable untracked cache without testing the filesystem"
+msgstr ""
+"включване на кеша за неследените файлове без проверка на файловата система"
+
#: builtin/update-ref.c:9
msgid "git update-ref [<options>] -d <refname> [<old-val>]"
msgstr "git update-ref [ОПЦИЯ…] -d ИМЕ_НА_УКАЗАТЕЛ [СТАРА_СТОЙНОСТ]"
@@ -10525,6 +10680,86 @@ msgstr "git verify-tag [-v | --verbose] ЕТИКЕТ…"
msgid "print tag contents"
msgstr "извеждане на съдържанието на ЕТИКЕТи"
+#: builtin/worktree.c:11
+msgid "git worktree add [<options>] <path> <branch>"
+msgstr "git worktree add [ОПЦИЯ…] ПЪТ КЛОН"
+
+#: builtin/worktree.c:12
+msgid "git worktree prune [<options>]"
+msgstr "git worktree prune [ОПЦИЯ…]"
+
+#: builtin/worktree.c:27
+#, c-format
+msgid "Removing worktrees/%s: not a valid directory"
+msgstr "Изтриване на „worktrees/%s“: не е правилна поддиректория"
+
+#: builtin/worktree.c:33
+#, c-format
+msgid "Removing worktrees/%s: gitdir file does not exist"
+msgstr "Изтриване на „worktrees/%s“: файлът „gitdir“ не съществува"
+
+#: builtin/worktree.c:38
+#, c-format
+msgid "Removing worktrees/%s: unable to read gitdir file (%s)"
+msgstr ""
+"Изтриване на „worktrees/%s“: файлът „gitdir“ (%s) не може да бъде прочетен"
+
+#: builtin/worktree.c:49
+#, c-format
+msgid "Removing worktrees/%s: invalid gitdir file"
+msgstr "Изтриване на „worktrees/%s“: неправилен файл „gitdir“"
+
+#: builtin/worktree.c:65
+#, c-format
+msgid "Removing worktrees/%s: gitdir file points to non-existent location"
+msgstr ""
+"Изтриване на „worktrees/%s“: файлът „gitdir“ сочи несъществуващо "
+"местоположение"
+
+#: builtin/worktree.c:100
+#, c-format
+msgid "failed to remove: %s"
+msgstr "„%s“ не може да се изтрие"
+
+#: builtin/worktree.c:186
+#, c-format
+msgid "'%s' already exists"
+msgstr "„%s“ вече съществува"
+
+#: builtin/worktree.c:207
+#, c-format
+msgid "could not create directory of '%s'"
+msgstr "директорията „%s“ не може да бъде създадена"
+
+#: builtin/worktree.c:241
+msgid "unable to resolve HEAD"
+msgstr "соченото от указателя „HEAD“ не може да бъде открито"
+
+#: builtin/worktree.c:249
+#, c-format
+msgid "Enter %s (identifier %s)"
+msgstr "Въведете %s (идентификатор %s)"
+
+#: builtin/worktree.c:281
+msgid "checkout <branch> even if already checked out in other worktree"
+msgstr "Изтегляне КЛОНа, дори и да е изтеглен в друго работно дърво"
+
+#: builtin/worktree.c:283
+msgid "create a new branch"
+msgstr "създаване на нов клон"
+
+#: builtin/worktree.c:285
+msgid "create or reset a branch"
+msgstr "създаване или зануляване на клони"
+
+#: builtin/worktree.c:286
+msgid "detach HEAD at named commit"
+msgstr "отделяне на указателя „HEAD“ към указаното подаване"
+
+#: builtin/worktree.c:292
+msgid "-b and -B are mutually exclusive"
+msgstr "опциите „-b“ и „-B“ са несъвместими"
+
#: builtin/write-tree.c:13
msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
msgstr "git write-tree [--missing-ok] [--prefix=ПРЕФИКС/]"
@@ -10557,110 +10792,131 @@ msgstr ""
"за\n"
"някое определено ПОНЯТИЕ използвайте „git help ПОНЯТИЕ“."
-#: common-cmds.h:8
+#: common-cmds.h:10
+msgid "start a working area (see also: git help tutorial)"
+msgstr "създаване на работно дърво (погледнете: „git help tutorial“)"
+
+#: common-cmds.h:11
+msgid "work on the current change (see also: git help everyday)"
+msgstr "работа по текущата промяна (погледнете: „git help everyday“)"
+
+#: common-cmds.h:12
+msgid "examine the history and state (see also: git help revisions)"
+msgstr "преглед на историята и състоянието (погледнете: „git help revisions“)"
+
+#: common-cmds.h:13
+msgid "grow, mark and tweak your common history"
+msgstr "увеличаване, отбелязване и промяна на общата история"
+
+#: common-cmds.h:14
+msgid "collaborate (see also: git help workflows)"
+msgstr "съвместна работа (погледнете: „git help workflows“)"
+
+#: common-cmds.h:18
msgid "Add file contents to the index"
msgstr "Добавяне на съдържанието на файла към индекса"
-#: common-cmds.h:9
+#: common-cmds.h:19
msgid "Find by binary search the change that introduced a bug"
msgstr "Двоично търсене на промяната, която е причинила грешка"
# FIXME - should be similar to tag
-#: common-cmds.h:10
+#: common-cmds.h:20
msgid "List, create, or delete branches"
msgstr "Извеждане, създаване, изтриване на клони"
-#: common-cmds.h:11
-msgid "Checkout a branch or paths to the working tree"
-msgstr "Изтегляне на цял клон или файлове/директории в работното дърво"
+#: common-cmds.h:21
+msgid "Switch branches or restore working tree files"
+msgstr ""
+"Преминаване към друг клон или възстановяване на файловете в работното дърво"
-#: common-cmds.h:12
+#: common-cmds.h:22
msgid "Clone a repository into a new directory"
msgstr "Клониране на хранилище в нова директория"
-#: common-cmds.h:13
+#: common-cmds.h:23
msgid "Record changes to the repository"
msgstr "Подаване на промени в хранилището"
-#: common-cmds.h:14
+#: common-cmds.h:24
msgid "Show changes between commits, commit and working tree, etc"
msgstr "Извеждане на разликите между подаванията, версиите, работното дърво"
-#: common-cmds.h:15
+#: common-cmds.h:25
msgid "Download objects and refs from another repository"
msgstr "Изтегляне на обекти и указатели от друго хранилище"
-#: common-cmds.h:16
+#: common-cmds.h:26
msgid "Print lines matching a pattern"
msgstr "Извеждане на редовете напасващи на шаблон"
-#: common-cmds.h:17
+#: common-cmds.h:27
msgid "Create an empty Git repository or reinitialize an existing one"
msgstr "Създаване на празно хранилище на Git или зануляване на съществуващо"
-#: common-cmds.h:18
+#: common-cmds.h:28
msgid "Show commit logs"
msgstr "Извеждане на журнала с подаванията"
-#: common-cmds.h:19
+#: common-cmds.h:29
msgid "Join two or more development histories together"
msgstr "Сливане на две или повече поредици/истории от промени"
-#: common-cmds.h:20
+#: common-cmds.h:30
msgid "Move or rename a file, a directory, or a symlink"
msgstr "Преместване или преименуване на файл, директория или символна връзка"
-#: common-cmds.h:21
+#: common-cmds.h:31
msgid "Fetch from and integrate with another repository or a local branch"
msgstr "Доставяне и интегрирането на промените от друго хранилище или клон"
-#: common-cmds.h:22
+#: common-cmds.h:32
msgid "Update remote refs along with associated objects"
msgstr "Обновяване на отдалечените указатели и свързаните с тях обекти"
-#: common-cmds.h:23
+#: common-cmds.h:33
msgid "Forward-port local commits to the updated upstream head"
msgstr "Пребазиране на промени към нова основа"
-#: common-cmds.h:24
+#: common-cmds.h:34
msgid "Reset current HEAD to the specified state"
msgstr "Привеждане на указателя „HEAD“ към зададеното състояние"
-#: common-cmds.h:25
+#: common-cmds.h:35
msgid "Remove files from the working tree and from the index"
msgstr "Изтриване на файлове от работното дърво и индекса"
-#: common-cmds.h:26
+#: common-cmds.h:36
msgid "Show various types of objects"
msgstr "Извеждане на различните видове обекти в Git"
-#: common-cmds.h:27
+#: common-cmds.h:37
msgid "Show the working tree status"
msgstr "Извеждане на състоянието на работното дърво"
# FIXME - should be similar to branch
-#: common-cmds.h:28
+#: common-cmds.h:38
msgid "Create, list, delete or verify a tag object signed with GPG"
msgstr "Извеждане, създаване, изтриване, проверка на етикети подписани с GPG"
-#: parse-options.h:143
+#: parse-options.h:142
msgid "expiry-date"
msgstr "период на валидност/запазване"
-#: parse-options.h:158
+#: parse-options.h:157
msgid "no-op (backward compatibility)"
msgstr "нулева операция (за съвместимост с предишни версии)"
-#: parse-options.h:232
+#: parse-options.h:231
msgid "be more verbose"
msgstr "повече подробности"
-#: parse-options.h:234
+#: parse-options.h:233
msgid "be more quiet"
msgstr "по-малко подробности"
# FIXME SHA-1 -> SHA1
-#: parse-options.h:240
+#: parse-options.h:239
msgid "use <n> digits to display SHA-1s"
msgstr "да се показват такъв БРОЙ цифри от сумите по SHA1"
@@ -10674,7 +10930,7 @@ msgstr ""
msgid "You need to set your committer info first"
msgstr "Първо трябва да зададете информация за себе си"
-#: git-am.sh:98
+#: git-am.sh:100
msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"
@@ -10685,7 +10941,7 @@ msgstr ""
"към\n"
"„ORIG_HEAD“"
-#: git-am.sh:108
+#: git-am.sh:110
#, sh-format
msgid ""
"When you have resolved this problem, run \"$cmdline --continue\".\n"
@@ -10699,21 +10955,21 @@ msgstr ""
"на \n"
"кръпки, изпълнете командата „$cmdline --abort“."
-#: git-am.sh:124
+#: git-am.sh:126
msgid "Cannot fall back to three-way merge."
msgstr "Не може да се премине към тройно сливане."
-#: git-am.sh:140
+#: git-am.sh:142