Re: git fetch behaves weirdely when run in a worktree

2018-09-25 Thread Kaartic Sivaraam
Hi,

I just wanted make a point a little more clear. See comment inline.


On 24 September 2018 01:39:26 GMT+05:30, Kaartic Sivaraam 
 wrote:
> To add to that
>confusion when I run
>
>   $ cat $MAIN_WORKTREE/.git/worktrees/$BUILD_WORKTREE/FETCH_HEAD
>
>it seems to be printing the info about the remote refs once and then if
>I run it again immediately nothing is printed. If I repeat it again,
>info about remote refs is printed but this time the info about the
>remote refs is printed thrice. This happens randomly. Sample output:
>
>   01:23 $ cat ../git/.git/worktrees/$BUILD_WORKTREE/FETCH_HEAD 
>53f9a3e157dbbc901a02ac2c73346d375e24978c   not-for-merge   branch 'maint'
>of https://github.com/git/git
>150f307afc13961b0322ad0e7205a7b193368586   not-for-merge   branch 'master'
>of https://github.com/git/git
>01d371f741e6f0b0076d9ed942d99bdb23757eac   not-for-merge   branch 'next' of
>https://github.com/git/git
>7a81cbc028be113058e0b55062706ec6de62ed94   not-for-merge   branch 'pu' of
>https://github.com/git/git
>722746685bce03f223ed75febe312495e6c139da   not-for-merge   branch 'todo' of
>https://github.com/git/git
>   01:23 $ cat ../git/.git/worktrees/$BUILD_WORKTREE/FETCH_HEAD 
>   01:23 $ cat ../git/.git/worktrees/$BUILD_WORKTREE/FETCH_HEAD 
>   01:23 $ cat ../git/.git/worktrees/$BUILD_WORKTREE/FETCH_HEAD 
>53f9a3e157dbbc901a02ac2c73346d375e24978c   not-for-merge   branch 'maint'
>of https://github.com/git/git
>150f307afc13961b0322ad0e7205a7b193368586   not-for-merge   branch 'master'
>of https://github.com/git/git
>01d371f741e6f0b0076d9ed942d99bdb23757eac   not-for-merge   branch 'next' of
>https://github.com/git/git
>7a81cbc028be113058e0b55062706ec6de62ed94   not-for-merge   branch 'pu' of
>https://github.com/git/git
>722746685bce03f223ed75febe312495e6c139da   not-for-merge   branch 'todo' of
>https://github.com/git/git
>53f9a3e157dbbc901a02ac2c73346d375e24978c   not-for-merge   branch 'maint'
>of https://github.com/git/git
>150f307afc13961b0322ad0e7205a7b193368586   not-for-merge   branch 'master'
>of https://github.com/git/git
>01d371f741e6f0b0076d9ed942d99bdb23757eac   not-for-merge   branch 'next' of
>https://github.com/git/git
>7a81cbc028be113058e0b55062706ec6de62ed94   not-for-merge   branch 'pu' of
>https://github.com/git/git
>722746685bce03f223ed75febe312495e6c139da   not-for-merge   branch 'todo' of
>https://github.com/git/git
>53f9a3e157dbbc901a02ac2c73346d375e24978c   not-for-merge   branch 'maint'
>of https://github.com/git/git
>150f307afc13961b0322ad0e7205a7b193368586   not-for-merge   branch 'master'
>of https://github.com/git/git
>01d371f741e6f0b0076d9ed942d99bdb23757eac   not-for-merge   branch 'next' of
>https://github.com/git/git
>7a81cbc028be113058e0b55062706ec6de62ed94   not-for-merge   branch 'pu' of
>https://github.com/git/git
>722746685bce03f223ed75febe312495e6c139da   not-for-merge   branch 'todo' of
>https://github.com/git/git
>   01:23 $ cat ../git/.git/worktrees/$BUILD_WORKTREE/FETCH_HEAD 
>53f9a3e157dbbc901a02ac2c73346d375e24978c   not-for-merge   branch 'maint'
>of https://github.com/git/git
>150f307afc13961b0322ad0e7205a7b193368586   not-for-merge   branch 'master'
>of https://github.com/git/git
>01d371f741e6f0b0076d9ed942d99bdb23757eac   not-for-merge   branch 'next' of
>https://github.com/git/git
>7a81cbc028be113058e0b55062706ec6de62ed94   not-for-merge   branch 'pu' of
>https://github.com/git/git
>722746685bce03f223ed75febe312495e6c139da   not-for-merge   branch 'todo' of
>https://github.com/git/git
>

This is the most interesting part of the issue. I **did not** run 'git fetch 
...' in between those cat commands. I was surprised by how the contents of 
FETCH_HEAD are changing without me spawning any git processes that might change 
it. Am I missing something here? As far as i could remember, there wasn't any 
IDE running that might automatically spawn git commands especially in that work 
tree. Weird.

-- 
Sivaraam

Sent from my Android device with K-9 Mail. Please excuse my brevity.


Re: [PATCH 1/8] sha1-array: provide oid_array_filter

2018-09-25 Thread Jeff King
On Tue, Sep 25, 2018 at 12:26:44PM -0700, Stefan Beller wrote:

> On Sat, Sep 22, 2018 at 5:58 AM Ævar Arnfjörð Bjarmason
>  wrote:
> >
> >
> > On Fri, Sep 21 2018, Stefan Beller wrote:
> >
> > > +/*
> > > + * Apply want to each entry in array, retaining only the entries for
> > > + * which the function returns true.  Preserve the order of the entries
> > > + * that are retained.
> > > + */
> > > +void oid_array_filter(struct oid_array *array,
> > > +   for_each_oid_fn want,
> > > +   void *cbdata);
> > > +
> > >  #endif /* SHA1_ARRAY_H */
> >
> > The code LGTM, but this comment should instead be an update to the API
> > docs, see my recent 5cc044e025 ("get_short_oid: sort ambiguous objects
> > by type, then SHA-1", 2018-05-10) for an addition of a new function to
> > this API where I added some new docs.
> 
> ok will fix for consistency (this whole API is there).
> 
> Longer term (I thought) we were trying to migrate API docs
> to headers instead?

Yes, please. I think it prevents exactly this sort of confusion. :)

-Peff


Re: [PATCH v4 9/9] Documentation/config: add odb..promisorRemote

2018-09-25 Thread Jeff King
On Tue, Sep 25, 2018 at 03:31:36PM -0700, Junio C Hamano wrote:

> Christian Couder  writes:
> 
> > The main issue that this patch series tries to solve is that
> > extensions.partialclone config option limits the partial clone and
> > promisor features to only one remote. One related issue is that it
> > also prevents to have other kind of promisor/partial clone/odb
> > remotes. By other kind I mean remotes that would not necessarily be
> > git repos, but that could store objects (that's where ODB, for Object
> > DataBase, comes from) and could provide those objects to Git through a
> > helper (or driver) script or program.
> 
> I do not think "sources that are not git repositories" is all that
> interesting, unless they can also serve as the source for ext::
> remote helper.  And if they can serve "git fetch ext::...", I think
> they can be treated just like a normal Git repository by the
> backfill code that needs to lazily populate the partial clone.

I don't know about that. Imagine I had a regular Git repo with a bunch
of large blobs, and then I also stored those large blobs in something
like S3 that provides caching, geographic locality, and resumable
transfers.

It would be nice to be able to say:

  1. Clone from the real repo, but do not transfer any blobs larger than
 10MB.

  2. When you need a blob, check the external odb that points to S3. Git
 cannot know about this automatically, but presumably you would set
 a few config variables to point to an external-odb helper script.

  3. If for some reason S3 doesn't work, you can always request it from
 the original repo. That part _doesn't_ need extra config, since we
 can assume that the source of the promisor pack can feed us the
 extra objects[1].

But you don't need to ever be able to "git fetch" from the S3 repo.

Now if you are arguing that the interface to the external-odb helper
script should be that it _looks_ like upload-pack, but simply advertises
no refs and will let you fetch any object, that makes more sense to me.
It's not something you could "git clone", but you can "git fetch" from
it.

However, that may be an overly constricting interface for the helper.
E.g., we might want to be able to issue several requests and have them
transfer in parallel. But I suppose we could teach that trick to
upload-pack in the long run, as it may be applicable even to fetching
from "real" git repos.

Hmm. Actually, I kind of like that direction the more I think about it.

-Peff


Re: git fetch behaves weirdely when run in a worktree

2018-09-25 Thread Kaartic Sivaraam
On 26 September 2018 03:10:17 GMT+05:30, Junio C Hamano  
wrote:
> 
> That looks like fetching only the 'next' branch and nothing else to
> me.
> 

Interesting.


> Perhaps your script is referring to a variable whose assignment is
> misspelled and invoking
> 
>   git fetch $origin $branch
> 
> and you are expecting the $branch variable to have string 'next' but
> due to some bugs it is empty somehow?  That explains why sometimes
> (i.e. when $branch does not get the value you expect it to have) the
> script fetches everything and some other times (i.e. when $branch
> does get the right value) the script fetches only the named branch.

Noce guees but I should have made this clear. The weirdness I described
in my initial mail happens when I run "git fetch origin next" manually
in the terminal.

The script only helped me identity that there was an issue as it was
automatically building the wrong version of Git. It was building and
installing the current 'origin/maint' when I wrote it for building
origin/next. I could easily identify the difference as 'origin/maint'
was at v2.18 while 'origin/next' was at v2.19 when I notived this
issue. Also the script doesn't depend on any variables for the branch
name. I've hardcoded the 'next' branch into it. For the sake of
reference, I've attached the script inline at the end of this mail.
Note that I've sanitized the path in which the worktree exists as
$COMMON_ROOT.

I did not notice this weirdness in another PC. But, this happens in all
the worktrees other than the main worktree in my laptop. I'm not sure
what I'm doing weirdly that might have caused this issue.

I'm not sure whether I mentioned this before I'm currently using a
manually built version of Git. It was built from origin/next pointing
at 01d371f741. But this also happens in Git v2.18.0 that comes via the
pacakge manager of my operating system (Debian testing).

--
Sivaraam

#!/bin/sh
#
# A script for the cron job that automatically fetches
# updates for the 'next' branch of Git and builds and
# installs the binary from source.
#
# The build succeeds only if the config.mak is present
# in the directory with appropriate configuration.
#
# The binary is installed into the default location if
# a prefix is not specified in the config.mak file.
# Bringing the binary into use is in the hands of the user.
# Hint: A bash alias might help.

GIT_NEXT_BUILD_AUTOMATE_DIR='$COMMON_ROOT/git-next-build-automate'
LOG_FILE="$GIT_NEXT_BUILD_AUTOMATE_DIR/GIT-NEXT-INSTALLATION-LOG.txt"
LOG_MSG_COMMON="installation of git 'next' build on $(date)"

if cd "$GIT_NEXT_BUILD_AUTOMATE_DIR"
then
# Fetch the remote changes
if git fetch origin next && git checkout -f FETCH_HEAD
then
if make install
then
GIT_NEXT_BUILD_STATUS=0
else
GIT_NEXT_BUILD_STATUS=1
fi
else
GIT_NEXT_BUILD_STATUS=1
fi
else
GIT_NEXT_BUILD_STATUS=1
fi

if test $GIT_NEXT_BUILD_STATUS -eq 0
then
echo "SUCCESS: $LOG_MSG_COMMON" >>"$LOG_FILE"
else
echo "FAILURE: $LOG_MSG_COMMON" >>"$LOG_FILE"
fi



Re: [PATCH v2 2/3] transport.c: introduce core.alternateRefsCommand

2018-09-25 Thread Jeff King
On Tue, Sep 25, 2018 at 06:09:35PM -0700, Taylor Blau wrote:

> > So I think this is fine (modulo that the grep and sed can be combined).
> > Yet another option would be to simply strip away everything except the
> > object id (which is all we care about), like:
> >
> >   depacketize | perl -lne '/^(\S+) \.have/ and print $1'
> 
> Thanks for this. This is the suggestion I ended up taking (modulo taking
> '-' as the first argument to 'depacketize').

I don't think depacketize takes any arguments. It always reads from
stdin directly, doesn't it? Your "-" is not hurting anything, but it is
totally ignored.

A perl tangent if you're interested:

  Normally for shell functions like this that are just wrappers around
  perl snippets, I would suggest to pass "$@" from the function's
  arguments to perl. So for example if we had:

haves_from_packets () {
perl -lne '/^(\S+) \.have/ and print $1' "$@"
}

  then you could call it with a filename:

haves_from_packets packets

  or input on stdin:

haves_from_packets )" explicitly in your program).

  But because depacketize() has to use byte-wise read() calls, it
  doesn't get that magic for free. And it did not seem worth the effort
  to implement, when shell redirections are so easy. ;)

  Just skimming through test-lib-functions.sh, though, it does seem that
  we often deviate from that pattern (e.g., all of the q_to_nul family).
  And has seemed to mind.

> The 'print $1' part of this makes things a lot nicer, actually, having
> removed the " .have" suffix. We can get rid of the expect_haves()
> function above, and instead call 'git rev-parse' inline and get the
> right results.

Yes. You can even do it all in a single rev-parse call.

-Peff


Re: [PATCH v2 2/3] transport.c: introduce core.alternateRefsCommand

2018-09-25 Thread Jeff King
On Tue, Sep 25, 2018 at 06:06:06PM -0700, Taylor Blau wrote:

> > > +extract_haves () {
> > > + depacketize - | grep '\.have' | sed -e 's/\\0.*$//g'
> > > +}
> >
> > Don't pipe grep into sed, especially when both the pattern to filter
> > and the operation to perform are simple.
> >
> > I am not sure what you are trying to achive with 'g' in
> > s/pattern$//g; The anchor at the rightmost end of the pattern makes
> > sure that the pattern matches only once per line at the end anyway,
> > so "do this howmanyever times as we have match on each line" would
> > not make any difference, no?
> 
> I admit to not fully understanding when the trailing `/g` is and is not
> useful. Anyway, I took Peff's suggestion below to convert this 'grep |
> sed' pipeline into a Perl invocation, which I think ended up much
> cleaner.

It makes the replacement global in the line. Without we substitute only
the first match. So try:

  echo foo | sed s/o/X/

versus:

  echo foo | sed s/o/X/g

-Peff


Re: [PATCH v2 3/3] transport.c: introduce core.alternateRefsPrefixes

2018-09-25 Thread Jeff King
On Tue, Sep 25, 2018 at 04:56:11PM -0700, Junio C Hamano wrote:

> Taylor Blau  writes:
> 
> > My reading of this is threefold:
> >
> >   1. There are some cosmetic changes that need to occur in t5410 and
> >  documentation, which are mentioned above. Those seem self
> >  explanatory, and I've applied the necessary bits already on my
> >  local version of this topic.
> >
> >   2. The core.alternateRefsCommand vs transport.* discussion was
> >  resolved in [1] as "let's use core.alternateRefsCommand and
> >  core.alternateRefsPrefixes" for now, and others contributors can
> >  change this as is needed.
> >
> >   3. We can apply Peff's patch to remove the refname requirement before
> >  mine, as well as any relevant changes in my series as have been
> >  affected by Peff's patch (e.g., documentation mentioning
> >  '%(refname)', etc).

Yeah, these three sound right to me.

> I do think it makes sense to allow alternateRefsCommand to output
> just the object names without adding any refnames, and to keep the
> parser simple, we should not even make the refname optional
> (i.e. "allow" above becomes "require"), and make the default one
> done via an invocation of for-each-ref also do the same.

Yeah, making it optional is just the worst of both worlds, IMHO. Then
callers sometimes get a real value and sometimes just whatever garbage
we fill in, and can't rely on it.

> I do not think there was a strong concensus that we need to change
> the internal C API signature, though.  If the function signature for
> the callback between each_ref_fn and alternate_ref_fn were the same,
> I would have opposed to the change, but because they are already
> different, I do not think it is necessary to keep the dummy refname
> parameter that is always passed a meaningless value.

Agreed. I adjusted my "rev-list --alternate-refs" patch for the proposed
new world order (just because it's the likely user of the refname
field). Since the function signatures aren't the same, I already had a
custom callback. It did chain to the existing each_ref_fn one, so I had
to adjust it like so:

diff --git a/revision.c b/revision.c
index 3988275fde..8dfe2fd4c0 100644
--- a/revision.c
+++ b/revision.c
@@ -1396,11 +1396,10 @@ void add_index_objects_to_pending(struct rev_info 
*revs, unsigned int flags)
free_worktrees(worktrees);
 }
 
-static void handle_one_alternate_ref(const char *refname,
-const struct object_id *oid,
+static void handle_one_alternate_ref(const struct object_id *oid,
 void *data)
 {
-   handle_one_ref(refname, oid, 0, data);
+   handle_one_ref(".have", oid, 0, data);
 }
 
 static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,

But I think that's fine. We have to handle the lack of name _somewhere_
in the call stack, so I'd just as soon it be here in the callback, where
we know what it will be used for (or not used at all).

> The final series would be
> 
>  1/4: peff's "refnames in alternates do nto matter"
> 
>  2/4: your "hardcoded for-each-ref becomes just a default"
> 
>  3/4: your "config can affect what command enumerates alternate's tips"
> 
>  4/4: your "with prefix config, you don't need a fully custom command"

Yep, that's what I'd expect from the new series.

-Peff


URGENT RESPONSE PLEASE.

2018-09-25 Thread Sean Kim.
Hello my dear.

Did you receive my email message to you? Please, get back to me ASAP as the 
matter is becoming late.  Expecting your urgent response.

Sean.



Re: [PATCH v2 3/3] transport.c: introduce core.alternateRefsPrefixes

2018-09-25 Thread Taylor Blau
On Tue, Sep 25, 2018 at 04:56:11PM -0700, Junio C Hamano wrote:
> Taylor Blau  writes:
>
> > My reading of this is threefold:
> >
> >   1. There are some cosmetic changes that need to occur in t5410 and
> >  documentation, which are mentioned above. Those seem self
> >  explanatory, and I've applied the necessary bits already on my
> >  local version of this topic.
> >
> >   2. The core.alternateRefsCommand vs transport.* discussion was
> >  resolved in [1] as "let's use core.alternateRefsCommand and
> >  core.alternateRefsPrefixes" for now, and others contributors can
> >  change this as is needed.
> >
> >   3. We can apply Peff's patch to remove the refname requirement before
> >  mine, as well as any relevant changes in my series as have been
> >  affected by Peff's patch (e.g., documentation mentioning
> >  '%(refname)', etc).
>
> I do think it makes sense to allow alternateRefsCommand to output
> just the object names without adding any refnames, and to keep the
> parser simple, we should not even make the refname optional
> (i.e. "allow" above becomes "require"), and make the default one
> done via an invocation of for-each-ref also do the same.
>
> I do not think there was a strong concensus that we need to change
> the internal C API signature, though.  If the function signature for
> the callback between each_ref_fn and alternate_ref_fn were the same,
> I would have opposed to the change, but because they are already
> different, I do not think it is necessary to keep the dummy refname
> parameter that is always passed a meaningless value.
>
> The final series would be
>
>  1/4: peff's "refnames in alternates do nto matter"
>
>  2/4: your "hardcoded for-each-ref becomes just a default"
>
>  3/4: your "config can affect what command enumerates alternate's tips"
>
>  4/4: your "with prefix config, you don't need a fully custom command"
>
> I guess?

Perfect -- we are in agreement on how the rerolled series should be
organized. I don't anticipate much further comment on v2 in this thread,
but I'll let it sit overnight to make sure that the dust has all settled
after my new mail.

I have a version of what will likely become 'v3', pushed here: [1].

Thanks,
Taylor

[1]: https://github.com/ttaylorr/git/tree/tb/alternate-refs-cmd


Re: [PATCH v2 2/3] transport.c: introduce core.alternateRefsCommand

2018-09-25 Thread Taylor Blau
On Sat, Sep 22, 2018 at 03:52:58PM -0400, Jeff King wrote:
> On Sat, Sep 22, 2018 at 06:02:31PM +, brian m. carlson wrote:
>
> > On Fri, Sep 21, 2018 at 02:47:43PM -0400, Taylor Blau wrote:
> > > +expect_haves () {
> > > + printf "%s .have\n" $(git rev-parse $@) >expect
> > > +}
> > > +
> > > +extract_haves () {
> > > + depacketize - | grep '\.have' | sed -e 's/\\0.*$//g'
> >
> > It looks like you're trying to match a NUL here in the sed expression,
> > but from my reading of it, POSIX doesn't permit BREs to match NUL.
>
> No, it's trying to literally match backslash followed by 0. The
> depacketize() script will have undone the NUL already. In perl, no less,
> making it more or less equivalent to your suggestion. ;)
>
> So I think this is fine (modulo that the grep and sed can be combined).
> Yet another option would be to simply strip away everything except the
> object id (which is all we care about), like:
>
>   depacketize | perl -lne '/^(\S+) \.have/ and print $1'

Thanks for this. This is the suggestion I ended up taking (modulo taking
'-' as the first argument to 'depacketize').

The 'print $1' part of this makes things a lot nicer, actually, having
removed the " .have" suffix. We can get rid of the expect_haves()
function above, and instead call 'git rev-parse' inline and get the
right results.

> Or the equivalent in sed. I am happy with any solution that does the
> correct thing.

Me too :-). Thanks again.

Thanks,
Taylor


Re: [PATCH v2 2/3] transport.c: introduce core.alternateRefsCommand

2018-09-25 Thread Taylor Blau
On Fri, Sep 21, 2018 at 02:09:08PM -0700, Junio C Hamano wrote:
> Taylor Blau  writes:
>
> > +core.alternateRefsCommand::
> > +   When listing references from an alternate (e.g., in the case of 
> > ".have"), use
>
> It is not clear how (e.g.,...) connects to what is said in the
> sentence.  "When advertising tips of available history from an
> alternate, use ..." without saying ".have" may be less cryptic.
>
> I dunno.

Thanks, I think that I tend to overuse both "e.g.," and "i.e.,". I took
your suggestion as above, which I think looks better than my original
prose.

> > +   the shell to execute the specified command instead of
> > +   linkgit:git-for-each-ref[1]. The first argument is the path of the 
> > alternate.
>
> "The path" meaning the absolute path?  Relative to the original
> object store?  Something else?

It's the absolute path, and I've updated the documentation to clarify it
as such.

> > +   Output must be of the form: `%(objectname) SPC %(refname)`.
> > ++
> > +This is useful when a repository only wishes to advertise some of its
> > +alternate's references as ".have"'s. For example, to only advertise branch
> > +heads, configure `core.alternateRefsCommand` to the path of a script which 
> > runs
> > +`git --git-dir="$1" for-each-ref refs/heads`.
> > +
> >  core.bare::
> > If true this repository is assumed to be 'bare' and has no
> > working directory associated with it.  If this is the case a
> > diff --git a/t/t5410-receive-pack.sh b/t/t5410-receive-pack.sh
> > new file mode 100755
> > index 00..2f21f1cb8f
> > --- /dev/null
> > +++ b/t/t5410-receive-pack.sh
> > @@ -0,0 +1,54 @@
> > +#!/bin/sh
> > +
> > +test_description='git receive-pack test'
> > +
> > +. ./test-lib.sh
> > +
> > +test_expect_success 'setup' '
> > +   test_commit one &&
> > +   git update-ref refs/heads/a HEAD &&
> > +   test_commit two &&
> > +   git update-ref refs/heads/b HEAD &&
> > +   test_commit three &&
> > +   git update-ref refs/heads/c HEAD &&
> > +   git clone --bare . fork &&
> > +   git clone fork pusher &&
> > +   (
> > +   cd fork &&
> > +   git config receive.advertisealternates true &&
>
> Hmph.  Do we have code to support this configuration variable?

We don't ;-). Peff's explanation of why is accurate, and the mistake is
mine.

> > +   cat <<-EOF | git update-ref --stdin &&
>
> Style: writing "<<-\EOF" instead would allow readers' eyes to
> coast over without having to look for $variable_references in
> the here-doc.
>
> > +   delete refs/heads/a
> > +   delete refs/heads/b
> > +   delete refs/heads/c
> > +   delete refs/heads/master
> > +   delete refs/tags/one
> > +   delete refs/tags/two
> > +   delete refs/tags/three

Thanks, it ended up being much cleaner to write <<-\EOF, and avoid the
unnecessary cat(1) entirely.

> So, the original created one/two/three/a/b/c/master, fork is a bare
> clone of it and has all these things, and then you deleted all of
> these?  What does fork have after this is done?  HEAD that is
> dangling?
>
> > +   EOF
> > +   echo "../../.git/objects" >objects/info/alternates
>
> When viewed from fork/objects, ../../.git is the GIT_DIR of the
> primary test repository, so that is where we borrow objects from.
>
> If we pruned the objects from fork's object store before this echo,
> we would have an almost empty repository that borrows from its
> alternates everything, which may make a more realistic sample case,
> but because you are only focusing on the ref advertisement, it does
> not matter that your fork is full of duplicate objects that are
> available from the alternates.

I could go either way. You're right in that we have only a dangling HEAD
reference in the fork, and that all of the objects are still there. I
suppose that we could gc the objects that are there, but I think (as you
note above) that it doesn't make a huge difference either way.

> > +expect_haves () {
> > +   printf "%s .have\n" $(git rev-parse $@) >expect
>
> Quote $@ inside dq pair, like $(git rev-parse "$@").

Thanks, I fixed this (per your and Eric's suggestion), but ended up
removing the function entirely anyway.

> > +extract_haves () {
> > +   depacketize - | grep '\.have' | sed -e 's/\\0.*$//g'
> > +}
>
> Don't pipe grep into sed, especially when both the pattern to filter
> and the operation to perform are simple.
>
> I am not sure what you are trying to achive with 'g' in
> s/pattern$//g; The anchor at the rightmost end of the pattern makes
> sure that the pattern matches only once per line at the end anyway,
> so "do this howmanyever times as we have match on each line" would
> not make any difference, no?

I admit to not fully understanding when the trailing `/g` is and is not
useful. Anyway, I took Peff's suggestion below to convert this 'grep |
sed' pipeline into a Perl invocation, which I think ended up much
cleaner.

Thanks,
Taylor


Re: [PATCH v2 2/3] transport.c: introduce core.alternateRefsCommand

2018-09-25 Thread Taylor Blau
On Fri, Sep 21, 2018 at 04:18:03PM -0400, Eric Sunshine wrote:
> On Fri, Sep 21, 2018 at 2:47 PM Taylor Blau  wrote:
> > When in a repository containing one or more alternates, Git would
> > sometimes like to list references from its alternates. For example, 'git
> > receive-pack' list the objects pointed to by alternate references as
> > special ".have" references.
> > [...]
> > Signed-off-by: Taylor Blau 
> > ---
> > diff --git a/t/t5410-receive-pack.sh b/t/t5410-receive-pack.sh
> > @@ -0,0 +1,54 @@
> > +expect_haves () {
> > +   printf "%s .have\n" $(git rev-parse $@) >expect
> > +}
>
> Magic quoting behavior only kicks in when $@ is itself quoted, so this
> should be:
>
> printf "%s .have\n" $(git rev-parse "$@") >expect
>
> However, as it's unlikely that you need magic quoting in this case,
> you might get by with plain $* (unquoted).

Yep, thanks for catching my mistake. I rewrote my local copy with "$@"
(instead of $@), and also applied your suggestion of not redirecting to
`>expect`, and renaming the function.

These both ended up becoming moot points, though, because of the
Perl-ism that Peff suggested and I adopted throughout this thread.

The Perl Peff wrote does not capture the " .have" suffix at all, and
instead only the object identifiers. Hence, all we really need is a call
to 'git-rev-parse(1)'. I doubt that this will ever change, so I removed
the function entirely.

Thanks,
Taylor


Re: [PATCH 2/3] transport.c: introduce core.alternateRefsCommand

2018-09-25 Thread Taylor Blau
On Fri, Sep 21, 2018 at 12:59:16PM -0700, Junio C Hamano wrote:
> Taylor Blau  writes:
>
> > In fact, I think that we can go even further: since we don't need to
> > catch the beginning '^.*' (without -o), we can instead:
> >
> >   extract_haves () {
> > depacketize - | grep '\.have' | sed -e 's/\\0.*$//g'
> >   }
>
> Do not pipe grep into sed, unless you have an overly elaborate set
> of patterns to filter with, e.g. something along the lines of...
>
>   sed -ne '/\.have/s/...//p'

Thanks, I'm not sure why I thought that this was a good idea to send
(even after discussing it to myself twice publicly on the list
beforehand).

Anyway, in my local copy, I adopted Peff's suggestion below in the
thread, which is:

  extract_haves () {
depacketize - | perl -lne '/^(\S+) \.have/ and print $1'
  }

I think that that should be OK, but I sent it here to double check
before sending you real patches.

Thanks,
Taylor


[no subject]

2018-09-25 Thread SUMITOIMO




--
Did you receive our proposal email ?


Re: [PATCH v2 3/3] transport.c: introduce core.alternateRefsPrefixes

2018-09-25 Thread Junio C Hamano
Taylor Blau  writes:

> My reading of this is threefold:
>
>   1. There are some cosmetic changes that need to occur in t5410 and
>  documentation, which are mentioned above. Those seem self
>  explanatory, and I've applied the necessary bits already on my
>  local version of this topic.
>
>   2. The core.alternateRefsCommand vs transport.* discussion was
>  resolved in [1] as "let's use core.alternateRefsCommand and
>  core.alternateRefsPrefixes" for now, and others contributors can
>  change this as is needed.
>
>   3. We can apply Peff's patch to remove the refname requirement before
>  mine, as well as any relevant changes in my series as have been
>  affected by Peff's patch (e.g., documentation mentioning
>  '%(refname)', etc).

I do think it makes sense to allow alternateRefsCommand to output
just the object names without adding any refnames, and to keep the
parser simple, we should not even make the refname optional
(i.e. "allow" above becomes "require"), and make the default one
done via an invocation of for-each-ref also do the same.

I do not think there was a strong concensus that we need to change
the internal C API signature, though.  If the function signature for
the callback between each_ref_fn and alternate_ref_fn were the same,
I would have opposed to the change, but because they are already
different, I do not think it is necessary to keep the dummy refname
parameter that is always passed a meaningless value.

The final series would be

 1/4: peff's "refnames in alternates do nto matter"

 2/4: your "hardcoded for-each-ref becomes just a default"

 3/4: your "config can affect what command enumerates alternate's tips"

 4/4: your "with prefix config, you don't need a fully custom command"

I guess?


Re: [RFC PATCH] transport: list refs before fetch if necessary

2018-09-25 Thread Junio C Hamano
Jonathan Tan  writes:

> diff --git a/transport-helper.c b/transport-helper.c
> index 143ca008c8..7213fa0d32 100644
> --- a/transport-helper.c
> +++ b/transport-helper.c
> @@ -1105,6 +1105,7 @@ static struct ref *get_refs_list(struct transport 
> *transport, int for_push,
>  }
>  
>  static struct transport_vtable vtable = {
> + 0,
>   set_helper_option,
>   get_refs_list,
>   fetch,
> diff --git a/transport-internal.h b/transport-internal.h
> index 1cde6258a7..004bee5e36 100644
> --- a/transport-internal.h
> +++ b/transport-internal.h
> @@ -6,6 +6,12 @@ struct transport;
>  struct argv_array;
>  
>  struct transport_vtable {
> + /**
> +  * This transport supports the fetch() function being called
> +  * without get_refs_list() first being called.
> +  */
> + unsigned fetch_without_list : 1;
> +
>   /**
>* Returns 0 if successful, positive if the option is not
>* recognized or is inapplicable, and negative if the option
> diff --git a/transport.c b/transport.c
> index 1c76d64aba..ee8a78ff37 100644
> --- a/transport.c
> +++ b/transport.c
> @@ -703,6 +703,7 @@ static int disconnect_git(struct transport *transport)
>  }
>  
>  static struct transport_vtable taken_over_vtable = {
> + 1,
>   NULL,
>   get_refs_via_connect,
>   fetch_refs_via_pack,
> @@ -852,6 +853,7 @@ void transport_check_allowed(const char *type)
>  }
>  
>  static struct transport_vtable bundle_vtable = {
> + 0,
>   NULL,
>   get_refs_from_bundle,
>   fetch_refs_from_bundle,
> @@ -861,6 +863,7 @@ static struct transport_vtable bundle_vtable = {
>  };
>  
>  static struct transport_vtable builtin_smart_vtable = {
> + 1,
>   NULL,
>   get_refs_via_connect,
>   fetch_refs_via_pack,

Up to this point I think I understand the change.  We gain one new
trait for each transport, many of the transport cannot run fetch
without first seeing the advertisement, some are OK, so we have 0 or
1 in these vtables as appropriately.

> @@ -1224,6 +1227,15 @@ int transport_fetch_refs(struct transport *transport, 
> struct ref *refs)
>   struct ref **heads = NULL;
>   struct ref *rm;
>  
> + if (!transport->vtable->fetch_without_list)
> + /*
> +  * Some transports (e.g. the built-in bundle transport and the
> +  * transport helper interface) do not work when fetching is
> +  * done immediately after transport creation. List the remote
> +  * refs anyway (if not already listed) as a workaround.
> +  */
> + transport_get_remote_refs(transport, NULL);
> +

But this I do not quite understand.  It looks saying "when asked to
fetch, if the transport does not allow us to do so without first
getting the advertisement, lazily do that", and that may be a good
thing to do, but then aren't the current set of callers already
calling transport-get-remote-refs elsewhere before they call
transport-fetch-refs?  IOW, I would have expected to see a matching
removal, or at least a code that turns an unconditional call to
get-remote-refs to a conditional one that is done only for the
transport that lacks the capability, or something along that line.

... ah, do you mean that this is not a new feature, but is a bugfix
for some callers that are not calling get-remote-refs before calling
fetch-refs, and the bit is to work around the fact that some
transport not just can function without get-remote-refs first but do
not want to call it?

IOW, I am a bit confused by this comment (copied from an earlier part)

> + /**
> +  * This transport supports the fetch() function being called
> +  * without get_refs_list() first being called.
> +  */

Shouldn't it read more like "this transport does not want its
get-refs-list called when fetch-refs is done"?

I dunno.


>   for (rm = refs; rm; rm = rm->next) {
>   nr_refs++;
>   if (rm->peer_ref &&


[RFC PATCH] transport: list refs before fetch if necessary

2018-09-25 Thread Jonathan Tan
The built-in bundle transport and the transport helper interface do not
work when transport_fetch_refs() is called immediately after transport
creation.

Evidence: fetch_refs_from_bundle() relies on data->header being
initialized in get_refs_from_bundle(), and fetch() in transport-helper.c
relies on either data->fetch or data->import being set by get_helper(),
but neither transport_helper_init() nor fetch() calls get_helper().

Up until the introduction of the partial clone feature, this has not
been a problem, because transport_fetch_refs() is always called after
transport_get_remote_refs(). With the introduction of the partial clone
feature, which involves calling transport_fetch_refs() (to fetch objects
by their OIDs) without transport_get_remote_refs(), this is still not a
problem, but only coincidentally - we do not support partially cloning a
bundle, and as for cloning using a transport-helper-using protocol, it
so happens that before transport_fetch_refs() is called, fetch_refs() in
fetch-object.c calls transport_set_option(), which means that the
aforementioned get_helper() is invoked through set_helper_option() in
transport-helper.c. In the future, though, there may be other use cases
in which we want to fetch without requiring listing of remote refs, so
this is still worth fixing.

This could be fixed by fixing the transports themselves, but it doesn't
seem like a good idea to me to open up previously untested code paths;
also, there may be transport helpers in the wild that assume that "list"
is always called before "fetch". Instead, fix this by having
transport_fetch_refs() call transport_get_remote_refs() to ensure that
the latter is always called at least once, unless the transport
explicitly states that it supports fetching without listing refs.

Signed-off-by: Jonathan Tan 
---
I discovered this while investigating the possibility of taking
advantage of the fact that protocol v2 allows us to fetch without first
invoking ls-refs. This is useful both when lazily fetching to a partial
clone, and when invoking "git fetch --no-tags  " (note
that tag following must be disabled).

Any comments on this (for or against) is appreciated, and suggestions of
better approaches are appreciated too.
---
 transport-helper.c   |  1 +
 transport-internal.h |  6 ++
 transport.c  | 12 
 3 files changed, 19 insertions(+)

diff --git a/transport-helper.c b/transport-helper.c
index 143ca008c8..7213fa0d32 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -1105,6 +1105,7 @@ static struct ref *get_refs_list(struct transport 
*transport, int for_push,
 }
 
 static struct transport_vtable vtable = {
+   0,
set_helper_option,
get_refs_list,
fetch,
diff --git a/transport-internal.h b/transport-internal.h
index 1cde6258a7..004bee5e36 100644
--- a/transport-internal.h
+++ b/transport-internal.h
@@ -6,6 +6,12 @@ struct transport;
 struct argv_array;
 
 struct transport_vtable {
+   /**
+* This transport supports the fetch() function being called
+* without get_refs_list() first being called.
+*/
+   unsigned fetch_without_list : 1;
+
/**
 * Returns 0 if successful, positive if the option is not
 * recognized or is inapplicable, and negative if the option
diff --git a/transport.c b/transport.c
index 1c76d64aba..ee8a78ff37 100644
--- a/transport.c
+++ b/transport.c
@@ -703,6 +703,7 @@ static int disconnect_git(struct transport *transport)
 }
 
 static struct transport_vtable taken_over_vtable = {
+   1,
NULL,
get_refs_via_connect,
fetch_refs_via_pack,
@@ -852,6 +853,7 @@ void transport_check_allowed(const char *type)
 }
 
 static struct transport_vtable bundle_vtable = {
+   0,
NULL,
get_refs_from_bundle,
fetch_refs_from_bundle,
@@ -861,6 +863,7 @@ static struct transport_vtable bundle_vtable = {
 };
 
 static struct transport_vtable builtin_smart_vtable = {
+   1,
NULL,
get_refs_via_connect,
fetch_refs_via_pack,
@@ -1224,6 +1227,15 @@ int transport_fetch_refs(struct transport *transport, 
struct ref *refs)
struct ref **heads = NULL;
struct ref *rm;
 
+   if (!transport->vtable->fetch_without_list)
+   /*
+* Some transports (e.g. the built-in bundle transport and the
+* transport helper interface) do not work when fetching is
+* done immediately after transport creation. List the remote
+* refs anyway (if not already listed) as a workaround.
+*/
+   transport_get_remote_refs(transport, NULL);
+
for (rm = refs; rm; rm = rm->next) {
nr_refs++;
if (rm->peer_ref &&
-- 
2.19.0.605.g01d371f741-goog



Re: [PATCH v2 3/3] transport.c: introduce core.alternateRefsPrefixes

2018-09-25 Thread Taylor Blau
On Tue, Sep 25, 2018 at 10:41:18AM -0700, Junio C Hamano wrote:
> Jeff King  writes:
>
> > Right, I think that is totally fine for the current uses. I guess my
> > question was: do you envision cutting the interface down to only the
> > oids to bite us in the future?
> >
> > I was on the fence during past discussions, but I think I've come over
> > to the idea that the refnames actively confuse things.
>
> [ ... ]
>
> So, I think we probably are better off without names.

Sorry for re-entering the thread a little later. I was travelling
yesterday, and was surprised when I discovered that our "grep | sed" vs.
"sed" discussion had grown so much ;-).

My reading of this is threefold:

  1. There are some cosmetic changes that need to occur in t5410 and
 documentation, which are mentioned above. Those seem self
 explanatory, and I've applied the necessary bits already on my
 local version of this topic.

  2. The core.alternateRefsCommand vs transport.* discussion was
 resolved in [1] as "let's use core.alternateRefsCommand and
 core.alternateRefsPrefixes" for now, and others contributors can
 change this as is needed.

  3. We can apply Peff's patch to remove the refname requirement before
 mine, as well as any relevant changes in my series as have been
 affected by Peff's patch (e.g., documentation mentioning
 '%(refname)', etc).

Does this all sound sane to you (and match your recollection/reading of
the thread)? If so, I'll send v3 hopefully tomorrow.

Sorry for repeating what's already been said in this thread, but I felt
it was important to ensure that we had matching understandings of one
another.

Thanks,
Taylor

[1]: https://public-inbox.org/git/xmqqa7o6skkl@gitster-ct.c.googlers.com/


[PATCH v9 07/21] stash: convert apply to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
From: Joel Teichroeb 

Add a builtin helper for performing stash commands. Converting
all at once proved hard to review, so starting with just apply
lets conversion get started without the other commands being
finished.

The helper is being implemented as a drop in replacement for
stash so that when it is complete it can simply be renamed and
the shell script deleted.

Delete the contents of the apply_stash shell function and replace
it with a call to stash--helper apply until pop is also
converted.

Signed-off-by: Joel Teichroeb 
Signed-off-by: Paul-Sebastian Ungureanu 
---
 .gitignore  |   1 +
 Makefile|   1 +
 builtin.h   |   1 +
 builtin/stash--helper.c | 452 
 git-stash.sh|  78 +--
 git.c   |   1 +
 6 files changed, 463 insertions(+), 71 deletions(-)
 create mode 100644 builtin/stash--helper.c

diff --git a/.gitignore b/.gitignore
index ffceea7d59..b59661cb88 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,6 +157,7 @@
 /git-show-ref
 /git-stage
 /git-stash
+/git-stash--helper
 /git-status
 /git-stripspace
 /git-submodule
diff --git a/Makefile b/Makefile
index d03df31c2a..f900c68e69 100644
--- a/Makefile
+++ b/Makefile
@@ -1093,6 +1093,7 @@ BUILTIN_OBJS += builtin/shortlog.o
 BUILTIN_OBJS += builtin/show-branch.o
 BUILTIN_OBJS += builtin/show-index.o
 BUILTIN_OBJS += builtin/show-ref.o
+BUILTIN_OBJS += builtin/stash--helper.o
 BUILTIN_OBJS += builtin/stripspace.o
 BUILTIN_OBJS += builtin/submodule--helper.o
 BUILTIN_OBJS += builtin/symbolic-ref.o
diff --git a/builtin.h b/builtin.h
index 99206df4bd..317bc338f7 100644
--- a/builtin.h
+++ b/builtin.h
@@ -223,6 +223,7 @@ extern int cmd_show(int argc, const char **argv, const char 
*prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
 extern int cmd_show_index(int argc, const char **argv, const char *prefix);
 extern int cmd_status(int argc, const char **argv, const char *prefix);
+extern int cmd_stash__helper(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_submodule__helper(int argc, const char **argv, const char 
*prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
new file mode 100644
index 00..7819dae332
--- /dev/null
+++ b/builtin/stash--helper.c
@@ -0,0 +1,452 @@
+#include "builtin.h"
+#include "config.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "lockfile.h"
+#include "cache-tree.h"
+#include "unpack-trees.h"
+#include "merge-recursive.h"
+#include "argv-array.h"
+#include "run-command.h"
+#include "dir.h"
+#include "rerere.h"
+
+static const char * const git_stash_helper_usage[] = {
+   N_("git stash--helper apply [--index] [-q|--quiet] []"),
+   NULL
+};
+
+static const char * const git_stash_helper_apply_usage[] = {
+   N_("git stash--helper apply [--index] [-q|--quiet] []"),
+   NULL
+};
+
+static const char *ref_stash = "refs/stash";
+static struct strbuf stash_index_path = STRBUF_INIT;
+
+/*
+ * w_commit is set to the commit containing the working tree
+ * b_commit is set to the base commit
+ * i_commit is set to the commit containing the index tree
+ * u_commit is set to the commit containing the untracked files tree
+ * w_tree is set to the working tree
+ * b_tree is set to the base tree
+ * i_tree is set to the index tree
+ * u_tree is set to the untracked files tree
+ */
+
+struct stash_info {
+   struct object_id w_commit;
+   struct object_id b_commit;
+   struct object_id i_commit;
+   struct object_id u_commit;
+   struct object_id w_tree;
+   struct object_id b_tree;
+   struct object_id i_tree;
+   struct object_id u_tree;
+   struct strbuf revision;
+   int is_stash_ref;
+   int has_u;
+};
+
+static void free_stash_info(struct stash_info *info)
+{
+   strbuf_release(>revision);
+}
+
+static void assert_stash_like(struct stash_info *info, const char *revision)
+{
+   if (get_oidf(>b_commit, "%s^1", revision) ||
+   get_oidf(>w_tree, "%s:", revision) ||
+   get_oidf(>b_tree, "%s^1:", revision) ||
+   get_oidf(>i_tree, "%s^2:", revision)) {
+   free_stash_info(info);
+   error(_("'%s' is not a stash-like commit"), revision);
+   exit(128);
+   }
+}
+
+static int get_stash_info(struct stash_info *info, int argc, const char **argv)
+{
+   int ret;
+   char *end_of_rev;
+   char *expanded_ref;
+   const char *revision;
+   const char *commit = NULL;
+   struct object_id dummy;
+   struct strbuf symbolic = STRBUF_INIT;
+
+   if (argc > 1) {
+   int i;
+   struct strbuf refs_msg = STRBUF_INIT;
+   for (i = 0; i < argc; i++)
+   strbuf_addf(_msg, " '%s'", argv[i]);
+

[GSoC][PATCH v9 06/21] strbuf.c: add `strbuf_join_argv()`

2018-09-25 Thread Paul-Sebastian Ungureanu
Implement `strbuf_join_argv()` to join arguments.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 strbuf.c | 15 +++
 strbuf.h |  7 +++
 2 files changed, 22 insertions(+)

diff --git a/strbuf.c b/strbuf.c
index 64041c3c24..3eb431b2b0 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -259,6 +259,21 @@ void strbuf_addbuf(struct strbuf *sb, const struct strbuf 
*sb2)
strbuf_setlen(sb, sb->len + sb2->len);
 }
 
+const char *strbuf_join_argv(struct strbuf *buf,
+int argc, const char **argv, char delim)
+{
+   if (!argc)
+   return buf->buf;
+
+   strbuf_addstr(buf, *argv);
+   while (--argc) {
+   strbuf_addch(buf, delim);
+   strbuf_addstr(buf, *(++argv));
+   }
+
+   return buf->buf;
+}
+
 void strbuf_addchars(struct strbuf *sb, int c, size_t n)
 {
strbuf_grow(sb, n);
diff --git a/strbuf.h b/strbuf.h
index 60a35aef16..7ed859bb8a 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -284,6 +284,13 @@ static inline void strbuf_addstr(struct strbuf *sb, const 
char *s)
  */
 extern void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
 
+
+/**
+ *
+ */
+extern const char *strbuf_join_argv(struct strbuf *buf, int argc,
+   const char **argv, char delim);
+
 /**
  * This function can be used to expand a format string containing
  * placeholders. To that end, it parses the string and calls the specified
-- 
2.19.0.rc0.23.g1c0a08a5d3



[PATCH v9 19/21] stash: convert `stash--helper.c` into `stash.c`

2018-09-25 Thread Paul-Sebastian Ungureanu
The old shell script `git-stash.sh`  was removed and replaced
entirely by `builtin/stash.c`. In order to do that, `create` and
`push` were adapted to work without `stash.sh`. For example, before
this commit, `git stash create` called `git stash--helper create
--message "$*"`. If it called `git stash--helper create "$@"`, then
some of these changes wouldn't have been necessary.

This commit also removes the word `helper` since now stash is
called directly and not by a shell script.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 .gitignore   |   1 -
 Makefile |   3 +-
 builtin.h|   2 +-
 builtin/{stash--helper.c => stash.c} | 162 ---
 git-stash.sh | 153 -
 git.c|   2 +-
 6 files changed, 98 insertions(+), 225 deletions(-)
 rename builtin/{stash--helper.c => stash.c} (90%)
 delete mode 100755 git-stash.sh

diff --git a/.gitignore b/.gitignore
index b59661cb88..ffceea7d59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,7 +157,6 @@
 /git-show-ref
 /git-stage
 /git-stash
-/git-stash--helper
 /git-status
 /git-stripspace
 /git-submodule
diff --git a/Makefile b/Makefile
index f900c68e69..ac1787d113 100644
--- a/Makefile
+++ b/Makefile
@@ -617,7 +617,6 @@ SCRIPT_SH += git-quiltimport.sh
 SCRIPT_SH += git-rebase.sh
 SCRIPT_SH += git-remote-testgit.sh
 SCRIPT_SH += git-request-pull.sh
-SCRIPT_SH += git-stash.sh
 SCRIPT_SH += git-submodule.sh
 SCRIPT_SH += git-web--browse.sh
 
@@ -1093,7 +1092,7 @@ BUILTIN_OBJS += builtin/shortlog.o
 BUILTIN_OBJS += builtin/show-branch.o
 BUILTIN_OBJS += builtin/show-index.o
 BUILTIN_OBJS += builtin/show-ref.o
-BUILTIN_OBJS += builtin/stash--helper.o
+BUILTIN_OBJS += builtin/stash.o
 BUILTIN_OBJS += builtin/stripspace.o
 BUILTIN_OBJS += builtin/submodule--helper.o
 BUILTIN_OBJS += builtin/symbolic-ref.o
diff --git a/builtin.h b/builtin.h
index 317bc338f7..e60f0fc58f 100644
--- a/builtin.h
+++ b/builtin.h
@@ -223,7 +223,7 @@ extern int cmd_show(int argc, const char **argv, const char 
*prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
 extern int cmd_show_index(int argc, const char **argv, const char *prefix);
 extern int cmd_status(int argc, const char **argv, const char *prefix);
-extern int cmd_stash__helper(int argc, const char **argv, const char *prefix);
+extern int cmd_stash(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_submodule__helper(int argc, const char **argv, const char 
*prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
diff --git a/builtin/stash--helper.c b/builtin/stash.c
similarity index 90%
rename from builtin/stash--helper.c
rename to builtin/stash.c
index 96689a00e9..fc4a2050b1 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash.c
@@ -16,75 +16,70 @@
 
 #define INCLUDE_ALL_FILES 2
 
-static const char * const git_stash_helper_usage[] = {
-   N_("git stash--helper list []"),
-   N_("git stash--helper show [] []"),
-   N_("git stash--helper drop [-q|--quiet] []"),
-   N_("git stash--helper ( pop | apply ) [--index] [-q|--quiet] 
[]"),
-   N_("git stash--helper branch  []"),
-   N_("git stash--helper clear"),
-   N_("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] 
[-q|--quiet]\n"
+static const char * const git_stash_usage[] = {
+   N_("git stash list []"),
+   N_("git stash show [] []"),
+   N_("git stash drop [-q|--quiet] []"),
+   N_("git stash ( pop | apply ) [--index] [-q|--quiet] []"),
+   N_("git stash branch  []"),
+   N_("git stash clear"),
+   N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
   "  [-u|--include-untracked] [-a|--all] [-m|--message 
]\n"
   "  [--] [...]]"),
-   N_("git stash--helper save [-p|--patch] [-k|--[no-]keep-index] 
[-q|--quiet]\n"
+   N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
   "  [-u|--include-untracked] [-a|--all] []"),
NULL
 };
 
-static const char * const git_stash_helper_list_usage[] = {
-   N_("git stash--helper list []"),
+static const char * const git_stash_list_usage[] = {
+   N_("git stash list []"),
NULL
 };
 
-static const char * const git_stash_helper_show_usage[] = {
-   N_("git stash--helper show [] []"),
+static const char * const git_stash_show_usage[] = {
+   N_("git stash show [] []"),
NULL
 };
 
-static const char * const git_stash_helper_drop_usage[] = {
-   N_("git stash--helper drop [-q|--quiet] []"),
+static const char * const git_stash_drop_usage[] = {
+   N_("git stash drop [-q|--quiet] []"),
NULL
 };
 
-static const char * const git_stash_helper_pop_usage[] = {
-   N_("git stash--helper pop [--index] [-q|--quiet] []"),

[PATCH v9 14/21] stash: convert store to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
Add stash store to the helper and delete the store_stash function
from the shell script.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c | 60 +
 git-stash.sh| 43 ++---
 2 files changed, 62 insertions(+), 41 deletions(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index 1f02f5f2e9..b7421b68aa 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -58,6 +58,11 @@ static const char * const git_stash_helper_clear_usage[] = {
NULL
 };
 
+static const char * const git_stash_helper_store_usage[] = {
+   N_("git stash--helper store [-m|--message ] [-q|--quiet] 
"),
+   NULL
+};
+
 static const char *ref_stash = "refs/stash";
 static struct strbuf stash_index_path = STRBUF_INIT;
 
@@ -728,6 +733,59 @@ static int show_stash(int argc, const char **argv, const 
char *prefix)
return diff_result_code(, 0);
 }
 
+static int do_store_stash(const struct object_id *w_commit, const char 
*stash_msg,
+ int quiet)
+{
+   if (!stash_msg)
+   stash_msg = "Created via \"git stash store\".";
+
+   if (update_ref(stash_msg, ref_stash, w_commit, NULL,
+  REF_FORCE_CREATE_REFLOG,
+  quiet ? UPDATE_REFS_QUIET_ON_ERR :
+  UPDATE_REFS_MSG_ON_ERR)) {
+   if (!quiet) {
+   fprintf_ln(stderr, _("Cannot update %s with %s"),
+  ref_stash, oid_to_hex(w_commit));
+   }
+   return -1;
+   }
+
+   return 0;
+}
+
+static int store_stash(int argc, const char **argv, const char *prefix)
+{
+   int quiet = 0;
+   const char *stash_msg = NULL;
+   struct object_id obj;
+   struct object_context dummy;
+   struct option options[] = {
+   OPT__QUIET(, N_("be quiet")),
+   OPT_STRING('m', "message", _msg, "message", N_("stash 
message")),
+   OPT_END()
+   };
+
+   argc = parse_options(argc, argv, prefix, options,
+git_stash_helper_store_usage,
+PARSE_OPT_KEEP_UNKNOWN);
+
+   if (argc != 1) {
+   if (!quiet)
+   fprintf_ln(stderr, _("\"git stash store\" requires one 
 argument"));
+   return -1;
+   }
+
+   if (get_oid_with_context(argv[0], quiet ? GET_OID_QUIETLY : 0, ,
+)) {
+   if (!quiet)
+   fprintf_ln(stderr, _("Cannot update %s with %s"),
+ref_stash, argv[0]);
+   return -1;
+   }
+
+   return do_store_stash(, stash_msg, quiet);
+}
+
 int cmd_stash__helper(int argc, const char **argv, const char *prefix)
 {
pid_t pid = getpid();
@@ -762,6 +820,8 @@ int cmd_stash__helper(int argc, const char **argv, const 
char *prefix)
return !!list_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "show"))
return !!show_stash(argc, argv, prefix);
+   else if (!strcmp(argv[0], "store"))
+   return !!store_stash(argc, argv, prefix);
 
usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
  git_stash_helper_usage, options);
diff --git a/git-stash.sh b/git-stash.sh
index 0d05cbc1e5..5739c51527 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -191,45 +191,6 @@ create_stash () {
die "$(gettext "Cannot record working tree state")"
 }
 
-store_stash () {
-   while test $# != 0
-   do
-   case "$1" in
-   -m|--message)
-   shift
-   stash_msg="$1"
-   ;;
-   -m*)
-   stash_msg=${1#-m}
-   ;;
-   --message=*)
-   stash_msg=${1#--message=}
-   ;;
-   -q|--quiet)
-   quiet=t
-   ;;
-   *)
-   break
-   ;;
-   esac
-   shift
-   done
-   test $# = 1 ||
-   die "$(eval_gettext "\"$dashless store\" requires one  
argument")"
-
-   w_commit="$1"
-   if test -z "$stash_msg"
-   then
-   stash_msg="Created via \"git stash store\"."
-   fi
-
-   git update-ref --create-reflog -m "$stash_msg" $ref_stash $w_commit
-   ret=$?
-   test $ret != 0 && test -z "$quiet" &&
-   die "$(eval_gettext "Cannot update \$ref_stash with \$w_commit")"
-   return $ret
-}
-
 push_stash () {
keep_index=
patch_mode=
@@ -308,7 +269,7 @@ push_stash () {
clear_stash || die "$(gettext "Cannot initialize stash")"
 
create_stash -m "$stash_msg" -u "$untracked" -- "$@"
-   store_stash -m "$stash_msg" -q $w_commit ||
+   git 

[PATCH v9 15/21] stash: convert create to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
Add stash create to the helper.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c | 450 
 git-stash.sh|   2 +-
 2 files changed, 451 insertions(+), 1 deletion(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index b7421b68aa..49b05f2458 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -12,6 +12,9 @@
 #include "rerere.h"
 #include "revision.h"
 #include "log-tree.h"
+#include "diffcore.h"
+
+#define INCLUDE_ALL_FILES 2
 
 static const char * const git_stash_helper_usage[] = {
N_("git stash--helper list []"),
@@ -63,6 +66,11 @@ static const char * const git_stash_helper_store_usage[] = {
NULL
 };
 
+static const char * const git_stash_helper_create_usage[] = {
+   N_("git stash--helper create []"),
+   NULL
+};
+
 static const char *ref_stash = "refs/stash";
 static struct strbuf stash_index_path = STRBUF_INIT;
 
@@ -289,6 +297,24 @@ static int reset_head(void)
return run_command();
 }
 
+static void add_diff_to_buf(struct diff_queue_struct *q,
+   struct diff_options *options,
+   void *data)
+{
+   int i;
+
+   for (i = 0; i < q->nr; i++) {
+   strbuf_addstr(data, q->queue[i]->one->path);
+
+   /*
+* The reason we add "0" at the end of this strbuf
+* is because we will pass the output further to
+* "git update-index -z ...".
+*/
+   strbuf_addch(data, 0);
+   }
+}
+
 static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
 {
struct child_process cp = CHILD_PROCESS_INIT;
@@ -786,6 +812,428 @@ static int store_stash(int argc, const char **argv, const 
char *prefix)
return do_store_stash(, stash_msg, quiet);
 }
 
+static void add_pathspecs(struct argv_array *args,
+  struct pathspec ps) {
+   int i;
+
+   for (i = 0; i < ps.nr; i++)
+   argv_array_push(args, ps.items[i].match);
+}
+
+/*
+ * `untracked_files` will be filled with the names of untracked files.
+ * The return value is:
+ *
+ * = 0 if there are not any untracked files
+ * > 0 if there are untracked files
+ */
+static int get_untracked_files(struct pathspec ps, int include_untracked,
+  struct strbuf *untracked_files)
+{
+   int i;
+   int max_len;
+   int found = 0;
+   char *seen;
+   struct dir_struct dir;
+
+   memset(, 0, sizeof(dir));
+   if (include_untracked != INCLUDE_ALL_FILES)
+   setup_standard_excludes();
+
+   seen = xcalloc(ps.nr, 1);
+
+   max_len = fill_directory(, the_repository->index, );
+   for (i = 0; i < dir.nr; i++) {
+   struct dir_entry *ent = dir.entries[i];
+   if (dir_path_match(_index, ent, , max_len, seen)) {
+   found++;
+   strbuf_addstr(untracked_files, ent->name);
+   /* NUL-terminate: will be fed to update-index -z */
+   strbuf_addch(untracked_files, 0);
+   }
+   free(ent);
+   }
+
+   free(seen);
+   free(dir.entries);
+   free(dir.ignored);
+   clear_directory();
+   return found;
+}
+
+/*
+ * The return value of `check_changes()` can be:
+ *
+ * < 0 if there was an error
+ * = 0 if there are no changes.
+ * > 0 if there are changes.
+ */
+static int check_changes(struct pathspec ps, int include_untracked)
+{
+   int result;
+   int ret = 0;
+   struct rev_info rev;
+   struct object_id dummy;
+   struct strbuf out = STRBUF_INIT;
+
+   /* No initial commit. */
+   if (get_oid("HEAD", ))
+   return -1;
+
+   if (read_cache() < 0)
+   return -1;
+
+   init_revisions(, NULL);
+   rev.prune_data = ps;
+
+   rev.diffopt.flags.quick = 1;
+   rev.diffopt.flags.ignore_submodules = 1;
+   rev.abbrev = 0;
+
+   add_head_to_pending();
+   diff_setup_done();
+
+   result = run_diff_index(, 1);
+   if (diff_result_code(, result))
+   return 1;
+
+   object_array_clear();
+   result = run_diff_files(, 0);
+   if (diff_result_code(, result))
+   return 1;
+
+   if (include_untracked && get_untracked_files(ps, include_untracked,
+)) {
+   strbuf_release();
+   return 1;
+   }
+
+   strbuf_release();
+   return 0;
+}
+
+static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
+   struct strbuf files)
+{
+   int ret = 0;
+   struct strbuf untracked_msg = STRBUF_INIT;
+   struct strbuf out = STRBUF_INIT;
+   struct child_process cp_upd_index = CHILD_PROCESS_INIT;
+   struct child_process cp_write_tree = CHILD_PROCESS_INIT;
+
+ 

[PATCH v9 08/21] stash: convert drop and clear to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
From: Joel Teichroeb 

Add the drop and clear commands to the builtin helper. These two
are each simple, but are being added together as they are quite
related.

We have to unfortunately keep the drop and clear functions in the
shell script as functions are called with parameters internally
that are not valid when the commands are called externally. Once
pop is converted they can both be removed.

Signed-off-by: Joel Teichroeb 
Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c | 116 
 git-stash.sh|   4 +-
 2 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index 7819dae332..72472eaeb7 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -12,7 +12,14 @@
 #include "rerere.h"
 
 static const char * const git_stash_helper_usage[] = {
+   N_("git stash--helper drop [-q|--quiet] []"),
N_("git stash--helper apply [--index] [-q|--quiet] []"),
+   N_("git stash--helper clear"),
+   NULL
+};
+
+static const char * const git_stash_helper_drop_usage[] = {
+   N_("git stash--helper drop [-q|--quiet] []"),
NULL
 };
 
@@ -21,6 +28,11 @@ static const char * const git_stash_helper_apply_usage[] = {
NULL
 };
 
+static const char * const git_stash_helper_clear_usage[] = {
+   N_("git stash--helper clear"),
+   NULL
+};
+
 static const char *ref_stash = "refs/stash";
 static struct strbuf stash_index_path = STRBUF_INIT;
 
@@ -139,6 +151,31 @@ static int get_stash_info(struct stash_info *info, int 
argc, const char **argv)
return !(ret == 0 || ret == 1);
 }
 
+static int do_clear_stash(void)
+{
+   struct object_id obj;
+   if (get_oid(ref_stash, ))
+   return 0;
+
+   return delete_ref(NULL, ref_stash, , 0);
+}
+
+static int clear_stash(int argc, const char **argv, const char *prefix)
+{
+   struct option options[] = {
+   OPT_END()
+   };
+
+   argc = parse_options(argc, argv, prefix, options,
+git_stash_helper_clear_usage,
+PARSE_OPT_STOP_AT_NON_OPTION);
+
+   if (argc)
+   return error(_("git stash clear with parameters is 
unimplemented"));
+
+   return do_clear_stash();
+}
+
 static int reset_tree(struct object_id *i_tree, int update, int reset)
 {
int nr_trees = 1;
@@ -424,6 +461,81 @@ static int apply_stash(int argc, const char **argv, const 
char *prefix)
return ret;
 }
 
+static int do_drop_stash(const char *prefix, struct stash_info *info, int 
quiet)
+{
+   int ret;
+   struct child_process cp_reflog = CHILD_PROCESS_INIT;
+   struct child_process cp = CHILD_PROCESS_INIT;
+
+   /*
+* reflog does not provide a simple function for deleting refs. One will
+* need to be added to avoid implementing too much reflog code here
+*/
+
+   cp_reflog.git_cmd = 1;
+   argv_array_pushl(_reflog.args, "reflog", "delete", "--updateref",
+"--rewrite", NULL);
+   argv_array_push(_reflog.args, info->revision.buf);
+   ret = run_command(_reflog);
+   if (!ret) {
+   if (!quiet)
+   printf_ln(_("Dropped %s (%s)"), info->revision.buf,
+ oid_to_hex(>w_commit));
+   } else {
+   return error(_("%s: Could not drop stash entry"),
+info->revision.buf);
+   }
+
+   /*
+* This could easily be replaced by get_oid, but currently it will throw
+* a fatal error when a reflog is empty, which we can not recover from.
+*/
+   cp.git_cmd = 1;
+   /* Even though --quiet is specified, rev-parse still outputs the hash */
+   cp.no_stdout = 1;
+   argv_array_pushl(, "rev-parse", "--verify", "--quiet", NULL);
+   argv_array_pushf(, "%s@{0}", ref_stash);
+   ret = run_command();
+
+   /* do_clear_stash if we just dropped the last stash entry */
+   if (ret)
+   do_clear_stash();
+
+   return 0;
+}
+
+static void assert_stash_ref(struct stash_info *info)
+{
+   if (!info->is_stash_ref) {
+   free_stash_info(info);
+   error(_("'%s' is not a stash reference"), info->revision.buf);
+   exit(128);
+   }
+}
+
+static int drop_stash(int argc, const char **argv, const char *prefix)
+{
+   int ret;
+   int quiet = 0;
+   struct stash_info info;
+   struct option options[] = {
+   OPT__QUIET(, N_("be quiet, only report errors")),
+   OPT_END()
+   };
+
+   argc = parse_options(argc, argv, prefix, options,
+git_stash_helper_drop_usage, 0);
+
+   if (get_stash_info(, argc, argv))
+   return -1;
+
+   assert_stash_ref();
+
+   ret = do_drop_stash(prefix, , quiet);
+   free_stash_info();
+   return ret;
+}
+
 int 

[PATCH v9 06/21] stash: add tests for `git stash show` config

2018-09-25 Thread Paul-Sebastian Ungureanu
This commit introduces tests for `git stash show`
config. It tests all the cases where `stash.showStat`
and `stash.showPatch` are unset or set to true / false.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 t/t3907-stash-show-config.sh | 83 
 1 file changed, 83 insertions(+)
 create mode 100755 t/t3907-stash-show-config.sh

diff --git a/t/t3907-stash-show-config.sh b/t/t3907-stash-show-config.sh
new file mode 100755
index 00..10914bba7b
--- /dev/null
+++ b/t/t3907-stash-show-config.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+test_description='Test git stash show configuration.'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+   test_commit file
+'
+
+# takes three parameters:
+# 1. the stash.showStat value (or "")
+# 2. the stash.showPatch value (or "")
+# 3. the diff options of the expected output (or nothing for no output)
+test_stat_and_patch () {
+   if test "" = "$1"
+   then
+   test_unconfig stash.showStat
+   else
+   test_config stash.showStat "$1"
+   fi &&
+
+   if test "" = "$2"
+   then
+   test_unconfig stash.showPatch
+   else
+   test_config stash.showPatch "$2"
+   fi &&
+
+   shift 2 &&
+   echo 2 >file.t &&
+   if test $# != 0
+   then
+   git diff "$@" >expect
+   fi &&
+   git stash &&
+   git stash show >actual &&
+
+   if test $# = 0
+   then
+   test_must_be_empty actual
+   else
+   test_cmp expect actual
+   fi
+}
+
+test_expect_success 'showStat unset showPatch unset' '
+   test_stat_and_patch "" "" --stat
+'
+
+test_expect_success 'showStat unset showPatch false' '
+   test_stat_and_patch "" false --stat
+'
+
+test_expect_success 'showStat unset showPatch true' '
+   test_stat_and_patch "" true --stat -p
+'
+
+test_expect_success 'showStat false showPatch unset' '
+   test_stat_and_patch false ""
+'
+
+test_expect_success 'showStat false showPatch false' '
+   test_stat_and_patch false false
+'
+
+test_expect_success 'showStat false showPatch true' '
+   test_stat_and_patch false true -p
+'
+
+test_expect_success 'showStat true showPatch unset' '
+   test_stat_and_patch true "" --stat
+'
+
+test_expect_success 'showStat true showPatch false' '
+   test_stat_and_patch true false --stat
+'
+
+test_expect_success 'showStat true showPatch true' '
+   test_stat_and_patch true true --stat -p
+'
+
+test_done
-- 
2.19.0.rc0.23.g1fb9f40d88



[PATCH v9 10/21] stash: convert pop to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
From: Joel Teichroeb 

Add stash pop to the helper and delete the pop_stash, drop_stash,
assert_stash_ref functions from the shell script now that they
are no longer needed.

Signed-off-by: Joel Teichroeb 
Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c | 38 -
 git-stash.sh| 47 ++---
 2 files changed, 39 insertions(+), 46 deletions(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index 5841bd0e98..c1f78d3275 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -13,7 +13,7 @@
 
 static const char * const git_stash_helper_usage[] = {
N_("git stash--helper drop [-q|--quiet] []"),
-   N_("git stash--helper apply [--index] [-q|--quiet] []"),
+   N_("git stash--helper ( pop | apply ) [--index] [-q|--quiet] 
[]"),
N_("git stash--helper branch  []"),
N_("git stash--helper clear"),
NULL
@@ -24,6 +24,11 @@ static const char * const git_stash_helper_drop_usage[] = {
NULL
 };
 
+static const char * const git_stash_helper_pop_usage[] = {
+   N_("git stash--helper pop [--index] [-q|--quiet] []"),
+   NULL
+};
+
 static const char * const git_stash_helper_apply_usage[] = {
N_("git stash--helper apply [--index] [-q|--quiet] []"),
NULL
@@ -542,6 +547,35 @@ static int drop_stash(int argc, const char **argv, const 
char *prefix)
return ret;
 }
 
+static int pop_stash(int argc, const char **argv, const char *prefix)
+{
+   int ret;
+   int index = 0;
+   int quiet = 0;
+   struct stash_info info;
+   struct option options[] = {
+   OPT__QUIET(, N_("be quiet, only report errors")),
+   OPT_BOOL(0, "index", ,
+N_("attempt to recreate the index")),
+   OPT_END()
+   };
+
+   argc = parse_options(argc, argv, prefix, options,
+git_stash_helper_pop_usage, 0);
+
+   if (get_stash_info(, argc, argv))
+   return -1;
+
+   assert_stash_ref();
+   if ((ret = do_apply_stash(prefix, , index, quiet)))
+   printf_ln(_("The stash entry is kept in case you need it 
again."));
+   else
+   ret = do_drop_stash(prefix, , quiet);
+
+   free_stash_info();
+   return ret;
+}
+
 static int branch_stash(int argc, const char **argv, const char *prefix)
 {
int ret;
@@ -606,6 +640,8 @@ int cmd_stash__helper(int argc, const char **argv, const 
char *prefix)
return !!clear_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "drop"))
return !!drop_stash(argc, argv, prefix);
+   else if (!strcmp(argv[0], "pop"))
+   return !!pop_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "branch"))
return !!branch_stash(argc, argv, prefix);
 
diff --git a/git-stash.sh b/git-stash.sh
index 29d9f44255..8f2640fe90 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -554,50 +554,6 @@ assert_stash_like() {
}
 }
 
-is_stash_ref() {
-   is_stash_like "$@" && test -n "$IS_STASH_REF"
-}
-
-assert_stash_ref() {
-   is_stash_ref "$@" || {
-   args="$*"
-   die "$(eval_gettext "'\$args' is not a stash reference")"
-   }
-}
-
-apply_stash () {
-   cd "$START_DIR"
-   git stash--helper apply "$@"
-   res=$?
-   cd_to_toplevel
-   return $res
-}
-
-pop_stash() {
-   assert_stash_ref "$@"
-
-   if apply_stash "$@"
-   then
-   drop_stash "$@"
-   else
-   status=$?
-   say "$(gettext "The stash entry is kept in case you need it 
again.")"
-   exit $status
-   fi
-}
-
-drop_stash () {
-   assert_stash_ref "$@"
-
-   git reflog delete --updateref --rewrite "${REV}" &&
-   say "$(eval_gettext "Dropped \${REV} (\$s)")" ||
-   die "$(eval_gettext "\${REV}: Could not drop stash entry")"
-
-   # clear_stash if we just dropped the last stash entry
-   git rev-parse --verify --quiet "$ref_stash@{0}" >/dev/null ||
-   clear_stash
-}
-
 test "$1" = "-p" && set "push" "$@"
 
 PARSE_CACHE='--not-parsed'
@@ -655,7 +611,8 @@ drop)
;;
 pop)
shift
-   pop_stash "$@"
+   cd "$START_DIR"
+   git stash--helper pop "$@"
;;
 branch)
shift
-- 
2.19.0.rc0.23.g1fb9f40d88



[PATCH v9 18/21] stash: convert save to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
Add stash save to the helper and delete functions which are no
longer needed (`show_help()`, `save_stash()`, `push_stash()`,
`create_stash()`, `clear_stash()`, `untracked_files()` and
`no_changes()`).

The `-m` option is no longer supported as it might not make
sense to have two ways of passing a message. Even if this is
a change in behaviour, the documentation remains the same
because the `-m` parameter was omitted before.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c |  50 +++
 git-stash.sh| 311 +---
 2 files changed, 52 insertions(+), 309 deletions(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index 73bb22dc94..96689a00e9 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -26,6 +26,8 @@ static const char * const git_stash_helper_usage[] = {
N_("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] 
[-q|--quiet]\n"
   "  [-u|--include-untracked] [-a|--all] [-m|--message 
]\n"
   "  [--] [...]]"),
+   N_("git stash--helper save [-p|--patch] [-k|--[no-]keep-index] 
[-q|--quiet]\n"
+  "  [-u|--include-untracked] [-a|--all] []"),
NULL
 };
 
@@ -81,6 +83,12 @@ static const char * const git_stash_helper_push_usage[] = {
NULL
 };
 
+static const char * const git_stash_helper_save_usage[] = {
+   N_("git stash--helper save [-p|--patch] [-k|--[no-]keep-index] 
[-q|--quiet]\n"
+  "  [-u|--include-untracked] [-a|--all] []"),
+   NULL
+};
+
 static const char *ref_stash = "refs/stash";
 static struct strbuf stash_index_path = STRBUF_INIT;
 
@@ -1481,6 +1489,46 @@ static int push_stash(int argc, const char **argv, const 
char *prefix)
 include_untracked);
 }
 
+static int save_stash(int argc, const char **argv, const char *prefix)
+{
+   int keep_index = -1;
+   int patch_mode = 0;
+   int include_untracked = 0;
+   int quiet = 0;
+   int ret = 0;
+   char *stash_msg = NULL;
+   struct pathspec ps;
+   struct strbuf buf = STRBUF_INIT;
+   struct option options[] = {
+   OPT_BOOL('k', "keep-index", _index,
+N_("keep index")),
+   OPT_BOOL('p', "patch", _mode,
+N_("stash in patch mode")),
+   OPT__QUIET(, N_("quiet mode")),
+   OPT_BOOL('u', "include-untracked", _untracked,
+N_("include untracked files in stash")),
+   OPT_SET_INT('a', "all", _untracked,
+   N_("include ignore files"), 2),
+   OPT_STRING('m', "message", _msg, "message",
+  N_("stash message")),
+   OPT_END()
+   };
+
+   argc = parse_options(argc, argv, prefix, options,
+git_stash_helper_save_usage,
+PARSE_OPT_KEEP_DASHDASH);
+
+   if (argc)
+   stash_msg = (char*) strbuf_join_argv(, argc, argv, ' ');
+
+   memset(, 0, sizeof(ps));
+   ret = do_push_stash(ps, stash_msg, quiet, keep_index, patch_mode,
+   include_untracked);
+
+   strbuf_release();
+   return ret;
+}
+
 int cmd_stash__helper(int argc, const char **argv, const char *prefix)
 {
pid_t pid = getpid();
@@ -1521,6 +1569,8 @@ int cmd_stash__helper(int argc, const char **argv, const 
char *prefix)
return !!create_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "push"))
return !!push_stash(argc, argv, prefix);
+   else if (!strcmp(argv[0], "save"))
+   return !!save_stash(argc, argv, prefix);
 
usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
  git_stash_helper_usage, options);
diff --git a/git-stash.sh b/git-stash.sh
index c3146f62ab..695f1feba3 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -36,314 +36,6 @@ else
reset_color=
 fi
 
-no_changes () {
-   git diff-index --quiet --cached HEAD --ignore-submodules -- "$@" &&
-   git diff-files --quiet --ignore-submodules -- "$@" &&
-   (test -z "$untracked" || test -z "$(untracked_files "$@")")
-}
-
-untracked_files () {
-   if test "$1" = "-z"
-   then
-   shift
-   z=-z
-   else
-   z=
-   fi
-   excl_opt=--exclude-standard
-   test "$untracked" = "all" && excl_opt=
-   git ls-files -o $z $excl_opt -- "$@"
-}
-
-clear_stash () {
-   if test $# != 0
-   then
-   die "$(gettext "git stash clear with parameters is 
unimplemented")"
-   fi
-   if current=$(git rev-parse --verify --quiet $ref_stash)
-   then
-   git update-ref -d $ref_stash $current
-   fi
-}
-
-create_stash () {
-   stash_msg=
-   untracked=
-   while test $# != 0
-   do
-   case "$1" in
-   -m|--message)
-   

[PATCH v9 01/21] sha1-name.c: add `get_oidf()` which acts like `get_oid()`

2018-09-25 Thread Paul-Sebastian Ungureanu
Compared to `get_oid()`, `get_oidf()` has as parameters
a pointer to `object_id`, a printf format string and
additional arguments. This will help simplify the code
in subsequent commits.

Original-idea-by: Johannes Schindelin 
Signed-off-by: Paul-Sebastian Ungureanu 
---
 cache.h |  1 +
 sha1-name.c | 19 +++
 2 files changed, 20 insertions(+)

diff --git a/cache.h b/cache.h
index b1fd3d58ab..d93b2e25a5 100644
--- a/cache.h
+++ b/cache.h
@@ -1309,6 +1309,7 @@ struct object_context {
GET_OID_BLOB)
 
 extern int get_oid(const char *str, struct object_id *oid);
+extern int get_oidf(struct object_id *oid, const char *fmt, ...);
 extern int get_oid_commit(const char *str, struct object_id *oid);
 extern int get_oid_committish(const char *str, struct object_id *oid);
 extern int get_oid_tree(const char *str, struct object_id *oid);
diff --git a/sha1-name.c b/sha1-name.c
index c9cc1318b7..261b960bbd 100644
--- a/sha1-name.c
+++ b/sha1-name.c
@@ -1471,6 +1471,25 @@ int get_oid(const char *name, struct object_id *oid)
return get_oid_with_context(name, 0, oid, );
 }
 
+/*
+ * This returns a non-zero value if the string (built using printf
+ * format and the given arguments) is not a valid object.
+ */
+int get_oidf(struct object_id *oid, const char *fmt, ...)
+{
+   va_list ap;
+   int ret;
+   struct strbuf sb = STRBUF_INIT;
+
+   va_start(ap, fmt);
+   strbuf_vaddf(, fmt, ap);
+   va_end(ap);
+
+   ret = get_oid(sb.buf, oid);
+   strbuf_release();
+
+   return ret;
+}
 
 /*
  * Many callers know that the user meant to name a commit-ish by
-- 
2.19.0.rc0.23.g1fb9f40d88



[PATCH v9 21/21] stash: replace all `write-tree` child processes with API calls

2018-09-25 Thread Paul-Sebastian Ungureanu
This commit replaces spawning `git write-tree` with API calls.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash.c | 41 -
 1 file changed, 12 insertions(+), 29 deletions(-)

diff --git a/builtin/stash.c b/builtin/stash.c
index 43d0de1f13..86a7e0a5a5 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -941,9 +941,8 @@ static int save_untracked_files(struct stash_info *info, 
struct strbuf *msg,
 {
int ret = 0;
struct strbuf untracked_msg = STRBUF_INIT;
-   struct strbuf out = STRBUF_INIT;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
-   struct child_process cp_write_tree = CHILD_PROCESS_INIT;
+   struct index_state istate = { NULL };
 
cp_upd_index.git_cmd = 1;
argv_array_pushl(_upd_index.args, "update-index", "-z", "--add",
@@ -957,15 +956,11 @@ static int save_untracked_files(struct stash_info *info, 
struct strbuf *msg,
goto done;
}
 
-   cp_write_tree.git_cmd = 1;
-   argv_array_push(_write_tree.args, "write-tree");
-   argv_array_pushf(_write_tree.env_array, "GIT_INDEX_FILE=%s",
-stash_index_path.buf);
-   if (pipe_command(_write_tree, NULL, 0, , 0,NULL, 0)) {
+   if (write_index_as_tree(>u_tree, , stash_index_path.buf, 0,
+   NULL)) {
ret = -1;
goto done;
}
-   get_oid_hex(out.buf, >u_tree);
 
if (commit_tree(untracked_msg.buf, untracked_msg.len,
>u_tree, NULL, >u_commit, NULL, NULL)) {
@@ -974,8 +969,8 @@ static int save_untracked_files(struct stash_info *info, 
struct strbuf *msg,
}
 
 done:
+   discard_index();
strbuf_release(_msg);
-   strbuf_release();
remove_path(stash_index_path.buf);
return ret;
 }
@@ -984,11 +979,10 @@ static int stash_patch(struct stash_info *info, struct 
pathspec ps,
   struct strbuf *out_patch, int quiet)
 {
int ret = 0;
-   struct strbuf out = STRBUF_INIT;
struct child_process cp_read_tree = CHILD_PROCESS_INIT;
struct child_process cp_add_i = CHILD_PROCESS_INIT;
-   struct child_process cp_write_tree = CHILD_PROCESS_INIT;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
+   struct index_state istate = { NULL };
 
remove_path(stash_index_path.buf);
 
@@ -1014,17 +1008,12 @@ static int stash_patch(struct stash_info *info, struct 
pathspec ps,
}
 
/* State of the working tree. */
-   cp_write_tree.git_cmd = 1;
-   argv_array_push(_write_tree.args, "write-tree");
-   argv_array_pushf(_write_tree.env_array, "GIT_INDEX_FILE=%s",
-stash_index_path.buf);
-   if (pipe_command(_write_tree, NULL, 0, , 0,NULL, 0)) {
+   if (write_index_as_tree(>w_tree, , stash_index_path.buf, 0,
+   NULL)) {
ret = -1;
goto done;
}
 
-   get_oid_hex(out.buf, >w_tree);
-
cp_diff_tree.git_cmd = 1;
argv_array_pushl(_diff_tree.args, "diff-tree", "-p", "HEAD",
 oid_to_hex(>w_tree), "--", NULL);
@@ -1040,7 +1029,7 @@ static int stash_patch(struct stash_info *info, struct 
pathspec ps,
}
 
 done:
-   strbuf_release();
+   discard_index();
remove_path(stash_index_path.buf);
return ret;
 }
@@ -1050,9 +1039,8 @@ static int stash_working_tree(struct stash_info *info, 
struct pathspec ps)
int ret = 0;
struct rev_info rev;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
-   struct child_process cp_write_tree = CHILD_PROCESS_INIT;
-   struct strbuf out = STRBUF_INIT;
struct strbuf diff_output = STRBUF_INIT;
+   struct index_state istate = { NULL };
 
set_alternate_index_output(stash_index_path.buf);
if (reset_tree(>i_tree, 0, 0)) {
@@ -1091,20 +1079,15 @@ static int stash_working_tree(struct stash_info *info, 
struct pathspec ps)
goto done;
}
 
-   cp_write_tree.git_cmd = 1;
-   argv_array_push(_write_tree.args, "write-tree");
-   argv_array_pushf(_write_tree.env_array, "GIT_INDEX_FILE=%s",
-stash_index_path.buf);
-   if (pipe_command(_write_tree, NULL, 0, , 0,NULL, 0)) {
+   if (write_index_as_tree(>w_tree, , stash_index_path.buf, 0,
+   NULL)) {
ret = -1;
goto done;
}
 
-   get_oid_hex(out.buf, >w_tree);
-
 done:
+   discard_index();
UNLEAK(rev);
-   strbuf_release();
object_array_clear();
strbuf_release(_output);
remove_path(stash_index_path.buf);
-- 
2.19.0.rc0.23.g1fb9f40d88



[PATCH v9 20/21] stash: optimize `get_untracked_files()` and `check_changes()`

2018-09-25 Thread Paul-Sebastian Ungureanu
This commits introduces a optimization by avoiding calling the
same functions again. For example, `git stash push -u`
would call at some points the following functions:

 * `check_changes()` (inside `do_push_stash()`)
 * `do_create_stash()`, which calls: `check_changes()` and
`get_untracked_files()`

Note that `check_changes()` also calls `get_untracked_files()`.
So, `check_changes()` is called 2 times and `get_untracked_files()`
3 times.

The old function `check_changes()` now consists of two functions:
`get_untracked_files()` and `check_changes_tracked_files()`.

These are the call chains for `push` and `create`:

 * `push_stash()` -> `do_push_stash()` -> `do_create_stash()`

 * `create_stash()` -> `do_create_stash()`

To prevent calling the same functions over and over again,
`check_changes()` inside `do_create_stash()` is now placed
in the caller functions (`create_stash()` and `do_push_stash()`).
This way `check_changes()` and `get_untracked files()` are called
only one time.

https://public-inbox.org/git/20180818223329.gj11...@hank.intra.tgummerer.com/

Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash.c | 51 -
 1 file changed, 29 insertions(+), 22 deletions(-)

diff --git a/builtin/stash.c b/builtin/stash.c
index fc4a2050b1..43d0de1f13 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -875,19 +875,18 @@ static int get_untracked_files(struct pathspec ps, int 
include_untracked,
 }
 
 /*
- * The return value of `check_changes()` can be:
+ * The return value of `check_changes_tracked_files()` can be:
  *
  * < 0 if there was an error
  * = 0 if there are no changes.
  * > 0 if there are changes.
  */
-static int check_changes(struct pathspec ps, int include_untracked)
+
+static int check_changes_tracked_files(struct pathspec ps)
 {
int result;
-   int ret = 0;
struct rev_info rev;
struct object_id dummy;
-   struct strbuf out = STRBUF_INIT;
 
/* No initial commit. */
if (get_oid("HEAD", ))
@@ -915,14 +914,26 @@ static int check_changes(struct pathspec ps, int 
include_untracked)
if (diff_result_code(, result))
return 1;
 
+   return 0;
+}
+
+/*
+ * The function will fill `untracked_files` with the names of untracked files
+ * It will return 1 if there were any changes and 0 if there were not.
+ */
+
+static int check_changes(struct pathspec ps, int include_untracked,
+struct strbuf *untracked_files)
+{
+   int ret = 0;
+   if (check_changes_tracked_files(ps))
+   ret = 1;
+
if (include_untracked && get_untracked_files(ps, include_untracked,
-)) {
-   strbuf_release();
-   return 1;
-   }
+untracked_files))
+   ret = 1;
 
-   strbuf_release();
-   return 0;
+   return ret;
 }
 
 static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
@@ -1131,7 +1142,7 @@ static int do_create_stash(struct pathspec ps, char 
**stash_msg,
head_commit = lookup_commit(the_repository, >b_commit);
}
 
-   if (!check_changes(ps, include_untracked)) {
+   if (!check_changes(ps, include_untracked, _files)) {
ret = 1;
*stash_msg = NULL;
goto done;
@@ -1157,8 +1168,7 @@ static int do_create_stash(struct pathspec ps, char 
**stash_msg,
goto done;
}
 
-   if (include_untracked && get_untracked_files(ps, include_untracked,
-_files)) {
+   if (include_untracked) {
if (save_untracked_files(info, , untracked_files)) {
if (!quiet)
fprintf_ln(stderr, _("Cannot save the untracked 
files"));
@@ -1234,18 +1244,14 @@ static int create_stash(int argc, const char **argv, 
const char *prefix)
 ++argv, ' ');
 
memset(, 0, sizeof(ps));
-   ret = do_create_stash(ps, _msg, 0, 0, , NULL, 0);
+   if (!check_changes_tracked_files(ps))
+   return 0;
 
-   if (!ret)
+   if (!(ret = do_create_stash(ps, _msg, 0, 0, , NULL, 0)))
printf_ln("%s", oid_to_hex(_commit));
 
strbuf_release(_msg_buf);
-
-   /*
-* ret can be 1 if there were no changes. In this case, we should
-* not error out.
-*/
-   return ret < 0;
+   return ret;
 }
 
 static int do_push_stash(struct pathspec ps, char *stash_msg, int quiet,
@@ -1254,6 +1260,7 @@ static int do_push_stash(struct pathspec ps, char 
*stash_msg, int quiet,
int ret = 0;
struct stash_info info;
struct strbuf patch = STRBUF_INIT;
+   struct strbuf untracked_files = STRBUF_INIT;
 
if (patch_mode && keep_index == -1)
keep_index = 1;
@@ 

[PATCH v9 11/21] stash: convert list to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
Add stash list to the helper and delete the list_stash function
from the shell script.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c | 31 +++
 git-stash.sh|  7 +--
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index c1f78d3275..9e256690ec 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -12,6 +12,7 @@
 #include "rerere.h"
 
 static const char * const git_stash_helper_usage[] = {
+   N_("git stash--helper list []"),
N_("git stash--helper drop [-q|--quiet] []"),
N_("git stash--helper ( pop | apply ) [--index] [-q|--quiet] 
[]"),
N_("git stash--helper branch  []"),
@@ -19,6 +20,11 @@ static const char * const git_stash_helper_usage[] = {
NULL
 };
 
+static const char * const git_stash_helper_list_usage[] = {
+   N_("git stash--helper list []"),
+   NULL
+};
+
 static const char * const git_stash_helper_drop_usage[] = {
N_("git stash--helper drop [-q|--quiet] []"),
NULL
@@ -614,6 +620,29 @@ static int branch_stash(int argc, const char **argv, const 
char *prefix)
return ret;
 }
 
+static int list_stash(int argc, const char **argv, const char *prefix)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct option options[] = {
+   OPT_END()
+   };
+
+   argc = parse_options(argc, argv, prefix, options,
+git_stash_helper_list_usage,
+PARSE_OPT_KEEP_UNKNOWN);
+
+   if (!ref_exists(ref_stash))
+   return 0;
+
+   cp.git_cmd = 1;
+   argv_array_pushl(, "log", "--format=%gd: %gs", "-g",
+"--first-parent", "-m", NULL);
+   argv_array_pushv(, argv);
+   argv_array_push(, ref_stash);
+   argv_array_push(, "--");
+   return run_command();
+}
+
 int cmd_stash__helper(int argc, const char **argv, const char *prefix)
 {
pid_t pid = getpid();
@@ -644,6 +673,8 @@ int cmd_stash__helper(int argc, const char **argv, const 
char *prefix)
return !!pop_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "branch"))
return !!branch_stash(argc, argv, prefix);
+   else if (!strcmp(argv[0], "list"))
+   return !!list_stash(argc, argv, prefix);
 
usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
  git_stash_helper_usage, options);
diff --git a/git-stash.sh b/git-stash.sh
index 8f2640fe90..6052441aa2 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -382,11 +382,6 @@ have_stash () {
git rev-parse --verify --quiet $ref_stash >/dev/null
 }
 
-list_stash () {
-   have_stash || return 0
-   git log --format="%gd: %gs" -g --first-parent -m "$@" $ref_stash --
-}
-
 show_stash () {
ALLOW_UNKNOWN_FLAGS=t
assert_stash_like "$@"
@@ -574,7 +569,7 @@ test -n "$seen_non_option" || set "push" "$@"
 case "$1" in
 list)
shift
-   list_stash "$@"
+   git stash--helper list "$@"
;;
 show)
shift
-- 
2.19.0.rc0.23.g1fb9f40d88



[PATCH v9 16/21] stash: convert push to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
Add stash push to the helper.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c | 244 +++-
 git-stash.sh|   6 +-
 2 files changed, 244 insertions(+), 6 deletions(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index 49b05f2458..d79233d7ec 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -23,6 +23,9 @@ static const char * const git_stash_helper_usage[] = {
N_("git stash--helper ( pop | apply ) [--index] [-q|--quiet] 
[]"),
N_("git stash--helper branch  []"),
N_("git stash--helper clear"),
+   N_("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] 
[-q|--quiet]\n"
+  "  [-u|--include-untracked] [-a|--all] [-m|--message 
]\n"
+  "  [--] [...]]"),
NULL
 };
 
@@ -71,6 +74,13 @@ static const char * const git_stash_helper_create_usage[] = {
NULL
 };
 
+static const char * const git_stash_helper_push_usage[] = {
+   N_("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] 
[-q|--quiet]\n"
+  "  [-u|--include-untracked] [-a|--all] [-m|--message 
]\n"
+  "  [--] [...]]"),
+   NULL
+};
+
 static const char *ref_stash = "refs/stash";
 static struct strbuf stash_index_path = STRBUF_INIT;
 
@@ -1088,7 +1098,7 @@ static int stash_working_tree(struct stash_info *info, 
struct pathspec ps)
 
 static int do_create_stash(struct pathspec ps, char **stash_msg,
   int include_untracked, int patch_mode,
-  struct stash_info *info)
+  struct stash_info *info, struct strbuf *patch)
 {
int ret = 0;
int flags = 0;
@@ -1102,7 +1112,6 @@ static int do_create_stash(struct pathspec ps, char 
**stash_msg,
struct strbuf commit_tree_label = STRBUF_INIT;
struct strbuf untracked_files = STRBUF_INIT;
struct strbuf stash_msg_buf = STRBUF_INIT;
-   struct strbuf patch = STRBUF_INIT;
 
read_cache_preload(NULL);
refresh_cache(REFRESH_QUIET);
@@ -1152,7 +1161,7 @@ static int do_create_stash(struct pathspec ps, char 
**stash_msg,
untracked_commit_option = 1;
}
if (patch_mode) {
-   ret = stash_patch(info, ps, );
+   ret = stash_patch(info, ps, patch);
*stash_msg = NULL;
if (ret < 0) {
fprintf_ln(stderr, _("Cannot save the current worktree 
state"));
@@ -1221,7 +1230,8 @@ static int create_stash(int argc, const char **argv, 
const char *prefix)
 0);
 
memset(, 0, sizeof(ps));
-   ret = do_create_stash(ps, _msg, include_untracked, 0, );
+   ret = do_create_stash(ps, _msg, include_untracked, 0, ,
+ NULL);
 
if (!ret)
printf_ln("%s", oid_to_hex(_commit));
@@ -1234,6 +1244,230 @@ static int create_stash(int argc, const char **argv, 
const char *prefix)
return ret < 0;
 }
 
+static int do_push_stash(struct pathspec ps, char *stash_msg, int quiet,
+int keep_index, int patch_mode, int include_untracked)
+{
+   int ret = 0;
+   struct stash_info info;
+   struct strbuf patch = STRBUF_INIT;
+
+   if (patch_mode && keep_index == -1)
+   keep_index = 1;
+
+   if (patch_mode && include_untracked) {
+   fprintf_ln(stderr, _("Can't use --patch and --include-untracked"
+" or --all at the same time"));
+   ret = -1;
+   goto done;
+   }
+
+   read_cache_preload(NULL);
+   if (!include_untracked && ps.nr) {
+   int i;
+   char *ps_matched = xcalloc(ps.nr, 1);
+
+   for (i = 0; i < active_nr; i++)
+   ce_path_match(_index, active_cache[i], ,
+ ps_matched);
+
+   if (report_path_error(ps_matched, , NULL)) {
+   fprintf_ln(stderr, _("Did you forget to 'git add'?"));
+   stash_msg = NULL;
+   ret = -1;
+   goto done;
+   }
+   free(ps_matched);
+   }
+
+   if (refresh_cache(REFRESH_QUIET)) {
+   stash_msg = NULL;
+   ret = -1;
+   goto done;
+   }
+
+   if (!check_changes(ps, include_untracked)) {
+   stash_msg = NULL;
+   if (!quiet)
+   printf_ln(_("No local changes to save"));
+   goto done;
+   }
+
+   if (!reflog_exists(ref_stash) && do_clear_stash()) {
+   stash_msg = NULL;
+   ret = -1;
+   fprintf_ln(stderr, _("Cannot initialize stash"));
+   goto done;
+   }
+
+   if (do_create_stash(ps, _msg, include_untracked, patch_mode,
+   , )) {
+  

[PATCH v9 00/21] Convert "git stash" to C builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
Hello,

This is a new iteration of `git stash`, based on the last review I got.
This new iteration brings mostly code styling fix issues in order to make
the code more readable. There is also a new patch "strbuf.c: add
`strbuf_join_argv()`". By making some small changes, the code is now a
little bit closer to be used as API.

Joel Teichroeb (5):
  stash: improve option parsing test coverage
  stash: convert apply to builtin
  stash: convert drop and clear to builtin
  stash: convert branch to builtin
  stash: convert pop to builtin

Paul-Sebastian Ungureanu (16):
  sha1-name.c: add `get_oidf()` which acts like `get_oid()`
  strbuf.c: add `strbuf_join_argv()`
  stash: update test cases conform to coding guidelines
  stash: rename test cases to be more descriptive
  stash: add tests for `git stash show` config
  stash: convert list to builtin
  stash: convert show to builtin
  stash: mention options in `show` synopsis.
  stash: convert store to builtin
  stash: convert create to builtin
  stash: convert push to builtin
  stash: make push -q quiet
  stash: convert save to builtin
  stash: convert `stash--helper.c` into `stash.c`
  stash: optimize `get_untracked_files()` and `check_changes()`
  stash: replace all `write-tree` child processes with API calls

 Documentation/git-stash.txt  |4 +-
 Makefile |2 +-
 builtin.h|1 +
 builtin/stash.c  | 1595 ++
 cache.h  |1 +
 git-stash.sh |  752 
 git.c|1 +
 sha1-name.c  |   19 +
 strbuf.c |   15 +
 strbuf.h |7 +
 t/t3903-stash.sh |  192 ++--
 t/t3907-stash-show-config.sh |   83 ++
 12 files changed, 1851 insertions(+), 821 deletions(-)
 create mode 100644 builtin/stash.c
 delete mode 100755 git-stash.sh
 create mode 100755 t/t3907-stash-show-config.sh

-- 
2.19.0.rc0.23.g1fb9f40d88



[GSoC][PATCH v9 05/21] stash: add tests for `git stash show` config

2018-09-25 Thread Paul-Sebastian Ungureanu
This commit introduces tests for `git stash show`
config. It tests all the cases where `stash.showStat`
and `stash.showPatch` are unset or set to true / false.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 t/t3907-stash-show-config.sh | 83 
 1 file changed, 83 insertions(+)
 create mode 100755 t/t3907-stash-show-config.sh

diff --git a/t/t3907-stash-show-config.sh b/t/t3907-stash-show-config.sh
new file mode 100755
index 00..10914bba7b
--- /dev/null
+++ b/t/t3907-stash-show-config.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+test_description='Test git stash show configuration.'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+   test_commit file
+'
+
+# takes three parameters:
+# 1. the stash.showStat value (or "")
+# 2. the stash.showPatch value (or "")
+# 3. the diff options of the expected output (or nothing for no output)
+test_stat_and_patch () {
+   if test "" = "$1"
+   then
+   test_unconfig stash.showStat
+   else
+   test_config stash.showStat "$1"
+   fi &&
+
+   if test "" = "$2"
+   then
+   test_unconfig stash.showPatch
+   else
+   test_config stash.showPatch "$2"
+   fi &&
+
+   shift 2 &&
+   echo 2 >file.t &&
+   if test $# != 0
+   then
+   git diff "$@" >expect
+   fi &&
+   git stash &&
+   git stash show >actual &&
+
+   if test $# = 0
+   then
+   test_must_be_empty actual
+   else
+   test_cmp expect actual
+   fi
+}
+
+test_expect_success 'showStat unset showPatch unset' '
+   test_stat_and_patch "" "" --stat
+'
+
+test_expect_success 'showStat unset showPatch false' '
+   test_stat_and_patch "" false --stat
+'
+
+test_expect_success 'showStat unset showPatch true' '
+   test_stat_and_patch "" true --stat -p
+'
+
+test_expect_success 'showStat false showPatch unset' '
+   test_stat_and_patch false ""
+'
+
+test_expect_success 'showStat false showPatch false' '
+   test_stat_and_patch false false
+'
+
+test_expect_success 'showStat false showPatch true' '
+   test_stat_and_patch false true -p
+'
+
+test_expect_success 'showStat true showPatch unset' '
+   test_stat_and_patch true "" --stat
+'
+
+test_expect_success 'showStat true showPatch false' '
+   test_stat_and_patch true false --stat
+'
+
+test_expect_success 'showStat true showPatch true' '
+   test_stat_and_patch true true --stat -p
+'
+
+test_done
-- 
2.19.0.rc0.23.g1c0a08a5d3



[PATCH v9 13/21] stash: mention options in `show` synopsis.

2018-09-25 Thread Paul-Sebastian Ungureanu
Mention in the usage text and in the documentation, that `show`
accepts any option known to `git diff`.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 Documentation/git-stash.txt | 4 ++--
 builtin/stash--helper.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 7ef8c47911..e31ea7d303 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -9,7 +9,7 @@ SYNOPSIS
 
 [verse]
 'git stash' list []
-'git stash' show []
+'git stash' show [] []
 'git stash' drop [-q|--quiet] []
 'git stash' ( pop | apply ) [--index] [-q|--quiet] []
 'git stash' branch  []
@@ -106,7 +106,7 @@ stash@{1}: On master: 9cc0589... Add git-stash
 The command takes options applicable to the 'git log'
 command to control what is shown and how. See linkgit:git-log[1].
 
-show []::
+show [] []::
 
Show the changes recorded in the stash entry as a diff between the
stashed contents and the commit back when the stash entry was first
diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index 1bc838ee6b..1f02f5f2e9 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -15,7 +15,7 @@
 
 static const char * const git_stash_helper_usage[] = {
N_("git stash--helper list []"),
-   N_("git stash--helper show []"),
+   N_("git stash--helper show [] []"),
N_("git stash--helper drop [-q|--quiet] []"),
N_("git stash--helper ( pop | apply ) [--index] [-q|--quiet] 
[]"),
N_("git stash--helper branch  []"),
@@ -29,7 +29,7 @@ static const char * const git_stash_helper_list_usage[] = {
 };
 
 static const char * const git_stash_helper_show_usage[] = {
-   N_("git stash--helper show []"),
+   N_("git stash--helper show [] []"),
NULL
 };
 
-- 
2.19.0.rc0.23.g1fb9f40d88



[PATCH v9 17/21] stash: make push -q quiet

2018-09-25 Thread Paul-Sebastian Ungureanu
There is a change in behaviour with this commit. When there was
no initial commit, the shell version of stash would still display
a message. This commit makes `push` to not display any message if
`--quiet` or `-q` is specified.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c | 45 ++---
 t/t3903-stash.sh| 23 +
 2 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index d79233d7ec..73bb22dc94 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -967,7 +967,7 @@ static int save_untracked_files(struct stash_info *info, 
struct strbuf *msg,
 }
 
 static int stash_patch(struct stash_info *info, struct pathspec ps,
-  struct strbuf *out_patch)
+  struct strbuf *out_patch, int quiet)
 {
int ret = 0;
struct strbuf out = STRBUF_INIT;
@@ -1020,7 +1020,8 @@ static int stash_patch(struct stash_info *info, struct 
pathspec ps,
}
 
if (!out_patch->len) {
-   fprintf_ln(stderr, _("No changes selected"));
+   if (!quiet)
+   fprintf_ln(stderr, _("No changes selected"));
ret = 1;
}
 
@@ -1098,7 +1099,8 @@ static int stash_working_tree(struct stash_info *info, 
struct pathspec ps)
 
 static int do_create_stash(struct pathspec ps, char **stash_msg,
   int include_untracked, int patch_mode,
-  struct stash_info *info, struct strbuf *patch)
+  struct stash_info *info, struct strbuf *patch,
+  int quiet)
 {
int ret = 0;
int flags = 0;
@@ -1117,7 +1119,8 @@ static int do_create_stash(struct pathspec ps, char 
**stash_msg,
refresh_cache(REFRESH_QUIET);
 
if (get_oid("HEAD", >b_commit)) {
-   fprintf_ln(stderr, _("You do not have the initial commit yet"));
+   if (!quiet)
+   fprintf_ln(stderr, _("You do not have the initial 
commit yet"));
ret = -1;
*stash_msg = NULL;
goto done;
@@ -1144,7 +1147,8 @@ static int do_create_stash(struct pathspec ps, char 
**stash_msg,
if (write_cache_as_tree(>i_tree, 0, NULL) ||
commit_tree(commit_tree_label.buf, commit_tree_label.len,
>i_tree, parents, >i_commit, NULL, NULL)) {
-   fprintf_ln(stderr, _("Cannot save the current index state"));
+   if (!quiet)
+   fprintf_ln(stderr, _("Cannot save the current index 
state"));
ret = -1;
*stash_msg = NULL;
goto done;
@@ -1153,7 +1157,8 @@ static int do_create_stash(struct pathspec ps, char 
**stash_msg,
if (include_untracked && get_untracked_files(ps, include_untracked,
 _files)) {
if (save_untracked_files(info, , untracked_files)) {
-   fprintf_ln(stderr, _("Cannot save the untracked 
files"));
+   if (!quiet)
+   fprintf_ln(stderr, _("Cannot save the untracked 
files"));
ret = -1;
*stash_msg = NULL;
goto done;
@@ -1161,17 +1166,19 @@ static int do_create_stash(struct pathspec ps, char 
**stash_msg,
untracked_commit_option = 1;
}
if (patch_mode) {
-   ret = stash_patch(info, ps, patch);
+   ret = stash_patch(info, ps, patch, quiet);
*stash_msg = NULL;
if (ret < 0) {
-   fprintf_ln(stderr, _("Cannot save the current worktree 
state"));
+   if (!quiet)
+   fprintf_ln(stderr, _("Cannot save the current 
worktree state"));
goto done;
} else if (ret > 0) {
goto done;
}
} else {
if (stash_working_tree(info, ps)) {
-   fprintf_ln(stderr, _("Cannot save the current worktree 
state"));
+   if (!quiet)
+   fprintf_ln(stderr, _("Cannot save the current 
worktree state"));
ret = -1;
*stash_msg = NULL;
goto done;
@@ -1197,7 +1204,8 @@ static int do_create_stash(struct pathspec ps, char 
**stash_msg,
 
if (commit_tree(*stash_msg, strlen(*stash_msg), >w_tree,
parents, >w_commit, NULL, NULL)) {
-   fprintf_ln(stderr, _("Cannot record working tree state"));
+   if (!quiet)
+   fprintf_ln(stderr, _("Cannot record working tree 
state"));
ret = -1;
goto done;
}
@@ -1231,7 +1239,7 @@ static int 

[PATCH v9 09/21] stash: convert branch to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
From: Joel Teichroeb 

Add stash branch to the helper and delete the apply_to_branch
function from the shell script.

Checkout does not currently provide a function for checking out
a branch as cmd_checkout does a large amount of sanity checks
first that we require here.

Signed-off-by: Joel Teichroeb 
Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c | 46 +
 git-stash.sh| 17 ++-
 2 files changed, 48 insertions(+), 15 deletions(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index 72472eaeb7..5841bd0e98 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -14,6 +14,7 @@
 static const char * const git_stash_helper_usage[] = {
N_("git stash--helper drop [-q|--quiet] []"),
N_("git stash--helper apply [--index] [-q|--quiet] []"),
+   N_("git stash--helper branch  []"),
N_("git stash--helper clear"),
NULL
 };
@@ -28,6 +29,11 @@ static const char * const git_stash_helper_apply_usage[] = {
NULL
 };
 
+static const char * const git_stash_helper_branch_usage[] = {
+   N_("git stash--helper branch  []"),
+   NULL
+};
+
 static const char * const git_stash_helper_clear_usage[] = {
N_("git stash--helper clear"),
NULL
@@ -536,6 +542,44 @@ static int drop_stash(int argc, const char **argv, const 
char *prefix)
return ret;
 }
 
+static int branch_stash(int argc, const char **argv, const char *prefix)
+{
+   int ret;
+   const char *branch = NULL;
+   struct stash_info info;
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct option options[] = {
+   OPT_END()
+   };
+
+   argc = parse_options(argc, argv, prefix, options,
+git_stash_helper_branch_usage, 0);
+
+   if (!argc) {
+   fprintf_ln(stderr, "No branch name specified");
+   return -1;
+   }
+
+   branch = argv[0];
+
+   if (get_stash_info(, argc - 1, argv + 1))
+   return -1;
+
+   cp.git_cmd = 1;
+   argv_array_pushl(, "checkout", "-b", NULL);
+   argv_array_push(, branch);
+   argv_array_push(, oid_to_hex(_commit));
+   ret = run_command();
+   if (!ret)
+   ret = do_apply_stash(prefix, , 1, 0);
+   if (!ret && info.is_stash_ref)
+   ret = do_drop_stash(prefix, , 0);
+
+   free_stash_info();
+
+   return ret;
+}
+
 int cmd_stash__helper(int argc, const char **argv, const char *prefix)
 {
pid_t pid = getpid();
@@ -562,6 +606,8 @@ int cmd_stash__helper(int argc, const char **argv, const 
char *prefix)
return !!clear_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "drop"))
return !!drop_stash(argc, argv, prefix);
+   else if (!strcmp(argv[0], "branch"))
+   return !!branch_stash(argc, argv, prefix);
 
usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
  git_stash_helper_usage, options);
diff --git a/git-stash.sh b/git-stash.sh
index a99d5dc9e5..29d9f44255 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -598,20 +598,6 @@ drop_stash () {
clear_stash
 }
 
-apply_to_branch () {
-   test -n "$1" || die "$(gettext "No branch name specified")"
-   branch=$1
-   shift 1
-
-   set -- --index "$@"
-   assert_stash_like "$@"
-
-   git checkout -b $branch $REV^ &&
-   apply_stash "$@" && {
-   test -z "$IS_STASH_REF" || drop_stash "$@"
-   }
-}
-
 test "$1" = "-p" && set "push" "$@"
 
 PARSE_CACHE='--not-parsed'
@@ -673,7 +659,8 @@ pop)
;;
 branch)
shift
-   apply_to_branch "$@"
+   cd "$START_DIR"
+   git stash--helper branch "$@"
;;
 *)
case $# in
-- 
2.19.0.rc0.23.g1fb9f40d88



[PATCH v9 04/21] stash: update test cases conform to coding guidelines

2018-09-25 Thread Paul-Sebastian Ungureanu
Removed whitespaces after redirection operators.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 t/t3903-stash.sh | 120 ---
 1 file changed, 61 insertions(+), 59 deletions(-)

diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index af7586d43d..de6cab1fe7 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -8,22 +8,22 @@ test_description='Test git stash'
 . ./test-lib.sh
 
 test_expect_success 'stash some dirty working directory' '
-   echo 1 > file &&
+   echo 1 >file &&
git add file &&
echo unrelated >other-file &&
git add other-file &&
test_tick &&
git commit -m initial &&
-   echo 2 > file &&
+   echo 2 >file &&
git add file &&
-   echo 3 > file &&
+   echo 3 >file &&
test_tick &&
git stash &&
git diff-files --quiet &&
git diff-index --cached --quiet HEAD
 '
 
-cat > expect << EOF
+cat >expect < output &&
+   git diff stash^2..stash >output &&
test_cmp output expect
 '
 
@@ -74,7 +74,7 @@ test_expect_success 'apply stashed changes' '
 
 test_expect_success 'apply stashed changes (including index)' '
git reset --hard HEAD^ &&
-   echo 6 > other-file &&
+   echo 6 >other-file &&
git add other-file &&
test_tick &&
git commit -m other-file &&
@@ -99,12 +99,12 @@ test_expect_success 'stash drop complains of extra options' 
'
 
 test_expect_success 'drop top stash' '
git reset --hard &&
-   git stash list > stashlist1 &&
-   echo 7 > file &&
+   git stash list >expected &&
+   echo 7 >file &&
git stash &&
git stash drop &&
-   git stash list > stashlist2 &&
-   test_cmp stashlist1 stashlist2 &&
+   git stash list >actual &&
+   test_cmp expected actual &&
git stash apply &&
test 3 = $(cat file) &&
test 1 = $(git show :file) &&
@@ -113,9 +113,9 @@ test_expect_success 'drop top stash' '
 
 test_expect_success 'drop middle stash' '
git reset --hard &&
-   echo 8 > file &&
+   echo 8 >file &&
git stash &&
-   echo 9 > file &&
+   echo 9 >file &&
git stash &&
git stash drop stash@{1} &&
test 2 = $(git stash list | wc -l) &&
@@ -160,7 +160,7 @@ test_expect_success 'stash pop' '
test 0 = $(git stash list | wc -l)
 '
 
-cat > expect << EOF
+cat >expect < expect1 << EOF
+cat >expect1 < expect2 << EOF
+cat >expect2 < file &&
+   echo foo >file &&
git commit file -m first &&
-   echo bar > file &&
-   echo bar2 > file2 &&
+   echo bar >file &&
+   echo bar2 >file2 &&
git add file2 &&
git stash &&
-   echo baz > file &&
+   echo baz >file &&
git commit file -m second &&
git stash branch stashbranch &&
test refs/heads/stashbranch = $(git symbolic-ref HEAD) &&
test $(git rev-parse HEAD) = $(git rev-parse master^) &&
-   git diff --cached > output &&
+   git diff --cached >output &&
test_cmp output expect &&
-   git diff > output &&
+   git diff >output &&
test_cmp output expect1 &&
git add file &&
git commit -m alternate\ second &&
-   git diff master..stashbranch > output &&
+   git diff master..stashbranch >output &&
test_cmp output expect2 &&
test 0 = $(git stash list | wc -l)
 '
 
 test_expect_success 'apply -q is quiet' '
-   echo foo > file &&
+   echo foo >file &&
git stash &&
-   git stash apply -q > output.out 2>&1 &&
+   git stash apply -q >output.out 2>&1 &&
test_must_be_empty output.out
 '
 
 test_expect_success 'save -q is quiet' '
-   git stash save --quiet > output.out 2>&1 &&
+   git stash save --quiet >output.out 2>&1 &&
test_must_be_empty output.out
 '
 
 test_expect_success 'pop -q is quiet' '
-   git stash pop -q > output.out 2>&1 &&
+   git stash pop -q >output.out 2>&1 &&
test_must_be_empty output.out
 '
 
 test_expect_success 'pop -q --index works and is quiet' '
-   echo foo > file &&
+   echo foo >file &&
git add file &&
git stash save --quiet &&
-   git stash pop -q --index > output.out 2>&1 &&
+   git stash pop -q --index >output.out 2>&1 &&
test foo = "$(git show :file)" &&
test_must_be_empty output.out
 '
 
 test_expect_success 'drop -q is quiet' '
git stash &&
-   git stash drop -q > output.out 2>&1 &&
+   git stash drop -q >output.out 2>&1 &&
test_must_be_empty output.out
 '
 
 test_expect_success 'stash -k' '
-   echo bar3 > file &&
-   echo bar4 > file2 &&
+   echo bar3 >file &&
+   echo bar4 >file2 &&
git add file2 &&
git stash -k &&
test bar,bar4 = $(cat file),$(cat file2)
 '
 
 test_expect_success 'stash --no-keep-index' '
-   echo bar33 > file &&
-   echo bar44 > file2 &&
+   echo bar33 >file &&
+   echo 

[PATCH v9 12/21] stash: convert show to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu
Add stash show to the helper and delete the show_stash, have_stash,
assert_stash_like, is_stash_like and parse_flags_and_rev functions
from the shell script now that they are no longer needed.

In shell version, although `git stash show` accepts `--index` and
`--quiet` options, it ignores them. In C, both options are passed
further to `git diff`.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 builtin/stash--helper.c |  87 ++
 git-stash.sh| 132 +---
 2 files changed, 88 insertions(+), 131 deletions(-)

diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
index 9e256690ec..1bc838ee6b 100644
--- a/builtin/stash--helper.c
+++ b/builtin/stash--helper.c
@@ -10,9 +10,12 @@
 #include "run-command.h"
 #include "dir.h"
 #include "rerere.h"
+#include "revision.h"
+#include "log-tree.h"
 
 static const char * const git_stash_helper_usage[] = {
N_("git stash--helper list []"),
+   N_("git stash--helper show []"),
N_("git stash--helper drop [-q|--quiet] []"),
N_("git stash--helper ( pop | apply ) [--index] [-q|--quiet] 
[]"),
N_("git stash--helper branch  []"),
@@ -25,6 +28,11 @@ static const char * const git_stash_helper_list_usage[] = {
NULL
 };
 
+static const char * const git_stash_helper_show_usage[] = {
+   N_("git stash--helper show []"),
+   NULL
+};
+
 static const char * const git_stash_helper_drop_usage[] = {
N_("git stash--helper drop [-q|--quiet] []"),
NULL
@@ -643,6 +651,83 @@ static int list_stash(int argc, const char **argv, const 
char *prefix)
return run_command();
 }
 
+static int show_stat = 1;
+static int show_patch;
+
+static int git_stash_config(const char *var, const char *value, void *cb)
+{
+   if (!strcmp(var, "stash.showstat")) {
+   show_stat = git_config_bool(var, value);
+   return 0;
+   }
+   if (!strcmp(var, "stash.showpatch")) {
+   show_patch = git_config_bool(var, value);
+   return 0;
+   }
+   return git_default_config(var, value, cb);
+}
+
+static int show_stash(int argc, const char **argv, const char *prefix)
+{
+   int i;
+   int opts = 0;
+   int ret = 0;
+   struct stash_info info;
+   struct rev_info rev;
+   struct argv_array stash_args = ARGV_ARRAY_INIT;
+   struct option options[] = {
+   OPT_END()
+   };
+
+   init_diff_ui_defaults();
+   git_config(git_diff_ui_config, NULL);
+   init_revisions(, prefix);
+
+   for (i = 1; i < argc; i++) {
+   if (argv[i][0] != '-')
+   argv_array_push(_args, argv[i]);
+   else
+   opts++;
+   }
+
+   ret = get_stash_info(, stash_args.argc, stash_args.argv);
+   argv_array_clear(_args);
+   if (ret)
+   return -1;
+
+   /*
+* The config settings are applied only if there are not passed
+* any options.
+*/
+   if (!opts) {
+   git_config(git_stash_config, NULL);
+   if (show_stat)
+   rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT;
+
+   if (show_patch)
+   rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
+
+   if (!show_stat && !show_patch) {
+   free_stash_info();
+   return 0;
+   }
+   }
+
+   argc = setup_revisions(argc, argv, , NULL);
+   if (argc > 1) {
+   free_stash_info();
+   usage_with_options(git_stash_helper_show_usage, options);
+   }
+
+   rev.diffopt.flags.recursive = 1;
+   setup_diff_pager();
+   diff_tree_oid(_commit, _commit, "", );
+   log_tree_diff_flush();
+
+   free_stash_info();
+   return diff_result_code(, 0);
+}
+
 int cmd_stash__helper(int argc, const char **argv, const char *prefix)
 {
pid_t pid = getpid();
@@ -675,6 +760,8 @@ int cmd_stash__helper(int argc, const char **argv, const 
char *prefix)
return !!branch_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "list"))
return !!list_stash(argc, argv, prefix);
+   else if (!strcmp(argv[0], "show"))
+   return !!show_stash(argc, argv, prefix);
 
usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
  git_stash_helper_usage, options);
diff --git a/git-stash.sh b/git-stash.sh
index 6052441aa2..0d05cbc1e5 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -378,35 +378,6 @@ save_stash () {
fi
 }
 
-have_stash () {
-   git rev-parse --verify --quiet $ref_stash >/dev/null
-}
-
-show_stash () {
-   ALLOW_UNKNOWN_FLAGS=t
-   assert_stash_like "$@"
-
-   if test -z "$FLAGS"
-   then
-   if test "$(git config --bool stash.showStat || echo true)" = 
"true"
-   then
-   FLAGS=--stat
-   

[PATCH v9 02/21] strbuf.c: add `strbuf_join_argv()`

2018-09-25 Thread Paul-Sebastian Ungureanu
Implement `strbuf_join_argv()` to join arguments
into a strbuf.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 strbuf.c | 15 +++
 strbuf.h |  7 +++
 2 files changed, 22 insertions(+)

diff --git a/strbuf.c b/strbuf.c
index 64041c3c24..3eb431b2b0 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -259,6 +259,21 @@ void strbuf_addbuf(struct strbuf *sb, const struct strbuf 
*sb2)
strbuf_setlen(sb, sb->len + sb2->len);
 }
 
+const char *strbuf_join_argv(struct strbuf *buf,
+int argc, const char **argv, char delim)
+{
+   if (!argc)
+   return buf->buf;
+
+   strbuf_addstr(buf, *argv);
+   while (--argc) {
+   strbuf_addch(buf, delim);
+   strbuf_addstr(buf, *(++argv));
+   }
+
+   return buf->buf;
+}
+
 void strbuf_addchars(struct strbuf *sb, int c, size_t n)
 {
strbuf_grow(sb, n);
diff --git a/strbuf.h b/strbuf.h
index 60a35aef16..7ed859bb8a 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -284,6 +284,13 @@ static inline void strbuf_addstr(struct strbuf *sb, const 
char *s)
  */
 extern void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
 
+
+/**
+ *
+ */
+extern const char *strbuf_join_argv(struct strbuf *buf, int argc,
+   const char **argv, char delim);
+
 /**
  * This function can be used to expand a format string containing
  * placeholders. To that end, it parses the string and calls the specified
-- 
2.19.0.rc0.23.g1fb9f40d88



[GSoC][PATCH v9 04/21] stash: rename test cases to be more descriptive

2018-09-25 Thread Paul-Sebastian Ungureanu
Rename some test cases' labels to be more descriptive and under 80
characters per line.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 t/t3903-stash.sh | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index de6cab1fe7..3114c7bc4c 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -604,7 +604,7 @@ test_expect_success 'stash show -p - no stashes on stack, 
stash-like argument' '
test_cmp expected actual
 '
 
-test_expect_success 'stash drop - fail early if specified stash is not a stash 
reference' '
+test_expect_success 'drop: fail early if specified stash is not a stash ref' '
git stash clear &&
test_when_finished "git reset --hard HEAD && git stash clear" &&
git reset --hard &&
@@ -618,7 +618,7 @@ test_expect_success 'stash drop - fail early if specified 
stash is not a stash r
git reset --hard HEAD
 '
 
-test_expect_success 'stash pop - fail early if specified stash is not a stash 
reference' '
+test_expect_success 'pop: fail early if specified stash is not a stash ref' '
git stash clear &&
test_when_finished "git reset --hard HEAD && git stash clear" &&
git reset --hard &&
@@ -682,7 +682,7 @@ test_expect_success 'invalid ref of the form "n", n >= N' '
git stash drop
 '
 
-test_expect_success 'stash branch should not drop the stash if the branch 
exists' '
+test_expect_success 'branch: do not drop the stash if the branch exists' '
git stash clear &&
echo foo >file &&
git add file &&
@@ -693,7 +693,7 @@ test_expect_success 'stash branch should not drop the stash 
if the branch exists
git rev-parse stash@{0} --
 '
 
-test_expect_success 'stash branch should not drop the stash if the apply 
fails' '
+test_expect_success 'branch: should not drop the stash if the apply fails' '
git stash clear &&
git reset HEAD~1 --hard &&
echo foo >file &&
@@ -707,7 +707,7 @@ test_expect_success 'stash branch should not drop the stash 
if the apply fails'
git rev-parse stash@{0} --
 '
 
-test_expect_success 'stash apply shows status same as git status (relative to 
current directory)' '
+test_expect_success 'apply: show same status as git status (relative to ./)' '
git stash clear &&
echo 1 >subdir/subfile1 &&
echo 2 >subdir/subfile2 &&
@@ -1048,7 +1048,7 @@ test_expect_success 'stash push -p with pathspec shows no 
changes only once' '
test_i18ncmp expect actual
 '
 
-test_expect_success 'stash push with pathspec shows no changes when there are 
none' '
+test_expect_success 'push : show no changes when there are none' '
>foo &&
git add foo &&
git commit -m "tmp" &&
@@ -1058,7 +1058,7 @@ test_expect_success 'stash push with pathspec shows no 
changes when there are no
test_i18ncmp expect actual
 '
 
-test_expect_success 'stash push with pathspec not in the repository errors 
out' '
+test_expect_success 'push:  not in the repository errors out' '
>untracked &&
test_must_fail git stash push untracked &&
test_path_is_file untracked
-- 
2.19.0.rc0.23.g1c0a08a5d3



[PATCH v9 05/21] stash: rename test cases to be more descriptive

2018-09-25 Thread Paul-Sebastian Ungureanu
Rename some test cases' labels to be more descriptive and under 80
characters per line.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 t/t3903-stash.sh | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index de6cab1fe7..3114c7bc4c 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -604,7 +604,7 @@ test_expect_success 'stash show -p - no stashes on stack, 
stash-like argument' '
test_cmp expected actual
 '
 
-test_expect_success 'stash drop - fail early if specified stash is not a stash 
reference' '
+test_expect_success 'drop: fail early if specified stash is not a stash ref' '
git stash clear &&
test_when_finished "git reset --hard HEAD && git stash clear" &&
git reset --hard &&
@@ -618,7 +618,7 @@ test_expect_success 'stash drop - fail early if specified 
stash is not a stash r
git reset --hard HEAD
 '
 
-test_expect_success 'stash pop - fail early if specified stash is not a stash 
reference' '
+test_expect_success 'pop: fail early if specified stash is not a stash ref' '
git stash clear &&
test_when_finished "git reset --hard HEAD && git stash clear" &&
git reset --hard &&
@@ -682,7 +682,7 @@ test_expect_success 'invalid ref of the form "n", n >= N' '
git stash drop
 '
 
-test_expect_success 'stash branch should not drop the stash if the branch 
exists' '
+test_expect_success 'branch: do not drop the stash if the branch exists' '
git stash clear &&
echo foo >file &&
git add file &&
@@ -693,7 +693,7 @@ test_expect_success 'stash branch should not drop the stash 
if the branch exists
git rev-parse stash@{0} --
 '
 
-test_expect_success 'stash branch should not drop the stash if the apply 
fails' '
+test_expect_success 'branch: should not drop the stash if the apply fails' '
git stash clear &&
git reset HEAD~1 --hard &&
echo foo >file &&
@@ -707,7 +707,7 @@ test_expect_success 'stash branch should not drop the stash 
if the apply fails'
git rev-parse stash@{0} --
 '
 
-test_expect_success 'stash apply shows status same as git status (relative to 
current directory)' '
+test_expect_success 'apply: show same status as git status (relative to ./)' '
git stash clear &&
echo 1 >subdir/subfile1 &&
echo 2 >subdir/subfile2 &&
@@ -1048,7 +1048,7 @@ test_expect_success 'stash push -p with pathspec shows no 
changes only once' '
test_i18ncmp expect actual
 '
 
-test_expect_success 'stash push with pathspec shows no changes when there are 
none' '
+test_expect_success 'push : show no changes when there are none' '
>foo &&
git add foo &&
git commit -m "tmp" &&
@@ -1058,7 +1058,7 @@ test_expect_success 'stash push with pathspec shows no 
changes when there are no
test_i18ncmp expect actual
 '
 
-test_expect_success 'stash push with pathspec not in the repository errors 
out' '
+test_expect_success 'push:  not in the repository errors out' '
>untracked &&
test_must_fail git stash push untracked &&
test_path_is_file untracked
-- 
2.19.0.rc0.23.g1fb9f40d88



[GSoC][PATCH v9 02/21] stash: improve option parsing test coverage

2018-09-25 Thread Paul-Sebastian Ungureanu
From: Joel Teichroeb 

In preparation for converting the stash command incrementally to
a builtin command, this patch improves test coverage of the option
parsing. Both for having too many parameters, or too few.

Signed-off-by: Joel Teichroeb 
Signed-off-by: Paul-Sebastian Ungureanu 
---
 t/t3903-stash.sh | 35 +++
 1 file changed, 35 insertions(+)

diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 1f871d3cca..af7586d43d 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -444,6 +444,36 @@ test_expect_failure 'stash file to directory' '
test foo = "$(cat file/file)"
 '
 
+test_expect_success 'giving too many ref arguments does not modify files' '
+   git stash clear &&
+   test_when_finished "git reset --hard HEAD" &&
+   echo foo >file2 &&
+   git stash &&
+   echo bar >file2 &&
+   git stash &&
+   test-tool chmtime =123456789 file2 &&
+   for type in apply pop "branch stash-branch"
+   do
+   test_must_fail git stash $type stash@{0} stash@{1} 2>err &&
+   test_i18ngrep "Too many revisions" err &&
+   test 123456789 = $(test-tool chmtime -g file2) || return 1
+   done
+'
+
+test_expect_success 'drop: too many arguments errors out (does nothing)' '
+   git stash list >expect &&
+   test_must_fail git stash drop stash@{0} stash@{1} 2>err &&
+   test_i18ngrep "Too many revisions" err &&
+   git stash list >actual &&
+   test_cmp expect actual
+'
+
+test_expect_success 'show: too many arguments errors out (does nothing)' '
+   test_must_fail git stash show stash@{0} stash@{1} 2>err 1>out &&
+   test_i18ngrep "Too many revisions" err &&
+   test_must_be_empty out
+'
+
 test_expect_success 'stash create - no changes' '
git stash clear &&
test_when_finished "git reset --hard HEAD" &&
@@ -479,6 +509,11 @@ test_expect_success 'stash branch - stashes on stack, 
stash-like argument' '
test $(git ls-files --modified | wc -l) -eq 1
 '
 
+test_expect_success 'stash branch complains with no arguments' '
+   test_must_fail git stash branch 2>err &&
+   test_i18ngrep "No branch name specified" err
+'
+
 test_expect_success 'stash show format defaults to --stat' '
git stash clear &&
test_when_finished "git reset --hard HEAD" &&
-- 
2.19.0.rc0.23.g1c0a08a5d3



[GSoC][PATCH v9 03/21] stash: update test cases conform to coding guidelines

2018-09-25 Thread Paul-Sebastian Ungureanu
Removed whitespaces after redirection operators.

Signed-off-by: Paul-Sebastian Ungureanu 
---
 t/t3903-stash.sh | 120 ---
 1 file changed, 61 insertions(+), 59 deletions(-)

diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index af7586d43d..de6cab1fe7 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -8,22 +8,22 @@ test_description='Test git stash'
 . ./test-lib.sh
 
 test_expect_success 'stash some dirty working directory' '
-   echo 1 > file &&
+   echo 1 >file &&
git add file &&
echo unrelated >other-file &&
git add other-file &&
test_tick &&
git commit -m initial &&
-   echo 2 > file &&
+   echo 2 >file &&
git add file &&
-   echo 3 > file &&
+   echo 3 >file &&
test_tick &&
git stash &&
git diff-files --quiet &&
git diff-index --cached --quiet HEAD
 '
 
-cat > expect << EOF
+cat >expect < output &&
+   git diff stash^2..stash >output &&
test_cmp output expect
 '
 
@@ -74,7 +74,7 @@ test_expect_success 'apply stashed changes' '
 
 test_expect_success 'apply stashed changes (including index)' '
git reset --hard HEAD^ &&
-   echo 6 > other-file &&
+   echo 6 >other-file &&
git add other-file &&
test_tick &&
git commit -m other-file &&
@@ -99,12 +99,12 @@ test_expect_success 'stash drop complains of extra options' 
'
 
 test_expect_success 'drop top stash' '
git reset --hard &&
-   git stash list > stashlist1 &&
-   echo 7 > file &&
+   git stash list >expected &&
+   echo 7 >file &&
git stash &&
git stash drop &&
-   git stash list > stashlist2 &&
-   test_cmp stashlist1 stashlist2 &&
+   git stash list >actual &&
+   test_cmp expected actual &&
git stash apply &&
test 3 = $(cat file) &&
test 1 = $(git show :file) &&
@@ -113,9 +113,9 @@ test_expect_success 'drop top stash' '
 
 test_expect_success 'drop middle stash' '
git reset --hard &&
-   echo 8 > file &&
+   echo 8 >file &&
git stash &&
-   echo 9 > file &&
+   echo 9 >file &&
git stash &&
git stash drop stash@{1} &&
test 2 = $(git stash list | wc -l) &&
@@ -160,7 +160,7 @@ test_expect_success 'stash pop' '
test 0 = $(git stash list | wc -l)
 '
 
-cat > expect << EOF
+cat >expect < expect1 << EOF
+cat >expect1 < expect2 << EOF
+cat >expect2 < file &&
+   echo foo >file &&
git commit file -m first &&
-   echo bar > file &&
-   echo bar2 > file2 &&
+   echo bar >file &&
+   echo bar2 >file2 &&
git add file2 &&
git stash &&
-   echo baz > file &&
+   echo baz >file &&
git commit file -m second &&
git stash branch stashbranch &&
test refs/heads/stashbranch = $(git symbolic-ref HEAD) &&
test $(git rev-parse HEAD) = $(git rev-parse master^) &&
-   git diff --cached > output &&
+   git diff --cached >output &&
test_cmp output expect &&
-   git diff > output &&
+   git diff >output &&
test_cmp output expect1 &&
git add file &&
git commit -m alternate\ second &&
-   git diff master..stashbranch > output &&
+   git diff master..stashbranch >output &&
test_cmp output expect2 &&
test 0 = $(git stash list | wc -l)
 '
 
 test_expect_success 'apply -q is quiet' '
-   echo foo > file &&
+   echo foo >file &&
git stash &&
-   git stash apply -q > output.out 2>&1 &&
+   git stash apply -q >output.out 2>&1 &&
test_must_be_empty output.out
 '
 
 test_expect_success 'save -q is quiet' '
-   git stash save --quiet > output.out 2>&1 &&
+   git stash save --quiet >output.out 2>&1 &&
test_must_be_empty output.out
 '
 
 test_expect_success 'pop -q is quiet' '
-   git stash pop -q > output.out 2>&1 &&
+   git stash pop -q >output.out 2>&1 &&
test_must_be_empty output.out
 '
 
 test_expect_success 'pop -q --index works and is quiet' '
-   echo foo > file &&
+   echo foo >file &&
git add file &&
git stash save --quiet &&
-   git stash pop -q --index > output.out 2>&1 &&
+   git stash pop -q --index >output.out 2>&1 &&
test foo = "$(git show :file)" &&
test_must_be_empty output.out
 '
 
 test_expect_success 'drop -q is quiet' '
git stash &&
-   git stash drop -q > output.out 2>&1 &&
+   git stash drop -q >output.out 2>&1 &&
test_must_be_empty output.out
 '
 
 test_expect_success 'stash -k' '
-   echo bar3 > file &&
-   echo bar4 > file2 &&
+   echo bar3 >file &&
+   echo bar4 >file2 &&
git add file2 &&
git stash -k &&
test bar,bar4 = $(cat file),$(cat file2)
 '
 
 test_expect_success 'stash --no-keep-index' '
-   echo bar33 > file &&
-   echo bar44 > file2 &&
+   echo bar33 >file &&
+   echo 

[PATCH v9 03/21] stash: improve option parsing test coverage

2018-09-25 Thread Paul-Sebastian Ungureanu
From: Joel Teichroeb 

In preparation for converting the stash command incrementally to
a builtin command, this patch improves test coverage of the option
parsing. Both for having too many parameters, or too few.

Signed-off-by: Joel Teichroeb 
Signed-off-by: Paul-Sebastian Ungureanu 
---
 t/t3903-stash.sh | 35 +++
 1 file changed, 35 insertions(+)

diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 1f871d3cca..af7586d43d 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -444,6 +444,36 @@ test_expect_failure 'stash file to directory' '
test foo = "$(cat file/file)"
 '
 
+test_expect_success 'giving too many ref arguments does not modify files' '
+   git stash clear &&
+   test_when_finished "git reset --hard HEAD" &&
+   echo foo >file2 &&
+   git stash &&
+   echo bar >file2 &&
+   git stash &&
+   test-tool chmtime =123456789 file2 &&
+   for type in apply pop "branch stash-branch"
+   do
+   test_must_fail git stash $type stash@{0} stash@{1} 2>err &&
+   test_i18ngrep "Too many revisions" err &&
+   test 123456789 = $(test-tool chmtime -g file2) || return 1
+   done
+'
+
+test_expect_success 'drop: too many arguments errors out (does nothing)' '
+   git stash list >expect &&
+   test_must_fail git stash drop stash@{0} stash@{1} 2>err &&
+   test_i18ngrep "Too many revisions" err &&
+   git stash list >actual &&
+   test_cmp expect actual
+'
+
+test_expect_success 'show: too many arguments errors out (does nothing)' '
+   test_must_fail git stash show stash@{0} stash@{1} 2>err 1>out &&
+   test_i18ngrep "Too many revisions" err &&
+   test_must_be_empty out
+'
+
 test_expect_success 'stash create - no changes' '
git stash clear &&
test_when_finished "git reset --hard HEAD" &&
@@ -479,6 +509,11 @@ test_expect_success 'stash branch - stashes on stack, 
stash-like argument' '
test $(git ls-files --modified | wc -l) -eq 1
 '
 
+test_expect_success 'stash branch complains with no arguments' '
+   test_must_fail git stash branch 2>err &&
+   test_i18ngrep "No branch name specified" err
+'
+
 test_expect_success 'stash show format defaults to --stat' '
git stash clear &&
test_when_finished "git reset --hard HEAD" &&
-- 
2.19.0.rc0.23.g1fb9f40d88



Re: [PATCH v4 9/9] Documentation/config: add odb..promisorRemote

2018-09-25 Thread Junio C Hamano
Christian Couder  writes:

> The main issue that this patch series tries to solve is that
> extensions.partialclone config option limits the partial clone and
> promisor features to only one remote. One related issue is that it
> also prevents to have other kind of promisor/partial clone/odb
> remotes. By other kind I mean remotes that would not necessarily be
> git repos, but that could store objects (that's where ODB, for Object
> DataBase, comes from) and could provide those objects to Git through a
> helper (or driver) script or program.

I do not think "sources that are not git repositories" is all that
interesting, unless they can also serve as the source for ext::
remote helper.  And if they can serve "git fetch ext::...", I think
they can be treated just like a normal Git repository by the
backfill code that needs to lazily populate the partial clone.

And it would be nice to be able to say "I took these commits from
that remote and that remote should be able to backfill the trees and
the blobs necessary to complete these commits" for more than one
remote would obviously be a good thing.  The way we mark the
promisor packs currently is by a mere presence of a file, but
nothing prevents us from extending it to write the nickname of the
configured remote the pack was taken from to help us answer "who can
feed us the remaining objects?", for example, so I do not think it
is an insurmountable problem

I guess JTan is the primary person who is interested/working on the
partial clone with backfill?  Have you two been collaborating well?

Do you two need help from us to make that happen, and if so what do
you need?  Stop the world and declare this and that source files are
off limits for two weeks, or something like that?




Re: [GSoC][PATCH v8 18/20] stash: convert `stash--helper.c` into `stash.c`

2018-09-25 Thread Paul-Sebastian Ungureanu

Hi,

  
@@ -1443,9 +1448,10 @@ static int push_stash(int argc, const char **argv, const char *prefix)

OPT_END()
};
  
-	argc = parse_options(argc, argv, prefix, options,

-git_stash_helper_push_usage,
-0);
+   if (argc)
+   argc = parse_options(argc, argv, prefix, options,
+git_stash_push_usage,
+0);


Is this `if (argc)` guard necessary?


Yes because without it, there would be a seg fault when
calling `git stash`. Why?

After spawning `git stash`, in `push_stash()`: `argc` would be
0 (and `argv` would be `NULL`).

`parse_options()` calls `parse_options_start()` which does the following:

ctx->argc = ctx->total = argc - 1;
ctx->argv = argv + 1;

So, `ctx->argc` would be `-1`. After we are back to `parse_options()`,
`parse_options_step()` would be called. In `parse_options_step()`:

for (; ctx->argc; ctx->argc--, ctx->argv++)

Which is an infinite loop, because `ctx->argc` is already -1.

This check is also done for `git notes list` (function `list()`
inside `builtin/notes.c`). Now, that I relook at it, it seems to me
that this is a bug. Probably a better solution would be to check at the 
beginning of `parse_options()` and return early if `argc` is less then one.



@@ -1536,7 +1544,44 @@ int cmd_stash__helper(int argc, const char **argv, const 
char *prefix)
return !!push_stash(argc, argv, prefix);
else if (!strcmp(argv[0], "save"))
return !!save_stash(argc, argv, prefix);
+   else if (*argv[0] != '-')
+   usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
+ git_stash_usage, options);
+
+   if (strcmp(argv[0], "-p")) {
+   while (++i < argc && strcmp(argv[i], "--")) {
+   /*
+* `akpqu` is a string which contains all short options,
+* except `-m` which is verified separately.
+*/
+   if ((strlen(argv[i]) == 2) && *argv[i] == '-' &&
+   strchr("akpqu", argv[i][1]))


I *think* this is missing the `n`.


I guess that by `n` you are referring to the short option of
`--no-keep-index`, which is missing because it was also omitted
in `stash.sh`. I am not sure whether it is worth adding it. In
case `stash` will learn any other option starting with `n`, this
might create confusion amongst users.

Best regards,
Paul


Re: [GSoC][PATCH v8 14/20] stash: convert create to builtin

2018-09-25 Thread Paul-Sebastian Ungureanu

Hi,

Sorry for the late reply. I had a lot on my plate for the last couple of 
weeks.



+
+   git_config(git_diff_basic_config, NULL);


Is this not called in as part of `git_config(git_default_config, NULL);`
in cmd_stash() already?

*clicketyclick*

I guess not. But then, maybe it would make sense to run with
`git_diff_basic_config` from the get go, to avoid having to run
`git_config()` twice.


I am not sure I got it right, but if I did:

Running `git_config` with `git_diff_basic_config` from the
beginning wouldn't be pointless when we would use any other
command than `create`, `push` and `save`? Although it might
confuse the reader a little bit, the stash should run without
problems.

Best,
Paul


Re: [PATCH] fetch-pack: approximate no_dependents with filter

2018-09-25 Thread Junio C Hamano
Jonathan Tan  writes:

> Whenever a lazy fetch is performed for a tree object, any trees and
> blobs it directly or indirectly references will be fetched as well.
> There is a "no_dependents" argument in struct fetch_pack_args that
> indicates that objects that the wanted object references need not be
> sent, but it currently has no effect other than to inhibit usage of
> object flags.
>
> Extend the "no_dependents" argument to also exclude sending of objects
> as much as the current protocol allows: when fetching a tree, all trees
> it references will be sent (but not the blobs), and when fetching a
> blob, it will still be sent. (If this mechanism is used to fetch a
> commit or any other non-blob object, all referenced objects, except
> blobs, will be sent.) The client neither needs to know or specify the
> type of each object it wants.
>
> The necessary code change is done in fetch_pack() instead of somewhere
> closer to where the "filter" instruction is written to the wire so that
> only one part of the code needs to be changed in order for users of all
> protocol versions to benefit from this optimization.

It is very clear how you are churning the code, but it is utterly
unclear from the description what you perceived as a problem and why
this change is a good (if not the best) solution for that problem,
at least to me.

After reading the above description, I cannot shake the feeling that
this is tied too strongly to the tree:0 use case?  Does it help
other use cases (e.g. would it be useful or harmful if a lazy clone
was done to exclude blobs that are larger than certain threshold, or
objects of all types that are not referenced by commits younger than
certain threshold)?



Re: [PATCH 1/1] config doc: highlight the name=value syntax

2018-09-25 Thread Junio C Hamano
Philip Oakley  writes:

> +Variable name/value syntax
> +^^
> +
>  All the other lines (and the remainder of the line after the section
>  header) are recognized as setting variables, in the form
>  'name = value' (or just 'name', which is a short-hand to say that
> @@ -69,7 +72,8 @@ stripped.  Leading whitespaces after 'name =', the 
> remainder of the
>  line after the first comment character '#' or ';', and trailing
>  whitespaces of the line are discarded unless they are enclosed in
>  double quotes.  Internal whitespaces within the value are retained
> -verbatim.
> +verbatim. Single quotes are not special and form part of the
> +variable's value.
>  
>  Inside double quotes, double quote `"` and backslash `\` characters
>  must be escaped: use `\"` for `"` and `\\` for `\`.

Hmph.  This feels a bit backwards.  

The original paragraph is horrible in that there is no clear mention
that a pair of dq can be used to quote (which primarily is useful if
your value have leading or trailing whitespaces); the closest hint
is "enclosed in double quotes" we see in the pre-context.  The added
sentence singles out sq but it is unclear why it is necessary to
call out that it is not special---the readers can legitimately
wonder if backquotes are special or not and why.

I wonder if this is easier to understand:

diff --git a/Documentation/config.txt b/Documentation/config.txt
index ad0f4510c3..5eebd539df 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -61,12 +61,16 @@ the variable is the boolean "true").
 The variable names are case-insensitive, allow only alphanumeric characters
 and `-`, and must start with an alphabetic character.

+The value part can have segments that are enclosed in a pair of
+double quotes (note: other kinds of quoting character pairs are not
+special)--the double quotes are stripped from the value.
+
 A line that defines a value can be continued to the next line by
 ending it with a `\`; the backquote and the end-of-line are
 stripped.  Leading whitespaces after 'name =', the remainder of the
 line after the first comment character '#' or ';', and trailing
-whitespaces of the line are discarded unless they are enclosed in
-double quotes.  Internal whitespaces within the value are retained
+whitespaces of the line are discarded.
+Internal whitespaces within the value are retained
 verbatim.

 Inside double quotes, double quote `"` and backslash `\` characters

> @@ -89,10 +93,14 @@ each other with the exception that `includeIf` sections 
> may be ignored
>  if their condition does not evaluate to true; see "Conditional includes"
>  below.
>  
> +Both the `include` and `includeIf` sections implicitly apply an 'if found'
> +condition to the given path names.
> +

Mentioning that missing target file is not an error is definitely an
improvement.  I've never viewed it as applying "if found" condition
myself, but it is not wrong per-se to do so, I would think.

>  You can include a config file from another by setting the special
>  `include.path` (or `includeIf.*.path`) variable to the name of the file
>  to be included. The variable takes a pathname as its value, and is
> -subject to tilde expansion. These variables can be given multiple times.
> +subject to tilde expansion and the value syntax detailed above.
> +These variables can be given multiple times.

I have a mild suspicion that this adds negative value.  Singling out
that "[include] path = ..."  follows the usual value syntax makes
the readers wonder if there are some "[section] variable = ..." that
does not follow the value syntax that they have to be aware of and
careful about.


Urgent,

2018-09-25 Thread Juliet Muhammad
Hello 

   i have been trying to contact you i have a transaction for you.


Re: [PATCH v3 1/5] CodingGuidelines: add shell piping guidelines

2018-09-25 Thread Matthew DeVore
On Mon, Sep 24, 2018 at 2:03 PM SZEDER Gábor  wrote:
> > + - In a piped chain such as "grep blob objects | sort", the exit codes
>
> Let's make an example with git in it, e.g. something like this:
>
>   git cmd | grep important | sort
>
> since just two lines below the new text mentions git crashing.
Done.

> > + - The $(git ...) construct also discards git's exit code, so if the
>
> This contruct is called command substitution, and it does preserve the
> command's exit code, when the expanded text is assigned to a variable:
>
>   $ var=$(exit 42) ; echo $?
>   42
>
> Note, however, that even in that case only the exit code of the last
> command substitution is preserved:
>
>   $ var=$(exit 1)foo$(exit 2)bar$(exit 3) ; echo $?
>   3
>
OK, I've changed this guideline to allow for setting a variable with
command substitution, but not in other contexts. It's worded
sufficiently openly such that your latter example will be forbidden.

> > +   goal is to test that particular command, redirect its output to a
> > +   temporary file rather than wrap it with $( ).
>
> I find this a bit vague, and to me it implies that ignoring the exit
> code of a git command that is not the main focus of the given test is
> acceptable, e.g. (made up pseudo example):
>
>   test_expect_success 'fetch gets what it should' '
> git fetch $remote &&
> test "$(git rev-parse just-fetched)" = $expected_oid
>   '
>
> In my opinion no tests should ignore the exit code of any git
> command, ever.

This seems like a pretty strong assertion, but something very similar
is written in t/README (in the "don't" section):

 - use '! git cmd' when you want to make sure the git command exits
   with failure in a controlled way by calling "die()".  Instead,
   use 'test_must_fail git cmd'.  This will signal a failure if git
   dies in an unexpected way (e.g. segfault).

So I've changed this to basically say you should never ignore git's exit code.

Here is the new commit with updated message (I will wait for a day or
two before I send a reroll):

Documentation: add shell guidelines

Add the following guideline to Documentation/CodingGuidelines:

&&, ||, and | should appear at the end of lines, not the
beginning, and the \ line continuation character should be
omitted

And the following to t/README (since it is specific to writing tests):

pipes and $(git ...) should be avoided when they swallow exit
codes of Git processes

Signed-off-by: Matthew DeVore 

diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 48aa4edfb..3d2cfea9b 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -118,6 +118,24 @@ For shell scripts specifically (not exhaustive):
 do this
 fi

+ - If a command sequence joined with && or || or | spans multiple
+   lines, put each command on a separate line and put && and || and |
+   operators at the end of each line, rather than the start. This
+   means you don't need to use \ to join lines, since the above
+   operators imply the sequence isn't finished.
+
+(incorrect)
+grep blob verify_pack_result \
+| awk -f print_1.awk \
+| sort >actual &&
+...
+
+(correct)
+grep blob verify_pack_result |
+awk -f print_1.awk |
+sort >actual &&
+...
+
  - We prefer "test" over "[ ... ]".

  - We do not write the noiseword "function" in front of shell
@@ -163,7 +181,6 @@ For shell scripts specifically (not exhaustive):

does not have such a problem.

-
 For C programs:

  - We use tabs to indent, and interpret tabs as taking up to
diff --git a/t/README b/t/README
index 9028b47d9..3e28b72c4 100644
--- a/t/README
+++ b/t/README
@@ -461,6 +461,32 @@ Don't:
platform commands; just use '! cmd'.  We are not in the business
of verifying that the world given to us sanely works.

+ - Use Git upstream in the non-final position in a piped chain, as in:
+
+ git -C repo ls-files |
+ xargs -n 1 basename |
+ grep foo
+
+   which will discard git's exit code and may mask a crash. In the
+   above example, all exit codes are ignored except grep's.
+
+   Instead, write the output of that command to a temporary
+   file with ">" or assign it to a variable with "x=$(git ...)" rather
+   than pipe it.
+
+ - Use command substitution in a way that discards git's exit code.
+   When assigning to a variable, the exit code is not discarded, e.g.:
+
+ x=$(git cat-file -p $sha) &&
+ ...
+
+   is OK because a crash in "git cat-file" will cause the "&&" chain
+   to fail, but:
+
+ test_cmp expect $(git cat-file -p $sha)
+
+   is not OK and a crash in git could go undetected.
+
  - use perl without spelling it as "$PERL_PATH". This is to help our
friends on Windows where the platform Perl often adds CR before
the end of line, and they bundle Git with a version of Perl that


>
>
> These last 

Urgent,

2018-09-25 Thread Juliet Muhammad
Hello 

   i have been trying to contact you i have a transaction for you.


[ANNOUNCE] New Git PLC Members

2018-09-25 Thread Jeff King
I mentioned about a month ago in [1] that we needed to add members to
the committee representing the Git project as part of Software Freedom
Conservancy (see that email for details on what exactly that means :) ).

I'm happy to announce that this is now done, and both Christian and Ævar
are on the committee. Welcome to both of you!

As before, if you have project governance questions, the best point of
contact is g...@sfconservancy.org, which goes to the four committee
members, along with a few Conservancy folks. Though unless it
specifically needs to be private, I'd generally encourage people to
raise issues first on the list so the whole community can discuss.

-Peff

[1] https://public-inbox.org/git/20180816224138.ga15...@sigill.intra.peff.net/


Urgent,

2018-09-25 Thread Juliet Muhammad
Hello 

   i have been trying to contact you i have a transaction for you.


Re: git fetch behaves weirdely when run in a worktree

2018-09-25 Thread Junio C Hamano
Kaartic Sivaraam  writes:

>>  Also please try
>> "git fetch" again with GIT_TRACE=1 and GIT_TRACE_SETUP=1. Hopefully we
>> could catch something with that.
>
> $ GIT_TRACE_SETUP=1 GIT_TRACE=1 git fetch origin next
> 23:10:26.049785 trace.c:377 setup: git_dir: 
> $COMMON_ROOT/git/.git/worktrees/git-next-build-automate
> ...
> 23:10:28.402815 git.c:415   trace: built-in: git rev-list 
> --objects --stdin --not --all --quiet
> From https://github.com/git/git
>  * branch  next   -> FETCH_HEAD
> 23:10:28.437350 run-command.c:1553  run_processes_parallel: preparing to 
> run up to 1 tasks
> ...

That looks like fetching only the 'next' branch and nothing else to
me.

Perhaps your script is referring to a variable whose assignment is
misspelled and invoking

git fetch $origin $branch

and you are expecting the $branch variable to have string 'next' but
due to some bugs it is empty somehow?  That explains why sometimes
(i.e. when $branch does not get the value you expect it to have) the
script fetches everything and some other times (i.e. when $branch
does get the right value) the script fetches only the named branch.



Re: [PATCH] worktree: add per-worktree config files

2018-09-25 Thread Junio C Hamano
Nguyễn Thái Ngọc Duy   writes:

> This extension is most useful in multiple worktree setup because you
> now have an option to store per-worktree config (which is either
> .git/config.worktree for main worktree, or
> .git/worktrees/xx/config.worktree for linked ones).

Heh.  "This is useful if you have multiple" is true without saying,
because this is totally useless if you have only a single worktree.
I'd suggest writing the above without "most useful".

> This design places a bet on the assumption that the majority of config
> variables are shared so it is the default mode. A safer move would be
> default writes go to per-worktree file, so that accidental changes are
> isolated.

Warning: devil's advocate mode on.

Done in either way, this will confuse the users.  What is the reason
why people are led to think it is a good idea to use multiple
worktrees, even when they need different settings?  What do they
want out of "multiple worktrees linked to a single repository" as
opposed to just a simple "as many clones as necessary"?  Reduced
disk footprint?  Is there a better way to achieve that without the
downside of multiple worktrees (e.g. configuration need to be
uniform)?

> (*) "git config --worktree" points back to "config" file when this
> extension is not present so that it works in any setup.

Shouldn't it barf and error out instead?  A user who hasn't enabled
the extension uses --worktree option and misled to believe that the
setting affects only a single worktree, even though the change is
made globally---that does not sound like a great end-user experience.


Re: [PATCH 1/1] read-cache: update index format default to v4

2018-09-25 Thread Ben Peart




On 9/25/2018 2:01 PM, Stefan Beller wrote:

On Tue, Sep 25, 2018 at 7:30 AM Derrick Stolee  wrote:


On 9/25/2018 3:06 AM, Patrick Steinhardt wrote:

On Mon, Sep 24, 2018 at 11:32:23PM +0200, SZEDER Gábor wrote:

On Mon, Sep 24, 2018 at 02:15:30PM -0700, Derrick Stolee via GitGitGadget wrote:

From: Derrick Stolee 

The index v4 format has been available since 2012 with 9d22778
"reach-cache.c: write prefix-compressed names in the index". Since
the format has been stable for so long, almost all versions of Git
in use today understand version 4, removing one barrier to upgrade
-- that someone may want to downgrade and needs a working repo.

What about alternative implementations, like JGit, libgit2, etc.?

Speaking of libgit2, we are able to read and write index v4 since
commit c1b370e93


This is a good point, Szeder.

Patrick: I'm glad LibGit2 is up-to-date with index formats.

Unfortunately, taking a look (for the first time) at the JGit code
reveals that they don't appear to have v4 support. In
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java, the
DirCache.readFrom() method: lines 488-494, I see the following snippet:

  final int ver = NB.decodeInt32(hdr, 4);
  boolean extended = false;
  if (ver == 3)
  extended = true;
  else if (ver != 2)
  throw new
CorruptObjectException(MessageFormat.format(
JGitText.get().unknownDIRCVersion, Integer.valueOf(ver)));

It looks like this will immediately throw with versions other than 2 or 3.

I'm adding Jonathan Nieder to CC so he can check with JGit people about
the impact of this change.


JGit is used both on the server (which doesn't use index/staging area)
as well as client side as e.g. an Eclipse integration, which would
very much like to use the index.

Adding Matthias Sohn as well, who is active in JGit and cares
more about the client side than Googlers who only make use
of the server side part of JGit.

Stefan



In addition to the compatibility with other implementations of git 
question, I think we should include Duy's patch [1] to "optimize reading 
index format v4" before flipping the default to V4.


In my testing, this reduced the index load time of V4 by 10%-15% making 
the CPU cost only ~2% more expensive than V2 or V3 indexes.  This 
increase in CPU cost is more than offset by the significant reduction in 
file IO due to the reduced index file size.


[1] https://public-inbox.org/git/20180825064458.28484-1-pclo...@gmail.com/


Re: [PATCH 3/8] refs: new ref types to make per-worktree refs visible to all worktrees

2018-09-25 Thread Junio C Hamano
Nguyễn Thái Ngọc Duy   writes:

> The main worktree has to be treated specially because well.. it's
> special from the beginning. So HEAD from the main worktree is
> acccessible via the name "main/HEAD" (we can't use
> "worktrees/main/HEAD" because "main" under "worktrees" is not
> reserved).

I do not quite follow.  So with this, both refs/heads/master and
main/refs/heads/master are good names for the master branch (even
though the local branch names are not per worktree), because
in the main worktree, refs/bisect/bad and main/refs/bisect/bad ought
to mean the same thing.

side note: Or is this only for pseudo-refs
(i.e. $GIT_DIR/$name where $name consists of all caps or
underscore and typically ends with HEAD)?  Even if that were
the case, I do not think it essentially changes the issue
around disambiguation that much.

The disambiguation rule has always been: if you have a confusingly
named ref, you can spell it out fully to avoid any ambiguity, e.g.
refs/heads/refs/heads/foo can be given to "git rev-parse" and will
mean the tip of the branch whose name is "refs/heads/foo", even when
another branch whose name is "foo" exists.

Would we have a reasonable disambiguation rules that work well with
the main/ and worktrees/* prefixes?  When somebody has main/HEAD branch
and writes "git rev-parse main/HEAD", does it find refs/heads/main/HEAD
or $GIT_DIR/HEAD, if the user is in the main worktree?

It could be simply that the design is underdocumented in this patch
set (in which case I would have appreciated 'RFC' near 'PATCH'), but
I have a feeling that the code came way too early before such design
issues are fleshed out.

> diff --git a/refs.h b/refs.h
> index bd52c1bbae..9b53dbeae8 100644
> --- a/refs.h
> +++ b/refs.h
> @@ -704,9 +704,11 @@ int parse_hide_refs_config(const char *var, const char 
> *value, const char *);
>  int ref_is_hidden(const char *, const char *);
>  
>  enum ref_type {
> - REF_TYPE_PER_WORKTREE,
> - REF_TYPE_PSEUDOREF,
> - REF_TYPE_NORMAL,
> + REF_TYPE_PER_WORKTREE,/* refs inside refs/ but not shared   */
> + REF_TYPE_PSEUDOREF,   /* refs outside refs/ in current worktree */
> + REF_TYPE_MAIN_PSEUDOREF,  /* pseudo refs from the main worktree */
> + REF_TYPE_OTHER_PSEUDOREF, /* pseudo refs from other worktrees   */
> + REF_TYPE_NORMAL,  /* normal/shared refs inside refs/*/
>  };
>  
>  enum ref_type ref_type(const char *refname);
> diff --git a/refs/files-backend.c b/refs/files-backend.c
> index 416eafa453..bf9ed633b1 100644
> --- a/refs/files-backend.c
> +++ b/refs/files-backend.c
> @@ -149,6 +149,23 @@ static struct files_ref_store *files_downcast(struct 
> ref_store *ref_store,
>   return refs;
>  }
>  
> +static void files_reflog_path_other_worktrees(struct files_ref_store *refs,
> +   struct strbuf *sb,
> +   const char *refname)
> +{
> + const char *real_ref;
> +
> + if (!skip_prefix(refname, "worktrees/", _ref))
> + BUG("refname %s is not a other-worktree ref", refname);
> + real_ref = strchr(real_ref, '/');
> + if (!real_ref)
> + BUG("refname %s is not a other-worktree ref", refname);
> + real_ref++;
> +
> + strbuf_addf(sb, "%s/%.*slogs/%s", refs->gitcommondir,
> + (int)(real_ref - refname), refname, real_ref);
> +}
> +
>  static void files_reflog_path(struct files_ref_store *refs,
> struct strbuf *sb,
> const char *refname)
> @@ -158,6 +175,12 @@ static void files_reflog_path(struct files_ref_store 
> *refs,
>   case REF_TYPE_PSEUDOREF:
>   strbuf_addf(sb, "%s/logs/%s", refs->gitdir, refname);
>   break;
> + case REF_TYPE_OTHER_PSEUDOREF:
> + return files_reflog_path_other_worktrees(refs, sb, refname);
> + case REF_TYPE_MAIN_PSEUDOREF:
> + if (!skip_prefix(refname, "main/", ))
> + BUG("ref %s is not a main pseudoref", refname);
> + /* passthru */
>   case REF_TYPE_NORMAL:
>   strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
>   break;
> @@ -176,6 +199,11 @@ static void files_ref_path(struct files_ref_store *refs,
>   case REF_TYPE_PSEUDOREF:
>   strbuf_addf(sb, "%s/%s", refs->gitdir, refname);
>   break;
> + case REF_TYPE_MAIN_PSEUDOREF:
> + if (!skip_prefix(refname, "main/", ))
> + BUG("ref %s is not a main pseudoref", refname);
> + /* passthru */
> + case REF_TYPE_OTHER_PSEUDOREF:
>   case REF_TYPE_NORMAL:
>   strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
>   break;
> diff --git a/t/t1415-worktree-refs.sh b/t/t1415-worktree-refs.sh
> index 0c2d5f89a9..46ca7bfc19 100755
> --- a/t/t1415-worktree-refs.sh
> +++ 

Re: Git Test Coverage Report (Tuesday, Sept 25)

2018-09-25 Thread Ben Peart




On 9/25/2018 2:42 PM, Derrick Stolee wrote:
In an effort to ensure new code is reasonably covered by the test suite, 
we now have contrib/coverage-diff.sh to combine the gcov output from 
'make coverage-test ; make coverage-report' with the output from 'git 
diff A B' to discover _new_ lines of code that are not covered.


This report takes the output of these results after running on four 
branches:


         pu: 80e728fa913dc3a1165b6dec9a7afa6052a86325

        jch: 0c10634844314ab89666ed0a1c7d36dde7ac9689

       next: 76f2f5c1e34c4dbef1029e2984c2892894c444ce

     master: fe8321ec057f9231c26c29b364721568e58040f7

master@{1}: 2d3b1c576c85b7f5db1f418907af00ab88e0c303

I ran the test suite on each of these branches on an Ubuntu Linux VM, 
and I'm missing some dependencies (like apache, svn, and perforce) so 
not all tests are run.


I submit this output without comment. I'm taking a look especially at my 
own lines to see where coverage can be improved.




Thanks for driving this.  I think it provides an interesting view into 
new code and how well it is being tested.  In an effort to make this as 
useful as possible, we should be looking to eliminate as much noise as 
possible otherwise people will stop looking at it.


I looked at the lines that came from my patches and most if not all of 
them are only going to be executed by the test suite if the correct 
"special setup" option is enabled.  In my particular case, that is the 
option "GIT_TEST_INDEX_THREADS=" as documented in t/README.


I suspect this will be the case for other code as well so I wonder if 
the tests should be run with each the GIT_TEST_* options that exist to 
exercise uncommon code paths with the test suite.  This should prevent 
false positives on code paths that are actually covered by the test 
suite as long as it is run with the appropriate option set.


I realize it would take a long time to run the entire test suite with 
all GIT_TEST_* variables so perhaps they can only be tested "as needed" 
(ie when patches add new variables in the "special setups" section of 
t/README).  This should reduce the number of combinations that need to 
be run while still eliminating many of the false positive hits.




Re: [PATCH] ref-filter: don't look for objects when outside of a repository

2018-09-25 Thread Junio C Hamano
SZEDER Gábor  writes:

> However, if we go for a more informative error message, then wouldn't
> it be better to add this condition in populate_value() before it even
> calls get_object()?  Then we could also add the problematic format
> specifier to the error message (I think, but didn't actually check),
> just in case someone specified multiple sort keys.

Even though I suspect that verify_ref_format() is the logically the
right place to do this (after all, it is about seeing if the format
makes sense, and a format that requires an object access used
outside a repository should trigger an verification error), doing
that in populate_value() probably strikes the best balance, I would
think.



Re: [PATCH] git help: promote 'git help -av'

2018-09-25 Thread Jeff King
On Tue, Sep 25, 2018 at 07:44:51PM +0200, Duy Nguyen wrote:

> > I think adding another section about external commands in "help -av"
> > would address the "clang-format" stuff. With that, it's probably good
> > enough to completely replace "help -a". It may also be good to list
> > aliases there too in a separate section so you have "all you can type"
> > in one (big) list.
> 
> Here's the patch that adds that external commands and aliases
> sections. I feel that external commands section is definitely good to
> have even if we don't replace "help -a". Aliases are more
> subjective...

Just eyeballing the output, it looks pretty reasonable to me. The lack
of explanation for external commands really stands out, but there's not
much we can do.

That part of the output is not very compact, and we _could_ put it in
columns, but that might be confusing since the rest of the output is
one-per-line.

Mentioning aliases seems reasonable to me. The definitions of some of
mine are pretty nasty bits of shell, but I guess that people either
don't have any ugly aliases, or are comfortable enough with them that
they won't be scared away. :)

> -- 8< --
> @@ -53,7 +52,6 @@ static struct option builtin_help_options[] = {
>   HELP_FORMAT_WEB),
>   OPT_SET_INT('i', "info", _format, N_("show info page"),
>   HELP_FORMAT_INFO),
> - OPT__VERBOSE(, N_("print command description")),
>   OPT_END(),
>  };

Would we want to continue respecting "-v" as a noop? I admit I did not
even know it existed until this thread, but if people have trained
themselves to run "git help -av", we should probably continue to give
them this output.

-Peff


Re: [PATCH 1/3] t7001: reformat to newer style

2018-09-25 Thread Junio C Hamano
Stefan Beller  writes:

> Heh, thanks for calling that out. So we're looking at a full formatter
> instead of a partial formatter that helps moving in the right direction now. 
> :-/

The parts left out of these patches (e.g. use subshell when working
in a subdirectory) need human decision and a bit of good taste, and
I think it was a good design decision to keep these three patches
all mechanical.  There do need a follow-up [PATCH {4,5,6}/3] that
cannot be done mechanically, though, before the result can be called
"this script has been cleaned up and new people are encouraged to
mimick the way it does things".  

That way, we can keep the mechanically good bits that are early in
the series while polishing the later bits that need human judgement.




Greeting

2018-09-25 Thread Finance
Hello Dear,

I am working in financial firm in Asia. I have a business to transfer i have 
abandon $19.000.000.00 in my office.
If you are interested in the transaction, please reply for full information.

Best Regards,
Financial Asia


Re: [PATCH] commit-reach: cleanups in can_all_from_reach...

2018-09-25 Thread Junio C Hamano
Derrick Stolee  writes:

> Another commit walk that could be improved by generation numbers? It's
> like my bat-signal!

Ah, nevermind.  The "traversal" done by these helper functions is
the most stupid kind (not the algorthim, but the need).  It's not
like there is an opportunity to optimize by not traversing the
remainder if we choose the order of traversal intelligently, so any
algorithm that does not visit the same node twice and does not do
the most naive recursion would work, and what we currently have
there is just fine.


Re: Git for games working group

2018-09-25 Thread Taylor Blau
On Mon, Sep 24, 2018 at 09:05:56PM -0700, John Austin wrote:
> On Mon, Sep 24, 2018 at 12:58 PM Taylor Blau  wrote:
> > I'm replying to this part of the email to note that this would cause Git
> > LFS to have to do some extra work, since running 'git lfs install'
> > already writes to .git/hooks/post-commit (ironically, to detect and
> > unlock locks that we should have released).
>
> Right, that should have been another bullet point. The fact that there
> can only be one git hook is.. frustrating.

Sure, I think one approach to dealing with this is to teach Git how to
handle multiple hooks for the same phase of hook.

I don't know how likely this is in practice to be something that would
be acceptable, since it seems to involve much more work than either of
our tools learning about the other.

> Perhaps, if LFS has an option to bundle global-graph, LFS could merge
> the hooks when installing?

Right. I think that (in an ideal world) both tools would know about the
other, that way we can not have to worry about who installs what first.

> If you instead install global-graph after LFS, I think it should
> probably attempt something like:
>   -- first move the existing hook to a folder: post-commit.d/
>   -- install the global-graph hook to post-commit.d/
>   -- install a new hook at post-commit that simply calls all
> executables in post-commit.d/
>
> Not sure if this is something that's been discussed, since I know LFS
> has a similar issue with existing hooks, but might be sensible.

Yeah, I think that that would be fine, too.

Thanks,
Taylor


[PATCH v4 4/9] submodule: move global changed_submodule_names into fetch submodule struct

2018-09-25 Thread Stefan Beller
The `changed_submodule_names` are only used for fetching, so let's make it
part of the struct that is passed around for fetching submodules.

Signed-off-by: Stefan Beller 
---
 submodule.c | 42 +++---
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/submodule.c b/submodule.c
index 22c64bd8559..17103379ba4 100644
--- a/submodule.c
+++ b/submodule.c
@@ -25,7 +25,7 @@
 #include "commit-reach.h"
 
 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
-static struct string_list changed_submodule_names = STRING_LIST_INIT_DUP;
+
 static int initialized_fetch_ref_tips;
 static struct oid_array ref_tips_before_fetch;
 static struct oid_array ref_tips_after_fetch;
@@ -1110,7 +1110,22 @@ void check_for_new_submodule_commits(struct object_id 
*oid)
oid_array_append(_tips_after_fetch, oid);
 }
 
-static void calculate_changed_submodule_paths(void)
+struct submodule_parallel_fetch {
+   int count;
+   struct argv_array args;
+   struct repository *r;
+   const char *prefix;
+   int command_line_option;
+   int default_option;
+   int quiet;
+   int result;
+
+   struct string_list changed_submodule_names;
+};
+#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0, 
STRING_LIST_INIT_DUP }
+
+static void calculate_changed_submodule_paths(
+   struct submodule_parallel_fetch *spf)
 {
struct argv_array argv = ARGV_ARRAY_INIT;
struct string_list changed_submodules = STRING_LIST_INIT_DUP;
@@ -1148,7 +1163,8 @@ static void calculate_changed_submodule_paths(void)
continue;
 
if (!submodule_has_commits(path, commits))
-   string_list_append(_submodule_names, 
name->string);
+   string_list_append(>changed_submodule_names,
+  name->string);
}
 
free_submodules_oids(_submodules);
@@ -1185,18 +1201,6 @@ int submodule_touches_in_range(struct object_id 
*excl_oid,
return ret;
 }
 
-struct submodule_parallel_fetch {
-   int count;
-   struct argv_array args;
-   struct repository *r;
-   const char *prefix;
-   int command_line_option;
-   int default_option;
-   int quiet;
-   int result;
-};
-#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0}
-
 static int get_fetch_recurse_config(const struct submodule *submodule,
struct submodule_parallel_fetch *spf)
 {
@@ -1257,7 +1261,7 @@ static int get_next_submodule(struct child_process *cp,
case RECURSE_SUBMODULES_ON_DEMAND:
if (!submodule ||
!string_list_lookup(
-   _submodule_names,
+   >changed_submodule_names,
submodule->name))
continue;
default_argv = "on-demand";
@@ -1349,8 +1353,8 @@ int fetch_populated_submodules(struct repository *r,
argv_array_push(, "--recurse-submodules-default");
/* default value, "--submodule-prefix" and its value are added later */
 
-   calculate_changed_submodule_paths();
-   string_list_sort(_submodule_names);
+   calculate_changed_submodule_paths();
+   string_list_sort(_submodule_names);
run_processes_parallel(max_parallel_jobs,
   get_next_submodule,
   fetch_start_failure,
@@ -1359,7 +1363,7 @@ int fetch_populated_submodules(struct repository *r,
 
argv_array_clear();
 out:
-   string_list_clear(_submodule_names, 1);
+   string_list_clear(_submodule_names, 1);
return spf.result;
 }
 
-- 
2.19.0.605.g01d371f741-goog



[PATCH v4 3/9] submodule.c: sort changed_submodule_names before searching it

2018-09-25 Thread Stefan Beller
We can string_list_insert() to maintain sorted-ness of the
list as we find new items, or we can string_list_append() to
build an unsorted list and sort it at the end just once.

To pick which one is more appropriate, we notice the fact
that we discover new items more or less in the already
sorted order.  That makes "append then sort" more
appropriate.

Signed-off-by: Stefan Beller 
---
 submodule.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/submodule.c b/submodule.c
index 0de9e2800ad..22c64bd8559 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1256,7 +1256,7 @@ static int get_next_submodule(struct child_process *cp,
case RECURSE_SUBMODULES_DEFAULT:
case RECURSE_SUBMODULES_ON_DEMAND:
if (!submodule ||
-   !unsorted_string_list_lookup(
+   !string_list_lookup(
_submodule_names,
submodule->name))
continue;
@@ -1350,6 +1350,7 @@ int fetch_populated_submodules(struct repository *r,
/* default value, "--submodule-prefix" and its value are added later */
 
calculate_changed_submodule_paths();
+   string_list_sort(_submodule_names);
run_processes_parallel(max_parallel_jobs,
   get_next_submodule,
   fetch_start_failure,
-- 
2.19.0.605.g01d371f741-goog



[PATCH v4 1/9] sha1-array: provide oid_array_filter

2018-09-25 Thread Stefan Beller
Helped-by: Junio C Hamano 
Signed-off-by: Stefan Beller 
---
 Documentation/technical/api-oid-array.txt |  5 +
 sha1-array.c  | 17 +
 sha1-array.h  |  3 +++
 3 files changed, 25 insertions(+)

diff --git a/Documentation/technical/api-oid-array.txt 
b/Documentation/technical/api-oid-array.txt
index 9febfb1d528..c97428c2c34 100644
--- a/Documentation/technical/api-oid-array.txt
+++ b/Documentation/technical/api-oid-array.txt
@@ -48,6 +48,11 @@ Functions
is not sorted, this function has the side effect of sorting
it.
 
+`oid_array_filter`::
+   Apply the callback function `want` to each entry in the array,
+   retaining only the entries for which the function returns true.
+   Preserve the order of the entries that are retained.
+
 Examples
 
 
diff --git a/sha1-array.c b/sha1-array.c
index b94e0ec0f5e..d922e94e3fc 100644
--- a/sha1-array.c
+++ b/sha1-array.c
@@ -77,3 +77,20 @@ int oid_array_for_each_unique(struct oid_array *array,
}
return 0;
 }
+
+void oid_array_filter(struct oid_array *array,
+ for_each_oid_fn want,
+ void *cb_data)
+{
+   unsigned nr = array->nr, src, dst;
+   struct object_id *oids = array->oid;
+
+   for (src = dst = 0; src < nr; src++) {
+   if (want([src], cb_data)) {
+   if (src != dst)
+   oidcpy([dst], [src]);
+   dst++;
+   }
+   }
+   array->nr = dst;
+}
diff --git a/sha1-array.h b/sha1-array.h
index 232bf950172..55d016c4bf7 100644
--- a/sha1-array.h
+++ b/sha1-array.h
@@ -22,5 +22,8 @@ int oid_array_for_each(struct oid_array *array,
 int oid_array_for_each_unique(struct oid_array *array,
  for_each_oid_fn fn,
  void *data);
+void oid_array_filter(struct oid_array *array,
+ for_each_oid_fn want,
+ void *cbdata);
 
 #endif /* SHA1_ARRAY_H */
-- 
2.19.0.605.g01d371f741-goog



[PATCH v4 2/9] submodule.c: fix indentation

2018-09-25 Thread Stefan Beller
The submodule subsystem is really bad at staying within 80 characters.
Fix it while we are here.

Signed-off-by: Stefan Beller 
---
 submodule.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/submodule.c b/submodule.c
index b53cb6e9c47..0de9e2800ad 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1244,7 +1244,8 @@ static int get_next_submodule(struct child_process *cp,
if (!submodule) {
const char *name = default_name_or_path(ce->name);
if (name) {
-   default_submodule.path = default_submodule.name 
= name;
+   default_submodule.path = name;
+   default_submodule.name = name;
submodule = _submodule;
}
}
@@ -1254,8 +1255,10 @@ static int get_next_submodule(struct child_process *cp,
default:
case RECURSE_SUBMODULES_DEFAULT:
case RECURSE_SUBMODULES_ON_DEMAND:
-   if (!submodule || 
!unsorted_string_list_lookup(_submodule_names,
-submodule->name))
+   if (!submodule ||
+   !unsorted_string_list_lookup(
+   _submodule_names,
+   submodule->name))
continue;
default_argv = "on-demand";
break;
-- 
2.19.0.605.g01d371f741-goog



[PATCH v4 5/9] submodule.c: do not copy around submodule list

2018-09-25 Thread Stefan Beller
'calculate_changed_submodule_paths' uses a local list to compute the
changed submodules, and then produces the result by copying appropriate
items into the result list.

Instead use the result list directly and prune items afterwards
using string_list_remove_empty_items.

By doing so we'll have access to the util pointer for longer that
contains the commits that we need to fetch, which will be
useful in a later patch.

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

diff --git a/submodule.c b/submodule.c
index 17103379ba4..dd478ed70bf 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1128,8 +1128,7 @@ static void calculate_changed_submodule_paths(
struct submodule_parallel_fetch *spf)
 {
struct argv_array argv = ARGV_ARRAY_INIT;
-   struct string_list changed_submodules = STRING_LIST_INIT_DUP;
-   const struct string_list_item *name;
+   struct string_list_item *name;
 
/* No need to check if there are no submodules configured */
if (!submodule_from_path(the_repository, NULL, NULL))
@@ -1146,9 +1145,9 @@ static void calculate_changed_submodule_paths(
 * Collect all submodules (whether checked out or not) for which new
 * commits have been recorded upstream in "changed_submodule_names".
 */
-   collect_changed_submodules(_submodules, );
+   collect_changed_submodules(>changed_submodule_names, );
 
-   for_each_string_list_item(name, _submodules) {
+   for_each_string_list_item(name, >changed_submodule_names) {
struct oid_array *commits = name->util;
const struct submodule *submodule;
const char *path = NULL;
@@ -1162,12 +1161,14 @@ static void calculate_changed_submodule_paths(
if (!path)
continue;
 
-   if (!submodule_has_commits(path, commits))
-   string_list_append(>changed_submodule_names,
-  name->string);
+   if (submodule_has_commits(path, commits)) {
+   oid_array_clear(commits);
+   *name->string = '\0';
+   }
}
 
-   free_submodules_oids(_submodules);
+   string_list_remove_empty_items(>changed_submodule_names, 1);
+
argv_array_clear();
oid_array_clear(_tips_before_fetch);
oid_array_clear(_tips_after_fetch);
@@ -1363,7 +1364,7 @@ int fetch_populated_submodules(struct repository *r,
 
argv_array_clear();
 out:
-   string_list_clear(_submodule_names, 1);
+   free_submodules_oids(_submodule_names);
return spf.result;
 }
 
-- 
2.19.0.605.g01d371f741-goog



[PATCH v4 0/9] fetch: make sure submodule oids are fetched

2018-09-25 Thread Stefan Beller
v4:
* Per Ævars comment, moved the docs for oid_array_filter into
  Documentation/technical/...
* addressed all outstanding comment as noted in "What's cooking" email,
* below is a range-diff against the currently queued version of the
  series.

v3:
* I discovered some issues with v2 after sending,
  which is why I rewrote the later patches completely
  and now we pass around a "task" struct that contains everything to know
  about the things to work on and what needs free()ing afterwards.
* as it is no longer string list based, this drops adding string_list_{pop, 
last}

v2:
* extended commit messages,
* plugged a memory leak
* rewrote the patch "sha1-array: provide oid_array_filter" to be much more like 
  object_array_fiter
* fixed a typo pointed out by Ramsay.

The range diff is below.
  
Thanks,
Stefan

v1:
Currently when git-fetch is asked to recurse into submodules, it dispatches
a plain "git-fetch -C " (and some submodule related options
such as prefix and recusing strategy, but) without any information of the
remote or the tip that should be fetched.

This works surprisingly well in some workflows, not so well in others,
which this series aims to fix.

The first patches provide new basic functionality and do some refactoring;
the interesting part is in the two last patches.

This was discussed in
https://public-inbox.org/git/20180808221752.195419-1-sbel...@google.com/
and I think I addressed all feedback so far.

Stefan Beller (9):
  sha1-array: provide oid_array_filter
  submodule.c: fix indentation
  submodule.c: sort changed_submodule_names before searching it
  submodule: move global changed_submodule_names into fetch submodule
struct
  submodule.c: do not copy around submodule list
  repository: repo_submodule_init to take a submodule struct
  submodule: fetch in submodules git directory instead of in worktree
  fetch: retry fetching submodules if needed objects were not fetched
  builtin/fetch: check for submodule updates for non branch fetches

 Documentation/technical/api-oid-array.txt |   5 +
 builtin/fetch.c   |  14 +-
 builtin/grep.c|  17 +-
 builtin/ls-files.c|  12 +-
 builtin/submodule--helper.c   |   2 +-
 repository.c  |  27 +--
 repository.h  |  11 +-
 sha1-array.c  |  17 ++
 sha1-array.h  |   3 +
 submodule.c   | 275 +-
 t/t5526-fetch-submodules.sh   |  23 +-
 11 files changed, 311 insertions(+), 95 deletions(-)

git range-diff  origin/sb/submodule-recursive-fetch-gets-the-tip...

  1:  6fecf7cd01a <   -:  --- string-list: add string_list_{pop, last} 
functions
  2:  7007a318a68 <   -:  --- sha1-array: provide oid_array_filter

[ ... snip ... I rebased onto: ]

  -:  --- > 215:  fe8321ec057 Second batch post 2.19
  -:  --- > 216:  a9b49d4cfe9 sha1-array: provide oid_array_filter
  3:  807429234ac ! 217:  813205700d1 submodule.c: fix indentation
@@ -6,7 +6,6 @@
 Fix it while we are here.
 
 Signed-off-by: Stefan Beller 
-Signed-off-by: Junio C Hamano 
 
  diff --git a/submodule.c b/submodule.c
  --- a/submodule.c
  4:  f6fa5273af9 ! 218:  b4aa77f72ba submodule.c: sort changed_submodule_names 
before searching it
@@ -12,7 +12,6 @@
 appropriate.
 
 Signed-off-by: Stefan Beller 
-Signed-off-by: Junio C Hamano 
 
  diff --git a/submodule.c b/submodule.c
  --- a/submodule.c
  5:  adf7a2fd203 ! 219:  df4da0e18e4 submodule: move global 
changed_submodule_names into fetch submodule struct
@@ -6,13 +6,12 @@
 part of the struct that is passed around for fetching submodules.
 
 Signed-off-by: Stefan Beller 
-Signed-off-by: Junio C Hamano 
 
  diff --git a/submodule.c b/submodule.c
  --- a/submodule.c
  +++ b/submodule.c
 @@
- #include "object-store.h"
+ #include "commit-reach.h"
  
  static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
 -static struct string_list changed_submodule_names = STRING_LIST_INIT_DUP;
  6:  56c9398589a ! 220:  b9f5d06c134 submodule.c: do not copy around submodule 
list
@@ -9,12 +9,11 @@
 Instead use the result list directly and prune items afterwards
 using string_list_remove_empty_items.
 
-By doin so we'll have access to the util pointer for longer that
+By doing so we'll have access to the util pointer for longer that
 contains the commits that we need to fetch, which will be
 useful in a later patch.
 
 Signed-off-by: Stefan Beller 
-Signed-off-by: Junio C Hamano 
 
  diff --git a/submodule.c b/submodule.c
  --- a/submodule.c
  -:  --- > 221:  e5ff287a0a2 repository: repo_submodule_init to take a 

[PATCH v4 6/9] repository: repo_submodule_init to take a submodule struct

2018-09-25 Thread Stefan Beller
When constructing a struct repository for a submodule for some revision
of the superproject where the submodule is not contained in the index,
it may not be present in the working tree currently either. In that
siutation giving a 'path' argument is not useful. Upgrade the
repo_submodule_init function to take a struct submodule instead.

While we are at it, overhaul the repo_submodule_init function by renaming
the submodule repository struct, which is to be initialized, to a name
that is not confused with the struct submodule as easily.

Also move its documentation into the header file.

Signed-off-by: Stefan Beller 
---
 builtin/grep.c  | 17 ++---
 builtin/ls-files.c  | 12 +++-
 builtin/submodule--helper.c |  2 +-
 repository.c| 27 ++-
 repository.h| 11 +--
 5 files changed, 37 insertions(+), 32 deletions(-)

diff --git a/builtin/grep.c b/builtin/grep.c
index 601f801158f..81c53c862b1 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -418,16 +418,19 @@ static int grep_submodule(struct grep_opt *opt, struct 
repository *superproject,
  const struct object_id *oid,
  const char *filename, const char *path)
 {
-   struct repository submodule;
+   struct repository subrepo;
+   const struct submodule *sub = submodule_from_path(superproject,
+ _oid, path);
+
int hit;
 
if (!is_submodule_active(superproject, path))
return 0;
 
-   if (repo_submodule_init(, superproject, path))
+   if (repo_submodule_init(, superproject, sub))
return 0;
 
-   repo_read_gitmodules();
+   repo_read_gitmodules();
 
/*
 * NEEDSWORK: This adds the submodule's object directory to the list of
@@ -440,7 +443,7 @@ static int grep_submodule(struct grep_opt *opt, struct 
repository *superproject,
 * object.
 */
grep_read_lock();
-   add_to_alternates_memory(submodule.objects->objectdir);
+   add_to_alternates_memory(subrepo.objects->objectdir);
grep_read_unlock();
 
if (oid) {
@@ -465,14 +468,14 @@ static int grep_submodule(struct grep_opt *opt, struct 
repository *superproject,
 
init_tree_desc(, data, size);
hit = grep_tree(opt, pathspec, , , base.len,
-   object->type == OBJ_COMMIT, );
+   object->type == OBJ_COMMIT, );
strbuf_release();
free(data);
} else {
-   hit = grep_cache(opt, , pathspec, 1);
+   hit = grep_cache(opt, , pathspec, 1);
}
 
-   repo_clear();
+   repo_clear();
return hit;
 }
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 7f9919a3623..4d1649c1b3a 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -206,17 +206,19 @@ static void show_files(struct repository *repo, struct 
dir_struct *dir);
 static void show_submodule(struct repository *superproject,
   struct dir_struct *dir, const char *path)
 {
-   struct repository submodule;
+   struct repository subrepo;
+   const struct submodule *sub = submodule_from_path(superproject,
+ _oid, path);
 
-   if (repo_submodule_init(, superproject, path))
+   if (repo_submodule_init(, superproject, sub))
return;
 
-   if (repo_read_index() < 0)
+   if (repo_read_index() < 0)
die("index file corrupt");
 
-   show_files(, dir);
+   show_files(, dir);
 
-   repo_clear();
+   repo_clear();
 }
 
 static void show_ce(struct repository *repo, struct dir_struct *dir,
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 40844870cfb..1164e0979bd 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2037,7 +2037,7 @@ static int ensure_core_worktree(int argc, const char 
**argv, const char *prefix)
if (!sub)
BUG("We could get the submodule handle before?");
 
-   if (repo_submodule_init(, the_repository, path))
+   if (repo_submodule_init(, the_repository, sub))
die(_("could not get a repository handle for submodule '%s'"), 
path);
 
if (!repo_config_get_string(, "core.worktree", )) {
diff --git a/repository.c b/repository.c
index 5dd14867181..aabe64ee5d9 100644
--- a/repository.c
+++ b/repository.c
@@ -166,30 +166,23 @@ int repo_init(struct repository *repo,
return -1;
 }
 
-/*
- * Initialize 'submodule' as the submodule given by 'path' in parent repository
- * 'superproject'.
- * Return 0 upon success and a non-zero value upon failure.
- */
-int repo_submodule_init(struct repository *submodule,
+int repo_submodule_init(struct repository *subrepo,
struct repository 

[PATCH v4 9/9] builtin/fetch: check for submodule updates for non branch fetches

2018-09-25 Thread Stefan Beller
Gerrit, the code review tool, has a different workflow than our mailing
list based approach. Usually users upload changes to a Gerrit server and
continuous integration and testing happens by bots. Sometimes however a
user wants to checkout a change locally and look at it locally. For this
use case, Gerrit offers a command line snippet to copy and paste to your
terminal, which looks like

  git fetch https:///gerrit refs/changes/ &&
  git checkout FETCH_HEAD

For Gerrit changes that contain changing submodule gitlinks, it would be
easy to extend both the fetch and checkout with the '--recurse-submodules'
flag, such that this command line snippet would produce the state of a
change locally.

However the functionality added in the previous patch, which would
ensure that we fetch the objects in the submodule that the gitlink pointed
at, only works for remote tracking branches so far, not for FETCH_HEAD.

Make sure that fetching a superproject to its FETCH_HEAD, also respects
the existence checks for objects in the submodule recursion.

Signed-off-by: Stefan Beller 
---
 builtin/fetch.c | 5 -
 t/t5526-fetch-submodules.sh | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index e3b03ad3bd3..f2d9e548bf0 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -894,11 +894,14 @@ static int store_updated_refs(const char *raw_url, const 
char *remote_name,
rc |= update_local_ref(ref, what, rm, ,
   summary_width);
free(ref);
-   } else
+   } else {
+   check_for_new_submodule_commits(>old_oid);
format_display(, '*',
   *kind ? kind : "branch", NULL,
   *what ? what : "HEAD",
   "FETCH_HEAD", summary_width);
+   }
+
if (note.len) {
if (verbosity >= 0 && !shown_url) {
fprintf(stderr, _("From %.*s\n"),
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
index af12c50e7dd..a509eabb044 100755
--- a/t/t5526-fetch-submodules.sh
+++ b/t/t5526-fetch-submodules.sh
@@ -615,7 +615,7 @@ test_expect_success "fetch new commits on-demand when they 
are not reachable" '
git update-ref refs/changes/2 $D &&
(
cd downstream &&
-   git fetch --recurse-submodules --recurse-submodules-default 
on-demand origin refs/changes/2:refs/heads/my_branch &&
+   git fetch --recurse-submodules origin refs/changes/2 &&
git -C submodule cat-file -t $C &&
git checkout --recurse-submodules FETCH_HEAD
)
-- 
2.19.0.605.g01d371f741-goog



[PATCH v4 7/9] submodule: fetch in submodules git directory instead of in worktree

2018-09-25 Thread Stefan Beller
This patch started as a refactoring to make 'get_next_submodule' more
readable, but upon doing so, I realized that "git fetch" of the submodule
actually doesn't need to be run in the submodules worktree. So let's run
it in its git dir instead.

That should pave the way towards fetching submodules that are currently
not checked out.

This patch leaks the cp->dir in get_next_submodule, as any further
callback in run_processes_parallel doesn't have access to the child
process any more. In an early iteration of this patch, the function
get_submodule_repo_for directly returned the string containing the
git directory, which would be a better design choice for this patch.

However the next patch both fixes the memory leak of cp->dir and also has
a use case for using the full repository handle of the submodule, so
it makes sense to introduce the get_submodule_repo_for here already.

Signed-off-by: Stefan Beller 
---
 submodule.c | 51 +++--
 t/t5526-fetch-submodules.sh |  7 -
 2 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/submodule.c b/submodule.c
index dd478ed70bf..3f791f22771 100644
--- a/submodule.c
+++ b/submodule.c
@@ -481,6 +481,12 @@ void prepare_submodule_repo_env(struct argv_array *out)
 DEFAULT_GIT_DIR_ENVIRONMENT);
 }
 
+static void prepare_submodule_repo_env_in_gitdir(struct argv_array *out)
+{
+   prepare_submodule_repo_env_no_git_dir(out);
+   argv_array_pushf(out, "%s=.", GIT_DIR_ENVIRONMENT);
+}
+
 /* Helper function to display the submodule header line prior to the full
  * summary output. If it can locate the submodule objects directory it will
  * attempt to lookup both the left and right commits and put them into the
@@ -1227,6 +1233,29 @@ static int get_fetch_recurse_config(const struct 
submodule *submodule,
return spf->default_option;
 }
 
+static struct repository *get_submodule_repo_for(struct repository *r,
+const struct submodule *sub)
+{
+   struct repository *ret = xmalloc(sizeof(*ret));
+
+   if (repo_submodule_init(ret, r, sub)) {
+   /*
+* No entry in .gitmodules? Technically not a submodule,
+* but historically we supported repositories that happen to be
+* in-place where a gitlink is. Keep supporting them.
+*/
+   struct strbuf gitdir = STRBUF_INIT;
+   strbuf_repo_worktree_path(, r, "%s/.git", sub->path);
+   if (repo_init(ret, gitdir.buf, NULL)) {
+   strbuf_release();
+   return NULL;
+   }
+   strbuf_release();
+   }
+
+   return ret;
+}
+
 static int get_next_submodule(struct child_process *cp,
  struct strbuf *err, void *data, void **task_cb)
 {
@@ -1234,12 +1263,11 @@ static int get_next_submodule(struct child_process *cp,
struct submodule_parallel_fetch *spf = data;
 
for (; spf->count < spf->r->index->cache_nr; spf->count++) {
-   struct strbuf submodule_path = STRBUF_INIT;
-   struct strbuf submodule_git_dir = STRBUF_INIT;
struct strbuf submodule_prefix = STRBUF_INIT;
const struct cache_entry *ce = spf->r->index->cache[spf->count];
-   const char *git_dir, *default_argv;
+   const char *default_argv;
const struct submodule *submodule;
+   struct repository *repo;
struct submodule default_submodule = SUBMODULE_INIT;
 
if (!S_ISGITLINK(ce->ce_mode))
@@ -1274,16 +1302,12 @@ static int get_next_submodule(struct child_process *cp,
continue;
}
 
-   strbuf_repo_worktree_path(_path, spf->r, "%s", 
ce->name);
-   strbuf_addf(_git_dir, "%s/.git", submodule_path.buf);
strbuf_addf(_prefix, "%s%s/", spf->prefix, ce->name);
-   git_dir = read_gitfile(submodule_git_dir.buf);
-   if (!git_dir)
-   git_dir = submodule_git_dir.buf;
-   if (is_directory(git_dir)) {
+   repo = get_submodule_repo_for(spf->r, submodule);
+   if (repo) {
child_process_init(cp);
-   cp->dir = strbuf_detach(_path, NULL);
-   prepare_submodule_repo_env(>env_array);
+   prepare_submodule_repo_env_in_gitdir(>env_array);
+   cp->dir = xstrdup(repo->gitdir);
cp->git_cmd = 1;
if (!spf->quiet)
strbuf_addf(err, "Fetching submodule %s%s\n",
@@ -1293,10 +1317,11 @@ static int get_next_submodule(struct child_process *cp,
argv_array_push(>args, default_argv);
argv_array_push(>args, "--submodule-prefix");
  

[PATCH v4 8/9] fetch: retry fetching submodules if needed objects were not fetched

2018-09-25 Thread Stefan Beller
Currently when git-fetch is asked to recurse into submodules, it dispatches
a plain "git-fetch -C " (with some submodule related options
such as prefix and recusing strategy, but) without any information of the
remote or the tip that should be fetched.

This works surprisingly well in some workflows (such as using submodules
as a third party library), while not so well in other scenarios, such
as in a Gerrit topic-based workflow, that can tie together changes
(potentially across repositories) on the server side. One of the parts
of such a Gerrit workflow is to download a change when wanting to examine
it, and you'd want to have its submodule changes that are in the same
topic downloaded as well. However these submodule changes reside in their
own repository in their own ref (refs/changes/).

Retry fetching a submodule by object name if the object id that the
superproject points to, cannot be found.

This retrying does not happen when the "git fetch" done at the
superproject is not storing the fetched results in remote
tracking branches (i.e. instead just recording them to
FETCH_HEAD) in this step. A later patch will fix this.

builtin/fetch used to only inspect submodules when they were fetched
"on-demand", as in either on/off case it was clear whether the submodule
needs to be fetched. However to know whether we need to try fetching the
object ids, we need to identify the object names, which is done in this
function check_for_new_submodule_commits(), so we'll also run that code
in case the submodule recursion is set to "on".

Signed-off-by: Stefan Beller 
---
 builtin/fetch.c |   9 +-
 submodule.c | 185 ++--
 t/t5526-fetch-submodules.sh |  16 
 3 files changed, 177 insertions(+), 33 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 0696abfc2a1..e3b03ad3bd3 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -707,8 +707,7 @@ static int update_local_ref(struct ref *ref,
what = _("[new ref]");
}
 
-   if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
-   (recurse_submodules != RECURSE_SUBMODULES_ON))
+   if (recurse_submodules != RECURSE_SUBMODULES_OFF)
check_for_new_submodule_commits(>new_oid);
r = s_update_ref(msg, ref, 0);
format_display(display, r ? '!' : '*', what,
@@ -723,8 +722,7 @@ static int update_local_ref(struct ref *ref,
strbuf_add_unique_abbrev(, >object.oid, 
DEFAULT_ABBREV);
strbuf_addstr(, "..");
strbuf_add_unique_abbrev(, >new_oid, 
DEFAULT_ABBREV);
-   if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
-   (recurse_submodules != RECURSE_SUBMODULES_ON))
+   if (recurse_submodules != RECURSE_SUBMODULES_OFF)
check_for_new_submodule_commits(>new_oid);
r = s_update_ref("fast-forward", ref, 1);
format_display(display, r ? '!' : ' ', quickref.buf,
@@ -738,8 +736,7 @@ static int update_local_ref(struct ref *ref,
strbuf_add_unique_abbrev(, >object.oid, 
DEFAULT_ABBREV);
strbuf_addstr(, "...");
strbuf_add_unique_abbrev(, >new_oid, 
DEFAULT_ABBREV);
-   if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
-   (recurse_submodules != RECURSE_SUBMODULES_ON))
+   if (recurse_submodules != RECURSE_SUBMODULES_OFF)
check_for_new_submodule_commits(>new_oid);
r = s_update_ref("forced-update", ref, 1);
format_display(display, r ? '!' : '+', quickref.buf,
diff --git a/submodule.c b/submodule.c
index 3f791f22771..05799362e05 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1127,8 +1127,12 @@ struct submodule_parallel_fetch {
int result;
 
struct string_list changed_submodule_names;
+   struct get_next_submodule_task **retry;
+   int retry_nr, retry_alloc;
 };
-#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0, 
STRING_LIST_INIT_DUP }
+#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0, \
+ STRING_LIST_INIT_DUP, \
+ NULL, 0, 0}
 
 static void calculate_changed_submodule_paths(
struct submodule_parallel_fetch *spf)
@@ -1233,6 +1237,56 @@ static int get_fetch_recurse_config(const struct 
submodule *submodule,
return spf->default_option;
 }
 
+struct get_next_submodule_task {
+   struct repository *repo;
+   const struct submodule *sub;
+   unsigned free_sub : 1; /* Do we need to free the submodule? */
+   struct oid_array *commits;
+};
+
+static const struct submodule *get_default_submodule(const char *path)
+{
+   struct submodule *ret = NULL;
+   const char *name = default_name_or_path(path);
+
+   if (!name)
+   return NULL;
+
+   ret = xmalloc(sizeof(*ret));
+   

Re: [PATCH 1/8] sha1-array: provide oid_array_filter

2018-09-25 Thread Stefan Beller
On Sat, Sep 22, 2018 at 5:58 AM Ævar Arnfjörð Bjarmason
 wrote:
>
>
> On Fri, Sep 21 2018, Stefan Beller wrote:
>
> > +/*
> > + * Apply want to each entry in array, retaining only the entries for
> > + * which the function returns true.  Preserve the order of the entries
> > + * that are retained.
> > + */
> > +void oid_array_filter(struct oid_array *array,
> > +   for_each_oid_fn want,
> > +   void *cbdata);
> > +
> >  #endif /* SHA1_ARRAY_H */
>
> The code LGTM, but this comment should instead be an update to the API
> docs, see my recent 5cc044e025 ("get_short_oid: sort ambiguous objects
> by type, then SHA-1", 2018-05-10) for an addition of a new function to
> this API where I added some new docs.

ok will fix for consistency (this whole API is there).

Longer term (I thought) we were trying to migrate API docs
to headers instead?

Stefan


Re: git fetch behaves weirdely when run in a worktree

2018-09-25 Thread Kaartic Sivaraam
On Mon, 2018-09-24 at 17:17 +0200, Duy Nguyen wrote:
> On Sun, Sep 23, 2018 at 10:19 PM Kaartic Sivaraam
>  wrote:
> 
> Yes, some bugs. It behaves correctly for me. There must be something
> strange that triggers this. What's your "git worktree list" (iow
> anything strange there, duplicate worktrees perhaps)?

Nothing seems strange in the list.

$ git worktree list
$COMMON_ROOT/git  01d371f741 (detached HEAD)
$COMMON_ROOT/git-next cfa73bbfcb (detached HEAD)
$COMMON_ROOT/git-next-build-automate  01d371f741 (detached HEAD)
$COMMON_ROOT/git-pu   363c5c06bb (detached HEAD)

Note: I sanitized the path in which the git worktrees (including the
main worktree) is present as $COMMON_ROOT.


>  Also please try
> "git fetch" again with GIT_TRACE=1 and GIT_TRACE_SETUP=1. Hopefully we
> could catch something with that.

$ GIT_TRACE_SETUP=1 GIT_TRACE=1 git fetch origin next
23:10:26.049785 trace.c:377 setup: git_dir: 
$COMMON_ROOT/git/.git/worktrees/git-next-build-automate
23:10:26.049868 trace.c:378 setup: git_common_dir: 
$COMMON_ROOT/git/.git
23:10:26.049901 trace.c:379 setup: worktree: 
$COMMON_ROOT/git-next-build-automate
23:10:26.049922 trace.c:380 setup: cwd: 
$COMMON_ROOT/git-next-build-automate
23:10:26.049941 trace.c:381 setup: prefix: (null)
23:10:26.049955 git.c:415   trace: built-in: git fetch origin next
23:10:26.051033 run-command.c:637   trace: run_command: git-remote-https 
origin https://github.com/git/git.git
23:10:28.366526 run-command.c:637   trace: run_command: git rev-list 
--objects --stdin --not --all --quiet
23:10:28.400979 run-command.c:637   trace: run_command: git rev-list 
--objects --stdin --not --all --quiet
23:10:28.402745 trace.c:377 setup: git_dir: 
$COMMON_ROOT/git/.git/worktrees/git-next-build-automate
23:10:28.402787 trace.c:378 setup: git_common_dir: 
$COMMON_ROOT/git/.git
23:10:28.402793 trace.c:379 setup: worktree: 
$COMMON_ROOT/git-next-build-automate
23:10:28.402798 trace.c:380 setup: cwd: 
$COMMON_ROOT/git-next-build-automate
23:10:28.402802 trace.c:381 setup: prefix: (null)
23:10:28.402815 git.c:415   trace: built-in: git rev-list --objects 
--stdin --not --all --quiet
>From https://github.com/git/git
 * branch  next   -> FETCH_HEAD
23:10:28.437350 run-command.c:1553  run_processes_parallel: preparing to 
run up to 1 tasks
23:10:28.437481 run-command.c:1585  run_processes_parallel: done
23:10:28.437763 run-command.c:637   trace: run_command: git gc --auto
23:10:28.439608 trace.c:377 setup: git_dir: 
$COMMON_ROOT/git/.git/worktrees/git-next-build-automate
23:10:28.439655 trace.c:378 setup: git_common_dir: 
$COMMON_ROOT/git/.git
23:10:28.439667 trace.c:379 setup: worktree: 
$COMMON_ROOT/git-next-build-automate
23:10:28.439677 trace.c:380 setup: cwd: 
$COMMON_ROOT/git-next-build-automate
23:10:28.439687 trace.c:381 setup: prefix: (null)
23:10:28.439699 git.c:415   trace: built-in: git gc --auto

HTH,
Sivaraam



Re: Re*: [PATCH v3 0/5] Cleanup pass on special test setups

2018-09-25 Thread Ben Peart




On 9/20/2018 2:43 PM, Junio C Hamano wrote:

Ben Peart  writes:


This round has one code change based on feedback. Other changes are just
rewording commit messages.


Thanks.  I think the only remaining issue is what to do with the
interaction between extra/additional error message that comes from
the updates in 3/5 and the test framework selftest in t.

-- >8 --
Subject: t: do not get self-test disrupted by environment warnings

The test framework test-lib.sh itself would want to give warnings
and hints, e.g. when it sees a deprecated environment variable is in
use that we want to encourage users to migrate to another variable.

The self-test of test framework done in t however do not expect
to see these warnings and hints, so depending on the settings of
environment variables, a running test may or may not produce these
messages to the standard error output, breaking the expectations of
self-test test framework does on itself.  Here is what we see:

 $ TEST_GIT_INDEX_VERSION=4 sh t-basic.sh -i -v
 ...
 'err' is not empty, it contains:
 warning: TEST_GIT_INDEX_VERSION is now GIT_TEST_INDEX_VERSION
 hint: set GIT_TEST_INDEX_VERSION too during the transition period
 not ok 5 - pretend we have a fully passing test suite

The following quick attempt to work it around does not work, because
some tests in t do want to see expected errors from the test
framework itself.

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

 diff --git a/t/t-basic.sh b/t/t-basic.sh
 index 850f651e4e..88c6ed4696 100755
 --- a/t/t-basic.sh
 +++ b/t/t-basic.sh
 @@ -88,7 +88,7 @@ _run_sub_test_lib_test_common () {
 '

 # Point to the t/test-lib.sh, which isn't in ../ as 
usual
 -  . "\$TEST_DIRECTORY"/test-lib.sh
 +  . "\$TEST_DIRECTORY"/test-lib.sh >/dev/null 2>&1
 EOF
 cat >>"$name.sh" &&
 chmod +x "$name.sh" &&

There are a few possible ways to work this around:

  * We could strip the warning: and hint: unconditionally from the
error output before the error messages are checked in the
self-test (helper functions check_sub_test_lib_test_err and
check_sub_test_lib_test); the problem with this approach is that
it will make it impossible to write self-tests to ensure that
right warnings and hints are given.

  * We could force a sane environment settings before the test helper
_run_sub_test_lib_test_common dot-sources test-lib.sh; the
problem with this approach is that _run_sub_test_lib_test_common
now needs to be aware of what pairs of environment variables are
checked in test-lib.sh using check_var_migration helper.

The final patch I came up with is probably the solution that is
least bad.  Set a variable to tell test-lib.sh that we are running
a self-test, so that various pieces in test-lib.sh can react to keep
the output stable.



This looks like a reasonable compromise to me.  It's nice to give the 
migration hints to end users so they know they need to update their 
environments to reflect the required changes.  On the other hand, we 
don't want or need them to be triggered when we are running the self-test.


It would be nice to enable that automatically without the need for 
another environment variable but I couldn't think of a good way to 
accomplish that so I agree - this seems like the "least bad" solution. :-)


Thanks Junio


Signed-off-by: Junio C Hamano 
---
  t/t-basic.sh | 4 
  t/test-lib.sh| 8 
  2 files changed, 12 insertions(+)

diff --git a/t/t-basic.sh b/t/t-basic.sh
index 850f651e4e..52c02b7c7e 100755
--- a/t/t-basic.sh
+++ b/t/t-basic.sh
@@ -87,6 +87,10 @@ _run_sub_test_lib_test_common () {
passing metrics
'
  
+		# Tell the framework that we are self-testing to make sure

+   # it yields a stable result.
+   GIT_TEST_FRAMEWORK_SELFTEST=t &&
+
# Point to the t/test-lib.sh, which isn't in ../ as usual
. "\$TEST_DIRECTORY"/test-lib.sh
EOF
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 8ef86e05a3..364a11ea25 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -135,9 +135,17 @@ GIT_TRACE_BARE=1
  export GIT_TRACE_BARE
  
  check_var_migration () {

+   # the warnings and hints given from this helper depends
+   # on end-user settings, which will disrupt the self-test
+   # done on the test framework itself.
+   case "$GIT_TEST_FRAMEWORK_SELFTEST" in
+   t)  return ;;
+   esac
+
old_name=$1 new_name=$2
eval "old_isset=\${${old_name}:+isset}"
eval "new_isset=\${${new_name}:+isset}"
+
case "$old_isset,$new_isset" in
isset,)
echo >&2 "warning: $old_name is now 

Git Test Coverage Report (Tuesday, Sept 25)

2018-09-25 Thread Derrick Stolee
In an effort to ensure new code is reasonably covered by the test suite, 
we now have contrib/coverage-diff.sh to combine the gcov output from 
'make coverage-test ; make coverage-report' with the output from 'git 
diff A B' to discover _new_ lines of code that are not covered.


This report takes the output of these results after running on four 
branches:


        pu: 80e728fa913dc3a1165b6dec9a7afa6052a86325

       jch: 0c10634844314ab89666ed0a1c7d36dde7ac9689

      next: 76f2f5c1e34c4dbef1029e2984c2892894c444ce

    master: fe8321ec057f9231c26c29b364721568e58040f7

master@{1}: 2d3b1c576c85b7f5db1f418907af00ab88e0c303

I ran the test suite on each of these branches on an Ubuntu Linux VM, 
and I'm missing some dependencies (like apache, svn, and perforce) so 
not all tests are run.


I submit this output without comment. I'm taking a look especially at my 
own lines to see where coverage can be improved.


Thanks,

-Stolee

---

master@{1}..master:

builtin/remote.c
5025425dfff (   Shulhan 2018-09-13 20:18:33 +0700 
864)    return error(_("No such remote: '%s'"), name);

commit-reach.c
b67f6b26e35 (Derrick Stolee 2018-09-21 08:05:26 -0700 
559)    continue;
b67f6b26e35 (Derrick Stolee 2018-09-21 08:05:26 -0700 
569)    from->objects[i].item->flags |= assign_flag;
b67f6b26e35 (Derrick Stolee 2018-09-21 08:05:26 -0700 
570)    continue;
b67f6b26e35 (Derrick Stolee 2018-09-21 08:05:26 -0700 
576)    result = 0;
b67f6b26e35 (Derrick Stolee 2018-09-21 08:05:26 -0700 
577)    goto cleanup;

cat: compat#mingw.c.gcov: No such file or directory
ll-merge.c
d64324cb60e (Torsten Bögershausen   2018-09-12 21:32:02 +0200   
379)    marker_size = DEFAULT_CONFLICT_MARKER_SIZE;

remote-curl.c
c3b9bc94b9b (Elijah Newren  2018-09-05 10:03:07 -0700 
181)    options.filter = xstrdup(value);


master..next:

fsck.c
fb8952077df (René Scharfe   2018-09-03 14:49:26 + 
212)    die_errno("Could not read '%s'", path);

midx.c
56ee7ff1565 (Derrick Stolee 2018-09-13 11:02:13 -0700 
949)    return 0;
cc6af73c029 (Derrick Stolee 2018-09-13 11:02:25 -0700 
990)    midx_report(_("failed to load pack-index for 
packfile %s"),
cc6af73c029 (Derrick Stolee 2018-09-13 11:02:25 -0700 
991)    e.p->pack_name);
cc6af73c029 (Derrick Stolee 2018-09-13 11:02:25 -0700 
992)    break;


next..jch:

blame.c
a470beea39b (Nguyễn Thái Ngọc Duy   2018-09-21 17:57:21 +0200   
113) !strcmp(r->index->cache[-1 - pos]->name, path))
a470beea39b (Nguyễn Thái Ngọc Duy   2018-09-21 17:57:21 +0200   
272)    int pos = index_name_pos(r->index, path, len);
a470beea39b (Nguyễn Thái Ngọc Duy   2018-09-21 17:57:21 +0200   
274)    mode = r->index->cache[pos]->ce_mode;

commit-graph.c
5cef295f283 (Derrick Stolee 2018-08-20 18:24:32 + 
67) return 0;
20fd6d57996 (Derrick Stolee 2018-08-20 18:24:30 + 
79) return 0;

config.c
4ee45bacad0 ( Ben Peart 2018-09-12 16:18:55 + 
2301)   if (is_bool)
4ee45bacad0 ( Ben Peart 2018-09-12 16:18:55 + 
2302)   return val ? 0 : 1;
4ee45bacad0 ( Ben Peart 2018-09-12 16:18:55 + 
2304)   return val;

diff.c
b78ea5fc357 (Nguyễn Thái Ngọc Duy   2018-09-21 17:57:19 +0200   
4117) add_external_diff_name(o->repo, , other, two);

http-push.c
2abf3503854 (Nguyễn Thái Ngọc Duy   2018-09-21 17:57:38 +0200   
1928)   repo_init_revisions(the_repository, , 
setup_git_directory());

list-objects-filter-options.c
7c8a0cecc49 (Matthew DeVore 2018-09-21 13:32:04 -0700 
55) if (errbuf) {
7c8a0cecc49 (Matthew DeVore 2018-09-21 13:32:04 -0700 
56) strbuf_addstr(
7c8a0cecc49 (Matthew DeVore 2018-09-21 13:32:04 -0700 
60) return 1;
ba72cca605f (Matthew DeVore 2018-09-21 13:32:03 -0700 86) if 
(errbuf)

list-objects-filter.c
22e9b63e620 (Matthew DeVore 2018-09-21 13:32:02 -0700 
47) BUG("unknown filter_situation: %d", filter_situation);

7c8a0cecc49 (Matthew DeVore 2018-09-21 13:32:04 -0700 100)    default:
7c8a0cecc49 (Matthew DeVore 2018-09-21 13:32:04 -0700 
101)    BUG("unknown filter_situation: %d", filter_situation);
22e9b63e620 (Matthew DeVore 2018-09-21 13:32:02 -0700 
152)    BUG("unknown filter_situation: %d", filter_situation);
22e9b63e620 (Matthew DeVore 2018-09-21 13:32:02 -0700 
257)    BUG("unknown filter_situation: %d", filter_situation);
22e9b63e620 (Matthew DeVore 2018-09-21 13:32:02 -0700 
438)    BUG("invalid list-objects filter choice: %d",

list-objects.c
f447a499dbb (Matthew DeVore 2018-08-13 11:14:28 -0700 
197)    

Re: [PATCH v3 1/1] contrib: add coverage-diff script

2018-09-25 Thread Junio C Hamano
"Derrick Stolee via GitGitGadget"  writes:

> +files=$(git diff --name-only $V1 $V2 -- *.c)

You'd want to quote that *.c from the shell, i.e. either one of
these

files=$(git diff --name-only $V1 $V2 -- \*.c)
files=$(git diff --name-only $V1 $V2 -- '*.c')

otherwise you'd lose things like "builtin/am.c", I'd think.

> +
> +for file in $files
> +do

I know this is only for running in _our_ source tree, and we do not
have a source with $IFS in it, so I'd declare that this is OK.  It
would be good to document that assumption in red capital letters at
the beginning of this loop, though ;-)

# Note: this script is only for our codebase and we rely on
# the fact that the pathnames of our source files do not
# have any funny characters---letting the shell split $files
# list at $IFS boundary is very much intentional, and not
# quoting "$file" in the code below also is.  Don't imitate
# this in scripts that are meant to handle random end-user
# repositories!
for file in $files
do
...

> + git diff $V1 $V2 -- $file \
> + | diff_lines \
> + | sort >new_lines.txt

I do not see a strong reason why we would want to limit $V1 and $V2
to branch names and raw commit object names, and quoting them in dq
pair is a cheap fix to allow things like

$ contrib/coverage-diff.sh master 'pu^{/^### match next}'

so let's do so.

Could you cut lines _after_ typing a pipe and omit backslashes, i.e.

git diff "$V1" "$V2" -- $file |
diff_lines |
sort >new_lines.txt

It seems to be personal taste whether to indent the second and
subsequent lines; I do not care if you indent or if you align too
much either way (but I have moderate perference to align).  

But I do not want to see people type unnecessary backslashes.  This
is not limited to just this pipeline but elsewhere in the script.

> + if ! test -s new_lines.txt
> + then
> + continue
> + fi
> +
> + hash_file=$(echo $file | sed "s/\//\#/")
> + sed -ne '/#:/{
> + s/#://
> + s/:.*//
> + s/ //g
> + p
> + }' "$hash_file.gcov" \
> + | sort >uncovered_lines.txt
> +
> + comm -12 uncovered_lines.txt new_lines.txt \
> + | sed -e 's/$/\)/' \
> + | sed -e 's/^/\t/' \

Do you need two sed invocations for this, or would

sed -e 's/$/\)/' -e '/^//'

work as well?  By the way """The meaning of an unescaped 
immediately followed by any character other than '&', , a
digit, , or the delimiter character used for this command,
is unspecified."""[*1*] so '\t' on the replacement side is a no-no
in the portability department.

Reference. *1*
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html


> + >uncovered_new_lines.txt
> +
> + grep -q '[^[:space:]]' < uncovered_new_lines.txt && \

Lose the backslash at the end.  The shell knows that you haven't
finished your sentence when it sees a line that ends with &&, || or
a pipe |, so there is no need to tell it redundantly that you have
more things to say with the backslash.

> + echo $file && \
> + git blame -c $file \
> + | grep -f uncovered_new_lines.txt
> +
> + rm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt
> +done

Near the begininng (like just before the "for file in $files" loop),
you can probably have a trap to make sure these are removed upon
exit, e.g.

trap 'rm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt' 0



Re: [PATCH] commit-reach: cleanups in can_all_from_reach...

2018-09-25 Thread Derrick Stolee

On 9/25/2018 2:06 PM, Junio C Hamano wrote:

Derrick Stolee  writes:


@@ -622,10 +623,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
}
  
  cleanup:

-   for (i = 0; i < nr_commits; i++) {
-   clear_commit_marks(list[i], RESULT);
-   clear_commit_marks(list[i], assign_flag);
-   }
+   clear_commit_marks_many(nr_commits, list, RESULT | assign_flag);
free(list);
  
  	for (i = 0; i < from->nr; i++)


base-commit: 4067a64672f9db8ca38d5a2682a7cdba7938c18b

This change looks good to me.

This is a tangent, but while re-reading clear_commit_marks() and its
helpers to refresh my memory, I found that the bottom-most helper in
the callchain was written in a very confusing way, but it is not a
fault of this clean-up.  I however suspect that it would not help us
all that much to use clear_commit_marks_many() with its current
implementation.  It first clears all commits on the first-parent
chain from each list[] element, while accumulating the parent
commits that are yet to be processed in a commit_list in LIFO order,
and then consumes these accumulated side parents the same way.  We
probably would benefit by rewriting clear_commit_marks_many() to
traverse from all the tips given in list[] taking advantage of the
generation numbers, using a prio queue to manage the commits
yet-to-be-cleared, or something.


Another commit walk that could be improved by generation numbers? It's 
like my bat-signal!


Thanks for pointing me in that direction. I'll take a look.

-Stolee



Re: [PATCH] commit-reach: cleanups in can_all_from_reach...

2018-09-25 Thread Junio C Hamano
Derrick Stolee  writes:

> @@ -622,10 +623,7 @@ int can_all_from_reach_with_flag(struct object_array 
> *from,
>   }
>  
>  cleanup:
> - for (i = 0; i < nr_commits; i++) {
> - clear_commit_marks(list[i], RESULT);
> - clear_commit_marks(list[i], assign_flag);
> - }
> + clear_commit_marks_many(nr_commits, list, RESULT | assign_flag);
>   free(list);
>  
>   for (i = 0; i < from->nr; i++)
>
> base-commit: 4067a64672f9db8ca38d5a2682a7cdba7938c18b

This change looks good to me. 

This is a tangent, but while re-reading clear_commit_marks() and its
helpers to refresh my memory, I found that the bottom-most helper in
the callchain was written in a very confusing way, but it is not a
fault of this clean-up.  I however suspect that it would not help us
all that much to use clear_commit_marks_many() with its current
implementation.  It first clears all commits on the first-parent
chain from each list[] element, while accumulating the parent
commits that are yet to be processed in a commit_list in LIFO order,
and then consumes these accumulated side parents the same way.  We
probably would benefit by rewriting clear_commit_marks_many() to
traverse from all the tips given in list[] taking advantage of the
generation numbers, using a prio queue to manage the commits
yet-to-be-cleared, or something.


Re: [PATCH 1/1] read-cache: update index format default to v4

2018-09-25 Thread Stefan Beller
On Tue, Sep 25, 2018 at 7:30 AM Derrick Stolee  wrote:
>
> On 9/25/2018 3:06 AM, Patrick Steinhardt wrote:
> > On Mon, Sep 24, 2018 at 11:32:23PM +0200, SZEDER Gábor wrote:
> >> On Mon, Sep 24, 2018 at 02:15:30PM -0700, Derrick Stolee via GitGitGadget 
> >> wrote:
> >>> From: Derrick Stolee 
> >>>
> >>> The index v4 format has been available since 2012 with 9d22778
> >>> "reach-cache.c: write prefix-compressed names in the index". Since
> >>> the format has been stable for so long, almost all versions of Git
> >>> in use today understand version 4, removing one barrier to upgrade
> >>> -- that someone may want to downgrade and needs a working repo.
> >> What about alternative implementations, like JGit, libgit2, etc.?
> > Speaking of libgit2, we are able to read and write index v4 since
> > commit c1b370e93
>
> This is a good point, Szeder.
>
> Patrick: I'm glad LibGit2 is up-to-date with index formats.
>
> Unfortunately, taking a look (for the first time) at the JGit code
> reveals that they don't appear to have v4 support. In
> org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java, the
> DirCache.readFrom() method: lines 488-494, I see the following snippet:
>
>  final int ver = NB.decodeInt32(hdr, 4);
>  boolean extended = false;
>  if (ver == 3)
>  extended = true;
>  else if (ver != 2)
>  throw new
> CorruptObjectException(MessageFormat.format(
> JGitText.get().unknownDIRCVersion, Integer.valueOf(ver)));
>
> It looks like this will immediately throw with versions other than 2 or 3.
>
> I'm adding Jonathan Nieder to CC so he can check with JGit people about
> the impact of this change.

JGit is used both on the server (which doesn't use index/staging area)
as well as client side as e.g. an Eclipse integration, which would
very much like to use the index.

Adding Matthias Sohn as well, who is active in JGit and cares
more about the client side than Googlers who only make use
of the server side part of JGit.

Stefan


Re: [PATCH 2/8] Add a place for (not) sharing stuff between worktrees

2018-09-25 Thread Stefan Beller
On Tue, Sep 25, 2018 at 9:55 AM Duy Nguyen  wrote:

> > And with that said, I wonder if the "local" part should be feature agnostic,
> > or if we want to be "local" for worktrees, "local" for remotes, "local"
> > for submodules (i.e. our own refs vs submodule refs).
>
> You lost me here.

Yeah, me too after rereading. :P

I think the "local" part always implies that there is a part that is
not local and depending on the feature you call it remote or other
worktree.

When writing this comment I briefly wondered if we want to combine
the local aspects of the various features.
However the "local" part really depends on the feature
(e.g. a ref on a different worktree is still local from the here/remote
perspective or from the superproject/submodule perspective),
so I think I was misguided.

> > > think as long as the word "worktree" is in there, people would notice
> > > the difference.
> >
> > That makes sense. But is refs/worktree shared or local? It's not quite
> > obvious to me, as I could have refs/worktree//master
> > instead when it is shared, so I tend to favor refs/local-worktree/ a bit
> > more, but that is more typing. :/
>
> OK I think mixing the two patches will different purposes messes you
> (or me) up ;-)

possible.

>
> refs/worktrees/xxx (and refs/main/xxx) are about visibility from other
> worktrees. Or like Eric put it, they are simply aliases. These refs
> are not shared because if they are, you can already see them without
> new "ref mount points" like this.
>
> refs/worktree (previously refs/local) is also per-worktree but it's
> specifically because you can't have per-worktree inside "refs/" (the
> only exception so far is refs/bisect which is hard coded). You can
> have refs outside "refs/" (like HEAD or FETCH_HEAD) and they will not
> be shared, but they cannot be iterated while those inside refs/ can
> be. This is more about deciding what to share and I believe is really
> worktree-specific and only matters to _current_ worktree.
>
> Since refs/worktree is per-worktree, you can also view them from a
> different worktree via refs/worktrees/. E.g. if you have
> refs/worktree/foo then another worktree can see it via
> refs/worktrees/xxx/refs/worktree/foo (besides pseudo refs like
> refs/worktrees/xxx/HEAD)

Ah. now I seem to understand, thanks for explaining.


Re: [PATCH] git help: promote 'git help -av'

2018-09-25 Thread Duy Nguyen
On Tue, Sep 25, 2018 at 05:15:38PM +0200, Duy Nguyen wrote:
> On Mon, Sep 24, 2018 at 10:58 PM Junio C Hamano  wrote:
> > I personally find "help -av" a bit too loud to my taste than plain
> > "-a", and more importantly, I look at "help -a" primarily to check
> > the last section "avaialble from elsewhere on your $PATH" to find
> > things like "clang-format", which I do not think is available
> > anywhere in "help -av", so I do not think "-av" can be promoted as
> > an upward-compatible replacement in its current form.
> 
> Yep. I also thought "help -a" was denser but wasn't sure if it
> actually helps or not. Whenever I look at that block of commands, I
> end up searching anyway. For my use case, "help -a" could be better
> served with something like "git apropos".
> 
> I think adding another section about external commands in "help -av"
> would address the "clang-format" stuff. With that, it's probably good
> enough to completely replace "help -a". It may also be good to list
> aliases there too in a separate section so you have "all you can type"
> in one (big) list.

Here's the patch that adds that external commands and aliases
sections. I feel that external commands section is definitely good to
have even if we don't replace "help -a". Aliases are more
subjective...

-- 8< --
diff --git a/builtin/help.c b/builtin/help.c
index 8d4f6dd301..23a34b36e7 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -38,7 +38,6 @@ static const char *html_path;
 static int show_all = 0;
 static int show_guides = 0;
 static int show_config;
-static int verbose;
 static unsigned int colopts;
 static enum help_format help_format = HELP_FORMAT_NONE;
 static int exclude_guides;
@@ -53,7 +52,6 @@ static struct option builtin_help_options[] = {
HELP_FORMAT_WEB),
OPT_SET_INT('i', "info", _format, N_("show info page"),
HELP_FORMAT_INFO),
-   OPT__VERBOSE(, N_("print command description")),
OPT_END(),
 };
 
@@ -437,14 +435,9 @@ int cmd_help(int argc, const char **argv, const char 
*prefix)
 
if (show_all) {
git_config(git_help_config, NULL);
-   if (verbose) {
-   setup_pager();
-   list_all_cmds_help();
-   return 0;
-   }
-   printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
-   load_command_list("git-", _cmds, _cmds);
-   list_commands(colopts, _cmds, _cmds);
+   setup_pager();
+   list_all_cmds_help();
+   return 0;
}
 
if (show_config) {
diff --git a/help.c b/help.c
index 96f6d221ed..4a168230dc 100644
--- a/help.c
+++ b/help.c
@@ -98,7 +98,8 @@ static int cmd_name_cmp(const void *elem1, const void *elem2)
return strcmp(e1->name, e2->name);
 }
 
-static void print_cmd_by_category(const struct category_description *catdesc)
+static void print_cmd_by_category(const struct category_description *catdesc,
+ int *longest_p)
 {
struct cmdname_help *cmds;
int longest = 0;
@@ -124,6 +125,8 @@ static void print_cmd_by_category(const struct 
category_description *catdesc)
print_command_list(cmds, mask, longest);
}
free(cmds);
+   if (longest_p)
+   *longest_p = longest;
 }
 
 void add_cmdname(struct cmdnames *cmds, const char *name, int len)
@@ -193,26 +196,6 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames 
*excludes)
cmds->cnt = cj;
 }
 
-static void pretty_print_cmdnames(struct cmdnames *cmds, unsigned int colopts)
-{
-   struct string_list list = STRING_LIST_INIT_NODUP;
-   struct column_options copts;
-   int i;
-
-   for (i = 0; i < cmds->cnt; i++)
-   string_list_append(, cmds->names[i]->name);
-   /*
-* always enable column display, we only consult column.*
-* about layout strategy and stuff
-*/
-   colopts = (colopts & ~COL_ENABLE_MASK) | COL_ENABLED;
-   memset(, 0, sizeof(copts));
-   copts.indent = "  ";
-   copts.padding = 2;
-   print_columns(, colopts, );
-   string_list_clear(, 0);
-}
-
 static void list_commands_in_dir(struct cmdnames *cmds,
 const char *path,
 const char *prefix)
@@ -285,29 +268,10 @@ void load_command_list(const char *prefix,
exclude_cmds(other_cmds, main_cmds);
 }
 
-void list_commands(unsigned int colopts,
-  struct cmdnames *main_cmds, struct cmdnames *other_cmds)
-{
-   if (main_cmds->cnt) {
-   const char *exec_path = git_exec_path();
-   printf_ln(_("available git commands in '%s'"), exec_path);
-   putchar('\n');
-   pretty_print_cmdnames(main_cmds, colopts);
-   putchar('\n');
-   }
-
-   if (other_cmds->cnt) {
-   printf_ln(_("git commands 

Re: [PATCH v2 3/3] transport.c: introduce core.alternateRefsPrefixes

2018-09-25 Thread Junio C Hamano
Jeff King  writes:

> Right, I think that is totally fine for the current uses. I guess my
> question was: do you envision cutting the interface down to only the
> oids to bite us in the future?
>
> I was on the fence during past discussions, but I think I've come over
> to the idea that the refnames actively confuse things.

Alternates are sort-of repositories that you interact with via more
normal transports like fetch or push, and at the object store level
(i.e. the one that helps you build your local history) you do not
really care what refnames other people use in their repository.
E.g. it does not matter if a pull request to you asks you to pull
their 'frotz' branch or 'nitfol' branch, as long as the work they
did on that branch is what you expected them to do.  And I think
"I am aware that I can get to the objects that are reachable from
these objects I can borrow from that alternate when I need them" is
quite similar in spirit; the borrower has even less need to be aware
of the refnames as there isn't even a need to "git pull" from it (at
that only one single point, you would care what name they used in
their pull request).

So, I think we probably are better off without names.


Re: [PATCH 2/8] Add a place for (not) sharing stuff between worktrees

2018-09-25 Thread Duy Nguyen
On Tue, Sep 25, 2018 at 6:24 PM Stefan Beller  wrote:
> > > That sounds dangerous to me. There is already a concept of
> > > local and remote-tracking branches. So I would think that local
> > > may soon become an overused word, (just like "index" today or
> > > "recursive" to a lesser extend).
> > >
> > > Could this special area be more explicit?
> > > (refs/worktree-local/ ? or after peeking at the docs below
> > > refs/un-common/ ?)
> >
> > refs/un-common sounds really "uncommon" :D. If refs/local is bad, I
> > guess we could go with either refs/worktree-local, refs/worktree,
> > refs/private, refs/per-worktree... My vote is on refs/worktree. I
>
> refs/worktree sounds good to me (I do not object), but I am not
> overly enthused either, as when I think further worktrees and
> submodules are both features with a very similar nature in that
> they touch a lot of core concepts in Git, but seem to be a niche
> feature for the masses for now.

I think the similarity is partly because submodule feature also has to
manage worktrees. My view is at some point, this "git worktree" would
be good enough that it can handle submodules as well (for the worktree
part only of course)

> For example I could think of submodules following this addressing
> mode as well: submodule//master sounds similar to the
> originally proposed worktree// convention.
> For now it is not quite clear to me why you would want to have
> access to the submodule refs in the superproject, but maybe
> the use case will come later.

Yeah. In theory we could "mount" the submodule ref store to a
superproject's ref store. I think it may be needed just for the same
reason it's needed for worktree: error reporting. If you peek into a
submodule and say "HEAD has an error", the user will get confused
whether it's superproject's HEAD or a submodule's HEAD.

> And with that said, I wonder if the "local" part should be feature agnostic,
> or if we want to be "local" for worktrees, "local" for remotes, "local"
> for submodules (i.e. our own refs vs submodule refs).

You lost me here.

>
> > think as long as the word "worktree" is in there, people would notice
> > the difference.
>
> That makes sense. But is refs/worktree shared or local? It's not quite
> obvious to me, as I could have refs/worktree//master
> instead when it is shared, so I tend to favor refs/local-worktree/ a bit
> more, but that is more typing. :/

OK I think mixing the two patches will different purposes messes you
(or me) up ;-)

refs/worktrees/xxx (and refs/main/xxx) are about visibility from other
worktrees. Or like Eric put it, they are simply aliases. These refs
are not shared because if they are, you can already see them without
new "ref mount points" like this.

refs/worktree (previously refs/local) is also per-worktree but it's
specifically because you can't have per-worktree inside "refs/" (the
only exception so far is refs/bisect which is hard coded). You can
have refs outside "refs/" (like HEAD or FETCH_HEAD) and they will not
be shared, but they cannot be iterated while those inside refs/ can
be. This is more about deciding what to share and I believe is really
worktree-specific and only matters to _current_ worktree.

Since refs/worktree is per-worktree, you can also view them from a
different worktree via refs/worktrees/. E.g. if you have
refs/worktree/foo then another worktree can see it via
refs/worktrees/xxx/refs/worktree/foo (besides pseudo refs like
refs/worktrees/xxx/HEAD)

> As we grow the worktree feature, do we ever expect the need to
> reference the current worktree?
>
> For example when there is a ref "test" that could be unique per
> repo and in the common area, so refs/heads/test would describe
> it and "test" would get there in DWIM mode.
>
> But then I could also delete the common ref and recreate a "test"
> ref in worktree A, in worktree B however DWIMming "test" could still
> refer to A's "test" as it is unique (so far) in the repository.
> And maybe I would want to check if test exists locally, so I'd
> want to ask for "self/test" (with "self" == "B" as that is my cwd).

You probably lost me again. In theory we must be able to detect
ambiguity and stop DWIMing. If you want to be ambiguity-free, you
specify full ref name, starting with "refs/" which should function
like "self/" because worktree design so far is always about the
current worktree's view.
-- 
Duy


Re: [PATCH 3/8] refs: new ref types to make per-worktree refs visible to all worktrees

2018-09-25 Thread Stefan Beller
On Tue, Sep 25, 2018 at 8:49 AM Duy Nguyen  wrote:
>
> On Tue, Sep 25, 2018 at 4:48 AM Stefan Beller  wrote:
> > > This patch also makes it possible to specify refs from one worktree in
> > > another one, e.g.
> > >
> > > git log worktrees/foo/HEAD
> >
> > This has strong similarities to remote refs:
> > Locally I may have a branch master, whose (stale local copy of its
> > distributed) counterpart is named origin/master.
>
> If you think of each worktree as independent clones (which is more or
> less true, the fact that they share ODB is more like an implementation
> detail) then yes it's almost like remotes.

Apart from the ODB and the refs subsystem, there is also the config
space, which is shared (but you have sent out patches to have local
config as well).

So I would think worktrees are better than having two clones not just
due to the shared ODB, but also due to the common config as then I
have to setup my repo only once and can add/remove worktrees
cheaply (in terms of "how much time do I need to spend to configure
it as I need").

> > It is also possible to have a working tree named origin
> > (just I like to name my worktree "git", when working on git.git),
> > how do we differentiate between the neighbor-worktree
> > "origin/master" and the remote-tracking branch "origin/master" ?
>
> Hmm.. I think you're thinking that origin/master could either mean
> refs/worktrees/origin/master or refs/remotes/origin/master. I do not
> think we're going to support expanding origin/master to
> refs/worktrees/origin/master. This part about ref resolution did cross
> my mind but I didn't see a good reason to support it.
>
> Even if we do support it, this is not even a new problem. If you have
> refs/heads/origin/master and refs/remotes/origin/master now, we have
> ref ambiguity anyway and a solution for this should handle
> refs/worktrees/origin/master well if it comes into the picture.

So once origin/master is overloaded, I would have to spell out
refs/worktrees/origin/master and refs/remotes/origin/master to
avoid confusing the DWIM machinery. Makes sense.

> > How do we deal with that?
>
> main is accessed via worktrees/main/HEAD while the main worktree's
> HEAD is accessed via main/HEAD (which is _not_ automatically expanded
> to refs/worktrees/main/HEAD). But if it is, yes we need to detect
> ambiguity and tell the user to specify full ref name, either
> refs/main/HEAD or refs/worktrees/main/HEAD.

Ah, I see. Now I actually understand the last paragraph of the
commit message. Thanks for explaining!

Stefan


Re: [PATCH 2/8] Add a place for (not) sharing stuff between worktrees

2018-09-25 Thread Stefan Beller
On Tue, Sep 25, 2018 at 8:36 AM Duy Nguyen  wrote:
>
> On Tue, Sep 25, 2018 at 4:35 AM Stefan Beller  wrote:
> >
> > On Sat, Sep 22, 2018 at 11:05 AM Nguyễn Thái Ngọc Duy  
> > wrote:
> > >
> > > When multiple worktrees are used, we need rules to determine if
> > > something belongs to one worktree or all of them. Instead of keeping
> > > adding rules when new stuff comes, have a generic rule:
> > >
> > > - Inside $GIT_DIR, which is per-worktree by default, add
> > >   $GIT_DIR/common which is always shared. New features that want to
> > >   share stuff should put stuff under this directory.
> >
> > So that /common is a directory and you have to use it specifically
> > in new code? That would be easy to overlook when coming up
> > with $GIT_DIR/foo for implementing the git-foo.
>
> There's no easy way out. I have to do _something_ if you want to share
> $GIT_DIR/foo to all worktrees. Either we have to update path.c and add
> "foo" which is not even an option for external commands, or we put
> "foo" in a common place, e.g. $GIT_DIR/common/foo.
>
> > > - Inside refs/, which is shared by default except refs/bisect, add
> > >   refs/local/ which is per-worktree. We may eventually move
> > >   refs/bisect to this new location and remove the exception in refs
> > >   code.
> >
> > That sounds dangerous to me. There is already a concept of
> > local and remote-tracking branches. So I would think that local
> > may soon become an overused word, (just like "index" today or
> > "recursive" to a lesser extend).
> >
> > Could this special area be more explicit?
> > (refs/worktree-local/ ? or after peeking at the docs below
> > refs/un-common/ ?)
>
> refs/un-common sounds really "uncommon" :D. If refs/local is bad, I
> guess we could go with either refs/worktree-local, refs/worktree,
> refs/private, refs/per-worktree... My vote is on refs/worktree. I

refs/worktree sounds good to me (I do not object), but I am not
overly enthused either, as when I think further worktrees and
submodules are both features with a very similar nature in that
they touch a lot of core concepts in Git, but seem to be a niche
feature for the masses for now.

For example I could think of submodules following this addressing
mode as well: submodule//master sounds similar to the
originally proposed worktree// convention.
For now it is not quite clear to me why you would want to have
access to the submodule refs in the superproject, but maybe
the use case will come later.

And with that said, I wonder if the "local" part should be feature agnostic,
or if we want to be "local" for worktrees, "local" for remotes, "local"
for submodules (i.e. our own refs vs submodule refs).

> think as long as the word "worktree" is in there, people would notice
> the difference.

That makes sense. But is refs/worktree shared or local? It's not quite
obvious to me, as I could have refs/worktree//master
instead when it is shared, so I tend to favor refs/local-worktree/ a bit
more, but that is more typing. :/

==
As we grow the worktree feature, do we ever expect the need to
reference the current worktree?

For example when there is a ref "test" that could be unique per
repo and in the common area, so refs/heads/test would describe
it and "test" would get there in DWIM mode.

But then I could also delete the common ref and recreate a "test"
ref in worktree A, in worktree B however DWIMming "test" could still
refer to A's "test" as it is unique (so far) in the repository.
And maybe I would want to check if test exists locally, so I'd
want to ask for "self/test" (with "self" == "B" as that is my cwd).

Stefan


Re: bug in 'git describe'?

2018-09-25 Thread Duy Nguyen
On Tue, Sep 25, 2018 at 6:05 PM Duy Nguyen  wrote:
>
> On Tue, Sep 25, 2018 at 5:41 PM Sebastian Kuzminsky  wrote:
> > That behavior seems to me to be different from what the (2.11) manpage says:
>
> Good opportunity to improve the man page anyway even if Junio is
> right. I agree that the section about "search strategy" is a bit
> misleading because it does not mention anything about time stuff.

If anybody's updating the man page, I think this is the commit that
changed git-describe's search strategy: 80dbae03b0 (Chose better tag
names in git-describe after merges. - 2007-01-10)

--
Duy


Re: bug in 'git describe'?

2018-09-25 Thread Duy Nguyen
On Tue, Sep 25, 2018 at 5:41 PM Sebastian Kuzminsky  wrote:
> That behavior seems to me to be different from what the (2.11) manpage says:

Good opportunity to improve the man page anyway even if Junio is
right. I agree that the section about "search strategy" is a bit
misleading because it does not mention anything about time stuff.

>
> > it suffixes the tag name with the number of additional commits on top
> > of the tagged object
>
>
> And:
>
> > If multiple tags were found during the walk then the tag which has
> > the fewest commits different from the input commit-ish will be
> > selected and output. Here fewest commits different is defined as the
> > number of commits which would be shown by git log tag..input will be
> > the smallest number of commits possible.
-- 
Duy


Re: [PATCH] worktree: add per-worktree config files

2018-09-25 Thread Duy Nguyen
On Mon, Sep 24, 2018 at 4:21 PM Taylor Blau  wrote:
> > +cmp_config() {
> > + if [ "$1" = "-C" ]; then
> > + shift &&
> > + GD="-C $1" &&
> > + shift
> > + else
> > + GD=
> > + fi &&
> > + echo "$1" >expected &&
> > + shift &&
> > + git $GD config "$@" >actual &&
> > + test_cmp expected actual
> > +}
>
> This cmp_config seems generally useful, perhaps beyond t2029. What do
> you think about putting it in t/test-lib-functions.sh instead?

Good point. t1300 (and I think some t13xx) does the same. Other tests also do

test "$(git config...)" = blah

which can also use this function to have better error reporting when
things go wrong.
-- 
Duy


Re: [PATCH 3/8] refs: new ref types to make per-worktree refs visible to all worktrees

2018-09-25 Thread Duy Nguyen
On Tue, Sep 25, 2018 at 4:48 AM Stefan Beller  wrote:
> > This patch also makes it possible to specify refs from one worktree in
> > another one, e.g.
> >
> > git log worktrees/foo/HEAD
>
> This has strong similarities to remote refs:
> Locally I may have a branch master, whose (stale local copy of its
> distributed) counterpart is named origin/master.

If you think of each worktree as independent clones (which is more or
less true, the fact that they share ODB is more like an implementation
detail) then yes it's almost like remotes.

> It is also possible to have a working tree named origin
> (just I like to name my worktree "git", when working on git.git),
> how do we differentiate between the neighbor-worktree
> "origin/master" and the remote-tracking branch "origin/master" ?

Hmm.. I think you're thinking that origin/master could either mean
refs/worktrees/origin/master or refs/remotes/origin/master. I do not
think we're going to support expanding origin/master to
refs/worktrees/origin/master. This part about ref resolution did cross
my mind but I didn't see a good reason to support it.

Even if we do support it, this is not even a new problem. If you have
refs/heads/origin/master and refs/remotes/origin/master now, we have
ref ambiguity anyway and a solution for this should handle
refs/worktrees/origin/master well if it comes into the picture.

> As the remote tracking branches are shared between all
> worktree there is no need to differentiate between a
> local-worktree remote tracking branch and a
> neighbor-worktree remote tracking branch.
>
> Now that you introduce the magic main working tree,
> we also need to disallow working trees to be named "main",
> i.e.
> $ git worktree add main HEAD
>
> produces
>
>   $ ls .git/worktrees/
>   main
>
> How do we deal with that?

main is accessed via worktrees/main/HEAD while the main worktree's
HEAD is accessed via main/HEAD (which is _not_ automatically expanded
to refs/worktrees/main/HEAD). But if it is, yes we need to detect
ambiguity and tell the user to specify full ref name, either
refs/main/HEAD or refs/worktrees/main/HEAD.
-- 
Duy


Re: bug in 'git describe'?

2018-09-25 Thread Sebastian Kuzminsky

On 9/24/18 4:24 PM, Junio C Hamano wrote:

Sebastian Kuzminsky  writes:

I've got two tiny git repos whose commit graphs are identical, but 
where 'git describe' gives different results. ... The histories

differ only in the timestamps of the commits...


describe does take the commit timestamps into account, so it is 
expected you would get different results out of an otherwise 
identically looking graph.


Thanks for that confirmation.

That behavior seems to me to be different from what the (2.11) manpage says:


it suffixes the tag name with the number of additional commits on top
of the tagged object



And:


If multiple tags were found during the walk then the tag which has
the fewest commits different from the input commit-ish will be
selected and output. Here fewest commits different is defined as the
number of commits which would be shown by git log tag..input will be
the smallest number of commits possible.


All that said, if you consider this "working as expected" then i'm 
content to let the matter drop.



--
Sebastian Kuzminsky


Re: [PATCH 2/8] Add a place for (not) sharing stuff between worktrees

2018-09-25 Thread Duy Nguyen
On Tue, Sep 25, 2018 at 4:35 AM Stefan Beller  wrote:
>
> On Sat, Sep 22, 2018 at 11:05 AM Nguyễn Thái Ngọc Duy  
> wrote:
> >
> > When multiple worktrees are used, we need rules to determine if
> > something belongs to one worktree or all of them. Instead of keeping
> > adding rules when new stuff comes, have a generic rule:
> >
> > - Inside $GIT_DIR, which is per-worktree by default, add
> >   $GIT_DIR/common which is always shared. New features that want to
> >   share stuff should put stuff under this directory.
>
> So that /common is a directory and you have to use it specifically
> in new code? That would be easy to overlook when coming up
> with $GIT_DIR/foo for implementing the git-foo.

There's no easy way out. I have to do _something_ if you want to share
$GIT_DIR/foo to all worktrees. Either we have to update path.c and add
"foo" which is not even an option for external commands, or we put
"foo" in a common place, e.g. $GIT_DIR/common/foo.

> > - Inside refs/, which is shared by default except refs/bisect, add
> >   refs/local/ which is per-worktree. We may eventually move
> >   refs/bisect to this new location and remove the exception in refs
> >   code.
>
> That sounds dangerous to me. There is already a concept of
> local and remote-tracking branches. So I would think that local
> may soon become an overused word, (just like "index" today or
> "recursive" to a lesser extend).
>
> Could this special area be more explicit?
> (refs/worktree-local/ ? or after peeking at the docs below
> refs/un-common/ ?)

refs/un-common sounds really "uncommon" :D. If refs/local is bad, I
guess we could go with either refs/worktree-local, refs/worktree,
refs/private, refs/per-worktree... My vote is on refs/worktree. I
think as long as the word "worktree" is in there, people would notice
the difference.
-- 
Duy


Re: [PATCH] git help: promote 'git help -av'

2018-09-25 Thread Duy Nguyen
On Mon, Sep 24, 2018 at 10:58 PM Junio C Hamano  wrote:
> I personally find "help -av" a bit too loud to my taste than plain
> "-a", and more importantly, I look at "help -a" primarily to check
> the last section "avaialble from elsewhere on your $PATH" to find
> things like "clang-format", which I do not think is available
> anywhere in "help -av", so I do not think "-av" can be promoted as
> an upward-compatible replacement in its current form.

Yep. I also thought "help -a" was denser but wasn't sure if it
actually helps or not. Whenever I look at that block of commands, I
end up searching anyway. For my use case, "help -a" could be better
served with something like "git apropos".

I think adding another section about external commands in "help -av"
would address the "clang-format" stuff. With that, it's probably good
enough to completely replace "help -a". It may also be good to list
aliases there too in a separate section so you have "all you can type"
in one (big) list.
--
Duy


Re: [PATCH v5 8/8] Documentation/config: add odb..promisorRemote

2018-09-25 Thread Duy Nguyen
On Tue, Sep 25, 2018 at 1:54 PM Christian Couder
 wrote:
>
> From: Christian Couder 
>
> Signed-off-by: Junio C Hamano 
> ---
>  Documentation/config.txt | 5 +
>  1 file changed, 5 insertions(+)
>
> diff --git a/Documentation/config.txt b/Documentation/config.txt
> index ad0f4510c3..9df988adb9 100644
> --- a/Documentation/config.txt
> +++ b/Documentation/config.txt
> @@ -2655,6 +2655,11 @@ This setting can be overridden with the 
> `GIT_NOTES_REWRITE_REF`
>  environment variable, which must be a colon separated list of refs or
>  globs.
>
> +odb..promisorRemote::
> +   The name of a promisor remote. For now promisor remotes are
> +   the only kind of remote object database (odb) that is
> +   supported.
> +

Nit. If this is the beginning of "odb" section in config.txt, maybe
move this to odb-config.txt and add

include::odb-config.txt[]

here since we're moving towards splitting config.txt for easier maintenance.
-- 
Duy


Subtree question and possible issue

2018-09-25 Thread Strain, Roger L.
We've got a fairly large codebase that's been through two previous source 
control systems, and recently converted to git. We have shared modules (but 
with customization) between projects, so subtrees looked like a good approach 
to sharing the code between projects. I've encountered a problem pushing 
commits back to the subtree repo which generated a question and maybe exposed 
an issue, though the issue could be with our repo for all I know.

[first attempt 2.16.0 (windows), retried with same results 2.19.0 (windows)]

Easier one first. Repo is set up to include code from another repo via subtree. 
We push code to the subtree using split --rejoin and get a commit linking the 
two together. New work is done on a branch that has a parent *before* the 
rejoin, and then merges back *after* the rejoin. When we later want to sync 
code using split --rejoin, am I right in believing that commit will appear 
parentless in the subtree repo, since the split will not process any commits 
which were reachable from the rejoin?  If that's right, is there any workaround 
other than --ignore-rejoins? Doing the split already takes quite a while, and 
if we don't get the benefit of rejoins, that process will only grow longer.

Harder part now. The actual problem I encountered was the remote claiming that 
my push couldn't be accepted because it was behind the remote HEAD of the 
branch. After looking closer at the local split, I discovered that the rejoin 
commit was not part of the new commit graph, which meant the commits were 
completely independent of the remote branch (hence the rejection). I reran the 
script with debug info turned on, and found the following result which was 
suspicious:

Processing commit: c3630d64ec64c56b3395bb9df573031d770803af
  parents: 8a1d1a97bfd04a77b2cd624038f64a256753fa09 
24b59e2a5f198d97a132a1c3080321a7238e176f
  newparents: 7da344d52155ec5cc3c67dde3577c6a99510ad05 
224fa84a093a3b0fc801d0ee1a2f7732a94e3f98
  tree is: 4b26d4dbe94c2ca43a4faa6c8e09f567400752d5
  newrev is: 224fa84a093a3b0fc801d0ee1a2f7732a94e3f98

This commit is the merge which links the parentless new-work commits (merged as 
224fa8) to the rejoin commit (accessible through 7da344). This particular 
commit should have been parented by both, but instead the script considered the 
two parents to be identical and simplified the graph to only use one. After 
digging into the script, it seems that this is because the tree hashes of the 
commits are the same. I've run a similar command to the one in the script to 
evaluate the hash information for both commits, including both tree hashes and 
commit hashes. There are some duplicate lines between the two, but they are 
clearly different commits with different histories. I've uploaded that output 
here, flagging the duplicate lines for convenience: 
https://gist.github.com/FoxFireX/41328a87bceeb3542c7a968348a92fa5

To further test this, I ran the script directly in (windows) bash, with the -x 
debug flag enabled on the script. It shows the comparison of the tree hashes, 
which is causing it to lose the parent that would link the branches together. 
That output is available here: 
https://gist.github.com/FoxFireX/d6b254d0f01af6533874eff2bb9ac135

I also went down the path of running the split with --ignore-joins (which I may 
need to do due to the first question anyway) but that process ended up creating 
an incorrect history that doesn't match the existing subtree, including a 
variety of commits which are completely unrelated to the subtree prefix. I 
haven't fully gone through the troubleshooting I want there, but may come back 
with other questions as I work through that process.

So, am I right about branching from pre-rejoin causing ugly commits in the 
subtree later? And what can I do about this split that refuses to properly join 
back up? Any help or insight would be most appreciated.

-- 
Roger Strain


Re: [PATCH 1/1] read-cache: update index format default to v4

2018-09-25 Thread Derrick Stolee

On 9/25/2018 3:06 AM, Patrick Steinhardt wrote:

On Mon, Sep 24, 2018 at 11:32:23PM +0200, SZEDER Gábor wrote:

On Mon, Sep 24, 2018 at 02:15:30PM -0700, Derrick Stolee via GitGitGadget wrote:

From: Derrick Stolee 

The index v4 format has been available since 2012 with 9d22778
"reach-cache.c: write prefix-compressed names in the index". Since
the format has been stable for so long, almost all versions of Git
in use today understand version 4, removing one barrier to upgrade
-- that someone may want to downgrade and needs a working repo.

What about alternative implementations, like JGit, libgit2, etc.?

Speaking of libgit2, we are able to read and write index v4 since
commit c1b370e93


This is a good point, Szeder.

Patrick: I'm glad LibGit2 is up-to-date with index formats.

Unfortunately, taking a look (for the first time) at the JGit code 
reveals that they don't appear to have v4 support. In 
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java, the 
DirCache.readFrom() method: lines 488-494, I see the following snippet:


    final int ver = NB.decodeInt32(hdr, 4);
    boolean extended = false;
    if (ver == 3)
    extended = true;
    else if (ver != 2)
    throw new 
CorruptObjectException(MessageFormat.format(

JGitText.get().unknownDIRCVersion, Integer.valueOf(ver)));

It looks like this will immediately throw with versions other than 2 or 3.

I'm adding Jonathan Nieder to CC so he can check with JGit people about 
the impact of this change.


Thanks,

-Stolee




  1   2   >