Git development
 help / color / mirror / Atom feed
* [PATCH] request-pull: explicitly ask tags/$name to be pulled
From: Junio C Hamano @ 2012-02-01  5:50 UTC (permalink / raw)
  To: git; +Cc: Mark Brown

When asking for a tag to be pulled, disambiguate by leaving tags/ prefix
in front of the name of the tag. E.g.

    ... in the git repository at:

      git://example.com/git/git.git/ tags/v1.2.3

    for you to fetch changes up to 123456...

This way, older versions of "git pull" can be used to respond to such a
request more easily, as "git pull $URL v1.2.3" did not DWIM to fetch
v1.2.3 tag in older versions. Also this makes it clearer for humans that
the pull request is made for a tag and he should anticipate a signed one.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---

 * http://thread.gmane.org/gmane.linux.kernel/1245709/focus=1245909
   triggered this

 .../howto/using-signed-tag-in-pull-request.txt     |    4 ++--
 git-request-pull.sh                                |    2 +-
 t/t5150-request-pull.sh                            |    6 +-----
 3 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/Documentation/howto/using-signed-tag-in-pull-request.txt b/Documentation/howto/using-signed-tag-in-pull-request.txt
index a1351c5..98c0033 100644
--- a/Documentation/howto/using-signed-tag-in-pull-request.txt
+++ b/Documentation/howto/using-signed-tag-in-pull-request.txt
@@ -109,7 +109,7 @@ The resulting msg.txt file begins like so:
 
  are available in the git repository at:
 
-   example.com:/git/froboz.git frotz-for-xyzzy
+   example.com:/git/froboz.git tags/frotz-for-xyzzy
 
  for you to fetch changes up to 703f05ad5835c...:
 
@@ -141,7 +141,7 @@ After receiving such a pull request message, the integrator fetches and
 integrates the tag named in the request, with:
 
 ------------
- $ git pull example.com:/git/froboz.git/ frotz-for-xyzzy
+ $ git pull example.com:/git/froboz.git/ tags/frotz-for-xyzzy
 ------------
 
 This operation will always open an editor to allow the integrator to fine
diff --git a/git-request-pull.sh b/git-request-pull.sh
index 64960d6..e6438e2 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -63,7 +63,7 @@ die "fatal: No commits in common between $base and $head"
 find_matching_ref='
 	sub abbr {
 		my $ref = shift;
-		if ($ref =~ s|refs/heads/|| || $ref =~ s|refs/tags/||) {
+		if ($ref =~ s|^refs/heads/|| || $ref =~ s|^refs/tags/|tags/|) {
 			return $ref;
 		} else {
 			return $ref;
diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh
index da25bc2..7c1dc64 100755
--- a/t/t5150-request-pull.sh
+++ b/t/t5150-request-pull.sh
@@ -179,11 +179,7 @@ test_expect_success 'request names an appropriate branch' '
 		read repository &&
 		read branch
 	} <digest &&
-	{
-		test "$branch" = full ||
-		test "$branch" = master ||
-		test "$branch" = for-upstream
-	}
+	test "$branch" = tags/full
 
 '
 
-- 
1.7.9.155.gf6ee6

^ permalink raw reply related

* What's cooking in git.git (Jan 2012, #08; Tue, 31)
From: Junio C Hamano @ 2012-02-01  7:19 UTC (permalink / raw)
  To: git

What's cooking in git.git (Jan 2012, #08; Tue, 31)
--------------------------------------------------

Here are the topics that have been cooking.  Commits prefixed with '-' are
only in 'pu' (proposed updates) while commits prefixed with '+' are in
'next'.

As promised in the recent couple of issues of "What's cooking", the first
batch of topics that have been cooking in 'next' are now in 'master'. The
tip of 'next' hasn't been rewound yet, but it soon will after the second
batch of topics graduate.

Here are the repositories that have my integration branches:

With maint, master, next, pu, todo:

        git://git.kernel.org/pub/scm/git/git.git
        git://repo.or.cz/alt-git.git
        https://code.google.com/p/git-core/
        https://github.com/git/git

With only maint and master:

        git://git.sourceforge.jp/gitroot/git-core/git.git
        git://git-core.git.sourceforge.net/gitroot/git-core/git-core

With all the topics and integration branches:

        https://github.com/gitster/git

The preformatted documentation in HTML and man format are found in:

        git://git.kernel.org/pub/scm/git/git-{htmldocs,manpages}.git/
        git://repo.or.cz/git-{htmldocs,manpages}.git/
        https://code.google.com/p/git-{htmldocs,manpages}.git/
        https://github.com/gitster/git-{htmldocs,manpages}.git/

--------------------------------------------------
[New Topics]

* fc/zsh-completion (2012-01-30) 4 commits
 - (squash to previous?) completion: remove unused code
 - completion: simplify __git_remotes
 - (squash) completion-style
 - completion: be nicer with zsh

Somehow only 2 out of 4-part series seem to have reached the list, missing
the other 2.

* jc/maint-request-pull-for-tag (2012-01-31) 1 commit
 - request-pull: explicitly ask tags/$name to be pulled

Usability improvement.
Will merge to 'next'.

* nd/find-pack-entry-recent-cache-invalidation (2012-01-31) 1 commit
 - find_pack_entry(): do not keep packed_git pointer locally

Review comments sent.

* nd/pack-objects-parseopt (2012-01-31) 1 commit
 - pack-objects: convert to use parse_options()

Review comments sent.

* tr/merge-edit-guidance (2012-01-31) 1 commit
  (merged to 'next' on 2012-01-31 at bb678f7)
 + merge: add instructions to the commit message when editing

Will merge to 'master' in the second batch.

--------------------------------------------------
[Graduated to "master"]

* ar/i18n-no-gettext (2012-01-27) 4 commits
  (merged to 'next' on 2012-01-27 at 0ecf258)
 + i18n: Do not force USE_GETTEXT_SCHEME=fallthrough on NO_GETTEXT
  (merged to 'next' on 2012-01-23 at 694a94e)
 + i18n: Make NO_GETTEXT imply fallthrough scheme in shell l10n
 + add a Makefile switch to avoid gettext translation in shell scripts
 + git-sh-i18n: restructure the logic to compute gettext.sh scheme

* da/maint-mergetool-twoway (2012-01-23) 1 commit
  (merged to 'next' on 2012-01-23 at f927323)
 + mergetool: Provide an empty file when needed

Caters to GUI merge backends that cannot merge two files without
a base by giving them an empty file as a "pretend" common ancestor.

* jc/advise-i18n (2011-12-22) 1 commit
  (merged to 'next' on 2012-01-23 at 6447013)
 + i18n of multi-line advice messages

Allow localization of advice messages that tend to be longer and
multi-line formatted. For now this is deliberately limited to advise()
interface and not vreportf() in general as touching the latter has
interactions with error() that has plumbing callers whose prefix "error: "
should never be translated.

* jl/submodule-re-add (2012-01-24) 1 commit
  (merged to 'next' on 2012-01-26 at 482553e)
 + submodule add: fix breakage when re-adding a deep submodule

"git submodule add" forgot to recompute the name to be stored in .gitmodules
when the module was once added to the superproject and already initialized.

* ks/sort-wildcard-in-makefile (2012-01-22) 1 commit
  (merged to 'next' on 2012-01-23 at e2e0c1d)
 + t/Makefile: Use $(sort ...) explicitly where needed

t/Makefile is adjusted to prevent newer versions of GNU make from running
tests in seemingly random order.

* ld/git-p4-branches-and-labels (2012-01-20) 5 commits
  (merged to 'next' on 2012-01-23 at 9020ec4)
 + git-p4: label import fails with multiple labels at the same changelist
 + git-p4: add test for p4 labels
 + git-p4: importing labels should cope with missing owner
 + git-p4: cope with labels with empty descriptions
 + git-p4: handle p4 branches and labels containing shell chars
 (this branch is used by va/git-p4-branch.)

* nd/clone-detached (2012-01-24) 12 commits
  (merged to 'next' on 2012-01-26 at 7b0cc8a)
 + clone: fix up delay cloning conditions
  (merged to 'next' on 2012-01-23 at bee31c6)
 + push: do not let configured foreign-vcs permanently clobbered
  (merged to 'next' on 2012-01-23 at 9cab64e)
 + clone: print advice on checking out detached HEAD
 + clone: allow --branch to take a tag
 + clone: refuse to clone if --branch points to bogus ref
 + clone: --branch=<branch> always means refs/heads/<branch>
 + clone: delay cloning until after remote HEAD checking
 + clone: factor out remote ref writing
 + clone: factor out HEAD update code
 + clone: factor out checkout code
 + clone: write detached HEAD in bare repositories
 + t5601: add missing && cascade

"git clone" learned to detach the HEAD in the resulting repository when
the source repository's HEAD does not point to a branch.

* rr/sequencer (2012-01-11) 2 commits
  (merged to 'next' on 2012-01-23 at f349b56)
 + sequencer: factor code out of revert builtin
 + revert: prepare to move replay_action to header

Moving large chunk of code out of cherry-pick/revert for later reuse,
primarily to prepare for the next cycle.

* tr/grep-l-with-decoration (2012-01-23) 1 commit
  (merged to 'next' on 2012-01-23 at 42b8795)
 + grep: fix -l/-L interaction with decoration lines

Using "git grep -l/-L" together with options -W or --break may not make
much sense as the output is to only count the number of hits and there is
no place for file breaks, but the latter options made "-l/-L" to miscount
the hits.

* va/git-p4-branch (2012-01-26) 4 commits
  (merged to 'next' on 2012-01-26 at e67c52a)
 + t9801: do not overuse test_must_fail
 + git-p4: Change p4 command invocation
 + git-p4: Add test case for complex branch import
 + git-p4: Search for parent commit on branch creation
 (this branch uses ld/git-p4-branches-and-labels.)

--------------------------------------------------
[Stalled]

* jc/advise-push-default (2011-12-18) 1 commit
 - push: hint to use push.default=upstream when appropriate

Peff had a good suggestion outlining an updated code structure so that
somebody new can try to dip his or her toes in the development. Any
takers?

Waiting for a reroll.

* ss/git-svn-prompt-sans-terminal (2012-01-04) 3 commits
 - fixup! 15eaaf4
 - git-svn, perl/Git.pm: extend Git::prompt helper for querying users
  (merged to 'next' on 2012-01-05 at 954f125)
 + perl/Git.pm: "prompt" helper to honor GIT_ASKPASS and SSH_ASKPASS

The bottom one has been replaced with a rewrite based on comments from
Ævar. The second one needs more work, both in perl/Git.pm and prompt.c, to
give precedence to tty over SSH_ASKPASS when terminal is available.

Will defer till the next cycle.

* nd/commit-ignore-i-t-a (2012-01-16) 2 commits
 - commit, write-tree: allow to ignore CE_INTENT_TO_ADD while writing trees
 - cache-tree: update API to take abitrary flags

May want to consider this as fixing an earlier UI mistake, and not as a
feature that devides the userbase.

Will defer till the next cycle.

--------------------------------------------------
[Cooking]

* bl/gitweb-project-filter (2012-01-31) 8 commits
 - gitweb: Make project search respect project_filter
 - gitweb: improve usability of projects search form
 - gitweb: place links to parent directories in page header
 - gitweb: show active project_filter in project_list page header
 - gitweb: limit links to alternate forms of project_list to active project_filter
 - gitweb: add project_filter to limit project list to a subdirectory
 - gitweb: prepare git_get_projects_list for use outside 'forks'.
 - gitweb: move hard coded .git suffix out of git_get_projects_list

Seems to break test 9502.

* rt/completion-branch-edit-desc (2012-01-29) 1 commit
  (merged to 'next' on 2012-01-31 at a0195c8)
 + completion: --edit-description option for git-branch

* jn/svn-fe (2012-01-27) 44 commits
  (merged to 'next' on 2012-01-29 at 001a395)
 + vcs-svn/svndiff.c: squelch false "unused" warning from gcc
 + Merge branch 'svn-fe' of git://repo.or.cz/git/jrn into jn/svn-fe
 + vcs-svn: reset first_commit_done in fast_export_init
 + Merge branch 'db/text-delta' into svn-fe
 + vcs-svn: do not initialize report_buffer twice
 + Merge branch 'db/text-delta' into svn-fe
 + vcs-svn: avoid hangs from corrupt deltas
 + vcs-svn: guard against overflow when computing preimage length
 + Merge branch 'db/delta-applier' into db/text-delta
 + vcs-svn: implement text-delta handling
 + Merge branch 'db/delta-applier' into db/text-delta
 + Merge branch 'db/delta-applier' into svn-fe
 + vcs-svn: cap number of bytes read from sliding view
 + test-svn-fe: split off "test-svn-fe -d" into a separate function
 + vcs-svn: let deltas use data from preimage
 + vcs-svn: let deltas use data from postimage
 + vcs-svn: verify that deltas consume all inline data
 + vcs-svn: implement copyfrom_data delta instruction
 + vcs-svn: read instructions from deltas
 + vcs-svn: read inline data from deltas
 + vcs-svn: read the preimage when applying deltas
 + vcs-svn: parse svndiff0 window header
 + vcs-svn: skeleton of an svn delta parser
 + vcs-svn: make buffer_read_binary API more convenient
 + vcs-svn: learn to maintain a sliding view of a file
 + Makefile: list one vcs-svn/xdiff object or header per line
 + Merge branch 'db/svn-fe-code-purge' into svn-fe
 + vcs-svn: drop obj_pool
 + vcs-svn: drop treap
 + vcs-svn: drop string_pool
 + vcs-svn: pass paths through to fast-import
 + Merge branch 'db/strbufs-for-metadata' into db/svn-fe-code-purge
 + Merge branch 'db/length-as-hash' (early part) into db/svn-fe-code-purge
 + Merge branch 'db/vcs-svn-incremental' into svn-fe
 + vcs-svn: avoid using ls command twice
 + vcs-svn: use mark from previous import for parent commit
 + vcs-svn: handle filenames with dq correctly
 + vcs-svn: quote paths correctly for ls command
 + vcs-svn: eliminate repo_tree structure
 + vcs-svn: add a comment before each commit
 + vcs-svn: save marks for imported commits
 + vcs-svn: use higher mark numbers for blobs
 + vcs-svn: set up channel to read fast-import cat-blob response
 + Merge commit 'v1.7.5' into svn-fe

"vcs-svn"/"svn-fe" learned to read dumps with svn-deltas and support
incremental imports.

Will merge to 'master' in the second batch.

* jc/split-blob (2012-01-24) 6 commits
 - chunked-object: streaming checkout
 - chunked-object: fallback checkout codepaths
 - bulk-checkin: support chunked-object encoding
 - bulk-checkin: allow the same data to be multiply hashed
 - new representation types in the packstream
 - varint-in-pack: refactor varint encoding/decoding

Not ready.

I finished the streaming checkout codepath, but as explained in 127b177
(bulk-checkin: support chunked-object encoding, 2011-11-30), these are
still early steps of a long and painful journey. At least pack-objects and
fsck need to learn the new encoding for the series to be usable locally,
and then index-pack/unpack-objects needs to learn it to be used remotely.

Given that I heard a lot of noise that people want large files, and that I
was asked by somebody at GitTogether'11 privately for an advice on how to
pay developers (not me) to help adding necessary support, I am somewhat
dissapointed that the original patch series that was sent almost two
months ago still remains here without much comments and updates from the
developer community. I even made the interface to the logic that decides
where to split chunks easily replaceable, and I deliberately made the
logic in the original patch extremely stupid to entice others, especially
the "bup" fanboys, to come up with a better logic, thinking that giving
people an easy target to shoot for, they may be encouraged to help
out. The plan is not working :-(.

* jc/pull-signed-tag (2012-01-23) 1 commit
  (merged to 'next' on 2012-01-23 at 4257553)
 + merge: use editor by default in interactive sessions

"git merge" in an interactive session learned to spawn the editor by
default to let the user edit the auto-generated merge message, to
encourage people to explain their merges better. Legacy scripts can
export MERGE_AUTOEDIT=no to retain the historical behaviour.

Will merge to 'master' in the second batch and deal with any fallout in
'master'.

--------------------------------------------------
[Discarded]

* mh/ref-api-rest (2011-12-12) 35 commits
 . repack_without_ref(): call clear_packed_ref_cache()
 . read_packed_refs(): keep track of the directory being worked in
 . is_refname_available(): query only possibly-conflicting references
 . refs: read loose references lazily
 . read_loose_refs(): take a (ref_entry *) as argument
 . struct ref_dir: store a reference to the enclosing ref_cache
 . sort_ref_dir(): take (ref_entry *) instead of (ref_dir *)
 . do_for_each_ref_in_dir*(): take (ref_entry *) instead of (ref_dir *)
 . add_entry(): take (ref_entry *) instead of (ref_dir *)
 . search_ref_dir(): take (ref_entry *) instead of (ref_dir *)
 . find_containing_direntry(): use (ref_entry *) instead of (ref_dir *)
 . add_ref(): take (ref_entry *) instead of (ref_dir *)
 . read_packed_refs(): take (ref_entry *) instead of (ref_dir *)
 . find_ref(): take (ref_entry *) instead of (ref_dir *)
 . is_refname_available(): take (ref_entry *) instead of (ref_dir *)
 . get_loose_refs(): return (ref_entry *) instead of (ref_dir *)
 . get_packed_refs(): return (ref_entry *) instead of (ref_dir *)
 . refs: wrap top-level ref_dirs in ref_entries
 . get_ref_dir(): keep track of the current ref_dir
 . do_for_each_ref(): only iterate over the subtree that was requested
 . refs: sort ref_dirs lazily
 . sort_ref_dir(): do not sort if already sorted
 . refs: store references hierarchically
 . refs.c: rename ref_array -> ref_dir
 . struct ref_entry: nest the value part in a union
 . check_refname_component(): return 0 for zero-length components
 . free_ref_entry(): new function
 . refs.c: reorder definitions more logically
 . is_refname_available(): reimplement using do_for_each_ref_in_array()
 . names_conflict(): simplify implementation
 . names_conflict(): new function, extracted from is_refname_available()
 . repack_without_ref(): reimplement using do_for_each_ref_in_array()
 . do_for_each_ref_in_arrays(): new function
 . do_for_each_ref_in_array(): new function
 . do_for_each_ref(): correctly terminate while processesing extra_refs

Will be re-rolled. Discarded without prejudice.

* mm/zsh-completion-regression-fix (2012-01-17) 1 commit
  (merged to 'next' on 2012-01-23 at 7bc2e0a)
 + bash-completion: don't add quoted space for ZSH (fix regression)

Superseded by a better fix already in 'master'.

^ permalink raw reply

* Re: [PATCH] Fix an "variable might be used uninitialized" gcc warning
From: Miles Bader @ 2012-02-01  7:16 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Ramsay Jones, Junio C Hamano, GIT Mailing-list
In-Reply-To: <20120131194302.GD12443@burratino>

Jonathan Nieder <jrnieder@gmail.com> writes:
>> The versions which complain are 3.4.4 and 4.1.2, whereas 4.4.0 compiles
>> the code without complaint. So, gcc *may* be getting more sane, but I wouldn't
>> bet on it! :-P
>>
>> I've had examples of this kind of warning, which relies heavily on the
>> analysis performed primarily for the optimizer, come-and-go in gcc before
>
> Yep, judging from the commit message, Junio found the same warning
> in 4.6.2.
>
>> Having said that, unless you are going to decree that the project only
>> supports gcc (and presumably only some particular versions of gcc), then you
>> may well find similar warnings triggered when using other compilers anyway ...
>
> Sure, when the control flow grows too complicated, that's probably worth
> fixing anyway, for the sake of humans especially.
>
> Sometimes gcc is the only crazy one, though. ;-)

It's hard to see how any compiler could detect that "mode" always
receives a value here .... it would have to realize that "stage" always
becomes 2 before the loop is exited, and that seems to depend on
non-trivial properties of external data structures...

-miles

-- 
Joy, n. An emotion variously excited, but in its highest degree arising from
the contemplation of grief in another.

^ permalink raw reply

* Re: [PATCH] Don't search files with an unset "grep" attribute
From: Junio C Hamano @ 2012-02-01  8:01 UTC (permalink / raw)
  To: Jeff King; +Cc: Conrad Irwin, git, Nguyen Thai Ngoc Duy, Dov Grobgeld
In-Reply-To: <20120125214625.GA4666@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> On Mon, Jan 23, 2012 at 10:59:45PM -0800, Junio C Hamano wrote:
>
>> Conrad Irwin <conrad.irwin@gmail.com> writes:
>> > I used to use this approach, hooking into the "diff" attribute directly to mark
>> > a file as binary, however that was clearly a hack.
>> 
>> After thinking about this a bit more, I have to say I disagree that it is
>> a hack.
>
> I kind of agree.
>
> The biggest problem is that the name is wrong.  The "diff.*.command"
> option really is about generating a diff between two blobs of a certain
> type. But "diff.*.textconv" and "diff.*.binary" are really just
> attributes of the file, and may or may not have to do with generating a
> diff. Ditto for diff.*.funcname, I think.
>
> You argue, and I agree, that if we are talking about attributes of the
> files and not diff-specific things, then other parts of git can and
> should make use of that information.
>
> So if this was all spelled:
>
>   $ cat .gitattributes
>   *.pdf filetype=pdf
>   $ cat .git/config
>   [filetype "pdf"]
>           binary = true
>           textconv = pdf2txt
>
> I think it would be a no-brainer that those type attributes should apply
> to "git grep".

I think this discussion has, instead of forking into two equally
interesting subthreads, veered to a more intellectually stimulating
tangent and we ended up losing focus.

Regardless of what to do with "I do not want to grep in these types of
files" and "I want textconv applied when grepping in these types", which
would be new attributes to implement two new features, I would like to see
us first concentrate on fixing the "binary" issue.  When somebody tells us
"Your autodetection may screw it up, but this file is binary; just show
'Binary files differ.' when comparing." with "-diff" (or "binary"), we
should honor that when "git grep" decides if it should take the 'Binary
file matches' codepath.  We currently do not, and it clearly is a bug.

This is especially made somewhat urgent because I do not want a half-baked
"two pathspecs" approach that only "git grep" knows about when we add the
support for "git grep --exclude-path=...".

We should have to teach the underlying machinery that matches pathspec
about negative pathspec entries only once. After we have done so, all the
callers, not just "git grep", should be able to take advantage of the
change by just learning to place negative pathspec entries in the "struct
pathspec" they pass to the machinery.  Doing anything else will lead to
madness of adding ad-hoc "here we should further filter with the other
negative 'struct pathspec'" in each and every application.

But I suspect that it would not materialize anytime soon.  And I also
suspect that the correct handling of 'Binary file matches', which is a
pure bugfix, should solve the original issue started these threads 90% in
practice.

^ permalink raw reply

* Re: [PATCH] Don't search files with an unset "grep" attribute
From: Jeff King @ 2012-02-01  8:20 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Conrad Irwin, git, Nguyen Thai Ngoc Duy, Dov Grobgeld
In-Reply-To: <7vhazb3rtm.fsf@alter.siamese.dyndns.org>

On Wed, Feb 01, 2012 at 12:01:41AM -0800, Junio C Hamano wrote:

> > So if this was all spelled:
> >
> >   $ cat .gitattributes
> >   *.pdf filetype=pdf
> >   $ cat .git/config
> >   [filetype "pdf"]
> >           binary = true
> >           textconv = pdf2txt
> >
> > I think it would be a no-brainer that those type attributes should apply
> > to "git grep".
> 
> I think this discussion has, instead of forking into two equally
> interesting subthreads, veered to a more intellectually stimulating
> tangent and we ended up losing focus.

That's what I'm here for.

> Regardless of what to do with "I do not want to grep in these types of
> files" and "I want textconv applied when grepping in these types", which
> would be new attributes to implement two new features, I would like to see
> us first concentrate on fixing the "binary" issue.  When somebody tells us
> "Your autodetection may screw it up, but this file is binary; just show
> 'Binary files differ.' when comparing." with "-diff" (or "binary"), we
> should honor that when "git grep" decides if it should take the 'Binary
> file matches' codepath.  We currently do not, and it clearly is a bug.

Right. It may have been lost in the verbosity of what I wrote in my
previous email, but I completely agree. With the caveat that one should
also respect "diff=foo" coupled with "diff.foo.binary = true" as making
something binary. But that is already handled transparently by the
userdiff.[ch] code (which seems like the obvious entry point for
grep to use for attribute lookup, and which we already use there for
funcname lookup).

The trivial-ish patch is below.

> We should have to teach the underlying machinery that matches pathspec
> about negative pathspec entries only once. After we have done so, all the
> callers, not just "git grep", should be able to take advantage of the
> change by just learning to place negative pathspec entries in the "struct
> pathspec" they pass to the machinery.  Doing anything else will lead to
> madness of adding ad-hoc "here we should further filter with the other
> negative 'struct pathspec'" in each and every application.

Yes, I agree.

> But I suspect that it would not materialize anytime soon.  And I also
> suspect that the correct handling of 'Binary file matches', which is a
> pure bugfix, should solve the original issue started these threads 90% in
> practice.

Also agree. Let's fix the bug and then give it some time to see whether
people really want more explicit exclusions.

Here's the bug-fix patch. Not quite ready for inclusion, as it obviously
needs tests and a commit message. Also, we can cache the result of the
userdiff lookup so the funcname code doesn't have to look it up again.

---
diff --git a/grep.c b/grep.c
index b29d09c..d7ab054 100644
--- a/grep.c
+++ b/grep.c
@@ -960,6 +960,15 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)
 	fwrite(buf, size, 1, stdout);
 }
 
+static int grep_buffer_is_binary(const char *path,
+				 char *buf, unsigned long size)
+{
+	struct userdiff_driver *drv = userdiff_find_by_path(path);
+	if (drv && drv->binary != -1)
+		return drv->binary;
+	return buffer_is_binary(buf, size);
+}
+
 static int grep_buffer_1(struct grep_opt *opt, const char *name,
 			 char *buf, unsigned long size, int collect_hits)
 {
@@ -994,11 +1003,11 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
 
 	switch (opt->binary) {
 	case GREP_BINARY_DEFAULT:
-		if (buffer_is_binary(buf, size))
+		if (grep_buffer_is_binary(name, buf, size))
 			binary_match_only = 1;
 		break;
 	case GREP_BINARY_NOMATCH:
-		if (buffer_is_binary(buf, size))
+		if (grep_buffer_is_binary(name, buf, size))
 			return 0; /* Assume unmatch */
 		break;
 	case GREP_BINARY_TEXT:

^ permalink raw reply related

* Re: [PATCH] Don't search files with an unset "grep" attribute
From: Jeff King @ 2012-02-01  9:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Conrad Irwin, git, Nguyen Thai Ngoc Duy, Dov Grobgeld
In-Reply-To: <20120201082005.GA32348@sigill.intra.peff.net>

On Wed, Feb 01, 2012 at 03:20:05AM -0500, Jeff King wrote:

> Here's the bug-fix patch. Not quite ready for inclusion, as it obviously
> needs tests and a commit message. Also, we can cache the result of the
> userdiff lookup so the funcname code doesn't have to look it up again.

Actually, it's a little bit more complicated. I was looking at a
slightly old version of grep.c. Since 0579f91 (grep: enable threading
with -p and -W using lazy attribute lookup, 2011-12-12), the lookup
happens in lots of sub-functions, and locking is required.

So this is what the patch looks like with proper locking and caching of
the looked-up driver. It's quite messy because the cached driver pointer
has to get passed around quite a bit. And I'm not sure it buys that much
in practice. The cost of attribute lookup _is_ noticeable (which I'll
discuss below), but funcname lookup only happens when we get a grep hit.
So unless you are searching for something extremely common, you're only
going to do a lookup very occasionally (compared to the load of actually
searching through the files). So all of the messiness and caching may
not be worth the effort, as I wasn't able to measure a performance gain.

But there's more. Respecting binary attributes does mean looking up
attributes for _every_ file. And that has a noticeable impact. My
best-of-five for "git grep foo" on linux-2.6 went from 0.302s to 0.392s.
Yuck.

Part of the problem, I suspect, is that the attribute lookup code is
optimized for locality. We only unwind as much of the stack as we need,
so looking at "foo/bar/baz.c" after "foo/bar/bleep.c" is much cheaper
than looking at "some/other/directory.c". But with threaded grep, that
locality is likely lost, as we are mixing up attribute requests from
different threads.

Given that binary lookup means we need every file's gitattribute, it
might be better to look them up serially at the beginning of the
program, and then pass the resulting userdiff driver to grep_buffer
along with each path.

---
diff --git a/grep.c b/grep.c
index 486230b..3ca840a 100644
--- a/grep.c
+++ b/grep.c
@@ -829,15 +829,28 @@ static inline void grep_attr_unlock(struct grep_opt *opt)
 #define grep_attr_unlock(opt)
 #endif
 
-static int match_funcname(struct grep_opt *opt, const char *name, char *bol, char *eol)
+static struct userdiff_driver *get_cached_userdiff(struct grep_opt *opt,
+						   const char *path,
+						   struct userdiff_driver **drv)
 {
-	xdemitconf_t *xecfg = opt->priv;
-	if (xecfg && !xecfg->find_func) {
-		struct userdiff_driver *drv;
+	if (!*drv) {
 		grep_attr_lock(opt);
-		drv = userdiff_find_by_path(name);
+		*drv = userdiff_find_by_path(path);
+		if (!*drv)
+			*drv = userdiff_find_by_name("default");
 		grep_attr_unlock(opt);
-		if (drv && drv->funcname.pattern) {
+	}
+	return *drv;
+}
+
+static int match_funcname(struct grep_opt *opt, const char *name,
+			  struct userdiff_driver **drv_p,
+			  char *bol, char *eol)
+{
+	xdemitconf_t *xecfg = opt->priv;
+	if (xecfg && !xecfg->find_func) {
+		struct userdiff_driver *drv = get_cached_userdiff(opt, name, drv_p);
+		if (drv->funcname.pattern) {
 			const struct userdiff_funcname *pe = &drv->funcname;
 			xdiff_set_find_func(xecfg, pe->pattern, pe->cflags);
 		} else {
@@ -859,6 +872,7 @@ static int match_funcname(struct grep_opt *opt, const char *name, char *bol, cha
 }
 
 static void show_funcname_line(struct grep_opt *opt, const char *name,
+			       struct userdiff_driver **drv_p,
 			       char *buf, char *bol, unsigned lno)
 {
 	while (bol > buf) {
@@ -871,20 +885,21 @@ static void show_funcname_line(struct grep_opt *opt, const char *name,
 		if (lno <= opt->last_shown)
 			break;
 
-		if (match_funcname(opt, name, bol, eol)) {
+		if (match_funcname(opt, name, drv_p, bol, eol)) {
 			show_line(opt, bol, eol, name, lno, '=');
 			break;
 		}
 	}
 }
 
-static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
-			     char *bol, char *end, unsigned lno)
+static void show_pre_context(struct grep_opt *opt, const char *name,
+			     struct userdiff_driver **drv_p,
+			     char *buf, char *bol, char *end, unsigned lno)
 {
 	unsigned cur = lno, from = 1, funcname_lno = 0;
 	int funcname_needed = !!opt->funcname;
 
-	if (opt->funcbody && !match_funcname(opt, name, bol, end))
+	if (opt->funcbody && !match_funcname(opt, name, drv_p, bol, end))
 		funcname_needed = 2;
 
 	if (opt->pre_context < lno)
@@ -900,7 +915,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
 		while (bol > buf && bol[-1] != '\n')
 			bol--;
 		cur--;
-		if (funcname_needed && match_funcname(opt, name, bol, eol)) {
+		if (funcname_needed && match_funcname(opt, name, drv_p, bol, eol)) {
 			funcname_lno = cur;
 			funcname_needed = 0;
 		}
@@ -908,7 +923,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
 
 	/* We need to look even further back to find a function signature. */
 	if (opt->funcname && funcname_needed)
-		show_funcname_line(opt, name, buf, bol, cur);
+		show_funcname_line(opt, name, drv_p, buf, bol, cur);
 
 	/* Back forward. */
 	while (cur < lno) {
@@ -983,6 +998,17 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)
 	fwrite(buf, size, 1, stdout);
 }
 
+static int grep_buffer_is_binary(struct grep_opt *opt,
+				 const char *path,
+				 char *buf, unsigned long size,
+				 struct userdiff_driver **drv_p)
+{
+	struct userdiff_driver *drv = get_cached_userdiff(opt, path, drv_p);
+	if (drv && drv->binary != -1)
+		return drv->binary;
+	return buffer_is_binary(buf, size);
+}
+
 static int grep_buffer_1(struct grep_opt *opt, const char *name,
 			 char *buf, unsigned long size, int collect_hits)
 {
@@ -996,6 +1022,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
 	int show_function = 0;
 	enum grep_context ctx = GREP_CONTEXT_HEAD;
 	xdemitconf_t xecfg;
+	struct userdiff_driver *drv = NULL;
 
 	if (!opt->output)
 		opt->output = std_output;
@@ -1017,11 +1044,11 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
 
 	switch (opt->binary) {
 	case GREP_BINARY_DEFAULT:
-		if (buffer_is_binary(buf, size))
+		if (grep_buffer_is_binary(opt, name, buf, size, &drv))
 			binary_match_only = 1;
 		break;
 	case GREP_BINARY_NOMATCH:
-		if (buffer_is_binary(buf, size))
+		if (grep_buffer_is_binary(opt, name, buf, size, &drv))
 			return 0; /* Assume unmatch */
 		break;
 	case GREP_BINARY_TEXT:
@@ -1099,16 +1126,16 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
 			 * pre-context lines, we would need to show them.
 			 */
 			if (opt->pre_context || opt->funcbody)
-				show_pre_context(opt, name, buf, bol, eol, lno);
+				show_pre_context(opt, name, &drv, buf, bol, eol, lno);
 			else if (opt->funcname)
-				show_funcname_line(opt, name, buf, bol, lno);
+				show_funcname_line(opt, name, &drv, buf, bol, lno);
 			show_line(opt, bol, eol, name, lno, ':');
 			last_hit = lno;
 			if (opt->funcbody)
 				show_function = 1;
 			goto next_line;
 		}
-		if (show_function && match_funcname(opt, name, bol, eol))
+		if (show_function && match_funcname(opt, name, &drv, bol, eol))
 			show_function = 0;
 		if (show_function ||
 		    (last_hit && lno <= last_hit + opt->post_context)) {

^ permalink raw reply related

* Re: [PATCH] Don't search files with an unset "grep" attribute
From: Conrad Irwin @ 2012-02-01  9:28 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, git, Nguyen Thai Ngoc Duy, Dov Grobgeld
In-Reply-To: <20120201091009.GA20984@sigill.intra.peff.net>

On Wed, Feb 1, 2012 at 1:10 AM, Jeff King <peff@peff.net> wrote:
> On Wed, Feb 01, 2012 at 03:20:05AM -0500, Jeff King wrote:
>
> Actually, it's a little bit more complicated. I was looking at a
> slightly old version of grep.c. Since 0579f91 (grep: enable threading
> with -p and -W using lazy attribute lookup, 2011-12-12), the lookup
> happens in lots of sub-functions, and locking is required.

Heh, you just beat me to it.

> But there's more. Respecting binary attributes does mean looking up
> attributes for _every_ file. And that has a noticeable impact. My
> best-of-five for "git grep foo" on linux-2.6 went from 0.302s to 0.392s.
> Yuck.

The first time I introduced this behaviour[1], I made it conditional
on a preference — those who wanted "good" grep could set the
preference, while those who wanted "fast" grep could not. I think
that's not a good idea, though if the performance issues are
show-stoppers, I'd suggest the opposite preference (so speed-freaks
can disable the checks).

Tests from [1] included below in case they're still useful (they pass
with your change)

[1] http://article.gmane.org/gmane.comp.version-control.git/179299/match=grep
---

diff --git a/t/t7008-grep-binary.sh b/t/t7008-grep-binary.sh
index 917a264..4d94461 100755
--- a/t/t7008-grep-binary.sh
+++ b/t/t7008-grep-binary.sh
@@ -99,4 +99,23 @@ test_expect_success 'git grep y<NUL>x a' "
        test_must_fail git grep -f f a
 "

+test_expect_success 'git -c grep.binaryFiles=1 grep ina a' "
+       echo 'a diff' > .gitattributes &&
+       printf 'binaryQfile' | q_to_nul >a &&
+       echo 'a:binaryQfile' | q_to_nul >expect &&
+       git -c grep.binaryFiles=1 grep ina a > actual &&
+       rm .gitattributes &&
+       test_cmp expect actual
+"
+test_expect_success 'git -c grep.binaryFiles=1 grep tex t' "
+       echo 'text' > t &&
+       git add t &&
+       echo 't -diff' > .gitattributes &&
+       echo Binary file t matches >expect &&
+       git -c grep.binaryFiles=1 grep tex t >actual &&
+       rm .gitattributes &&
+       test_cmp expect actual
+"
+
+
 test_done

^ permalink raw reply related

* Re: [PATCH] Correct singular form in diff summary line for human interaction
From: Thomas Dickey @ 2012-02-01  9:40 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: dickey, Nguyen Thai Ngoc Duy, Jonathan Nieder, git,
	Ævar Arnfjörð, Frederik Schwarzer, Brandon Casey,
	dickey
In-Reply-To: <7vk4475k5s.fsf@alter.siamese.dyndns.org>

[-- Attachment #1: Type: text/plain, Size: 3686 bytes --]

On Tue, Jan 31, 2012 at 07:04:15PM -0800, Junio C Hamano wrote:
> Thomas Dickey <dickey@his.com> writes:
> 
> > On Wed, Feb 01, 2012 at 08:32:43AM +0700, Nguyen Thai Ngoc Duy wrote:
> >> On Wed, Feb 1, 2012 at 12:50 AM, Junio C Hamano <gitster@pobox.com> wrote:
> >> >> If there is an environment variable to say "I don't want to see
> >> >> variations on strings intended for humans", can it be spelled as
> >> >> LC_ALL=C?
> >> >
> >> >  ...
> >
> > ... diffstat (google helped find context)
> 
> When we show diffstat from "git diff --stat" (or "git apply --stat"), we
> currently do not do any singular/plural on the last line of the output
> that summarizes the graph, ending up with:
> 
> 	1 files changed, 1 insertions(+), 0 deletions(-)
> 
> when there is a single line insertion to a file and nothing else.
> 
> My recollection is that our behaviour originally came from our desire to
> be as close as what "diffstat" produces, but that does not seem to be the
> case.  I observed that the output from recent versions of "diffstat" is
> much more human friendly.  We get these, depending on the input, from
> "diffstat" version 1.53:

I added the PLURAL() macro in 1.22, in 1996/3/16, which was a few months
before Tony Nugent commented that it was being used by other people.  Since
I'd been sending patches with diffstat's since mid-1994, it's possible
that there were a few copies using the form without plurals.  But it's
been quite a while.  Also, it was in 1998/1/17 that I modified the
copyright notice (1.26) at the request of someone in the Linux group, so
I'd assume that they would have started using the newer version.

Except for later applying PLURAL to the number of files changed (which Jean
Delvare pointed out in 2005), the message construction has not changed since
then.  The insert/delete/modify parts of the message were optional as you see in
my earliest version (1.3) from 1993/10/23:

	printf("%d files changed", num_files);
	if (total_ins) printf(", %d insertions", total_ins);
	if (total_del) printf(", %d deletions", total_del);
	if (total_mod) printf(", %d modifications", total_mod);
	printf("\n");
 
>         1 file changed, 1 insertion(+)
>         1 file changed, 1 deletion(-)
> 	0 files changed
> 	2 files changed, 3 insertions(+), 1 deletion(-)
> 
> Namely, it does singular/plural correctly, and omits unnecessary "0
> deletions(-)" and "0 insertions(+)".
> 
> I was wondering if you remember what the behaviour of older versions of
> "diffstat" was, and if it was changed to be more human friendly over
> time. It is very possible that I am misremembering this and "diffstat" has
> always done the singular/plural correctly and omitted useless "0 lines".

I have back to 1.3 in my archive. I use rcshist to look for things like this.
(also, for small things like this, I have a script that pulls all versions,
with proper timestamps to make it simpler to sort the files by date).
 
> Somehow it seems hard to get hold of older versions of "diffstat", and I
> was hoping that I could get that information straight out of the current
> maintainer.

I can provide the information.

Actually a couple of weeks ago I was experimenting with rcs-fast-export, but
found that would need more work to export diffstat (I use branches a lot)
I'm using "conflict" as a test-case for the changes that I'm making to support
exporting mawk.

> Thanks for responding and sorry for the lack of context of the original
> message.

no problem - google was helpful ;-)

-- 
Thomas E. Dickey <dickey@invisible-island.net>
http://invisible-island.net
ftp://invisible-island.net

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* ANNOUNCE: Git for Windows 1.7.9
From: Pat Thoyts @ 2012-02-01 11:23 UTC (permalink / raw)
  To: msysGit; +Cc: Git Mailing List

This release brings the latest release of Git to Windows users.

Pre-built installers are available from
http://code.google.com/p/msysgit/downloads/list

Further details about the Git for Windows project are at
http://code.google.com/p/msysgit/

^ permalink raw reply

* Re: What's cooking in git.git (Jan 2012, #08; Tue, 31)
From: Jakub Narebski @ 2012-02-01 12:07 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Bernhard R. Link
In-Reply-To: <7vlion3tr5.fsf@alter.siamese.dyndns.org>

Junio C Hamano <gitster@pobox.com> writes:

> --------------------------------------------------
> [Cooking]
> 
> * bl/gitweb-project-filter (2012-01-31) 8 commits
>  - gitweb: Make project search respect project_filter
>  - gitweb: improve usability of projects search form
>  - gitweb: place links to parent directories in page header
>  - gitweb: show active project_filter in project_list page header
>  - gitweb: limit links to alternate forms of project_list to active project_filter
>  - gitweb: add project_filter to limit project list to a subdirectory
>  - gitweb: prepare git_get_projects_list for use outside 'forks'.
>  - gitweb: move hard coded .git suffix out of git_get_projects_list
> 
> Seems to break test 9502.

Hmmm... strange.  I have applied my patches on top of earlier version
of project_filter commits:

   - gitweb: Make project search respect project_filter
   - gitweb: Improve projects search form
   - gitweb: place links to parent directories in page header
   - gitweb: add project_filter to limit project list to a subdirectory

and all gitweb tests passes.

I will investigate.

-- 
Jakub Narebski

^ permalink raw reply

* Re: [BUG] git clean -X skips a directory containing only ignored files
From: Michael Schubert @ 2012-02-01 12:18 UTC (permalink / raw)
  To: Andrew Wong; +Cc: Paul Berry, git
In-Reply-To: <4F2814D7.8030504@sohovfx.com>

On 01/31/2012 05:20 PM, Andrew Wong wrote:
> I think there were a bit of discussions on this issues just while ago too:
> http://thread.gmane.org/gmane.comp.version-control.git/188605

Thanks, missed that.

Below a patch with an update for Documentation/git-clean.txt - I'm not sure
if the issue should be described more accurate.?

-- >8 --

Subject: [PATCH] Documentation: tell about "git clean -Xd" bug

"git clean -Xd" doesn't work as expected (delete all ignored files and
untracked directories), because Git's dir subsystem is skipping
directories which both aren't explicitly ignored and don't hold any
tracked files.

Tell about this limitation in BUGS.

Signed-off-by: Michael Schubert <mschub@elegosoft.com>
---
 Documentation/git-clean.txt |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index 79fb984..888c07d 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -29,7 +29,8 @@ OPTIONS
 	Remove untracked directories in addition to untracked files.
 	If an untracked directory is managed by a different git
 	repository, it is not removed by default.  Use -f option twice
-	if you really want to remove such a directory.
+	if you really want to remove such a directory.  Also see BUGS
+	below.
 
 -f::
 --force::
@@ -63,6 +64,11 @@ OPTIONS
 	Remove only files ignored by git.  This may be useful to rebuild
 	everything from scratch, but keep manually created files.
 
+BUGS
+----
+'git-clean -Xd' doesn't work as expected for directories which don't hold
+any tracked files and aren't explicitly ignored either.
+
 GIT
 ---
 Part of the linkgit:git[1] suite
-- 
1.7.9.174.g356eff6

^ permalink raw reply related

* [PATCH v2] Use correct grammar in diffstat summary line
From: Nguyễn Thái Ngọc Duy @ 2012-02-01 12:55 UTC (permalink / raw)
  To: git
  Cc: Thomas Dickey, Junio C Hamano, Jonathan Nieder,
	Ævar Arnfjörð, Frederik Schwarzer, Brandon Casey,
	dickey, Nguyễn Thái Ngọc Duy
In-Reply-To: <1328019840-6168-1-git-send-email-pclouds@gmail.com>

"git diff --stat" and "git apply --stat" now learn to print the line
"%d files changed, %d insertions(+), %d deletions(-)" in singular form
whenever applicable. "0 insertions" and "0 deletions" are also omitted
unless they are both zero.

Also make this line translatable.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Second try. Make it unconditionally (I'd still rather have no changes
 when LANG=C). Also omit "0 operations", although I keep "%d files
 changed, 0 insertions(+), 0 deletions(-)" for binary diff.

 In Vietnamese, the summary line is "thay đổi 68 tập tin, thêm(+) 163,
 xoá(-) 116". Lovely. Perhaps I'll translate git into Vietnamese after
 all :)

 And this patch's diffstat looks just scary due to test suite's updates.

 builtin/apply.c                                    |    3 +-
 diff.c                                             |   53 ++++++++++++++++++--
 diff.h                                             |    3 +
 t/t0023-crlf-am.sh                                 |    2 +-
 t/t1200-tutorial.sh                                |    2 +-
 t/t3300-funny-names.sh                             |    2 +-
 t/t3508-cherry-pick-many-commits.sh                |   12 ++--
 t/t3903-stash.sh                                   |    4 +-
 ...ff-tree_--cc_--patch-with-stat_--summary_master |    2 +-
 ...diff-tree_--cc_--patch-with-stat_--summary_side |    2 +-
 .../diff.diff-tree_--cc_--patch-with-stat_master   |    2 +-
 .../diff.diff-tree_--cc_--stat_--summary_master    |    2 +-
 t/t4013/diff.diff-tree_--cc_--stat_--summary_side  |    2 +-
 t/t4013/diff.diff-tree_--cc_--stat_master          |    2 +-
 ...pretty=oneline_--root_--patch-with-stat_initial |    2 +-
 .../diff.diff-tree_--pretty_--patch-with-stat_side |    2 +-
 ...-tree_--pretty_--root_--patch-with-stat_initial |    2 +-
 ...f-tree_--pretty_--root_--stat_--summary_initial |    2 +-
 .../diff.diff-tree_--pretty_--root_--stat_initial  |    2 +-
 ...diff.diff-tree_--root_--patch-with-stat_initial |    2 +-
 t/t4013/diff.diff-tree_-c_--stat_--summary_master  |    2 +-
 t/t4013/diff.diff-tree_-c_--stat_--summary_side    |    2 +-
 t/t4013/diff.diff-tree_-c_--stat_master            |    2 +-
 .../diff.diff_--patch-with-stat_-r_initial..side   |    2 +-
 t/t4013/diff.diff_--patch-with-stat_initial..side  |    2 +-
 t/t4013/diff.diff_--stat_initial..side             |    2 +-
 t/t4013/diff.diff_-r_--stat_initial..side          |    2 +-
 ..._--attach_--stdout_--suffix=.diff_initial..side |    2 +-
 ....format-patch_--attach_--stdout_initial..master |    4 +-
 ...format-patch_--attach_--stdout_initial..master^ |    2 +-
 ...ff.format-patch_--attach_--stdout_initial..side |    2 +-
 ...nline_--stdout_--numbered-files_initial..master |    4 +-
 ...tdout_--subject-prefix=TESTCASE_initial..master |    4 +-
 ....format-patch_--inline_--stdout_initial..master |    4 +-
 ...format-patch_--inline_--stdout_initial..master^ |    2 +-
 ...ff.format-patch_--inline_--stdout_initial..side |    2 +-
 ...tch_--stdout_--cover-letter_-n_initial..master^ |    2 +-
 ...at-patch_--stdout_--no-numbered_initial..master |    4 +-
 ...ormat-patch_--stdout_--numbered_initial..master |    4 +-
 t/t4013/diff.format-patch_--stdout_initial..master |    4 +-
 .../diff.format-patch_--stdout_initial..master^    |    2 +-
 t/t4013/diff.format-patch_--stdout_initial..side   |    2 +-
 ....log_--patch-with-stat_--summary_master_--_dir_ |    6 +-
 t/t4013/diff.log_--patch-with-stat_master          |    4 +-
 t/t4013/diff.log_--patch-with-stat_master_--_dir_  |    6 +-
 ..._--root_--cc_--patch-with-stat_--summary_master |    8 ++--
 ...f.log_--root_--patch-with-stat_--summary_master |    6 +-
 t/t4013/diff.log_--root_--patch-with-stat_master   |    6 +-
 ...og_--root_-c_--patch-with-stat_--summary_master |    8 ++--
 t/t4013/diff.show_--patch-with-stat_--summary_side |    2 +-
 t/t4013/diff.show_--patch-with-stat_side           |    2 +-
 t/t4013/diff.show_--stat_--summary_side            |    2 +-
 t/t4013/diff.show_--stat_side                      |    2 +-
 ...nged_--patch-with-stat_--summary_master_--_dir_ |    6 +-
 t/t4013/diff.whatchanged_--patch-with-stat_master  |    4 +-
 ...ff.whatchanged_--patch-with-stat_master_--_dir_ |    6 +-
 ..._--root_--cc_--patch-with-stat_--summary_master |    8 ++--
 ...anged_--root_--patch-with-stat_--summary_master |    6 +-
 ...iff.whatchanged_--root_--patch-with-stat_master |    6 +-
 ...ed_--root_-c_--patch-with-stat_--summary_master |    8 ++--
 t/t4014-format-patch.sh                            |    2 +-
 t/t4030-diff-textconv.sh                           |    2 +-
 t/t4045-diff-relative.sh                           |    2 +-
 t/t4049-diff-stat-count.sh                         |    2 +-
 t/t4100/t-apply-8.expect                           |    2 +-
 t/t4100/t-apply-9.expect                           |    2 +-
 t/t5150-request-pull.sh                            |    2 +-
 t/t7602-merge-octopus-many.sh                      |    6 +-
 68 files changed, 163 insertions(+), 116 deletions(-)

diff --git a/builtin/apply.c b/builtin/apply.c
index c24dc54..389898f 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -14,6 +14,7 @@
 #include "builtin.h"
 #include "string-list.h"
 #include "dir.h"
+#include "diff.h"
 #include "parse-options.h"
 
 /*
@@ -3241,7 +3242,7 @@ static void stat_patch_list(struct patch *patch)
 		show_stats(patch);
 	}
 
-	printf(" %d files changed, %d insertions(+), %d deletions(-)\n", files, adds, dels);
+	print_stat_summary(stdout, files, adds, dels);
 }
 
 static void numstat_patch_list(struct patch *patch)
diff --git a/diff.c b/diff.c
index 7e15426..5c31b36 100644
--- a/diff.c
+++ b/diff.c
@@ -1322,6 +1322,52 @@ static void fill_print_name(struct diffstat_file *file)
 	file->print_name = pname;
 }
 
+int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret;
+
+	if (!files) {
+		assert(insertions == 0 && deletions == 0);
+		return fputs(_(" no changes\n"), fp);
+	}
+
+	strbuf_addf(&sb,
+		    ngettext(" %d file changed", " %d files changed",
+			     files),
+		    files);
+
+	/*
+	 * For binary diff, the caller may want to print "x files
+	 * changed" with insertions == 0 && deletions == 0. Not
+	 * omitting "0 insertions(+), 0 deletions(-)" in this case is
+	 * probably less confusing (i.e skip over "2 files changed but
+	 * nothing about added/removed lines? Is this a bug in
+	 * git??").
+	 */
+	if (insertions || deletions == 0) {
+		strbuf_addf(&sb,
+			    /* TRANSLATORS: "+" in (+) is a line
+			       addition marker, do not translate it */
+			    ngettext(", %d insertion(+)", ", %d insertions(+)",
+				     insertions),
+			    insertions);
+	}
+
+	if (deletions || insertions == 0) {
+		strbuf_addf(&sb,
+			    /* TRANSLATORS: "-" in (-) is a line
+			       removal marker, do not translate it */
+			    ngettext(", %d deletion(-)", ", %d deletions(-)",
+				     deletions),
+			    deletions);
+	}
+	strbuf_addch(&sb, '\n');
+	ret = fputs(sb.buf, fp);
+	strbuf_release(&sb);
+	return ret;
+}
+
 static void show_stats(struct diffstat_t *data, struct diff_options *options)
 {
 	int i, len, add, del, adds = 0, dels = 0;
@@ -1475,9 +1521,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
 		extra_shown = 1;
 	}
 	fprintf(options->file, "%s", line_prefix);
-	fprintf(options->file,
-	       " %d files changed, %d insertions(+), %d deletions(-)\n",
-	       total_files, adds, dels);
+	print_stat_summary(options->file, total_files, adds, dels);
 }
 
 static void show_shortstats(struct diffstat_t *data, struct diff_options *options)
@@ -1507,8 +1551,7 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option
 				options->output_prefix_data);
 		fprintf(options->file, "%s", msg->buf);
 	}
-	fprintf(options->file, " %d files changed, %d insertions(+), %d deletions(-)\n",
-	       total_files, adds, dels);
+	print_stat_summary(options->file, total_files, adds, dels);
 }
 
 static void show_numstat(struct diffstat_t *data, struct diff_options *options)
diff --git a/diff.h b/diff.h
index ae71f4c..7af5f1e 100644
--- a/diff.h
+++ b/diff.h
@@ -324,4 +324,7 @@ extern struct userdiff_driver *get_textconv(struct diff_filespec *one);
 
 extern int parse_rename_score(const char **cp_p);
 
+extern int print_stat_summary(FILE *fp, int files,
+			      int insertions, int deletions);
+
 #endif /* DIFF_H */
diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh
index aaed725..18fe27b 100755
--- a/t/t0023-crlf-am.sh
+++ b/t/t0023-crlf-am.sh
@@ -12,7 +12,7 @@ Subject: test1
 
 ---
  foo |    1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  create mode 100644 foo
 
 diff --git a/foo b/foo
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
index 5e29e13..9356bea 100755
--- a/t/t1200-tutorial.sh
+++ b/t/t1200-tutorial.sh
@@ -156,7 +156,7 @@ Updating VARIABLE..VARIABLE
 FASTFORWARD (no commit created; -m option ignored)
  example |    1 +
  hello   |    1 +
- 2 files changed, 2 insertions(+), 0 deletions(-)
+ 2 files changed, 2 insertions(+)
 EOF
 
 test_expect_success 'git resolve' '
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index 5e29a05..9f00ada 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -167,7 +167,7 @@ test_expect_success TABS_IN_FILENAMES 'git diff-tree delete with-funny' \
 test_expect_success TABS_IN_FILENAMES 'setup expect' '
 cat >expected <<\EOF
  "tabs\t,\" (dq) and spaces"
- 1 files changed, 0 insertions(+), 0 deletions(-)
+ 1 file changed, 0 insertions(+), 0 deletions(-)
 EOF
 '
 
diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh
index 8e09fd0..1b3a344 100755
--- a/t/t3508-cherry-pick-many-commits.sh
+++ b/t/t3508-cherry-pick-many-commits.sh
@@ -38,13 +38,13 @@ test_expect_success 'cherry-pick first..fourth works' '
 	cat <<-\EOF >expected &&
 	[master OBJID] second
 	 Author: A U Thor <author@example.com>
-	 1 files changed, 1 insertions(+), 0 deletions(-)
+	 1 file changed, 1 insertion(+)
 	[master OBJID] third
 	 Author: A U Thor <author@example.com>
-	 1 files changed, 1 insertions(+), 0 deletions(-)
+	 1 file changed, 1 insertion(+)
 	[master OBJID] fourth
 	 Author: A U Thor <author@example.com>
-	 1 files changed, 1 insertions(+), 0 deletions(-)
+	 1 file changed, 1 insertion(+)
 	EOF
 
 	git checkout -f master &&
@@ -64,15 +64,15 @@ test_expect_success 'cherry-pick --strategy resolve first..fourth works' '
 	Trying simple merge.
 	[master OBJID] second
 	 Author: A U Thor <author@example.com>
-	 1 files changed, 1 insertions(+), 0 deletions(-)
+	 1 file changed, 1 insertion(+)
 	Trying simple merge.
 	[master OBJID] third
 	 Author: A U Thor <author@example.com>
-	 1 files changed, 1 insertions(+), 0 deletions(-)
+	 1 file changed, 1 insertion(+)
 	Trying simple merge.
 	[master OBJID] fourth
 	 Author: A U Thor <author@example.com>
-	 1 files changed, 1 insertions(+), 0 deletions(-)
+	 1 file changed, 1 insertion(+)
 	EOF
 
 	git checkout -f master &&
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index dbe2ac1..663c60a 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -444,7 +444,7 @@ test_expect_success 'stash show - stashes on stack, stash-like argument' '
 	git reset --hard &&
 	cat >expected <<-EOF &&
 	 file |    1 +
-	 1 files changed, 1 insertions(+), 0 deletions(-)
+	 1 file changed, 1 insertion(+)
 	EOF
 	git stash show ${STASH_ID} >actual &&
 	test_cmp expected actual
@@ -482,7 +482,7 @@ test_expect_success 'stash show - no stashes on stack, stash-like argument' '
 	git reset --hard &&
 	cat >expected <<-EOF &&
 	 file |    1 +
-	 1 files changed, 1 insertions(+), 0 deletions(-)
+	 1 file changed, 1 insertion(+)
 	EOF
 	git stash show ${STASH_ID} >actual &&
 	test_cmp expected actual
diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
index 3a9f78a..2f8560c 100644
--- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
@@ -2,7 +2,7 @@ $ git diff-tree --cc --patch-with-stat --summary master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
 index cead32e,7289e35..992913c
diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
index a61ad8c..72e03c1 100644
--- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
+++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
@@ -3,7 +3,7 @@ c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
index 49f23b9..8b357d9 100644
--- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
+++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
@@ -2,7 +2,7 @@ $ git diff-tree --cc --patch-with-stat master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
 index cead32e,7289e35..992913c
diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master
index cc6eb3b..e0568d6 100644
--- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master
+++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master
@@ -2,5 +2,5 @@ $ git diff-tree --cc --stat --summary master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 $
diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side
index 50362be..5afc823 100644
--- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side
+++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side
@@ -3,6 +3,6 @@ c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 $
diff --git a/t/t4013/diff.diff-tree_--cc_--stat_master b/t/t4013/diff.diff-tree_--cc_--stat_master
index fae7f33..f48367a 100644
--- a/t/t4013/diff.diff-tree_--cc_--stat_master
+++ b/t/t4013/diff.diff-tree_--cc_--stat_master
@@ -2,5 +2,5 @@ $ git diff-tree --cc --stat master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 $
diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
index d5c333a..590864c 100644
--- a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
+++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
@@ -3,7 +3,7 @@ $ git diff-tree --pretty=oneline --root --patch-with-stat initial
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
index 4d30e7e..e05e778 100644
--- a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
+++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
index 7dfa6af..0e2c956 100644
--- a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
index 43bfce2..384fa44 100644
--- a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
index 9154aa4..10384a8 100644
--- a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
+++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
@@ -8,5 +8,5 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 $
diff --git a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
index 1562b62..f57062e 100644
--- a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
+++ b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
@@ -3,7 +3,7 @@ $ git diff-tree --root --patch-with-stat initial
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_master b/t/t4013/diff.diff-tree_-c_--stat_--summary_master
index ac9f641..7088683 100644
--- a/t/t4013/diff.diff-tree_-c_--stat_--summary_master
+++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_master
@@ -2,5 +2,5 @@ $ git diff-tree -c --stat --summary master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 $
diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_side b/t/t4013/diff.diff-tree_-c_--stat_--summary_side
index 2afcca1..ef216ab 100644
--- a/t/t4013/diff.diff-tree_-c_--stat_--summary_side
+++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_side
@@ -3,6 +3,6 @@ c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 $
diff --git a/t/t4013/diff.diff-tree_-c_--stat_master b/t/t4013/diff.diff-tree_-c_--stat_master
index c2fe6a9..ad19f10 100644
--- a/t/t4013/diff.diff-tree_-c_--stat_master
+++ b/t/t4013/diff.diff-tree_-c_--stat_master
@@ -2,5 +2,5 @@ $ git diff-tree -c --stat master
 59d314ad6f356dd08601a4cd5e530381da3e3c64
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 $
diff --git a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side
index 9ed317a..ddad917 100644
--- a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side
+++ b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side
@@ -2,7 +2,7 @@ $ git diff --patch-with-stat -r initial..side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
diff --git a/t/t4013/diff.diff_--patch-with-stat_initial..side b/t/t4013/diff.diff_--patch-with-stat_initial..side
index 8b50629..bdbd114 100644
--- a/t/t4013/diff.diff_--patch-with-stat_initial..side
+++ b/t/t4013/diff.diff_--patch-with-stat_initial..side
@@ -2,7 +2,7 @@ $ git diff --patch-with-stat initial..side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
diff --git a/t/t4013/diff.diff_--stat_initial..side b/t/t4013/diff.diff_--stat_initial..side
index 0517b5d..6d08f3d 100644
--- a/t/t4013/diff.diff_--stat_initial..side
+++ b/t/t4013/diff.diff_--stat_initial..side
@@ -2,5 +2,5 @@ $ git diff --stat initial..side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 $
diff --git a/t/t4013/diff.diff_-r_--stat_initial..side b/t/t4013/diff.diff_-r_--stat_initial..side
index 245220d..2ddb254 100644
--- a/t/t4013/diff.diff_-r_--stat_initial..side
+++ b/t/t4013/diff.diff_-r_--stat_initial..side
@@ -2,5 +2,5 @@ $ git diff -r --stat initial..side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 $
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
index 52116d3..3cab049 100644
--- a/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
+++ b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
@@ -15,7 +15,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master
index ce49bd6..564a4d3 100644
--- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master
+++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
@@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^
index 5f1b238..4f28460 100644
--- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^
+++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side
index 4a2364a..b10cc2e 100644
--- a/t/t4013/diff.format-patch_--attach_--stdout_initial..side
+++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side
@@ -15,7 +15,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
index 43b81eb..a976a8a 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
+++ b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
@@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
index ca3f60b..b4fd664 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
+++ b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
@@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_initial..master
index 08f2301..0d31036 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master
+++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
@@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^
index 07f1230..18d4714 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^
+++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^
@@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..side b/t/t4013/diff.format-patch_--inline_--stdout_initial..side
index 67633d4..3572f20 100644
--- a/t/t4013/diff.format-patch_--inline_--stdout_initial..side
+++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..side
@@ -15,7 +15,7 @@ Content-Transfer-Encoding: 8bit
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 
diff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
index 3b4e113..54cdcda 100644
--- a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
+++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
@@ -75,7 +75,7 @@ Subject: [DIFFERENT_PREFIX 2/2] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
index f7752eb..23194eb 100644
--- a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
+++ b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
@@ -53,7 +53,7 @@ Subject: [PATCH] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -88,7 +88,7 @@ Subject: [PATCH] Side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--numbered_initial..master
index 8e67dbf..78f1a80 100644
--- a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master
+++ b/t/t4013/diff.format-patch_--stdout_--numbered_initial..master
@@ -53,7 +53,7 @@ Subject: [PATCH 2/3] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -88,7 +88,7 @@ Subject: [PATCH 3/3] Side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..master
index 7b89978..a3dab7f 100644
--- a/t/t4013/diff.format-patch_--stdout_initial..master
+++ b/t/t4013/diff.format-patch_--stdout_initial..master
@@ -53,7 +53,7 @@ Subject: [PATCH 2/3] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -88,7 +88,7 @@ Subject: [PATCH 3/3] Side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..master^
index b7f9725..39f4a3f 100644
--- a/t/t4013/diff.format-patch_--stdout_initial..master^
+++ b/t/t4013/diff.format-patch_--stdout_initial..master^
@@ -53,7 +53,7 @@ Subject: [PATCH 2/2] Third
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.format-patch_--stdout_initial..side b/t/t4013/diff.format-patch_--stdout_initial..side
index e765088..8810920 100644
--- a/t/t4013/diff.format-patch_--stdout_initial..side
+++ b/t/t4013/diff.format-patch_--stdout_initial..side
@@ -8,7 +8,7 @@ Subject: [PATCH] Side
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
index bd7f5c0..4085bbd 100644
--- a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
+++ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
@@ -13,7 +13,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
     Side
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -32,7 +32,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
     Third
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -54,7 +54,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     This is the second commit.
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..8422d40 100644
diff --git a/t/t4013/diff.log_--patch-with-stat_master b/t/t4013/diff.log_--patch-with-stat_master
index 14595a6..4586279 100644
--- a/t/t4013/diff.log_--patch-with-stat_master
+++ b/t/t4013/diff.log_--patch-with-stat_master
@@ -15,7 +15,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -56,7 +56,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
diff --git a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_
index 5a4e727..6e172cf 100644
--- a/t/t4013/diff.log_--patch-with-stat_master_--_dir_
+++ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_
@@ -13,7 +13,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
     Side
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -32,7 +32,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
     Third
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -54,7 +54,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     This is the second commit.
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..8422d40 100644
diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
index df0aaa9..48b0d4b 100644
--- a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
 index cead32e,7289e35..992913c
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -89,7 +89,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -165,7 +165,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master
index c11b5f2c..f9dc512 100644
--- a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master
@@ -15,7 +15,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -57,7 +57,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -133,7 +133,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.log_--root_--patch-with-stat_master b/t/t4013/diff.log_--root_--patch-with-stat_master
index 5f0c98f..0807ece 100644
--- a/t/t4013/diff.log_--root_--patch-with-stat_master
+++ b/t/t4013/diff.log_--root_--patch-with-stat_master
@@ -15,7 +15,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -56,7 +56,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -130,7 +130,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
index e62c368..84f5ef6 100644
--- a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --combined dir/sub
 index cead32e,7289e35..992913c
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -89,7 +89,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -165,7 +165,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.show_--patch-with-stat_--summary_side b/t/t4013/diff.show_--patch-with-stat_--summary_side
index 377f2b7..e60384d 100644
--- a/t/t4013/diff.show_--patch-with-stat_--summary_side
+++ b/t/t4013/diff.show_--patch-with-stat_--summary_side
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
diff --git a/t/t4013/diff.show_--patch-with-stat_side b/t/t4013/diff.show_--patch-with-stat_side
index fb14c53..a3a3255 100644
--- a/t/t4013/diff.show_--patch-with-stat_side
+++ b/t/t4013/diff.show_--patch-with-stat_side
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
diff --git a/t/t4013/diff.show_--stat_--summary_side b/t/t4013/diff.show_--stat_--summary_side
index 5bd5977..d16f464 100644
--- a/t/t4013/diff.show_--stat_--summary_side
+++ b/t/t4013/diff.show_--stat_--summary_side
@@ -8,6 +8,6 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 $
diff --git a/t/t4013/diff.show_--stat_side b/t/t4013/diff.show_--stat_side
index 3b22327..6300c05 100644
--- a/t/t4013/diff.show_--stat_side
+++ b/t/t4013/diff.show_--stat_side
@@ -8,5 +8,5 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 $
diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
index 6a467cc..16ae543 100644
--- a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
+++ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
@@ -6,7 +6,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
     Side
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -25,7 +25,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
     Third
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     This is the second commit.
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..8422d40 100644
diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master b/t/t4013/diff.whatchanged_--patch-with-stat_master
index 1e1bbe1..f3e45ec 100644
--- a/t/t4013/diff.whatchanged_--patch-with-stat_master
+++ b/t/t4013/diff.whatchanged_--patch-with-stat_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -49,7 +49,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
index 13789f1..c77f0bc 100644
--- a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
+++ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
@@ -6,7 +6,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
     Side
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -25,7 +25,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
     Third
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:01:00 2006 +0000
     This is the second commit.
 ---
  dir/sub |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
+ 1 file changed, 2 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..8422d40 100644
diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
index e96ff1f..8d03efe 100644
--- a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --cc dir/sub
 index cead32e,7289e35..992913c
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -89,7 +89,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -165,7 +165,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
index 0291153..1874d06 100644
--- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -50,7 +50,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -126,7 +126,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master
index 9b0349c..5211ff2 100644
--- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master
+++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 35d242b..7289e35 100644
@@ -49,7 +49,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 index 8422d40..cead32e 100644
@@ -123,7 +123,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
 
 diff --git a/dir/sub b/dir/sub
 new file mode 100644
diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
index c0aff68..ad30245 100644
--- a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
+++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
@@ -8,7 +8,7 @@ Date:   Mon Jun 26 00:04:00 2006 +0000
 
  dir/sub |    2 ++
  file0   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
 
 diff --combined dir/sub
 index cead32e,7289e35..992913c
@@ -47,7 +47,7 @@ Date:   Mon Jun 26 00:03:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file3   |    4 ++++
- 3 files changed, 9 insertions(+), 0 deletions(-)
+ 3 files changed, 9 insertions(+)
  create mode 100644 file3
 
 diff --git a/dir/sub b/dir/sub
@@ -89,7 +89,7 @@ Date:   Mon Jun 26 00:02:00 2006 +0000
 ---
  dir/sub |    2 ++
  file1   |    3 +++
- 2 files changed, 5 insertions(+), 0 deletions(-)
+ 2 files changed, 5 insertions(+)
  create mode 100644 file1
 
 diff --git a/dir/sub b/dir/sub
@@ -165,7 +165,7 @@ Date:   Mon Jun 26 00:00:00 2006 +0000
  dir/sub |    2 ++
  file0   |    3 +++
  file2   |    3 +++
- 3 files changed, 8 insertions(+), 0 deletions(-)
+ 3 files changed, 8 insertions(+)
  create mode 100644 dir/sub
  create mode 100644 file0
  create mode 100644 file2
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 6797512..7dfe716 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -520,7 +520,7 @@ test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
 cat > expect << EOF
 ---
  file |   16 ++++++++++++++++
- 1 files changed, 16 insertions(+), 0 deletions(-)
+ 1 file changed, 16 insertions(+)
 
 diff --git a/file b/file
 index 40f36c6..2dc5c23 100644
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index 88c5619..4ac162c 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -86,7 +86,7 @@ test_expect_success 'status -v produces text' '
 
 cat >expect.stat <<'EOF'
  file |  Bin 2 -> 4 bytes
- 1 files changed, 0 insertions(+), 0 deletions(-)
+ 1 file changed, 0 insertions(+), 0 deletions(-)
 EOF
 test_expect_success 'diffstat does not run textconv' '
 	echo file diff=fail >.gitattributes &&
diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh
index 8a3c63b..bd119be 100755
--- a/t/t4045-diff-relative.sh
+++ b/t/t4045-diff-relative.sh
@@ -33,7 +33,7 @@ check_stat() {
 expect=$1; shift
 cat >expected <<EOF
  $expect |    1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
 EOF
 test_expect_success "--stat $*" "
 	git diff --stat $* HEAD^ >actual &&
diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh
index 641e70d..a6d1887 100755
--- a/t/t4049-diff-stat-count.sh
+++ b/t/t4049-diff-stat-count.sh
@@ -16,7 +16,7 @@ test_expect_success setup '
 	cat >expect <<-\EOF
 	 a |    1 +
 	 b |    1 +
-	 2 files changed, 2 insertions(+), 0 deletions(-)
+	 2 files changed, 2 insertions(+)
 	EOF
 	git diff --stat --stat-count=2 >actual &&
 	test_cmp expect actual
diff --git a/t/t4100/t-apply-8.expect b/t/t4100/t-apply-8.expect
index eef7f2e..55a55c3 100644
--- a/t/t4100/t-apply-8.expect
+++ b/t/t4100/t-apply-8.expect
@@ -1,2 +1,2 @@
  t/t4100-apply-stat.sh |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/t/t4100/t-apply-9.expect b/t/t4100/t-apply-9.expect
index eef7f2e..55a55c3 100644
--- a/t/t4100/t-apply-9.expect
+++ b/t/t4100/t-apply-9.expect
@@ -1,2 +1,2 @@
  t/t4100-apply-stat.sh |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh
index da25bc2..34c482f 100755
--- a/t/t5150-request-pull.sh
+++ b/t/t5150-request-pull.sh
@@ -95,7 +95,7 @@ test_expect_success 'setup: two scripts for reading pull requests' '
 	b
 	: diffstat
 	n
-	/ [0-9]* files changed/ {
+	/ [0-9]* files\? changed/ {
 		a\\
 	DIFFSTAT
 		b
diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh
index 61f36ba..5783ebf 100755
--- a/t/t7602-merge-octopus-many.sh
+++ b/t/t7602-merge-octopus-many.sh
@@ -57,7 +57,7 @@ Merge made by the 'octopus' strategy.
  c2.c |    1 +
  c3.c |    1 +
  c4.c |    1 +
- 3 files changed, 3 insertions(+), 0 deletions(-)
+ 3 files changed, 3 insertions(+)
  create mode 100644 c2.c
  create mode 100644 c3.c
  create mode 100644 c4.c
@@ -74,7 +74,7 @@ Already up-to-date with c4
 Trying simple merge with c5
 Merge made by the 'octopus' strategy.
  c5.c |    1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ 1 file changed, 1 insertion(+)
  create mode 100644 c5.c
 EOF
 
@@ -89,7 +89,7 @@ Trying simple merge with c2
 Merge made by the 'octopus' strategy.
  c1.c |    1 +
  c2.c |    1 +
- 2 files changed, 2 insertions(+), 0 deletions(-)
+ 2 files changed, 2 insertions(+)
  create mode 100644 c1.c
  create mode 100644 c2.c
 EOF
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* Re: [PATCH] gitk: make "git describe" output clickable, too
From: Jim Meyering @ 2012-02-01 13:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Paul Mackerras, git list
In-Reply-To: <7v62hl4llk.fsf@alter.siamese.dyndns.org>

Junio C Hamano wrote:
> Jim Meyering <jim@meyering.net> writes:
>
>> I noticed that automake's contribution guidelines suggest using
>> "git describe" output in commit logs to reference previous commits.
>> By contrast, in coreutils, I had acquired the habit of using a bare SHA1
>> prefix (8 hex digits), since gitk creates clickable links for that, and
>> not for "git describe" output.
>>
>> I prefer the readability of the full "git describe" output, yet want to
>> retain the gitk links, so wrote the following that renders as clickable
>> not just SHA1-like strings, but also an SHA1-like string that is
>> prefixed by "-g".
>>
>> Signed-off-by: Jim Meyering <meyering@redhat.com>
>> ---
>> This is relative to master.
>> Think of this as mere proof-of-concept:
>
> Paul, I think this makes tons of sense. Comments?

Thanks for the feedback, Junio.

>> Ideally, the string preceding the -g would be used to disambiguate
>> the SHA1 prefix, but that would require more code.
>>
>> I confess that I haven't looked to see if documentation needs
>> to be updated or if this would merit test suite additions.
>>
>>  gitk-git/gitk |    6 +++++-
>>  1 files changed, 5 insertions(+), 1 deletions(-)
>>
>> diff --git a/gitk-git/gitk b/gitk-git/gitk
>> index 4cde0c4..f8eb613 100755
>> --- a/gitk-git/gitk
>> +++ b/gitk-git/gitk
>> @@ -6688,7 +6688,7 @@ proc appendwithlinks {text tags} {
>>
>>      set start [$ctext index "end - 1c"]
>>      $ctext insert end $text $tags
>> -    set links [regexp -indices -all -inline {\m[0-9a-f]{6,40}\M} $text]
>> +    set links [regexp -indices -all -inline {(?:\m|-g)[0-9a-f]{6,40}\M} $text]
>>      foreach l $links {
>>  	set s [lindex $l 0]
>>  	set e [lindex $l 1]
>> @@ -6704,6 +6704,10 @@ proc appendwithlinks {text tags} {
>>  proc setlink {id lk} {
>>      global curview ctext pendinglinks
>>
>> +    if {[string range $id 0 1] eq "-g"} {
>> +      set id [string range $id 2 end]
>> +    }
>> +
>>      set known 0
>>      if {[string length $id] < 40} {
>>  	set matches [longid $id]
>> --
>> 1.7.8.163.g9859a

^ permalink raw reply

* [PATCH v3 1/2] Factor find_pack_entry()'s core out
From: Nguyễn Thái Ngọc Duy @ 2012-02-01 13:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nicolas Pitre,
	Nguyễn Thái Ngọc Duy
In-Reply-To: <1328010239-29669-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 sha1_file.c |   59 +++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/sha1_file.c b/sha1_file.c
index 88f2151..ff5bf42 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2010,11 +2010,42 @@ int is_pack_valid(struct packed_git *p)
 	return !open_packed_git(p);
 }
 
+static int find_pack_entry_1(const unsigned char *sha1,
+			     struct packed_git *p, struct pack_entry *e)
+{
+	off_t offset;
+	if (p->num_bad_objects) {
+		unsigned i;
+		for (i = 0; i < p->num_bad_objects; i++)
+			if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
+				return 0;
+	}
+
+	offset = find_pack_entry_one(sha1, p);
+	if (!offset)
+		return 0;
+
+	/*
+	 * We are about to tell the caller where they can locate the
+	 * requested object.  We better make sure the packfile is
+	 * still here and can be accessed before supplying that
+	 * answer, as it may have been deleted since the index was
+	 * loaded!
+	 */
+	if (!is_pack_valid(p)) {
+		warning("packfile %s cannot be accessed", p->pack_name);
+		return 0;
+	}
+	e->offset = offset;
+	e->p = p;
+	hashcpy(e->sha1, sha1);
+	return 1;
+}
+
 static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
 {
 	static struct packed_git *last_found = (void *)1;
 	struct packed_git *p;
-	off_t offset;
 
 	prepare_packed_git();
 	if (!packed_git)
@@ -2022,35 +2053,11 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
 	p = (last_found == (void *)1) ? packed_git : last_found;
 
 	do {
-		if (p->num_bad_objects) {
-			unsigned i;
-			for (i = 0; i < p->num_bad_objects; i++)
-				if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
-					goto next;
-		}
-
-		offset = find_pack_entry_one(sha1, p);
-		if (offset) {
-			/*
-			 * We are about to tell the caller where they can
-			 * locate the requested object.  We better make
-			 * sure the packfile is still here and can be
-			 * accessed before supplying that answer, as
-			 * it may have been deleted since the index
-			 * was loaded!
-			 */
-			if (!is_pack_valid(p)) {
-				warning("packfile %s cannot be accessed", p->pack_name);
-				goto next;
-			}
-			e->offset = offset;
-			e->p = p;
-			hashcpy(e->sha1, sha1);
+		if (find_pack_entry_1(sha1, p, e)) {
 			last_found = p;
 			return 1;
 		}
 
-		next:
 		if (p == last_found)
 			p = packed_git;
 		else
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* [PATCH v3 2/2] find_pack_entry(): do not keep packed_git pointer locally
From: Nguyễn Thái Ngọc Duy @ 2012-02-01 13:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nicolas Pitre,
	Nguyễn Thái Ngọc Duy
In-Reply-To: <1328104135-475-1-git-send-email-pclouds@gmail.com>

Commit f7c22cc (always start looking up objects in the last used pack
first - 2007-05-30) introduce a static packed_git* pointer as an
optimization.  The kept pointer however may become invalid if
free_pack_by_name() happens to free that particular pack.

Current code base does not access packs after calling
free_pack_by_name() so it should not be a problem. Anyway, move the
pointer out so that free_pack_by_name() can reset it to avoid running
into troubles in future.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Since Junio's already done the hard work. It'd be silly of me not to
 take advantage and credit for free :)

 The new loop looks much better.

 sha1_file.c |   27 +++++++++++++--------------
 1 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/sha1_file.c b/sha1_file.c
index ff5bf42..ebe77b3 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -54,6 +54,8 @@ static struct cached_object empty_tree = {
 	0
 };
 
+static struct packed_git *last_found_pack;
+
 static struct cached_object *find_cached_object(const unsigned char *sha1)
 {
 	int i;
@@ -720,6 +722,8 @@ void free_pack_by_name(const char *pack_name)
 			close_pack_index(p);
 			free(p->bad_object_sha1);
 			*pp = p->next;
+			if (last_found_pack == p)
+				last_found_pack = NULL;
 			free(p);
 			return;
 		}
@@ -2044,27 +2048,22 @@ static int find_pack_entry_1(const unsigned char *sha1,
 
 static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
 {
-	static struct packed_git *last_found = (void *)1;
 	struct packed_git *p;
 
 	prepare_packed_git();
 	if (!packed_git)
 		return 0;
-	p = (last_found == (void *)1) ? packed_git : last_found;
 
-	do {
-		if (find_pack_entry_1(sha1, p, e)) {
-			last_found = p;
-			return 1;
-		}
+	if (last_found_pack && find_pack_entry_1(sha1, last_found_pack, e))
+		return 1;
 
-		if (p == last_found)
-			p = packed_git;
-		else
-			p = p->next;
-		if (p == last_found)
-			p = p->next;
-	} while (p);
+	for (p = packed_git; p; p = p->next) {
+		if (p == last_found_pack || !find_pack_entry_1(sha1, p, e))
+			continue;
+
+		last_found_pack = p;
+		return 1;
+	}
 	return 0;
 }
 
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* Re: [PATCH] pack-objects: convert to use parse_options()
From: Nguyen Thai Ngoc Duy @ 2012-02-01 14:30 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v4nvb78om.fsf@alter.siamese.dyndns.org>

I'm going to address your comments soon (thanks by the way, making up
summary line for each option from git-pack-objects.txt was painful)
but since you like thought-provoking, check this comment out:

	/* Traditionally "pack-objects [options] base extra" failed;
	 * we would however want to take refs parameter that would
	 * have been given to upstream rev-list ourselves, which means
	 * we somehow want to say what the base name is.  So the
	 * syntax would be:
	 *
	 * pack-objects [options] base <refs...>
	 *
	 * in other words, we would treat the first non-option as the
	 * base_name and send everything else to the internal revision
	 * walker.
	 */

The last paragraph does not hold true anymore as far as I understand
the code. IOW it drops everything in argv after base name. Looking
back in history, the change was made by 8d1d8f8 (pack-objects: further
work on internal rev-list logic. - 2006-09-06). Nothing is mentioned
why it drops the remaining of argv. I suspect this is a regression and
we should reinstate the behavior as the comment says.
-- 
Duy

^ permalink raw reply

* Re: [PATCH] pack-objects: convert to use parse_options()
From: Nguyen Thai Ngoc Duy @ 2012-02-01 14:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <CACsJy8CZm96pVkavq_LvpX-MxdOtBw7XuwsQF61FJE8qk6ZZTg@mail.gmail.com>

On Wed, Feb 1, 2012 at 9:30 PM, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
>        /* Traditionally "pack-objects [options] base extra" failed;
>         * we would however want to take refs parameter that would
>         * have been given to upstream rev-list ourselves, which means
>         * we somehow want to say what the base name is.  So the
>         * syntax would be:
>         *
>         * pack-objects [options] base <refs...>
>         *
>         * in other words, we would treat the first non-option as the
>         * base_name and send everything else to the internal revision
>         * walker.
>         */
>
> The last paragraph does not hold true anymore as far as I understand
> the code. IOW it drops everything in argv after base name. Looking
> back in history, the change was made by 8d1d8f8 (pack-objects: further
> work on internal rev-list logic. - 2006-09-06). Nothing is mentioned
> why it drops the remaining of argv. I suspect this is a regression and
> we should reinstate the behavior as the comment says.

Nope, false alarm. The comment was introduced in b5d97e6
(pack-objects: run rev-list equivalent internally. - 2006-09-04) and
the remaining of argv has been ignored ever since.
-- 
Duy

^ permalink raw reply

* [PATCH v2 2/3] pack-objects: remove bogus comment
From: Nguyễn Thái Ngọc Duy @ 2012-02-01 15:17 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1328109440-9510-1-git-send-email-pclouds@gmail.com>

The comment was introduced in b5d97e6 (pack-objects: run rev-list
equivalent internally. - 2006-09-04), stating that

git pack-objects [options] base-name <refs...>

is acceptable and refs should be passed into rev-list. But that's not
true. All arguments after base-name are ignored.

Remove the comment and reject this syntax (i.e. no more arguments after
base name)

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/pack-objects.c |   15 +--------------
 t/t5300-pack-object.sh |    4 ++++
 2 files changed, 5 insertions(+), 14 deletions(-)

diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 297f792..80e3114 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2484,23 +2484,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 		usage(pack_usage);
 	}
 
-	/* Traditionally "pack-objects [options] base extra" failed;
-	 * we would however want to take refs parameter that would
-	 * have been given to upstream rev-list ourselves, which means
-	 * we somehow want to say what the base name is.  So the
-	 * syntax would be:
-	 *
-	 * pack-objects [options] base <refs...>
-	 *
-	 * in other words, we would treat the first non-option as the
-	 * base_name and send everything else to the internal revision
-	 * walker.
-	 */
-
 	if (!pack_to_stdout)
 		base_name = argv[i++];
 
-	if (pack_to_stdout != !base_name)
+	if (pack_to_stdout != !base_name || argv[i])
 		usage(pack_usage);
 
 	if (!pack_to_stdout && !pack_size_limit)
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index 602806d..d9d856b 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -38,6 +38,10 @@ test_expect_success \
     'pack without delta' \
     'packname_1=$(git pack-objects --window=0 test-1 <obj-list)'
 
+test_expect_success \
+    'pack-objects with bogus arguments' \
+    'test_must_fail git pack-objects --window=0 test-1 blah blah <obj-list'
+
 rm -fr .git2
 mkdir .git2
 
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* [PATCH v2 3/3] pack-objects: convert to use parse_options()
From: Nguyễn Thái Ngọc Duy @ 2012-02-01 15:17 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1328109440-9510-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Regarding die() vs error() in option_parse_*, nope, using error()
 makes parse_options() print command usage, which is long and distracts
 users from the real error message. I'm going to stick with die().

 builtin/pack-objects.c |  315 +++++++++++++++++++++---------------------------
 1 files changed, 139 insertions(+), 176 deletions(-)

diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 80e3114..e21e5af 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -18,16 +18,11 @@
 #include "refs.h"
 #include "thread-utils.h"
 
-static const char pack_usage[] =
-  "git pack-objects [ -q | --progress | --all-progress ]\n"
-  "        [--all-progress-implied]\n"
-  "        [--max-pack-size=<n>] [--local] [--incremental]\n"
-  "        [--window=<n>] [--window-memory=<n>] [--depth=<n>]\n"
-  "        [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n"
-  "        [--threads=<n>] [--non-empty] [--revs [--unpacked | --all]]\n"
-  "        [--reflog] [--stdout | base-name] [--include-tag]\n"
-  "        [--keep-unreachable | --unpack-unreachable]\n"
-  "        [< ref-list | < object-list]";
+static const char *pack_usage[] = {
+	"git pack-objects --stdout [options...] [< ref-list | < object-list]",
+	"git pack-objects [options...] base-name [< ref-list | < object-list]",
+	NULL
+};
 
 struct object_entry {
 	struct pack_idx_entry idx;
@@ -2305,191 +2300,159 @@ static void get_object_list(int ac, const char **av)
 		loosen_unused_packed_objects(&revs);
 }
 
+static int option_parse_index_version(const struct option *opt,
+				      const char *arg, int unset)
+{
+	char *c;
+	const char *val = arg;
+	pack_idx_opts.version = strtoul(val, &c, 10);
+	if (pack_idx_opts.version > 2)
+		die(_("unsupported index version %s"), val);
+	if (*c == ',' && c[1])
+		pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
+	if (*c || pack_idx_opts.off32_limit & 0x80000000)
+		die(_("bad index version '%s'"), val);
+	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;
 	int thin = 0;
 	int all_progress_implied = 0;
-	uint32_t i;
-	const char **rp_av;
-	int rp_ac_alloc = 64;
-	int rp_ac;
+	const char *rp_av[6];
+	int rp_ac = 0;
+	int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
+	struct option pack_objects_options[] = {
+		OPT_SET_INT('q', "quiet", &progress,
+			    "do not show progress meter", 0),
+		OPT_SET_INT(0, "progress", &progress,
+			    "show progress meter", 1),
+		OPT_SET_INT(0, "all-progress", &progress,
+			    "show progress meter during object writing phase", 2),
+		OPT_BOOL(0, "all-progress-implied",
+			 &all_progress_implied,
+			 "similar to --all-progress when progress meter is shown"),
+		{ OPTION_CALLBACK, 0, "index-version", NULL, "version[,offset]",
+		  "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,
+			  "maximum size of each output pack file"),
+		OPT_BOOL(0, "local", &local,
+			 "ignore borrowed objects from alternate object store"),
+		OPT_BOOL(0, "incremental", &incremental,
+			 "ignore packed objects"),
+		OPT_INTEGER(0, "window", &window,
+			    "limit pack window by objects"),
+		OPT_ULONG(0, "window-memory", &window_memory_limit,
+			  "limit pack window by memory in addition to object limit"),
+		OPT_INTEGER(0, "depth", &depth,
+			    "maximum length of delta chain allowed in the resulting pack"),
+		OPT_BOOL(0, "reuse-delta", &reuse_delta,
+			 "reuse existing deltas"),
+		OPT_BOOL(0, "reuse-object", &reuse_object,
+			 "reuse existing objects"),
+		OPT_BOOL(0, "delta-base-offset", &allow_ofs_delta,
+			 "use OFS_DELTA objects"),
+		OPT_INTEGER(0, "threads", &delta_search_threads,
+			    "use threads when searching for best delta matches"),
+		OPT_BOOL(0, "non-empty", &non_empty,
+			 "do not create an empty pack output"),
+		OPT_BOOL(0, "revs", &use_internal_rev_list,
+			 "read revision arguments from standard input"),
+		{ OPTION_SET_INT, 0, "unpacked", &rev_list_unpacked, NULL,
+		  "limit the objects to those that are not yet packed",
+		  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+		{ OPTION_SET_INT, 0, "all", &rev_list_all, NULL,
+		  "include objects reachable from any reference",
+		  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+		{ OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
+		  "include objects referred by reflog entries",
+		  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+		OPT_BOOL(0, "stdout", &pack_to_stdout,
+			 "output pack to stdout"),
+		OPT_BOOL(0, "include-tag", &include_tag,
+			 "include tag objects that refer to objects to be packed"),
+		OPT_BOOL(0, "keep-unreachable", &keep_unreachable,
+			 "keep unreachable objects"),
+		OPT_BOOL(0, "unpack-unreachable", &unpack_unreachable,
+			 "unpack unreachable objects"),
+		OPT_BOOL(0, "thin", &thin,
+			 "create thin packs"),
+		OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
+			 "ignore packs that have companion .keep file"),
+		OPT_INTEGER(0, "compression", &pack_compression_level,
+			    "pack compression level"),
+		OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
+			    "do not hide commits by grafts", 0),
+		OPT_END(),
+	};
 
 	read_replace_refs = 0;
 
-	rp_av = xcalloc(rp_ac_alloc, sizeof(*rp_av));
-
-	rp_av[0] = "pack-objects";
-	rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
-	rp_ac = 2;
-
 	reset_pack_idx_option(&pack_idx_opts);
 	git_config(git_pack_config, NULL);
 	if (!pack_compression_seen && core_compression_seen)
 		pack_compression_level = core_compression_level;
 
 	progress = isatty(2);
-	for (i = 1; i < argc; i++) {
-		const char *arg = argv[i];
+	argc = parse_options(argc, argv, prefix, pack_objects_options,
+			     pack_usage, 0);
 
-		if (*arg != '-')
-			break;
-
-		if (!strcmp("--non-empty", arg)) {
-			non_empty = 1;
-			continue;
-		}
-		if (!strcmp("--local", arg)) {
-			local = 1;
-			continue;
-		}
-		if (!strcmp("--incremental", arg)) {
-			incremental = 1;
-			continue;
-		}
-		if (!strcmp("--honor-pack-keep", arg)) {
-			ignore_packed_keep = 1;
-			continue;
-		}
-		if (!prefixcmp(arg, "--compression=")) {
-			char *end;
-			int level = strtoul(arg+14, &end, 0);
-			if (!arg[14] || *end)
-				usage(pack_usage);
-			if (level == -1)
-				level = Z_DEFAULT_COMPRESSION;
-			else if (level < 0 || level > Z_BEST_COMPRESSION)
-				die("bad pack compression level %d", level);
-			pack_compression_level = level;
-			continue;
-		}
-		if (!prefixcmp(arg, "--max-pack-size=")) {
-			pack_size_limit_cfg = 0;
-			if (!git_parse_ulong(arg+16, &pack_size_limit))
-				usage(pack_usage);
-			continue;
-		}
-		if (!prefixcmp(arg, "--window=")) {
-			char *end;
-			window = strtoul(arg+9, &end, 0);
-			if (!arg[9] || *end)
-				usage(pack_usage);
-			continue;
-		}
-		if (!prefixcmp(arg, "--window-memory=")) {
-			if (!git_parse_ulong(arg+16, &window_memory_limit))
-				usage(pack_usage);
-			continue;
-		}
-		if (!prefixcmp(arg, "--threads=")) {
-			char *end;
-			delta_search_threads = strtoul(arg+10, &end, 0);
-			if (!arg[10] || *end || delta_search_threads < 0)
-				usage(pack_usage);
-#ifdef NO_PTHREADS
-			if (delta_search_threads != 1)
-				warning("no threads support, "
-					"ignoring %s", arg);
-#endif
-			continue;
-		}
-		if (!prefixcmp(arg, "--depth=")) {
-			char *end;
-			depth = strtoul(arg+8, &end, 0);
-			if (!arg[8] || *end)
-				usage(pack_usage);
-			continue;
-		}
-		if (!strcmp("--progress", arg)) {
-			progress = 1;
-			continue;
-		}
-		if (!strcmp("--all-progress", arg)) {
-			progress = 2;
-			continue;
-		}
-		if (!strcmp("--all-progress-implied", arg)) {
-			all_progress_implied = 1;
-			continue;
-		}
-		if (!strcmp("-q", arg)) {
-			progress = 0;
-			continue;
-		}
-		if (!strcmp("--no-reuse-delta", arg)) {
-			reuse_delta = 0;
-			continue;
-		}
-		if (!strcmp("--no-reuse-object", arg)) {
-			reuse_object = reuse_delta = 0;
-			continue;
-		}
-		if (!strcmp("--delta-base-offset", arg)) {
-			allow_ofs_delta = 1;
-			continue;
-		}
-		if (!strcmp("--stdout", arg)) {
-			pack_to_stdout = 1;
-			continue;
-		}
-		if (!strcmp("--revs", arg)) {
-			use_internal_rev_list = 1;
-			continue;
-		}
-		if (!strcmp("--keep-unreachable", arg)) {
-			keep_unreachable = 1;
-			continue;
-		}
-		if (!strcmp("--unpack-unreachable", arg)) {
-			unpack_unreachable = 1;
-			continue;
-		}
-		if (!strcmp("--include-tag", arg)) {
-			include_tag = 1;
-			continue;
-		}
-		if (!strcmp("--unpacked", arg) ||
-		    !strcmp("--reflog", arg) ||
-		    !strcmp("--all", arg)) {
-			use_internal_rev_list = 1;
-			if (rp_ac >= rp_ac_alloc - 1) {
-				rp_ac_alloc = alloc_nr(rp_ac_alloc);
-				rp_av = xrealloc(rp_av,
-						 rp_ac_alloc * sizeof(*rp_av));
-			}
-			rp_av[rp_ac++] = arg;
-			continue;
-		}
-		if (!strcmp("--thin", arg)) {
-			use_internal_rev_list = 1;
-			thin = 1;
-			rp_av[1] = "--objects-edge";
-			continue;
-		}
-		if (!prefixcmp(arg, "--index-version=")) {
-			char *c;
-			pack_idx_opts.version = strtoul(arg + 16, &c, 10);
-			if (pack_idx_opts.version > 2)
-				die("bad %s", arg);
-			if (*c == ',' && c[1])
-				pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
-			if (*c || pack_idx_opts.off32_limit & 0x80000000)
-				die("bad %s", arg);
-			continue;
-		}
-		if (!strcmp(arg, "--keep-true-parents")) {
-			grafts_replace_parents = 0;
-			continue;
-		}
-		usage(pack_usage);
+	if (argc) {
+		base_name = argv[0];
+		argc--;
 	}
+	if (pack_to_stdout != !base_name || argc)
+		usage_with_options(pack_usage, pack_objects_options);
 
-	if (!pack_to_stdout)
-		base_name = argv[i++];
+	rp_av[rp_ac++] = "pack-objects";
+	if (thin) {
+		use_internal_rev_list = 1;
+		rp_av[rp_ac++] = "--objects-edge";
+	} else
+		rp_av[rp_ac++] = "--objects";
 
-	if (pack_to_stdout != !base_name || argv[i])
-		usage(pack_usage);
+	if (rev_list_all) {
+		use_internal_rev_list = 1;
+		rp_av[rp_ac++] = "--all";
+	}
+	if (rev_list_reflog) {
+		use_internal_rev_list = 1;
+		rp_av[rp_ac++] = "--reflog";
+	}
+	if (rev_list_unpacked) {
+		use_internal_rev_list = 1;
+		rp_av[rp_ac++] = "--unpacked";
+	}
 
+	if (!reuse_object)
+		reuse_delta = 0;
+	if (pack_compression_level == -1)
+		pack_compression_level = Z_DEFAULT_COMPRESSION;
+	else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)
+		die("bad pack compression level %d", pack_compression_level);
+#ifdef NO_PTHREADS
+	if (delta_search_threads != 1)
+		warning("no threads support, ignoring %s", arg);
+#endif
 	if (!pack_to_stdout && !pack_size_limit)
 		pack_size_limit = pack_size_limit_cfg;
 	if (pack_to_stdout && pack_size_limit)
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* [PATCH v2 1/3] pack-objects: do not accept "--index-version=version,"
From: Nguyễn Thái Ngọc Duy @ 2012-02-01 15:17 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1328017702-14489-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/pack-objects.c |    2 +-
 t/t5302-pack-index.sh  |    4 ++++
 2 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 0f2e7b8..297f792 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2471,7 +2471,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 			pack_idx_opts.version = strtoul(arg + 16, &c, 10);
 			if (pack_idx_opts.version > 2)
 				die("bad %s", arg);
-			if (*c == ',')
+			if (*c == ',' && c[1])
 				pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
 			if (*c || pack_idx_opts.off32_limit & 0x80000000)
 				die("bad %s", arg);
diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh
index f8fa924..fe82025 100755
--- a/t/t5302-pack-index.sh
+++ b/t/t5302-pack-index.sh
@@ -74,6 +74,10 @@ test_expect_success 'index-pack --verify on index version 2' '
 '
 
 test_expect_success \
+    'pack-objects --index-version=2, is not accepted' \
+    'test_must_fail git pack-objects --index-version=2, test-3 <obj-list'
+
+test_expect_success \
     'index v2: force some 64-bit offsets with pack-objects' \
     'pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)'
 
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* [PATCH] i18n: po for zh_cn
From: Jiang Xin @ 2012-02-01 15:50 UTC (permalink / raw)
  To: Git List, Junio C Hamano; +Cc: Jiang Xin

Git can speak Chinese now.

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 po/zh_cn.po | 3568 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 个文件被修改, 3568 处添加(+), 0 处删除(-)
 create mode 100644 po/zh_cn.po

diff --git a/po/zh_cn.po b/po/zh_cn.po
new file mode 100644
index 00000..61a5b
--- /dev/null
+++ b/po/zh_cn.po
@@ -0,0 +1,3568 @@
+# Chinese translations for Git package
+# Git 软件包的简体中文翻译.
+# Copyright (C) 2012 Jiang Xin <worldhello.net AT gmail.com>
+# This file is distributed under the same license as the Git package.
+# Contributers:
+#   - Jiang Xin <worldhello.net AT gmail.com>
+#   - Riku <lu.riku AT gmail.com>
+#   - Zhuang Ya <zhuangya AT me.com>
+#   - Lian Cheng <rhythm.mail AT gmail.com>
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Git\n"
+"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
+"POT-Creation-Date: 2012-02-01 20:52+0800\n"
+"PO-Revision-Date: 2012-01-30 00:00+0800\n"
+"Last-Translator: riku <lu.riku@gmail.com>\n"
+"Language-Team: GitHub <https://github.com/gotgit/git-l10n-zh-cn/>\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: commit.c:47
+#, c-format
+msgid "could not parse %s"
+msgstr "不能解析 %s"
+
+#: commit.c:49
+#, c-format
+msgid "%s %s is not a commit!"
+msgstr "%s %s 不是一个提交!"
+
+#: compat/obstack.c:406 compat/obstack.c:408
+msgid "memory exhausted"
+msgstr "内存耗尽"
+
+#: connected.c:39
+msgid "Could not run 'git rev-list'"
+msgstr "不能执行 'git rev-list'"
+
+#: connected.c:48
+#, c-format
+msgid "failed write to rev-list: %s"
+msgstr "无法写入 rev-list:%s"
+
+#: connected.c:56
+#, c-format
+msgid "failed to close rev-list's stdin: %s"
+msgstr "无法关闭 rev-list 的标准输入:%s"
+
+#  注意保持前导空格
+#: diff.c:104
+#, c-format
+msgid "  Failed to parse dirstat cut-off percentage '%.*s'\n"
+msgstr "  无法解析 dirstat 阈值 '%.*s'\n"
+
+#  注意保持前导空格
+#: diff.c:109
+#, c-format
+msgid "  Unknown dirstat parameter '%.*s'\n"
+msgstr "  未知 dirstat 参数 '%.*s'\n"
+
+#: diff.c:208
+#, c-format
+msgid ""
+"Found errors in 'diff.dirstat' config variable:\n"
+"%s"
+msgstr ""
+"配置变量 'diff.dirstat' 出错:\n"
+"%s"
+
+#: diff.c:1479 diff.c:1510 builtin/apply.c:3244
+#, c-format
+msgid " %d files changed, %d insertions(+), %d deletions(-)\n"
+msgstr " %d 个文件被修改, %d 处添加(+), %d 处删除(-)\n"
+
+#: diff.c:3308
+#, c-format
+msgid ""
+"Failed to parse --dirstat/-X option parameter:\n"
+"%s"
+msgstr ""
+"无法解析 --dirstat/-X 选项的参数:\n"
+"%s"
+
+#: gpg-interface.c:59
+msgid "could not run gpg."
+msgstr "不能执行 gpg。"
+
+#: gpg-interface.c:71
+msgid "gpg did not accept the data"
+msgstr "gpg 没有接受数据"
+
+#: gpg-interface.c:82
+msgid "gpg failed to sign the data"
+msgstr "gpg 无法为数据签名"
+
+#: help.c:309
+#, c-format
+msgid ""
+"'%s' appears to be a git command, but we were not\n"
+"able to execute it. Maybe git-%s is broken?"
+msgstr ""
+"'%s' 像是一个 git 命令,但却无法运行。\n"
+"可能是 git-%s 受损?"
+
+#: remote.c:1575
+#, c-format
+msgid "Your branch is ahead of '%s' by %d %s.\n"
+msgstr "您的分支领先 '%s' 共 %d 个%s。\n"
+
+#: remote.c:1577 remote.c:1582
+msgid "commit"
+msgid_plural "commits"
+msgstr[0] "提交"
+
+#: remote.c:1579
+#, c-format
+msgid "Your branch is behind '%s' by %d %s, and can be fast-forwarded.\n"
+msgstr "您的分支落后 '%s' 共 %d 个%s,且可以快进式推送。\n"
+
+#: remote.c:1584
+#, c-format
+msgid ""
+"Your branch and '%s' have diverged,\n"
+"and have %d and %d different commit(s) each, respectively.\n"
+msgstr ""
+"您的分支和 '%s' 出现了偏离,\n"
+"并且各自分别有 %d 和 %d 处不同的提交。\n"
+
+#: wt-status.c:134
+msgid "Unmerged paths:"
+msgstr "未合并的路径:"
+
+#  注意保持前导空格
+#: wt-status.c:140 wt-status.c:157
+#, c-format
+msgid "  (use \"git reset %s <file>...\" to unstage)"
+msgstr "  (使用 \"git reset %s <file>...\" 撤出暂存区)"
+
+#  注意保持前导空格
+#: wt-status.c:142 wt-status.c:159
+msgid "  (use \"git rm --cached <file>...\" to unstage)"
+msgstr "  (使用 \"git rm --cached <file>...\" 撤出暂存区)"
+
+#  注意保持前导空格
+#: wt-status.c:143
+msgid "  (use \"git add/rm <file>...\" as appropriate to mark resolution)"
+msgstr "  (酌情使用 \"git add/rm <file>...\" 标记解决方案)"
+
+#: wt-status.c:151
+msgid "Changes to be committed:"
+msgstr "要提交的变更:"
+
+#: wt-status.c:169
+msgid "Changes not staged for commit:"
+msgstr "未暂存至提交的变更:"
+
+#  注意保持前导空格
+#: wt-status.c:173
+msgid "  (use \"git add <file>...\" to update what will be committed)"
+msgstr "  (使用 \"git add <file>...\" 更新要提交的内容)"
+
+#  注意保持前导空格
+#: wt-status.c:175
+msgid "  (use \"git add/rm <file>...\" to update what will be committed)"
+msgstr "  (使用 \"git add/rm <file>...\" 更新要提交的内容)"
+
+#  注意保持前导空格
+#: wt-status.c:176
+msgid ""
+"  (use \"git checkout -- <file>...\" to discard changes in working directory)"
+msgstr "  (使用 \"git checkout -- <file>...\" 丢弃工作区的改动)"
+
+#  注意保持前导空格
+#: wt-status.c:178
+msgid "  (commit or discard the untracked or modified content in submodules)"
+msgstr "  (提交或丢弃子模组中未跟踪或修改的内容)"
+
+#: wt-status.c:187
+#, c-format
+msgid "%s files:"
+msgstr "%s文件:"
+
+#  注意保持前导空格
+#: wt-status.c:190
+#, c-format
+msgid "  (use \"git %s <file>...\" to include in what will be committed)"
+msgstr "  (使用 \"git %s <file>...\" 包含到提交列表)"
+
+#: wt-status.c:207
+msgid "bug"
+msgstr "bug"
+
+#: wt-status.c:212
+msgid "both deleted:"
+msgstr "双方删除:"
+
+#: wt-status.c:213
+msgid "added by us:"
+msgstr "由我们添加:"
+
+#: wt-status.c:214
+msgid "deleted by them:"
+msgstr "由他们删除:"
+
+#: wt-status.c:215
+msgid "added by them:"
+msgstr "由他们添加:"
+
+#: wt-status.c:216
+msgid "deleted by us:"
+msgstr "由我们删除:"
+
+#: wt-status.c:217
+msgid "both added:"
+msgstr "双方添加:"
+
+#: wt-status.c:218
+msgid "both modified:"
+msgstr "双方修改:"
+
+#: wt-status.c:248
+msgid "new commits, "
+msgstr "新提交,"
+
+#: wt-status.c:250
+msgid "modified content, "
+msgstr "修改的内容,"
+
+#: wt-status.c:252
+msgid "untracked content, "
+msgstr "未跟踪的内容,"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:266
+#, c-format
+msgid "new file:   %s"
+msgstr "新文件:    %s"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:269
+#, c-format
+msgid "copied:     %s -> %s"
+msgstr "拷贝:      %s -> %s"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:272
+#, c-format
+msgid "deleted:    %s"
+msgstr "删除:      %s"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:275
+#, c-format
+msgid "modified:   %s"
+msgstr "修改:      %s"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:278
+#, c-format
+msgid "renamed:    %s -> %s"
+msgstr "重命名:    %s -> %s"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:281
+#, c-format
+msgid "typechange: %s"
+msgstr "类型变更:  %s"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:284
+#, c-format
+msgid "unknown:    %s"
+msgstr "未知:      %s"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: wt-status.c:287
+#, c-format
+msgid "unmerged:   %s"
+msgstr "未合并:    %s"
+
+#: wt-status.c:290
+#, c-format
+msgid "bug: unhandled diff status %c"
+msgstr "bug: 未处理的差异状态 %c"
+
+#: wt-status.c:713
+msgid "On branch "
+msgstr "位于分支 "
+
+#: wt-status.c:720
+msgid "Not currently on any branch."
+msgstr "当前不在任何分支上。"
+
+#: wt-status.c:731
+msgid "Initial commit"
+msgstr "初始提交"
+
+#: wt-status.c:745
+msgid "Untracked"
+msgstr "未跟踪的"
+
+#: wt-status.c:747
+msgid "Ignored"
+msgstr "忽略的"
+
+#: wt-status.c:749
+#, c-format
+msgid "Untracked files not listed%s"
+msgstr "未跟踪的文件没有列出%s"
+
+#  注意保持前导空格
+#: wt-status.c:751
+msgid " (use -u option to show untracked files)"
+msgstr " (使用 -u 参数显示未跟踪的文件)"
+
+#: wt-status.c:757
+msgid "No changes"
+msgstr "没有修改"
+
+#: wt-status.c:761
+#, c-format
+msgid "no changes added to commit%s\n"
+msgstr "修改尚未加入提交%s\n"
+
+#  注意保持前导空格
+#: wt-status.c:763
+msgid " (use \"git add\" and/or \"git commit -a\")"
+msgstr " (使用 \"git add\" 和/或 \"git commit -a\")"
+
+#: wt-status.c:765
+#, c-format
+msgid "nothing added to commit but untracked files present%s\n"
+msgstr "空提交但存在未跟踪文件%s\n"
+
+#  注意保持前导空格
+#: wt-status.c:767
+msgid " (use \"git add\" to track)"
+msgstr " (使用 \"git add\" 建立跟踪)"
+
+#: wt-status.c:769 wt-status.c:772 wt-status.c:775
+#, c-format
+msgid "nothing to commit%s\n"
+msgstr "无须提交%s\n"
+
+#  注意保持前导空格
+#: wt-status.c:770
+msgid " (create/copy files and use \"git add\" to track)"
+msgstr " (新建/拷贝的文件使用 \"git add\" 建立跟踪)"
+
+#  注意保持前导空格
+#: wt-status.c:773
+msgid " (use -u to show untracked files)"
+msgstr " (使用 -u 显示未跟踪文件)"
+
+#  注意保持前导空格
+#: wt-status.c:776
+msgid " (working directory clean)"
+msgstr " (干净的工作区)"
+
+#: wt-status.c:884
+msgid "HEAD (no branch)"
+msgstr "头(非分支)"
+
+#  注意保持句尾空格
+#: wt-status.c:890
+msgid "Initial commit on "
+msgstr "初始提交于 "
+
+#  注意保持句尾空格
+#: wt-status.c:905
+msgid "behind "
+msgstr "落后 "
+
+#  注意保持句尾空格
+#: wt-status.c:908 wt-status.c:911
+msgid "ahead "
+msgstr "领先 "
+
+#  注意保持句尾空格
+#: wt-status.c:913
+msgid ", behind "
+msgstr ",落后 "
+
+#: builtin/add.c:62
+#, c-format
+msgid "unexpected diff status %c"
+msgstr "意外的差异状态 %c"
+
+#: builtin/add.c:67 builtin/commit.c:298
+msgid "updating files failed"
+msgstr "更新文件失败"
+
+#: builtin/add.c:77
+#, c-format
+msgid "remove '%s'\n"
+msgstr "删除 '%s'\n"
+
+#: builtin/add.c:176
+#, c-format
+msgid "Path '%s' is in submodule '%.*s'"
+msgstr "路径 '%s' 属于模组 '%.*s'"
+
+#: builtin/add.c:192
+msgid "Unstaged changes after refreshing the index:"
+msgstr "刷新暂存区后未暂存的变更:"
+
+#: builtin/add.c:195 builtin/add.c:455 builtin/rm.c:186
+#, c-format
+msgid "pathspec '%s' did not match any files"
+msgstr "路径 '%s' 未匹配任何文件"
+
+#: builtin/add.c:209
+#, c-format
+msgid "'%s' is beyond a symbolic link"
+msgstr "'%s' 位于符号链接中"
+
+#: builtin/add.c:276
+msgid "Could not read the index"
+msgstr "无法读取暂存区"
+
+#: builtin/add.c:285
+#, c-format
+msgid "Could not open '%s' for writing."
+msgstr "无法打开 '%s' 以写入。"
+
+#: builtin/add.c:289
+msgid "Could not write patch"
+msgstr "无法写补丁"
+
+#: builtin/add.c:294
+#, c-format
+msgid "Could not stat '%s'"
+msgstr "无法查看文件状态 '%s'"
+
+#: builtin/add.c:296
+msgid "Empty patch. Aborted."
+msgstr "空补丁。异常终止。"
+
+#: builtin/add.c:302
+#, c-format
+msgid "Could not apply '%s'"
+msgstr "无法应用 '%s'"
+
+#: builtin/add.c:311
+msgid "The following paths are ignored by one of your .gitignore files:\n"
+msgstr "下列路径被您的一个 .gitignore 文件所忽略:\n"
+
+#: builtin/add.c:351
+#, c-format
+msgid "Use -f if you really want to add them.\n"
+msgstr "使用 -f 参数如果你确实要添加它们。\n"
+
+#: builtin/add.c:352
+msgid "no files added"
+msgstr "没有文件被添加"
+
+#: builtin/add.c:358
+msgid "adding files failed"
+msgstr "添加文件失败"
+
+#: builtin/add.c:390
+msgid "-A and -u are mutually incompatible"
+msgstr "-A 和 -u 选项互斥"
+
+#: builtin/add.c:392
+msgid "Option --ignore-missing can only be used together with --dry-run"
+msgstr "选项 --ignore-missing 只能和 --dry-run 共用"
+
+#: builtin/add.c:412
+#, c-format
+msgid "Nothing specified, nothing added.\n"
+msgstr "未提供参数,没有文件被添加。\n"
+
+#: builtin/add.c:413
+#, c-format
+msgid "Maybe you wanted to say 'git add .'?\n"
+msgstr "也许您想要执行 'git add .'?\n"
+
+#: builtin/add.c:419 builtin/clean.c:95 builtin/commit.c:358 builtin/mv.c:82
+#: builtin/rm.c:162
+msgid "index file corrupt"
+msgstr "暂存区文件损坏"
+
+#: builtin/add.c:475 builtin/mv.c:229 builtin/rm.c:260
+msgid "Unable to write new index file"
+msgstr "无法写入新暂存区文件"
+
+#: builtin/archive.c:17
+#, c-format
+msgid "could not create archive file '%s'"
+msgstr "无法创建归档文件 '%s'"
+
+#: builtin/archive.c:20
+msgid "could not redirect output"
+msgstr "无法重定向输出"
+
+#: builtin/archive.c:37
+msgid "git archive: Remote with no URL"
+msgstr "git archive: 未提供远程URL"
+
+#: builtin/archive.c:58
+msgid "git archive: expected ACK/NAK, got EOF"
+msgstr "git archive: 期待ACK/NACK,却得到EOF"
+
+#: builtin/archive.c:63
+#, c-format
+msgid "git archive: NACK %s"
+msgstr "git archive: NACK %s"
+
+#: builtin/archive.c:65
+#, c-format
+msgid "remote error: %s"
+msgstr "远程错误:%s"
+
+#: builtin/archive.c:66
+msgid "git archive: protocol error"
+msgstr "git archive: 协议错误"
+
+#: builtin/archive.c:71
+msgid "git archive: expected a flush"
+msgstr "git archive: 预期一个刷新"
+
+#: builtin/branch.c:137
+#, c-format
+msgid ""
+"deleting branch '%s' that has been merged to\n"
+"         '%s', but not yet merged to HEAD."
+msgstr ""
+"要删除的分支 '%s' 已经合并到\n"
+"         '%s',但未合并到 HEAD。"
+
+#: builtin/branch.c:141
+#, c-format
+msgid ""
+"not deleting branch '%s' that is not yet merged to\n"
+"         '%s', even though it is merged to HEAD."
+msgstr ""
+"不要删除分支 '%s' 其尚未合并到\n"
+"         '%s',虽然它已经合并到 HEAD。"
+
+#  汉字之间无空格,故删除尾部空格
+#. TRANSLATORS: This is "remote " in "remote branch '%s' not found"
+#: builtin/branch.c:163
+msgid "remote "
+msgstr "远程"
+
+#: builtin/branch.c:171
+msgid "cannot use -a with -d"
+msgstr "不能将 -a 和 -d 共用"
+
+#: builtin/branch.c:177
+msgid "Couldn't look up commit object for HEAD"
+msgstr "无法查询 HEAD 指向的提交对象"
+
+#: builtin/branch.c:182
+#, c-format
+msgid "Cannot delete the branch '%s' which you are currently on."
+msgstr "无法删除您当前所在的分支 '%s'。"
+
+#: builtin/branch.c:192
+#, c-format
+msgid "%sbranch '%s' not found."
+msgstr "%s分支 '%s' 未发现。"
+
+#: builtin/branch.c:200
+#, c-format
+msgid "Couldn't look up commit object for '%s'"
+msgstr "无法查询 '%s' 指向的提交对象"
+
+#: builtin/branch.c:206
+#, c-format
+msgid ""
+"The branch '%s' is not fully merged.\n"
+"If you are sure you want to delete it, run 'git branch -D %s'."
+msgstr ""
+"分支 '%s' 没有完全合并。\n"
+"如果您确认要删除它,执行 'git branch -D %s'。"
+
+#: builtin/branch.c:214
+#, c-format
+msgid "Error deleting %sbranch '%s'"
+msgstr "错误删除 %s分支 '%s'"
+
+#: builtin/branch.c:219
+#, c-format
+msgid "Deleted %sbranch %s (was %s).\n"
+msgstr "已删除 %s分支 %s(曾为 %s)。\n"
+
+#: builtin/branch.c:224
+msgid "Update of config-file failed"
+msgstr "无法更新 config 文件"
+
+#: builtin/branch.c:322
+#, c-format
+msgid "branch '%s' does not point at a commit"
+msgstr "分支 '%s' 未指向一个提交"
+
+#  注意保持句尾空格
+#: builtin/branch.c:394
+#, c-format
+msgid "behind %d] "
+msgstr "落后 %d] "
+
+#  注意保持句尾空格
+#: builtin/branch.c:396
+#, c-format
+msgid "ahead %d] "
+msgstr "领先 %d] "
+
+#  注意保持句尾空格
+#: builtin/branch.c:398
+#, c-format
+msgid "ahead %d, behind %d] "
+msgstr "领先 %d,落后 %d] "
+
+#: builtin/branch.c:501
+msgid "(no branch)"
+msgstr "(非分支)"
+
+#: builtin/branch.c:562
+msgid "some refs could not be read"
+msgstr "一些引用无法读取"
+
+#: builtin/branch.c:575
+msgid "cannot rename the current branch while not on any."
+msgstr "无法重命名不存在的当前分支。"
+
+#: builtin/branch.c:585
+#, c-format
+msgid "Invalid branch name: '%s'"
+msgstr "无效的分支名:'%s'"
+
+#: builtin/branch.c:600
+msgid "Branch rename failed"
+msgstr "分支重命名失败"
+
+#: builtin/branch.c:604
+#, c-format
+msgid "Renamed a misnamed branch '%s' away"
+msgstr "重命名掉一个错误命名的旧分支 '%s'"
+
+#: builtin/branch.c:608
+#, c-format
+msgid "Branch renamed to %s, but HEAD is not updated!"
+msgstr "分支重命名为 %s,但 HEAD 没有更新!"
+
+#: builtin/branch.c:615
+msgid "Branch is renamed, but update of config-file failed"
+msgstr "分支被重命名,但更新 config 文件失败"
+
+#: builtin/branch.c:630
+#, c-format
+msgid "malformed object name %s"
+msgstr "非法的对象名 %s"
+
+#: builtin/branch.c:654
+#, c-format
+msgid "could not write branch description template: %s\n"
+msgstr "不能写分支描述模版:%s\n"
+
+#: builtin/branch.c:742
+msgid "Failed to resolve HEAD as a valid ref."
+msgstr "无法将 HEAD 解析为有效引用。"
+
+#: builtin/branch.c:747
+msgid "HEAD not found below refs/heads!"
+msgstr "未在 /refs/heads 下发现 HEAD!"
+
+#: builtin/branch.c:790
+msgid "-a and -r options to 'git branch' do not make sense with a branch name"
+msgstr "'git branch' 的 -a 和 -r 选项带一个分支名参数没有意义"
+
+#: builtin/bundle.c:47
+#, c-format
+msgid "%s is okay\n"
+msgstr "%s 可以\n"
+
+#: builtin/bundle.c:56
+msgid "Need a repository to create a bundle."
+msgstr "需要一个版本库来创建包"
+
+#: builtin/bundle.c:60
+msgid "Need a repository to unbundle."
+msgstr "需要一个版本库来解包"
+
+#: builtin/checkout.c:113 builtin/checkout.c:146
+#, c-format
+msgid "path '%s' does not have our version"
+msgstr "路径 '%s' 没有我们的版本"
+
+#: builtin/checkout.c:115 builtin/checkout.c:148
+#, c-format
+msgid "path '%s' does not have their version"
+msgstr "路径 '%s' 没有他们的版本"
+
+#: builtin/checkout.c:131
+#, c-format
+msgid "path '%s' does not have all necessary versions"
+msgstr "路径 '%s' 没有全部必须的版本"
+
+#: builtin/checkout.c:175
+#, c-format
+msgid "path '%s' does not have necessary versions"
+msgstr "路径 '%s' 没有必须的版本"
+
+#: builtin/checkout.c:192
+#, c-format
+msgid "path '%s': cannot merge"
+msgstr "path '%s': 无法合并"
+
+#: builtin/checkout.c:209
+#, c-format
+msgid "Unable to add merge result for '%s'"
+msgstr "无法为 '%s' 添加合并结果"
+
+#: builtin/checkout.c:212 builtin/reset.c:158
+#, c-format
+msgid "make_cache_entry failed for path '%s'"
+msgstr "对路径 '%s' 的 make_cache_entry 操作失败"
+
+#: builtin/checkout.c:234 builtin/checkout.c:392
+msgid "corrupt index file"
+msgstr "冲突的暂存区文件"
+
+#: builtin/checkout.c:264 builtin/checkout.c:271
+#, c-format
+msgid "path '%s' is unmerged"
+msgstr "路径 '%s' 未合并"
+
+#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:769
+#: builtin/merge.c:809
+msgid "unable to write new index file"
+msgstr "无法写新的暂存区文件"
+
+#: builtin/checkout.c:319 builtin/diff.c:298 builtin/merge.c:406
+msgid "diff_setup_done failed"
+msgstr "diff_setup_done 失败"
+
+#: builtin/checkout.c:414
+msgid "you need to resolve your current index first"
+msgstr "您需要先解决当前暂存区的冲突"
+
+#: builtin/checkout.c:547
+#, c-format
+msgid "Can not do reflog for '%s'\n"
+msgstr "不能对 '%s' 保存引用日志\n"
+
+#: builtin/checkout.c:579
+msgid "HEAD is now at"
+msgstr "HEAD 目前位于"
+
+#: builtin/checkout.c:586
+#, c-format
+msgid "Reset branch '%s'\n"
+msgstr "重置分支 '%s'\n"
+
+#: builtin/checkout.c:589
+#, c-format
+msgid "Already on '%s'\n"
+msgstr "已经位于 '%s'\n"
+
+#: builtin/checkout.c:593
+#, c-format
+msgid "Switched to and reset branch '%s'\n"
+msgstr "切换并重置分支 '%s'\n"
+
+#: builtin/checkout.c:595
+#, c-format
+msgid "Switched to a new branch '%s'\n"
+msgstr "切换到一个新分支 '%s'\n"
+
+#: builtin/checkout.c:597
+#, c-format
+msgid "Switched to branch '%s'\n"
+msgstr "切换到分支 '%s'\n"
+
+#  注意保持前导空格
+#: builtin/checkout.c:653
+#, c-format
+msgid " ... and %d more.\n"
+msgstr " ... 及 %d 更多。\n"
+
+#. The singular version
+#: builtin/checkout.c:659
+#, c-format
+msgid ""
+"Warning: you are leaving %d commit behind, not connected to\n"
+"any of your branches:\n"
+"\n"
+"%s\n"
+msgid_plural ""
+"Warning: you are leaving %d commits behind, not connected to\n"
+"any of your branches:\n"
+"\n"
+"%s\n"
+msgstr[0] ""
+"警告:您正丢下 %d 个提交,未和任何分支关联:\n"
+"\n"
+"%s\n"
+
+#: builtin/checkout.c:677
+#, c-format
+msgid ""
+"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 ""
+"如果您想要通过创建新分支保存他们,这可能是一个好时候。\n"
+"如下操作:\n"
+"\n"
+" git branch new_branch_name %s\n"
+"\n"
+
+#: builtin/checkout.c:706
+msgid "internal error in revision walk"
+msgstr "在版本遍历时遇到内部错误"
+
+#: builtin/checkout.c:710
+msgid "Previous HEAD position was"
+msgstr "之前的 HEAD 位置是"
+
+#: builtin/checkout.c:736
+msgid "You are on a branch yet to be born"
+msgstr "您位于一个未初始化的分支"
+
+#. case (1)
+#: builtin/checkout.c:867
+#, c-format
+msgid "invalid reference: %s"
+msgstr "无效引用:%s"
+
+#. case (1): want a tree
+#: builtin/checkout.c:906
+#, c-format
+msgid "reference is not a tree: %s"
+msgstr "引用不是一个树:%s"
+
+#: builtin/checkout.c:975
+msgid "-B cannot be used with -b"
+msgstr "-B 不能和 -b 共用"
+
+#: builtin/checkout.c:984
+msgid "--patch is incompatible with all other options"
+msgstr "--patch 选项和其他选项不兼容"
+
+#: builtin/checkout.c:987
+msgid "--detach cannot be used with -b/-B/--orphan"
+msgstr "--detach 不能和 -b/-B/--orphan 共用"
+
+#: builtin/checkout.c:989
+msgid "--detach cannot be used with -t"
+msgstr "--detach 不能和 -t 共用"
+
+#: builtin/checkout.c:995
+msgid "--track needs a branch name"
+msgstr "--track 需要一个分支名"
+
+#: builtin/checkout.c:1002
+msgid "Missing branch name; try -b"
+msgstr "缺少分支名;尝试 -b"
+
+#: builtin/checkout.c:1008
+msgid "--orphan and -b|-B are mutually exclusive"
+msgstr "--orphan 和 -b|-B 互斥"
+
+#: builtin/checkout.c:1010
+msgid "--orphan cannot be used with -t"
+msgstr "--orphan 不能和 -t 共用"
+
+#: builtin/checkout.c:1020
+msgid "git checkout: -f and -m are incompatible"
+msgstr "git checkout: -f 和 -m 不兼容"
+
+#: builtin/checkout.c:1054
+msgid "invalid path specification"
+msgstr "无效的路径"
+
+#: builtin/checkout.c:1062
+#, c-format
+msgid ""
+"git checkout: updating paths is incompatible with switching branches.\n"
+"Did you intend to checkout '%s' which can not be resolved as commit?"
+msgstr ""
+"git checkout: 更新路径和切换分支不兼容。\n"
+"您是想要检出 '%s' 但未能将其解析为提交么?"
+
+#: builtin/checkout.c:1064
+msgid "git checkout: updating paths is incompatible with switching branches."
+msgstr "git checkout: 更新路径和切换分支不兼容。"
+
+#: builtin/checkout.c:1069
+msgid "git checkout: --detach does not take a path argument"
+msgstr "git checkout: --detach 不跟路径参数"
+
+#: builtin/checkout.c:1072
+msgid ""
+"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+"checking out of the index."
+msgstr ""
+"git checkout: --ours/--theirs, --force 和 --merge 不兼容当\n"
+"检出暂存区时。"
+
+#: builtin/checkout.c:1091
+msgid "Cannot switch branch to a non-commit."
+msgstr "无法切换分支到一个非提交。"
+
+#: builtin/checkout.c:1094
+msgid "--ours/--theirs is incompatible with switching branches."
+msgstr "--ours/--theirs 和切换分支不兼容。"
+
+#: builtin/clean.c:78
+msgid "-x and -X cannot be used together"
+msgstr "-x 和 -X 不能共用"
+
+#: builtin/clean.c:82
+msgid ""
+"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
+msgstr ""
+"clean.requireForce 设置为 true,若未提供 -n 或 -f 选项,拒绝执行清理动作"
+
+#: builtin/clean.c:85
+msgid ""
+"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
+"clean"
+msgstr ""
+"clean.requireForce 默认为 true,若未提供 -n 或 -f 选项,拒绝执行清理动作"
+
+#: builtin/clean.c:155 builtin/clean.c:176
+#, c-format
+msgid "Would remove %s\n"
+msgstr "将删除 %s\n"
+
+#: builtin/clean.c:159 builtin/clean.c:179
+#, c-format
+msgid "Removing %s\n"
+msgstr "正删除 %s\n"
+
+#: builtin/clean.c:162 builtin/clean.c:182
+#, c-format
+msgid "failed to remove %s"
+msgstr "无法删除 %s"
+
+#: builtin/clean.c:166
+#, c-format
+msgid "Would not remove %s\n"
+msgstr "不会删除 %s\n"
+
+#: builtin/clean.c:168
+#, c-format
+msgid "Not removing %s\n"
+msgstr "未删除 %s\n"
+
+#: builtin/clone.c:244
+#, c-format
+msgid "reference repository '%s' is not a local directory."
+msgstr "引用版本库 '%s' 不是一个本地目录。"
+
+#: builtin/clone.c:311
+#, c-format
+msgid "failed to open '%s'"
+msgstr "打开 '%s' 失败"
+
+#: builtin/clone.c:315
+#, c-format
+msgid "failed to create directory '%s'"
+msgstr "创建目录 '%s' 失败"
+
+#: builtin/clone.c:317 builtin/diff.c:75
+#, c-format
+msgid "failed to stat '%s'"
+msgstr "枚举 '%s' 状态失败"
+
+#: builtin/clone.c:319
+#, c-format
+msgid "%s exists and is not a directory"
+msgstr "%s 存在且不是一个目录"
+
+#: builtin/clone.c:333
+#, c-format
+msgid "failed to stat %s\n"
+msgstr "枚举 %s 状态失败\n"
+
+#: builtin/clone.c:350
+#, c-format
+msgid "failed to unlink '%s'"
+msgstr "删除 '%s' 失败"
+
+#: builtin/clone.c:355
+#, c-format
+msgid "failed to create link '%s'"
+msgstr "创建链接 '%s' 失败"
+
+#: builtin/clone.c:359
+#, c-format
+msgid "failed to copy file to '%s'"
+msgstr "拷贝文件至 '%s' 失败"
+
+#: builtin/clone.c:391
+#, c-format
+msgid "done.\n"
+msgstr "完成。\n"
+
+#: builtin/clone.c:494
+msgid "Too many arguments."
+msgstr "太多参数。"
+
+#: builtin/clone.c:498
+msgid "You must specify a repository to clone."
+msgstr "你必须指定一个版本库来克隆"
+
+#: builtin/clone.c:506
+#, c-format
+msgid "--bare and --origin %s options are incompatible."
+msgstr "--bare 和 --origin %s 选项不兼容。"
+
+#: builtin/clone.c:520
+#, c-format
+msgid "repository '%s' does not exist"
+msgstr "版本库 '%s' 不存在"
+
+#: builtin/clone.c:525
+msgid "--depth is ignored in local clones; use file:// instead."
+msgstr "--depth 在本地克隆被忽略,改为 file:// 协议试试。"
+
+#: builtin/clone.c:535
+#, c-format
+msgid "destination path '%s' already exists and is not an empty directory."
+msgstr "目标路径 '%s' 已经存在且不是一个空目录。"
+
+#: builtin/clone.c:545
+#, c-format
+msgid "working tree '%s' already exists."
+msgstr "工作区 '%s' 已经存在。"
+
+#: builtin/clone.c:558 builtin/clone.c:572
+#, c-format
+msgid "could not create leading directories of '%s'"
+msgstr "无法为 '%s' 创建目录"
+
+#: builtin/clone.c:561
+#, c-format
+msgid "could not create work tree dir '%s'."
+msgstr "无法为 '%s' 创建工作区目录。"
+
+#: builtin/clone.c:580
+#, c-format
+msgid "Cloning into bare repository '%s'...\n"
+msgstr "克隆到裸版本库 '%s'...\n"
+
+#: builtin/clone.c:582
+#, c-format
+msgid "Cloning into '%s'...\n"
+msgstr "正克隆到 '%s'...\n"
+
+#: builtin/clone.c:641
+#, c-format
+msgid "Don't know how to clone %s"
+msgstr "不知道如何克隆 %s"
+
+#: builtin/clone.c:680
+#, c-format
+msgid "Remote branch %s not found in upstream %s, using HEAD instead"
+msgstr "远程分支 %s 在上游 %s 未发现,改为使用 HEAD"
+
+#: builtin/clone.c:690
+msgid "You appear to have cloned an empty repository."
+msgstr "您似乎克隆了一个空版本库。"
+
+#: builtin/clone.c:732
+msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
+msgstr "远程 HEAD 指向一个不存在的引用,无法检出。\n"
+
+#: builtin/commit.c:42
+msgid ""
+"Your name and email address were configured automatically based\n"
+"on your username and hostname. Please check that they are accurate.\n"
+"You can suppress this message by setting them explicitly:\n"
+"\n"
+"    git config --global user.name \"Your Name\"\n"
+"    git config --global user.email you@example.com\n"
+"\n"
+"After doing this, you may fix the identity used for this commit with:\n"
+"\n"
+"    git commit --amend --reset-author\n"
+msgstr ""
+"您的姓名和邮件地址会基于您的用户名和主机地址自动配置。请检查它们\n"
+"正确与否。您可通过下面命令对其显式声明以避免重复出现类似提示:\n"
+"\n"
+"    git config --global user.name \"Your Name\"\n"
+"    git config --global user.email you@example.com\n"
+"\n"
+"设置完毕后,您可用下面命令来更改此次提交所使用的用户ID:\n"
+"\n"
+"    git commit --amend --reset-author\n"
+
+#: builtin/commit.c:54
+msgid ""
+"You asked to amend the most recent commit, but doing so would make\n"
+"it empty. You can repeat your command with --allow-empty, or you can\n"
+"remove the commit entirely with \"git reset HEAD^\".\n"
+msgstr ""
+"您要求修补最近的提交,但这么做会造成空提交。您可重复您的命令并带上\n"
+"--allow-empty 选项,或者您可以整个删除该提交用 \"git reset HEAD^\"。\n"
+
+#: builtin/commit.c:59
+msgid ""
+"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
+"If you wish to commit it anyway, use:\n"
+"\n"
+"    git commit --allow-empty\n"
+"\n"
+"Otherwise, please use 'git reset'\n"
+msgstr ""
+"之前的拣选操作现在为空,可能是由冲突解决导致的。如果您想继续提交,用:\n"
+"\n"
+"    git commit --allow-empty\n"
+"\n"
+"否则,请用 'git reset'\n"
+
+#: builtin/commit.c:205 builtin/reset.c:33
+msgid "merge"
+msgstr "合并"
+
+#: builtin/commit.c:208
+msgid "cherry-pick"
+msgstr "拣选"
+
+#: builtin/commit.c:325
+msgid "failed to unpack HEAD tree object"
+msgstr "解包 HEAD 树对象失败"
+
+#: builtin/commit.c:367
+msgid "unable to create temporary index"
+msgstr "不能创建临时暂存区"
+
+#: builtin/commit.c:373
+msgid "interactive add failed"
+msgstr "交互式添加失败"
+
+#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473
+msgid "unable to write new_index file"
+msgstr "无法写入新暂存区文件"
+
+#  %s若翻为中文,前后不需要空格
+#: builtin/commit.c:457
+#, c-format
+msgid "cannot do a partial commit during a %s."
+msgstr "在%s过程中不能做部分提交。"
+
+#: builtin/commit.c:466
+msgid "cannot read the index"
+msgstr "无法读取暂存区"
+
+#: builtin/commit.c:486
+msgid "unable to write temporary index file"
+msgstr "无法写临时暂存区文件"
+
+#: builtin/commit.c:549 builtin/commit.c:555
+#, c-format
+msgid "invalid commit: %s"
+msgstr "无效的提交:%s"
+
+#: builtin/commit.c:573
+msgid "malformed --author parameter"
+msgstr "非法的 --author 参数"
+
+#: builtin/commit.c:629
+#, c-format
+msgid "Malformed ident string: '%s'"
+msgstr "非法的识别字串:'%s'"
+
+#: builtin/commit.c:664 builtin/commit.c:697 builtin/commit.c:994
+#, c-format
+msgid "could not lookup commit %s"
+msgstr "不能查询提交 %s"
+
+#: builtin/commit.c:676 builtin/shortlog.c:296
+#, c-format
+msgid "(reading log message from standard input)\n"
+msgstr "(正从标准输入中读取说明信息)\n"
+
+#: builtin/commit.c:678
+msgid "could not read log from standard input"
+msgstr "无法从标准输入中读取说明信息"
+
+#: builtin/commit.c:682
+#, c-format
+msgid "could not read log file '%s'"
+msgstr "无法读取说明文件 '%s'"
+
+#: builtin/commit.c:688
+msgid "commit has empty message"
+msgstr "提交说明为空"
+
+#: builtin/commit.c:704
+msgid "could not read MERGE_MSG"
+msgstr "无法读取 MERGE_MSG"
+
+#: builtin/commit.c:708
+msgid "could not read SQUASH_MSG"
+msgstr "无法读取 SQUASH_MSG"
+
+#: builtin/commit.c:712
+#, c-format
+msgid "could not read '%s'"
+msgstr "无法读取 '%s'"
+
+#: builtin/commit.c:740
+#, c-format
+msgid "could not open '%s'"
+msgstr "无法打开 '%s'"
+
+#: builtin/commit.c:764
+msgid "could not write commit template"
+msgstr "无法写提交模版"
+
+#  %s若翻为中文,前后不需要空格
+#: builtin/commit.c:777
+#, c-format
+msgid ""
+"\n"
+"It looks like you may be committing a %s.\n"
+"If this is not correct, please remove the file\n"
+"\t%s\n"
+"and try again.\n"
+msgstr ""
+"\n"
+"看起来您正在提交一个%s。\n"
+"如果不是这样,请删除文件\n"
+"\t%s\n"
+"然后重试。\n"
+
+#  注意保持前导空格
+#: builtin/commit.c:790
+msgid "Please enter the commit message for your changes."
+msgstr "请为您的修改输入提交说明。"
+
+#: builtin/commit.c:793
+msgid ""
+" Lines starting\n"
+"with '#' will be ignored, and an empty message aborts the commit.\n"
+msgstr ""
+" 以 '#' 开头\n"
+"的行将被忽略,而且空提交说明将会终止提交。\n"
+
+#  注意保持前导空格
+#: builtin/commit.c:798
+msgid ""
+" Lines starting\n"
+"with '#' will be kept; you may remove them yourself if you want to.\n"
+"An empty message aborts the commit.\n"
+msgstr ""
+" 以 '#' 开头\n"
+"的行将被保留,您可以删除它们如果您想这样做。空提交说明将会终止提交。\n"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: builtin/commit.c:810
+#, c-format
+msgid "%sAuthor:    %s"
+msgstr "%s作者:     %s"
+
+#  为保证在输出中对齐,注意调整句中空格!
+#: builtin/commit.c:817
+#, c-format
+msgid "%sCommitter: %s"
+msgstr "%s提交者:   %s"
+
+#: builtin/commit.c:837
+msgid "Cannot read index"
+msgstr "无法读取暂存区"
+
+#: builtin/commit.c:874
+msgid "Error building trees"
+msgstr "无法创建树对象"
+
+#: builtin/commit.c:889 builtin/tag.c:324
+#, c-format
+msgid "Please supply the message using either -m or -F option.\n"
+msgstr "请使用 -m 或者 -F 选项提供说明。\n"
+
+#: builtin/commit.c:969
+#, c-format
+msgid "No existing author found with '%s'"
+msgstr "没有找到匹配 '%s' 的作者"
+
+#: builtin/commit.c:984 builtin/commit.c:1176
+#, c-format
+msgid "Invalid untracked files mode '%s'"
+msgstr "无效的非追踪文件参数 '%s'"
+
+#: builtin/commit.c:1024
+msgid "Using both --reset-author and --author does not make sense"
+msgstr "同时使用 --reset-author 和 --author 没有意义"
+
+#: builtin/commit.c:1035
+msgid "You have nothing to amend."
+msgstr "您没有要修补。"
+
+#  %s若翻为中文,前后不需要空格
+#: builtin/commit.c:1037
+#, c-format
+msgid "You are in the middle of a %s -- cannot amend."
+msgstr "您正处于一个%s过程中 -- 无法修补提交。"
+
+#: builtin/commit.c:1039
+msgid "Options --squash and --fixup cannot be used together"
+msgstr "选项 --squash 和 --fixup 不能共用"
+
+#: builtin/commit.c:1049
+msgid "Only one of -c/-C/-F/--fixup can be used."
+msgstr "只能用一个 -c/-C/-F/--fixup 选项。"
+
+#: builtin/commit.c:1051
+msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
+msgstr "选项 -m 不能和 -c/-C/-F/--fixup 共用。"
+
+#: builtin/commit.c:1057
+msgid "--reset-author can be used only with -C, -c or --amend."
+msgstr "--reset-author 只能和 -C, -c 或 --amend 共用。"
+
+#: builtin/commit.c:1074
+msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
+msgstr "只能用一个 --include/--only/--all/--interactive/--patch 选项。"
+
+#: builtin/commit.c:1076
+msgid "No paths with --include/--only does not make sense."
+msgstr "参数 --include/--only 不跟路径没有意义。"
+
+#: builtin/commit.c:1078
+msgid "Clever... amending the last one with dirty index."
+msgstr "聪明... 在暂存区不干净下修补最后的提交。"
+
+#: builtin/commit.c:1080
+msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
+msgstr "没有用 -i 或 -o 选项而显式地提供路径,认为是 --only paths..."
+
+#: builtin/commit.c:1090 builtin/tag.c:500
+#, c-format
+msgid "Invalid cleanup mode %s"
+msgstr "无效的清理模式 %s"
+
+#: builtin/commit.c:1095
+msgid "Paths with -a does not make sense."
+msgstr "路径和 -a 选项共用没有意义。"
+
+#: builtin/commit.c:1274
+msgid "couldn't look up newly created commit"
+msgstr "无法找到新创建的提交"
+
+#: builtin/commit.c:1276
+msgid "could not parse newly created commit"
+msgstr "无法解析新创建的提交"
+
+#: builtin/commit.c:1317
+msgid "detached HEAD"
+msgstr "分离头指针"
+
+#  注意保持前导空格
+#: builtin/commit.c:1319
+msgid " (root-commit)"
+msgstr " (根提交)"
+
+#: builtin/commit.c:1409
+msgid "could not parse HEAD commit"
+msgstr "无法解析 HEAD 提交"
+
+#: builtin/commit.c:1446 builtin/merge.c:507
+#, c-format
+msgid "could not open '%s' for reading"
+msgstr "无法打开 '%s' 读取"
+
+#: builtin/commit.c:1453
+#, c-format
+msgid "Corrupt MERGE_HEAD file (%s)"
+msgstr "损坏的 MERGE_HEAD 文件 (%s)"
+
+#: builtin/commit.c:1460
+msgid "could not read MERGE_MODE"
+msgstr "无法读取 MERGE_MODE"
+
+#: builtin/commit.c:1479
+#, c-format
+msgid "could not read commit message: %s"
+msgstr "无法读取提交说明:%s"
+
+#: builtin/commit.c:1493
+#, c-format
+msgid "Aborting commit due to empty commit message.\n"
+msgstr "终止提交因为提交说明为空。\n"
+
+#: builtin/commit.c:1508 builtin/merge.c:923 builtin/merge.c:956
+msgid "failed to write commit object"
+msgstr "写提交对象失败"
+
+#: builtin/commit.c:1529
+msgid "cannot lock HEAD ref"
+msgstr "无法锁定 HEAD 引用"
+
+#: builtin/commit.c:1533
+msgid "cannot update HEAD ref"
+msgstr "无法更新 HEAD 引用"
+
+#: builtin/commit.c:1544
+msgid ""
+"Repository has been updated, but unable to write\n"
+"new_index file. Check that disk is not full or quota is\n"
+"not exceeded, and then \"git reset HEAD\" to recover."
+msgstr ""
+"版本库已被更新,但无法写入新暂存区文件。检查是否磁盘\n"
+"已满或磁盘配额耗尽,然后执行 \"git reset HEAD\" 恢复。"
+
+#: builtin/describe.c:234
+#, c-format
+msgid "annotated tag %s not available"
+msgstr "注释 tag %s 无效"
+
+#: builtin/describe.c:238
+#, c-format
+msgid "annotated tag %s has no embedded name"
+msgstr "注释 tag %s 没有嵌入名称"
+
+#: builtin/describe.c:240
+#, c-format
+msgid "tag '%s' is really '%s' here"
+msgstr "tag '%s' 确是在 '%s'"
+
+#: builtin/describe.c:267
+#, c-format
+msgid "Not a valid object name %s"
+msgstr "不是一个有效的对象名 %s"
+
+#: builtin/describe.c:270
+#, c-format
+msgid "%s is not a valid '%s' object"
+msgstr "%s 不是一个有效的 '%s' 对象"
+
+#: builtin/describe.c:287
+#, c-format
+msgid "no tag exactly matches '%s'"
+msgstr "没有 tag 准确匹配 '%s'"
+
+#: builtin/describe.c:289
+#, c-format
+msgid "searching to describe %s\n"
+msgstr "搜索描述 %s\n"
+
+#: builtin/describe.c:329
+#, c-format
+msgid "finished search at %s\n"
+msgstr "完成搜索 %s\n"
+
+#: builtin/describe.c:353
+#, c-format
+msgid ""
+"No annotated tags can describe '%s'.\n"
+"However, there were unannotated tags: try --tags."
+msgstr ""
+"没有注释 tag 能描述 '%s'。\n"
+"然而,有非注释 tag:尝试 --tags。"
+
+#: builtin/describe.c:357
+#, c-format
+msgid ""
+"No tags can describe '%s'.\n"
+"Try --always, or create some tags."
+msgstr ""
+"没有注释 tag 能描述 '%s'。\n"
+"尝试 --always,或创建一些 tag。"
+
+#: builtin/describe.c:378
+#, c-format
+msgid "traversed %lu commits\n"
+msgstr "已遍历 %lu 个提交\n"
+
+#: builtin/describe.c:381
+#, c-format
+msgid ""
+"more than %i tags found; listed %i most recent\n"
+"gave up search at %s\n"
+msgstr ""
+"发现多于 %i 个 tag;列出最近的 %i 个\n"
+"放弃搜索 %s\n"
+
+#: builtin/describe.c:436
+msgid "--long is incompatible with --abbrev=0"
+msgstr "--long 与 --abbrev=0 不兼容"
+
+#: builtin/describe.c:462
+msgid "No names found, cannot describe anything."
+msgstr "没有发现名称,无法描述任何东西"
+
+#: builtin/describe.c:482
+msgid "--dirty is incompatible with committishes"
+msgstr "--dirty 不能与提交共用"
+
+#: builtin/diff.c:77
+#, c-format
+msgid "'%s': not a regular file or symlink"
+msgstr "'%s':不是一个正规文件或符号链接"
+
+#: builtin/diff.c:220
+#, c-format
+msgid "invalid option: %s"
+msgstr "无效选项:%s"
+
+#: builtin/diff.c:293
+msgid "Not a git repository"
+msgstr "不是一个 git 版本库"
+
+#: builtin/diff.c:343
+#, c-format
+msgid "invalid object '%s' given."
+msgstr "提供了无效对象 '%s'。"
+
+#: builtin/diff.c:348
+#, c-format
+msgid "more than %d trees given: '%s'"
+msgstr "提供了超过 %d 个树对象:'%s'"
+
+#: builtin/diff.c:358
+#, c-format
+msgid "more than two blobs given: '%s'"
+msgstr "提供了超过两个 blob 对象:'%s'"
+
+#: builtin/diff.c:366
+#, c-format
+msgid "unhandled object '%s' given."
+msgstr "提供了无法处理的对象 '%s'。"
+
+#: builtin/fetch.c:200
+msgid "Couldn't find remote ref HEAD"
+msgstr "无法发现远程 HEAD 引用"
+
+#: builtin/fetch.c:252
+#, c-format
+msgid "object %s not found"
+msgstr "对象 %s 未发现"
+
+#: builtin/fetch.c:258
+msgid "[up to date]"
+msgstr "[最新]"
+
+#: builtin/fetch.c:272
+#, c-format
+msgid "! %-*s %-*s -> %s  (can't fetch in current branch)"
+msgstr "! %-*s %-*s -> %s  (在当前分支下不能获取)"
+
+#: builtin/fetch.c:273 builtin/fetch.c:351
+msgid "[rejected]"
+msgstr "[已拒绝]"
+
+#: builtin/fetch.c:284
+msgid "[tag update]"
+msgstr "[tag更新]"
+
+#  注意保持前导空格
+#: builtin/fetch.c:286 builtin/fetch.c:313 builtin/fetch.c:331
+msgid "  (unable to update local ref)"
+msgstr "  (不能更新本地引用)"
+
+#: builtin/fetch.c:298
+msgid "[new tag]"
+msgstr "[新tag]"
+
+#: builtin/fetch.c:302
+msgid "[new branch]"
+msgstr "[新分支]"
+
+#: builtin/fetch.c:347
+msgid "unable to update local ref"
+msgstr "不能更新本地引用"
+
+#: builtin/fetch.c:347
+msgid "forced update"
+msgstr "强制更新"
+
+#: builtin/fetch.c:353
+msgid "(non-fast-forward)"
+msgstr "(非快进式推送)"
+
+#: builtin/fetch.c:384 builtin/fetch.c:676
+#, c-format
+msgid "cannot open %s: %s\n"
+msgstr "无法打开 %s:%s\n"
+
+#: builtin/fetch.c:393
+#, c-format
+msgid "%s did not send all necessary objects\n"
+msgstr "%s 未发送所有必须的对象\n"
+
+#: builtin/fetch.c:479
+#, c-format
+msgid "From %.*s\n"
+msgstr "来自 %.*s\n"
+
+#: builtin/fetch.c:490
+#, c-format
+msgid ""
+"some local refs could not be updated; try running\n"
+" 'git remote prune %s' to remove any old, conflicting branches"
+msgstr ""
+"一些本地引用不能被更新;尝试运行\n"
+" 'git remote prune %s' 来删除旧的、有冲突的分支"
+
+#  注意保持前导空格
+#: builtin/fetch.c:540
+#, c-format
+msgid "   (%s will become dangling)\n"
+msgstr "   (%s 将成为悬空状态)\n"
+
+#  注意保持前导空格
+#: builtin/fetch.c:541
+#, c-format
+msgid "   (%s has become dangling)\n"
+msgstr "   (%s 已成为悬空状态)\n"
+
+#: builtin/fetch.c:548
+msgid "[deleted]"
+msgstr "[已删除]"
+
+#: builtin/fetch.c:549
+msgid "(none)"
+msgstr "(无)"
+
+#: builtin/fetch.c:666
+#, c-format
+msgid "Refusing to fetch into current branch %s of non-bare repository"
+msgstr "拒绝获取到非裸版本库的当前分支 %s"
+
+#: builtin/fetch.c:700
+#, c-format
+msgid "Don't know how to fetch from %s"
+msgstr "不知道如何从 %s 获取"
+
+#: builtin/fetch.c:777
+#, c-format
+msgid "Option \"%s\" value \"%s\" is not valid for %s"
+msgstr "选项 \"%s\" 的值 \"%s\" 对于 %s 是无效的"
+
+#: builtin/fetch.c:780
+#, c-format
+msgid "Option \"%s\" is ignored for %s\n"
+msgstr "选项 \"%s\" 对于 %s 被忽略\n"
+
+#: builtin/fetch.c:879
+#, c-format
+msgid "Fetching %s\n"
+msgstr "正获取 %s\n"
+
+#: builtin/fetch.c:881
+#, c-format
+msgid "Could not fetch %s"
+msgstr "不能获取 %s"
+
+#: builtin/fetch.c:898
+msgid ""
+"No remote repository specified.  Please, specify either a URL or a\n"
+"remote name from which new revisions should be fetched."
+msgstr "未提供远程版本库。请提供一个URL或远程版本库名,用于获取新版本。"
+
+#: builtin/fetch.c:918
+msgid "You need to specify a tag name."
+msgstr "你需要提供一个 tag 名称"
+
+#: builtin/fetch.c:970
+msgid "fetch --all does not take a repository argument"
+msgstr "fetch --all 不能带一个版本库参数"
+
+#: builtin/fetch.c:972
+msgid "fetch --all does not make sense with refspecs"
+msgstr "fetch --all 带引用表达式没有任何意义"
+
+#: builtin/fetch.c:983
+#, c-format
+msgid "No such remote or remote group: %s"
+msgstr "没有这样的远程或远程组:%s"
+
+#: builtin/fetch.c:991
+msgid "Fetching a group and specifying refspecs does not make sense"
+msgstr "获取组并提供引用表达式没有意义"
+
+#: builtin/gc.c:63
+#, c-format
+msgid "Invalid %s: '%s'"
+msgstr "无效的 %s:'%s'"
+
+#: builtin/gc.c:78
+msgid "Too many options specified"
+msgstr "提供了太多的选项"
+
+#: builtin/gc.c:103
+#, c-format
+msgid "insanely long object directory %.*s"
+msgstr "不正常的长对象目录 %.*s"
+
+#: builtin/gc.c:223
+#, c-format
+msgid "Auto packing the repository for optimum performance.\n"
+msgstr "自动打包版本库以求最佳性能。\n"
+
+#: builtin/gc.c:226
+#, c-format
+msgid ""
+"Auto packing the repository for optimum performance. You may also\n"
+"run \"git gc\" manually. See \"git help gc\" for more information.\n"
+msgstr ""
+"自动打包版本库以求最佳性能。你还可以\n"
+"手动运行 \"git gc\"。 参见 \"git help gc\" 获取更多信息。\n"
+
+#: builtin/gc.c:256
+msgid ""
+"There are too many unreachable loose objects; run 'git prune' to remove them."
+msgstr "有太多无指向的松散对象,运行 'git prune' 删除它们。"
+
+#: builtin/grep.c:275
+#, c-format
+msgid "grep: failed to create thread: %s"
+msgstr "grep: 无法创建线程:%s"
+
+#: builtin/grep.c:390
+#, c-format
+msgid "'%s': unable to read %s"
+msgstr "'%s':无法读取 %s"
+
+#: builtin/grep.c:441
+#, c-format
+msgid "'%s': %s"
+msgstr "'%s':%s"
+
+#: builtin/grep.c:452
+#, c-format
+msgid "'%s': short read %s"
+msgstr "'%s':读取不完整 %s"
+
+#: builtin/grep.c:514
+#, c-format
+msgid "Failed to chdir: %s"
+msgstr "无法切换目录:%s"
+
+#: builtin/grep.c:590 builtin/grep.c:624
+#, c-format
+msgid "unable to read tree (%s)"
+msgstr "无法读取代码树(%s)"
+
+#: builtin/grep.c:638
+#, c-format
+msgid "unable to grep from object of type %s"
+msgstr "无法抓取来自于 %s 类型的对象"
+
+#: builtin/grep.c:696
+#, c-format
+msgid "switch `%c' expects a numerical value"
+msgstr "开关 `%c' 期望一个数字值"
+
+#: builtin/grep.c:713
+#, c-format
+msgid "cannot open '%s'"
+msgstr "不能打开 '%s'"
+
+#: builtin/grep.c:1001
+msgid "no pattern given."
+msgstr "未提供模式匹配。"
+
+#: builtin/grep.c:1015
+#, c-format
+msgid "bad object %s"
+msgstr "坏对象 %s"
+
+#: builtin/grep.c:1057
+msgid "--open-files-in-pager only works on the worktree"
+msgstr "--open-files-in-pager 仅用于工作区"
+
+#: builtin/grep.c:1080
+msgid "--cached or --untracked cannot be used with --no-index."
+msgstr "--cached 或 --untracked 不能与 --no-index 共用"
+
+#: builtin/grep.c:1085
+msgid "--no-index or --untracked cannot be used with revs."
+msgstr "--no-index 或 --untracked 不能和版本共用。"
+
+#: builtin/grep.c:1088
+msgid "--[no-]exclude-standard cannot be used for tracked contents."
+msgstr "--[no-]exclude-standard 不能用于跟踪内容。"
+
+#: builtin/grep.c:1096
+msgid "both --cached and trees are given."
+msgstr "同时给出了 --cached 和树对象。"
+
+#: builtin/init-db.c:35
+#, c-format
+msgid "Could not make %s writable by group"
+msgstr "不能设置 %s 为组可写"
+
+#: builtin/init-db.c:62
+#, c-format
+msgid "insanely long template name %s"
+msgstr "太长的模版名 %s"
+
+#: builtin/init-db.c:67
+#, c-format
+msgid "cannot stat '%s'"
+msgstr "不能枚举 '%s' 状态"
+
+#: builtin/init-db.c:73
+#, c-format
+msgid "cannot stat template '%s'"
+msgstr "不能枚举模版 '%s' 状态"
+
+#: builtin/init-db.c:80
+#, c-format
+msgid "cannot opendir '%s'"
+msgstr "不能打开目录 '%s'"
+
+#: builtin/init-db.c:97
+#, c-format
+msgid "cannot readlink '%s'"
+msgstr "不能读取链接 '%s'"
+
+#: builtin/init-db.c:99
+#, c-format
+msgid "insanely long symlink %s"
+msgstr "太长的符号链接 %s"
+
+#: builtin/init-db.c:102
+#, c-format
+msgid "cannot symlink '%s' '%s'"
+msgstr "不能创建符号链接 '%s' 到 '%s'"
+
+#: builtin/init-db.c:106
+#, c-format
+msgid "cannot copy '%s' to '%s'"
+msgstr "不能拷贝 '%s' 至 '%s'"
+
+#: builtin/init-db.c:110
+#, c-format
+msgid "ignoring template %s"
+msgstr "忽略模版 %s"
+
+#: builtin/init-db.c:133
+#, c-format
+msgid "insanely long template path %s"
+msgstr "太长的模版路径 %s"
+
+#: builtin/init-db.c:141
+#, c-format
+msgid "templates not found %s"
+msgstr "模版未找到 %s"
+
+#: builtin/init-db.c:154
+#, c-format
+msgid "not copying templates of a wrong format version %d from '%s'"
+msgstr "未复制错误版本 %d 的模版自 '%s'"
+
+#: builtin/init-db.c:192
+#, c-format
+msgid "insane git directory %s"
+msgstr "不正常的 git 目录 %s"
+
+#: builtin/init-db.c:322 builtin/init-db.c:325
+#, c-format
+msgid "%s already exists"
+msgstr "%s 已经存在"
+
+#: builtin/init-db.c:354
+#, c-format
+msgid "unable to handle file type %d"
+msgstr "不能处理 %d 类型的文件"
+
+#: builtin/init-db.c:357
+#, c-format
+msgid "unable to move %s to %s"
+msgstr "不能移动 %s 至 %s"
+
+#: builtin/init-db.c:362
+#, c-format
+msgid "Could not create git link %s"
+msgstr "不能创建 git link %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:419
+#, c-format
+msgid "%s%s Git repository in %s%s\n"
+msgstr "%s%s Git 版本库于 %s%s\n"
+
+#: builtin/init-db.c:420
+msgid "Reinitialized existing"
+msgstr "重新初始化现存的"
+
+#: builtin/init-db.c:420
+msgid "Initialized empty"
+msgstr "初始化空的"
+
+#  汉字字串合并,之间无空格,故删除前导空格
+#: builtin/init-db.c:421
+msgid " shared"
+msgstr "共享的"
+
+#: builtin/init-db.c:440
+msgid "cannot tell cwd"
+msgstr "无法获知当前路径"
+
+#: builtin/init-db.c:521 builtin/init-db.c:528
+#, c-format
+msgid "cannot mkdir %s"
+msgstr "不能创建目录 %s"
+
+#: builtin/init-db.c:532
+#, c-format
+msgid "cannot chdir to %s"
+msgstr "不能切换目录到 %s"
+
+#: builtin/init-db.c:554
+#, c-format
+msgid ""
+"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
+"dir=<directory>)"
+msgstr ""
+"不允许 %s(或 --work-tree=<directory>)而没有 %s(或 --git-dir=<directory>)"
+
+#: builtin/init-db.c:578
+msgid "Cannot access current working directory"
+msgstr "不能访问当前工作目录"
+
+#: builtin/init-db.c:585
+#, c-format
+msgid "Cannot access work tree '%s'"
+msgstr "不能访问工作区 '%s'"
+
+#: builtin/log.c:185
+#, c-format
+msgid "Final output: %d %s\n"
+msgstr "最终输出:%d %s\n"
+
+#: builtin/log.c:286 builtin/log.c:709 builtin/log.c:1325 builtin/log.c:1544
+#: builtin/merge.c:348 builtin/revert.c:651 builtin/revert.c:1110
+#: builtin/shortlog.c:181
+msgid "revision walk setup failed"
+msgstr "版本遍历设置失败"
+
+#: builtin/log.c:393 builtin/log.c:479
+#, c-format
+msgid "Could not read object %s"
+msgstr "无法读取对象 %s"
+
+#: builtin/log.c:503
+#, c-format
+msgid "Unknown type: %d"
+msgstr "未知类型:%d"
+
+#: builtin/log.c:592
+msgid "format.headers without value"
+msgstr "format.headers 没有值"
+
+#: builtin/log.c:665
+msgid "name of output directory is too long"
+msgstr "输出目录名太长"
+
+#: builtin/log.c:676
+#, c-format
+msgid "Cannot open patch file %s"
+msgstr "无法打开补丁文件 %s"
+
+#: builtin/log.c:690
+msgid "Need exactly one range."
+msgstr "只需要一个范围。"
+
+#: builtin/log.c:698
+msgid "Not a range."
+msgstr "不是一个范围。"
+
+#: builtin/log.c:735
+msgid "Could not extract email from committer identity."
+msgstr "无法从提交者身份中提取邮件地址。"
+
+#: builtin/log.c:781
+msgid "Cover letter needs email format"
+msgstr "信封需要邮件地址格式"
+
+#: builtin/log.c:875
+#, c-format
+msgid "insane in-reply-to: %s"
+msgstr "不正常的 in-reply-to:%s"
+
+#: builtin/log.c:948
+msgid "Two output directories?"
+msgstr "两个输出目录?"
+
+#: builtin/log.c:1169
+#, c-format
+msgid "bogus committer info %s"
+msgstr "虚假的提交者信息 %s"
+
+#: builtin/log.c:1214
+msgid "-n and -k are mutually exclusive."
+msgstr "-n 和 -k 互斥。"
+
+#: builtin/log.c:1216
+msgid "--subject-prefix and -k are mutually exclusive."
+msgstr "--subject-prefix 和 -k 互斥。"
+
+#: builtin/log.c:1221 builtin/shortlog.c:284
+#, c-format
+msgid "unrecognized argument: %s"
+msgstr "未识别的参数:%s"
+
+#: builtin/log.c:1224
+msgid "--name-only does not make sense"
+msgstr "--name-only 无意义"
+
+#: builtin/log.c:1226
+msgid "--name-status does not make sense"
+msgstr "--name-status 无意义"
+
+#: builtin/log.c:1228
+msgid "--check does not make sense"
+msgstr "--check 无意义"
+
+#: builtin/log.c:1251
+msgid "standard output, or directory, which one?"
+msgstr "标准输出或目录,哪一个?"
+
+#: builtin/log.c:1253
+#, c-format
+msgid "Could not create directory '%s'"
+msgstr "无法创建目录 '%s'"
+
+#: builtin/log.c:1406
+msgid "Failed to create output files"
+msgstr "无法创建输出文件"
+
+#: builtin/log.c:1510
+#, c-format
+msgid ""
+"Could not find a tracked remote branch, please specify <upstream> manually.\n"
+msgstr "无法找到跟踪的远程分支,请手工提供 <upstream>。\n"
+
+#: builtin/log.c:1526 builtin/log.c:1528 builtin/log.c:1540
+#, c-format
+msgid "Unknown commit %s"
+msgstr "未知提交 %s"
+
+#: builtin/merge.c:91
+msgid "switch `m' requires a value"
+msgstr "开关 `m' 需要一个值"
+
+#: builtin/merge.c:128
+#, c-format
+msgid "Could not find merge strategy '%s'.\n"
+msgstr "无法找到合并策略 '%s'。\n"
+
+#: builtin/merge.c:129
+#, c-format
+msgid "Available strategies are:"
+msgstr "可用的策略有:"
+
+#: builtin/merge.c:134
+#, c-format
+msgid "Available custom strategies are:"
+msgstr "可用的自定义策略有:"
+
+#: builtin/merge.c:241
+msgid "could not run stash."
+msgstr "不能进行进度保存。"
+
+#: builtin/merge.c:246
+msgid "stash failed"
+msgstr "进度保存失败"
+
+#: builtin/merge.c:251
+#, c-format
+msgid "not a valid object: %s"
+msgstr "不是一个有效对象:%s"
+
+#: builtin/merge.c:270 builtin/merge.c:287
+msgid "read-tree failed"
+msgstr "读取树失败"
+
+#  注意保持前导空格
+#: builtin/merge.c:317
+msgid " (nothing to squash)"
+msgstr " (无可压缩)"
+
+#: builtin/merge.c:330
+#, c-format
+msgid "Squash commit -- not updating HEAD\n"
+msgstr "压缩提交 -- 未更新 HEAD\n"
+
+#: builtin/merge.c:334 builtin/merge.c:865 builtin/merge.c:1085
+#: builtin/merge.c:1098 builtin/revert.c:327
+#, c-format
+msgid "Could not write to '%s'"
+msgstr "无法写入 '%s'"
+
+#: builtin/merge.c:362
+msgid "Writing SQUASH_MSG"
+msgstr "写入 SQUASH_MSG"
+
+#: builtin/merge.c:364
+msgid "Finishing SQUASH_MSG"
+msgstr "完成 SQUASH_MSG"
+
+#: builtin/merge.c:386
+#, c-format
+msgid "No merge message -- not updating HEAD\n"
+msgstr "无合并信息 -- 未更新 HEAD\n"
+
+#: builtin/merge.c:435
+#, c-format
+msgid "'%s' does not point to a commit"
+msgstr "'%s' 没有指向一个提交"
+
+#: builtin/merge.c:534
+#, c-format
+msgid "Bad branch.%s.mergeoptions string: %s"
+msgstr "错的 branch.%s.mergeoptions 字串:%s"
+
+#: builtin/merge.c:627
+msgid "git write-tree failed to write a tree"
+msgstr "git write-tree 无法写入一树对象"
+
+#: builtin/merge.c:677
+msgid "failed to read the cache"
+msgstr "无法读取缓存"
+
+#: builtin/merge.c:694
+msgid "Unable to write index."
+msgstr "不能写暂存区。"
+
+#: builtin/merge.c:707
+msgid "Not handling anything other than two heads merge."
+msgstr "不能处理两个头合并之外的任何操作。"
+
+#: builtin/merge.c:721
+#, c-format
+msgid "Unknown option for merge-recursive: -X%s"
+msgstr "merge-recursive 的未知选项:-X%s"
+
+#: builtin/merge.c:735
+#, c-format
+msgid "unable to write %s"
+msgstr "不能写 %s"
+
+#: builtin/merge.c:862 builtin/merge.c:973 builtin/merge.c:1083
+#: builtin/merge.c:1093 builtin/revert.c:325
+#, c-format
+msgid "Could not open '%s' for writing"
+msgstr "无法为写入打开 '%s'"
+
+#: builtin/merge.c:874
+#, c-format
+msgid "Could not read from '%s'"
+msgstr "不能从 '%s' 读取"
+
+#: builtin/merge.c:883
+#, c-format
+msgid "Not committing merge; use 'git commit' to complete the merge.\n"
+msgstr "未提交合并,使用 'git commit' 完成此次合并。\n"
+
+#: builtin/merge.c:903
+msgid "Empty commit message."
+msgstr "空提交信息。"
+
+#: builtin/merge.c:915
+#, c-format
+msgid "Wonderful.\n"
+msgstr "太棒了。\n"
+
+#: builtin/merge.c:988
+#, c-format
+msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
+msgstr "自动合并失败,修正冲突然后提交修正的结果。\n"
+
+#: builtin/merge.c:1004
+#, c-format
+msgid "'%s' is not a commit"
+msgstr "'%s' 不是一个提交"
+
+#: builtin/merge.c:1045
+msgid "No current branch."
+msgstr "当前不在分支上。"
+
+#: builtin/merge.c:1047
+msgid "No remote for the current branch."
+msgstr "当前分支没有远程版本库。"
+
+#: builtin/merge.c:1049
+msgid "No default upstream defined for the current branch."
+msgstr "当前分支未定义默认上游分支。"
+
+#: builtin/merge.c:1054
+#, c-format
+msgid "No remote tracking branch for %s from %s"
+msgstr "%s 没有来自 %s 的远程跟踪分支"
+
+#: builtin/merge.c:1149
+msgid "There is no merge to abort (MERGE_HEAD missing)."
+msgstr "没有要终止的合并(MERGE_HEAD 丢失)"
+
+#: builtin/merge.c:1165 git-pull.sh:31
+msgid ""
+"You have not concluded your merge (MERGE_HEAD exists).\n"
+"Please, commit your changes before you can merge."
+msgstr ""
+"您尚未结束您的合并(存在 MERGE_HEAD)。\n"
+"请先提交您的修改,您才能合并。"
+
+#: builtin/merge.c:1168 git-pull.sh:34
+msgid "You have not concluded your merge (MERGE_HEAD exists)."
+msgstr "您尚未结束您的合并(存在 MERGE_HEAD)。"
+
+#: builtin/merge.c:1172
+msgid ""
+"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
+"Please, commit your changes before you can merge."
+msgstr ""
+"您尚未结束您的拣选(存在 CHERRY_PICK_HEAD)。\n"
+"请先提交您的修改,您才能合并。"
+
+#: builtin/merge.c:1175
+msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
+msgstr "您尚未结束您的拣选(存在 CHERRY_PICK_HEAD)。"
+
+#: builtin/merge.c:1184
+msgid "You cannot combine --squash with --no-ff."
+msgstr "您不能将 --squash 与 --no-ff 共用。"
+
+#: builtin/merge.c:1189
+msgid "You cannot combine --no-ff with --ff-only."
+msgstr "您不能将 --no-ff 与 --ff-only 共用。"
+
+#: builtin/merge.c:1196
+msgid "No commit specified and merge.defaultToUpstream not set."
+msgstr "未指出提交并且 merge.defaultToUpstream 未设置。"
+
+#: builtin/merge.c:1227
+msgid "Can merge only exactly one commit into empty head"
+msgstr "只可将一个提交合并到空分支上"
+
+#: builtin/merge.c:1230
+msgid "Squash commit into empty head not supported yet"
+msgstr "尚不支持到空分支的压缩提交"
+
+#: builtin/merge.c:1232
+msgid "Non-fast-forward commit does not make sense into an empty head"
+msgstr "到空分支的非快进式提交没有意义"
+
+#: builtin/merge.c:1236 builtin/merge.c:1280
+#, c-format
+msgid "%s - not something we can merge"
+msgstr "%s - 不是我们可以合并的东西"
+
+#: builtin/merge.c:1341
+#, c-format
+msgid "Updating %s..%s\n"
+msgstr "更新 %s..%s\n"
+
+#: builtin/merge.c:1379
+#, c-format
+msgid "Trying really trivial in-index merge...\n"
+msgstr "尝试非常小的暂存区内合并...\n"
+
+#: builtin/merge.c:1386
+#, c-format
+msgid "Nope.\n"
+msgstr "无。\n"
+
+#: builtin/merge.c:1418
+msgid "Not possible to fast-forward, aborting."
+msgstr "不可能快进式,终止。"
+
+#: builtin/merge.c:1441 builtin/merge.c:1518
+#, c-format
+msgid "Rewinding the tree to pristine...\n"
+msgstr "将树回滚至原始状态...\n"
+
+#: builtin/merge.c:1445
+#, c-format
+msgid "Trying merge strategy %s...\n"
+msgstr "尝试合并策略 %s...\n"
+
+#: builtin/merge.c:1509
+#, c-format
+msgid "No merge strategy handled the merge.\n"
+msgstr "没有合并策略处理此合并。\n"
+
+#: builtin/merge.c:1511
+#, c-format
+msgid "Merge with strategy %s failed.\n"
+msgstr "使用策略 %s 合并失败。\n"
+
+#: builtin/merge.c:1520
+#, c-format
+msgid "Using the %s to prepare resolving by hand.\n"
+msgstr "使用 %s 以准备手工解决。\n"
+
+#: builtin/merge.c:1531
+#, c-format
+msgid "Automatic merge went well; stopped before committing as requested\n"
+msgstr "自动合并进展顺利,按要求在提交前停止\n"
+
+#: builtin/mv.c:108
+#, c-format
+msgid "Checking rename of '%s' to '%s'\n"
+msgstr "检查 '%s' 到 '%s' 的重命名\n"
+
+#: builtin/mv.c:112
+msgid "bad source"
+msgstr "坏的源"
+
+#: builtin/mv.c:115
+msgid "can not move directory into itself"
+msgstr "不能将目录移动到自身"
+
+#: builtin/mv.c:118
+msgid "cannot move directory over file"
+msgstr "不能将目录移动到文件"
+
+#: builtin/mv.c:128
+#, c-format
+msgid "Huh? %.*s is in index?"
+msgstr "嗯?%.*s 在暂存区中?"
+
+#: builtin/mv.c:140
+msgid "source directory is empty"
+msgstr "源目录为空"
+
+#: builtin/mv.c:171
+msgid "not under version control"
+msgstr "不在版本控制之下"
+
+#: builtin/mv.c:173
+msgid "destination exists"
+msgstr "目标已存在"
+
+#: builtin/mv.c:181
+#, c-format
+msgid "overwriting '%s'"
+msgstr "覆盖 '%s'"
+
+#: builtin/mv.c:184
+msgid "Cannot overwrite"
+msgstr "不能覆盖"
+
+#: builtin/mv.c:187
+msgid "multiple sources for the same target"
+msgstr "同一目标具有多个源"
+
+#: builtin/mv.c:202
+#, c-format
+msgid "%s, source=%s, destination=%s"
+msgstr "%s,源=%s,目标=%s"
+
+#: builtin/mv.c:212
+#, c-format
+msgid "Renaming %s to %s\n"
+msgstr "重命名 %s 至 %s\n"
+
+#: builtin/mv.c:215
+#, c-format
+msgid "renaming '%s' failed"
+msgstr "重命名 '%s' 失败"
+
+#: builtin/notes.c:139
+#, c-format
+msgid "unable to start 'show' for object '%s'"
+msgstr "不能为对象 '%s' 开始 'show'"
+
+#: builtin/notes.c:145
+msgid "can't fdopen 'show' output fd"
+msgstr "不能打开 'show' 输出文件句柄"
+
+#: builtin/notes.c:155
+#, c-format
+msgid "failed to close pipe to 'show' for object '%s'"
+msgstr "无法为对象 '%s' 的 'show' 关闭管道"
+
+#: builtin/notes.c:158
+#, c-format
+msgid "failed to finish 'show' for object '%s'"
+msgstr "无法为对象 '%s' 完成 'show'"
+
+#: builtin/notes.c:175 builtin/tag.c:310
+#, c-format
+msgid "could not create file '%s'"
+msgstr "不能创建文件 '%s'"
+
+#: builtin/notes.c:189
+msgid "Please supply the note contents using either -m or -F option"
+msgstr "请通过 -m 或 -F 选项为注解提供内容"
+
+#: builtin/notes.c:210 builtin/notes.c:973
+#, c-format
+msgid "Removing note for object %s\n"
+msgstr "删除对象 %s 的注解\n"
+
+#: builtin/notes.c:215
+msgid "unable to write note object"
+msgstr "不能写注解对象"
+
+#: builtin/notes.c:217
+#, c-format
+msgid "The note contents has been left in %s"
+msgstr "注解内容被留在文件 %s 中"
+
+#: builtin/notes.c:251 builtin/tag.c:465
+#, c-format
+msgid "cannot read '%s'"
+msgstr "不能读取 '%s'"
+
+#: builtin/notes.c:253 builtin/tag.c:468
+#, c-format
+msgid "could not open or read '%s'"
+msgstr "不能打开或读取 '%s'"
+
+#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447
+#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644
+#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766
+#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:481
+#, c-format
+msgid "Failed to resolve '%s' as a valid ref."
+msgstr "无法解析 '%s' 为一个有效引用"
+
+#: builtin/notes.c:275
+#, c-format
+msgid "Failed to read object '%s'."
+msgstr "无法读取对象 '%s'。"
+
+#: builtin/notes.c:299
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr "不能提交未初始化/未引用的注解树"
+
+#: builtin/notes.c:340
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "错误的 notes.rewriteMode 值:'%s'"
+
+#: builtin/notes.c:350
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr "拒绝向 %s(在 refs/notes/ 之外)写入注解"
+
+#. TRANSLATORS: The first %s is the name of the
+#. environment variable, the second %s is its value
+#: builtin/notes.c:377
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr "错误的 %s 值:'%s'"
+
+#: builtin/notes.c:441
+#, c-format
+msgid "Malformed input line: '%s'."
+msgstr "非法的输入行:'%s'。"
+
+#: builtin/notes.c:456
+#, c-format
+msgid "Failed to copy notes from '%s' to '%s'"
+msgstr "无法从 '%s' 拷贝注解到 '%s'"
+
+#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627
+#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759
+#: builtin/notes.c:1033
+msgid "too many parameters"
+msgstr "参数太多"
+
+#: builtin/notes.c:513 builtin/notes.c:772
+#, c-format
+msgid "No note found for object %s."
+msgstr "未发现对象 %s 的注解。"
+
+#: builtin/notes.c:580
+#, c-format
+msgid ""
+"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr "不能添加注解。发现对象 %s 已存在注解。使用 '-f' 覆盖现存注解"
+
+#: builtin/notes.c:585 builtin/notes.c:662
+#, c-format
+msgid "Overwriting existing notes for object %s\n"
+msgstr "覆盖对象 %s 现存注解\n"
+
+#: builtin/notes.c:635
+msgid "too few parameters"
+msgstr "参数太少"
+
+#: builtin/notes.c:656
+#, c-format
+msgid ""
+"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
+"existing notes"
+msgstr "不能拷贝注解。发现对象 %s 已存在注解。使用 '-f' 覆盖现存注解"
+
+#: builtin/notes.c:668
+#, c-format
+msgid "Missing notes on source object %s. Cannot copy."
+msgstr "源对象 %s 缺少注解。不能拷贝。"
+
+#: builtin/notes.c:717
+#, c-format
+msgid ""
+"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
+"Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
+msgstr ""
+"选项 -m/-F/-c/-C 已为 'edit' 子命令废弃。\n"
+"请换用 'git notes add -f -m/-F/-c/-C'。\n"
+
+#: builtin/notes.c:971
+#, c-format
+msgid "Object %s has no note\n"
+msgstr "对象 %s 没有注解\n"
+
+#: builtin/notes.c:1103
+#, c-format
+msgid "Unknown subcommand: %s"
+msgstr "未知子命令:%s"
+
+#: builtin/push.c:44
+msgid "tag shorthand without <tag>"
+msgstr "tag 简写没有跟 <tag> 参数"
+
+#: builtin/push.c:63
+msgid "--delete only accepts plain target ref names"
+msgstr "--delete 只接受简单的引用名称"
+
+#: builtin/push.c:73
+#, c-format
+msgid ""
+"You are not currently on a branch.\n"
+"To push the history leading to the current (detached HEAD)\n"
+"state now, use\n"
+"\n"
+"    git push %s HEAD:<name-of-remote-branch>\n"
+msgstr ""
+"您当前不在一个分支上。\n"
+"现在为推送当前历史(分离头指针),使用\n"
+"\n"
+"    git push %s HEAD:<name-of-remote-branch>\n"
+
+#: builtin/push.c:80
+#, c-format
+msgid ""
+"The current branch %s has no upstream branch.\n"
+"To push the current branch and set the remote as upstream, use\n"
+"\n"
+"    git push --set-upstream %s %s\n"
+msgstr ""
+"当前分支 %s 没有对应的上游分支。\n"
+"为推送当前分支并建立与远程上游的跟踪,使用\n"
+"\n"
+"    git push --set-upstream %s %s\n"
+
+#: builtin/push.c:88
+#, c-format
+msgid "The current branch %s has multiple upstream branches, refusing to push."
+msgstr "当前分支 %s 有多个上游分支,拒绝推送。"
+
+#: builtin/push.c:111
+msgid ""
+"You didn't specify any refspecs to push, and push.default is \"nothing\"."
+msgstr "您没有为推送提供任何引用表达式,并且 push.default 为 \"nothing\"。"
+
+#: builtin/push.c:131
+#, c-format
+msgid "Pushing to %s\n"
+msgstr "推送到 %s\n"
+
+#: builtin/push.c:135
+#, c-format
+msgid "failed to push some refs to '%s'"
+msgstr "无法推送一些引用到 '%s'"
+
+#: builtin/push.c:143
+#, c-format
+msgid ""
+"To prevent you from losing history, non-fast-forward updates were rejected\n"
+"Merge the remote changes (e.g. 'git pull') before pushing again.  See the\n"
+"'Note about fast-forwards' section of 'git push --help' for details.\n"
+msgstr ""
+"为防止您丢失提交历史,禁止非快进式推送。\n"
+"再次推送前先与远程变更合并(如 'git pull')。详见\n"
+"'git push --help' 中的 'Note about fast-forwards' 小节。\n"
+
+#: builtin/push.c:160
+#, c-format
+msgid "bad repository '%s'"
+msgstr "错误的版本库 '%s'"
+
+#: builtin/push.c:161
+msgid ""
+"No configured push destination.\n"
+"Either specify the URL from the command-line or configure a remote "
+"repository using\n"
+"\n"
+"    git remote add <name> <url>\n"
+"\n"
+"and then push using the remote name\n"
+"\n"
+"    git push <name>\n"
+msgstr ""
+"未配置推送目标。\n"
+"或者通过命令行提供URL,或者用下面命令配置一个远程版本库\n"
+"\n"
+"    git remote add <name> <url>\n"
+"\n"
+"然后使用该远程版本库名执行推送\n"
+"\n"
+"    git push <name>\n"
+
+#: builtin/push.c:176
+msgid "--all and --tags are incompatible"
+msgstr "--all 和 --tags 不兼容"
+
+#: builtin/push.c:177
+msgid "--all can't be combined with refspecs"
+msgstr "--all 不能和引用表达式共用"
+
+#: builtin/push.c:182
+msgid "--mirror and --tags are incompatible"
+msgstr "--mirror 和 --tags 不兼容"
+
+#: builtin/push.c:183
+msgid "--mirror can't be combined with refspecs"
+msgstr "--mirror 不能和引用表达式共用"
+
+#: builtin/push.c:188
+msgid "--all and --mirror are incompatible"
+msgstr "--all 和 --mirror 不兼容"
+
+#: builtin/push.c:272
+msgid "--delete is incompatible with --all, --mirror and --tags"
+msgstr "--delete 与 --all、--mirror 及 --tags 不兼容"
+
+#: builtin/push.c:274
+msgid "--delete doesn't make sense without any refs"
+msgstr "--delete 未接任何引用没有意义"
+
+#: builtin/reset.c:33
+msgid "mixed"
+msgstr "混杂"
+
+#: builtin/reset.c:33
+msgid "soft"
+msgstr "软性"
+
+#: builtin/reset.c:33
+msgid "hard"
+msgstr "硬性"
+
+#: builtin/reset.c:33
+msgid "keep"
+msgstr "保持"
+
+#: builtin/reset.c:77
+msgid "You do not have a valid HEAD."
+msgstr "您没有一个有效的 HEAD。"
+
+#: builtin/reset.c:79
+msgid "Failed to find tree of HEAD."
+msgstr "无法找到 HEAD 指向的树。"
+
+#: builtin/reset.c:85
+#, c-format
+msgid "Failed to find tree of %s."
+msgstr "无法找到 %s 指向的树。"
+
+#: builtin/reset.c:96
+msgid "Could not write new index file."
+msgstr "无法写入新的暂存区文件。"
+
+#: builtin/reset.c:106
+#, c-format
+msgid "HEAD is now at %s"
+msgstr "HEAD 现在位于 %s"
+
+#: builtin/reset.c:130
+msgid "Could not read index"
+msgstr "不能读取暂存区"
+
+#: builtin/reset.c:133
+msgid "Unstaged changes after reset:"
+msgstr "重置后变更撤出暂存区:"
+
+#  汉字之间无空格,故删除%s前后空格
+#: builtin/reset.c:223
+#, c-format
+msgid "Cannot do a %s reset in the middle of a merge."
+msgstr "在合并过程中不能做%s重置操作。"
+
+#: builtin/reset.c:297
+#, c-format
+msgid "Could not parse object '%s'."
+msgstr "不能解析对象 '%s'。"
+
+#: builtin/reset.c:302
+msgid "--patch is incompatible with --{hard,mixed,soft}"
+msgstr "--patch 与 --{hard,mixed,soft} 不兼容"
+
+#: builtin/reset.c:311
+msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
+msgstr "--mixed 带路径已弃用,代之以 'git reset -- <paths>'。"
+
+#  汉字之间无空格,故删除%s前后空格
+#: builtin/reset.c:313
+#, c-format
+msgid "Cannot do %s reset with paths."
+msgstr "不能带路径进行%s重置。"
+
+#  汉字之间无空格,故删除%s前后空格
+#: builtin/reset.c:325
+#, c-format
+msgid "%s reset is not allowed in a bare repository"
+msgstr "不能对裸版本库进行%s重置"
+
+#: builtin/reset.c:341
+#, c-format
+msgid "Could not reset index file to revision '%s'."
+msgstr "不能重置暂存区至版本 '%s'。"
+
+#: builtin/revert.c:114 builtin/revert.c:135
+#, c-format
+msgid "%s: %s cannot be used with %s"
+msgstr "%s: %s 不能和 %s 共用"
+
+#: builtin/revert.c:170
+msgid "program error"
+msgstr "程序错误"
+
+#: builtin/revert.c:360 builtin/revert.c:886 builtin/revert.c:969
+#, c-format
+msgid "Could not write to %s"
+msgstr "不能写入 %s"
+
+#: builtin/revert.c:363
+#, c-format
+msgid "Error wrapping up %s"
+msgstr "错误收尾 %s"
+
+#: builtin/revert.c:378
+msgid "Your local changes would be overwritten by cherry-pick."
+msgstr "您的本地修改将被拣选操作覆盖。"
+
+#: builtin/revert.c:380
+msgid "Your local changes would be overwritten by revert."
+msgstr "您的本地修改将被还原操作覆盖。"
+
+#: builtin/revert.c:383
+msgid "Commit your changes or stash them to proceed."
+msgstr "提交您的修改或保存进度后再继续。"
+
+#. TRANSLATORS: %s will be "revert" or "cherry-pick"
+#: builtin/revert.c:433
+#, c-format
+msgid "%s: Unable to write new index file"
+msgstr "%s:无法写入新暂存区文件"
+
+#: builtin/revert.c:499
+msgid "Your index file is unmerged."
+msgstr "您的暂存区文件未完成合并。"
+
+#: builtin/revert.c:502
+msgid "You do not have a valid HEAD"
+msgstr "您没有一个有效的 HEAD"
+
+#: builtin/revert.c:517
+#, c-format
+msgid "Commit %s is a merge but no -m option was given."
+msgstr "提交 %s 是一个合并提交但未提供 -m 选项。"
+
+#: builtin/revert.c:525
+#, c-format
+msgid "Commit %s does not have parent %d"
+msgstr "提交 %s 没有父提交 %d"
+
+#: builtin/revert.c:529
+#, c-format
+msgid "Mainline was specified but commit %s is not a merge."
+msgstr "提供了主线但提交 %s 不是一个合并。"
+
+#. TRANSLATORS: The first %s will be "revert" or
+#. "cherry-pick", the second %s a SHA1
+#: builtin/revert.c:540
+#, c-format
+msgid "%s: cannot parse parent commit %s"
+msgstr "%s:不能解析父提交 %s"
+
+#: builtin/revert.c:544
+#, c-format
+msgid "Cannot get commit message for %s"
+msgstr "不能得到 %s 的提交说明"
+
+#: builtin/revert.c:628
+#, c-format
+msgid "could not revert %s... %s"
+msgstr "不能还原 %s... %s"
+
+#: builtin/revert.c:629
+#, c-format
+msgid "could not apply %s... %s"
+msgstr "不能应用 %s... %s"
+
+#: builtin/revert.c:654
+msgid "empty commit set passed"
+msgstr "提供了空的提交集"
+
+#: builtin/revert.c:662
+#, c-format
+msgid "git %s: failed to read the index"
+msgstr "git %s: 无法读取暂存区"
+
+#: builtin/revert.c:667
+#, c-format
+msgid "git %s: failed to refresh the index"
+msgstr "git %s: 无法刷新暂存区"
+
+#: builtin/revert.c:752
+#, c-format
+msgid "Cannot %s during a %s"
+msgstr "无法 %s 在 %s 过程中"
+
+#: builtin/revert.c:774
+#, c-format
+msgid "Could not parse line %d."
+msgstr "无法解析第 %d 行。"
+
+#: builtin/revert.c:779
+msgid "No commits parsed."
+msgstr "未有提交被解析。"
+
+#: builtin/revert.c:792
+#, c-format
+msgid "Could not open %s"
+msgstr "不能打开 %s"
+
+#: builtin/revert.c:796
+#, c-format
+msgid "Could not read %s."
+msgstr "不能读取 %s。"
+
+#: builtin/revert.c:803
+#, c-format
+msgid "Unusable instruction sheet: %s"
+msgstr "无用的指令表单:%s"
+
+#: builtin/revert.c:831
+#, c-format
+msgid "Invalid key: %s"
+msgstr "无效键名:%s"
+
+#: builtin/revert.c:834
+#, c-format
+msgid "Invalid value for %s: %s"
+msgstr "无效的 %s 值:%s"
+
+#: builtin/revert.c:846
+#, c-format
+msgid "Malformed options sheet: %s"
+msgstr "非法的选项表单:%s"
+
+#: builtin/revert.c:867
+msgid "a cherry-pick or revert is already in progress"
+msgstr "一个拣选或还原操作已在进行"
+
+#: builtin/revert.c:868
+msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
+msgstr "尝试 \"git cherry-pick (--continue | --quit | --abort)\""
+
+#: builtin/revert.c:872
+#, c-format
+msgid "Could not create sequencer directory %s"
+msgstr "无法创建序列目录 %s"
+
+#: builtin/revert.c:888 builtin/revert.c:973
+#, c-format
+msgid "Error wrapping up %s."
+msgstr "错误收尾 %s。"
+
+#: builtin/revert.c:907 builtin/revert.c:1041
+msgid "no cherry-pick or revert in progress"
+msgstr "没有拣选或还原操作在进行"
+
+#: builtin/revert.c:909
+msgid "cannot resolve HEAD"
+msgstr "不能解析 HEAD"
+
+#: builtin/revert.c:911
+msgid "cannot abort from a branch yet to be born"
+msgstr "不能从未初始分支终止"
+
+#: builtin/revert.c:933
+#, c-format
+msgid "cannot open %s: %s"
+msgstr "不能打开 %s:%s"
+
+#: builtin/revert.c:936
+#, c-format
+msgid "cannot read %s: %s"
+msgstr "不能读取 %s:%s"
+
+#: builtin/revert.c:937
+msgid "unexpected end of file"
+msgstr "未预期的文件结束"
+
+#: builtin/revert.c:943
+#, c-format
+msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
+msgstr "保存预拣选提交的 HEAD 文件 '%s' 损坏"
+
+#: builtin/revert.c:966
+#, c-format
+msgid "Could not format %s."
+msgstr "不能格式化 %s。"
+
+#: builtin/revert.c:1128
+msgid "Can't revert as initial commit"
+msgstr "不能作为初始提交还原"
+
+#: builtin/revert.c:1129
+msgid "Can't cherry-pick into empty head"
+msgstr "不能拣选到空分支"
+
+#: builtin/revert.c:1149
+msgid "revert failed"
+msgstr "还原失败"
+
+#: builtin/revert.c:1164
+msgid "cherry-pick failed"
+msgstr "拣选失败"
+
+#: builtin/rm.c:109
+#, c-format
+msgid ""
+"'%s' has staged content different from both the file and the HEAD\n"
+"(use -f to force removal)"
+msgstr ""
+"'%s' 暂存的内容和工作区文件及 HEAD 中的都不一样\n"
+"(使用 -f 强制删除)"
+
+#: builtin/rm.c:115
+#, c-format
+msgid ""
+"'%s' has changes staged in the index\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+"'%s' 有变更已加入暂存区中\n"
+"(使用 --cached 保存文件,或用 -f 强制删除)"
+
+#: builtin/rm.c:119
+#, c-format
+msgid ""
+"'%s' has local modifications\n"
+"(use --cached to keep the file, or -f to force removal)"
+msgstr ""
+"'%s' 有本地修改\n"
+"(使用 --cached 保存文件,或用 -f 强制删除)"
+
+#: builtin/rm.c:194
+#, c-format
+msgid "not removing '%s' recursively without -r"
+msgstr "未提供 -r 选项不会递归删除 '%s'"
+
+#: builtin/rm.c:230
+#, c-format
+msgid "git rm: unable to remove %s"
+msgstr "git rm:不能删除 %s"
+
+#: builtin/shortlog.c:157
+#, c-format
+msgid "Missing author: %s"
+msgstr "缺少作者:%s"
+
+#: builtin/tag.c:172
+#, c-format
+msgid "tag name too long: %.*s..."
+msgstr "tag 名字太长:%.*s..."
+
+#: builtin/tag.c:177
+#, c-format
+msgid "tag '%s' not found."
+msgstr "tag '%s' 未发现。"
+
+#: builtin/tag.c:192
+#, c-format
+msgid "Deleted tag '%s' (was %s)\n"
+msgstr "已删除 tag '%s'(曾为 %s)\n"
+
+#: builtin/tag.c:204
+#, c-format
+msgid "could not verify the tag '%s'"
+msgstr "不能校验 tag '%s'"
+
+#: builtin/tag.c:214
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be ignored.\n"
+"#\n"
+msgstr ""
+"\n"
+"#\n"
+"# 输入一个 tag 说明\n"
+"# 以 '#' 开头的行将被忽略。\n"
+"#\n"
+
+#: builtin/tag.c:221
+msgid ""
+"\n"
+"#\n"
+"# Write a tag message\n"
+"# Lines starting with '#' will be kept; you may remove them yourself if you "
+"want to.\n"
+"#\n"
+msgstr ""
+"\n"
+"#\n"
+"# 输入一个 tag 说明\n"
+"# 以 '#' 开头的行将被忽略,您可以删除它们如果您想这样做。\n"
+"#\n"
+
+#: builtin/tag.c:261
+msgid "unable to sign the tag"
+msgstr "无法签署 tag"
+
+#: builtin/tag.c:263
+msgid "unable to write tag file"
+msgstr "无法写 tag 文件"
+
+#: builtin/tag.c:288
+msgid "bad object type."
+msgstr "无效的对象类型"
+
+#: builtin/tag.c:301
+msgid "tag header too big."
+msgstr "tag 头信息太大"
+
+#: builtin/tag.c:333
+msgid "no tag message?"
+msgstr "无 tag 说明?"
+
+#: builtin/tag.c:339
+#, c-format
+msgid "The tag message has been left in %s\n"
+msgstr "tag 说明被保留在 %s\n"
+
+#: builtin/tag.c:448
+msgid "-n option is only allowed with -l."
+msgstr "-n 选项只允许和 -l 共用。"
+
+#: builtin/tag.c:450
+msgid "--contains option is only allowed with -l."
+msgstr "--contains 选项只允许和 -l 共用。"
+
+#: builtin/tag.c:458
+msgid "only one -F or -m option is allowed."
+msgstr "只允许一个 -F 或 -m 选项。"
+
+#: builtin/tag.c:478
+msgid "too many params"
+msgstr "太多参数"
+
+#: builtin/tag.c:484
+#, c-format
+msgid "'%s' is not a valid tag name."
+msgstr "'%s' 不是一个有效的tag名称"
+
+#: builtin/tag.c:489
+#, c-format
+msgid "tag '%s' already exists"
+msgstr "tag '%s' 已存在"
+
+#: builtin/tag.c:507
+#, c-format
+msgid "%s: cannot lock the ref"
+msgstr "%s:不能锁定引用"
+
+#: builtin/tag.c:509
+#, c-format
+msgid "%s: cannot update the ref"
+msgstr "%s:不能更新引用"
+
+#: builtin/tag.c:511
+#, c-format
+msgid "Updated tag '%s' (was %s)\n"
+msgstr "已更新tag '%s'(曾为 %s)\n"
+
+#: git-am.sh:48
+msgid "You need to set your committer info first"
+msgstr "您需要先设置你的提交者信息"
+
+#: git-am.sh:134
+msgid "Repository lacks necessary blobs to fall back on 3-way merge."
+msgstr "版本库缺乏必要的 blob 数据以进行三路合并。"
+
+#: git-am.sh:143
+msgid ""
+"Did you hand edit your patch?\n"
+"It does not apply to blobs recorded in its index."
+msgstr ""
+"您是否曾手动编辑过您的补丁?\n"
+"无法应用补丁到暂存区的数据中。"
+
+#: git-am.sh:152
+msgid "Falling back to patching base and 3-way merge..."
+msgstr "转而使用补丁应用的基础版本和三路合并..."
+
+#: git-am.sh:264
+msgid "Only one StGIT patch series can be applied at once"
+msgstr "一次只能有一个 StGIT 补丁队列被应用"
+
+#: git-am.sh:351
+#, sh-format
+msgid "Patch format $patch_format is not supported."
+msgstr "不支持 $patch_format 补丁格式。"
+
+#: git-am.sh:353
+msgid "Patch format detection failed."
+msgstr "补丁格式检测失败。"
+
+#: git-am.sh:403
+msgid "-d option is no longer supported.  Do not use."
+msgstr "不再支持 -d 选项。不要使用。"
+
+#: git-am.sh:466
+#, sh-format
+msgid "previous rebase directory $dotest still exists but mbox given."
+msgstr "之前的变基目录 $dotest 仍然存在但给出了mbox。"
+
+#: git-am.sh:471
+msgid "Please make up your mind. --skip or --abort?"
+msgstr "请下决心。--skip 或是 --abort ?"
+
+#: git-am.sh:498
+msgid "Resolve operation not in progress, we are not resuming."
+msgstr "解决操作未进行,我们不会继续。"
+
+#: git-am.sh:564
+#, sh-format
+msgid "Dirty index: cannot apply patches (dirty: $files)"
+msgstr "脏的暂存区:不能应用补丁(脏文件:$files)"
+
+#: git-am.sh:731
+msgid "cannot be interactive without stdin connected to a terminal."
+msgstr "没有和终端关联的标准输入不能进行交互式操作。"
+
+#  注意保持句尾空格
+#. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
+#. in your translation. The program will only accept English
+#. input at this point.
+#: git-am.sh:742
+msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
+msgstr "应用?[y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
+
+#: git-am.sh:778
+#, sh-format
+msgid "Applying: $FIRSTLINE"
+msgstr "正应用:$FIRSTLINE"
+
+#: git-am.sh:823
+msgid "No changes -- Patch already applied."
+msgstr "没有变更 -- 补丁已经应用过。"
+
+#: git-am.sh:849
+msgid "applying to an empty history"
+msgstr "正应用到一个空历史上"
+
+#  注意保持句尾空格
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:54
+msgid "Do you want me to do it for you [Y/n]? "
+msgstr "您想让我为您这样做么[Y/n]? "
+
+#: git-bisect.sh:95
+#, sh-format
+msgid "unrecognised option: '$arg'"
+msgstr "未识别的选项:'$arg'"
+
+#: git-bisect.sh:99
+#, sh-format
+msgid "'$arg' does not appear to be a valid revision"
+msgstr "'$arg' 看起来不像是一个有效的版本"
+
+#: git-bisect.sh:117
+msgid "Bad HEAD - I need a HEAD"
+msgstr "坏的 HEAD - 我需要一个 HEAD"
+
+#: git-bisect.sh:130
+#, sh-format
+msgid ""
+"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
+msgstr "检出 '$start_head' 失败。尝试 'git bisect reset <validbranch>'。"
+
+#: git-bisect.sh:140
+msgid "won't bisect on seeked tree"
+msgstr "不会在已查找过的树上二分查找"
+
+#: git-bisect.sh:144
+msgid "Bad HEAD - strange symbolic ref"
+msgstr "错误的 HEAD - 奇怪的符号引用"
+
+#: git-bisect.sh:189
+#, sh-format
+msgid "Bad bisect_write argument: $state"
+msgstr "错误的bisect_write参数:$state"
+
+#: git-bisect.sh:218
+#, sh-format
+msgid "Bad rev input: $arg"
+msgstr "输入错误版本:$arg"
+
+#: git-bisect.sh:232
+msgid "Please call 'bisect_state' with at least one argument."
+msgstr "请在调用 'bisect_state' 时跟至少一个参数。"
+
+#: git-bisect.sh:244
+#, sh-format
+msgid "Bad rev input: $rev"
+msgstr "输入坏的版本:$rev"
+
+#: git-bisect.sh:250
+msgid "'git bisect bad' can take only one argument."
+msgstr "'git bisect bad' 只能带一个参数。"
+
+#  注意保持句尾空格
+#. TRANSLATORS: Make sure to include [Y] and [n] in your
+#. translation. The program will only accept English input
+#. at this point.
+#: git-bisect.sh:279
+msgid "Are you sure [Y/n]? "
+msgstr "您确认么[Y/n]? "
+
+#: git-bisect.sh:354
+#, sh-format
+msgid "'$invalid' is not a valid commit"
+msgstr "'$invalid' 不是一个有效的提交"
+
+#: git-bisect.sh:363
+#, sh-format
+msgid ""
+"Could not check out original HEAD '$branch'.\n"
+"Try 'git bisect reset <commit>'."
+msgstr ""
+"不能检出原始 HEAD '$branch'。\n"
+"尝试 'git bisect reset <commit>'。"
+
+#: git-bisect.sh:390
+msgid "No logfile given"
+msgstr "未提供日志文件"
+
+#: git-bisect.sh:391
+#, sh-format
+msgid "cannot read $file for replaying"
+msgstr "不能读取 $file 来重放"
+
+#: git-bisect.sh:408
+msgid "?? what are you talking about?"
+msgstr "?? 您在说什么?"
+
+#: git-bisect.sh:474
+msgid "We are not bisecting."
+msgstr "我们没有进行二分查找。"
+
+#: git-pull.sh:21
+msgid ""
+"Pull is not possible because you have unmerged files.\n"
+"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
+"as appropriate to mark resolution, or use 'git commit -a'."
+msgstr ""
+"Pull 不可用,因为你尚有未合并的文件。请先在工作区改正文件,\n"
+"然后酌情使用 'git add/rm <file>' 标记解决方案,\n"
+"或使用 'git commit -a'。"
+
+#: git-pull.sh:25
+msgid "Pull is not possible because you have unmerged files."
+msgstr "Pull 不可用,因为你尚有未合并的文件。"
+
+#: git-pull.sh:193
+msgid "updating an unborn branch with changes added to the index"
+msgstr "更新尚未诞生的分支,变更添加至暂存区"
+
+#: git-pull.sh:249
+msgid "Cannot merge multiple branches into empty head"
+msgstr "无法将多个分支合并到空分支"
+
+#: git-pull.sh:253
+msgid "Cannot rebase onto multiple branches"
+msgstr "无法变基到多个分支"
+
+#: git-stash.sh:51
+msgid "git stash clear with parameters is unimplemented"
+msgstr "git stash clear 不支持参数"
+
+#: git-stash.sh:74
+msgid "You do not have the initial commit yet"
+msgstr "您尚未建立初始提交"
+
+#: git-stash.sh:89
+msgid "Cannot save the current index state"
+msgstr "无法保存当前暂存区状态"
+
+#: git-stash.sh:123 git-stash.sh:136
+msgid "Cannot save the current worktree state"
+msgstr "无法保存当前工作区状态"
+
+#: git-stash.sh:140
+msgid "No changes selected"
+msgstr "没有修改被选择"
+
+#: git-stash.sh:143
+msgid "Cannot remove temporary index (can't happen)"
+msgstr "无法删除临时暂存区(不应发生)"
+
+#: git-stash.sh:156
+msgid "Cannot record working tree state"
+msgstr "不能记录工作区状态"
+
+#: git-stash.sh:223
+msgid "No local changes to save"
+msgstr "没有要保存的本地修改"
+
+#: git-stash.sh:227
+msgid "Cannot initialize stash"
+msgstr "无法初始化stash"
+
+#: git-stash.sh:235
+msgid "Cannot save the current status"
+msgstr "无法保存当前状态"
+
+#: git-stash.sh:253
+msgid "Cannot remove worktree changes"
+msgstr "无法删除工作区变更"
+
+#: git-stash.sh:352
+msgid "No stash found."
+msgstr "未发现stash。"
+
+#: git-stash.sh:359
+#, sh-format
+msgid "Too many revisions specified: $REV"
+msgstr "提供太多的版本:$REV"
+
+#: git-stash.sh:365
+#, sh-format
+msgid "$reference is not valid reference"
+msgstr "$reference 不是有效的引用"
+
+#: git-stash.sh:393
+#, sh-format
+msgid "'$args' is not a stash-like commit"
+msgstr "'$args' 不是stash样提交"
+
+#: git-stash.sh:404
+#, sh-format
+msgid "'$args' is not a stash reference"
+msgstr "'$args' 不是一个stash引用"
+
+#: git-stash.sh:412
+msgid "unable to refresh index"
+msgstr "无法刷新暂存区"
+
+#: git-stash.sh:416
+msgid "Cannot apply a stash in the middle of a merge"
+msgstr "无法在合并过程中恢复进度"
+
+#: git-stash.sh:424
+msgid "Conflicts in index. Try without --index."
+msgstr "暂存区冲突。尝试不用 --index。"
+
+#: git-stash.sh:426
+msgid "Could not save index tree"
+msgstr "无法保存暂存区"
+
+#: git-stash.sh:460
+msgid "Cannot unstage modified files"
+msgstr "无法还原修改的文件"
+
+#: git-stash.sh:491
+#, sh-format
+msgid "Dropped ${REV} ($s)"
+msgstr "丢弃了 ${REV} ($s)"
+
+#: git-stash.sh:492
+#, sh-format
+msgid "${REV}: Could not drop stash entry"
+msgstr "${REV}: 无法丢弃进度条目"
+
+#: git-stash.sh:499
+msgid "No branch name specified"
+msgstr "未指定分支名"
+
+#: git-stash.sh:570
+msgid "(To restore them type \"git stash apply\")"
+msgstr "(为恢复数据输入 \"git stash apply\")"
+
+#: git-submodule.sh:56
+#, sh-format
+msgid "cannot strip one component off url '$remoteurl'"
+msgstr "无法从 url '$remoteurl' 剥离一个组件"
+
+#: git-submodule.sh:108
+#, sh-format
+msgid "No submodule mapping found in .gitmodules for path '$path'"
+msgstr "未在 .gitmodules 中发现路径 '$path' 的子模组映射"
+
+#: git-submodule.sh:172
+#, sh-format
+msgid "Clone of '$url' into submodule path '$path' failed"
+msgstr "克隆 '$url' 到子模组路径 '$path' 失败"
+
+#: git-submodule.sh:246
+#, sh-format
+msgid "repo URL: '$repo' must be absolute or begin with ./|../"
+msgstr "版本库URL:'$repo' 必须是绝对路径或以 ./|../ 起始"
+
+#: git-submodule.sh:263
+#, sh-format
+msgid "'$path' already exists in the index"
+msgstr "'$path' 已经存在于暂存区中"
+
+#: git-submodule.sh:280
+#, sh-format
+msgid "'$path' already exists and is not a valid git repo"
+msgstr "'$path' 已存在且不是一个有效的 git 版本库"
+
+#: git-submodule.sh:294
+#, sh-format
+msgid "Unable to checkout submodule '$path'"
+msgstr "不能检出子模组 '$path'"
+
+#: git-submodule.sh:299
+#, sh-format
+msgid "Failed to add submodule '$path'"
+msgstr "无法添加子模组 '$path'"
+
+#: git-submodule.sh:304
+#, sh-format
+msgid "Failed to register submodule '$path'"
+msgstr "无法注册子模组 '$path'"
+
+#: git-submodule.sh:346
+#, sh-format
+msgid "Entering '$prefix$path'"
+msgstr "正在进入 '$prefix$path'"
+
+#: git-submodule.sh:358
+#, sh-format
+msgid "Stopping at '$path'; script returned non-zero status."
+msgstr "停止于 '$path',脚本返回非零值。"
+
+#: git-submodule.sh:400
+#, sh-format
+msgid "No url found for submodule path '$path' in .gitmodules"
+msgstr "在 .gitmodules 中未找到子模组路径 '$path' 的url"
+
+#: git-submodule.sh:409
+#, sh-format
+msgid "Failed to register url for submodule path '$path'"
+msgstr "无法为子模组路径 '$path' 注册 url"
+
+#: git-submodule.sh:417
+#, sh-format
+msgid "Failed to register update mode for submodule path '$path'"
+msgstr "无法为子模组路径 '$path' 注册更新模式"
+
+#: git-submodule.sh:419
+#, sh-format
+msgid "Submodule '$name' ($url) registered for path '$path'"
+msgstr "子模组 '$name' ($url) 已为路径 '$path' 注册"
+
+#: git-submodule.sh:518
+#, sh-format
+msgid ""
+"Submodule path '$path' not initialized\n"
+"Maybe you want to use 'update --init'?"
+msgstr ""
+"子模组路径 '$path' 没有初始化\n"
+"也许你想用 'update --init'?"
+
+#: git-submodule.sh:531
+#, sh-format
+msgid "Unable to find current revision in submodule path '$path'"
+msgstr "无法在子模组路径 '$path' 中找到当前版本"
+
+#: git-submodule.sh:550
+#, sh-format
+msgid "Unable to fetch in submodule path '$path'"
+msgstr "无法在子模组路径 '$path' 中获取"
+
+#: git-submodule.sh:564
+#, sh-format
+msgid "Unable to rebase '$sha1' in submodule path '$path'"
+msgstr "无法在子模组路径 '$path' 中变基 '$sha1'"
+
+#: git-submodule.sh:565
+#, sh-format
+msgid "Submodule path '$path': rebased into '$sha1'"
+msgstr "子模组路径 '$path':变基至 '$sha1'"
+
+#: git-submodule.sh:570
+#, sh-format
+msgid "Unable to merge '$sha1' in submodule path '$path'"
+msgstr "无法合并 '$sha1' 到子模组路径 '$path' 中"
+
+#: git-submodule.sh:571
+#, sh-format
+msgid "Submodule path '$path': merged in '$sha1'"
+msgstr "子模组路径 '$path':已合并入 '$sha1'"
+
+#: git-submodule.sh:576
+#, sh-format
+msgid "Unable to checkout '$sha1' in submodule path '$path'"
+msgstr "无法在子模组路径 '$path' 中检出 '$sha1'"
+
+#: git-submodule.sh:577
+#, sh-format
+msgid "Submodule path '$path': checked out '$sha1'"
+msgstr "子模组路径 '$path':检出 '$sha1'"
+
+#: git-submodule.sh:599 git-submodule.sh:922
+#, sh-format
+msgid "Failed to recurse into submodule path '$path'"
+msgstr "无法递归进子模组路径 '$path'"
+
+#: git-submodule.sh:707
+msgid "--"
+msgstr "--"
+
+#  注意保持前导空格
+#: git-submodule.sh:765
+#, sh-format
+msgid "  Warn: $name doesn't contain commit $sha1_src"
+msgstr "  警告:$name 未包含提交 $sha1_src"
+
+#  注意保持前导空格
+#: git-submodule.sh:768
+#, sh-format
+msgid "  Warn: $name doesn't contain commit $sha1_dst"
+msgstr "  警告:$name 未包含提交 $sha1_dst"
+
+#  注意保持前导空格
+#: git-submodule.sh:771
+#, sh-format
+msgid "  Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgstr "  警告:$name 未包含提交 $sha1_src 和 $sha1_dst"
+
+#: git-submodule.sh:796
+msgid "blob"
+msgstr "blob"
+
+#: git-submodule.sh:797
+msgid "submodule"
+msgstr "子模组"
+
+#: git-submodule.sh:968
+#, sh-format
+msgid "Synchronizing submodule url for '$name'"
+msgstr "为 '$name' 同步子模组url"
-- 
1.7.9.3.g1fbd7

^ permalink raw reply

* Re: [PATCH v3 1/2] Factor find_pack_entry()'s core out
From: Nicolas Pitre @ 2012-02-01 15:59 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano
In-Reply-To: <1328104135-475-1-git-send-email-pclouds@gmail.com>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2950 bytes --]

On Wed, 1 Feb 2012, Nguyễn Thái Ngọc Duy wrote:

> 
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  sha1_file.c |   59 +++++++++++++++++++++++++++++++++--------------------------
>  1 files changed, 33 insertions(+), 26 deletions(-)
> 
> diff --git a/sha1_file.c b/sha1_file.c
> index 88f2151..ff5bf42 100644
> --- a/sha1_file.c
> +++ b/sha1_file.c
> @@ -2010,11 +2010,42 @@ int is_pack_valid(struct packed_git *p)
>  	return !open_packed_git(p);
>  }
>  
> +static int find_pack_entry_1(const unsigned char *sha1,
> +			     struct packed_git *p, struct pack_entry *e)

This looks all goot but the name.  Pretty please, try to find something 
that is more descriptive than "1".  Suggestions: 
"find_pack_entry_lookup", "find_pack_entry_inner", etc.

With that fixed, you can add:

Acked-by: Nicolas Pitre <nico@fluxnic.net>

> +{
> +	off_t offset;
> +	if (p->num_bad_objects) {
> +		unsigned i;
> +		for (i = 0; i < p->num_bad_objects; i++)
> +			if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
> +				return 0;
> +	}
> +
> +	offset = find_pack_entry_one(sha1, p);
> +	if (!offset)
> +		return 0;
> +
> +	/*
> +	 * We are about to tell the caller where they can locate the
> +	 * requested object.  We better make sure the packfile is
> +	 * still here and can be accessed before supplying that
> +	 * answer, as it may have been deleted since the index was
> +	 * loaded!
> +	 */
> +	if (!is_pack_valid(p)) {
> +		warning("packfile %s cannot be accessed", p->pack_name);
> +		return 0;
> +	}
> +	e->offset = offset;
> +	e->p = p;
> +	hashcpy(e->sha1, sha1);
> +	return 1;
> +}
> +
>  static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
>  {
>  	static struct packed_git *last_found = (void *)1;
>  	struct packed_git *p;
> -	off_t offset;
>  
>  	prepare_packed_git();
>  	if (!packed_git)
> @@ -2022,35 +2053,11 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
>  	p = (last_found == (void *)1) ? packed_git : last_found;
>  
>  	do {
> -		if (p->num_bad_objects) {
> -			unsigned i;
> -			for (i = 0; i < p->num_bad_objects; i++)
> -				if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
> -					goto next;
> -		}
> -
> -		offset = find_pack_entry_one(sha1, p);
> -		if (offset) {
> -			/*
> -			 * We are about to tell the caller where they can
> -			 * locate the requested object.  We better make
> -			 * sure the packfile is still here and can be
> -			 * accessed before supplying that answer, as
> -			 * it may have been deleted since the index
> -			 * was loaded!
> -			 */
> -			if (!is_pack_valid(p)) {
> -				warning("packfile %s cannot be accessed", p->pack_name);
> -				goto next;
> -			}
> -			e->offset = offset;
> -			e->p = p;
> -			hashcpy(e->sha1, sha1);
> +		if (find_pack_entry_1(sha1, p, e)) {
>  			last_found = p;
>  			return 1;
>  		}
>  
> -		next:
>  		if (p == last_found)
>  			p = packed_git;
>  		else
> -- 
> 1.7.8.36.g69ee2
> 

^ permalink raw reply

* Re: [PATCH v3 2/2] find_pack_entry(): do not keep packed_git pointer locally
From: Nicolas Pitre @ 2012-02-01 16:02 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano
In-Reply-To: <1328104135-475-2-git-send-email-pclouds@gmail.com>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2556 bytes --]

On Wed, 1 Feb 2012, Nguyễn Thái Ngọc Duy wrote:

> Commit f7c22cc (always start looking up objects in the last used pack
> first - 2007-05-30) introduce a static packed_git* pointer as an
> optimization.  The kept pointer however may become invalid if
> free_pack_by_name() happens to free that particular pack.
> 
> Current code base does not access packs after calling
> free_pack_by_name() so it should not be a problem. Anyway, move the
> pointer out so that free_pack_by_name() can reset it to avoid running
> into troubles in future.
> 
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>

Acked-by: Nicolas Pitre <nico@fluxnic.net>


>  Since Junio's already done the hard work. It'd be silly of me not to
>  take advantage and credit for free :)

Maybe a little "Thanks to Junio for code layout suggestions" in the 
commit message would give him some credit back.

>  The new loop looks much better.

Indeed.

>  sha1_file.c |   27 +++++++++++++--------------
>  1 files changed, 13 insertions(+), 14 deletions(-)
> 
> diff --git a/sha1_file.c b/sha1_file.c
> index ff5bf42..ebe77b3 100644
> --- a/sha1_file.c
> +++ b/sha1_file.c
> @@ -54,6 +54,8 @@ static struct cached_object empty_tree = {
>  	0
>  };
>  
> +static struct packed_git *last_found_pack;
> +
>  static struct cached_object *find_cached_object(const unsigned char *sha1)
>  {
>  	int i;
> @@ -720,6 +722,8 @@ void free_pack_by_name(const char *pack_name)
>  			close_pack_index(p);
>  			free(p->bad_object_sha1);
>  			*pp = p->next;
> +			if (last_found_pack == p)
> +				last_found_pack = NULL;
>  			free(p);
>  			return;
>  		}
> @@ -2044,27 +2048,22 @@ static int find_pack_entry_1(const unsigned char *sha1,
>  
>  static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
>  {
> -	static struct packed_git *last_found = (void *)1;
>  	struct packed_git *p;
>  
>  	prepare_packed_git();
>  	if (!packed_git)
>  		return 0;
> -	p = (last_found == (void *)1) ? packed_git : last_found;
>  
> -	do {
> -		if (find_pack_entry_1(sha1, p, e)) {
> -			last_found = p;
> -			return 1;
> -		}
> +	if (last_found_pack && find_pack_entry_1(sha1, last_found_pack, e))
> +		return 1;
>  
> -		if (p == last_found)
> -			p = packed_git;
> -		else
> -			p = p->next;
> -		if (p == last_found)
> -			p = p->next;
> -	} while (p);
> +	for (p = packed_git; p; p = p->next) {
> +		if (p == last_found_pack || !find_pack_entry_1(sha1, p, e))
> +			continue;
> +
> +		last_found_pack = p;
> +		return 1;
> +	}
>  	return 0;
>  }
>  
> -- 
> 1.7.8.36.g69ee2
> 

^ permalink raw reply

* Re: [PATCH] Don't search files with an unset "grep" attribute
From: Junio C Hamano @ 2012-02-01 16:28 UTC (permalink / raw)
  To: Jeff King; +Cc: Conrad Irwin, git, Nguyen Thai Ngoc Duy, Dov Grobgeld
In-Reply-To: <20120201091009.GA20984@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> Part of the problem, I suspect, is that the attribute lookup code is
> optimized for locality. We only unwind as much of the stack as we need,
> so looking at "foo/bar/baz.c" after "foo/bar/bleep.c" is much cheaper
> than looking at "some/other/directory.c". But with threaded grep, that
> locality is likely lost, as we are mixing up attribute requests from
> different threads.
>
> Given that binary lookup means we need every file's gitattribute, it
> might be better to look them up serially at the beginning of the
> program, and then pass the resulting userdiff driver to grep_buffer
> along with each path.

Yeah, that was my impression when the performance of threaded grep was
discussed, which was before this "let's honor binary attribute".

^ permalink raw reply

* Re: [PATCH v5 2/5] gitweb: add project_filter to limit project list to a subdirectory
From: Bernhard R. Link @ 2012-02-01 16:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jakub Narebski, git
In-Reply-To: <7v39axaq0v.fsf@alter.siamese.dyndns.org>

* Junio C Hamano <gitster@pobox.com> [120130 21:34]:
> Thanks; I'll queue them in 'pu' for now (if Jakub wants to Ack the pieces,
> I'll amend them).
>
> Regarding the first patch in the series, while it may be a valid perl to
> introduce a new variable, assign to it and then munge its contents with
> s///, all inside a parameter list of a function call, it is doing a bit
> too much and makes it hard to see if the variable may or may not later be
> used in the same scope (in this case, it is not).
>
> I am tempted to squash the following in.

Look liks a change like that is actually needed. I made the mistake of
assuming
  (my $filter = $project) =~ s/\.git$//;
was the same like
  $project =~ s/\.git$//r;
but the latter returns the changed string, the former returns the number
of arguments. (So it looks for forks in a directory named '1').

(Should have tested it again after this last change)...

Can you squash it in (with the correction of Jakub Narebski), or do you
prefer a new patch?

        Bernhard R. Link

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox