Re: [RFC/PATCH 2/3] wildmatch: add interface for precompiling wildmatch() patterns

2017-06-23 Thread Junio C Hamano
Ævar Arnfjörð Bjarmason   writes:

> +struct wildmatch_compiled *wildmatch_compile(const char *pattern, unsigned 
> int flags)
> +{
> + struct wildmatch_compiled *code = xmalloc(sizeof(struct 
> wildmatch_compiled));
> + code->pattern = xstrdup(pattern);
> + code->flags = flags;
> +
> + return code;
> +}
> +
> +int wildmatch_match(struct wildmatch_compiled *code, const char *text)
> +{
> + return wildmatch(code->pattern, text, code->flags);
> +}

Is the far-in-the-future vision to make this the other way around?
That is, this being scaffolding, wildmatch_match() which is supposed
to be precompiled match actually uses wildmatch() as its underlying
engine, but when a viable compilation machinery is plugged in, the
wildmatch_match() that takes a precompiled pattern will call into
the machinery to execute the compiled pattern, and wildmatch() will
be reimplemented as "compile, call wildmatch_match() once and
discard" sequence?

Otherwise I'd be worried about wildmatch() vs wildmatch_match()
introducing subtle behaviour differences that leads to hard to debug
problems.



Re: [PATCH v2 00/29] Create a reference backend for packed refs

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 02:47:01PM -0700, Junio C Hamano wrote:

> > Speculating on my own question. I guess it would prepare us for a day
> > when a possible ref store is to use a packed-refs _without_ loose refs.
> > IOW, the property is defined on packed-refs today, but a possible future
> > direction would be to use it by itself. But maybe I'm just making things
> > up.
> 
> OK.  In other words, it's not a packed-refs's characteristics that
> cruft are allowed.  It's that a ref storage that is implemented as
> an overlay of one storage (which happens to be the loose one) on top
> of another (which happens to be the packed refs file) allows the
> latter one to have cruft if (and only if) that broken one is covered
> by the former one.

Thanks, that's a much better way of saying what I was trying to get at.
I don't know if that's Michael's argument or not, but it's certainly one
I find reasonable. :)

-Peff


Re: --color-moved feedback, was Re: [PATCH v2 19/29] packed-backend: new module for handling packed references

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 01:23:52PM -0700, Stefan Beller wrote:

> > In the end, I just did --color-moved=plain,  ...
> > "yep, this is all a giant moved chunk, so I don't have to look carefully
> > at it".
> 
> This is dangerous, as "plain" does not care about permutations.
> See the 7f5af90798 (diff.c: color moved lines differently, 2017-06-19)
> for details. You would want at least "zebra", which would show you
> permutations.

Ah, I see. I think what I'd really want is some way of correlating two
particular hunks. That's hard to do with color, though. I guess that's
the "you would need a ton of colors" discussion I saw going on before?

It would depend on how many hunks there are, and how close together they
are. For instance, your 6cd5757c8 seems like a good candidate, but I
have to admit with --color-moved=zebra I have no idea what's going on.
Some things are definitely colored, but I'm not sure what corresponds to
what.

> > That feels more dangerous to me, just because the heuristics seem to
> > find a lot of "moves" of repeated code. Imagine a simple patch like
> > "switch return 0 to return -1". If the code you're touching went away,
> > there's a very good chance that another "return 0" popped up somewhere
> > else in the code base. A conflict is what you want there; silently
> > changing some other site would be not only wrong, but quite subtle and
> > hard to find.
> 
> I agree, that is the danger, but the scale of danger is the size of the moved
> chunk. A file is usually a very large chunk, such that it is obviously a good
> idea to fix that. Maybe we'd introduce a threshold, that the fix must not be 
> in
> range of the block boundaries of say 3 lines.
> (Then the moved block must be at least 7 lines of code such that a one liner
> fix in the middle would kick in)

Yes, I'd agree it's really a continuum from "one line" to "whole file".
I think right now the --color-moved stuff is too close to the former to
be safe, but pushing it farther towards the middle would remedy that.

-Peff


Re: What's cooking in git.git (Jun 2017, #06; Thu, 22)

2017-06-23 Thread Junio C Hamano
Junio C Hamano  writes:

> But for the purpose of this "moved line coloring",
> excluding multiple copy destinations of the same thing may be a
> simpler and more robust solution.  It will not catch "somebody
> stupidly removed one function and made two private copies", though.

Let me take this one back.  Treating multiple copy destinations and
multiple copy sources differently is a bad idea.  It is easy for a
user to give "-R" option to "diff" to turn such a stupid patch into
"somebody brilliantly consolidated two copies of the same thing into
a single function", and we want to keep "diff" and "diff -R" output
symmetric.



Re: [PATCH 2/3] builtin/fetch: parse recurse-submodules-default at default options parsing

2017-06-23 Thread Junio C Hamano
Stefan Beller  writes:

>>>   if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
>>> - if (recurse_submodules_default) {
>>> - int arg = 
>>> parse_fetch_recurse_submodules_arg("--recurse-submodules-default", 
>>> recurse_submodules_default);
>>> - set_config_fetch_recurse_submodules(arg);
>>> - }
>>> + if (recurse_submodules_default != RECURSE_SUBMODULES_DEFAULT)
>>> + 
>>> set_config_fetch_recurse_submodules(recurse_submodules_default);
>>
>> This is not a new thing, and it may not even be a problem, but I
>> have to wonder why this needs to be done conditionally.  "The
>> ...
>
> As far as I suspect, the original author considered
> evaluating the additional config too expensive.
>
> gitmodules_config(); // <- this specifically?
> git_config(submodule_config, NULL);
>
> And that is why we only react if any switch is
> given to recurse. 

I am not talking about the outer "if" condition.  

The inner 

"if (recurse_submodules_default != RECURSE_SUBMODULES_DEFAULT)"

block, is what I am questioning, i.e. I am wondering why
set_config_fetch_recurse_submodules() need to be conditionally
called.

The two statement you quoted above will be executed either way,
regardless of the value of recurse_submodule_default.

Unless --recurse-submodules=off is given, in which case the outer
"if" condition rejects.  And I think you are explaining that part,
but that was not what I am questioning.


Re: What's cooking in git.git (Jun 2017, #06; Thu, 22)

2017-06-23 Thread Junio C Hamano
Stefan Beller  writes:

> * add some heuristic to omit small blobs, (empty lines, closing braces)
>   Maybe this is can be solved by not considering anything
>   that occurs multiple times?

I vaguely recall that we had to do something similar in "blame -C"
where it tries to avoid passing blame for insignificant changes down
as copied.  But for the purpose of this "moved line coloring",
excluding multiple copy destinations of the same thing may be a
simpler and more robust solution.  It will not catch "somebody
stupidly removed one function and made two private copies", though.



Re: What's cooking in git.git (Jun 2017, #06; Thu, 22)

2017-06-23 Thread Junio C Hamano
Ævar Arnfjörð Bjarmason  writes:

> This is bad:
>
> $ ./git --exec-path=$PWD -c diff.colorMoved=crap show
> fatal: unable to parse 'diff.colormoved' from command-line config
>
> Fixed with:
>
> diff --git a/diff.c b/diff.c
> index 7cae4f1ddb..036dbc1c3c 100644
> --- a/diff.c
> +++ b/diff.c
> @@ -278,7 +278,7 @@ int git_diff_ui_config(const char *var, const char 
> *value, void *cb)
> if (!strcmp(var, "diff.colormoved")) {
> int cm = parse_color_moved(value);
> if (cm < 0)
> -   return -1;
> +   die("bad --color-moved argument: %s", value);
> diff_color_moved_default = cm;
> return 0;
> }

You would want to model this after an existing practice nearby.

$ git -c color.diff.new=frotz diff
error: error: invalid color value: frotz
fatal: unable to parse 'color.diff.new' from command-line config

It could be argued that it would even be better to show "here is the
list of valid values the configuration takes", but generally we do
not do that in other configuration variables.


Re: What's cooking in git.git (Jun 2017, #06; Thu, 22)

2017-06-23 Thread Junio C Hamano
Junio C Hamano  writes:

>>> * ab/sha1dc (2017-06-07) 2 commits
>>> ...
>>>  Will keep in 'pu'.
>>>  Impact to the various build and release infrastructure of using
>>>  submodule is not yet fully known, but this lets us dip our toes.
>> ...
>> But it's been 1 month kicking around in pu now. What are we gaining from
>> keeping it there even longer at this point?
>
> I am sort of waiting for a success from Windows box at Travis.  It
> hasn't passed for other reasons for a while, though.

https://travis-ci.org/git/git/jobs/246371006#L480 shows that on
Linux, we are taking the code from the submodule and the compilation
is happy.

https://travis-ci.org/git/git/jobs/246371008#L25 shows that we do
init and update the submodule but it does not appear that neither
the bundled sha1dc/ nor the submodule gets used on MacOS.  Probably
we are using the hash from the platform?

https://travis-ci.org/git/git/jobs/246371011#L724 shows that the
bundled sha1dc/ is used on Windows, not from the submodule, for
whatever reason.  I trust what Dscho does for Windows platform well
enough that I do not feel unconfortable for not knowing why the
build there triggered by Travis does not use the submodule one.
Whatever configuration he chooses would be the best for the
platform.

So the only nit I may have is that we may possibly want to turn this
on in .travis.yml on MacOS before we move it forward (otherwise we'd
be shipping bundled one and submodule one without doing any build on
that platform)?  Other than that, the topic seems ready to be merged
down.

Thanks.



Re: What's cooking in git.git (Jun 2017, #06; Thu, 22)

2017-06-23 Thread Stefan Beller
> This is good:
>
> $ ./git --exec-path=$PWD show --color-moved=crap
> fatal: bad --color-moved argument: crap
>
> This is bad:
>
> $ ./git --exec-path=$PWD -c diff.colorMoved=crap show
> fatal: unable to parse 'diff.colormoved' from command-line config
>
> Fixed with:
>
> diff --git a/diff.c b/diff.c
> index 7cae4f1ddb..036dbc1c3c 100644
> --- a/diff.c
> +++ b/diff.c
> @@ -278,7 +278,7 @@ int git_diff_ui_config(const char *var, const char 
> *value, void *cb)
> if (!strcmp(var, "diff.colormoved")) {
> int cm = parse_color_moved(value);
> if (cm < 0)
> -   return -1;
> +   die("bad --color-moved argument: %s", value);
> diff_color_moved_default = cm;
> return 0;
> }
>
> But I'm not familiar enough with the code to say if just dying here, as
> opposed to returning -1 is OK or not.

I think this one is 'not good', as it (a) does not help the user a lot
and (b) is not consistent with the rest around in that function, for example

  $ git -c diff.interhunkcontext=-2 diff
  fatal: unable to parse 'diff.interhunkcontext' from command-line config

So instead of return -1, we could issue an additional warning, but this could
be a generic warning?


Re: What's cooking in git.git (Jun 2017, #06; Thu, 22)

2017-06-23 Thread Stefan Beller
On Fri, Jun 23, 2017 at 2:59 PM, Ævar Arnfjörð Bjarmason
 wrote:
>
> On Thu, Jun 22 2017, Junio C. Hamano jotted:
>
>> * sb/diff-color-move (2017-06-21) 25 commits
>>  - diff: document the new --color-moved setting
>>  - diff.c: add dimming to moved line detection
>>  - diff.c: color moved lines differently, plain mode
>>  - diff.c: color moved lines differently
>>  - diff.c: buffer all output if asked to
>>  - diff.c: emit_diff_symbol learns about DIFF_SYMBOL_SUMMARY
>>  - diff.c: emit_diff_symbol learns about DIFF_SYMBOL_STAT_SEP
>>  - diff.c: convert word diffing to use emit_diff_symbol
>>  - diff.c: convert show_stats to use emit_diff_symbol
>>  - diff.c: convert emit_binary_diff_body to use emit_diff_symbol
>>  - submodule.c: migrate diff output to use emit_diff_symbol
>>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_REWRITE_DIFF
>>  - diff.c: emit_diff_symbol learns about DIFF_SYMBOL_BINARY_FILES
>>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_HEADER
>>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_FILEPAIR
>>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_CONTEXT_INCOMPLETE
>>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_WORDS{_PORCELAIN}
>>  - diff.c: migrate emit_line_checked to use emit_diff_symbol
>>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_NO_LF_EOF
>>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_CONTEXT_FRAGINFO
>>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_CONTEXT_MARKER
>>  - diff.c: introduce emit_diff_symbol
>>  - diff.c: factor out diff_flush_patch_all_file_pairs
>>  - diff.c: move line ending check into emit_hunk_header
>>  - diff.c: readability fix
>>
>>  "git diff" has been taught to optionally paint new lines that are
>>  the same as deleted lines elsewhere differently from genuinely new
>>  lines.
>>
>>  Is any more update coming?
>
> I guess here's as good a place for feedback is any, this feature's
> great, but I discovered some minor warts in it:

Thanks for reporting these. :)

So:
* have the boolean option as below
* fix error modes in config
* rewrite documentation for lazy skimming readers :)

I also consider
* changing the default to zebra (instead of dimmed_zebra)

Junio wrote (when reviewing Michaels series)
> This patch shows OK, but when applied to other changes in the
> series, e.g. "packed_ref_store: make class into a subclass of
> `ref_store`", it was somewhat irritating that all new blank lines
> are shown as a copy-move of a single deleted blank line (also a
> single "return refs" in an entirely new function being a copy/move
> looked confusing).

* add some heuristic to omit small blobs, (empty lines, closing braces)
  Maybe this is can be solved by not considering anything
  that occurs multiple times?


Re: [PATCH] xdiff: trim common tail with -U0 after diff

2017-06-23 Thread Daniel Hahler
On 23.06.2017 22:39, René Scharfe wrote:

> The changed test script passes just fine for me even without your change
> to xdiff-interface.c, which is odd.

Sorry, I've apparently messed this up - it seems to be the case for me, too.

I would assume that using the functions.c context/diff in this test file might 
prove it, but when I wrote this test I was already unsure to base it on an 
experimental feature, that might just get removed again (with its tests).

> Do you have another way to demonstrate the unexpected behavior?

It was clearly reproducible with a local test case, based on "copying an 
existing test case, and modifying the header for it only".

Given the other replies, it seems like it is more a question now if the 
trimming should get moved down, or removed completely it seems.
So I will not update the patch/test for now.


-- 
http://daniel.hahler.de/



signature.asc
Description: OpenPGP digital signature


Re: [PATCH] submodule--helper: teach push-check to handle HEAD

2017-06-23 Thread Junio C Hamano
Brandon Williams  writes:

> In 06bf4ad1d (push: propagate remote and refspec with
> --recurse-submodules) push was taught how to propagate a refspec down to
> submodules when the '--recurse-submodules' flag is given.  The only refspecs
> that are allowed to be propagated are ones which name a ref which exists
> in both the superproject and the submodule, with the caveat that 'HEAD'
> was disallowed.
>
> This patch teaches push-check (the submodule helper which determines if
> a refspec can be propagated to a submodule) to permit propagating 'HEAD'
> if and only if the superproject and the submodule both have the same
> named branch checked out and the submodule is not in a detached head
> state.
>
> Signed-off-by: Brandon Williams 
> ---
>  builtin/submodule--helper.c| 57 
> +++---
>  submodule.c| 18 ++---
>  t/t5531-deep-submodule-push.sh | 25 +-
>  3 files changed, 82 insertions(+), 18 deletions(-)
>
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 1b4d2b346..fd5020036 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -1107,24 +1107,41 @@ static int resolve_remote_submodule_branch(int argc, 
> const char **argv,
>  static int push_check(int argc, const char **argv, const char *prefix)
>  {
>   struct remote *remote;
> + const char *superproject_head;
> + char *head;
> + int detached_head = 0;
> + struct object_id head_oid;
>  
> - if (argc < 2)
> - die("submodule--helper push-check requires at least 1 
> argument");
> + if (argc < 3)
> + die("submodule--helper push-check requires at least 2 
> argument");

"arguments"?

> +
> + /*
> +  * superproject's resolved head ref.
> +  * if HEAD then the superproject is in a detached head state, otherwise
> +  * it will be the resolved head ref.
> +  */
> + superproject_head = argv[1];

The above makes it sound like the caller gives either "HEAD" (when
detached) or "refs/heads/branch" (when on 'branch') in argv[1] and
you are stashing it away, but ...

> + /* Get the submodule's head ref and determine if it is detached */
> + head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
> + if (!head)
> + die(_("Failed to resolve HEAD as a valid ref."));
> + if (!strcmp(head, "HEAD"))
> + detached_head = 1;

... the work to see which branch we are on and if we are detached is
done by this code without consulting argv[1].  I cannot tell what is
going on.  Is argv[1] assigned to superproject_head a red herring?

>   /*
>* The remote must be configured.
>* This is to avoid pushing to the exact same URL as the parent.
>*/
> - remote = pushremote_get(argv[1]);
> + remote = pushremote_get(argv[2]);
>   if (!remote || remote->origin == REMOTE_UNCONFIGURED)
> - die("remote '%s' not configured", argv[1]);
> + die("remote '%s' not configured", argv[2]);
>  
>   /* Check the refspec */
> - if (argc > 2) {
> - int i, refspec_nr = argc - 2;
> + if (argc > 3) {
> + int i, refspec_nr = argc - 3;
>   struct ref *local_refs = get_local_heads();
>   struct refspec *refspec = parse_push_refspec(refspec_nr,
> -  argv + 2);
> +  argv + 3);

If you have no need for argv[1] (and you don't, as you have stashed
it away in superproject_head), it may be less damage to the code if
you shifted argv upfront after grabbing superproject_head.

>   for (i = 0; i < refspec_nr; i++) {
>   struct refspec *rs = refspec + i;
> @@ -1132,18 +1149,30 @@ static int push_check(int argc, const char **argv, 
> const char *prefix)
>   if (rs->pattern || rs->matching)
>   continue;
>  
> - /*
> -  * LHS must match a single ref
> -  * NEEDSWORK: add logic to special case 'HEAD' once
> -  * working with submodules in a detached head state
> -  * ceases to be the norm.
> -  */
> - if (count_refspec_match(rs->src, local_refs, NULL) != 1)
> + /* LHS must match a single ref */
> + switch(count_refspec_match(rs->src, local_refs, NULL)) {

"switch (count..."

> + case 1:
> + break;
> + case 0:
> + /*
> +  * If LHS matches 'HEAD' then we need to ensure
> +  * that it matches the same named branch
> +  * checked out in the superproject.
> +  */
> +   

Re: [PATCH 2/3] builtin/fetch: parse recurse-submodules-default at default options parsing

2017-06-23 Thread Stefan Beller
On Fri, Jun 23, 2017 at 3:36 PM, Junio C Hamano  wrote:
> Stefan Beller  writes:
>
>> @@ -1333,10 +1336,8 @@ int cmd_fetch(int argc, const char **argv, const char 
>> *prefix)
>>   deepen = 1;
>>
>>   if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
>> - if (recurse_submodules_default) {
>> - int arg = 
>> parse_fetch_recurse_submodules_arg("--recurse-submodules-default", 
>> recurse_submodules_default);
>> - set_config_fetch_recurse_submodules(arg);
>> - }
>> + if (recurse_submodules_default != RECURSE_SUBMODULES_DEFAULT)
>> + 
>> set_config_fetch_recurse_submodules(recurse_submodules_default);
>
> This is not a new thing, and it may not even be a problem, but I
> have to wonder why this needs to be done conditionally.  "The
> command line did not explicitly say --no-recurse-submodules, so we
> would set what came from --recurse-submodule-default if and only if
> that is given---otherwise we leave it as a compiled-in default" is
> what the code before or after this patch tells me.  But if we drop
> the "if (default is not DEFAULT)", the resulting code becomes "The
> command line did not explicitly say --no-recurse-submodules, so we
> would set whatever is the default (which may not have been given
> from the command line, but came built-in to the binary)".  Aren't
> they saying the same thing?

I assumed so as well, yes. But the test suite pointed out there
is another subtlety going on, which I have not dug into, yet.

>
> It's not like there is a configuration knob that further interferes
> the interaction between these two.  I am puzzled.

As far as I suspect, the original author considered
evaluating the additional config too expensive.

gitmodules_config(); // <- this specifically?
git_config(submodule_config, NULL);

And that is why we only react if any switch is
given to recurse. Before be254a0ea9 (Add the
'fetch.recurseSubmodules' config setting, 2010-11-11)
we would not load the config unless the user
asked for submodule action.

Then with the config switch we *had* to load the config
(both .gitmodules as well as .git/config), so at that commit
it would have made sense to inline this into the regular config
and command line argument parsing.


Re: [PATCH 2/3] builtin/fetch: parse recurse-submodules-default at default options parsing

2017-06-23 Thread Junio C Hamano
Stefan Beller  writes:

> @@ -1333,10 +1336,8 @@ int cmd_fetch(int argc, const char **argv, const char 
> *prefix)
>   deepen = 1;
>  
>   if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
> - if (recurse_submodules_default) {
> - int arg = 
> parse_fetch_recurse_submodules_arg("--recurse-submodules-default", 
> recurse_submodules_default);
> - set_config_fetch_recurse_submodules(arg);
> - }
> + if (recurse_submodules_default != RECURSE_SUBMODULES_DEFAULT)
> + 
> set_config_fetch_recurse_submodules(recurse_submodules_default);

This is not a new thing, and it may not even be a problem, but I
have to wonder why this needs to be done conditionally.  "The
command line did not explicitly say --no-recurse-submodules, so we
would set what came from --recurse-submodule-default if and only if
that is given---otherwise we leave it as a compiled-in default" is
what the code before or after this patch tells me.  But if we drop
the "if (default is not DEFAULT)", the resulting code becomes "The
command line did not explicitly say --no-recurse-submodules, so we
would set whatever is the default (which may not have been given
from the command line, but came built-in to the binary)".  Aren't
they saying the same thing?

It's not like there is a configuration knob that further interferes
the interaction between these two.  I am puzzled.


>   gitmodules_config();
>   git_config(submodule_config, NULL);
>   }


Re: [PATCH 1/3] builtin/fetch: factor submodule recurse parsing out to submodule config

2017-06-23 Thread Junio C Hamano
Stefan Beller  writes:

> Later we want to access this parsing in builtin/pull as well.
>
> Signed-off-by: Stefan Beller 
> ---
>  builtin/fetch.c| 18 ++
>  submodule-config.c | 22 ++
>  submodule-config.h |  3 +++
>  3 files changed, 27 insertions(+), 16 deletions(-)
>
> diff --git a/builtin/fetch.c b/builtin/fetch.c
> index 100248c5af..9d58dc0a8a 100644
> --- a/builtin/fetch.c
> +++ b/builtin/fetch.c
> @@ -53,20 +53,6 @@ static int shown_url = 0;
>  static int refmap_alloc, refmap_nr;
>  static const char **refmap_array;
>  
> -static int option_parse_recurse_submodules(const struct option *opt,
> -const char *arg, int unset)
> -{
> - if (unset) {
> - recurse_submodules = RECURSE_SUBMODULES_OFF;
> - } else {
> - if (arg)
> - recurse_submodules = 
> parse_fetch_recurse_submodules_arg(opt->long_name, arg);
> - else
> - recurse_submodules = RECURSE_SUBMODULES_ON;
> - }
> - return 0;
> -}
> -
>  static int git_fetch_config(const char *k, const char *v, void *cb)
>  {
>   if (!strcmp(k, "fetch.prune")) {
> @@ -115,9 +101,9 @@ static struct option builtin_fetch_options[] = {
>   N_("number of submodules fetched in parallel")),
>   OPT_BOOL('p', "prune", &prune,
>N_("prune remote-tracking branches no longer on remote")),
> - { OPTION_CALLBACK, 0, "recurse-submodules", NULL, N_("on-demand"),
> + { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, 
> N_("on-demand"),
>   N_("control recursive fetching of submodules"),
> - PARSE_OPT_OPTARG, option_parse_recurse_submodules },
> + PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules },
>   OPT_BOOL(0, "dry-run", &dry_run,
>N_("dry run")),
>   OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
> diff --git a/submodule-config.c b/submodule-config.c
> index 4f58491ddb..265d036095 100644
> --- a/submodule-config.c
> +++ b/submodule-config.c
> @@ -2,6 +2,7 @@
>  #include "submodule-config.h"
>  #include "submodule.h"
>  #include "strbuf.h"
> +#include "parse-options.h"
>  
>  /*
>   * submodule cache lookup structure
> @@ -234,6 +235,27 @@ int parse_fetch_recurse_submodules_arg(const char *opt, 
> const char *arg)
>   return parse_fetch_recurse(opt, arg, 1);
>  }
>  
> +int option_fetch_parse_recurse_submodules(const struct option *opt,
> +   const char *arg, int unset)
> +{
> + int *v;
> +
> + if (!opt->value)
> + return -1;

It would have been easier to view this change if the original
already had used opt->value to specify where to place the parsed
value, but that is water under the bridge ;-)

Looks like a faithful converison to me.

> + v = opt->value;
> +
> + if (unset) {
> + *v = RECURSE_SUBMODULES_OFF;
> + } else {
> + if (arg)
> + *v = parse_fetch_recurse_submodules_arg(opt->long_name, 
> arg);
> + else
> + *v = RECURSE_SUBMODULES_ON;
> + }
> + return 0;
> +}
> +
>  static int parse_update_recurse(const char *opt, const char *arg,
>   int die_on_error)
>  {
> diff --git a/submodule-config.h b/submodule-config.h
> index d434ecdb45..1076a68653 100644
> --- a/submodule-config.h
> +++ b/submodule-config.h
> @@ -23,6 +23,9 @@ struct submodule {
>  };
>  
>  extern int parse_fetch_recurse_submodules_arg(const char *opt, const char 
> *arg);
> +struct option;
> +extern int option_fetch_parse_recurse_submodules(const struct option *opt,
> +  const char *arg, int unset);
>  extern int parse_update_recurse_submodules_arg(const char *opt, const char 
> *arg);
>  extern int parse_push_recurse_submodules_arg(const char *opt, const char 
> *arg);
>  extern int parse_submodule_config_option(const char *var, const char *value);


Re: [PATCH v2 3/3] t1700: make sure split-index respects core.sharedrepository

2017-06-23 Thread Junio C Hamano
Christian Couder  writes:

> Add a few tests to check that both the split-index file and the
> shared-index file are created using the right permissions when
> core.sharedrepository is set.
>
> Signed-off-by: Christian Couder 
> ---
>  t/t1700-split-index.sh | 17 +
>  1 file changed, 17 insertions(+)
>
> diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
> index af3ec0da5a..2c5be732e4 100755
> --- a/t/t1700-split-index.sh
> +++ b/t/t1700-split-index.sh
> @@ -370,4 +370,21 @@ test_expect_success 'check splitIndex.sharedIndexExpire 
> set to "never" and "now"
>   test $(ls .git/sharedindex.* | wc -l) -le 2
>  '
>  
> +while read -r mode modebits filename; do

Style.

while read -r mode modebits filename
do

> + test_expect_success POSIXPERM "split index respects 
> core.sharedrepository $mode" '
> + git config core.sharedrepository "$mode" &&
> + : >"$filename" &&
> + git update-index --add "$filename" &&
> + echo "$modebits" >expect &&
> + test_modebits .git/index >actual &&
> + test_cmp expect actual &&
> + newest_shared_index=$(ls -t .git/sharedindex.* | head -1) &&
> + test_modebits "$newest_shared_index" >actual &&
> + test_cmp expect actual
> + '

Running this twice in a loop would create two .git/sharedindex.*
files in quick succession.  I do not think we want to assume that
the filesystem timestamp can keep up with us to allow "ls -t" to
work reliably in the second round (if there is a leftover shared
index from previous test, even the first round may not catch the
latest one).

How about doing each iteration this way instead?  Which might be a
better solution to work around that.

- with core.sharedrepository set to false, force the index to be
  unsplit; "index" will have the default unshared permission
  bits (but we do not care what it is and no need to check it).

- remove any leftover sharedindex.*, if any.

- with core.sharedrepository set to whatever mode being tested,
  do the adding to force split.

- test the permission of index file.

- test the permission of sharedindex.* file; there should be
  only one instance, so erroring out when we see two or more is
  also a good test.

The last two steps may look like:

test_modebits .git/index >actual && test_cmp expect actual &&
shared=$(ls .git/sharedindex.*) &&
case "$shared" in
*" "*)
# we have more than one???
false ;;
*)  
test_modebits "shared" >actual &&
test_cmp expect actual ;;
esac

> +done <<\EOF
> +0666 -rw-rw-rw- seventeen
> +0642 -rw-r---w- eightteen
> +EOF
> +
>  test_done


Re: [PATCH v2 1/3] read-cache: use shared perms when writing shared index

2017-06-23 Thread Junio C Hamano
Christian Couder  writes:

> Since f6ecc62dbf (write_shared_index(): use tempfile module, 2015-08-10)
> write_shared_index() has been using mks_tempfile() to create the
> temporary file that will become the shared index.
>
> But even before that, it looks like the functions used to create this
> file didn't call adjust_shared_perm(), which means that the shared
> index file has always been created with 600 permissions regardless
> of the shared permission settings.
>
> Because of that, on repositories created with `git init --shared=all`
> and using the split index feature, one gets an error like:
>
> fatal: .git/sharedindex.a52f910b489bc462f187ab572ba0086f7b5157de: index file 
> open failed: Permission denied
>
> when another user performs any operation that reads the shared index.
>
> We could use create_tempfile() that calls adjust_shared_perm(), but
> unfortunately create_tempfile() doesn't replace the XX at the end
> of the path it is passed. So let's just call adjust_shared_perm() by
> ourselves.

Because create_tempfile() is not even a viable alternative, the
above sounds just as silly as saying "We could use X, but
unfortunately that X doesn't create a temporary file and return its
file descriptor" with X replaced with any one of about a dozen
functions that happen to call adjust_shared_perm().

Call adjust_shared_perm() on the temporary file created by
mks_tempfile() ourselves to adjust the permission bits.

should be sufficient.

Thanks.

>
> Signed-off-by: Christian Couder 
> ---
>  read-cache.c | 8 
>  1 file changed, 8 insertions(+)
>
> diff --git a/read-cache.c b/read-cache.c
> index bc156a133e..66f85f8d58 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -2425,6 +2425,14 @@ static int write_shared_index(struct index_state 
> *istate,
>   delete_tempfile(&temporary_sharedindex);
>   return ret;
>   }
> + ret = adjust_shared_perm(temporary_sharedindex.filename.buf);
> + if (ret) {
> + int save_errno = errno;
> + error("cannot fix permission bits on %s", 
> temporary_sharedindex.filename.buf);
> + delete_tempfile(&temporary_sharedindex);
> + errno = save_errno;
> + return ret;
> + }
>   ret = rename_tempfile(&temporary_sharedindex,
> git_path("sharedindex.%s", 
> sha1_to_hex(si->base->sha1)));
>   if (!ret) {


Re: What's cooking in git.git (Jun 2017, #06; Thu, 22)

2017-06-23 Thread Ævar Arnfjörð Bjarmason

On Thu, Jun 22 2017, Junio C. Hamano jotted:

> * sb/diff-color-move (2017-06-21) 25 commits
>  - diff: document the new --color-moved setting
>  - diff.c: add dimming to moved line detection
>  - diff.c: color moved lines differently, plain mode
>  - diff.c: color moved lines differently
>  - diff.c: buffer all output if asked to
>  - diff.c: emit_diff_symbol learns about DIFF_SYMBOL_SUMMARY
>  - diff.c: emit_diff_symbol learns about DIFF_SYMBOL_STAT_SEP
>  - diff.c: convert word diffing to use emit_diff_symbol
>  - diff.c: convert show_stats to use emit_diff_symbol
>  - diff.c: convert emit_binary_diff_body to use emit_diff_symbol
>  - submodule.c: migrate diff output to use emit_diff_symbol
>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_REWRITE_DIFF
>  - diff.c: emit_diff_symbol learns about DIFF_SYMBOL_BINARY_FILES
>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_HEADER
>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_FILEPAIR
>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_CONTEXT_INCOMPLETE
>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_WORDS{_PORCELAIN}
>  - diff.c: migrate emit_line_checked to use emit_diff_symbol
>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_NO_LF_EOF
>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_CONTEXT_FRAGINFO
>  - diff.c: emit_diff_symbol learns DIFF_SYMBOL_CONTEXT_MARKER
>  - diff.c: introduce emit_diff_symbol
>  - diff.c: factor out diff_flush_patch_all_file_pairs
>  - diff.c: move line ending check into emit_hunk_header
>  - diff.c: readability fix
>
>  "git diff" has been taught to optionally paint new lines that are
>  the same as deleted lines elsewhere differently from genuinely new
>  lines.
>
>  Is any more update coming?

I guess here's as good a place for feedback is any, this feature's
great, but I discovered some minor warts in it:

This is good:

$ ./git --exec-path=$PWD show --color-moved=crap
fatal: bad --color-moved argument: crap

This is bad:

$ ./git --exec-path=$PWD -c diff.colorMoved=crap show
fatal: unable to parse 'diff.colormoved' from command-line config

Fixed with:

diff --git a/diff.c b/diff.c
index 7cae4f1ddb..036dbc1c3c 100644
--- a/diff.c
+++ b/diff.c
@@ -278,7 +278,7 @@ int git_diff_ui_config(const char *var, const char 
*value, void *cb)
if (!strcmp(var, "diff.colormoved")) {
int cm = parse_color_moved(value);
if (cm < 0)
-   return -1;
+   die("bad --color-moved argument: %s", value);
diff_color_moved_default = cm;
return 0;
}

But I'm not familiar enough with the code to say if just dying here, as
opposed to returning -1 is OK or not.

Also, I think something like this (very lighty tested) patch on top
makes sense:

diff --git a/diff.c b/diff.c
index 7cae4f1ddb..d195d304d3 100644
--- a/diff.c
+++ b/diff.c
@@ -257,6 +257,15 @@ int git_diff_heuristic_config(const char *var, const 
char *value, void *cb)

 static int parse_color_moved(const char *arg)
 {
+   int v = git_parse_maybe_bool(arg);
+
+   if (v != -1) {
+   if (v == 0)
+   return COLOR_MOVED_NO;
+   else if (v == 1)
+   return COLOR_MOVED_PLAIN;
+   }
+
if (!strcmp(arg, "no"))
return COLOR_MOVED_NO;
else if (!strcmp(arg, "plain"))

I don't want to set this to a specific value, just "true" and it should
pick whatever the default is (and that in the config yields a very bad
error message, hence the first patch).

If you don't want to have a default for whatever reason I think the docs
need to change:

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1ab7bdfb49..4b6f8c6d5c 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1085,8 +1085,9 @@ This does not affect linkgit:git-format-patch[1] or 
the
 command line with the `--color[=]` option.

 diff.colorMoved::
-   If set moved lines in a diff are colored differently,
-   for details see '--color-moved' in linkgit:git-diff[1].
+   If set to a valid `` moved lines in a diff are colored
+   differently, for details of valid modes see '--color-moved' in
+   linkgit:git-diff[1].

 color.diff.::
Use customized color for diff colorization.  `` specifies

Right now the lazy reader (i.e. me) just reads "if set..."
tries it out, and then gets a cryptic error. "If set" to me immediately
sounds like a bool variable (but then I read the diff docs and found
it's not). So with that bool parsing it could be changed to:

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1ab7bdfb49..e62d926740 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1085,8 +1085,10 @@ This does not affect linkgit:g

Re: [PATCH v2 1/3] read-cache: use shared perms when writing shared index

2017-06-23 Thread Junio C Hamano
Christian Couder  writes:

> Since f6ecc62dbf (write_shared_index(): use tempfile module, 2015-08-10)
> write_shared_index() has been using mks_tempfile() to create the
> temporary file that will become the shared index.
>
> But even before that, it looks like the functions used to create this
> file didn't call adjust_shared_perm(), which means that the shared
> index file has always been created with 600 permissions regardless
> of the shared permission settings.
>
> Because of that, on repositories created with `git init --shared=all`
> and using the split index feature, one gets an error like:
>
> fatal: .git/sharedindex.a52f910b489bc462f187ab572ba0086f7b5157de: index file 
> open failed: Permission denied
>
> when another user performs any operation that reads the shared index.
>
> We could use create_tempfile() that calls adjust_shared_perm(), but
> unfortunately create_tempfile() doesn't replace the XX at the end
> of the path it is passed. So let's just call adjust_shared_perm() by
> ourselves.
>
> Signed-off-by: Christian Couder 
> ---
>  read-cache.c | 8 
>  1 file changed, 8 insertions(+)
>
> diff --git a/read-cache.c b/read-cache.c
> index bc156a133e..66f85f8d58 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -2425,6 +2425,14 @@ static int write_shared_index(struct index_state 
> *istate,
>   delete_tempfile(&temporary_sharedindex);
>   return ret;
>   }
> + ret = adjust_shared_perm(temporary_sharedindex.filename.buf);

Shouldn't we be using the API function get_tempfile_path() for this
instead of reaching into its implementation detail?

> + if (ret) {
> + int save_errno = errno;
> + error("cannot fix permission bits on %s", 
> temporary_sharedindex.filename.buf);
> + delete_tempfile(&temporary_sharedindex);
> + errno = save_errno;
> + return ret;
> + }
>   ret = rename_tempfile(&temporary_sharedindex,
> git_path("sharedindex.%s", 
> sha1_to_hex(si->base->sha1)));
>   if (!ret) {


Re: [PATCH v2 00/29] Create a reference backend for packed refs

2017-06-23 Thread Junio C Hamano
Jeff King  writes:

> On Fri, Jun 23, 2017 at 03:01:59PM -0400, Jeff King wrote:
>
>> On Fri, Jun 23, 2017 at 09:01:18AM +0200, Michael Haggerty wrote:
>> 
>> > * Change patch 17 "packed_ref_store: support iteration" to always
>> >   iterate over the packed refs using `DO_FOR_EACH_INCLUDE_BROKEN`.
>> >   This switches off the check in the packed-ref iterator of whether a
>> >   reference is broken. This is now checked only in
>> >   `files_ref_iterator_advance()`, after the packed and loose
>> >   references have been merged together. It also saves some work.
>> 
>> I'm curious why you prefer this solution to just removing the code
>> entirely. Wouldn't it be an error to call the packed ref iterator
>> without INCLUDE_BROKEN? The "entries may not be valid" thing is a
>> property of the packed-refs concept itself, not a particular caller's
>> view of it.
>
> Speculating on my own question. I guess it would prepare us for a day
> when a possible ref store is to use a packed-refs _without_ loose refs.
> IOW, the property is defined on packed-refs today, but a possible future
> direction would be to use it by itself. But maybe I'm just making things
> up.

OK.  In other words, it's not a packed-refs's characteristics that
cruft are allowed.  It's that a ref storage that is implemented as
an overlay of one storage (which happens to be the loose one) on top
of another (which happens to be the packed refs file) allows the
latter one to have cruft if (and only if) that broken one is covered
by the former one.

> At any rate, I've read through the whole series and dropped a few
> comments in there. Overall it looks good. If I had one complaint, it's
> that the individual commits all look obviously correct but it is hard to
> judge whether the bigger steps they are taking are the right thing. I
> mostly have faith in you, as I know that your end goal is a good one,
> and that you're very familiar with this code.  But just something I
> noticed while reviewing.

Thanks.


Re: [showing-off RFC/PATCH 26/26] diff.c: have a "machine parseable" move coloring

2017-06-23 Thread Ævar Arnfjörð Bjarmason

On Tue, Jun 20 2017, Stefan Beller jotted:

> + Ævar, who was not part of the email where I copied all recipients
> from for this series.

I played around with this a bit, it would be great to have something
like this on top of --color-moved eventually. It's a lot easier to /^_
in a pager than looking for color codes.

Of course it's diff-incompatible output, but it's fair enough to have
that hidden behind some option IMO.

> On Mon, Jun 19, 2017 at 7:48 PM, Stefan Beller  wrote:
>> Ævar asked for it, this is how you would do it.
>> (plus documentation, tests, CLI knobs, options)
>>
>> Signed-off-by: Stefan Beller 
>> ---
>>  diff.c | 15 +++
>>  diff.h |  2 ++
>>  2 files changed, 13 insertions(+), 4 deletions(-)
>>
>> diff --git a/diff.c b/diff.c
>> index 7756f7610c..61caa057ff 100644
>> --- a/diff.c
>> +++ b/diff.c
>> @@ -997,6 +997,7 @@ static void emit_diff_symbol_from_struct(struct 
>> diff_options *o,
>> static const char *nneof = " No newline at end of file\n";
>> const char *context, *reset, *set, *meta, *fraginfo;
>> struct strbuf sb = STRBUF_INIT;
>> +   int sign;
>>
>> enum diff_symbol s = eds->s;
>> const char *line = eds->line;
>> @@ -1058,8 +1059,11 @@ static void emit_diff_symbol_from_struct(struct 
>> diff_options *o,
>> default:
>> set = diff_get_color_opt(o, DIFF_FILE_NEW);
>> }
>> +   sign = '+';
>> +   if (flags & DIFF_SYMBOL_MOVED_LINE && 
>> o->machine_readable_moves)
>> +   sign = '*';
>> reset = diff_get_color_opt(o, DIFF_RESET);
>> -   emit_line_ws_markup(o, set, reset, line, len, '+',
>> +   emit_line_ws_markup(o, set, reset, line, len, sign,
>> flags & DIFF_SYMBOL_CONTENT_WS_MASK,
>> flags & 
>> DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF);
>> break;
>> @@ -1086,8 +1090,11 @@ static void emit_diff_symbol_from_struct(struct 
>> diff_options *o,
>> default:
>> set = diff_get_color_opt(o, DIFF_FILE_OLD);
>> }
>> +   sign = '-';
>> +   if (flags & DIFF_SYMBOL_MOVED_LINE && 
>> o->machine_readable_moves)
>> +   sign = '_';
>> reset = diff_get_color_opt(o, DIFF_RESET);
>> -   emit_line_ws_markup(o, set, reset, line, len, '-',
>> +   emit_line_ws_markup(o, set, reset, line, len, sign,
>> flags & DIFF_SYMBOL_CONTENT_WS_MASK, 0);
>> break;
>> case DIFF_SYMBOL_WORDS_PORCELAIN:
>> @@ -5475,7 +5482,7 @@ static void diff_flush_patch_all_file_pairs(struct 
>> diff_options *o)
>> static struct emitted_diff_symbols esm = EMITTED_DIFF_SYMBOLS_INIT;
>> struct diff_queue_struct *q = &diff_queued_diff;
>>
>> -   if (o->color_moved)
>> +   if (o->color_moved || o->machine_readable_moves)
>> o->emitted_symbols = &esm;
>>
>> for (i = 0; i < q->nr; i++) {
>> @@ -5485,7 +5492,7 @@ static void diff_flush_patch_all_file_pairs(struct 
>> diff_options *o)
>> }
>>
>> if (o->emitted_symbols) {
>> -   if (o->color_moved) {
>> +   if (o->color_moved || o->machine_readable_moves) {
>> struct hashmap add_lines, del_lines;
>> unsigned ignore_ws = DIFF_XDL_TST(o, 
>> IGNORE_WHITESPACE);
>>
>> diff --git a/diff.h b/diff.h
>> index 98abd75521..b6c4d7ab0f 100644
>> --- a/diff.h
>> +++ b/diff.h
>> @@ -194,6 +194,8 @@ struct diff_options {
>> COLOR_MOVED_ZEBRA = 2,
>> COLOR_MOVED_ZEBRA_DIM = 3,
>> } color_moved;
>> +
>> +   int machine_readable_moves;
>>  };
>>
>>  void diff_emit_submodule_del(struct diff_options *o, const char *line);
>> --
>> 2.12.2.575.gb14f27f917
>>


Re: [RFC PATCH] proposal for refs/tracking/* hierarchy

2017-06-23 Thread Jacob Keller
On Fri, Jun 23, 2017 at 1:54 PM, Junio C Hamano  wrote:
> Jacob Keller  writes:
>
>> Instead, lets add support for a new refs/tracking/* hierarchy which is
>> laid out in such a way to avoid this inconsistency. All refs in
>> "refs/tracking//*" will include the complete ref, such that
>> dropping the "tracking/" part will give the exact ref name as it
>> is found in the upstream. Thus, we can track any ref here by simply
>> fetching it into refs/tracking//*.
>
> I do think this overall is a good goal to aim for wrt "tracking",
> i.e.  keeping a pristine copy of what we observed from the outside
> world.  In addition to what you listed as "undecided" below,
> however, I expect that this will highlight a lot of trouble in
> "working together", i.e. reconciling the differences of various
> world views and moving the project forward, in two orthogonal axes:
>

I agree, I think this is definitely a problem that we'd want/have to solve.

>  - Things pointed at by some refs (e.g. notes/, but I think the
>".gitmodules equivalent that is not tied to any particular commit
>in the superproject" Jonathan Nieder and friends advocate falls
>into the same category) do not correspond to the working tree
>contents, and merging their contents will always pose challenge
>when we need to prepare for conflict resolution.

This is part of why I started by looking at notes, since there is
already some code for notes merge, it just doesn't have a standard
place to store "remote" notes. I've wanted that ability to enable more
ease of sharing.

>
>  - Things pointed at by some other refs (e.g. tags/) do not make
>sense to be merged.  You may locally call a commit with a tag
>"wip", while your friends may use the same "wip" tag to point at
>a different one.  Both are valid, and more importantly, there is
>no point even trying to reconcile what the "wip" tag means in the
>project globally.
>
> For the former, I expect that merging these non-working tree
> contents will all have to require some specific tool that is
> tailored for the meaning each hierarchy has, just like "git notes
> merge" gives a solution that is very specific to the notes refs (I
> do not know how well "notes merge" works in practice, though).

Agreed. That's also part of why I'm looking at doing it as a partial
"one hierarchy at a time" proposal, I've got a somewhat better format
for that coming Soon(TM)

>
> For the latter, having a separate tracking hierarchy is a strict
> improvement from "tracking" point of view, but I think "working
> together" also needs a well designed set of new look-up rules, and a
> new convention.  For example, some tags may not want to be shared
> (e.g. "wip" example above) even though they should be easy to access
> by those who already have them (e.g. "git log ..wip" should work
> without having to say "git log ..refs/local-tags/wip", even if we
> decide to implement the "some tags may not want to be shared"
> segregation by introducing a new hierarchy).  And also a shared tag
> that is copied to "refs/tracking/origin/tags/v1.0" would need a way
> better than "git log tracking/origin/tags/v1.0" for this mechanism
> to be useful in everyday workflow.
>
> Thanks.
>

My thoughts on tags are sort of the following:

keep the default semantics of tags get copied into our local
refs/tags, (if we're fetching them). However, create some mechanism
for easily showing when you have a local tag with the same name as a
remote tag which don't point at the same thing, by using the
refs/tracking. Possibly, any time you grab a tag, check and see if the
remote version is different and "do something" like complain, or show
both, or give some advice (possibly with a new tool to "pull in the
remote tag if you verify it's accurate, etc".

This way, you generally work with tags the same way but get added
protection for knowing when your local tags differ from what remotes
show?

Thanks,
Jake


Re: [PATCH v2 19/29] packed-backend: new module for handling packed references

2017-06-23 Thread Junio C Hamano
Jeff King  writes:

> On Fri, Jun 23, 2017 at 09:01:37AM +0200, Michael Haggerty wrote:
>
>> Now that the interface between `files_ref_store` and
>> `packed_ref_store` is relatively narrow, move the latter into a new
>> module, "refs/packed-backend.h" and "refs/packed-backend.c". It still
>> doesn't quite implement the `ref_store` interface, but it will soon.
>> 
>> This commit moves code around and adjusts its visibility, but doesn't
>> change anything.
>
> Looks good. Stefan will be happy to know that I used --color-moved to
> look at it. ;)

This patch shows OK, but when applied to other changes in the
series, e.g. "packed_ref_store: make class into a subclass of
`ref_store`", it was somewhat irritating that all new blank lines
are shown as a copy-move of a single deleted blank line (also a
single "return refs" in an entirely new function being a copy/move
looked confusing).






Re: [PATCH] pathspec: die on empty strings as pathspec

2017-06-23 Thread Junio C Hamano
Torsten Bögershausen  writes:

> On 23/06/17 20:04, Junio C Hamano wrote:
>...
>> At this point in the test sequence, there is no modified path that
>> need to be further added before committing; the working tree is
>> empty except for .gitattributes which was just added to the index.
>> So we could instead pass no pathspec, but this is a conversion more
>> faithful to the original.
>>
>> Signed-off-by: Junio C Hamano 
>> ---
>>   t/t0027-auto-crlf.sh | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
>> index 93725895a4..e41c9b3bb2 100755
>> --- a/t/t0027-auto-crlf.sh
>> +++ b/t/t0027-auto-crlf.sh
>> @@ -322,7 +322,7 @@ test_expect_success 'setup master' '
>>  echo >.gitattributes &&
>>  git checkout -b master &&
>>  git add .gitattributes &&
>> -git commit -m "add .gitattributes" "" &&
>> +git commit -m "add .gitattributes" . &&
>
> Reading the context here, there shouldn't be a "pathspec" at all,
> as .gitattributes had been added just one line above.
>
> The line should have been from the very beginning:
>   git commit -m "add .gitattributes"  &&
>
> # What do you think ?

See above ;-)

And to be more explicit, it is not a fault of your earlier change,
either, that we didn't notice this problem since we started "warning".

We need to see if we can update our test framework to help us
better; I really think the test framework could and should have
helped us to notice this soon after we went into "keep behaving as
before but warn" stage.


Re: [RFC PATCH] proposal for refs/tracking/* hierarchy

2017-06-23 Thread Junio C Hamano
Jacob Keller  writes:

> Instead, lets add support for a new refs/tracking/* hierarchy which is
> laid out in such a way to avoid this inconsistency. All refs in
> "refs/tracking//*" will include the complete ref, such that
> dropping the "tracking/" part will give the exact ref name as it
> is found in the upstream. Thus, we can track any ref here by simply
> fetching it into refs/tracking//*.

I do think this overall is a good goal to aim for wrt "tracking",
i.e.  keeping a pristine copy of what we observed from the outside
world.  In addition to what you listed as "undecided" below,
however, I expect that this will highlight a lot of trouble in
"working together", i.e. reconciling the differences of various
world views and moving the project forward, in two orthogonal axes:

 - Things pointed at by some refs (e.g. notes/, but I think the
   ".gitmodules equivalent that is not tied to any particular commit
   in the superproject" Jonathan Nieder and friends advocate falls
   into the same category) do not correspond to the working tree
   contents, and merging their contents will always pose challenge
   when we need to prepare for conflict resolution.

 - Things pointed at by some other refs (e.g. tags/) do not make
   sense to be merged.  You may locally call a commit with a tag
   "wip", while your friends may use the same "wip" tag to point at
   a different one.  Both are valid, and more importantly, there is
   no point even trying to reconcile what the "wip" tag means in the
   project globally.

For the former, I expect that merging these non-working tree
contents will all have to require some specific tool that is
tailored for the meaning each hierarchy has, just like "git notes
merge" gives a solution that is very specific to the notes refs (I
do not know how well "notes merge" works in practice, though).

For the latter, having a separate tracking hierarchy is a strict
improvement from "tracking" point of view, but I think "working
together" also needs a well designed set of new look-up rules, and a
new convention.  For example, some tags may not want to be shared
(e.g. "wip" example above) even though they should be easy to access
by those who already have them (e.g. "git log ..wip" should work
without having to say "git log ..refs/local-tags/wip", even if we
decide to implement the "some tags may not want to be shared"
segregation by introducing a new hierarchy).  And also a shared tag
that is copied to "refs/tracking/origin/tags/v1.0" would need a way
better than "git log tracking/origin/tags/v1.0" for this mechanism
to be useful in everyday workflow.

Thanks.



Re: [PATCH] pathspec: die on empty strings as pathspec

2017-06-23 Thread Torsten Bögershausen


On 23/06/17 20:04, Junio C Hamano wrote:

Junio C Hamano  writes:


Sorry for my mess, see below




I am not sure if we even want the dot there, but at least that is
what the original author of the test intended to do when s/he
decided to pass an empty string as the pathspec.

  t/t0027-auto-crlf.sh | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)


I'll queue the following _before_ your "final step", so that the
whole thing can be advanced to 'next' and hopefully to 'master' in
some future releases.

Given that we ourselves did not even notice until now that one of
our scripts get broken by this "final step", even though we kept
issuing the warning message, we may want to re-think our overall
strategy for deprecation.  We've assumed that "keep behaving as
before but warn for a few years and then finally give a hard
failure" would be sufficient, but depending on how the script that
employ our programs hide the warnings from the end users, that may
not be a good enough transition strategy.

At the same time we re-think the deprecation strategy, we also need
to see if we can update our test framework to help us better.
Ideally, we could have caught this existing breakage of passing ""
as pathspec in the test soon after we went into "keep behaving as
before but warn" stage.  We didn't and found it out only when we
switched to "finally give a hard failure" stage.  That is very
unsatisfactory.

Needless to say, neither of the above two comes from _your_ change.
It's just something we need to improve in a larger scope of the
whole project I realized.

Thanks.

-- >8 --
Subject: [PATCH] t0027: do not use an empty string as a pathspec element

In an upcoming update, we will finally make an empty string illegal
as an element in a pathspec; it traditionally meant the same as ".",
i.e. include everything, so update this test that passes "" to pass
a dot instead.

At this point in the test sequence, there is no modified path that
need to be further added before committing; the working tree is
empty except for .gitattributes which was just added to the index.
So we could instead pass no pathspec, but this is a conversion more
faithful to the original.

Signed-off-by: Junio C Hamano 
---
  t/t0027-auto-crlf.sh | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 93725895a4..e41c9b3bb2 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -322,7 +322,7 @@ test_expect_success 'setup master' '
echo >.gitattributes &&
git checkout -b master &&
git add .gitattributes &&
-   git commit -m "add .gitattributes" "" &&
+   git commit -m "add .gitattributes" . &&


Reading the context here, there shouldn't be a "pathspec" at all,
as .gitattributes had been added just one line above.

The line should have been from the very beginning:
git commit -m "add .gitattributes"  &&

# What do you think ?



printf "\$Id:  
\$\nLINEONE\nLINETWO\nLINETHREE" >LF &&
printf "\$Id:  
\$\r\nLINEONE\r\nLINETWO\r\nLINETHREE" >CRLF &&
printf "\$Id:  
\$\nLINEONE\r\nLINETWO\nLINETHREE"   >CRLF_mix_LF &&



Re: [PATCH] xdiff: trim common tail with -U0 after diff

2017-06-23 Thread René Scharfe

Am 23.06.2017 um 12:36 schrieb Daniel Hahler:

When -U0 is used, trim_common_tail should be called after `xdl_diff`, so
that `--indent-heuristic` (and other diff processing) works as expected.

It also removes the check for `!(xecfg->flags & XDL_EMIT_FUNCCONTEXT)`
added in e0876bca4, which does not appear to be necessary anymore after
moving the trimming down.

This only adds a test to t4061-diff-indent.sh, but should also have one for
normal (i.e. non-experimental) diff mode probably?!

Ref: https://github.com/tomtom/quickfixsigns_vim/issues/74#issue-237900460
---
  t/t4061-diff-indent.sh | 15 +++
  xdiff-interface.c  |  7 ---
  2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/t/t4061-diff-indent.sh b/t/t4061-diff-indent.sh
index 2affd7a10..df3151393 100755
--- a/t/t4061-diff-indent.sh
+++ b/t/t4061-diff-indent.sh
@@ -116,6 +116,16 @@ test_expect_success 'prepare' '
 4
EOF
  
+	cat <<-\EOF >spaces-compacted-U0-expect &&

+   diff --git a/spaces.txt b/spaces.txt
+   --- a/spaces.txt
+   +++ b/spaces.txt
+   @@ -4,0 +5,3 @@ a
+   +b
+   +a
+   +
+   EOF
+
tr "_" " " <<-\EOF >functions-expect &&
diff --git a/functions.c b/functions.c
--- a/functions.c
@@ -184,6 +194,11 @@ test_expect_success 'diff: --indent-heuristic with 
--histogram' '
compare_diff spaces-compacted-expect out-compacted4
  '
  
+test_expect_success 'diff: --indent-heuristic with -U0' '

+   git diff -U0 --indent-heuristic old new -- spaces.txt >out-compacted5 &&
+   compare_diff spaces-compacted-U0-expect out-compacted5
+'
+
  test_expect_success 'diff: ugly functions' '
git diff --no-indent-heuristic old new -- functions.c >out &&
compare_diff functions-expect out


The changed test script passes just fine for me even without your change
to xdiff-interface.c, which is odd.  Do you have another way to
demonstrate the unexpected behavior?  And can someone replicate the
failure?

René


Re: [PATCH] submodule--helper: teach push-check to handle HEAD

2017-06-23 Thread Stefan Beller
On Fri, Jun 23, 2017 at 1:04 PM, Brandon Williams  wrote:
> In 06bf4ad1d (push: propagate remote and refspec with
> --recurse-submodules) push was taught how to propagate a refspec down to
> submodules when the '--recurse-submodules' flag is given.  The only refspecs
> that are allowed to be propagated are ones which name a ref which exists
> in both the superproject and the submodule, with the caveat that 'HEAD'
> was disallowed.
>
> This patch teaches push-check (the submodule helper which determines if
> a refspec can be propagated to a submodule) to permit propagating 'HEAD'
> if and only if the superproject and the submodule both have the same
> named branch checked out and the submodule is not in a detached head
> state.

cont'd:

We need this use case because Gerrit's documentation ingrains
this workflow in its users to use

git push  HEAD:refs/for/

And when both the submodule as well as the superproject
are still on a branch with the same name (and not detached) we'd
not be misunderstood by the user on the syntax.

More on the code later.


Re: [PATCH v2 00/29] Create a reference backend for packed refs

2017-06-23 Thread Junio C Hamano
Jeff King  writes:

> On Fri, Jun 23, 2017 at 09:01:18AM +0200, Michael Haggerty wrote:
>
>> * Change patch 17 "packed_ref_store: support iteration" to always
>>   iterate over the packed refs using `DO_FOR_EACH_INCLUDE_BROKEN`.
>>   This switches off the check in the packed-ref iterator of whether a
>>   reference is broken. This is now checked only in
>>   `files_ref_iterator_advance()`, after the packed and loose
>>   references have been merged together. It also saves some work.
>
> I'm curious why you prefer this solution to just removing the code
> entirely. Wouldn't it be an error to call the packed ref iterator
> without INCLUDE_BROKEN? The "entries may not be valid" thing is a
> property of the packed-refs concept itself, not a particular caller's
> view of it.

Thanks for pointing it out.  I was wondering about the same thing
and you phrased it a lot more succinctly than the draft I was
writing.


Re: --color-moved feedback, was Re: [PATCH v2 19/29] packed-backend: new module for handling packed references

2017-06-23 Thread Stefan Beller
On Fri, Jun 23, 2017 at 1:10 PM, Jeff King  wrote:
> [I culled the cc list, as it was big and they don't all necessarily care
> about this feature]

Yeah I was on the verge to do that, but did not pull through.


>
> In the end, I just did --color-moved=plain,  ...
> "yep, this is all a giant moved chunk, so I don't have to look carefully
> at it".

This is dangerous, as "plain" does not care about permutations.
See the 7f5af90798 (diff.c: color moved lines differently, 2017-06-19)
for details. You would want at least "zebra", which would show you
permutations.

> I'm not sure what the default mode is. When I first used it it seemed to
> italicize a bunch of text. Which I didn't even notice at first, so I
> thought it was broken.

ok, italics does not seem to be popular.
I liked it as I could take the same color for these uninteresting lines.

> I didn't try the "dim" feature; I don't think urxvt supports that
> attribute (though maybe it was what was doing the italics?).

That is on by default (with italics), maybe the default should rather
be "zebra" as that has fewer colors but still contains all the information
needed to be sure about
"yep, this is all a giant moved chunk, so I don't have to look
carefully at it".

>
> One minor quibble is that I used with "git log", so I was looking at all
> the commits with that coloring. But the ones that didn't have movement
> had a lot of noisy "moved" sections. E.g., one line moving here or
> there, or even blank lines. It might be worth having some heuristics to
> identify a chunk (I think I saw some discussion on that earlier, and
> maybe it's even there and I didn't see it).

It is not there, yet. It was Michaels suggestions.
I'll give that a try, too.

>> Let's take this patch as an example, if someone were to find a bug
>> in one of the moved functions, they would send a fix based on the
>> function in refs/files-backend.c, such that it can easily be merged down
>> to maint, but when merging it forward with this, it may clash.
>
> That feels more dangerous to me, just because the heuristics seem to
> find a lot of "moves" of repeated code. Imagine a simple patch like
> "switch return 0 to return -1". If the code you're touching went away,
> there's a very good chance that another "return 0" popped up somewhere
> else in the code base. A conflict is what you want there; silently
> changing some other site would be not only wrong, but quite subtle and
> hard to find.

I agree, that is the danger, but the scale of danger is the size of the moved
chunk. A file is usually a very large chunk, such that it is obviously a good
idea to fix that. Maybe we'd introduce a threshold, that the fix must not be in
range of the block boundaries of say 3 lines.
(Then the moved block must be at least 7 lines of code such that a one liner
fix in the middle would kick in)

Thanks,
Stefan


Re: [PATCH v2 01/29] t1408: add a test of stale packed refs covered by loose refs

2017-06-23 Thread Junio C Hamano
Jeff King  writes:

> On Fri, Jun 23, 2017 at 09:01:19AM +0200, Michael Haggerty wrote:
>
>> +test_expect_success setup '
>> +test_tick &&
>> +git commit --allow-empty -m one &&
>> +one=$(git rev-parse HEAD) &&
>> +git for-each-ref >actual &&
>> +echo "$one commit   refs/heads/master" >expect &&
>> +test_cmp expect actual &&
>> +
>> +git pack-refs --all &&
>> +git for-each-ref >actual &&
>> +echo "$one commit   refs/heads/master" >expect &&
>> +test_cmp expect actual &&
>> +
>> +cat .git/packed-refs &&
>
> I think we'd usually drop debugging "cat"s like these in the name of
> keeping the process count down. Unless they really are intended to
> confirm that .git/packed-refs exists (although test_path_is_file is a
> less expensive way of checking that).
>
> That's a minor nit, though.

Sorry, these two cat's were what I used while debugging the test and
should be dropped.

Will remove while queuing.

Thanks for spotting.


Re: [PATCHv2 04/25] diff.c: introduce emit_diff_symbol

2017-06-23 Thread Stefan Beller
On Fri, Jun 23, 2017 at 1:07 PM, Junio C Hamano  wrote:
> Stefan Beller  writes:
>
>> diff --git a/new.txt b/new.txt
>> index fa69b07..412428c 100644
>> Binary files a/new.txt and b/new.txt differ
>>
>>   could be buffered as
>>  DIFF_SYMBOL_DIFF_START + new.txt
>>  DIFF_SYMBOL_INDEX_MODE + fa69b07 412428c "non-executable" flag
>>  DIFF_SYMBOL_BINARY_FILES + new.txt
>
> Hopefully this is an oversimplified example and I'd assume that you
> will do the right thing when showing a renamed filepair by allowing
> both old and new paths that could be different?

Yes, this is simplified to drive the point of having as little data as possible,
so I thought we might have a flag that says "same file name" instead of giving
the file name twice.

We do not do such an optimization yet.


--color-moved feedback, was Re: [PATCH v2 19/29] packed-backend: new module for handling packed references

2017-06-23 Thread Jeff King
[I culled the cc list, as it was big and they don't all necessarily care
about this feature]

On Fri, Jun 23, 2017 at 12:46:47PM -0700, Stefan Beller wrote:

> > Looks good. Stefan will be happy to know that I used --color-moved to
> > look at it. ;)
> 
> Hah!
> 
> As a follow up on that, let's perform a user survey :-P
> * How was your review experience?
> * Were you annoyed by the default colors or mode?
>   (That is best expressed as a patch, as it seems like
>bikeshedding to me, but I am far from being a UX expert ;)

I'm not sure what the default mode is. When I first used it it seemed to
italicize a bunch of text. Which I didn't even notice at first, so I
thought it was broken.

In the end, I just did --color-moved=plain, which seemed to color with
magenta/cyan. I found that a bit loud and switched to "red 80" and
"green 80" (i.e., a dark grey background, as I usually have a black
one). I probably would have picked a darker grey, but I use urxvt and it
doesn't seem to do 24-bit color codes.

I didn't try the "dim" feature; I don't think urxvt supports that
attribute (though maybe it was what was doing the italics?).

Anyway, it worked fine after that. My main use for it was just seeing
"yep, this is all a giant moved chunk, so I don't have to look carefully
at it".

One minor quibble is that I used with "git log", so I was looking at all
the commits with that coloring. But the ones that didn't have movement
had a lot of noisy "moved" sections. E.g., one line moving here or
there, or even blank lines. It might be worth having some heuristics to
identify a chunk (I think I saw some discussion on that earlier, and
maybe it's even there and I didn't see it).

> Just today I thought about that further:
> While reviewing is one thing (which I do a lot), how can we make this
> work with merging changes?
> 
> I think the file rename detection is acknowledged by the merge code,
> such that a plain file rename and a patch to said file is easy on the
> maintainer, but we would want that for smaller code movements, too.
> 
> Let's take this patch as an example, if someone were to find a bug
> in one of the moved functions, they would send a fix based on the
> function in refs/files-backend.c, such that it can easily be merged down
> to maint, but when merging it forward with this, it may clash.

That feels more dangerous to me, just because the heuristics seem to
find a lot of "moves" of repeated code. Imagine a simple patch like
"switch return 0 to return -1". If the code you're touching went away,
there's a very good chance that another "return 0" popped up somewhere
else in the code base. A conflict is what you want there; silently
changing some other site would be not only wrong, but quite subtle and
hard to find.

-Peff


Re: [PATCHv2 04/25] diff.c: introduce emit_diff_symbol

2017-06-23 Thread Junio C Hamano
Stefan Beller  writes:

> diff --git a/new.txt b/new.txt
> index fa69b07..412428c 100644
> Binary files a/new.txt and b/new.txt differ
>
>   could be buffered as
>  DIFF_SYMBOL_DIFF_START + new.txt
>  DIFF_SYMBOL_INDEX_MODE + fa69b07 412428c "non-executable" flag
>  DIFF_SYMBOL_BINARY_FILES + new.txt

Hopefully this is an oversimplified example and I'd assume that you
will do the right thing when showing a renamed filepair by allowing
both old and new paths that could be different?



[PATCH] submodule--helper: teach push-check to handle HEAD

2017-06-23 Thread Brandon Williams
In 06bf4ad1d (push: propagate remote and refspec with
--recurse-submodules) push was taught how to propagate a refspec down to
submodules when the '--recurse-submodules' flag is given.  The only refspecs
that are allowed to be propagated are ones which name a ref which exists
in both the superproject and the submodule, with the caveat that 'HEAD'
was disallowed.

This patch teaches push-check (the submodule helper which determines if
a refspec can be propagated to a submodule) to permit propagating 'HEAD'
if and only if the superproject and the submodule both have the same
named branch checked out and the submodule is not in a detached head
state.

Signed-off-by: Brandon Williams 
---
 builtin/submodule--helper.c| 57 +++---
 submodule.c| 18 ++---
 t/t5531-deep-submodule-push.sh | 25 +-
 3 files changed, 82 insertions(+), 18 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1b4d2b346..fd5020036 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1107,24 +1107,41 @@ static int resolve_remote_submodule_branch(int argc, 
const char **argv,
 static int push_check(int argc, const char **argv, const char *prefix)
 {
struct remote *remote;
+   const char *superproject_head;
+   char *head;
+   int detached_head = 0;
+   struct object_id head_oid;
 
-   if (argc < 2)
-   die("submodule--helper push-check requires at least 1 
argument");
+   if (argc < 3)
+   die("submodule--helper push-check requires at least 2 
argument");
+
+   /*
+* superproject's resolved head ref.
+* if HEAD then the superproject is in a detached head state, otherwise
+* it will be the resolved head ref.
+*/
+   superproject_head = argv[1];
+   /* Get the submodule's head ref and determine if it is detached */
+   head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+   if (!head)
+   die(_("Failed to resolve HEAD as a valid ref."));
+   if (!strcmp(head, "HEAD"))
+   detached_head = 1;
 
/*
 * The remote must be configured.
 * This is to avoid pushing to the exact same URL as the parent.
 */
-   remote = pushremote_get(argv[1]);
+   remote = pushremote_get(argv[2]);
if (!remote || remote->origin == REMOTE_UNCONFIGURED)
-   die("remote '%s' not configured", argv[1]);
+   die("remote '%s' not configured", argv[2]);
 
/* Check the refspec */
-   if (argc > 2) {
-   int i, refspec_nr = argc - 2;
+   if (argc > 3) {
+   int i, refspec_nr = argc - 3;
struct ref *local_refs = get_local_heads();
struct refspec *refspec = parse_push_refspec(refspec_nr,
-argv + 2);
+argv + 3);
 
for (i = 0; i < refspec_nr; i++) {
struct refspec *rs = refspec + i;
@@ -1132,18 +1149,30 @@ static int push_check(int argc, const char **argv, 
const char *prefix)
if (rs->pattern || rs->matching)
continue;
 
-   /*
-* LHS must match a single ref
-* NEEDSWORK: add logic to special case 'HEAD' once
-* working with submodules in a detached head state
-* ceases to be the norm.
-*/
-   if (count_refspec_match(rs->src, local_refs, NULL) != 1)
+   /* LHS must match a single ref */
+   switch(count_refspec_match(rs->src, local_refs, NULL)) {
+   case 1:
+   break;
+   case 0:
+   /*
+* If LHS matches 'HEAD' then we need to ensure
+* that it matches the same named branch
+* checked out in the superproject.
+*/
+   if (!strcmp(rs->src, "HEAD")) {
+   if (!detached_head &&
+   !strcmp(head, superproject_head))
+   break;
+   die("HEAD does not match the named 
branch in the superproject");
+   }
+   default:
die("src refspec '%s' must name a ref",
rs->src);
+   }
}
free_refspec(refspec_nr, refspec);
}
+   free(head);
 
return 0;
 }
diff --git a/submodule.c b/submodule.

Re: [PATCH v2 00/29] Create a reference backend for packed refs

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 03:01:59PM -0400, Jeff King wrote:

> On Fri, Jun 23, 2017 at 09:01:18AM +0200, Michael Haggerty wrote:
> 
> > * Change patch 17 "packed_ref_store: support iteration" to always
> >   iterate over the packed refs using `DO_FOR_EACH_INCLUDE_BROKEN`.
> >   This switches off the check in the packed-ref iterator of whether a
> >   reference is broken. This is now checked only in
> >   `files_ref_iterator_advance()`, after the packed and loose
> >   references have been merged together. It also saves some work.
> 
> I'm curious why you prefer this solution to just removing the code
> entirely. Wouldn't it be an error to call the packed ref iterator
> without INCLUDE_BROKEN? The "entries may not be valid" thing is a
> property of the packed-refs concept itself, not a particular caller's
> view of it.

Speculating on my own question. I guess it would prepare us for a day
when a possible ref store is to use a packed-refs _without_ loose refs.
IOW, the property is defined on packed-refs today, but a possible future
direction would be to use it by itself. But maybe I'm just making things
up.

At any rate, I've read through the whole series and dropped a few
comments in there. Overall it looks good. If I had one complaint, it's
that the individual commits all look obviously correct but it is hard to
judge whether the bigger steps they are taking are the right thing. I
mostly have faith in you, as I know that your end goal is a good one,
and that you're very familiar with this code.  But just something I
noticed while reviewing.

-Peff


Re: [PATCH v2 29/29] read_packed_refs(): die if `packed-refs` contains bogus data

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:47AM +0200, Michael Haggerty wrote:

> The old code ignored any lines that it didn't understand. This is
> dangerous. Instead, `die()` if the `packed-refs` file contains any
> lines that we don't know how to handle.

This seems like a big improvement. Is it worth adding a test for a
corrupted file?

I assume this isn't something you saw in the wild, but just a deficiency
you noticed while reading the code.

I suspect this laxness may have been what allowed us to add the optional
peeled values long ago. But I think I'd rather see us be more strict and
notice corruption or nonsense rather than quietly ignoring (especially
because an operation like "git pack-refs" would then overwrite it,
dropping whatever entries we didn't understand).

-Peff


Re: [PATCH v2 28/29] repack_without_refs(): don't lock or unlock the packed refs

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:46AM +0200, Michael Haggerty wrote:

> Change `repack_without_refs()` to expect the packed-refs lock to be
> held already, and not to release the lock before returning. Change the
> callers to deal with lock management.
> 
> This change makes it possible for callers to hold the packed-refs lock
> for a longer span of time, a possibility that will eventually make it
> possible to fix some longstanding races.

This is the sort of clue I was thinking about in my last email. :)

> The only semantic change here is that `repack_without_refs()` used to
> forgot to release the lock in the `if (!removed)` exit path. That
> omission is now fixed.

s/used to forgot/previously forgot/ or similar?

> @@ -731,14 +717,12 @@ int repack_without_refs(struct ref_store *ref_store,
>* All packed entries disappeared while we were
>* acquiring the lock.
>*/
> - rollback_packed_refs(refs);
> + clear_packed_ref_cache(refs);
>   return 0;

And this is the reason for the earlier "you should be able to clear the
packed ref cache without holding the lock" commit, I guess. Makes sense.

-Peff


Re: [PATCH v2 27/29] commit_packed_refs(): remove call to `packed_refs_unlock()`

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:45AM +0200, Michael Haggerty wrote:

> Instead, change the callers of `commit_packed_refs()` to call
> `packed_refs_unlock()`.

Why? I can guess that the reason is probably "because we're going to add
a new caller that doesn't want to do that", but it's nice to hear even
that. Those kinds of clues help make a more coherent narrative when
you're reading through 29 refactoring patches. ;)

-Peff


Re: [RFC/PATCH v4 09/49] Add initial external odb support

2017-06-23 Thread Ben Peart



On 6/20/2017 3:54 AM, Christian Couder wrote:

From: Jeff King 

Signed-off-by: Christian Couder 


I'd suggest you make the function names consistent with the capabilities 
flags (ie get, put, have) both here in odb_helper.c/h and in 
external_odb.c/h.



+int odb_helper_has_object(struct odb_helper *o, const unsigned char *sha1);
+int odb_helper_fetch_object(struct odb_helper *o, const unsigned char *sha1,
+   int fd);
+
+#endif /* ODB_HELPER_H */


The following patch fixes a few compiler warnings/errors.


diff --git a/odb-helper.c b/odb-helper.c
index 01cd6a713c..ffbbd2fc87 100644
--- a/odb-helper.c
+++ b/odb-helper.c
@@ -118,7 +118,7 @@ static int check_object_process_error(int err,
  unsigned int capability)
 {
if (!err)
-   return;
+   return 0;

if (!strcmp(status, "error")) {
/* The process signaled a problem with the file. */
@@ -192,7 +192,7 @@ static ssize_t 
read_packetized_plain_object_to_fd(struct odb_helper *o,

git_SHA1_Init(&hash);

/* First header.. */
-   hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), 
size) + 1;
+   hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX, 
typename(type), size) + 1;

stream.next_in = (unsigned char *)hdr;
stream.avail_in = hdrlen;
while (git_deflate(&stream, 0) == Z_OK)
@@ -253,7 +253,7 @@ static ssize_t 
read_packetized_plain_object_to_fd(struct odb_helper *o,

return -1;
}
if (total_got != size) {
-   warning("size mismatch from odb helper '%s' for %s (%lu 
!= %lu)",
+   warning("size mismatch from odb helper '%s' for %s (%lu 
!= %"PRIuMAX")",

o->name, sha1_to_hex(sha1), total_got, size);
return -1;
}
@@ -587,7 +587,6 @@ static int have_object_process(struct odb_helper *o)
struct strbuf status = STRBUF_INIT;
const char *cmd = o->cmd;
uint64_t start;
-   char *line;
int packet_len;
int total_got = 0;

@@ -946,7 +945,7 @@ int odb_helper_for_each_object(struct odb_helper *o,
return 0;
 }

-int odb_helper_write_plain_object(struct odb_helper *o,
+static int odb_helper_write_plain_object(struct odb_helper *o,
  const void *buf, size_t len,
  const char *type, unsigned char *sha1)
 {



Re: [PATCH v2 26/29] clear_packed_ref_cache(): don't protest if the lock is held

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:44AM +0200, Michael Haggerty wrote:

> The existing callers already check that the lock isn't held just
> before calling `clear_packed_ref_cache()`, and in the near future we
> want to be able to call this function when the lock is held.

OK. It's not immediately obvious that this is true, because some of the
relationships are a bit buried, but I double-checked and I think it is
the case.

-Peff


Re: [PATCH v2 19/29] packed-backend: new module for handling packed references

2017-06-23 Thread Stefan Beller
On Fri, Jun 23, 2017 at 12:35 PM, Jeff King  wrote:
> On Fri, Jun 23, 2017 at 09:01:37AM +0200, Michael Haggerty wrote:
>
>> Now that the interface between `files_ref_store` and
>> `packed_ref_store` is relatively narrow, move the latter into a new
>> module, "refs/packed-backend.h" and "refs/packed-backend.c". It still
>> doesn't quite implement the `ref_store` interface, but it will soon.
>>
>> This commit moves code around and adjusts its visibility, but doesn't
>> change anything.
>
> Looks good. Stefan will be happy to know that I used --color-moved to
> look at it. ;)

Hah!

As a follow up on that, let's perform a user survey :-P
* How was your review experience?
* Were you annoyed by the default colors or mode?
  (That is best expressed as a patch, as it seems like
   bikeshedding to me, but I am far from being a UX expert ;)

Just today I thought about that further:
While reviewing is one thing (which I do a lot), how can we make this
work with merging changes?

I think the file rename detection is acknowledged by the merge code,
such that a plain file rename and a patch to said file is easy on the
maintainer, but we would want that for smaller code movements, too.

Let's take this patch as an example, if someone were to find a bug
in one of the moved functions, they would send a fix based on the
function in refs/files-backend.c, such that it can easily be merged down
to maint, but when merging it forward with this, it may clash.


Re: [PATCH v2 22/29] commit_packed_refs(): use a staging file separate from the lockfile

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:40AM +0200, Michael Haggerty wrote:

> @@ -522,10 +529,16 @@ int lock_packed_refs(struct ref_store *ref_store, int 
> flags)
>   timeout_configured = 1;
>   }
>  
> + /*
> +  * Note that we close the lockfile immediately because we
> +  * don't write new content to it, but rather to a separate
> +  * tempfile.
> +  */
>   if (hold_lock_file_for_update_timeout(
>   &refs->lock,
>   refs->path,
> - flags, timeout_value) < 0)
> + flags, timeout_value) < 0 ||
> + close_lock_file(&refs->lock))
>   return -1;

I was wondering whether we'd catch a case which accidentally wrote to
the lockfile (instead of the new tempfile, but this close() is a good
safety check).

> - if (commit_lock_file(&refs->lock)) {
> - strbuf_addf(err, "error overwriting %s: %s",
> + if (rename_tempfile(&refs->tempfile, refs->path)) {
> + strbuf_addf(err, "error replacing %s: %s",
>   refs->path, strerror(errno));
>   goto out;
>   }

So our idea of committing now is the tempfile rename, and then...

> @@ -617,9 +640,10 @@ int commit_packed_refs(struct ref_store *ref_store, 
> struct strbuf *err)
>   goto out;
>  
>  error:
> - rollback_lock_file(&refs->lock);
> + delete_tempfile(&refs->tempfile);
>  
>  out:
> + rollback_lock_file(&refs->lock);

We always rollback the lockfile regardless, because committing it would
overwrite our new content with an empty file. There's no real safety
against somebody calling commit_lock_file() on it, but it also seems
like an uncommon error to make.

So this all looks good to me.

-Peff


Re: [PATCH] xdiff: trim common tail with -U0 after diff

2017-06-23 Thread Junio C Hamano
Stefan Beller  writes:

> So I tried finding out more about this hack,
> and found the patch that introduced the common tail trimming at
>   https://public-inbox.org/git/7vmysez0oa@gitster.siamese.dyndns.org/
>   913b45f51b (xdi_diff: trim common trailing lines, 2007-12-13)

A relevant one that makes me hesitate to take this kind of change is
this:

https://public-inbox.org/git/alpine.lfd.0..0712202009290.21...@woody.linux-foundation.org/#t

that resulted in this change:

commit d2f82950a9226ae1102a7a97f03440a4bf8c6c09
Author: Linus Torvalds 
Date:   Thu Dec 20 20:22:46 2007 -0800

Re(-re)*fix trim_common_tail()

The tar-ball and the git archive itself is fine, but yes, the diff from
2.6.23 to 2.6.24-rc6 is bad. It's the "trim_common_tail()" optimization
that has caused way too much pain.

Very interesting breakage. The patch was actually "correct" in a (rather
limited) technical sense, but the context at the end was missing because
while the trim_common_tail() code made sure to keep enough common context
to allow a valid diff to be generated, the diff machinery itself could
decide that it could generate the diff differently than the "obvious"
solution.

Thee sad fact is that the git optimization (which is very important for
"git blame", which needs no context), is only really valid for that one
case where we really don't need any context.



Re: [PATCH v2 20/29] packed_ref_store: make class into a subclass of `ref_store`

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:38AM +0200, Michael Haggerty wrote:

> Add the infrastructure to make `packed_ref_store` implement
> `ref_store`, at least formally (few of the methods are actually
> implemented yet). Change the functions in its interface to take
> `ref_store *` arguments. Change `files_ref_store` to store a pointer
> to `ref_store *` and to call functions via the virtual `ref_store`
> interface where possible. This also means that a few
> `packed_ref_store` functions can become static.

By itself this looks correct (as do the patches leading up to it). But I
think some of the "big picture" is lost. Why do we want it to look like
a ref store?

I suspect the answer is too big to go into this individual commit
message. But I went back and re-read the cover letter, and I don't think
it's really explained there, either.

So I'm not really sure where it ought to be covered (or if I simply
missed it somewhere, or if it's coming up; I'm reading the patches
linearly).

-Peff


Re: [PATCH] xdiff: trim common tail with -U0 after diff

2017-06-23 Thread Stefan Beller
On Fri, Jun 23, 2017 at 12:13 PM, Junio C Hamano  wrote:
> Daniel Hahler  writes:
>
>> When -U0 is used, trim_common_tail should be called after `xdl_diff`, so
>> that `--indent-heuristic` (and other diff processing) works as expected.
>
> I thought common-tail trimming was a hack/optimization to avoid
> having to pass the whole thing to have xdl_diff() work on it?  What
> would we be gaining by unconditionally passing the whole thing first
> and then still trimming?

So I tried finding out more about this hack,
and found the patch that introduced the common tail trimming at
  https://public-inbox.org/git/7vmysez0oa@gitster.siamese.dyndns.org/
  913b45f51b (xdi_diff: trim common trailing lines, 2007-12-13)

In the early days there were much larger email threads apparently.
I haven't seen such a big one in a while. I did not find the email that
the commit message referenced to unfortunately.

AFAICT we have 2 things going on:
* swapping the order of xdl_diff and the tail trimming
* change the condition under which the tail is trimmed
  (as a logical follow up/ cleanup because of the first point)

I do not understand the first one, yet.


Re: [PATCH v2 19/29] packed-backend: new module for handling packed references

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:37AM +0200, Michael Haggerty wrote:

> Now that the interface between `files_ref_store` and
> `packed_ref_store` is relatively narrow, move the latter into a new
> module, "refs/packed-backend.h" and "refs/packed-backend.c". It still
> doesn't quite implement the `ref_store` interface, but it will soon.
> 
> This commit moves code around and adjusts its visibility, but doesn't
> change anything.

Looks good. Stefan will be happy to know that I used --color-moved to
look at it. ;)

-Peff


Re: [PATCH] xdiff: trim common tail with -U0 after diff

2017-06-23 Thread Junio C Hamano
Daniel Hahler  writes:

> When -U0 is used, trim_common_tail should be called after `xdl_diff`, so
> that `--indent-heuristic` (and other diff processing) works as expected.

I thought common-tail trimming was a hack/optimization to avoid
having to pass the whole thing to have xdl_diff() work on it?  What
would we be gaining by unconditionally passing the whole thing first
and then still trimming?

> It also removes the check for `!(xecfg->flags & XDL_EMIT_FUNCCONTEXT)`
> added in e0876bca4, which does not appear to be necessary anymore after
> moving the trimming down.

The code was conditionally disabling the hack/optimization; with it
unconditionally disabled, of course it wouldn't be needed, no?

I could understand if the motivation and the proposed change were
"tail-trimming outlived its usefulness, so remove it altogether", or
"trail-trimming negatively affects the output by robbing useful
information that could be used by indent-heuristic, so disable it
when the heuristic is in use".

But neither is what this patch does, so I am sort of at loss.


> --- a/t/t4061-diff-indent.sh
> +++ b/t/t4061-diff-indent.sh
> @@ -116,6 +116,16 @@ test_expect_success 'prepare' '
>4
>   EOF
>  
> + cat <<-\EOF >spaces-compacted-U0-expect &&
> + diff --git a/spaces.txt b/spaces.txt
> + --- a/spaces.txt
> + +++ b/spaces.txt
> + @@ -4,0 +5,3 @@ a
> + +b
> + +a
> + +
> + EOF
> +
>   tr "_" " " <<-\EOF >functions-expect &&
>   diff --git a/functions.c b/functions.c
>   --- a/functions.c
> @@ -184,6 +194,11 @@ test_expect_success 'diff: --indent-heuristic with 
> --histogram' '
>   compare_diff spaces-compacted-expect out-compacted4
>  '
>  
> +test_expect_success 'diff: --indent-heuristic with -U0' '
> + git diff -U0 --indent-heuristic old new -- spaces.txt >out-compacted5 &&
> + compare_diff spaces-compacted-U0-expect out-compacted5
> +'
> +
>  test_expect_success 'diff: ugly functions' '
>   git diff --no-indent-heuristic old new -- functions.c >out &&
>   compare_diff functions-expect out
> diff --git a/xdiff-interface.c b/xdiff-interface.c
> index d3f78ca2a..a7e0e3583 100644
> --- a/xdiff-interface.c
> +++ b/xdiff-interface.c
> @@ -125,16 +125,17 @@ static void trim_common_tail(mmfile_t *a, mmfile_t *b)
>  
>  int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, 
> xdemitconf_t const *xecfg, xdemitcb_t *xecb)
>  {
> + int ret;
>   mmfile_t a = *mf1;
>   mmfile_t b = *mf2;
>  
>   if (mf1->size > MAX_XDIFF_SIZE || mf2->size > MAX_XDIFF_SIZE)
>   return -1;
>  
> - if (!xecfg->ctxlen && !(xecfg->flags & XDL_EMIT_FUNCCONTEXT))
> + ret = xdl_diff(&a, &b, xpp, xecfg, xecb);
> + if (ret && !xecfg->ctxlen)
>   trim_common_tail(&a, &b);
> -
> - return xdl_diff(&a, &b, xpp, xecfg, xecb);
> + return ret;
>  }
>  
>  int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,




[PATCH 2/3] builtin/fetch: parse recurse-submodules-default at default options parsing

2017-06-23 Thread Stefan Beller
Instead of just storing the string and then later calling our own
parsing function 'parse_fetch_recurse_submodules_arg', make use of the
function callback 'option_fetch_parse_recurse_submodules' that was
introduced in the last patch. Also move all submodule recursing variables
in one spot at the top of the file.

Signed-off-by: Stefan Beller 
---
 builtin/fetch.c | 19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 9d58dc0a8a..3cca568173 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -36,7 +36,7 @@ static int prune = -1; /* unspecified */
 #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
 
 static int all, append, dry_run, force, keep, multiple, update_head_ok, 
verbosity, deepen_relative;
-static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+static int progress = -1;
 static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
 static int max_children = -1;
 static enum transport_family family;
@@ -48,7 +48,8 @@ static struct strbuf default_rla = STRBUF_INIT;
 static struct transport *gtransport;
 static struct transport *gsecondary;
 static const char *submodule_prefix = "";
-static const char *recurse_submodules_default;
+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+static int recurse_submodules_default = RECURSE_SUBMODULES_DEFAULT;
 static int shown_url = 0;
 static int refmap_alloc, refmap_nr;
 static const char **refmap_array;
@@ -123,9 +124,11 @@ static struct option builtin_fetch_options[] = {
   PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
   N_("prepend this to submodule path output"), 
PARSE_OPT_HIDDEN },
-   { OPTION_STRING, 0, "recurse-submodules-default",
-  &recurse_submodules_default, NULL,
-  N_("default mode for recursion"), PARSE_OPT_HIDDEN },
+   { OPTION_CALLBACK, 0, "recurse-submodules-default",
+  &recurse_submodules_default, N_("on-demand"),
+  N_("default for recursive fetching of submodules "
+ "(lower priority than config files)"),
+  PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules },
OPT_BOOL(0, "update-shallow", &update_shallow,
 N_("accept refs that update .git/shallow")),
{ OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"),
@@ -1333,10 +1336,8 @@ int cmd_fetch(int argc, const char **argv, const char 
*prefix)
deepen = 1;
 
if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
-   if (recurse_submodules_default) {
-   int arg = 
parse_fetch_recurse_submodules_arg("--recurse-submodules-default", 
recurse_submodules_default);
-   set_config_fetch_recurse_submodules(arg);
-   }
+   if (recurse_submodules_default != RECURSE_SUBMODULES_DEFAULT)
+   
set_config_fetch_recurse_submodules(recurse_submodules_default);
gitmodules_config();
git_config(submodule_config, NULL);
}
-- 
2.12.2.575.gb14f27f917



[PATCH 3/3] pull: optionally rebase submodules (remote submodule changes only)

2017-06-23 Thread Stefan Beller
Teach pull to optionally update submodules when '--recurse-submodules'
is provided.  This will teach pull to run 'submodule update --rebase'
when the '--recurse-submodules' and '--rebase' flags are given under
specific circumstances.

On a rebase workflow:
=

1. Both sides change the submodule
 --
Let's assume the following history in a submodule:

  H---I---J---K---L local branch
   \
M---N---O---P remote branch

and the following in the superproject (recorded submodule in parens):

  A(H)---B(I)---F(K)---G(L)  local branch
  \
   C(N)---D(N)---E(P) remote branch

In an ideal world this would rebase the submodule and rewrite
the submodule pointers that the superproject points at such that
the superproject looks like

  A(H)---B(I)  F(K')---G(L')  rebased branch
   \/
   C(N)---D(N)---E(P) remote branch

and the submodule as:

J---K---L (old dangeling tip)
   /
  H---I   J'---K'---L' rebased branch
   \ /
M---N---O---P remote branch

And if a conflict arises in the submodule the superproject rebase
would stop at that commit at which the submodule conflict occurs.

Currently a "pull --rebase" in the superproject produces
a merge conflict as the submodule pointer changes are
conflicting and cannot be resolved.

2. Local submodule changes only
 ---
Assuming histories as above, except that the remote branch
would not contain submodule changes, then a result as

  A(H)---B(I)   F(K)---G(L)  rebased branch
   \/
   C(I)---D(I)---E(I) remote branch

is desire-able. This is what currently happens in rebase.

If the recursive flag is given, the ideal git would
produce a superproject as:

  A(H)---B(I)  F(K')---G(L')  rebased branch (incl. sub rebase!)
   \/
   C(I)---D(I)---E(I) remote branch

and the submodule as:

J---K---L (old dangeling tip)
   /
  H---I   J'---K'---L' locally rebased branch
   \ /
M---N---O---P advanced branch

This patch doesn't address this issue, however
a test is added that this fails up front.

3. Remote submodule changes only
 --
Assuming histories as in (1) except that the local superproject branch
would not have touched the submodule the rebase already works out in the
superproject with no conflicts:

  A(H)---B(I)   F(P)---G(P)  rebased branch (no sub changes)
   \ /
   C(N)---D(N)---E(P) remote branch

The recurse flag as presented in this patch would additionally
update the submodule as:

  H---I  J'---K'---L' rebased branch
   \/
M---N---O---P remote branch

As neither J, K, L nor J', K', L' are referred to from the superproject,
no rewriting of the superproject commits is required.

Conclusion for 'pull --rebase --recursive'
 -
If there are no local superproject changes it is sufficient to call
"submodule update --rebase" as this produces the desired results. In case
of conflicts, the behavior is the same as in 'submodule update --recursive'
which is assumed to be sane.

This patch implements (3) only.

On a merge workflow:


We'll start off with the same underlying DAG as in (1) in the rebase
workflow. So in an ideal world a 'pull --merge --recursive' would
produce this:

  H---I---J---K---LX
   \  /
M---N---O---P

with X as the new merge-commit in the submodule and the superproject
as:

  A(H)---B(I)---F(K)---G(L)---Y(X)
  \  /
   C(N)---D(N)---E(P)

However modifying the submodules on the fly is not supported in git-merge
such that Y(X) is not easy to produce in a single patch. In fact git-merge
doesn't know about submodules at all.

However when at least one side does not contain commits touching the
submodule at all, then we do not need to perform the merge for the
submodule but a fast-forward can be done via checking out either L or P
in the submodule.  This strategy is implemented in 68d03e4a6e (Implement
automatic fast-forward merge for submodules, 2010-07-07) already, so
to align with the rebase behavior we need to also update the worktree
of the submodule.

Signed-off-by: Brandon Williams 
Signed-off-by: Stefan Beller 
---
 Documentation/git-pull.txt | 12 
 builtin/pull.c | 73 +++---
 submodule.c| 26 +
 submodule.h|  4 +++
 t/t5572-pull-submodule.sh  | 58 
 5 files changed, 157 insertions(+), 16 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index e414185f5a..b201af6f19 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -86,12 +86,12 @@

[PATCH 1/3] builtin/fetch: factor submodule recurse parsing out to submodule config

2017-06-23 Thread Stefan Beller
Later we want to access this parsing in builtin/pull as well.

Signed-off-by: Stefan Beller 
---
 builtin/fetch.c| 18 ++
 submodule-config.c | 22 ++
 submodule-config.h |  3 +++
 3 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 100248c5af..9d58dc0a8a 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -53,20 +53,6 @@ static int shown_url = 0;
 static int refmap_alloc, refmap_nr;
 static const char **refmap_array;
 
-static int option_parse_recurse_submodules(const struct option *opt,
-  const char *arg, int unset)
-{
-   if (unset) {
-   recurse_submodules = RECURSE_SUBMODULES_OFF;
-   } else {
-   if (arg)
-   recurse_submodules = 
parse_fetch_recurse_submodules_arg(opt->long_name, arg);
-   else
-   recurse_submodules = RECURSE_SUBMODULES_ON;
-   }
-   return 0;
-}
-
 static int git_fetch_config(const char *k, const char *v, void *cb)
 {
if (!strcmp(k, "fetch.prune")) {
@@ -115,9 +101,9 @@ static struct option builtin_fetch_options[] = {
N_("number of submodules fetched in parallel")),
OPT_BOOL('p', "prune", &prune,
 N_("prune remote-tracking branches no longer on remote")),
-   { OPTION_CALLBACK, 0, "recurse-submodules", NULL, N_("on-demand"),
+   { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, 
N_("on-demand"),
N_("control recursive fetching of submodules"),
-   PARSE_OPT_OPTARG, option_parse_recurse_submodules },
+   PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules },
OPT_BOOL(0, "dry-run", &dry_run,
 N_("dry run")),
OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
diff --git a/submodule-config.c b/submodule-config.c
index 4f58491ddb..265d036095 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -2,6 +2,7 @@
 #include "submodule-config.h"
 #include "submodule.h"
 #include "strbuf.h"
+#include "parse-options.h"
 
 /*
  * submodule cache lookup structure
@@ -234,6 +235,27 @@ int parse_fetch_recurse_submodules_arg(const char *opt, 
const char *arg)
return parse_fetch_recurse(opt, arg, 1);
 }
 
+int option_fetch_parse_recurse_submodules(const struct option *opt,
+ const char *arg, int unset)
+{
+   int *v;
+
+   if (!opt->value)
+   return -1;
+
+   v = opt->value;
+
+   if (unset) {
+   *v = RECURSE_SUBMODULES_OFF;
+   } else {
+   if (arg)
+   *v = parse_fetch_recurse_submodules_arg(opt->long_name, 
arg);
+   else
+   *v = RECURSE_SUBMODULES_ON;
+   }
+   return 0;
+}
+
 static int parse_update_recurse(const char *opt, const char *arg,
int die_on_error)
 {
diff --git a/submodule-config.h b/submodule-config.h
index d434ecdb45..1076a68653 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -23,6 +23,9 @@ struct submodule {
 };
 
 extern int parse_fetch_recurse_submodules_arg(const char *opt, const char 
*arg);
+struct option;
+extern int option_fetch_parse_recurse_submodules(const struct option *opt,
+const char *arg, int unset);
 extern int parse_update_recurse_submodules_arg(const char *opt, const char 
*arg);
 extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg);
 extern int parse_submodule_config_option(const char *var, const char *value);
-- 
2.12.2.575.gb14f27f917



[PATCH 0/3] pull: optionally rebase submodules

2017-06-23 Thread Stefan Beller
This supersedes the RFC in May by Brandon
https://public-inbox.org/git/20170511172437.96878-1-bmw...@google.com/

It adds more (enough?) error checking, as explained in the last
commit message.

Documentation and issues raised in the review
of that RFC have been addressed.

The first two patches are a little refactoring needed for the last patch
that adds the functionality.

Thanks,
Stefan

Stefan Beller (3):
  builtin/fetch: factor submodule recurse parsing out to submodule
config
  builtin/fetch: parse recurse-submodules-default at default options
parsing
  pull: optionally rebase submodules (remote submodule changes only)

 Documentation/git-pull.txt | 12 
 builtin/fetch.c| 37 ---
 builtin/pull.c | 73 +++---
 submodule-config.c | 22 ++
 submodule-config.h |  3 ++
 submodule.c| 26 +
 submodule.h|  4 +++
 t/t5572-pull-submodule.sh  | 58 
 8 files changed, 194 insertions(+), 41 deletions(-)

-- 
2.12.2.575.gb14f27f917



Re: [PATCH v2 17/29] packed_ref_store: support iteration

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:35AM +0200, Michael Haggerty wrote:

> +static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
> +{
> + struct packed_ref_iterator *iter =
> + (struct packed_ref_iterator *)ref_iterator;

I thought had some kind of safe downcasting mechanism for iterators, but
I think I was just thinking of files_downcast() for the ref-store.

I don't mind not having that kind of safety. It seems like an uncommon
error to call the packed-ref iterator function on the wrong type,
especially as it's static here and only accessible as a virtual function
for a packed_ref_iterator.

But something to think about, I guess, as we add more polymorphism.

-Peff


Re: [PATCH v2 00/29] Create a reference backend for packed refs

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:18AM +0200, Michael Haggerty wrote:

> * Change patch 17 "packed_ref_store: support iteration" to always
>   iterate over the packed refs using `DO_FOR_EACH_INCLUDE_BROKEN`.
>   This switches off the check in the packed-ref iterator of whether a
>   reference is broken. This is now checked only in
>   `files_ref_iterator_advance()`, after the packed and loose
>   references have been merged together. It also saves some work.

I'm curious why you prefer this solution to just removing the code
entirely. Wouldn't it be an error to call the packed ref iterator
without INCLUDE_BROKEN? The "entries may not be valid" thing is a
property of the packed-refs concept itself, not a particular caller's
view of it.

-Peff


Re: [PATCH v3 0/4] Add regression tests for recent rebase -i fixes

2017-06-23 Thread Junio C Hamano
Junio C Hamano  writes:

> For 3420, I can wrap the two-liner patch I showed here earlier into
> a commit on top of the series.  

So, here is what I'll queue on top before merging the topic down to
'master'.

-- >8 --
Subject: [PATCH] t3420: fix under GETTEXT_POISON build

Newly added tests to t3420 in this series prepare expected
human-readable output from "git rebase -i" and then compare the
actual output with it.  As the output from the command is designed
to go through i18n/l10n, we need to use test_i18ncmp to tell
GETTEXT_POISON build that it is OK the output does not match.

Signed-off-by: Junio C Hamano 
---
 t/t3420-rebase-autostash.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh
index 6826c38cbd..e243700660 100755
--- a/t/t3420-rebase-autostash.sh
+++ b/t/t3420-rebase-autostash.sh
@@ -178,7 +178,7 @@ testrebase () {
test_when_finished git branch -D rebased-feature-branch &&
suffix=${type#\ --} && suffix=${suffix:-am} &&
create_expected_success_$suffix &&
-   test_cmp expected actual
+   test_i18ncmp expected actual
'
 
test_expect_success "rebase$type: dirty index, non-conflicting rebase" '
@@ -275,7 +275,7 @@ testrebase () {
test_when_finished git branch -D rebased-feature-branch &&
suffix=${type#\ --} && suffix=${suffix:-am} &&
create_expected_failure_$suffix &&
-   test_cmp expected actual
+   test_i18ncmp expected actual
'
 }
 
-- 
2.13.1-678-g93553a431c



Re: [PATCH v2 01/29] t1408: add a test of stale packed refs covered by loose refs

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 09:01:19AM +0200, Michael Haggerty wrote:

> +test_expect_success setup '
> + test_tick &&
> + git commit --allow-empty -m one &&
> + one=$(git rev-parse HEAD) &&
> + git for-each-ref >actual &&
> + echo "$one commit   refs/heads/master" >expect &&
> + test_cmp expect actual &&
> +
> + git pack-refs --all &&
> + git for-each-ref >actual &&
> + echo "$one commit   refs/heads/master" >expect &&
> + test_cmp expect actual &&
> +
> + cat .git/packed-refs &&

I think we'd usually drop debugging "cat"s like these in the name of
keeping the process count down. Unless they really are intended to
confirm that .git/packed-refs exists (although test_path_is_file is a
less expensive way of checking that).

That's a minor nit, though.

-Peff


Re: [RFC/PATCH v4 07/49] Git/Packet.pm: add packet_initialize()

2017-06-23 Thread Ben Peart
I like where this ends but it seems to me that patches 6, 7 and 8 should 
just get merged into patch 4 and 5.


On 6/20/2017 3:54 AM, Christian Couder wrote:

Add a function to initialize the communication. And use this
function in 't/t0021/rot13-filter.pl'.

Signed-off-by: Christian Couder 
---
  perl/Git/Packet.pm  | 13 +
  t/t0021/rot13-filter.pl |  8 +---
  2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/perl/Git/Packet.pm b/perl/Git/Packet.pm
index 2ad6b00d6c..b0233caf37 100644
--- a/perl/Git/Packet.pm
+++ b/perl/Git/Packet.pm
@@ -19,6 +19,7 @@ our @EXPORT = qw(
packet_bin_write
packet_txt_write
packet_flush
+   packet_initialize
);
  our @EXPORT_OK = @EXPORT;
  
@@ -70,3 +71,15 @@ sub packet_flush {

print STDOUT sprintf( "%04x", 0 );
STDOUT->flush();
  }
+
+sub packet_initialize {
+   my ($name, $version) = @_;
+
+   ( packet_txt_read() eq ( 0, $name . "-client" ) ) || die "bad 
initialize";
+   ( packet_txt_read() eq ( 0, "version=" . $version ) ) || die "bad 
version";
+   ( packet_bin_read() eq ( 1, "" ) )|| die "bad version 
end";
+
+   packet_txt_write( $name . "-server" );
+   packet_txt_write( "version=" . $version );
+   packet_flush();
+}
diff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl
index 36a9eb3608..5b05518640 100644
--- a/t/t0021/rot13-filter.pl
+++ b/t/t0021/rot13-filter.pl
@@ -40,13 +40,7 @@ sub rot13 {
  print $debug "START\n";
  $debug->flush();
  
-( packet_txt_read() eq ( 0, "git-filter-client" ) ) || die "bad initialize";

-( packet_txt_read() eq ( 0, "version=2" ) ) || die "bad version";
-( packet_bin_read() eq ( 1, "" ) )  || die "bad version end";
-
-packet_txt_write("git-filter-server");
-packet_txt_write("version=2");
-packet_flush();
+packet_initialize("git-filter", 2);
  
  ( packet_txt_read() eq ( 0, "capability=clean" ) )  || die "bad capability";

  ( packet_txt_read() eq ( 0, "capability=smudge" ) ) || die "bad capability";



Re: [PATCH v3 0/4] Add regression tests for recent rebase -i fixes

2017-06-23 Thread Junio C Hamano
Junio C Hamano  writes:

> 3404 needs a similar fix-up for the series to be able to stand on
> its own.  Alternatively, at least we need to understand what in 'pu'
> makes the result of the merge pass---the symptom indicates that this
> topic cannot be merged to a released version without that unknown
> other topic in 'pu' merged if we want to keep POISON build passing
> the tests.

Ah, no worries.  I think I figured it out.  

The topic "rebase -i regression fix", which this "regression fix
tests" builds on, is queued on an older codebase than 0d75bfe6
("tests: fix tests broken under GETTEXT_POISON=YesPlease",
2017-05-05); it is natural these old test breakages can be seen when
the topic is tested alone.

So we can safely merge this topic down.

Thanks for prodding me to take a deeper look.




Re: your mail

2017-06-23 Thread Junio C Hamano
Jeff King  writes:

> On Thu, Jun 22, 2017 at 10:23:17PM -0700, Junio C Hamano wrote:
>
>> Otoh, "community" page does not encourage subscription as a way to
>> ensure you'll see follow-up discussion, which may be a good thing to
>> add.
>> 
>> A tangent I just found funny is this paragraph on the "community"
>> page:
>> 
>> The archive can be found on public-inbox. Click here to
>> subscribe.
>> 
>> Of course clicking does not take you to a subscription page for
>> public-inbox, even though the two sentences appear to be related.
>> 
>> Perhaps swap the order of the two, like so, with a bit richer
>> explanation taken from Ævar's version:
>> 
>>  ... disable HTML in your outgoing messages.
>> 
>>  By subscribing (click here), you can make sure you're not
>>  missing follow-up discussion and also learn from other
>>  development in the community.  The list archive can be found
>>  on public-inbox.
>
> Yeah, I think that's a good suggestion. Do you want to phrase it in the
> form of a patch? :)

OK. Letme try.


Re: [RFC/PATCH v4 00/49] Add initial experimental external ODB support

2017-06-23 Thread Ben Peart



On 6/20/2017 3:54 AM, Christian Couder wrote:

Goal


Git can store its objects only in the form of loose objects in
separate files or packed objects in a pack file.

To be able to better handle some kind of objects, for example big
blobs, it would be nice if Git could store its objects in other object
databases (ODB).

To do that, this patch series makes it possible to register commands,
also called "helpers", using "odb..command" config variables,
to access external ODBs where objects can be stored and retrieved.

External ODBs should be able to tranfer information about the blobs
they store. This patch series shows how this is possible using kind of
replace refs.



Great to see this making progress!

My thoughts and questions are mostly about the overall design tradeoffs.

Is your intention to enable the ODB to completely replace the regular 
object store or just to supplement it?  I think it would be good to 
ensure the interface is robust and performant enough to actually replace 
the current object store interface (even if we don't actually do that 
just yet).


Another way of asking this is: do the 3 verbs (have, get, put) and the 3 
types of "get" enable you to wrap the current loose object and pack file 
code as ODBs and run completely via the external ODB interface?  If not, 
what is missing and can it be added?


_Eventually_ it would be great to see the current object store(s) moved 
behind the new ODB interface.


When there are multiple ODB providers, what is the order they are 
called?  If one fails a request (get, have, put) are the others called 
to see if they can fulfill the request?


Can the order they are called for various verb be configured explicitly? 
For example, it would be nice to have a "large object ODB handler" 
configured to get first try at all "put" verbs.  Then if it meets it's 
size requirements, it will handle the verb, otherwise it fail and git 
will try the other ODBs.




Design
~~

* The "helpers" (registered commands)

Each helper manages access to one external ODB.

There are now 2 different modes for helper:

   - When "odb..scriptMode" is set to "true", the helper is
 launched each time Git wants to communicate with the 
 external ODB.

   - When "odb..scriptMode" is not set or set to "false", then
 the helper is launched once as a sub-process (using
 sub-process.h), and Git communicates with it using packet lines.



Is it worth supporting two different modes long term?  It seems that 
this could be simplified (less code to write, debug, document, support) 
by only supporting the 2nd that uses the sub-process.  As far as I can 
tell, the capabilities are the same, it's just the second one is more 
performant when multiple calls are made.



A helper can be given different instructions by Git. The instructions
that are supported are negociated at the beginning of the
communication using a capability mechanism.

For now the following instructions are supported:

   - "have": the helper should respond with the sha1, size and type of
 all the objects the external ODB contains, one object per line.

   - "get ": the helper should then read from the external ODB
 the content of the object corresponding to  and pass it to Git.

   - "put   ": the helper should then read from from
 Git an object and store it in the external ODB.

Currently "have" and "put" are optional.


It's good the various verbs can be optional.  That way any particular 
ODB only has to handle those it needs to provide a different behavior for.




There are 3 different kinds of "get" instructions depending on how the
helper passes objects to Git:

   - "fault_in": the helper will write the requested objects directly
 into the regular Git object database, and then Git will retry
 reading it from there.



I think the "fault_in" behavior can be implemented efficiently without 
the overhead of a 3rd special "get" instruction if we enable some of the 
other capabilities discussed.


For example, assume an ODB is setup to handle missing objects (by 
registering itself as "last" in the prioritized list of ODB handlers). 
If it is ever asked to retrieve a missing object, it can retrieve the 
object and return it as a "git_object" or "plain_object" and also cache 
it locally as a loose object, pack file, or any other ODB handler 
supported mechanism.  Future requests will then provide that object via 
the locally cached copy and its associated ODB handler.



   - "git_object": the helper will send the object as a Git object.

   - "plain_object": the helper will send the object (a blob) as a raw
 object. (The blob content will be sent as is.)

For now the kind of "get" that is supported is read from the
"odb..fetchKind" configuration variable, but in the future it
should be decided as part of the capability negociation.



I agree it makes sense to move this into the capability negotiation but 
I also wonder if we really need to support both.  Is there

Re: [PATCH] pathspec: die on empty strings as pathspec

2017-06-23 Thread Junio C Hamano
Junio C Hamano  writes:

> I am not sure if we even want the dot there, but at least that is
> what the original author of the test intended to do when s/he
> decided to pass an empty string as the pathspec.
>
>  t/t0027-auto-crlf.sh | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

I'll queue the following _before_ your "final step", so that the
whole thing can be advanced to 'next' and hopefully to 'master' in
some future releases.  

Given that we ourselves did not even notice until now that one of
our scripts get broken by this "final step", even though we kept
issuing the warning message, we may want to re-think our overall
strategy for deprecation.  We've assumed that "keep behaving as
before but warn for a few years and then finally give a hard
failure" would be sufficient, but depending on how the script that
employ our programs hide the warnings from the end users, that may
not be a good enough transition strategy.

At the same time we re-think the deprecation strategy, we also need
to see if we can update our test framework to help us better.
Ideally, we could have caught this existing breakage of passing ""
as pathspec in the test soon after we went into "keep behaving as
before but warn" stage.  We didn't and found it out only when we
switched to "finally give a hard failure" stage.  That is very
unsatisfactory.

Needless to say, neither of the above two comes from _your_ change.
It's just something we need to improve in a larger scope of the
whole project I realized.

Thanks.

-- >8 --
Subject: [PATCH] t0027: do not use an empty string as a pathspec element

In an upcoming update, we will finally make an empty string illegal
as an element in a pathspec; it traditionally meant the same as ".",
i.e. include everything, so update this test that passes "" to pass
a dot instead.

At this point in the test sequence, there is no modified path that
need to be further added before committing; the working tree is
empty except for .gitattributes which was just added to the index.
So we could instead pass no pathspec, but this is a conversion more
faithful to the original.

Signed-off-by: Junio C Hamano 
---
 t/t0027-auto-crlf.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
index 93725895a4..e41c9b3bb2 100755
--- a/t/t0027-auto-crlf.sh
+++ b/t/t0027-auto-crlf.sh
@@ -322,7 +322,7 @@ test_expect_success 'setup master' '
echo >.gitattributes &&
git checkout -b master &&
git add .gitattributes &&
-   git commit -m "add .gitattributes" "" &&
+   git commit -m "add .gitattributes" . &&
printf "\$Id:  
\$\nLINEONE\nLINETWO\nLINETHREE" >LF &&
printf "\$Id:  
\$\r\nLINEONE\r\nLINETWO\r\nLINETHREE" >CRLF &&
printf "\$Id:  
\$\nLINEONE\r\nLINETWO\nLINETHREE"   >CRLF_mix_LF &&
-- 
2.13.1-678-g93553a431c






Re: [PATCH v4 00/20] repository object

2017-06-23 Thread Junio C Hamano
Jeff Hostetler  writes:

> On 6/22/2017 2:43 PM, Brandon Williams wrote:
>> As before you can find this series at:
>> https://github.com/bmwill/git/tree/repository-object
>>
>> Changes in v4:
>>
>> * Patch 11 is slightly different and turns off all path relocation when a
>>worktree is provided instead of just for the index file (Thanks for the 
>> help
>>Jonathan Nieder).
>> * 'repo_init()' has a tighter API and now requires that the provided gitdir 
>> is
>>a path to the gitdir instead of either a path to the gitdir or path to the
>>worktree (which has a .git file or directory) (Thanks Jonathan Tan).
>> * Minor comment and commit message chagnes
>>
>> Note: Like v3 this series is dependent on on 'bw/config-h' and
>>'bw/ls-files-sans-the-index'
>>
>> Brandon Williams (20):
>
> I read thru the v1 and v4 versions.  Very nice.
> And thanks for splitting the earlier parts out
> into independent patches.
>
> I didn't have any complaints, but did want to ACK
> that I had looked at it.

Thanks.


Re: [PATCH 1/3] list-objects: add filter_blob to traverse_commit_list

2017-06-23 Thread Jeff Hostetler



On 6/22/2017 6:10 PM, Jonathan Tan wrote:

On Thu, 22 Jun 2017 14:45:26 -0700
Jonathan Tan  wrote:


On Thu, 22 Jun 2017 20:36:13 +
Jeff Hostetler  wrote:


From: Jeff Hostetler 

In preparation for partial/sparse clone/fetch where the
server is allowed to omit large/all blobs from the packfile,
teach traverse_commit_list() to take a blob filter-proc that
controls when blobs are shown and marked as SEEN.

Normally, traverse_commit_list() always marks visited blobs
as SEEN, so that the show_object() callback will never see
duplicates.  Since a single blob OID may be referenced by
multiple pathnames, we may not be able to decide if a blob
should be excluded until later pathnames have been traversed.
With the filter-proc, the automatic deduping is disabled.


Comparing this approach (this patch and the next one) against mine [1],
I see that this has the advantage of (in pack-objects) avoiding the
invocation of add_preferred_base_object() on blobs that are filtered
out, avoiding polluting the "to_pack" data structure with information
that we do not need.

But it does add an extra place where blobs are filtered out (besides
add_object_entry()), which makes it harder for the reader to keep track
of what's going on. I took a brief look to see if filtering could be
eliminated from add_object_entry(), but that function is called from
many places, so I couldn't tell.

Anyway, I think both approaches will work (this patch's and mine [1]).

[1] 
https://public-inbox.org/git/6f7934621717141ce3bb6bc05cf1d59c7900ccc5.1496432147.git.jonathanta...@google.com/


Also it should be mentioned somewhere that this does not cover the
bitmap case - a similar discussion should be included in one of the
patches, like I did in [1].

And looking back at my original cover letter [2], I wrote:


This is similar to [1] except that this

[...]

is slightly more comprehensive in
that the read_object_list_from_stdin() codepath is also covered in
addition to the get_object_list() codepath. (Although, to be clear,
upload-pack always passes "--revs" and thus only needs the
get_object_list() codepath).


(The [1] in the quote above refers to one of Jeff Hostetler's patches,
[QUOTE 1].)

The same issue applies to this patch (since
read_object_list_from_stdin() invokes add_object_entry() directly
without going through the traversal mechanism) and probably warrants at
least some description in one of the commit messages.

[1] 
https://public-inbox.org/git/6f7934621717141ce3bb6bc05cf1d59c7900ccc5.1496432147.git.jonathanta...@google.com/
[2] https://public-inbox.org/git/cover.1496361873.git.jonathanta...@google.com/

[QUOTE 1] 
https://public-inbox.org/git/1488994685-37403-3-git-send-email-jeffh...@microsoft.com/




Thanks for the quick feedback.  I'll dig into each of these comments
as I work on my next draft.

Jeff


Re: [PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread Junio C Hamano
Jeff King  writes:

> The idea was that eventually the caller might be able to come up with a
> TZ that is not blank, but is also not what strftime("%Z") would produce.
> Conceivably that could be done if Git commits carried the "%Z"
> information (not likely), or if we used a reverse-lookup table (also not
> likely).

The former might be conceivable, but I do not think the latter is
workable.  Knowing that a location happened to be using a particular
GMT offset at a specific point in time simply is not sufficient to
give us a zone name; the whole idea of a zone name being that it
will give us rules that would apply to other timestamps, not just
the one we are paring with GMT offset in our committer and author
timestamp fields.

A third possibility is the information may come out of band.
Something like "When gitster is in +0900 he is in JST" can be
maintained per project and supplied by the caller.

> This closes the door on that.  Since we don't have immediate plans to go
> that route, I'm OK with this patch. It would be easy enough to re-open
> the door if we change our minds later.

I agree that it is not too much hassle to revert this change.  I
actually would not have minded if René's original were written with
a boolean flag.  But I do not see the value in flipping ("" vs NULL)
with a bool now.  The benefit we are gaining (other than closing the
door) is unclear to me.

>>  /**
>>   * Add the time specified by `tm`, as formatted by `strftime`.
>> - * `tz_name` is used to expand %Z internally unless it's NULL.
>>   * `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
>>   * of Greenwich, and it's used to expand %z internally.  However, tokens
>>   * with modifiers (e.g. %Ez) are passed to `strftime`.
>> + * `omit_strftime_tz_name` when set, means don't let `strftime` format
>> + * %Z, instead do our own formatting.
>
> Since we now always turn it into a blank string, perhaps "do our own
> formatting" could be more descriptive: we convert it into the empty
> string.

Yeah, that reads better.  I am also OK if this said that an empty
string is an accepted POSIX way to fallback when the information is
unavailable---and we really are in that "information is unavailable"
situation in this code.


Re: [PATCH v3 0/4] Add regression tests for recent rebase -i fixes

2017-06-23 Thread Junio C Hamano
Phillip Wood  writes:

> t3404 passes for me,
> $ make GETTEXT_POISON=YesPlease
> $ cd t &&sh t3404-rebase-interactive.sh -i -v
> ...
> # still have 1 known breakage(s)
> # passed all remaining 95 test(s)
> 1..96

Interesting.  The tip of 'pu', which includes this series, does pass
for me, too, but the tip of this topic 7d70e6b9 ("rebase: add more
regression tests for console output", 2017-06-19) tested in
isolation fails, and gives the output at the end of this message.

> Do you want me to submit a fixup patch for t3420 or have you
> got one already?

For 3420, I can wrap the two-liner patch I showed here earlier into
a commit on top of the series.  

3404 needs a similar fix-up for the series to be able to stand on
its own.  Alternatively, at least we need to understand what in 'pu'
makes the result of the merge pass---the symptom indicates that this
topic cannot be merged to a released version without that unknown
other topic in 'pu' merged if we want to keep POISON build passing
the tests.

Thanks.

-- output from 3404 follows --

Initialized empty Git repository in /home/gitster/git/t/trash 
directory.t3404-rebase-interactive/.git/
expecting success: 
test_commit A file1 &&
test_commit B file1 &&
test_commit C file2 &&
test_commit D file1 &&
test_commit E file3 &&
git checkout -b branch1 A &&
test_commit F file4 &&
test_commit G file1 &&
test_commit H file5 &&
git checkout -b branch2 F &&
test_commit I file6 &&
git checkout -b conflict-branch A &&
test_commit one conflict &&
test_commit two conflict &&
test_commit three conflict &&
test_commit four conflict &&
git checkout -b no-conflict-branch A &&
test_commit J fileJ &&
test_commit K fileK &&
test_commit L fileL &&
test_commit M fileM &&
git checkout -b no-ff-branch A &&
test_commit N fileN &&
test_commit O fileO &&
test_commit P fileP

[master# GETTEXT POISON # 6e62bf8] A
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 file1
[master 313fe96] B
 Author: A U Thor 
 1 file changed, 1 insertion(+), 1 deletion(-)
[master d0f65f2] C
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 file2
[master 0547e3f] D
 Author: A U Thor 
 1 file changed, 1 insertion(+), 1 deletion(-)
[master 8f99a4f] E
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 file3
# GETTEXT POISON #[branch1 cfefd94] F
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 file4
[branch1 83751a6] G
 Author: A U Thor 
 1 file changed, 1 insertion(+), 1 deletion(-)
[branch1 4373208] H
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 file5
# GETTEXT POISON #[branch2 615be62] I
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 file6
# GETTEXT POISON #[conflict-branch b895952] one
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 conflict
[conflict-branch 766a798] two
 Author: A U Thor 
 1 file changed, 1 insertion(+), 1 deletion(-)
[conflict-branch 1eadf03] three
 Author: A U Thor 
 1 file changed, 1 insertion(+), 1 deletion(-)
[conflict-branch f91a2b3] four
 Author: A U Thor 
 1 file changed, 1 insertion(+), 1 deletion(-)
# GETTEXT POISON #[no-conflict-branch 808874f] J
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 fileJ
[no-conflict-branch 265b89e] K
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 fileK
[no-conflict-branch 6b0f5e6] L
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 fileL
[no-conflict-branch 3389558] M
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 fileM
# GETTEXT POISON #[no-ff-branch 53b4423] N
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 fileN
[no-ff-branch cc47714] O
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 fileO
[no-ff-branch faef1a5] P
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 fileP
ok 1 - setup

expecting success: 
git checkout -b emptybranch master &&
git commit --allow-empty -m "empty" &&
git rebase --keep-empty -i HEAD~2 &&
git log --oneline >actual &&
test_line_count = 6 actual

# GETTEXT POISON #[emptybranch da33401] empty
 Author: A U Thor 
Successfully rebased and updated refs/heads/emptybranch.
ok 2 - rebase --keep-empty

expecting success: 
git checkout master &&
(
set_fake_editor &&
FAKE_LINES="1 exec_>touch-one
2 exec_>touch-two exec_false exec_>touch-three
3 4 
exec_>\"touch-file__name_with_spaces\";_>touch-after-semicolon 5" &&
export FAKE_LINES &&
test_must_fail git rebase -i A
) &&
test_path_is_file touch-one &&
test_path_is_file touch-two &&
test_path_is_missing touch-three " (should have st

Re: your mail

2017-06-23 Thread Jeff King
On Thu, Jun 22, 2017 at 10:23:17PM -0700, Junio C Hamano wrote:

> Otoh, "community" page does not encourage subscription as a way to
> ensure you'll see follow-up discussion, which may be a good thing to
> add.
> 
> A tangent I just found funny is this paragraph on the "community"
> page:
> 
> The archive can be found on public-inbox. Click here to
> subscribe.
> 
> Of course clicking does not take you to a subscription page for
> public-inbox, even though the two sentences appear to be related.
> 
> Perhaps swap the order of the two, like so, with a bit richer
> explanation taken from Ævar's version:
> 
>   ... disable HTML in your outgoing messages.
> 
>   By subscribing (click here), you can make sure you're not
>   missing follow-up discussion and also learn from other
>   development in the community.  The list archive can be found
>   on public-inbox.

Yeah, I think that's a good suggestion. Do you want to phrase it in the
form of a patch? :)

-Peff


Re: [PATCH v4 00/20] repository object

2017-06-23 Thread Jeff Hostetler



On 6/22/2017 2:43 PM, Brandon Williams wrote:

As before you can find this series at:
https://github.com/bmwill/git/tree/repository-object

Changes in v4:

* Patch 11 is slightly different and turns off all path relocation when a
   worktree is provided instead of just for the index file (Thanks for the help
   Jonathan Nieder).
* 'repo_init()' has a tighter API and now requires that the provided gitdir is
   a path to the gitdir instead of either a path to the gitdir or path to the
   worktree (which has a .git file or directory) (Thanks Jonathan Tan).
* Minor comment and commit message chagnes

Note: Like v3 this series is dependent on on 'bw/config-h' and
   'bw/ls-files-sans-the-index'

Brandon Williams (20):


I read thru the v1 and v4 versions.  Very nice.
And thanks for splitting the earlier parts out
into independent patches.

I didn't have any complaints, but did want to ACK
that I had looked at it.

Jeff



Re: [PATCH -v2] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 04:36:06PM +, Ævar Arnfjörð Bjarmason wrote:

> I believe this addresses the comments in the thread so far. Also Re:
> René's "why const?" in a2673ce4-5cf8-6b40-d4db-8e2a49518...@web.de:
> Because tzname_from_tz isn't changed in the body of the function, only
> read.

Sure, it's not wrong. But that property is also held by 99% of the
parameters that are passed by value. It's the normal style in our code
base (and in most C code bases I know of) to never declare pass-by-value
as const. It pollutes the interface and isn't something the caller cares
about.

Without passing judgement on whether that style is good or not (though
IMHO it is), making this one case different than all the others is a bad
idea. It makes the reader wonder why it's different.

> diff --git a/date.c b/date.c
> index 1fd6d66375..17db07d905 100644
> --- a/date.c
> +++ b/date.c
> @@ -256,7 +256,7 @@ const char *show_date(timestamp_t time, int tz, const 
> struct date_mode *mode)
>   tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
>   else if (mode->type == DATE_STRFTIME)
>   strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
> - mode->local ? NULL : "");
> + mode->local);

You flipped the boolean here. That's OK by me. But in the definition...

>  void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
> -  int tz_offset, const char *tz_name)
> +  int tz_offset, const int tzname_from_tz)

Wouldn't tzname_from_tz only happen when we're _not_ in local mode? I
suggested that name anticipating your second patch to actually compute
it based on "tz". In local-mode it's not coming from tz, it's coming
from secret unportable magic (the combination of localtime() and
strftime()).

> @@ -815,8 +815,7 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, 
> const struct tm *tm,
>   fmt++;
>   break;
>   case 'Z':
> - if (tz_name) {
> - strbuf_addstr(&munged_fmt, tz_name);
> + if (!tzname_from_tz) {
>   fmt++;
>   break;
>   }

This logic matches your inversion in the caller, so it does the right
thing. But I think the name is wrong, as above.

> index 4559035c47..eba5d59a77 100644
> --- a/strbuf.h
> +++ b/strbuf.h
> @@ -340,14 +340,15 @@ extern void strbuf_vaddf(struct strbuf *sb, const char 
> *fmt, va_list ap);
>  
>  /**
>   * Add the time specified by `tm`, as formatted by `strftime`.
> - * `tz_name` is used to expand %Z internally unless it's NULL.
>   * `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
>   * of Greenwich, and it's used to expand %z internally.  However, tokens
>   * with modifiers (e.g. %Ez) are passed to `strftime`.
> + * `tzname_from_tz` when set, means let `strftime` format %Z, instead
> + * of intercepting it and doing our own formatting.
>   */
>  extern void strbuf_addftime(struct strbuf *sb, const char *fmt,
>   const struct tm *tm, int tz_offset,
> - const char *tz_name);
> + const int omit_strftime_tz_name);

This would need the new name, too (whatever it is).

-Peff


Re: [PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 06:23:10PM +0200, René Scharfe wrote:

> > > I have a WIP patch (which may not make it on-list, depending) playing
> > > with the idea I proposed in
> > > CACBZZX5OQc45fUyDVayE89rkT=+8m5s4efsxcabcy7upme5...@mail.gmail.com which
> > > just inserts the custom TZ name based on the offset inside that `if
> > > (omit_strftime_tz_name)` branch.
> > 
> > OK. I'd assumed that would all happen outside of strbuf_addftime(). But
> > if it happens inside, then I agree a flag is better.
> 
> Oh, so the interface that was meant to allow better time zone names
> without having to make strbuf_addftime() even bigger than it already is
> turns out to be too ugly for its purpose?  I'm sorry. :(

I haven't seen Ævar's patch, but I agree that if the caller did:

  if (mode->local)
tzname = NULL; /* let strftime handle it */
  else
tzname = fake_tz_from_offset(tz);
  ...
  strbuf_addftime(&buf, fmt, tm, tz, tzname);

that would be pretty clean (and what I was expecting with the "I'd
assumed" above).

-Peff


[PATCH -v2] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread Ævar Arnfjörð Bjarmason
Change the code for deciding what's to be done about %Z to stop
passing always either a NULL or "" char * to
strbuf_addftime(). Instead pass a boolean int to indicate whether the
strftime() %Z format should be expanded to an empty string, which is
what this code is actually doing.

This code grew organically between the changes in 9eafe86d58 ("Merge
branch 'rs/strbuf-addftime-zZ'", 2017-06-22) yielding an end result
that wasn't very readable.

Out of context it looked as though the call to strbuf_addstr() might
be adding a custom tz_name to the string, but actually tz_name would
always be "", so the call to strbuf_addstr() just to add an empty
string to the format was pointless.

Signed-off-by: Ævar Arnfjörð Bjarmason 
---

I believe this addresses the comments in the thread so far. Also Re:
René's "why const?" in a2673ce4-5cf8-6b40-d4db-8e2a49518...@web.de:
Because tzname_from_tz isn't changed in the body of the function, only
read.

 date.c   | 2 +-
 strbuf.c | 5 ++---
 strbuf.h | 5 +++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/date.c b/date.c
index 1fd6d66375..17db07d905 100644
--- a/date.c
+++ b/date.c
@@ -256,7 +256,7 @@ const char *show_date(timestamp_t time, int tz, const 
struct date_mode *mode)
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
else if (mode->type == DATE_STRFTIME)
strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
-   mode->local ? NULL : "");
+   mode->local);
else
strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
weekday_names[tm->tm_wday],
diff --git a/strbuf.c b/strbuf.c
index be3b9e37b1..92b7bda772 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -786,7 +786,7 @@ char *xstrfmt(const char *fmt, ...)
 }
 
 void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
-int tz_offset, const char *tz_name)
+int tz_offset, const int tzname_from_tz)
 {
struct strbuf munged_fmt = STRBUF_INIT;
size_t hint = 128;
@@ -815,8 +815,7 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, 
const struct tm *tm,
fmt++;
break;
case 'Z':
-   if (tz_name) {
-   strbuf_addstr(&munged_fmt, tz_name);
+   if (!tzname_from_tz) {
fmt++;
break;
}
diff --git a/strbuf.h b/strbuf.h
index 4559035c47..eba5d59a77 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -340,14 +340,15 @@ extern void strbuf_vaddf(struct strbuf *sb, const char 
*fmt, va_list ap);
 
 /**
  * Add the time specified by `tm`, as formatted by `strftime`.
- * `tz_name` is used to expand %Z internally unless it's NULL.
  * `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
  * of Greenwich, and it's used to expand %z internally.  However, tokens
  * with modifiers (e.g. %Ez) are passed to `strftime`.
+ * `tzname_from_tz` when set, means let `strftime` format %Z, instead
+ * of intercepting it and doing our own formatting.
  */
 extern void strbuf_addftime(struct strbuf *sb, const char *fmt,
const struct tm *tm, int tz_offset,
-   const char *tz_name);
+   const int omit_strftime_tz_name);
 
 /**
  * Read a given size of data from a FILE* pointer to the buffer.
-- 
2.13.1.611.g7e3b11ae1



Re: [PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread René Scharfe

Am 23.06.2017 um 17:23 schrieb Jeff King:

On Fri, Jun 23, 2017 at 05:13:38PM +0200, Ævar Arnfjörð Bjarmason wrote:


The idea was that eventually the caller might be able to come up with a
TZ that is not blank, but is also not what strftime("%Z") would produce.
Conceivably that could be done if Git commits carried the "%Z"
information (not likely), or if we used a reverse-lookup table (also not
likely).

This closes the door on that.  Since we don't have immediate plans to go
that route, I'm OK with this patch. It would be easy enough to re-open
the door if we change our minds later.


Closes the door on doing that via passing the char * of the prepared
custom tz_name to strbuf_addftime().

I have a WIP patch (which may not make it on-list, depending) playing
with the idea I proposed in
CACBZZX5OQc45fUyDVayE89rkT=+8m5s4efsxcabcy7upme5...@mail.gmail.com which
just inserts the custom TZ name based on the offset inside that `if
(omit_strftime_tz_name)` branch.


OK. I'd assumed that would all happen outside of strbuf_addftime(). But
if it happens inside, then I agree a flag is better.


Oh, so the interface that was meant to allow better time zone names
without having to make strbuf_addftime() even bigger than it already is
turns out to be too ugly for its purpose?  I'm sorry. :(

René


Re: [PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread René Scharfe

Am 23.06.2017 um 17:25 schrieb Jeff King:

On Fri, Jun 23, 2017 at 05:20:19PM +0200, René Scharfe wrote:


diff --git a/strbuf.c b/strbuf.c
index be3b9e37b1..81ff3570e2 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -786,7 +786,7 @@ char *xstrfmt(const char *fmt, ...)
   }
   void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
-int tz_offset, const char *tz_name)
+int tz_offset, const int omit_strftime_tz_name)


Why const?  And as written above, naming the parameter local would make
it easier to understand instead of exposing an implementation detail in
the interface.


I think calling it "local" isn't right. That's a decision the _caller_
is making about whether to pass through %Z. But the actual
implementation is more like "should the function fill tzname based on
tz?" So some name along those lines would make sense.

In which case the caller would then pass "!mode->local" for the flag.


We only have a single caller currently, so responsibilities can still be
shifted, and it's a bit hard to draw the line.  "Here's a format and all
time information I have, expand!" is just as viable as "here's a format
and most time information, expand, and handle %Z in this particular way
when you see it!", I think.

René


Re: [PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 05:20:19PM +0200, René Scharfe wrote:

> > diff --git a/strbuf.c b/strbuf.c
> > index be3b9e37b1..81ff3570e2 100644
> > --- a/strbuf.c
> > +++ b/strbuf.c
> > @@ -786,7 +786,7 @@ char *xstrfmt(const char *fmt, ...)
> >   }
> >   void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm 
> > *tm,
> > -int tz_offset, const char *tz_name)
> > +int tz_offset, const int omit_strftime_tz_name)
> 
> Why const?  And as written above, naming the parameter local would make
> it easier to understand instead of exposing an implementation detail in
> the interface.

I think calling it "local" isn't right. That's a decision the _caller_
is making about whether to pass through %Z. But the actual
implementation is more like "should the function fill tzname based on
tz?" So some name along those lines would make sense.

In which case the caller would then pass "!mode->local" for the flag.

-Peff


Re: [PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 05:13:38PM +0200, Ævar Arnfjörð Bjarmason wrote:

> > The idea was that eventually the caller might be able to come up with a
> > TZ that is not blank, but is also not what strftime("%Z") would produce.
> > Conceivably that could be done if Git commits carried the "%Z"
> > information (not likely), or if we used a reverse-lookup table (also not
> > likely).
> >
> > This closes the door on that.  Since we don't have immediate plans to go
> > that route, I'm OK with this patch. It would be easy enough to re-open
> > the door if we change our minds later.
> 
> Closes the door on doing that via passing the char * of the prepared
> custom tz_name to strbuf_addftime().
> 
> I have a WIP patch (which may not make it on-list, depending) playing
> with the idea I proposed in
> CACBZZX5OQc45fUyDVayE89rkT=+8m5s4efsxcabcy7upme5...@mail.gmail.com which
> just inserts the custom TZ name based on the offset inside that `if
> (omit_strftime_tz_name)` branch.

OK. I'd assumed that would all happen outside of strbuf_addftime(). But
if it happens inside, then I agree a flag is better.

> >>   * Add the time specified by `tm`, as formatted by `strftime`.
> >> - * `tz_name` is used to expand %Z internally unless it's NULL.
> >>   * `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
> >>   * of Greenwich, and it's used to expand %z internally.  However, tokens
> >>   * with modifiers (e.g. %Ez) are passed to `strftime`.
> >> + * `omit_strftime_tz_name` when set, means don't let `strftime` format
> >> + * %Z, instead do our own formatting.
> >
> > Since we now always turn it into a blank string, perhaps "do our own
> > formatting" could be more descriptive: we convert it into the empty
> > string.
> 
> Then we'd need to change this comment again if we had some patch like
> the one I mentioned above, I thought it was better to just leave this
> vague enough that we didn't need to do that.

Right, if you're going to do your own formatting inside the function,
then I agree the wording should be kept. But then "omit" is not really
the right word. Isn't it "tzname_from_tz" or something?

-Peff


Re: [PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread René Scharfe

Am 23.06.2017 um 16:46 schrieb Ævar Arnfjörð Bjarmason:

Change the code for deciding what's to be done about %Z to stop
passing always either a NULL or "" char * to
strbuf_addftime(). Instead pass a boolean int to indicate whether the
strftime() %Z format should be omitted, which is what this code is
actually doing.


"Omitting" sounds not quite right somehow.  We expand %Z to the empty
string because that's the best we can do -- which amounts to a removal,
but that's not the intent, just an implementation detail.  Calling it
"handling %Z internally" would be better, I think.


This code grew organically between the changes in 9eafe86d58 ("Merge
branch 'rs/strbuf-addftime-zZ'", 2017-06-22) yielding an end result
that wasn't very readable. Out of context it looked as though the call
to strbuf_addstr() might be adding a custom tz_name to the string, but
actually tz_name would always be "", so the call to strbuf_addstr()
just to add an empty string to the format was pointless.

Signed-off-by: Ævar Arnfjörð Bjarmason 
---
  date.c   | 2 +-
  strbuf.c | 5 ++---
  strbuf.h | 5 +++--
  3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/date.c b/date.c
index 1fd6d66375..5f09743bad 100644
--- a/date.c
+++ b/date.c
@@ -256,7 +256,7 @@ const char *show_date(timestamp_t time, int tz, const 
struct date_mode *mode)
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
else if (mode->type == DATE_STRFTIME)
strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
-   mode->local ? NULL : "");
+   mode->local ? 0 : 1);


I don't see how this is more readable -- both look about equally ugly to
me.  Passing mode->local unchanged would be better.


else
strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
weekday_names[tm->tm_wday],
diff --git a/strbuf.c b/strbuf.c
index be3b9e37b1..81ff3570e2 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -786,7 +786,7 @@ char *xstrfmt(const char *fmt, ...)
  }
  
  void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,

-int tz_offset, const char *tz_name)
+int tz_offset, const int omit_strftime_tz_name)


Why const?  And as written above, naming the parameter local would make
it easier to understand instead of exposing an implementation detail in
the interface.


  {
struct strbuf munged_fmt = STRBUF_INIT;
size_t hint = 128;
@@ -815,8 +815,7 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, 
const struct tm *tm,
fmt++;
break;
case 'Z':
-   if (tz_name) {
-   strbuf_addstr(&munged_fmt, tz_name);
+   if (omit_strftime_tz_name) {


Getting rid of this strbuf_addstr call is nice, but as Peff mentioned in
his reply it also reduces the flexibility of the function.  While it's
unlikely to be needed I'm not convinced that we should already block
this path (even though it could be easily reopened).


fmt++;
break;
}
diff --git a/strbuf.h b/strbuf.h
index 4559035c47..bad698058a 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -340,14 +340,15 @@ extern void strbuf_vaddf(struct strbuf *sb, const char 
*fmt, va_list ap);
  
  /**

   * Add the time specified by `tm`, as formatted by `strftime`.
- * `tz_name` is used to expand %Z internally unless it's NULL.
   * `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
   * of Greenwich, and it's used to expand %z internally.  However, tokens
   * with modifiers (e.g. %Ez) are passed to `strftime`.
+ * `omit_strftime_tz_name` when set, means don't let `strftime` format
+ * %Z, instead do our own formatting.
   */
  extern void strbuf_addftime(struct strbuf *sb, const char *fmt,
const struct tm *tm, int tz_offset,
-   const char *tz_name);
+   const int omit_strftime_tz_name);
  
  /**

   * Read a given size of data from a FILE* pointer to the buffer.



[PATCH v2 2/3] t1301: move modebits() to test-lib-functions.sh

2017-06-23 Thread Christian Couder
As the modebits() function can be useful outside t1301,
let's move it into test-lib-functions.sh, and while at
it let's rename it test_modebits().

Signed-off-by: Christian Couder 
---
 t/t1301-shared-repo.sh  | 18 +++---
 t/test-lib-functions.sh |  5 +
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index 1312004f8c..dfece751b5 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -19,10 +19,6 @@ test_expect_success 'shared = 0400 (faulty permission u-w)' '
)
 '
 
-modebits () {
-   ls -l "$1" | sed -e 's|^\(..\).*|\1|'
-}
-
 for u in 002 022
 do
test_expect_success POSIXPERM "shared=1 does not clear bits preset by 
umask $u" '
@@ -88,7 +84,7 @@ do
 
rm -f .git/info/refs &&
git update-server-info &&
-   actual="$(modebits .git/info/refs)" &&
+   actual="$(test_modebits .git/info/refs)" &&
verbose test "x$actual" = "x-$y"
 
'
@@ -98,7 +94,7 @@ do
 
rm -f .git/info/refs &&
git update-server-info &&
-   actual="$(modebits .git/info/refs)" &&
+   actual="$(test_modebits .git/info/refs)" &&
verbose test "x$actual" = "x-$x"
 
'
@@ -111,7 +107,7 @@ test_expect_success POSIXPERM 'info/refs respects umask in 
unshared repo' '
umask 002 &&
git update-server-info &&
echo "-rw-rw-r--" >expect &&
-   modebits .git/info/refs >actual &&
+   test_modebits .git/info/refs >actual &&
test_cmp expect actual
 '
 
@@ -177,7 +173,7 @@ test_expect_success POSIXPERM 'remote init does not use 
config from cwd' '
umask 0022 &&
git init --bare child.git &&
echo "-rw-r--r--" >expect &&
-   modebits child.git/config >actual &&
+   test_modebits child.git/config >actual &&
test_cmp expect actual
 '
 
@@ -187,7 +183,7 @@ test_expect_success POSIXPERM 're-init respects 
core.sharedrepository (local)' '
echo whatever >templates/foo &&
git init --template=templates &&
echo "-rw-rw-rw-" >expect &&
-   modebits .git/foo >actual &&
+   test_modebits .git/foo >actual &&
test_cmp expect actual
 '
 
@@ -198,7 +194,7 @@ test_expect_success POSIXPERM 're-init respects 
core.sharedrepository (remote)'
test_path_is_missing child.git/foo &&
git init --bare --template=../templates child.git &&
echo "-rw-rw-rw-" >expect &&
-   modebits child.git/foo >actual &&
+   test_modebits child.git/foo >actual &&
test_cmp expect actual
 '
 
@@ -209,7 +205,7 @@ test_expect_success POSIXPERM 'template can set 
core.sharedrepository' '
cp .git/config templates/config &&
git init --bare --template=../templates child.git &&
echo "-rw-rw-rw-" >expect &&
-   modebits child.git/HEAD >actual &&
+   test_modebits child.git/HEAD >actual &&
test_cmp expect actual
 '
 
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 5ee124332a..db622c3555 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -216,6 +216,11 @@ test_chmod () {
git update-index --add "--chmod=$@"
 }
 
+# Get the modebits from a file.
+test_modebits () {
+   ls -l "$1" | sed -e 's|^\(..\).*|\1|'
+}
+
 # Unset a configuration variable, but don't fail if it doesn't exist.
 test_unconfig () {
config_dir=
-- 
2.13.1.519.g0a0746bea4



[PATCH v2 3/3] t1700: make sure split-index respects core.sharedrepository

2017-06-23 Thread Christian Couder
Add a few tests to check that both the split-index file and the
shared-index file are created using the right permissions when
core.sharedrepository is set.

Signed-off-by: Christian Couder 
---
 t/t1700-split-index.sh | 17 +
 1 file changed, 17 insertions(+)

diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
index af3ec0da5a..2c5be732e4 100755
--- a/t/t1700-split-index.sh
+++ b/t/t1700-split-index.sh
@@ -370,4 +370,21 @@ test_expect_success 'check splitIndex.sharedIndexExpire 
set to "never" and "now"
test $(ls .git/sharedindex.* | wc -l) -le 2
 '
 
+while read -r mode modebits filename; do
+   test_expect_success POSIXPERM "split index respects 
core.sharedrepository $mode" '
+   git config core.sharedrepository "$mode" &&
+   : >"$filename" &&
+   git update-index --add "$filename" &&
+   echo "$modebits" >expect &&
+   test_modebits .git/index >actual &&
+   test_cmp expect actual &&
+   newest_shared_index=$(ls -t .git/sharedindex.* | head -1) &&
+   test_modebits "$newest_shared_index" >actual &&
+   test_cmp expect actual
+   '
+done <<\EOF
+0666 -rw-rw-rw- seventeen
+0642 -rw-r---w- eightteen
+EOF
+
 test_done
-- 
2.13.1.519.g0a0746bea4



[PATCH v2 1/3] read-cache: use shared perms when writing shared index

2017-06-23 Thread Christian Couder
Since f6ecc62dbf (write_shared_index(): use tempfile module, 2015-08-10)
write_shared_index() has been using mks_tempfile() to create the
temporary file that will become the shared index.

But even before that, it looks like the functions used to create this
file didn't call adjust_shared_perm(), which means that the shared
index file has always been created with 600 permissions regardless
of the shared permission settings.

Because of that, on repositories created with `git init --shared=all`
and using the split index feature, one gets an error like:

fatal: .git/sharedindex.a52f910b489bc462f187ab572ba0086f7b5157de: index file 
open failed: Permission denied

when another user performs any operation that reads the shared index.

We could use create_tempfile() that calls adjust_shared_perm(), but
unfortunately create_tempfile() doesn't replace the XX at the end
of the path it is passed. So let's just call adjust_shared_perm() by
ourselves.

Signed-off-by: Christian Couder 
---
 read-cache.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/read-cache.c b/read-cache.c
index bc156a133e..66f85f8d58 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -2425,6 +2425,14 @@ static int write_shared_index(struct index_state *istate,
delete_tempfile(&temporary_sharedindex);
return ret;
}
+   ret = adjust_shared_perm(temporary_sharedindex.filename.buf);
+   if (ret) {
+   int save_errno = errno;
+   error("cannot fix permission bits on %s", 
temporary_sharedindex.filename.buf);
+   delete_tempfile(&temporary_sharedindex);
+   errno = save_errno;
+   return ret;
+   }
ret = rename_tempfile(&temporary_sharedindex,
  git_path("sharedindex.%s", 
sha1_to_hex(si->base->sha1)));
if (!ret) {
-- 
2.13.1.519.g0a0746bea4



Re: [PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread Ævar Arnfjörð Bjarmason

On Fri, Jun 23 2017, Jeff King jotted:

> On Fri, Jun 23, 2017 at 02:46:03PM +, Ævar Arnfjörð Bjarmason wrote:
>
>> Change the code for deciding what's to be done about %Z to stop
>> passing always either a NULL or "" char * to
>> strbuf_addftime(). Instead pass a boolean int to indicate whether the
>> strftime() %Z format should be omitted, which is what this code is
>> actually doing.
>>
>> This code grew organically between the changes in 9eafe86d58 ("Merge
>> branch 'rs/strbuf-addftime-zZ'", 2017-06-22) yielding an end result
>> that wasn't very readable. Out of context it looked as though the call
>> to strbuf_addstr() might be adding a custom tz_name to the string, but
>> actually tz_name would always be "", so the call to strbuf_addstr()
>> just to add an empty string to the format was pointless.
>
> The idea was that eventually the caller might be able to come up with a
> TZ that is not blank, but is also not what strftime("%Z") would produce.
> Conceivably that could be done if Git commits carried the "%Z"
> information (not likely), or if we used a reverse-lookup table (also not
> likely).
>
> This closes the door on that.  Since we don't have immediate plans to go
> that route, I'm OK with this patch. It would be easy enough to re-open
> the door if we change our minds later.

Closes the door on doing that via passing the char * of the prepared
custom tz_name to strbuf_addftime().

I have a WIP patch (which may not make it on-list, depending) playing
with the idea I proposed in
CACBZZX5OQc45fUyDVayE89rkT=+8m5s4efsxcabcy7upme5...@mail.gmail.com which
just inserts the custom TZ name based on the offset inside that `if
(omit_strftime_tz_name)` branch.

That seems like a more straightforward way to do it than passing the
name to strbuf_addftime().

>>  /**
>>   * Add the time specified by `tm`, as formatted by `strftime`.
>> - * `tz_name` is used to expand %Z internally unless it's NULL.
>>   * `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
>>   * of Greenwich, and it's used to expand %z internally.  However, tokens
>>   * with modifiers (e.g. %Ez) are passed to `strftime`.
>> + * `omit_strftime_tz_name` when set, means don't let `strftime` format
>> + * %Z, instead do our own formatting.
>
> Since we now always turn it into a blank string, perhaps "do our own
> formatting" could be more descriptive: we convert it into the empty
> string.

Then we'd need to change this comment again if we had some patch like
the one I mentioned above, I thought it was better to just leave this
vague enough that we didn't need to do that.


Re: [PATCH 1/3] read-cache: use shared perms when writing shared index

2017-06-23 Thread Christian Couder
On Thu, Jun 22, 2017 at 9:51 PM, Junio C Hamano  wrote:
> Christian Couder  writes:

>> Let's fix that by using create_tempfile() instead of mks_tempfile()
>> to create the shared index file.
>>
>> ...
>> - fd = mks_tempfile(&temporary_sharedindex, 
>> git_path("sharedindex_XX"));
>> + fd = create_tempfile(&temporary_sharedindex, 
>> git_path("sharedindex_XX"));
>
> So we used to create a temporary file that made sure its name is
> unique but now we create sharedindex_XX with 6 X's literally
> at the end?
>
> Doesn't mks_tempfile() family include a variant where you can give
> custom mode?  Better yet, perhaps you can call adjust_shared_perm()
> on the path _after_ seeing that mks_tempfile() succeeds (you can ask
> get_tempfile_path() which path to adjust, I presume)?

Yeah, adjust_shared_perm() is called after mks_tempfile() succeeds, in
the next version.


Re: [PATCH 2/3] t1301: move movebits() to test-lib-functions.sh

2017-06-23 Thread Christian Couder
On Fri, Jun 23, 2017 at 1:09 AM, Ramsay Jones
 wrote:
>
>
> On 22/06/17 20:52, Junio C Hamano wrote:
>> Christian Couder  writes:
>>
>>> As the movebits() function can be useful outside t1301,
>>> let's move it into test-lib-functions.sh, and while at
>>> it let's rename it test_movebits().
>>
>> Good thinking, especially on the renaming.
>
> Err, except for the commit message! :-D
>
> Both the commit message subject and the commit message body
> refer to _move_bits() rather than _mode_bits() etc.
> (So, three instances of s/move/mode/).

Yeah, sorry about that. This is fixed in the version I will send
really soon now.


Re: [PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread Jeff King
On Fri, Jun 23, 2017 at 02:46:03PM +, Ævar Arnfjörð Bjarmason wrote:

> Change the code for deciding what's to be done about %Z to stop
> passing always either a NULL or "" char * to
> strbuf_addftime(). Instead pass a boolean int to indicate whether the
> strftime() %Z format should be omitted, which is what this code is
> actually doing.
> 
> This code grew organically between the changes in 9eafe86d58 ("Merge
> branch 'rs/strbuf-addftime-zZ'", 2017-06-22) yielding an end result
> that wasn't very readable. Out of context it looked as though the call
> to strbuf_addstr() might be adding a custom tz_name to the string, but
> actually tz_name would always be "", so the call to strbuf_addstr()
> just to add an empty string to the format was pointless.

The idea was that eventually the caller might be able to come up with a
TZ that is not blank, but is also not what strftime("%Z") would produce.
Conceivably that could be done if Git commits carried the "%Z"
information (not likely), or if we used a reverse-lookup table (also not
likely).

This closes the door on that.  Since we don't have immediate plans to go
that route, I'm OK with this patch. It would be easy enough to re-open
the door if we change our minds later.

>  /**
>   * Add the time specified by `tm`, as formatted by `strftime`.
> - * `tz_name` is used to expand %Z internally unless it's NULL.
>   * `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
>   * of Greenwich, and it's used to expand %z internally.  However, tokens
>   * with modifiers (e.g. %Ez) are passed to `strftime`.
> + * `omit_strftime_tz_name` when set, means don't let `strftime` format
> + * %Z, instead do our own formatting.

Since we now always turn it into a blank string, perhaps "do our own
formatting" could be more descriptive: we convert it into the empty
string.

-Peff


[PATCH] strbuf: change an always NULL/"" strbuf_addftime() param to bool

2017-06-23 Thread Ævar Arnfjörð Bjarmason
Change the code for deciding what's to be done about %Z to stop
passing always either a NULL or "" char * to
strbuf_addftime(). Instead pass a boolean int to indicate whether the
strftime() %Z format should be omitted, which is what this code is
actually doing.

This code grew organically between the changes in 9eafe86d58 ("Merge
branch 'rs/strbuf-addftime-zZ'", 2017-06-22) yielding an end result
that wasn't very readable. Out of context it looked as though the call
to strbuf_addstr() might be adding a custom tz_name to the string, but
actually tz_name would always be "", so the call to strbuf_addstr()
just to add an empty string to the format was pointless.

Signed-off-by: Ævar Arnfjörð Bjarmason 
---
 date.c   | 2 +-
 strbuf.c | 5 ++---
 strbuf.h | 5 +++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/date.c b/date.c
index 1fd6d66375..5f09743bad 100644
--- a/date.c
+++ b/date.c
@@ -256,7 +256,7 @@ const char *show_date(timestamp_t time, int tz, const 
struct date_mode *mode)
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
else if (mode->type == DATE_STRFTIME)
strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
-   mode->local ? NULL : "");
+   mode->local ? 0 : 1);
else
strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
weekday_names[tm->tm_wday],
diff --git a/strbuf.c b/strbuf.c
index be3b9e37b1..81ff3570e2 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -786,7 +786,7 @@ char *xstrfmt(const char *fmt, ...)
 }
 
 void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
-int tz_offset, const char *tz_name)
+int tz_offset, const int omit_strftime_tz_name)
 {
struct strbuf munged_fmt = STRBUF_INIT;
size_t hint = 128;
@@ -815,8 +815,7 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, 
const struct tm *tm,
fmt++;
break;
case 'Z':
-   if (tz_name) {
-   strbuf_addstr(&munged_fmt, tz_name);
+   if (omit_strftime_tz_name) {
fmt++;
break;
}
diff --git a/strbuf.h b/strbuf.h
index 4559035c47..bad698058a 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -340,14 +340,15 @@ extern void strbuf_vaddf(struct strbuf *sb, const char 
*fmt, va_list ap);
 
 /**
  * Add the time specified by `tm`, as formatted by `strftime`.
- * `tz_name` is used to expand %Z internally unless it's NULL.
  * `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
  * of Greenwich, and it's used to expand %z internally.  However, tokens
  * with modifiers (e.g. %Ez) are passed to `strftime`.
+ * `omit_strftime_tz_name` when set, means don't let `strftime` format
+ * %Z, instead do our own formatting.
  */
 extern void strbuf_addftime(struct strbuf *sb, const char *fmt,
const struct tm *tm, int tz_offset,
-   const char *tz_name);
+   const int omit_strftime_tz_name);
 
 /**
  * Read a given size of data from a FILE* pointer to the buffer.
-- 
2.13.1.611.g7e3b11ae1



Re: [RFC PATCH] proposal for refs/tracking/* hierarchy

2017-06-23 Thread Jacob Keller
On Fri, Jun 23, 2017 at 6:52 AM, Jacob Keller  wrote:
> From: Jacob Keller 
>
> Historically, git has tracked the status of remote branches (heads) in
> refs/remotes//*. This is necessary and useful as it allows users
> to track the difference between their local work and the last known
> status of the remote work.
>
> Unfortunately this hierarchy is limited in that it only tracks branches.
> Additionally, it is not feasible to extend it directly, because the
> layout would become ambiguous. For example, if a user happened to have
> a local branch named "notes" it could be confusing if you tried to add
> "refs/remotes/origin/notes/ with the already existing refs/remotes/origin/notes branch that existed.
>
> Instead, lets add support for a new refs/tracking/* hierarchy which is
> laid out in such a way to avoid this inconsistency. All refs in
> "refs/tracking//*" will include the complete ref, such that
> dropping the "tracking/" part will give the exact ref name as it
> is found in the upstream. Thus, we can track any ref here by simply
> fetching it into refs/tracking//*.
>
> Add support to tell a new remote to start tracking remote hierarchies
> via "--follow" which will track all refs under that section, ie:
>
> git remote add --follow notes origin  will cause
>
> +refs/notes/*:refs/tracking/origin/notes/* to be added as a fetch
> refspec for this remote.
>
> This ensures that any future refs which want a method of sharing the
> current remote status separate from local status could use
> refs/tracking
>
> A long term goal might be to deprecate refs/remotes/ in favor of
> refs/tracking (possibly adding in magic to convert refs/remotes directly
> into refs/tracking so that old stuff still works?).
>
> Things not yet thought through:
>
> 1) maybe we should create a configurable default so that some known set
>of default refs get pulled (ie: notes, grafts, replace, etc?)
>Possibly with some sort of easy way to add or subtract from the list
>in config...
>
> 2) so far, there's no work done to figure out how to remove
>refs/tracking when a remote is dropped. I *think* we can just delete
>all refs under refs/tracking/ but I'm not completely certain
>
> 3) adding magic to complete refs under tracking, such as for git-notes
>or similar may wish to understand shorthand for referencing the
>remote version of notes
>
> 4) adding support for clone.. (this is weird because git-clone and
>git-remote don't both use the same flow for setup.. oops??)
>
> 5) tests, documentation etc. (This is primarily an RFC, with the goal of
>providing a known location for remote references such as notes to
>reside)
>
> 6) we probably want to enable notes and grafts and other similar things
>to use the remote tracking data if its available.
>
> 7) what about tags? Currently we fetch all tags into refs/tags directly,
>which is a bit awkward, if for example you create a local tag and
>a remote creates a tag with the same name, you simply don't get that
>new version. This is good, but now you have no idea how to tell if
>your tags are out of date or not. refs/tracking can partially resolve
>this since remote tags will always be "exactly" what the remote has.
>Unfortunately, I don't know how we'd resolve them into local tags...
>

Oops:

8) if we decided to go with "all refs always get tracked in
refs/tracking" we probably want to either add a way to say "all refs
except refs/tracking ones" or we want a way for servers to (by
default) not advertise refs/tracking when clients fetch from them.
That's partially why I went with the easier "only some hierarchies
will get pulled by default" Otherwise, two remotes that fetch from
each other could create a never ending cycle of
refs/tracking/origin/tracking/origin/tracking/origin/ adding a new
layer every time they fetched.

Thanks,
Jake


[RFC PATCH] proposal for refs/tracking/* hierarchy

2017-06-23 Thread Jacob Keller
From: Jacob Keller 

Historically, git has tracked the status of remote branches (heads) in
refs/remotes//*. This is necessary and useful as it allows users
to track the difference between their local work and the last known
status of the remote work.

Unfortunately this hierarchy is limited in that it only tracks branches.
Additionally, it is not feasible to extend it directly, because the
layout would become ambiguous. For example, if a user happened to have
a local branch named "notes" it could be confusing if you tried to add
"refs/remotes/origin/notes//*" will include the complete ref, such that
dropping the "tracking/" part will give the exact ref name as it
is found in the upstream. Thus, we can track any ref here by simply
fetching it into refs/tracking//*.

Add support to tell a new remote to start tracking remote hierarchies
via "--follow" which will track all refs under that section, ie:

git remote add --follow notes origin  will cause

+refs/notes/*:refs/tracking/origin/notes/* to be added as a fetch
refspec for this remote.

This ensures that any future refs which want a method of sharing the
current remote status separate from local status could use
refs/tracking

A long term goal might be to deprecate refs/remotes/ in favor of
refs/tracking (possibly adding in magic to convert refs/remotes directly
into refs/tracking so that old stuff still works?).

Things not yet thought through:

1) maybe we should create a configurable default so that some known set
   of default refs get pulled (ie: notes, grafts, replace, etc?)
   Possibly with some sort of easy way to add or subtract from the list
   in config...

2) so far, there's no work done to figure out how to remove
   refs/tracking when a remote is dropped. I *think* we can just delete
   all refs under refs/tracking/ but I'm not completely certain

3) adding magic to complete refs under tracking, such as for git-notes
   or similar may wish to understand shorthand for referencing the
   remote version of notes

4) adding support for clone.. (this is weird because git-clone and
   git-remote don't both use the same flow for setup.. oops??)

5) tests, documentation etc. (This is primarily an RFC, with the goal of
   providing a known location for remote references such as notes to
   reside)

6) we probably want to enable notes and grafts and other similar things
   to use the remote tracking data if its available.

7) what about tags? Currently we fetch all tags into refs/tags directly,
   which is a bit awkward, if for example you create a local tag and
   a remote creates a tag with the same name, you simply don't get that
   new version. This is good, but now you have no idea how to tell if
   your tags are out of date or not. refs/tracking can partially resolve
   this since remote tags will always be "exactly" what the remote has.
   Unfortunately, I don't know how we'd resolve them into local tags...

Probably other things missing too...

Signed-off-by: Jacob Keller 
---
 builtin/remote.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/builtin/remote.c b/builtin/remote.c
index f1a88fe26589..dffe3892be11 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -122,6 +122,16 @@ static void add_branch(const char *key, const char 
*branchname,
git_config_set_multivar(key, tmp->buf, "^$", 0);
 }
 
+static void add_tracking(const char *key, const char *namespace,
+const char *remotename, struct strbuf *tmp)
+{
+   strbuf_reset(tmp);
+   strbuf_addch(tmp, '+');
+   strbuf_addf(tmp, "refs/%s/*:refs/tracking/%s/%s/*",
+   namespace, remotename, namespace);
+   git_config_set_multivar(key, tmp->buf, "^$", 0);
+}
+
 static const char mirror_advice[] =
 N_("--mirror is dangerous and deprecated; please\n"
"\t use --mirror=fetch or --mirror=push instead");
@@ -149,6 +159,7 @@ static int add(int argc, const char **argv)
int fetch = 0, fetch_tags = TAGS_DEFAULT;
unsigned mirror = MIRROR_NONE;
struct string_list track = STRING_LIST_INIT_NODUP;
+   struct string_list follow = STRING_LIST_INIT_NODUP;
const char *master = NULL;
struct remote *remote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
@@ -164,6 +175,8 @@ static int add(int argc, const char **argv)
N_("or do not fetch any tag at all (--no-tags)"), 
TAGS_UNSET),
OPT_STRING_LIST('t', "track", &track, N_("branch"),
N_("branch(es) to track")),
+   OPT_STRING_LIST(0, "follow", &follow, N_("namespace"),
+   N_("refs namespaces to follow in 
refs/tracking")),
OPT_STRING('m', "master", &master, N_("branch"), N_("master 
branch")),
{ OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"),
N_("set up remote as a mirror to push to or fetch 
from"),
@@ -207,6 +220,11 @@ static int add(int a

[PATCH] xdiff: trim common tail with -U0 after diff

2017-06-23 Thread Daniel Hahler
When -U0 is used, trim_common_tail should be called after `xdl_diff`, so
that `--indent-heuristic` (and other diff processing) works as expected.

It also removes the check for `!(xecfg->flags & XDL_EMIT_FUNCCONTEXT)`
added in e0876bca4, which does not appear to be necessary anymore after
moving the trimming down.

This only adds a test to t4061-diff-indent.sh, but should also have one for
normal (i.e. non-experimental) diff mode probably?!

Ref: https://github.com/tomtom/quickfixsigns_vim/issues/74#issue-237900460
---
 t/t4061-diff-indent.sh | 15 +++
 xdiff-interface.c  |  7 ---
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/t/t4061-diff-indent.sh b/t/t4061-diff-indent.sh
index 2affd7a10..df3151393 100755
--- a/t/t4061-diff-indent.sh
+++ b/t/t4061-diff-indent.sh
@@ -116,6 +116,16 @@ test_expect_success 'prepare' '
 4
EOF
 
+   cat <<-\EOF >spaces-compacted-U0-expect &&
+   diff --git a/spaces.txt b/spaces.txt
+   --- a/spaces.txt
+   +++ b/spaces.txt
+   @@ -4,0 +5,3 @@ a
+   +b
+   +a
+   +
+   EOF
+
tr "_" " " <<-\EOF >functions-expect &&
diff --git a/functions.c b/functions.c
--- a/functions.c
@@ -184,6 +194,11 @@ test_expect_success 'diff: --indent-heuristic with 
--histogram' '
compare_diff spaces-compacted-expect out-compacted4
 '
 
+test_expect_success 'diff: --indent-heuristic with -U0' '
+   git diff -U0 --indent-heuristic old new -- spaces.txt >out-compacted5 &&
+   compare_diff spaces-compacted-U0-expect out-compacted5
+'
+
 test_expect_success 'diff: ugly functions' '
git diff --no-indent-heuristic old new -- functions.c >out &&
compare_diff functions-expect out
diff --git a/xdiff-interface.c b/xdiff-interface.c
index d3f78ca2a..a7e0e3583 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -125,16 +125,17 @@ static void trim_common_tail(mmfile_t *a, mmfile_t *b)
 
 int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t 
const *xecfg, xdemitcb_t *xecb)
 {
+   int ret;
mmfile_t a = *mf1;
mmfile_t b = *mf2;
 
if (mf1->size > MAX_XDIFF_SIZE || mf2->size > MAX_XDIFF_SIZE)
return -1;
 
-   if (!xecfg->ctxlen && !(xecfg->flags & XDL_EMIT_FUNCCONTEXT))
+   ret = xdl_diff(&a, &b, xpp, xecfg, xecb);
+   if (ret && !xecfg->ctxlen)
trim_common_tail(&a, &b);
-
-   return xdl_diff(&a, &b, xpp, xecfg, xecb);
+   return ret;
 }
 
 int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
-- 
2.13.1



Re: [PATCH v3 0/4] Add regression tests for recent rebase -i fixes

2017-06-23 Thread Phillip Wood
On 23/06/17 06:07, Junio C Hamano wrote:
> Junio C Hamano  writes:
> 
>>>  git-rebase.sh |   4 +-
>>>  sequencer.c   |  11 ++--
>>>  t/t3404-rebase-interactive.sh |   7 +++
>>>  t/t3420-rebase-autostash.sh   | 136 
>>> --
>>>  4 files changed, 147 insertions(+), 11 deletions(-)
>>
>> I've merged this to 'next' but I probably shouldn't have before
>> making sure that Travis tests passes 'pu' while this was still in
>> there.  
>>
>> At least t3420 seems to fail under GETTEXT_POISON build.
>>
>>   https://travis-ci.org/git/git/jobs/245990993
> 
> This should be sufficient to make t3420 pass.  It seems that t3404
> is also broken under GETTEXT_POISON build, but I won't have time to
> look at it, at least tonight.
> 
> $ make GETTEXT_POISON=YesPlease
> $ cd t && sh ./t3404-*.sh -i -v
> 
> to see how it breaks.

t3404 passes for me,
$ make GETTEXT_POISON=YesPlease
$ cd t &&sh t3404-rebase-interactive.sh -i -v
...
# still have 1 known breakage(s)
# passed all remaining 95 test(s)
1..96

Also as far as I can see it passes on travis -
https://travis-ci.org/git/git/jobs/245990993#L910 have I missed
something? Do you want me to submit a fixup patch for t3420 or have you
got one already?

Thanks

Phillip

> Thanks.
> 
>  t/t3420-rebase-autostash.sh | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh
> index 6826c38cbd..e243700660 100755
> --- a/t/t3420-rebase-autostash.sh
> +++ b/t/t3420-rebase-autostash.sh
> @@ -178,7 +178,7 @@ testrebase () {
>   test_when_finished git branch -D rebased-feature-branch &&
>   suffix=${type#\ --} && suffix=${suffix:-am} &&
>   create_expected_success_$suffix &&
> - test_cmp expected actual
> + test_i18ncmp expected actual
>   '
>  
>   test_expect_success "rebase$type: dirty index, non-conflicting rebase" '
> @@ -275,7 +275,7 @@ testrebase () {
>   test_when_finished git branch -D rebased-feature-branch &&
>   suffix=${type#\ --} && suffix=${suffix:-am} &&
>   create_expected_failure_$suffix &&
> - test_cmp expected actual
> + test_i18ncmp expected actual
>   '
>  }
>  
> 



Re: What's cooking in git.git (Jun 2017, #06; Thu, 22)

2017-06-23 Thread Lars Schneider

> On 23 Jun 2017, at 00:35, Junio C Hamano  wrote:
> 
> Here are the topics that have been cooking.  Commits prefixed with
> '-' are only in 'pu' (proposed updates) while commits prefixed with
> '+' are in 'next'.  The ones marked with '.' do not appear in any of
> the integration branches, but I am still holding onto them.
> 
> You can find the changes described here in the integration branches
> of the repositories listed at
> 
>http://git-blame.blogspot.com/p/git-public-repositories.html
> 
> --
> 
...

> 
> * ls/filter-process-delayed (2017-06-01) 5 commits
> - convert: add "status=delayed" to filter process protocol
> - convert: move multiple file filter error handling to separate function
> - t0021: write "OUT" only on success
> - t0021: make debug log file name configurable
> - t0021: keep filter log files on comparison
> 
> The filter-process interface learned to allow a process with long
> latency give a "delayed" response.
> 
> Needs review.

I am still desperately looking for reviewers!
It would be awesome if this feature would have a chance 
to go into 2.14 :-)


> * pw/rebase-i-regression-fix-tests (2017-06-19) 4 commits
>  (merged to 'next' on 2017-06-22 at d1dde1672a)
> + rebase: add more regression tests for console output
> + rebase: add regression tests for console output
> + rebase -i: add test for reflog message
> + sequencer: print autostash messages to stderr
> 
> Fix a recent regression to "git rebase -i" and add tests that would
> have caught it and others.
> 
> Will merge to 'master'.

I think this series breaks t3420-rebase-autostash.sh 
with GETTEXT_POISON=YesPlease

See: https://travis-ci.org/git/git/jobs/245990993


- Lars



[PATCH v2 25/29] packed_refs_unlock(), packed_refs_is_locked(): new functions

2017-06-23 Thread Michael Haggerty
Add two new public functions, `packed_refs_unlock()` and
`packed_refs_is_locked()`, with which callers can manage and query the
`packed-refs` lock externally.

Call `packed_refs_unlock()` from `commit_packed_refs()` and
`rollback_packed_refs()`.

Signed-off-by: Michael Haggerty 
---
 refs/packed-backend.c | 31 +--
 refs/packed-backend.h |  3 +++
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 78e877a9e3..f27943f9a1 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -563,6 +563,29 @@ int packed_refs_lock(struct ref_store *ref_store, int 
flags, struct strbuf *err)
return 0;
 }
 
+void packed_refs_unlock(struct ref_store *ref_store)
+{
+   struct packed_ref_store *refs = packed_downcast(
+   ref_store,
+   REF_STORE_READ | REF_STORE_WRITE,
+   "packed_refs_unlock");
+
+   if (!is_lock_file_locked(&refs->lock))
+   die("BUG: packed_refs_unlock() called when not locked");
+   rollback_lock_file(&refs->lock);
+   release_packed_ref_cache(refs->cache);
+}
+
+int packed_refs_is_locked(struct ref_store *ref_store)
+{
+   struct packed_ref_store *refs = packed_downcast(
+   ref_store,
+   REF_STORE_READ | REF_STORE_WRITE,
+   "packed_refs_is_locked");
+
+   return is_lock_file_locked(&refs->lock);
+}
+
 /*
  * The packed-refs header line that we write out.  Perhaps other
  * traits will be added later.  The trailing space is required.
@@ -649,8 +672,7 @@ int commit_packed_refs(struct ref_store *ref_store, struct 
strbuf *err)
delete_tempfile(&refs->tempfile);
 
 out:
-   rollback_lock_file(&refs->lock);
-   release_packed_ref_cache(packed_ref_cache);
+   packed_refs_unlock(ref_store);
return ret;
 }
 
@@ -661,14 +683,11 @@ int commit_packed_refs(struct ref_store *ref_store, 
struct strbuf *err)
  */
 static void rollback_packed_refs(struct packed_ref_store *refs)
 {
-   struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs);
-
packed_assert_main_repository(refs, "rollback_packed_refs");
 
if (!is_lock_file_locked(&refs->lock))
die("BUG: packed-refs not locked");
-   rollback_lock_file(&refs->lock);
-   release_packed_ref_cache(packed_ref_cache);
+   packed_refs_unlock(&refs->base);
clear_packed_ref_cache(refs);
 }
 
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
index 210e3f35ce..03b7c1de95 100644
--- a/refs/packed-backend.h
+++ b/refs/packed-backend.h
@@ -11,6 +11,9 @@ struct ref_store *packed_ref_store_create(const char *path,
  */
 int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf 
*err);
 
+void packed_refs_unlock(struct ref_store *ref_store);
+int packed_refs_is_locked(struct ref_store *ref_store);
+
 void add_packed_ref(struct ref_store *ref_store,
const char *refname, const struct object_id *oid);
 
-- 
2.11.0



[PATCH v2 23/29] packed_refs_lock(): function renamed from lock_packed_refs()

2017-06-23 Thread Michael Haggerty
Rename `lock_packed_refs()` to `packed_refs_lock()` for consistency
with how other methods are named. Also, it's about to get some
companions.

Signed-off-by: Michael Haggerty 
---
 refs/files-backend.c  |  4 ++--
 refs/packed-backend.c | 10 +-
 refs/packed-backend.h |  2 +-
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 2810785efc..88de907148 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1096,7 +1096,7 @@ static int files_pack_refs(struct ref_store *ref_store, 
unsigned int flags)
struct ref_to_prune *refs_to_prune = NULL;
struct strbuf err = STRBUF_INIT;
 
-   lock_packed_refs(refs->packed_ref_store, LOCK_DIE_ON_ERROR);
+   packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR);
 
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL, 0);
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
@@ -2679,7 +2679,7 @@ static int files_initial_transaction_commit(struct 
ref_store *ref_store,
}
}
 
-   if (lock_packed_refs(refs->packed_ref_store, 0)) {
+   if (packed_refs_lock(refs->packed_ref_store, 0)) {
strbuf_addf(err, "unable to lock packed-refs file: %s",
strerror(errno));
ret = TRANSACTION_GENERIC_ERROR;
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 71f92ed6f0..cd214e07a1 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -321,7 +321,7 @@ static struct ref_dir *get_packed_refs(struct 
packed_ref_store *refs)
 /*
  * Add or overwrite a reference in the in-memory packed reference
  * cache. This may only be called while the packed-refs file is locked
- * (see lock_packed_refs()). To actually write the packed-refs file,
+ * (see packed_refs_lock()). To actually write the packed-refs file,
  * call commit_packed_refs().
  */
 void add_packed_ref(struct ref_store *ref_store,
@@ -515,11 +515,11 @@ static int write_packed_entry(FILE *fh, const char 
*refname,
return 0;
 }
 
-int lock_packed_refs(struct ref_store *ref_store, int flags)
+int packed_refs_lock(struct ref_store *ref_store, int flags)
 {
struct packed_ref_store *refs =
packed_downcast(ref_store, REF_STORE_WRITE | REF_STORE_MAIN,
-   "lock_packed_refs");
+   "packed_refs_lock");
static int timeout_configured = 0;
static int timeout_value = 1000;
struct packed_ref_cache *packed_ref_cache;
@@ -567,7 +567,7 @@ static const char PACKED_REFS_HEADER[] =
 /*
  * Write the current version of the packed refs cache from memory to
  * disk. The packed-refs file must already be locked for writing (see
- * lock_packed_refs()). Return zero on success. On errors, rollback
+ * packed_refs_lock()). Return zero on success. On errors, rollback
  * the lockfile, write an error message to `err`, and return a nonzero
  * value.
  */
@@ -698,7 +698,7 @@ int repack_without_refs(struct ref_store *ref_store,
if (!needs_repacking)
return 0; /* no refname exists in packed refs */
 
-   if (lock_packed_refs(&refs->base, 0)) {
+   if (packed_refs_lock(&refs->base, 0)) {
unable_to_lock_message(refs->path, errno, err);
return -1;
}
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
index 3d4057b65b..dbc00d3396 100644
--- a/refs/packed-backend.h
+++ b/refs/packed-backend.h
@@ -9,7 +9,7 @@ struct ref_store *packed_ref_store_create(const char *path,
  * hold_lock_file_for_update(). Return 0 on success. On errors, set
  * errno appropriately and return a nonzero value.
  */
-int lock_packed_refs(struct ref_store *ref_store, int flags);
+int packed_refs_lock(struct ref_store *ref_store, int flags);
 
 void add_packed_ref(struct ref_store *ref_store,
const char *refname, const struct object_id *oid);
-- 
2.11.0



[PATCH v2 18/29] packed_read_raw_ref(): new function, replacing `resolve_packed_ref()`

2017-06-23 Thread Michael Haggerty
Add a new function, `packed_read_raw_ref()`, which is nearly a
`read_raw_ref_fn`. Use it in place of `resolve_packed_ref()`.

Signed-off-by: Michael Haggerty 
---
 refs/files-backend.c | 36 +---
 1 file changed, 17 insertions(+), 19 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 0490cc087e..346794cf7c 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -608,27 +608,23 @@ static struct ref_entry *get_packed_ref(struct 
packed_ref_store *refs,
return find_ref_entry(get_packed_refs(refs), refname);
 }
 
-/*
- * A loose ref file doesn't exist; check for a packed ref.
- */
-static int resolve_packed_ref(struct files_ref_store *refs,
- const char *refname,
- unsigned char *sha1, unsigned int *flags)
+static int packed_read_raw_ref(struct packed_ref_store *refs,
+  const char *refname, unsigned char *sha1,
+  struct strbuf *referent, unsigned int *type)
 {
struct ref_entry *entry;
 
-   /*
-* The loose reference file does not exist; check for a packed
-* reference.
-*/
-   entry = get_packed_ref(refs->packed_ref_store, refname);
-   if (entry) {
-   hashcpy(sha1, entry->u.value.oid.hash);
-   *flags |= REF_ISPACKED;
-   return 0;
+   *type = 0;
+
+   entry = get_packed_ref(refs, refname);
+   if (!entry) {
+   errno = ENOENT;
+   return -1;
}
-   /* refname is not a packed reference. */
-   return -1;
+
+   hashcpy(sha1, entry->u.value.oid.hash);
+   *type = REF_ISPACKED;
+   return 0;
 }
 
 static int files_read_raw_ref(struct ref_store *ref_store,
@@ -674,7 +670,8 @@ static int files_read_raw_ref(struct ref_store *ref_store,
if (lstat(path, &st) < 0) {
if (errno != ENOENT)
goto out;
-   if (resolve_packed_ref(refs, refname, sha1, type)) {
+   if (packed_read_raw_ref(refs->packed_ref_store, refname,
+   sha1, referent, type)) {
errno = ENOENT;
goto out;
}
@@ -713,7 +710,8 @@ static int files_read_raw_ref(struct ref_store *ref_store,
 * ref is supposed to be, there could still be a
 * packed ref:
 */
-   if (resolve_packed_ref(refs, refname, sha1, type)) {
+   if (packed_read_raw_ref(refs->packed_ref_store, refname,
+   sha1, referent, type)) {
errno = EISDIR;
goto out;
}
-- 
2.11.0



[PATCH v2 15/29] repack_without_refs(): take a `packed_ref_store *` parameter

2017-06-23 Thread Michael Haggerty
It only cares about the packed-refs part of the reference store.

Signed-off-by: Michael Haggerty 
---
 refs/files-backend.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 2b9d93d3b6..c206791b91 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1621,19 +1621,19 @@ static int files_pack_refs(struct ref_store *ref_store, 
unsigned int flags)
  *
  * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
  */
-static int repack_without_refs(struct files_ref_store *refs,
+static int repack_without_refs(struct packed_ref_store *refs,
   struct string_list *refnames, struct strbuf *err)
 {
struct ref_dir *packed;
struct string_list_item *refname;
int ret, needs_repacking = 0, removed = 0;
 
-   files_assert_main_repository(refs, "repack_without_refs");
+   packed_assert_main_repository(refs, "repack_without_refs");
assert(err);
 
/* Look for a packed ref */
for_each_string_list_item(refname, refnames) {
-   if (get_packed_ref(refs->packed_ref_store, refname->string)) {
+   if (get_packed_ref(refs, refname->string)) {
needs_repacking = 1;
break;
}
@@ -1643,11 +1643,11 @@ static int repack_without_refs(struct files_ref_store 
*refs,
if (!needs_repacking)
return 0; /* no refname exists in packed refs */
 
-   if (lock_packed_refs(refs->packed_ref_store, 0)) {
-   unable_to_lock_message(refs->packed_ref_store->path, errno, 
err);
+   if (lock_packed_refs(refs, 0)) {
+   unable_to_lock_message(refs->path, errno, err);
return -1;
}
-   packed = get_packed_refs(refs->packed_ref_store);
+   packed = get_packed_refs(refs);
 
/* Remove refnames from the cache */
for_each_string_list_item(refname, refnames)
@@ -1658,12 +1658,12 @@ static int repack_without_refs(struct files_ref_store 
*refs,
 * All packed entries disappeared while we were
 * acquiring the lock.
 */
-   rollback_packed_refs(refs->packed_ref_store);
+   rollback_packed_refs(refs);
return 0;
}
 
/* Write what remains */
-   ret = commit_packed_refs(refs->packed_ref_store);
+   ret = commit_packed_refs(refs);
if (ret)
strbuf_addf(err, "unable to overwrite old ref-pack file: %s",
strerror(errno));
@@ -1681,7 +1681,7 @@ static int files_delete_refs(struct ref_store *ref_store, 
const char *msg,
if (!refnames->nr)
return 0;
 
-   result = repack_without_refs(refs, refnames, &err);
+   result = repack_without_refs(refs->packed_ref_store, refnames, &err);
if (result) {
/*
 * If we failed to rewrite the packed-refs file, then
@@ -3101,7 +3101,7 @@ static int files_transaction_finish(struct ref_store 
*ref_store,
}
}
 
-   if (repack_without_refs(refs, &refs_to_delete, err)) {
+   if (repack_without_refs(refs->packed_ref_store, &refs_to_delete, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
-- 
2.11.0



[PATCH v2 11/29] lock_packed_refs(): take a `packed_ref_store *` parameter

2017-06-23 Thread Michael Haggerty
It only cares about the packed-refs part of the reference store.

Signed-off-by: Michael Haggerty 
---
 refs/files-backend.c | 31 ++-
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 4943207098..0d8f39089f 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -80,6 +80,19 @@ static struct packed_ref_store *packed_ref_store_create(
return refs;
 }
 
+/*
+ * Die if refs is not the main ref store. caller is used in any
+ * necessary error messages.
+ */
+static void packed_assert_main_repository(struct packed_ref_store *refs,
+ const char *caller)
+{
+   if (refs->store_flags & REF_STORE_MAIN)
+   return;
+
+   die("BUG: operation %s only allowed for main ref store", caller);
+}
+
 /*
  * Future: need to be in "struct repository"
  * when doing a full libification.
@@ -1334,13 +1347,13 @@ static void write_packed_entry(FILE *fh, const char 
*refname,
  * hold_lock_file_for_update(). Return 0 on success. On errors, set
  * errno appropriately and return a nonzero value.
  */
-static int lock_packed_refs(struct files_ref_store *refs, int flags)
+static int lock_packed_refs(struct packed_ref_store *refs, int flags)
 {
static int timeout_configured = 0;
static int timeout_value = 1000;
struct packed_ref_cache *packed_ref_cache;
 
-   files_assert_main_repository(refs, "lock_packed_refs");
+   packed_assert_main_repository(refs, "lock_packed_refs");
 
if (!timeout_configured) {
git_config_get_int("core.packedrefstimeout", &timeout_value);
@@ -1348,8 +1361,8 @@ static int lock_packed_refs(struct files_ref_store *refs, 
int flags)
}
 
if (hold_lock_file_for_update_timeout(
-   &refs->packed_ref_store->lock,
-   refs->packed_ref_store->path,
+   &refs->lock,
+   refs->path,
flags, timeout_value) < 0)
return -1;
 
@@ -1361,9 +1374,9 @@ static int lock_packed_refs(struct files_ref_store *refs, 
int flags)
 * cache is still valid. We've just locked the file, but it
 * might have changed the moment *before* we locked it.
 */
-   validate_packed_ref_cache(refs->packed_ref_store);
+   validate_packed_ref_cache(refs);
 
-   packed_ref_cache = get_packed_ref_cache(refs->packed_ref_store);
+   packed_ref_cache = get_packed_ref_cache(refs);
/* Increment the reference count to prevent it from being freed: */
acquire_packed_ref_cache(packed_ref_cache);
return 0;
@@ -1560,7 +1573,7 @@ static int files_pack_refs(struct ref_store *ref_store, 
unsigned int flags)
int ok;
struct ref_to_prune *refs_to_prune = NULL;
 
-   lock_packed_refs(refs, LOCK_DIE_ON_ERROR);
+   lock_packed_refs(refs->packed_ref_store, LOCK_DIE_ON_ERROR);
 
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL, 0);
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
@@ -1629,7 +1642,7 @@ static int repack_without_refs(struct files_ref_store 
*refs,
if (!needs_repacking)
return 0; /* no refname exists in packed refs */
 
-   if (lock_packed_refs(refs, 0)) {
+   if (lock_packed_refs(refs->packed_ref_store, 0)) {
unable_to_lock_message(refs->packed_ref_store->path, errno, 
err);
return -1;
}
@@ -3198,7 +3211,7 @@ static int files_initial_transaction_commit(struct 
ref_store *ref_store,
}
}
 
-   if (lock_packed_refs(refs, 0)) {
+   if (lock_packed_refs(refs->packed_ref_store, 0)) {
strbuf_addf(err, "unable to lock packed-refs file: %s",
strerror(errno));
ret = TRANSACTION_GENERIC_ERROR;
-- 
2.11.0



[PATCH v2 26/29] clear_packed_ref_cache(): don't protest if the lock is held

2017-06-23 Thread Michael Haggerty
The existing callers already check that the lock isn't held just
before calling `clear_packed_ref_cache()`, and in the near future we
want to be able to call this function when the lock is held.

Signed-off-by: Michael Haggerty 
---
 refs/packed-backend.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index f27943f9a1..96d92a5eea 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -133,8 +133,6 @@ static void clear_packed_ref_cache(struct packed_ref_store 
*refs)
if (refs->cache) {
struct packed_ref_cache *cache = refs->cache;
 
-   if (is_lock_file_locked(&refs->lock))
-   die("BUG: packed-ref cache cleared while locked");
refs->cache = NULL;
release_packed_ref_cache(cache);
}
-- 
2.11.0



[PATCH v2 10/29] add_packed_ref(): take a `packed_ref_store *` parameter

2017-06-23 Thread Michael Haggerty
It only cares about the packed-refs part of the reference store.

Signed-off-by: Michael Haggerty 
---
 refs/files-backend.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index bc5c0de84e..4943207098 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -438,19 +438,19 @@ static struct ref_dir *get_packed_refs(struct 
packed_ref_store *refs)
  * (see lock_packed_refs()). To actually write the packed-refs file,
  * call commit_packed_refs().
  */
-static void add_packed_ref(struct files_ref_store *refs,
+static void add_packed_ref(struct packed_ref_store *refs,
   const char *refname, const struct object_id *oid)
 {
struct ref_dir *packed_refs;
struct ref_entry *packed_entry;
 
-   if (!is_lock_file_locked(&refs->packed_ref_store->lock))
+   if (!is_lock_file_locked(&refs->lock))
die("BUG: packed refs not locked");
 
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
die("Reference has invalid format: '%s'", refname);
 
-   packed_refs = get_packed_refs(refs->packed_ref_store);
+   packed_refs = get_packed_refs(refs);
packed_entry = find_ref_entry(packed_refs, refname);
if (packed_entry) {
/* Overwrite the existing entry: */
@@ -1579,7 +1579,7 @@ static int files_pack_refs(struct ref_store *ref_store, 
unsigned int flags)
 * we don't copy the peeled status, because we want it
 * to be re-peeled.
 */
-   add_packed_ref(refs, iter->refname, iter->oid);
+   add_packed_ref(refs->packed_ref_store, iter->refname, 
iter->oid);
 
/* Schedule the loose reference for pruning if requested. */
if ((flags & PACK_REFS_PRUNE)) {
@@ -3210,7 +3210,7 @@ static int files_initial_transaction_commit(struct 
ref_store *ref_store,
 
if ((update->flags & REF_HAVE_NEW) &&
!is_null_oid(&update->new_oid))
-   add_packed_ref(refs, update->refname,
+   add_packed_ref(refs->packed_ref_store, update->refname,
   &update->new_oid);
}
 
-- 
2.11.0



[PATCH v2 08/29] get_packed_ref_cache(): take a `packed_ref_store *` parameter

2017-06-23 Thread Michael Haggerty
It only cares about the packed-refs part of the reference store.

Signed-off-by: Michael Haggerty 
---
 refs/files-backend.c | 26 --
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index f061506bf0..b2ef7b3bb9 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -404,24 +404,22 @@ static void validate_packed_ref_cache(struct 
packed_ref_store *refs)
 }
 
 /*
- * Get the packed_ref_cache for the specified files_ref_store,
+ * Get the packed_ref_cache for the specified packed_ref_store,
  * creating and populating it if it hasn't been read before or if the
  * file has been changed (according to its `validity` field) since it
  * was last read. On the other hand, if we hold the lock, then assume
  * that the file hasn't been changed out from under us, so skip the
  * extra `stat()` call in `stat_validity_check()`.
  */
-static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store 
*refs)
+static struct packed_ref_cache *get_packed_ref_cache(struct packed_ref_store 
*refs)
 {
-   const char *packed_refs_file = refs->packed_ref_store->path;
+   if (!is_lock_file_locked(&refs->lock))
+   validate_packed_ref_cache(refs);
 
-   if (!is_lock_file_locked(&refs->packed_ref_store->lock))
-   validate_packed_ref_cache(refs->packed_ref_store);
-
-   if (!refs->packed_ref_store->cache)
-   refs->packed_ref_store->cache = 
read_packed_refs(packed_refs_file);
+   if (!refs->cache)
+   refs->cache = read_packed_refs(refs->path);
 
-   return refs->packed_ref_store->cache;
+   return refs->cache;
 }
 
 static struct ref_dir *get_packed_ref_dir(struct packed_ref_cache 
*packed_ref_cache)
@@ -431,7 +429,7 @@ static struct ref_dir *get_packed_ref_dir(struct 
packed_ref_cache *packed_ref_ca
 
 static struct ref_dir *get_packed_refs(struct files_ref_store *refs)
 {
-   return get_packed_ref_dir(get_packed_ref_cache(refs));
+   return get_packed_ref_dir(get_packed_ref_cache(refs->packed_ref_store));
 }
 
 /*
@@ -1151,7 +1149,7 @@ static struct ref_iterator *files_ref_iterator_begin(
loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),
  prefix, 1);
 
-   iter->packed_ref_cache = get_packed_ref_cache(refs);
+   iter->packed_ref_cache = get_packed_ref_cache(refs->packed_ref_store);
acquire_packed_ref_cache(iter->packed_ref_cache);
packed_iter = cache_ref_iterator_begin(iter->packed_ref_cache->cache,
   prefix, 0);
@@ -1365,7 +1363,7 @@ static int lock_packed_refs(struct files_ref_store *refs, 
int flags)
 */
validate_packed_ref_cache(refs->packed_ref_store);
 
-   packed_ref_cache = get_packed_ref_cache(refs);
+   packed_ref_cache = get_packed_ref_cache(refs->packed_ref_store);
/* Increment the reference count to prevent it from being freed: */
acquire_packed_ref_cache(packed_ref_cache);
return 0;
@@ -1380,7 +1378,7 @@ static int lock_packed_refs(struct files_ref_store *refs, 
int flags)
 static int commit_packed_refs(struct files_ref_store *refs)
 {
struct packed_ref_cache *packed_ref_cache =
-   get_packed_ref_cache(refs);
+   get_packed_ref_cache(refs->packed_ref_store);
int ok, error = 0;
int save_errno = 0;
FILE *out;
@@ -1426,7 +1424,7 @@ static int commit_packed_refs(struct files_ref_store 
*refs)
 static void rollback_packed_refs(struct files_ref_store *refs)
 {
struct packed_ref_cache *packed_ref_cache =
-   get_packed_ref_cache(refs);
+   get_packed_ref_cache(refs->packed_ref_store);
 
files_assert_main_repository(refs, "rollback_packed_refs");
 
-- 
2.11.0



[PATCH v2 29/29] read_packed_refs(): die if `packed-refs` contains bogus data

2017-06-23 Thread Michael Haggerty
The old code ignored any lines that it didn't understand. This is
dangerous. Instead, `die()` if the `packed-refs` file contains any
lines that we don't know how to handle.

Signed-off-by: Michael Haggerty 
---
 refs/packed-backend.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 377c775adb..1cbaf036df 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -253,9 +253,7 @@ static struct packed_ref_cache *read_packed_refs(const char 
*packed_refs_file)
(peeled == PEELED_TAGS && starts_with(refname, 
"refs/tags/")))
last->flag |= REF_KNOWS_PEELED;
add_ref_entry(dir, last);
-   continue;
-   }
-   if (last &&
+   } else if (last &&
line.buf[0] == '^' &&
line.len == PEELED_LINE_LENGTH &&
line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
@@ -267,6 +265,8 @@ static struct packed_ref_cache *read_packed_refs(const char 
*packed_refs_file)
 * reference:
 */
last->flag |= REF_KNOWS_PEELED;
+   } else {
+   die("unexpected line in %s: %s", packed_refs_file, 
line.buf);
}
}
 
-- 
2.11.0



[PATCH v2 27/29] commit_packed_refs(): remove call to `packed_refs_unlock()`

2017-06-23 Thread Michael Haggerty
Instead, change the callers of `commit_packed_refs()` to call
`packed_refs_unlock()`.

Signed-off-by: Michael Haggerty 
---
 refs/files-backend.c  |  2 ++
 refs/packed-backend.c | 18 --
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 8ea4e9ab05..93bdc8f0c8 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1131,6 +1131,7 @@ static int files_pack_refs(struct ref_store *ref_store, 
unsigned int flags)
 
if (commit_packed_refs(refs->packed_ref_store, &err))
die("unable to overwrite old ref-pack file: %s", err.buf);
+   packed_refs_unlock(refs->packed_ref_store);
 
prune_refs(refs, refs_to_prune);
strbuf_release(&err);
@@ -2699,6 +2700,7 @@ static int files_initial_transaction_commit(struct 
ref_store *ref_store,
}
 
 cleanup:
+   packed_refs_unlock(refs->packed_ref_store);
transaction->state = REF_TRANSACTION_CLOSED;
string_list_clear(&affected_refnames, 0);
return ret;
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 96d92a5eea..5cf6b3d40e 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -606,7 +606,6 @@ int commit_packed_refs(struct ref_store *ref_store, struct 
strbuf *err)
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(refs);
int ok;
-   int ret = -1;
struct strbuf sb = STRBUF_INIT;
FILE *out;
struct ref_iterator *iter;
@@ -619,7 +618,7 @@ int commit_packed_refs(struct ref_store *ref_store, struct 
strbuf *err)
strbuf_addf(err, "unable to create file %s: %s",
sb.buf, strerror(errno));
strbuf_release(&sb);
-   goto out;
+   return -1;
}
strbuf_release(&sb);
 
@@ -660,18 +659,14 @@ int commit_packed_refs(struct ref_store *ref_store, 
struct strbuf *err)
if (rename_tempfile(&refs->tempfile, refs->path)) {
strbuf_addf(err, "error replacing %s: %s",
refs->path, strerror(errno));
-   goto out;
+   return -1;
}
 
-   ret = 0;
-   goto out;
+   return 0;
 
 error:
delete_tempfile(&refs->tempfile);
-
-out:
-   packed_refs_unlock(ref_store);
-   return ret;
+   return -1;
 }
 
 /*
@@ -705,6 +700,7 @@ int repack_without_refs(struct ref_store *ref_store,
struct ref_dir *packed;
struct string_list_item *refname;
int needs_repacking = 0, removed = 0;
+   int ret;
 
packed_assert_main_repository(refs, "repack_without_refs");
assert(err);
@@ -740,7 +736,9 @@ int repack_without_refs(struct ref_store *ref_store,
}
 
/* Write what remains */
-   return commit_packed_refs(&refs->base, err);
+   ret = commit_packed_refs(&refs->base, err);
+   packed_refs_unlock(ref_store);
+   return ret;
 }
 
 static int packed_init_db(struct ref_store *ref_store, struct strbuf *err)
-- 
2.11.0



[PATCH v2 28/29] repack_without_refs(): don't lock or unlock the packed refs

2017-06-23 Thread Michael Haggerty
Change `repack_without_refs()` to expect the packed-refs lock to be
held already, and not to release the lock before returning. Change the
callers to deal with lock management.

This change makes it possible for callers to hold the packed-refs lock
for a longer span of time, a possibility that will eventually make it
possible to fix some longstanding races.

The only semantic change here is that `repack_without_refs()` used to
forgot to release the lock in the `if (!removed)` exit path. That
omission is now fixed.

Signed-off-by: Michael Haggerty 
---
 refs/files-backend.c  | 47 +++
 refs/packed-backend.c | 32 
 2 files changed, 39 insertions(+), 40 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 93bdc8f0c8..e9b95592b6 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1149,24 +1149,16 @@ static int files_delete_refs(struct ref_store 
*ref_store, const char *msg,
if (!refnames->nr)
return 0;
 
-   result = repack_without_refs(refs->packed_ref_store, refnames, &err);
-   if (result) {
-   /*
-* If we failed to rewrite the packed-refs file, then
-* it is unsafe to try to remove loose refs, because
-* doing so might expose an obsolete packed value for
-* a reference that might even point at an object that
-* has been garbage collected.
-*/
-   if (refnames->nr == 1)
-   error(_("could not delete reference %s: %s"),
- refnames->items[0].string, err.buf);
-   else
-   error(_("could not delete references: %s"), err.buf);
+   if (packed_refs_lock(refs->packed_ref_store, 0, &err))
+   goto error;
 
-   goto out;
+   if (repack_without_refs(refs->packed_ref_store, refnames, &err)) {
+   packed_refs_unlock(refs->packed_ref_store);
+   goto error;
}
 
+   packed_refs_unlock(refs->packed_ref_store);
+
for (i = 0; i < refnames->nr; i++) {
const char *refname = refnames->items[i].string;
 
@@ -1174,9 +1166,24 @@ static int files_delete_refs(struct ref_store 
*ref_store, const char *msg,
result |= error(_("could not remove reference %s"), 
refname);
}
 
-out:
strbuf_release(&err);
return result;
+
+error:
+   /*
+* If we failed to rewrite the packed-refs file, then it is
+* unsafe to try to remove loose refs, because doing so might
+* expose an obsolete packed value for a reference that might
+* even point at an object that has been garbage collected.
+*/
+   if (refnames->nr == 1)
+   error(_("could not delete reference %s: %s"),
+ refnames->items[0].string, err.buf);
+   else
+   error(_("could not delete references: %s"), err.buf);
+
+   strbuf_release(&err);
+   return -1;
 }
 
 /*
@@ -2569,11 +2576,19 @@ static int files_transaction_finish(struct ref_store 
*ref_store,
}
}
 
+   if (packed_refs_lock(refs->packed_ref_store, 0, err)) {
+   ret = TRANSACTION_GENERIC_ERROR;
+   goto cleanup;
+   }
+
if (repack_without_refs(refs->packed_ref_store, &refs_to_delete, err)) {
ret = TRANSACTION_GENERIC_ERROR;
+   packed_refs_unlock(refs->packed_ref_store);
goto cleanup;
}
 
+   packed_refs_unlock(refs->packed_ref_store);
+
/* Delete the reflogs of any references that were deleted: */
for_each_string_list_item(ref_to_delete, &refs_to_delete) {
strbuf_reset(&sb);
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 5cf6b3d40e..377c775adb 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -669,25 +669,12 @@ int commit_packed_refs(struct ref_store *ref_store, 
struct strbuf *err)
return -1;
 }
 
-/*
- * Rollback the lockfile for the packed-refs file, and discard the
- * in-memory packed reference cache.  (The packed-refs file will be
- * read anew if it is needed again after this function is called.)
- */
-static void rollback_packed_refs(struct packed_ref_store *refs)
-{
-   packed_assert_main_repository(refs, "rollback_packed_refs");
-
-   if (!is_lock_file_locked(&refs->lock))
-   die("BUG: packed-refs not locked");
-   packed_refs_unlock(&refs->base);
-   clear_packed_ref_cache(refs);
-}
-
 /*
  * Rewrite the packed-refs file, omitting any refs listed in
  * 'refnames'. On error, leave packed-refs unchanged, write an error
- * message to 'err', and return a nonzero value.
+ * message to 'err', and return a nonzero value. The packed refs lock
+ * must be held when calling this function; it will still be held when
+ * the function r

[PATCH v2 24/29] packed_refs_lock(): report errors via a `struct strbuf *err`

2017-06-23 Thread Michael Haggerty
That way the callers don't have to come up with error messages
themselves.

Signed-off-by: Michael Haggerty 
---
 refs/files-backend.c  |  6 ++
 refs/packed-backend.c | 17 +++--
 refs/packed-backend.h |  6 +++---
 3 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 88de907148..8ea4e9ab05 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1096,7 +1096,7 @@ static int files_pack_refs(struct ref_store *ref_store, 
unsigned int flags)
struct ref_to_prune *refs_to_prune = NULL;
struct strbuf err = STRBUF_INIT;
 
-   packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR);
+   packed_refs_lock(refs->packed_ref_store, LOCK_DIE_ON_ERROR, &err);
 
iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL, 0);
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
@@ -2679,9 +2679,7 @@ static int files_initial_transaction_commit(struct 
ref_store *ref_store,
}
}
 
-   if (packed_refs_lock(refs->packed_ref_store, 0)) {
-   strbuf_addf(err, "unable to lock packed-refs file: %s",
-   strerror(errno));
+   if (packed_refs_lock(refs->packed_ref_store, 0, err)) {
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index cd214e07a1..78e877a9e3 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -515,7 +515,7 @@ static int write_packed_entry(FILE *fh, const char *refname,
return 0;
 }
 
-int packed_refs_lock(struct ref_store *ref_store, int flags)
+int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf 
*err)
 {
struct packed_ref_store *refs =
packed_downcast(ref_store, REF_STORE_WRITE | REF_STORE_MAIN,
@@ -537,9 +537,15 @@ int packed_refs_lock(struct ref_store *ref_store, int 
flags)
if (hold_lock_file_for_update_timeout(
&refs->lock,
refs->path,
-   flags, timeout_value) < 0 ||
-   close_lock_file(&refs->lock))
+   flags, timeout_value) < 0) {
+   unable_to_lock_message(refs->path, errno, err);
+   return -1;
+   }
+
+   if (close_lock_file(&refs->lock)) {
+   strbuf_addf(err, "unable to close %s: %s", refs->path, 
strerror(errno));
return -1;
+   }
 
/*
 * Now that we hold the `packed-refs` lock, make sure that our
@@ -698,10 +704,9 @@ int repack_without_refs(struct ref_store *ref_store,
if (!needs_repacking)
return 0; /* no refname exists in packed refs */
 
-   if (packed_refs_lock(&refs->base, 0)) {
-   unable_to_lock_message(refs->path, errno, err);
+   if (packed_refs_lock(&refs->base, 0, err))
return -1;
-   }
+
packed = get_packed_refs(refs);
 
/* Remove refnames from the cache */
diff --git a/refs/packed-backend.h b/refs/packed-backend.h
index dbc00d3396..210e3f35ce 100644
--- a/refs/packed-backend.h
+++ b/refs/packed-backend.h
@@ -6,10 +6,10 @@ struct ref_store *packed_ref_store_create(const char *path,
 
 /*
  * Lock the packed-refs file for writing. Flags is passed to
- * hold_lock_file_for_update(). Return 0 on success. On errors, set
- * errno appropriately and return a nonzero value.
+ * hold_lock_file_for_update(). Return 0 on success. On errors, write
+ * an error message to `err` and return a nonzero value.
  */
-int packed_refs_lock(struct ref_store *ref_store, int flags);
+int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf 
*err);
 
 void add_packed_ref(struct ref_store *ref_store,
const char *refname, const struct object_id *oid);
-- 
2.11.0



  1   2   >