Git development
 help / color / mirror / Atom feed
* git log -S problem
From: Johannes Sixt @ 2007-05-20 19:15 UTC (permalink / raw)
  To: git

There is something odd with -S of git log. Try this in your git.git:

$ git log --pretty=oneline -Sbuiltin-merge-base -- Makefile 
71dfbf224ff980f4085f75868dc409118418731e Make merge-base a built-in.

$ git log --pretty=oneline -Smerge-base -- Makefile
e468305a954d95a26bfcdec3bc6e4bd477d95676 [PATCH] Remove the explicit ...
a3df180138b85a603656582bde6df757095618cf Rename git core commands ...
cef661fc799a3a13ffdea4a3f69f1acd295de53d Add support for alternate ...
e590d694ead8d50c2afc7086161d4ddc5d907655 Add more header dependencies.
6683463ed6b2da9eed309c305806f9393d1ae728 Do a very simple "merge-base"...

$ git version
git version 1.5.2

I had expected that the set of commits found by the second search string are a 
proper superset of those found by the first one. What's wrong here? Why does 
a search for 'merge-base' not find occurences of 'builtin-merge-base'?

-- Hannes

^ permalink raw reply

* Re: [PATCH] Teach mailsplit about Maildir's
From: Johan Herland @ 2007-05-20 19:27 UTC (permalink / raw)
  To: git; +Cc: Fernando J. Pereda, Junio C Hamano
In-Reply-To: <20070520191821.GF13197@ferdyx.org>

On Sunday 20 May 2007, Fernando J. Pereda wrote:
> On Sun, May 20, 2007 at 08:53:32PM +0200, Johan Herland wrote:
> > I use KMail with Maildir for all my mail, except for my "patches" mail folder 
> > where I copy patches to import into my repos (which is in mbox format). 
> > KMail makes it easy to mix mbox and Maildir folders, so it's not really a 
> > big deal for me, but I would of course prefer Maildir support if it's 
> > possible to get it right.
> > 
> > Not sure how I feel about the usefulness of the patch if it requires correct 
> > sorting, and most mail clients turn out to _not_ sort correctly. Of course 
> > I have no idea what most mail clients do, but KMail seems to get it about 
> > right, AFAICS (mail filename starts with timestamp, so they're at least 
> > sorted roughly on (arrival) date).
> 
> [ I sent this only to Johan, re-sending to the rest of the people now.
> Sorry Johan for the dupe ]
> 
> I discussed this with a pine user in #git and we concluded (looking at
> the respective code) that both Mutt and Pine generate correct filenames
> based on when that mail arrived to the Maildir.
> 
> I use Mutt, and to test it I picked a thread that didn't arrive in
> order, tagged and copied it to a different Maildir, patches were
> splitted in correct order.

Well, if Mutt, Pine, and KMail all get it right, then it looks like a 
useful feature to add.

Does anybody now of (current versions of) mail clients that do _not_ 
get this right?


-- 
Johan Herland, <johan@herland.net>
www.herland.net

^ permalink raw reply

* Re: [PATCH] Teach mailsplit about Maildir's
From: Fernando J. Pereda @ 2007-05-20 19:18 UTC (permalink / raw)
  To: Johan Herland; +Cc: git, Junio C Hamano
In-Reply-To: <200705202053.32291.johan@herland.net>

On Sun, May 20, 2007 at 08:53:32PM +0200, Johan Herland wrote:
> I use KMail with Maildir for all my mail, except for my "patches" mail folder 
> where I copy patches to import into my repos (which is in mbox format). 
> KMail makes it easy to mix mbox and Maildir folders, so it's not really a 
> big deal for me, but I would of course prefer Maildir support if it's 
> possible to get it right.
> 
> Not sure how I feel about the usefulness of the patch if it requires correct 
> sorting, and most mail clients turn out to _not_ sort correctly. Of course 
> I have no idea what most mail clients do, but KMail seems to get it about 
> right, AFAICS (mail filename starts with timestamp, so they're at least 
> sorted roughly on (arrival) date).

[ I sent this only to Johan, re-sending to the rest of the people now.
Sorry Johan for the dupe ]

I discussed this with a pine user in #git and we concluded (looking at
the respective code) that both Mutt and Pine generate correct filenames
based on when that mail arrived to the Maildir.

I use Mutt, and to test it I picked a thread that didn't arrive in
order, tagged and copied it to a different Maildir, patches were
splitted in correct order.

- ferdy

-- 
Fernando J. Pereda Garcimartín
20BB BDC3 761A 4781 E6ED  ED0B 0A48 5B0C 60BD 28D4

^ permalink raw reply

* Re: [PATCH] Teach 'git-apply --whitespace=strip' to remove empty lines at the end of file
From: Frank Lichtenheld @ 2007-05-20 19:17 UTC (permalink / raw)
  To: Marco Costalba; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <e5bfff550705201156m244e1cf0v7e6b3ab43fa3b47b@mail.gmail.com>

On Sun, May 20, 2007 at 08:56:49PM +0200, Marco Costalba wrote:
> On 5/20/07, Junio C Hamano <junkio@cox.net> wrote:
> >>               if (offset >= 0) {
> >> +
> >> +                     if (desc->size - oldsize - offset == 0) /* end of 
> >file? */
> >> +                             newsize -= trailing_added_lines;
> >> +
> >>                       int diff = newsize - oldsize;
> >>                       unsigned long size = desc->size + diff;
> >>                       unsigned long alloc = desc->alloc;
> >
> >But we have kept our sources -Wdeclaration-after-statement
> >clean so far
> 
> ??????
> 
> Wie bitte?

man gcc:

-Wdeclaration-after-statement (C only)
   Warn when a declaration is found after a statement in a block.

Gruesse,
-- 
Frank Lichtenheld <frank@lichtenheld.de>
www: http://www.djpig.de/

^ permalink raw reply

* Re: [PATCH] Teach 'git-apply --whitespace=strip' to remove empty lines at the end of file
From: Junio C Hamano @ 2007-05-20 19:16 UTC (permalink / raw)
  To: Marco Costalba; +Cc: Git Mailing List
In-Reply-To: <e5bfff550705201156m244e1cf0v7e6b3ab43fa3b47b@mail.gmail.com>

"Marco Costalba" <mcostalba@gmail.com> writes:

> On 5/20/07, Junio C Hamano <junkio@cox.net> wrote:
> ...
>> > diff --git a/builtin-apply.c b/builtin-apply.c
>> > index 0399743..6032f78 100644
>> > --- a/builtin-apply.c
>> > +++ b/builtin-apply.c
>> > ...
>> > @@ -1770,6 +1800,10 @@ static int apply_one_fragment(struct buffer_desc *desc,
>> >               if (match_beginning && offset)
>> >                       offset = -1;
>> >               if (offset >= 0) {
>> > +
>> > +                     if (desc->size - oldsize - offset == 0) /* end of file? */
>> > +                             newsize -= trailing_added_lines;
>> > +
>> >                       int diff = newsize - oldsize;
>> >                       unsigned long size = desc->size + diff;
>> >                       unsigned long alloc = desc->alloc;
>>
>> But we have kept our sources -Wdeclaration-after-statement
>> clean so far
>
> ??????
>
> Wie bitte?

Sorry I forgot to mention that that is "trivial" so there is no
reason to resend.  I don't expect me doing much git stuff for
the rest of the day, but you'll hear from me about this patch
later (hopefully it would appear on 'next' -- we'll see).

^ permalink raw reply

* Re: [RFC] Third round of support for cloning submodules
From: Junio C Hamano @ 2007-05-20 19:10 UTC (permalink / raw)
  To: skimo; +Cc: git
In-Reply-To: <11796842882917-git-send-email-skimo@liacs.nl>

skimo@liacs.nl writes:

> This patch series implements a mechanism for cloning submodules.

Let me start by asking a few stupid questions.

> Each submodule is specified by a 'submodule.<submodule>.url'
> configuration option, e.g.,
>
> bash-3.00$ ./git-config --remote=http://www.liacs.nl/~sverdool/isa.git --get-regexp 'submodule\..*\.url' 
> submodule.cloog.url /home/sverdool/public_html/cloog.git
> submodule.cloog.url http://www.liacs.nl/~sverdool/cloog.git

You are priming the process by having these configuration
variables in the superproject to be cloned (i.e. this is done by
the owner of the superproject).

> git-checkout will use the first url that works.
> E.g., a
>
> git clone --submodules ssh://liacs/~/public_html/isa.git
>
> followed by
>
> git checkout origin/submodule
>
> (which only works for me), will use the first url, while a
>
> git clone --submodules http://www.liacs.nl/~sverdool/isa.git
>
> followed by
>
> git checkout origin/submodule
>
> will use the second.

What's the design like to make clone and checkout work together?
When you run the first clone with -n ("do not checkout"), what
should happen (I am not asking what your code does, but what the
desired behaviour should be)?  My take on that question is
"subproject cloning is done by checkout, not clone".

> The cloning of submodules is now handled inside git-checkout.

which I guess means your answer is the same as mine, which
is fine.

I am very worried about this big red switch that says "all
subprojects to be cloned and checked out, or nothing".  I think
this would not work well with projects that truly need
superproject support (i.e. very large ones, where most people
would not want to clone and check out every single subproject).

> I currently do not fetch after the initial clone, since
> I'm not sure what ref to use for the revision I need to
> fetch for the supermodule.

I think fetching inside the subproject can be safely done with
the default (i.e. refs/heads/*:refs/remotes/origin/*) of 1.5.0
or later, as long as we tell the users of the feature that they
should make sure that the commit referenced by superproject tree
entries are available with such a fetch, which is a sane thing
to require anyway.

The more important issue I think is at what point in the
superproject operation does a recursive checkout in a subproject
should happen, and how we should do the checkout.  Issues I can
think of offhand are (no way exhaustive):

 - Do we checkout a branch? if so which one?

 - Do we detach HEAD if the commit named by the superproject
   tree is not at the tip of the current branch of subproject?
   do we detach always even if the commit is at the tip?

 - What would we do when the subproject working tree is not
   clean?

 - How can a user decide which subproject to descend into and
   which subproject to ignore, and how does git remember the
   earlier decision made by the user without asking the same
   again, and how does a user express "now I want to also track
   that subproject I've ignored so far" and "now I am not
   interested in following that subproject anymore"?

So I tend to disagree with not having the indirection we
discussed on the other thread about .gitmodules, but I consider
it a minor detail of cloning, and it is not a major deal to me.

However, I agree with Alex that checkout semantics is a much
bigger deal, and would expect people (brighter than myself,
hopefully) to offer ideas.

^ permalink raw reply

* Re: git-rebase (1.5.0.6) errors
From: Ilpo Järvinen @ 2007-05-20 19:02 UTC (permalink / raw)
  To: Jan Hudec; +Cc: David Kastrup, Paolo Teti, git
In-Reply-To: <20070520124345.GB27087@efreet.light.src>

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

On Sun, 20 May 2007, Jan Hudec wrote:

> On Fri, May 18, 2007 at 17:02:56 +0300, Ilpo Järvinen wrote:
> > David Kastrup <dak@gnu.org> wrote:
> > 
> > > Only if size_t is a larger type than int (could be on x86-64 and alpha
> > > architectures).  Other than that, this comparison would work.  Which
> > > does not mean that this does not warrant fixing, but it is not
> > > necessarily the cause of this problem.
> > 
> > ...sizeof(size_t) == sizeof(int) should hold...
> 
> Really?
> 
> $ cat test.c
> #include <stdio.h>
> int main(void)
> {
>     printf("sizeof(int) = %i\n", sizeof(int));
>     printf("sizeof(long) = %i\n", sizeof(long));
>     printf("sizeof(size_t) = %i\n", sizeof(size_t));
>     return 0;
> }
> $ gcc -otest test.c
> $ ./test
> sizeof(int) = 4
> sizeof(long) = 8
> sizeof(size_t) = 8
> 
> Hm, it does not seem that sizeof(size_t) == sizeof(int).

...On 64-bit perhaps but mine isn't one of them... I'm sorry if my 
wording was misleading, I meant to say that on my system the equality 
of sizeof()s should hold... :-)

> $ uname -m
> x86_64
> 
> Yes, this is a 64-bit system.

ijjarvin@kivilampi-30:~/src/testsize$ ./main
sizeof(int) = 4
sizeof(long) = 4
sizeof(size_t) = 4

$ uname -m
i686


-- 
 i.

^ permalink raw reply

* Re: [PATCH] Teach mailsplit about Maildir's
From: Fernando J. Pereda @ 2007-05-20 19:00 UTC (permalink / raw)
  To: Alex Riesen; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <20070520184959.GA25462@steel.home>

On Sun, May 20, 2007 at 08:49:59PM +0200, Alex Riesen wrote:
> Junio C Hamano, Sun, May 20, 2007 20:36:25 +0200:
> > > +IMPORTANT: Maildir splitting relies upon filenames being sorted to output
> > > +patches in the correct order.
> > 
> > I am sure there are many users who uses Maildir layout on this
> > list.  Happy with this patch?  Please speak out.
> 
> I do use maildirs, but I have a suggestion: --maildir or something, to
> create a non-existing maildir and split into it, so that the user does
> not have to pre-create it.

I can't think of a use case for this...

- ferdy

-- 
Fernando J. Pereda Garcimartín
20BB BDC3 761A 4781 E6ED  ED0B 0A48 5B0C 60BD 28D4

^ permalink raw reply

* Re: [PATCH] Teach 'git-apply --whitespace=strip' to remove empty lines at the end of file
From: Marco Costalba @ 2007-05-20 18:56 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List
In-Reply-To: <7v1whbmjel.fsf@assigned-by-dhcp.cox.net>

On 5/20/07, Junio C Hamano <junkio@cox.net> wrote:
> "Marco Costalba" <mcostalba@gmail.com> writes:
>
> > Ok. This is take 3. It works correctly on standard patches and also on
> > u0 example that you gave above.
> >
> > This patch is on top of git 1.5.2
> >
> > Please check it.
>
> I think the checks and actions are at the right places (I
> haven't looked very closely nor tried to run it yet).
>
> > builtin-apply.c |   34 ++++++++++++++++++++++++++++++++++
> > 1 files changed, 34 insertions(+), 0 deletions(-)
> >
> > diff --git a/builtin-apply.c b/builtin-apply.c
> > index 0399743..6032f78 100644
> > --- a/builtin-apply.c
> > +++ b/builtin-apply.c
> > ...
> > @@ -1770,6 +1800,10 @@ static int apply_one_fragment(struct buffer_desc *desc,
> >               if (match_beginning && offset)
> >                       offset = -1;
> >               if (offset >= 0) {
> > +
> > +                     if (desc->size - oldsize - offset == 0) /* end of file? */
> > +                             newsize -= trailing_added_lines;
> > +
> >                       int diff = newsize - oldsize;
> >                       unsigned long size = desc->size + diff;
> >                       unsigned long alloc = desc->alloc;
>
> But we have kept our sources -Wdeclaration-after-statement
> clean so far

??????

Wie bitte?

^ permalink raw reply

* Re: [PATCH] Teach mailsplit about Maildir's
From: Johan Herland @ 2007-05-20 18:53 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Fernando J. Pereda
In-Reply-To: <7v7ir3mjfa.fsf@assigned-by-dhcp.cox.net>

On Sunday 20 May 2007, Junio C Hamano wrote:
> "Fernando J. Pereda" <ferdy@gentoo.org> writes:
> 
> > Signed-off-by: Fernando J. Pereda <ferdy@gentoo.org>
> > ---
> >
> > 	I never got ACK or NACK when I sent it the first time, that's why
> > 	I'm resending this one with (almost) no changes.
> 
> Sorry, I had a (n obviously false) impression that you retracted
> this patch due to this:
> 
> > ...
> > +IMPORTANT: Maildir splitting relies upon filenames being sorted to output
> > +patches in the correct order.
> 
> I am sure there are many users who uses Maildir layout on this
> list.  Happy with this patch?  Please speak out.

I use KMail with Maildir for all my mail, except for my "patches" mail folder 
where I copy patches to import into my repos (which is in mbox format). 
KMail makes it easy to mix mbox and Maildir folders, so it's not really a 
big deal for me, but I would of course prefer Maildir support if it's 
possible to get it right.

Not sure how I feel about the usefulness of the patch if it requires correct 
sorting, and most mail clients turn out to _not_ sort correctly. Of course 
I have no idea what most mail clients do, but KMail seems to get it about 
right, AFAICS (mail filename starts with timestamp, so they're at least 
sorted roughly on (arrival) date).


Have fun!

...Johan

-- 
Johan Herland, <johan@herland.net>
www.herland.net

^ permalink raw reply

* Re: [PATCH] Teach mailsplit about Maildir's
From: Alex Riesen @ 2007-05-20 18:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Fernando J. Pereda, Git Mailing List
In-Reply-To: <7v7ir3mjfa.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano, Sun, May 20, 2007 20:36:25 +0200:
> > +IMPORTANT: Maildir splitting relies upon filenames being sorted to output
> > +patches in the correct order.
> 
> I am sure there are many users who uses Maildir layout on this
> list.  Happy with this patch?  Please speak out.

I do use maildirs, but I have a suggestion: --maildir or something, to
create a non-existing maildir and split into it, so that the user does
not have to pre-create it.

^ permalink raw reply

* Re: [PATCH] rev-list: '--indent' oneline output
From: Junio C Hamano @ 2007-05-20 18:36 UTC (permalink / raw)
  To: Steffen Prohaska; +Cc: git, bfields, torvalds, junkio
In-Reply-To: <1179676829751-git-send-email-prohaska@zib.de>

Steffen Prohaska <prohaska@zib.de> writes:

> Summaries in oneline output are indented to show the location of
> parents in merge commits. Indentation level is computed as the
> smallest sum of parent locations along all paths that reach the
> commit.
>
> As a result, the output of
>     git-rev-list --pretty=oneline --topo-order --indent
> is formatted in a way that resembles merge summaries. All commits that
> were pulled from a branch are indented with one additional space below
> the summary of the merge commit.

I would have expected this kind of UI level tweak to be done not
as a rev-list feature, but the subject of the e-mail to read
something like "--pretty=oneline: allow indentation levels",
i.e. wouldn't the feature apply not just rev-list but also
git-log?

^ permalink raw reply

* Re: [PATCH] Teach 'git-apply --whitespace=strip' to remove empty lines at the end of file
From: Junio C Hamano @ 2007-05-20 18:36 UTC (permalink / raw)
  To: Marco Costalba; +Cc: Git Mailing List
In-Reply-To: <e5bfff550705200545kcf1f7f9n4f3f6d7d25955e1@mail.gmail.com>

"Marco Costalba" <mcostalba@gmail.com> writes:

> Ok. This is take 3. It works correctly on standard patches and also on
> u0 example that you gave above.
>
> This patch is on top of git 1.5.2
>
> Please check it.

I think the checks and actions are at the right places (I
haven't looked very closely nor tried to run it yet).

> builtin-apply.c |   34 ++++++++++++++++++++++++++++++++++
> 1 files changed, 34 insertions(+), 0 deletions(-)
>
> diff --git a/builtin-apply.c b/builtin-apply.c
> index 0399743..6032f78 100644
> --- a/builtin-apply.c
> +++ b/builtin-apply.c
> ...
> @@ -1770,6 +1800,10 @@ static int apply_one_fragment(struct buffer_desc *desc,
> 		if (match_beginning && offset)
> 			offset = -1;
> 		if (offset >= 0) {
> +
> +			if (desc->size - oldsize - offset == 0) /* end of file? */
> +				newsize -= trailing_added_lines;
> +
> 			int diff = newsize - oldsize;
> 			unsigned long size = desc->size + diff;
> 			unsigned long alloc = desc->alloc;

But we have kept our sources -Wdeclaration-after-statement
clean so far, and this hunk needs a trivial adjustment.

^ permalink raw reply

* Re: [PATCH] Teach mailsplit about Maildir's
From: Junio C Hamano @ 2007-05-20 18:36 UTC (permalink / raw)
  To: Fernando J. Pereda; +Cc: Git Mailing List
In-Reply-To: <20070520181447.GA10638@ferdyx.org>

"Fernando J. Pereda" <ferdy@gentoo.org> writes:

> Signed-off-by: Fernando J. Pereda <ferdy@gentoo.org>
> ---
>
> 	I never got ACK or NACK when I sent it the first time, that's why
> 	I'm resending this one with (almost) no changes.

Sorry, I had a (n obviously false) impression that you retracted
this patch due to this:

> ...
> +IMPORTANT: Maildir splitting relies upon filenames being sorted to output
> +patches in the correct order.

I am sure there are many users who uses Maildir layout on this
list.  Happy with this patch?  Please speak out.

^ permalink raw reply

* Re: [PATCH 07/16] git-read-tree: take --submodules option
From: Junio C Hamano @ 2007-05-20 18:33 UTC (permalink / raw)
  To: Jan Hudec; +Cc: skimo, Alex Riesen, git
In-Reply-To: <20070520155407.GC27087@efreet.light.src>

Jan Hudec <bulb@ucw.cz> writes:

> IMHO it makes more sense to fetch during fetch of superproject:
>
>  - If you don't fetch the superproject, it won't start refering to
>    unavailable commit of subproject. So should only need to fetch subproject
>    after fetching superproject.

Eh, I was suggesting that the subproject fetch would come after
checkout in "fetch and then checkout" sequence of the
superproject, and if you are arguing against it, you should
justify why it should not happen before checkout, as we both
agree it should come after fetch of superproject.  Your argument
is like saying you have to git-init before doing anything so
you should fetch when you git-init.  That's not a justification.

>  - If you fetch from more than one location, you want to fetch subproject
>    from location corresponding to where you fetch superproject from.

Not at all.  There is no reason to believe that the case that
superproject and subproject come from related URLs is more
common.  One of the reasons to do a separated project
organization is to allow looser bindings of the project from
project administrative viewpoint. The integrator may not
necessarily have any control over what the subproject guys do,
and more importantly, the subproject people do not even care nor
be aware of the fact that their project is sometimes bound
inside other peoples' superprojects.  Think of the embedded
appliance vendor binding the kernel, libc and busybox in their
superproject that holds them together with the build
infrastructure. The kernel folks certainly do not particularly
care about the vendor.

^ permalink raw reply

* Re: [PATCH] allow commands to be executed in submodules
From: Junio C Hamano @ 2007-05-20 18:25 UTC (permalink / raw)
  To: Alex Riesen; +Cc: Martin Waitz, git
In-Reply-To: <20070520181433.GA19668@steel.home>

Alex Riesen <raa.lkml@gmail.com> writes:

> Martin Waitz, Sun, May 20, 2007 17:39:08 +0200:
>> Add an extra "submodule" field to struct child_process to be able to
>> easily start commands which are to be executed in a submodule
>> repository.
>
> How about making it more generic by allowing to specify the directory
> to change to and environment for subprocess? You probably will be able
> to convert even some of existing code to your new run_command then
> (merge_recursive in builtin-revert.c, for example).

Sounds useful and more generic.

^ permalink raw reply

* [PATCH] Teach mailsplit about Maildir's
From: Fernando J. Pereda @ 2007-05-20 18:14 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

Signed-off-by: Fernando J. Pereda <ferdy@gentoo.org>
---

	I never got ACK or NACK when I sent it the first time, that's why
	I'm resending this one with (almost) no changes.

 Documentation/git-am.txt        |    8 ++-
 Documentation/git-mailsplit.txt |   13 +++-
 builtin-mailsplit.c             |  122 ++++++++++++++++++++++++++++++++------
 builtin.h                       |    2 +-
 4 files changed, 118 insertions(+), 27 deletions(-)

diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index ba79773..25cf84a 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -12,7 +12,8 @@ SYNOPSIS
 'git-am' [--signoff] [--dotest=<dir>] [--keep] [--utf8 | --no-utf8]
          [--3way] [--interactive] [--binary]
          [--whitespace=<option>] [-C<n>] [-p<n>]
-         <mbox>...
+         <mbox>|<Maildir>...
+
 'git-am' [--skip | --resolved]
 
 DESCRIPTION
@@ -23,9 +24,10 @@ current branch.
 
 OPTIONS
 -------
-<mbox>...::
+<mbox>|<Maildir>...::
 	The list of mailbox files to read patches from. If you do not
-	supply this argument, reads from the standard input.
+	supply this argument, reads from the standard input. If you supply
+	directories, they'll be treated as Maildirs.
 
 -s, --signoff::
 	Add `Signed-off-by:` line to the commit message, using
diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt
index c11d6a5..abb0903 100644
--- a/Documentation/git-mailsplit.txt
+++ b/Documentation/git-mailsplit.txt
@@ -7,12 +7,15 @@ git-mailsplit - Simple UNIX mbox splitter program
 
 SYNOPSIS
 --------
-'git-mailsplit' [-b] [-f<nn>] [-d<prec>] -o<directory> [--] [<mbox>...]
+'git-mailsplit' [-b] [-f<nn>] [-d<prec>] -o<directory> [--] [<mbox>|<Maildir>...]
 
 DESCRIPTION
 -----------
-Splits a mbox file into a list of files: "0001" "0002" ..  in the specified
-directory so you can process them further from there.
+Splits a mbox file or a Maildir into a list of files: "0001" "0002" ..  in the
+specified directory so you can process them further from there.
+
+IMPORTANT: Maildir splitting relies upon filenames being sorted to output
+patches in the correct order.
 
 OPTIONS
 -------
@@ -20,6 +23,10 @@ OPTIONS
 	Mbox file to split.  If not given, the mbox is read from
 	the standard input.
 
+<Maildir>::
+	Root of the Maildir to split. This directory should contain the cur, tmp
+	and new subdirectories.
+
 <directory>::
 	Directory in which to place the individual messages.
 
diff --git a/builtin-mailsplit.c b/builtin-mailsplit.c
index 3bca855..1d096d6 100644
--- a/builtin-mailsplit.c
+++ b/builtin-mailsplit.c
@@ -6,9 +6,10 @@
  */
 #include "cache.h"
 #include "builtin.h"
+#include "path-list.h"
 
 static const char git_mailsplit_usage[] =
-"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>...";
+"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>|<Maildir>...";
 
 static int is_from_line(const char *line, int len)
 {
@@ -96,44 +97,106 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
 	exit(1);
 }
 
-int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip)
+static int populate_maildir_list(struct path_list *list, const char *path)
 {
-	char *name = xmalloc(strlen(dir) + 2 + 3 * sizeof(skip));
+	DIR *dir;
+	struct dirent *dent;
+
+	if ((dir = opendir(path)) == NULL) {
+		error("cannot diropen %s (%s)", path, strerror(errno));
+		return -1;
+	}
+
+	while ((dent = readdir(dir)) != NULL) {
+		if (dent->d_name[0] == '.')
+			continue;
+		path_list_insert(dent->d_name, list);
+	}
+
+	closedir(dir);
+
+	return 1;
+}
+
+static int split_maildir(const char *maildir, const char *dir,
+	int nr_prec, int skip)
+{
+	char file[PATH_MAX];
+	char curdir[PATH_MAX];
+	char name[PATH_MAX];
 	int ret = -1;
+	struct path_list list = {NULL, 0, 0, 1};
 
-	while (*mbox) {
-		const char *file = *mbox++;
-		FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
-		int file_done = 0;
+	snprintf(curdir, sizeof(curdir), "%s/cur", maildir);
+	if (populate_maildir_list(&list, curdir) < 0)
+		goto out;
 
-		if ( !f ) {
-			error("cannot open mbox %s", file);
+	int i;
+	for (i = 0; i < list.nr; i++) {
+		snprintf(file, sizeof(file), "%s/%s", curdir, list.items[i].path);
+		FILE *f = fopen(file, "r");
+		if (!f) {
+			error("cannot open mail %s (%s)", file, strerror(errno));
 			goto out;
 		}
 
 		if (fgets(buf, sizeof(buf), f) == NULL) {
-			if (f == stdin)
-				break; /* empty stdin is OK */
-			error("cannot read mbox %s", file);
+			error("cannot read mail %s (%s)", file, strerror(errno));
 			goto out;
 		}
 
-		while (!file_done) {
-			sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
-			file_done = split_one(f, name, allow_bare);
+		sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+		split_one(f, name, 1);
+
+		fclose(f);
+	}
+
+	path_list_clear(&list, 1);
+
+	ret = skip;
+out:
+	return ret;
+}
+
+int split_mbox(const char *file, const char *dir, int allow_bare,
+		int nr_prec, int skip)
+{
+	char name[PATH_MAX];
+	int ret = -1;
+
+	FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
+	int file_done = 0;
+
+	if (!f) {
+		error("cannot open mbox %s", file);
+		goto out;
+	}
+
+	if (fgets(buf, sizeof(buf), f) == NULL) {
+		/* empty stdin is OK */
+		if (f != stdin) {
+			error("cannot read mbox %s", file);
+			goto out;
 		}
+		file_done = 1;
+	}
 
-		if (f != stdin)
-			fclose(f);
+	while (!file_done) {
+		sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+		file_done = split_one(f, name, allow_bare);
 	}
+
+	if (f != stdin)
+		fclose(f);
+
 	ret = skip;
 out:
-	free(name);
 	return ret;
 }
+
 int cmd_mailsplit(int argc, const char **argv, const char *prefix)
 {
-	int nr = 0, nr_prec = 4, ret;
+	int nr = 0, nr_prec = 4, ret = 0;
 	int allow_bare = 0;
 	const char *dir = NULL;
 	const char **argp;
@@ -186,7 +249,26 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)
 			argp = stdin_only;
 	}
 
-	ret = split_mbox(argp, dir, allow_bare, nr_prec, nr);
+	while (*argp) {
+		const char *arg = *argp++;
+		struct stat argstat;
+
+		if (arg[0] == '-' && arg[1] == 0) {
+			ret |= split_mbox(arg, dir, allow_bare, nr_prec, nr);
+			continue;
+		}
+
+		if (stat(arg, &argstat) == -1) {
+			error("cannot stat %s (%s)", arg, strerror(errno));
+			return 1;
+		}
+
+		if (S_ISDIR(argstat.st_mode))
+			ret |= split_maildir(arg, dir, nr_prec, nr);
+		else
+			ret |= split_mbox(arg, dir, allow_bare, nr_prec, nr);
+	}
+
 	if (ret != -1)
 		printf("%d\n", ret);
 
diff --git a/builtin.h b/builtin.h
index d3f3a74..39290d1 100644
--- a/builtin.h
+++ b/builtin.h
@@ -8,7 +8,7 @@ extern const char git_usage_string[];
 
 extern void help_unknown_cmd(const char *cmd);
 extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
-extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
+extern int split_mbox(const char *file, const char *dir, int allow_bare, int nr_prec, int skip);
 extern void stripspace(FILE *in, FILE *out);
 extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
 extern void prune_packed_objects(int);
-- 
1.5.2


-- 
Fernando J. Pereda Garcimartín
20BB BDC3 761A 4781 E6ED  ED0B 0A48 5B0C 60BD 28D4

^ permalink raw reply related

* Re: [PATCH] allow commands to be executed in submodules
From: Alex Riesen @ 2007-05-20 18:14 UTC (permalink / raw)
  To: Martin Waitz; +Cc: git
In-Reply-To: <20070520153908.GF5412@admingilde.org>

Martin Waitz, Sun, May 20, 2007 17:39:08 +0200:
> Add an extra "submodule" field to struct child_process to be able to
> easily start commands which are to be executed in a submodule
> repository.

How about making it more generic by allowing to specify the directory
to change to and environment for subprocess? You probably will be able
to convert even some of existing code to your new run_command then
(merge_recursive in builtin-revert.c, for example).

Something like this, perhaps:

diff --git a/run-command.c b/run-command.c
index eff523e..605aa1e 100644
--- a/run-command.c
+++ b/run-command.c
@@ -73,6 +73,13 @@ int start_command(struct child_process *cmd)
 			close(cmd->out);
 		}
 
+		if (cmd->dir && chdir(cmd->dir))
+			die("exec %s: cd to %s failed (%s)", cmd->argv[0],
+			    cmd->dir, strerror(errno));
+		if (cmd->env) {
+			for (; *cmd->env; cmd->env++)
+				putenv((char*)*cmd->env);
+		}
 		if (cmd->git_cmd) {
 			execv_git_cmd(cmd->argv);
 		} else {
@@ -133,13 +140,38 @@ int run_command(struct child_process *cmd)
 	return finish_command(cmd);
 }
 
+static void prepare_run_command_v_opt(struct child_process *cmd,
+				      const char **argv,
+				      int opt)
+{
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->argv = argv;
+	cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
+	cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
+	cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
+}
+
 int run_command_v_opt(const char **argv, int opt)
 {
 	struct child_process cmd;
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.argv = argv;
-	cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
-	cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
-	cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
+	prepare_run_command_v_opt(&cmd, argv, opt);
 	return run_command(&cmd);
 }
+
+int run_command_v_opt_cd(const char **argv, int opt, const char *dir)
+{
+	struct child_process cmd;
+	prepare_run_command_v_opt(&cmd, argv, opt);
+	cmd.dir = dir;
+	return run_command(&cmd);
+}
+
+int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
+{
+	struct child_process cmd;
+	prepare_run_command_v_opt(&cmd, argv, opt);
+	cmd.dir = dir;
+	cmd.env = env;
+	return run_command(&cmd);
+}
+
diff --git a/run-command.h b/run-command.h
index 3680ef9..af1e0bf 100644
--- a/run-command.h
+++ b/run-command.h
@@ -16,6 +16,8 @@ struct child_process {
 	pid_t pid;
 	int in;
 	int out;
+	const char *dir;
+	const char *const *env;
 	unsigned close_in:1;
 	unsigned close_out:1;
 	unsigned no_stdin:1;
@@ -32,5 +34,7 @@ int run_command(struct child_process *);
 #define RUN_GIT_CMD	     2	/*If this is to be git sub-command */
 #define RUN_COMMAND_STDOUT_TO_STDERR 4
 int run_command_v_opt(const char **argv, int opt);
+int run_command_v_opt_cd(const char **argv, int opt, const char *dir);
+int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env);
 
 #endif

^ permalink raw reply related

* Re: [PATCH 02/15] git-config: add --remote option for reading config from remote repo
From: Frank Lichtenheld @ 2007-05-20 18:11 UTC (permalink / raw)
  To: skimo; +Cc: git, Junio C Hamano
In-Reply-To: <11796842881646-git-send-email-skimo@liacs.nl>

On Sun, May 20, 2007 at 08:04:35PM +0200, skimo@liacs.nl wrote:
> From: Sven Verdoolaege <skimo@kotnet.org>
> 
> Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
> ---
>  Documentation/git-config.txt |   33 +++++++++++++++++++++---------

All my old suggestions and corrections for the documentation
part still apply... should I repeat them?

Gruesse,
-- 
Frank Lichtenheld <frank@lichtenheld.de>
www: http://www.djpig.de/

^ permalink raw reply

* [PATCH 15/15] git-clone: add --submodules for cloning submodules
From: skimo @ 2007-05-20 18:04 UTC (permalink / raw)
  To: git, Junio C Hamano
In-Reply-To: <11796842882917-git-send-email-skimo@liacs.nl>

From: Sven Verdoolaege <skimo@kotnet.org>

When the --submodules option is specified, git-clone will search
for submodule.<submodule>.url options in the remote configuration
and clone each submodule using the first url that it can use from
the local site.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
---
 Documentation/git-clone.txt |    6 +++++-
 git-clone.sh                |   16 ++++++++++++++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 644bf12..565155b 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
 	  [-o <name>] [-u <upload-pack>] [--reference <repository>]
-	  [--depth <depth>] <repository> [<directory>]
+	  [--depth <depth>] [--submodules] <repository> [<directory>]
 
 DESCRIPTION
 -----------
@@ -105,6 +105,10 @@ OPTIONS
 	with a long history, and would want to send in a fixes
 	as patches.
 
+--submodules::
+	Clone submodules specified in (remote) configuration parameters
+	submodule.<submodule>.url.
+
 <repository>::
 	The (possibly remote) repository to clone from.  It can
 	be any URL git-fetch supports.
diff --git a/git-clone.sh b/git-clone.sh
index fdd354f..a51b887 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -14,7 +14,7 @@ die() {
 }
 
 usage() {
-	die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] <repo> [<dir>]"
+	die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] [--submodules] <repo> [<dir>]"
 }
 
 get_repo_base() {
@@ -88,6 +88,7 @@ origin_override=
 use_separate_remote=t
 depth=
 no_progress=
+submodules=
 test -t 1 || no_progress=--no-progress
 while
 	case "$#,$1" in
@@ -138,6 +139,8 @@ while
 	*,--depth)
 		shift
 		depth="--depth=$1";;
+	*,--su|*,--sub|*,--subm|*,--submo|*,--submod|*,--submodu|*,--submodul|\
+	*,--submodule|*,--submodules) submodules="--submodules" ;;
 	*,-*) usage ;;
 	*) break ;;
 	esac
@@ -156,6 +159,10 @@ then
 	then
 		die '--bare and --origin $origin options are incompatible.'
 	fi
+	if test -n "$submodules"
+	then
+		die '--bare and --submodules origin options are incompatible.'
+	fi
 	no_checkout=yes
 	use_separate_remote=
 fi
@@ -401,10 +408,15 @@ then
 		git-config branch."$head_points_at".merge "refs/heads/$head_points_at"
 	esac
 
+	if test -n "$submodules"
+	then
+		git-config core.submodules true
+	fi
+
 	case "$no_checkout" in
 	'')
 		test "z$quiet" = z -a "z$no_progress" = z && v=-v || v=
-		git-read-tree -m -u $v HEAD HEAD
+		git-read-tree -m -u $v $submodules HEAD HEAD
 	esac
 fi
 rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD"
-- 
1.5.2.rc3.815.g8fc2

^ permalink raw reply related

* [PATCH 12/15] git_config: add void * for callback data
From: skimo @ 2007-05-20 18:04 UTC (permalink / raw)
  To: git, Junio C Hamano
In-Reply-To: <11796842882917-git-send-email-skimo@liacs.nl>

From: Sven Verdoolaege <skimo@kotnet.org>

---
 archive-tar.c            |    6 +++---
 builtin-add.c            |    6 +++---
 builtin-apply.c          |    6 +++---
 builtin-blame.c          |    6 +++---
 builtin-branch.c         |   10 +++++-----
 builtin-cat-file.c       |    2 +-
 builtin-checkout-index.c |    2 +-
 builtin-commit-tree.c    |    2 +-
 builtin-config.c         |   21 +++++++++++----------
 builtin-diff-files.c     |    2 +-
 builtin-diff-index.c     |    2 +-
 builtin-diff-tree.c      |    2 +-
 builtin-diff.c           |    2 +-
 builtin-fmt-merge-msg.c  |    5 +++--
 builtin-gc.c             |    6 +++---
 builtin-init-db.c        |    4 ++--
 builtin-log.c            |   18 +++++++++---------
 builtin-ls-files.c       |    2 +-
 builtin-ls-tree.c        |    2 +-
 builtin-mailinfo.c       |    2 +-
 builtin-merge-base.c     |    2 +-
 builtin-mv.c             |    2 +-
 builtin-name-rev.c       |    2 +-
 builtin-pack-objects.c   |    6 +++---
 builtin-push.c           |    4 ++--
 builtin-read-tree.c      |    9 +++++----
 builtin-reflog.c         |    7 ++++---
 builtin-rerere.c         |    6 +++---
 builtin-rev-list.c       |    2 +-
 builtin-rev-parse.c      |    2 +-
 builtin-revert.c         |    2 +-
 builtin-rm.c             |    2 +-
 builtin-runstatus.c      |    2 +-
 builtin-show-branch.c    |    7 ++++---
 builtin-symbolic-ref.c   |    2 +-
 builtin-unpack-objects.c |    2 +-
 builtin-update-index.c   |    2 +-
 builtin-update-ref.c     |    2 +-
 builtin-verify-pack.c    |    2 +-
 cache.h                  |   13 +++++++------
 config.c                 |   36 ++++++++++++++++++------------------
 connect.c                |    7 ++++---
 convert.c                |    5 +++--
 daemon.c                 |    4 ++--
 diff.c                   |    6 +++---
 diff.h                   |    2 +-
 dump-config.c            |    4 ++--
 fast-import.c            |    2 +-
 fetch-pack.c             |    6 +++---
 git.c                    |    4 ++--
 http-fetch.c             |    2 +-
 http.c                   |    6 +++---
 imap-send.c              |    4 ++--
 local-fetch.c            |    2 +-
 merge-recursive.c        |   10 +++++-----
 receive-pack.c           |    6 +++---
 send-pack.c              |    2 +-
 setup.c                  |    5 +++--
 ssh-fetch.c              |    2 +-
 unpack-file.c            |    2 +-
 var.c                    |    8 ++++----
 wt-status.c              |    4 ++--
 wt-status.h              |    2 +-
 63 files changed, 163 insertions(+), 154 deletions(-)

diff --git a/archive-tar.c b/archive-tar.c
index 33e7657..595c153 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -242,7 +242,7 @@ static void write_global_extended_header(const unsigned char *sha1)
 	free(ext_header.buf);
 }
 
-static int git_tar_config(const char *var, const char *value)
+static int git_tar_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "tar.umask")) {
 		if (!strcmp(value, "user")) {
@@ -253,7 +253,7 @@ static int git_tar_config(const char *var, const char *value)
 		}
 		return 0;
 	}
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static int write_tar_entry(const unsigned char *sha1,
@@ -300,7 +300,7 @@ int write_tar_archive(struct archiver_args *args)
 {
 	int plen = args->base ? strlen(args->base) : 0;
 
-	git_config(git_tar_config);
+	git_config(git_tar_config, NULL);
 
 	archive_time = args->time;
 	verbose = args->verbose;
diff --git a/builtin-add.c b/builtin-add.c
index 1591171..1b24c56 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -136,7 +136,7 @@ static void update(int verbose, const char **files)
 	run_diff_files(&rev, 0);
 }
 
-static int git_add_config(const char *var, const char *value)
+static int git_add_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "core.excludesfile")) {
 		if (!value)
@@ -145,7 +145,7 @@ static int git_add_config(const char *var, const char *value)
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static struct lock_file lock_file;
@@ -175,7 +175,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 		exit(1);
 	}
 
-	git_config(git_add_config);
+	git_config(git_add_config, NULL);
 
 	newfd = hold_locked_index(&lock_file, 1);
 
diff --git a/builtin-apply.c b/builtin-apply.c
index 0399743..deae199 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -2707,13 +2707,13 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
 	return 0;
 }
 
-static int git_apply_config(const char *var, const char *value)
+static int git_apply_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "apply.whitespace")) {
 		apply_default_whitespace = xstrdup(value);
 		return 0;
 	}
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 
@@ -2729,7 +2729,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 
 	prefix = setup_git_directory_gently(&is_not_gitdir);
 	prefix_length = prefix ? strlen(prefix) : 0;
-	git_config(git_apply_config);
+	git_config(git_apply_config, NULL);
 	if (apply_default_whitespace)
 		parse_whitespace_option(apply_default_whitespace);
 
diff --git a/builtin-blame.c b/builtin-blame.c
index 35471fc..0fb76ee 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -1973,7 +1973,7 @@ static void prepare_blame_range(struct scoreboard *sb,
 		usage(blame_usage);
 }
 
-static int git_blame_config(const char *var, const char *value)
+static int git_blame_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "blame.showroot")) {
 		show_root = git_config_bool(var, value);
@@ -1983,7 +1983,7 @@ static int git_blame_config(const char *var, const char *value)
 		blank_boundary = git_config_bool(var, value);
 		return 0;
 	}
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static struct commit *fake_working_tree_commit(const char *path, const char *contents_from)
@@ -2136,7 +2136,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 
 	cmd_is_annotate = !strcmp(argv[0], "annotate");
 
-	git_config(git_blame_config);
+	git_config(git_blame_config, NULL);
 	save_commit_buffer = 0;
 
 	opt = 0;
diff --git a/builtin-branch.c b/builtin-branch.c
index 6bd5843..a0f4c23 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -55,7 +55,7 @@ static int parse_branch_color_slot(const char *var, int ofs)
 	die("bad config variable '%s'", var);
 }
 
-int git_branch_config(const char *var, const char *value)
+int git_branch_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "color.branch")) {
 		branch_use_color = git_config_colorbool(var, value);
@@ -69,7 +69,7 @@ int git_branch_config(const char *var, const char *value)
 	if (!strcmp(var, "branch.autosetupmerge"))
 		branch_track_remotes = git_config_bool(var, value);
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 const char *branch_get_color(enum color_branch ix)
@@ -356,7 +356,7 @@ static int get_remote_branch_name(const char *value)
 	return 0;
 }
 
-static int get_remote_config(const char *key, const char *value)
+static int get_remote_config(const char *key, const char *value, void *cb_data)
 {
 	const char *var;
 	if (prefixcmp(key, "remote."))
@@ -400,7 +400,7 @@ static void set_branch_defaults(const char *name, const char *real_ref)
 	start_ref = real_ref;
 	start_len = strlen(real_ref);
 	base_len = slash - real_ref;
-	git_config(get_remote_config);
+	git_config(get_remote_config, NULL);
 	if (!config_repo && !config_remote &&
 	    !prefixcmp(real_ref, "refs/heads/")) {
 		set_branch_merge(name, ".", real_ref);
@@ -538,7 +538,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	int kinds = REF_LOCAL_BRANCH;
 	int i;
 
-	git_config(git_branch_config);
+	git_config(git_branch_config, NULL);
 	track = branch_track_remotes;
 
 	for (i = 1; i < argc; i++) {
diff --git a/builtin-cat-file.c b/builtin-cat-file.c
index f132d58..b488fad 100644
--- a/builtin-cat-file.c
+++ b/builtin-cat-file.c
@@ -85,7 +85,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
 	int opt;
 	const char *exp_type, *obj_name;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	if (argc != 3)
 		usage("git-cat-file [-t|-s|-e|-p|<type>] <sha1>");
 	exp_type = argv[1];
diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c
index 8460f97..47a8b1b 100644
--- a/builtin-checkout-index.c
+++ b/builtin-checkout-index.c
@@ -168,7 +168,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
 	int read_from_stdin = 0;
 	int prefix_length;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	state.base_dir = "";
 	prefix_length = prefix ? strlen(prefix) : 0;
 
diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c
index ccbcbe3..3439321 100644
--- a/builtin-commit-tree.c
+++ b/builtin-commit-tree.c
@@ -92,7 +92,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 	unsigned int size;
 	int encoding_is_utf8;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	if (argc < 2)
 		usage(commit_tree_usage);
diff --git a/builtin-config.c b/builtin-config.c
index 7e18f73..7834e19 100644
--- a/builtin-config.c
+++ b/builtin-config.c
@@ -16,7 +16,7 @@ static int do_not_match;
 static int seen;
 static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
 
-static int show_all_config(const char *key_, const char *value_)
+static int show_all_config(const char *key_, const char *value_, void *cb_data)
 {
 	if (value_)
 		printf("%s=%s\n", key_, value_);
@@ -25,7 +25,7 @@ static int show_all_config(const char *key_, const char *value_)
 	return 0;
 }
 
-static int show_config(const char* key_, const char* value_)
+static int show_config(const char* key_, const char* value_, void *cb_data)
 {
 	char value[256];
 	const char *vptr = value;
@@ -107,17 +107,17 @@ static int get_value(const char* key_, const char* regex_)
 	}
 
 	if (dest)
-		git_config_from_remote(show_config, dest);
+		git_config_from_remote(show_config, dest, NULL);
 	else {
 		if (do_all && system_wide)
-			git_config_from_file(show_config, system_wide);
+			git_config_from_file(show_config, system_wide, NULL);
 		if (do_all && global)
-			git_config_from_file(show_config, global);
-		git_config_from_file(show_config, local);
+			git_config_from_file(show_config, global, NULL);
+		git_config_from_file(show_config, local, NULL);
 		if (!do_all && !seen && global)
-			git_config_from_file(show_config, global);
+			git_config_from_file(show_config, global, NULL);
 		if (!do_all && !seen && system_wide)
-			git_config_from_file(show_config, system_wide);
+			git_config_from_file(show_config, system_wide, NULL);
 	}
 
 	free(key);
@@ -149,9 +149,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 			type = T_BOOL;
 		else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
 			if (dest)
-				return git_config_from_remote(show_all_config, dest);
+				return git_config_from_remote(show_all_config,
+								dest, NULL);
 			else
-				return git_config(show_all_config);
+				return git_config(show_all_config, NULL);
 		}
 		else if (!strcmp(argv[1], "--global")) {
 			char *home = getenv("HOME");
diff --git a/builtin-diff-files.c b/builtin-diff-files.c
index 6cb30c8..017f4b9 100644
--- a/builtin-diff-files.c
+++ b/builtin-diff-files.c
@@ -21,7 +21,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
 
 	prefix = setup_git_directory_gently(&nongit);
 	init_revisions(&rev, prefix);
-	git_config(git_default_config); /* no "diff" UI options */
+	git_config(git_default_config, NULL); /* no "diff" UI options */
 	rev.abbrev = 0;
 
 	if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
diff --git a/builtin-diff-index.c b/builtin-diff-index.c
index d90eba9..6e92b78 100644
--- a/builtin-diff-index.c
+++ b/builtin-diff-index.c
@@ -17,7 +17,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
 	int result;
 
 	init_revisions(&rev, prefix);
-	git_config(git_default_config); /* no "diff" UI options */
+	git_config(git_default_config, NULL); /* no "diff" UI options */
 	rev.abbrev = 0;
 
 	argc = setup_revisions(argc, argv, &rev, NULL);
diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c
index 0b591c8..341edad 100644
--- a/builtin-diff-tree.c
+++ b/builtin-diff-tree.c
@@ -68,7 +68,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
 	int read_stdin = 0;
 
 	init_revisions(opt, prefix);
-	git_config(git_default_config); /* no "diff" UI options */
+	git_config(git_default_config, NULL); /* no "diff" UI options */
 	nr_sha1 = 0;
 	opt->abbrev = 0;
 	opt->diff = 1;
diff --git a/builtin-diff.c b/builtin-diff.c
index 7f367b6..906b698 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -220,7 +220,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 	 */
 
 	prefix = setup_git_directory_gently(&nongit);
-	git_config(git_diff_ui_config);
+	git_config(git_diff_ui_config, NULL);
 	init_revisions(&rev, prefix);
 
 	if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix))
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
index 5c145d2..a156548 100644
--- a/builtin-fmt-merge-msg.c
+++ b/builtin-fmt-merge-msg.c
@@ -10,7 +10,8 @@ static const char *fmt_merge_msg_usage =
 
 static int merge_summary;
 
-static int fmt_merge_msg_config(const char *key, const char *value)
+static int fmt_merge_msg_config(const char *key, const char *value,
+				void *cb_data)
 {
 	if (!strcmp("merge.summary", key))
 		merge_summary = git_config_bool(key, value);
@@ -251,7 +252,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 	unsigned char head_sha1[20];
 	const char *current_branch;
 
-	git_config(fmt_merge_msg_config);
+	git_config(fmt_merge_msg_config, NULL);
 
 	while (argc > 1) {
 		if (!strcmp(argv[1], "--summary"))
diff --git a/builtin-gc.c b/builtin-gc.c
index 8ea165a..164fe71 100644
--- a/builtin-gc.c
+++ b/builtin-gc.c
@@ -27,7 +27,7 @@ static const char *argv_repack[MAX_ADD] = {"repack", "-a", "-d", "-l", NULL};
 static const char *argv_prune[] = {"prune", NULL};
 static const char *argv_rerere[] = {"rerere", "gc", NULL};
 
-static int gc_config(const char *var, const char *value)
+static int gc_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "gc.packrefs")) {
 		if (!strcmp(value, "notbare"))
@@ -40,7 +40,7 @@ static int gc_config(const char *var, const char *value)
 		aggressive_window = git_config_int(var, value);
 		return 0;
 	}
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static void append_option(const char **cmd, const char *opt, int max_length)
@@ -62,7 +62,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
 	int prune = 0;
 	char buf[80];
 
-	git_config(gc_config);
+	git_config(gc_config, NULL);
 
 	if (pack_refs < 0)
 		pack_refs = !is_bare_repository();
diff --git a/builtin-init-db.c b/builtin-init-db.c
index 4df9fd0..11460b6 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -152,7 +152,7 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
 	strcpy(template_path + template_len, "config");
 	repository_format_version = 0;
 	git_config_from_file(check_repository_format_version,
-			     template_path);
+			     template_path, NULL);
 	template_path[template_len] = 0;
 
 	if (repository_format_version &&
@@ -207,7 +207,7 @@ static int create_default_files(const char *git_dir, const char *template_path)
 	path[len] = 0;
 	copy_templates(path, len, template_path);
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	/*
 	 * We would have created the above under user's umask -- under
diff --git a/builtin-log.c b/builtin-log.c
index 3744712..2581ce4 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -93,20 +93,20 @@ static int cmd_log_walk(struct rev_info *rev)
 	return 0;
 }
 
-static int git_log_config(const char *var, const char *value)
+static int git_log_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "log.showroot")) {
 		default_show_root = git_config_bool(var, value);
 		return 0;
 	}
-	return git_diff_ui_config(var, value);
+	return git_diff_ui_config(var, value, NULL);
 }
 
 int cmd_whatchanged(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info rev;
 
-	git_config(git_log_config);
+	git_config(git_log_config, NULL);
 	init_revisions(&rev, prefix);
 	rev.diff = 1;
 	rev.diffopt.recursive = 1;
@@ -155,7 +155,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 	struct object_array_entry *objects;
 	int i, count, ret = 0;
 
-	git_config(git_log_config);
+	git_config(git_log_config, NULL);
 	init_revisions(&rev, prefix);
 	rev.diff = 1;
 	rev.diffopt.recursive = 1;
@@ -220,7 +220,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info rev;
 
-	git_config(git_log_config);
+	git_config(git_log_config, NULL);
 	init_revisions(&rev, prefix);
 	init_reflog_walk(&rev.reflog_info);
 	rev.abbrev_commit = 1;
@@ -248,7 +248,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info rev;
 
-	git_config(git_log_config);
+	git_config(git_log_config, NULL);
 	init_revisions(&rev, prefix);
 	rev.always_show_header = 1;
 	cmd_log_init(argc, argv, prefix, &rev);
@@ -268,7 +268,7 @@ static char *extra_headers = NULL;
 static int extra_headers_size = 0;
 static const char *fmt_patch_suffix = ".patch";
 
-static int git_format_config(const char *var, const char *value)
+static int git_format_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "format.headers")) {
 		int len;
@@ -291,7 +291,7 @@ static int git_format_config(const char *var, const char *value)
 	if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
 		return 0;
 	}
-	return git_log_config(var, value);
+	return git_log_config(var, value, NULL);
 }
 
 
@@ -440,7 +440,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	char message_id[1024];
 	char ref_message_id[1024];
 
-	git_config(git_format_config);
+	git_config(git_format_config, NULL);
 	init_revisions(&rev, prefix);
 	rev.commit_format = CMIT_FMT_EMAIL;
 	rev.verbose_header = 1;
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index f7c066b..9bdadc4 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -347,7 +347,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
 	memset(&dir, 0, sizeof(dir));
 	if (prefix)
 		prefix_offset = strlen(prefix);
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c
index 1cb4dca..104e98f 100644
--- a/builtin-ls-tree.c
+++ b/builtin-ls-tree.c
@@ -108,7 +108,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
 	unsigned char sha1[20];
 	struct tree *tree;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	ls_tree_prefix = prefix;
 	if (prefix && *prefix)
 		chomp_prefix = strlen(prefix);
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index c95e477..82f7a6e 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -894,7 +894,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
 	/* NEEDSWORK: might want to do the optional .git/ directory
 	 * discovery
 	 */
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	def_charset = (git_commit_encoding ? git_commit_encoding : "utf-8");
 	metainfo_charset = def_charset;
diff --git a/builtin-merge-base.c b/builtin-merge-base.c
index e35d362..9f766c5 100644
--- a/builtin-merge-base.c
+++ b/builtin-merge-base.c
@@ -27,7 +27,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
 	unsigned char rev1key[20], rev2key[20];
 	int show_all = 0;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	while (1 < argc && argv[1][0] == '-') {
 		const char *arg = argv[1];
diff --git a/builtin-mv.c b/builtin-mv.c
index 3563216..7d01203 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -75,7 +75,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 	struct path_list deleted = {NULL, 0, 0, 0};
 	struct path_list changed = {NULL, 0, 0, 0};
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	newfd = hold_locked_index(&lock_file, 1);
 	if (read_cache() < 0)
diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index ef16385..988426c 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -151,7 +151,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 	int as_is = 0, all = 0, transform_stdin = 0;
 	struct name_ref_data data = { 0, NULL };
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	if (argc < 2)
 		usage(name_rev_usage);
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index d165f10..e6ce67a 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -1419,7 +1419,7 @@ static void prepare_pack(int window, int depth)
 	free(delta_list);
 }
 
-static int git_pack_config(const char *k, const char *v)
+static int git_pack_config(const char *k, const char *v, void *cb_data)
 {
 	if(!strcmp(k, "pack.window")) {
 		window = git_config_int(k, v);
@@ -1439,7 +1439,7 @@ static int git_pack_config(const char *k, const char *v)
 		pack_compression_seen = 1;
 		return 0;
 	}
-	return git_default_config(k, v);
+	return git_default_config(k, v, NULL);
 }
 
 static void read_object_list_from_stdin(void)
@@ -1549,7 +1549,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 	rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
 	rp_ac = 2;
 
-	git_config(git_pack_config);
+	git_config(git_pack_config, NULL);
 	if (!pack_compression_seen && core_compression_seen)
 		pack_compression_level = core_compression_level;
 
diff --git a/builtin-push.c b/builtin-push.c
index cb78401..a19be32 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -193,7 +193,7 @@ static int config_current_uri;
 static int config_get_refspecs;
 static int config_get_receivepack;
 
-static int get_remote_config(const char* key, const char* value)
+static int get_remote_config(const char* key, const char* value, void *cb_data)
 {
 	if (!prefixcmp(key, "remote.") &&
 	    !strncmp(key + 7, config_repo, config_repo_len)) {
@@ -230,7 +230,7 @@ static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI])
 	config_get_refspecs = !(refspec_nr || all || tags);
 	config_get_receivepack = (receivepack == NULL);
 
-	git_config(get_remote_config);
+	git_config(get_remote_config, NULL);
 	return config_current_uri;
 }
 
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index b9fcff7..cec2021 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -92,14 +92,15 @@ static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive
 static struct lock_file lock_file;
 static struct unpack_trees_options opts;
 
-static int git_read_tree_config(const char *var, const char *value)
+static int git_read_tree_config(const char *var, const char *value,
+				void *cb_data)
 {
 	if (!strcmp(var, "core.submodules")) {
 		opts.submodules = git_config_bool(var, value);
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
@@ -110,11 +111,11 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
 	opts.head_idx = -1;
 
 	setup_git_directory();
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	newfd = hold_locked_index(&lock_file, 1);
 
-	git_config(git_read_tree_config);
+	git_config(git_read_tree_config, NULL);
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
diff --git a/builtin-reflog.c b/builtin-reflog.c
index ce093ca..c616a0a 100644
--- a/builtin-reflog.c
+++ b/builtin-reflog.c
@@ -281,14 +281,15 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
 	return status;
 }
 
-static int reflog_expire_config(const char *var, const char *value)
+static int reflog_expire_config(const char *var, const char *value,
+				void *cb_data)
 {
 	if (!strcmp(var, "gc.reflogexpire"))
 		default_reflog_expire = approxidate(value);
 	else if (!strcmp(var, "gc.reflogexpireunreachable"))
 		default_reflog_expire_unreachable = approxidate(value);
 	else
-		return git_default_config(var, value);
+		return git_default_config(var, value, NULL);
 	return 0;
 }
 
@@ -298,7 +299,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
 	unsigned long now = time(NULL);
 	int i, status, do_all;
 
-	git_config(reflog_expire_config);
+	git_config(reflog_expire_config, NULL);
 
 	save_commit_buffer = 0;
 	do_all = status = 0;
diff --git a/builtin-rerere.c b/builtin-rerere.c
index 8c2c8bd..5d1fe12 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -380,14 +380,14 @@ tail_optimization:
 	return write_rr(rr, fd);
 }
 
-static int git_rerere_config(const char *var, const char *value)
+static int git_rerere_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "gc.rerereresolved"))
 		cutoff_resolve = git_config_int(var, value);
 	else if (!strcmp(var, "gc.rerereunresolved"))
 		cutoff_noresolve = git_config_int(var, value);
 	else
-		return git_default_config(var, value);
+		return git_default_config(var, value, NULL);
 	return 0;
 }
 
@@ -400,7 +400,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
 	if (stat(git_path("rr-cache"), &st) || !S_ISDIR(st.st_mode))
 		return 0;
 
-	git_config(git_rerere_config);
+	git_config(git_rerere_config, NULL);
 
 	merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR"));
 	fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index ebf53f5..8700d37 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -468,7 +468,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 	int read_from_stdin = 0;
 	int bisect_show_vars = 0;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	init_revisions(&revs, prefix);
 	revs.abbrev = 0;
 	revs.commit_format = CMIT_FMT_UNSPECIFIED;
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 37addb2..8e868c3 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -214,7 +214,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 	int i, as_is = 0, verify = 0;
 	unsigned char sha1[20];
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
diff --git a/builtin-revert.c b/builtin-revert.c
index ea2f15b..aa26c27 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -239,7 +239,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
 	const char *message, *encoding;
 	const char *defmsg = xstrdup(git_path("MERGE_MSG"));
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	me = action == REVERT ? "revert" : "cherry-pick";
 	setenv(GIT_REFLOG_ACTION, me, 0);
 	parse_options(argc, argv);
diff --git a/builtin-rm.c b/builtin-rm.c
index 4a0bd93..7f03735 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -109,7 +109,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
 	const char **pathspec;
 	char *seen;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	newfd = hold_locked_index(&lock_file, 1);
 
diff --git a/builtin-runstatus.c b/builtin-runstatus.c
index 4b489b1..d365d7d 100644
--- a/builtin-runstatus.c
+++ b/builtin-runstatus.c
@@ -11,7 +11,7 @@ int cmd_runstatus(int argc, const char **argv, const char *prefix)
 	struct wt_status s;
 	int i;
 
-	git_config(git_status_config);
+	git_config(git_status_config, NULL);
 	wt_status_prepare(&s);
 
 	for (i = 1; i < argc; i++) {
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index c892f1f..73565c8 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -531,7 +531,8 @@ static void append_one_rev(const char *av)
 	die("bad sha1 reference %s", av);
 }
 
-static int git_show_branch_config(const char *var, const char *value)
+static int git_show_branch_config(const char *var, const char *value,
+				  void *cb_data)
 {
 	if (!strcmp(var, "showbranch.default")) {
 		if (default_alloc <= default_num + 1) {
@@ -543,7 +544,7 @@ static int git_show_branch_config(const char *var, const char *value)
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -607,7 +608,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 	int reflog = 0;
 	const char *reflog_base = NULL;
 
-	git_config(git_show_branch_config);
+	git_config(git_show_branch_config, NULL);
 
 	/* If nothing is specified, try the default first */
 	if (ac == 1 && default_num) {
diff --git a/builtin-symbolic-ref.c b/builtin-symbolic-ref.c
index d41b406..114c473 100644
--- a/builtin-symbolic-ref.c
+++ b/builtin-symbolic-ref.c
@@ -27,7 +27,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 	int quiet = 0;
 	const char *msg = NULL;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	while (1 < argc) {
 		const char *arg = argv[1];
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index a6ff62f..73dd79f 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -341,7 +341,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
 	int i;
 	unsigned char sha1[20];
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	quiet = !isatty(2);
 
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 8f98991..023c2dc 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -570,7 +570,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 	int lock_error = 0;
 	struct lock_file *lock_file;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	/* We can't free this memory, it becomes part of a linked list parsed atexit() */
 	lock_file = xcalloc(1, sizeof(struct lock_file));
diff --git a/builtin-update-ref.c b/builtin-update-ref.c
index feac2ed..782d4aa 100644
--- a/builtin-update-ref.c
+++ b/builtin-update-ref.c
@@ -14,7 +14,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
 
 	delete = 0;
 	ref_flags = 0;
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	for (i = 1; i < argc; i++) {
 		if (!strcmp("-m", argv[i])) {
diff --git a/builtin-verify-pack.c b/builtin-verify-pack.c
index 4e31c27..8a59d14 100644
--- a/builtin-verify-pack.c
+++ b/builtin-verify-pack.c
@@ -55,7 +55,7 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix)
 	int no_more_options = 0;
 	int nothing_done = 1;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	while (1 < argc) {
 		if (!no_more_options && argv[1][0] == '-') {
 			if (!strcmp("-v", argv[1]))
diff --git a/cache.h b/cache.h
index 446030a..d56db20 100644
--- a/cache.h
+++ b/cache.h
@@ -499,17 +499,18 @@ extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigne
 /* Dumb servers support */
 extern int update_server_info(int);
 
-typedef int (*config_fn_t)(const char *, const char *);
-extern int git_default_config(const char *, const char *);
-extern int git_config_from_file(config_fn_t fn, const char *);
-extern int git_config_from_remote(config_fn_t fn, char *dest);
-extern int git_config(config_fn_t fn);
+typedef int (*config_fn_t)(const char *, const char *, void *cb_data);
+extern int git_default_config(const char *, const char *, void *cb_data);
+extern int git_config_from_file(config_fn_t fn, const char *, void *cb_data);
+extern int git_config_from_remote(config_fn_t fn, char *dest, void *cb_data);
+extern int git_config(config_fn_t fn, void *cb_data);
 extern int git_config_int(const char *, const char *);
 extern int git_config_bool(const char *, const char *);
 extern int git_config_set(const char *, const char *);
 extern int git_config_set_multivar(const char *, const char *, const char *, int);
 extern int git_config_rename_section(const char *, const char *);
-extern int check_repository_format_version(const char *var, const char *value);
+extern int check_repository_format_version(const char *var, const char *value,
+					   void *cb_data);
 
 #define MAX_GITNAME (1000)
 extern char git_default_email[MAX_GITNAME];
diff --git a/config.c b/config.c
index fc2162b..cab6f29 100644
--- a/config.c
+++ b/config.c
@@ -113,7 +113,7 @@ static inline int iskeychar(int c)
 	return isalnum(c) || c == '-';
 }
 
-static int get_value(config_fn_t fn, char *name, unsigned int len)
+static int get_value(config_fn_t fn, char *name, unsigned int len, void *cb_data)
 {
 	int c;
 	char *value;
@@ -141,7 +141,7 @@ static int get_value(config_fn_t fn, char *name, unsigned int len)
 		if (!value)
 			return -1;
 	}
-	return fn(name, value);
+	return fn(name, value, cb_data);
 }
 
 static int get_extended_base_var(char *name, int baselen, int c)
@@ -199,7 +199,7 @@ static int get_base_var(char *name)
 	}
 }
 
-static int git_parse_file(config_fn_t fn)
+static int git_parse_file(config_fn_t fn, void *cb_data)
 {
 	int comment = 0;
 	int baselen = 0;
@@ -231,7 +231,7 @@ static int git_parse_file(config_fn_t fn)
 		if (!isalpha(c))
 			break;
 		var[baselen] = tolower(c);
-		if (get_value(fn, var, baselen+1) < 0)
+		if (get_value(fn, var, baselen+1, cb_data) < 0)
 			break;
 	}
 	die("bad config file line %d in %s", config_linenr, config_file_name);
@@ -267,7 +267,7 @@ int git_config_bool(const char *name, const char *value)
 	return git_config_int(name, value) != 0;
 }
 
-int git_default_config(const char *var, const char *value)
+int git_default_config(const char *var, const char *value, void *cb_data)
 {
 	/* This needs a better name */
 	if (!strcmp(var, "core.filemode")) {
@@ -390,7 +390,7 @@ int git_default_config(const char *var, const char *value)
 	return 0;
 }
 
-int git_config_from_file(config_fn_t fn, const char *filename)
+int git_config_from_file(config_fn_t fn, const char *filename, void *cb_data)
 {
 	int ret;
 	FILE *f = fopen(filename, "r");
@@ -400,24 +400,24 @@ int git_config_from_file(config_fn_t fn, const char *filename)
 		config_file = f;
 		config_file_name = filename;
 		config_linenr = 1;
-		ret = git_parse_file(fn);
+		ret = git_parse_file(fn, cb_data);
 		fclose(f);
 		config_file_name = NULL;
 	}
 	return ret;
 }
 
-static int config_from_http(config_fn_t fn, char *dest)
+static int config_from_http(config_fn_t fn, char *dest, void *cb_data)
 {
 	char config_temp[50];
 	if (git_http_fetch_config(dest, config_temp, sizeof(config_temp)))
 		return 1;
-	git_config_from_file(fn, config_temp);
+	git_config_from_file(fn, config_temp, cb_data);
 	unlink(config_temp);
 	return 0;
 }
 
-int git_config_from_remote(config_fn_t fn, char *dest)
+int git_config_from_remote(config_fn_t fn, char *dest, void *cb_data)
 {
 	int ret;
 	int fd[2];
@@ -426,7 +426,7 @@ int git_config_from_remote(config_fn_t fn, char *dest)
 	static char value[1024];
 
 	if (!prefixcmp(dest, "http://"))
-		return config_from_http(fn, dest);
+		return config_from_http(fn, dest, cb_data);
 
 	pid = git_connect(fd, dest, dumpconfig, 0);
 	if (pid < 0)
@@ -435,7 +435,7 @@ int git_config_from_remote(config_fn_t fn, char *dest)
 	while (packet_read_line(fd[0], var, sizeof(var))) {
 		if (!packet_read_line(fd[0], value, sizeof(value)))
 			die("Missing value");
-		fn(var, value);
+		fn(var, value, cb_data);
 	}
 	close(fd[0]);
 	close(fd[1]);
@@ -443,7 +443,7 @@ int git_config_from_remote(config_fn_t fn, char *dest)
 	return !!ret;
 }
 
-int git_config(config_fn_t fn)
+int git_config(config_fn_t fn, void *cb_data)
 {
 	int ret = 0;
 	char *repo_config = NULL;
@@ -456,7 +456,7 @@ int git_config(config_fn_t fn)
 	filename = getenv(CONFIG_ENVIRONMENT);
 	if (!filename) {
 		if (!access(ETC_GITCONFIG, R_OK))
-			ret += git_config_from_file(fn, ETC_GITCONFIG);
+			ret += git_config_from_file(fn, ETC_GITCONFIG, cb_data);
 		home = getenv("HOME");
 		filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
 		if (!filename)
@@ -466,11 +466,11 @@ int git_config(config_fn_t fn)
 	if (home) {
 		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 		if (!access(user_config, R_OK))
-			ret = git_config_from_file(fn, user_config);
+			ret = git_config_from_file(fn, user_config, cb_data);
 		free(user_config);
 	}
 
-	ret += git_config_from_file(fn, filename);
+	ret += git_config_from_file(fn, filename, cb_data);
 	free(repo_config);
 	return ret;
 }
@@ -500,7 +500,7 @@ static int matches(const char* key, const char* value)
 		  !regexec(store.value_regex, value, 0, NULL, 0)));
 }
 
-static int store_aux(const char* key, const char* value)
+static int store_aux(const char* key, const char* value, void *cb_data)
 {
 	const char *ep;
 	size_t section_len;
@@ -836,7 +836,7 @@ int git_config_set_multivar(const char* key, const char* value,
 		 * As a side effect, we make sure to transform only a valid
 		 * existing config file.
 		 */
-		if (git_config_from_file(store_aux, config_filename)) {
+		if (git_config_from_file(store_aux, config_filename, NULL)) {
 			fprintf(stderr, "invalid config file\n");
 			free(store.key);
 			if (store.value_regex != NULL) {
diff --git a/connect.c b/connect.c
index 2a26fdb..08cfac0 100644
--- a/connect.c
+++ b/connect.c
@@ -558,7 +558,8 @@ static char *git_proxy_command;
 static const char *rhost_name;
 static int rhost_len;
 
-static int git_proxy_command_options(const char *var, const char *value)
+static int git_proxy_command_options(const char *var, const char *value,
+				     void *cb_data)
 {
 	if (!strcmp(var, "core.gitproxy")) {
 		const char *for_pos;
@@ -602,7 +603,7 @@ static int git_proxy_command_options(const char *var, const char *value)
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static int git_use_proxy(const char *host)
@@ -610,7 +611,7 @@ static int git_use_proxy(const char *host)
 	rhost_name = host;
 	rhost_len = strlen(host);
 	git_proxy_command = getenv("GIT_PROXY_COMMAND");
-	git_config(git_proxy_command_options);
+	git_config(git_proxy_command_options, NULL);
 	rhost_name = NULL;
 	return (git_proxy_command && *git_proxy_command);
 }
diff --git a/convert.c b/convert.c
index 4b26b1a..6dde5fa 100644
--- a/convert.c
+++ b/convert.c
@@ -335,7 +335,8 @@ static struct convert_driver {
 	char *clean;
 } *user_convert, **user_convert_tail;
 
-static int read_convert_config(const char *var, const char *value)
+static int read_convert_config(const char *var, const char *value,
+				void *cb_data)
 {
 	const char *ep, *name;
 	int namelen;
@@ -402,7 +403,7 @@ static void setup_convert_check(struct git_attr_check *check)
 		attr_ident = git_attr("ident", 5);
 		attr_filter = git_attr("filter", 6);
 		user_convert_tail = &user_convert;
-		git_config(read_convert_config);
+		git_config(read_convert_config, NULL);
 	}
 	check[0].attr = attr_crlf;
 	check[1].attr = attr_ident;
diff --git a/daemon.c b/daemon.c
index 3e5ebf3..2d6302f 100644
--- a/daemon.c
+++ b/daemon.c
@@ -284,7 +284,7 @@ struct daemon_service {
 static struct daemon_service *service_looking_at;
 static int service_enabled;
 
-static int git_daemon_config(const char *var, const char *value)
+static int git_daemon_config(const char *var, const char *value, void *cb_data)
 {
 	if (!prefixcmp(var, "daemon.") &&
 	    !strcmp(var + 7, service_looking_at->config_name)) {
@@ -334,7 +334,7 @@ static int run_service(struct interp *itable, struct daemon_service *service)
 	if (service->overridable) {
 		service_looking_at = service;
 		service_enabled = -1;
-		git_config(git_daemon_config);
+		git_config(git_daemon_config, NULL);
 		if (0 <= service_enabled)
 			enabled = service_enabled;
 	}
diff --git a/diff.c b/diff.c
index 33297aa..8edfcc5 100644
--- a/diff.c
+++ b/diff.c
@@ -99,7 +99,7 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
  * never be affected by the setting of diff.renames
  * the user happens to have in the configuration file.
  */
-int git_diff_ui_config(const char *var, const char *value)
+int git_diff_ui_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp(var, "diff.renamelimit")) {
 		diff_rename_limit_default = git_config_int(var, value);
@@ -131,7 +131,7 @@ int git_diff_ui_config(const char *var, const char *value)
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static char *quote_one(const char *str)
@@ -1762,7 +1762,7 @@ static const char *external_diff_attr(const char *name)
 
 			if (!user_diff_tail) {
 				user_diff_tail = &user_diff;
-				git_config(git_diff_ui_config);
+				git_config(git_diff_ui_config, NULL);
 			}
 			for (drv = user_diff; drv; drv = drv->next)
 				if (!strcmp(drv->name, value))
diff --git a/diff.h b/diff.h
index 63738c1..a715dff 100644
--- a/diff.h
+++ b/diff.h
@@ -161,7 +161,7 @@ extern int diff_scoreopt_parse(const char *opt);
 #define DIFF_SETUP_USE_CACHE		2
 #define DIFF_SETUP_USE_SIZE_CACHE	4
 
-extern int git_diff_ui_config(const char *var, const char *value);
+extern int git_diff_ui_config(const char *var, const char *value, void *cb_data);
 extern void diff_setup(struct diff_options *);
 extern int diff_opt_parse(struct diff_options *, const char **, int);
 extern int diff_setup_done(struct diff_options *);
diff --git a/dump-config.c b/dump-config.c
index 355920d..99dbeb6 100644
--- a/dump-config.c
+++ b/dump-config.c
@@ -4,7 +4,7 @@
 
 static const char dump_config_usage[] = "git-dump-config <dir>";
 
-static int dump_config(const char *var, const char *value)
+static int dump_config(const char *var, const char *value, void *cb_data)
 {
 	packet_write(1, "%s", var);
 	packet_write(1, "%s", value);
@@ -22,7 +22,7 @@ int main(int argc, char **argv)
 	if (!enter_repo(dir, 0))
 		die("'%s': unable to chdir or not a git archive", dir);
 
-	git_config(dump_config);
+	git_config(dump_config, NULL);
 	packet_flush(1);
 
 	return 0;
diff --git a/fast-import.c b/fast-import.c
index ffa00fd..599d045 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -2009,7 +2009,7 @@ int main(int argc, const char **argv)
 {
 	int i, show_stats = 1;
 
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	alloc_objects(object_entry_alloc);
 	strbuf_init(&command_buf);
 	atom_table = xcalloc(atom_table_sz, sizeof(struct atom_str*));
diff --git a/fetch-pack.c b/fetch-pack.c
index aa59043..c7d24fe 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -646,7 +646,7 @@ static int remove_duplicates(int nr_heads, char **heads)
 	return dst;
 }
 
-static int fetch_pack_config(const char *var, const char *value)
+static int fetch_pack_config(const char *var, const char *value, void *cb_data)
 {
 	if (strcmp(var, "fetch.unpacklimit") == 0) {
 		fetch_unpack_limit = git_config_int(var, value);
@@ -658,7 +658,7 @@ static int fetch_pack_config(const char *var, const char *value)
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static struct lock_file lock;
@@ -672,7 +672,7 @@ int main(int argc, char **argv)
 	struct stat st;
 
 	setup_git_directory();
-	git_config(fetch_pack_config);
+	git_config(fetch_pack_config, NULL);
 
 	if (0 <= transfer_unpack_limit)
 		unpack_limit = transfer_unpack_limit;
diff --git a/git.c b/git.c
index f200907..bbe09d5 100644
--- a/git.c
+++ b/git.c
@@ -87,7 +87,7 @@ static int handle_options(const char*** argv, int* argc)
 static const char *alias_command;
 static char *alias_string;
 
-static int git_alias_config(const char *var, const char *value)
+static int git_alias_config(const char *var, const char *value, void *cb_data)
 {
 	if (!prefixcmp(var, "alias.") && !strcmp(var + 6, alias_command)) {
 		alias_string = xstrdup(value);
@@ -158,7 +158,7 @@ static int handle_alias(int *argcp, const char ***argv)
 	subdir = setup_git_directory_gently(&nongit);
 
 	alias_command = (*argv)[0];
-	git_config(git_alias_config);
+	git_config(git_alias_config, NULL);
 	if (alias_string) {
 		if (alias_string[0] == '!') {
 			trace_printf("trace: alias to shell cmd: %s => %s\n",
diff --git a/http-fetch.c b/http-fetch.c
index 53fb2a9..bc87d4b 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -996,7 +996,7 @@ int main(int argc, const char **argv)
 	int rc = 0;
 
 	setup_git_directory();
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	while (arg < argc && argv[arg][0] == '-') {
 		if (argv[arg][1] == 't') {
diff --git a/http.c b/http.c
index c8237cb..fd359bf 100644
--- a/http.c
+++ b/http.c
@@ -97,7 +97,7 @@ static void process_curl_messages(void)
 }
 #endif
 
-static int http_options(const char *var, const char *value)
+static int http_options(const char *var, const char *value, void *cb_data)
 {
 	if (!strcmp("http.sslverify", var)) {
 		if (curl_ssl_verify == -1) {
@@ -164,7 +164,7 @@ static int http_options(const char *var, const char *value)
 	}
 
 	/* Fall back on the default ones */
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static CURL* get_curl_handle(void)
@@ -252,7 +252,7 @@ void http_init(void)
 	if (low_speed_time != NULL)
 		curl_low_speed_time = strtol(low_speed_time, NULL, 10);
 
-	git_config(http_options);
+	git_config(http_options, NULL);
 
 	if (curl_ssl_verify == -1)
 		curl_ssl_verify = 1;
diff --git a/imap-send.c b/imap-send.c
index 4283a4a..129776c 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1255,7 +1255,7 @@ static imap_server_conf_t server =
 static char *imap_folder;
 
 static int
-git_imap_config(const char *key, const char *val)
+git_imap_config(const char *key, const char *val, void *cb_data)
 {
 	char imap_key[] = "imap.";
 
@@ -1300,7 +1300,7 @@ main(int argc, char **argv)
 	/* init the random number generator */
 	arc4_init();
 
-	git_config( git_imap_config );
+	git_config(git_imap_config, NULL);
 
 	if (!imap_folder) {
 		fprintf( stderr, "no imap store specified\n" );
diff --git a/local-fetch.c b/local-fetch.c
index 4b650ef..23d2cbe 100644
--- a/local-fetch.c
+++ b/local-fetch.c
@@ -204,7 +204,7 @@ int main(int argc, const char **argv)
 	int arg = 1;
 
 	setup_git_directory();
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	while (arg < argc && argv[arg][0] == '-') {
 		if (argv[arg][1] == 't')
diff --git a/merge-recursive.c b/merge-recursive.c
index 8f72b2c..f774342 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -851,7 +851,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
 static struct ll_merge_driver *ll_user_merge, **ll_user_merge_tail;
 static const char *default_ll_merge;
 
-static int read_merge_config(const char *var, const char *value)
+static int read_merge_config(const char *var, const char *value, void *cb_data)
 {
 	struct ll_merge_driver *fn;
 	const char *ep, *name;
@@ -940,7 +940,7 @@ static void initialize_ll_merge(void)
 	if (ll_user_merge_tail)
 		return;
 	ll_user_merge_tail = &ll_user_merge;
-	git_config(read_merge_config);
+	git_config(read_merge_config, NULL);
 }
 
 static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr)
@@ -1696,13 +1696,13 @@ static struct commit *get_ref(const char *ref)
 	return (struct commit *)object;
 }
 
-static int merge_config(const char *var, const char *value)
+static int merge_config(const char *var, const char *value, void *cb_data)
 {
 	if (!strcasecmp(var, "merge.verbosity")) {
 		verbosity = git_config_int(var, value);
 		return 0;
 	}
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 int main(int argc, char *argv[])
@@ -1723,7 +1723,7 @@ int main(int argc, char *argv[])
 			subtree_merge = 1;
 	}
 
-	git_config(merge_config);
+	git_config(merge_config, NULL);
 	if (getenv("GIT_MERGE_VERBOSITY"))
 		verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10);
 
diff --git a/receive-pack.c b/receive-pack.c
index d3c422b..feab9a4 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -18,7 +18,7 @@ static int report_status;
 static char capabilities[] = " report-status delete-refs ";
 static int capabilities_sent;
 
-static int receive_pack_config(const char *var, const char *value)
+static int receive_pack_config(const char *var, const char *value, void *cb_data)
 {
 	if (strcmp(var, "receive.denynonfastforwards") == 0) {
 		deny_non_fast_forwards = git_config_bool(var, value);
@@ -35,7 +35,7 @@ static int receive_pack_config(const char *var, const char *value)
 		return 0;
 	}
 
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
@@ -484,7 +484,7 @@ int main(int argc, char **argv)
 	if (is_repository_shallow())
 		die("attempt to push into a shallow repository");
 
-	git_config(receive_pack_config);
+	git_config(receive_pack_config, NULL);
 
 	if (0 <= transfer_unpack_limit)
 		unpack_limit = transfer_unpack_limit;
diff --git a/send-pack.c b/send-pack.c
index 83ee87d..7895520 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -346,7 +346,7 @@ int main(int argc, char **argv)
 	pid_t pid;
 
 	setup_git_directory();
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	argv++;
 	for (i = 1; i < argc; i++, argv++) {
diff --git a/setup.c b/setup.c
index a45ea83..d3487aa 100644
--- a/setup.c
+++ b/setup.c
@@ -270,7 +270,8 @@ int git_config_perm(const char *var, const char *value)
 	return git_config_bool(var, value);
 }
 
-int check_repository_format_version(const char *var, const char *value)
+int check_repository_format_version(const char *var, const char *value,
+				    void *cb_data)
 {
        if (strcmp(var, "core.repositoryformatversion") == 0)
                repository_format_version = git_config_int(var, value);
@@ -281,7 +282,7 @@ int check_repository_format_version(const char *var, const char *value)
 
 int check_repository_format(void)
 {
-	git_config(check_repository_format_version);
+	git_config(check_repository_format_version, NULL);
 	if (GIT_REPO_VERSION < repository_format_version)
 		die ("Expected git repo version <= %d, found %d",
 		     GIT_REPO_VERSION, repository_format_version);
diff --git a/ssh-fetch.c b/ssh-fetch.c
index bdf51a7..ceb8b7d 100644
--- a/ssh-fetch.c
+++ b/ssh-fetch.c
@@ -125,7 +125,7 @@ int main(int argc, char **argv)
 	if (!prog) prog = "git-ssh-upload";
 
 	setup_git_directory();
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	while (arg < argc && argv[arg][0] == '-') {
 		if (argv[arg][1] == 't') {
diff --git a/unpack-file.c b/unpack-file.c
index 25c56b3..ade9926 100644
--- a/unpack-file.c
+++ b/unpack-file.c
@@ -33,7 +33,7 @@ int main(int argc, char **argv)
 		die("Not a valid object name %s", argv[1]);
 
 	setup_git_directory();
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 
 	puts(create_temp_file(sha1));
 	return 0;
diff --git a/var.c b/var.c
index e585e59..8ec0fdd 100644
--- a/var.c
+++ b/var.c
@@ -39,13 +39,13 @@ static const char *read_var(const char *var)
 	return val;
 }
 
-static int show_config(const char *var, const char *value)
+static int show_config(const char *var, const char *value, void *cb_data)
 {
 	if (value)
 		printf("%s=%s\n", var, value);
 	else
 		printf("%s\n", var);
-	return git_default_config(var, value);
+	return git_default_config(var, value, NULL);
 }
 
 int main(int argc, char **argv)
@@ -59,11 +59,11 @@ int main(int argc, char **argv)
 	val = NULL;
 
 	if (strcmp(argv[1], "-l") == 0) {
-		git_config(show_config);
+		git_config(show_config, NULL);
 		list_vars();
 		return 0;
 	}
-	git_config(git_default_config);
+	git_config(git_default_config, NULL);
 	val = read_var(argv[1]);
 	if (!val)
 		usage(var_usage);
diff --git a/wt-status.c b/wt-status.c
index a055990..6e40870 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -346,7 +346,7 @@ void wt_status_print(struct wt_status *s)
 	}
 }
 
-int git_status_config(const char *k, const char *v)
+int git_status_config(const char *k, const char *v, void *cb_data)
 {
 	if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
 		wt_status_use_color = git_config_colorbool(k, v);
@@ -356,5 +356,5 @@ int git_status_config(const char *k, const char *v)
 		int slot = parse_status_slot(k, 13);
 		color_parse(v, k, wt_status_colors[slot]);
 	}
-	return git_default_config(k, v);
+	return git_default_config(k, v, NULL);
 }
diff --git a/wt-status.h b/wt-status.h
index cfea4ae..242e9c5 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -21,7 +21,7 @@ struct wt_status {
 	int workdir_untracked;
 };
 
-int git_status_config(const char *var, const char *value);
+int git_status_config(const char *var, const char *value, void *cb_data);
 void wt_status_prepare(struct wt_status *s);
 void wt_status_print(struct wt_status *s);
 
-- 
1.5.2.rc3.815.g8fc2

^ permalink raw reply related

* [PATCH 13/15] unpack-trees.c: optionally clone submodules for later checkout
From: skimo @ 2007-05-20 18:04 UTC (permalink / raw)
  To: git, Junio C Hamano
In-Reply-To: <11796842882917-git-send-email-skimo@liacs.nl>

From: Sven Verdoolaege <skimo@kotnet.org>

When the --submodules option is specified and a submodule
to be checked out is not available locally, git-checkout will
search for submodule.<submodule>.url options in the remote
configuration and clone each submodule using the first url that
it can use from the local site.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
---
 Documentation/config.txt |    3 +
 Makefile                 |    5 +-
 submodules.c             |  209 ++++++++++++++++++++++++++++++++++++++++++++++
 submodules.h             |    6 ++
 unpack-trees.c           |   51 +++++++++++
 5 files changed, 272 insertions(+), 2 deletions(-)
 create mode 100644 submodules.c
 create mode 100644 submodules.h

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5d891ac..cee9e40 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -610,6 +610,9 @@ showbranch.default::
 	The default set of branches for gitlink:git-show-branch[1].
 	See gitlink:git-show-branch[1].
 
+submodule.<submodule>.url
+	The URL of a submodule.  See gitlink:git-clone[1].
+
 tar.umask::
 	By default, gitlink:git-tar-tree[1] sets file and directories modes
 	to 0666 or 0777. While this is both useful and acceptable for projects
diff --git a/Makefile b/Makefile
index bce8514..c79e636 100644
--- a/Makefile
+++ b/Makefile
@@ -297,7 +297,8 @@ LIB_H = \
 	diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
 	run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
 	tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
-	utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h mailmap.h
+	utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h mailmap.h \
+	submodules.h
 
 DIFF_OBJS = \
 	diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -320,7 +321,7 @@ LIB_OBJS = \
 	alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
 	color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
 	convert.o attr.o decorate.o progress.o mailmap.o symlinks.o \
-	$(HTTP_CONFIG_OBJ)
+	$(HTTP_CONFIG_OBJ) submodules.o
 
 BUILTIN_OBJS = \
 	builtin-add.o \
diff --git a/submodules.c b/submodules.c
new file mode 100644
index 0000000..5035a05
--- /dev/null
+++ b/submodules.c
@@ -0,0 +1,209 @@
+#include "cache.h"
+#include "submodules.h"
+#include "run-command.h"
+
+struct key_val_list {
+	struct key_val_list *next;
+	char *key;
+	char *val;
+};
+
+static void free_key_val_list(struct key_val_list *list)
+{
+	struct key_val_list *next;
+	for (; list; list = next) {
+		next = list->next;
+		free(list->key);
+		free(list->val);
+		free(list);
+	}
+}
+
+static struct key_val_list *find_key_val_list(struct key_val_list *list,
+						const char *key)
+{
+	while (list && strcmp(list->key, key))
+		list = list->next;
+	return list;
+}
+
+struct collect_urls_data {
+	struct key_val_list **next;
+
+	const char *type;
+};
+
+static int collect_urls(const char *var, const char *value, void *cb_data)
+{
+	struct collect_urls_data *cb = (struct collect_urls_data*)cb_data;
+	int typelen = strlen(cb->type);
+	int len;
+	char *doturl;
+	struct key_val_list *item;
+
+	if (prefixcmp(var, cb->type))
+		return 0;
+
+	if (var[typelen] != '.')
+		return 0;
+
+	var += typelen+1;
+
+	doturl = strrchr(var, '.');
+	if (!doturl || strcmp(doturl, ".url"))
+		return 0;
+
+	len = doturl-var;
+	if (len <= 0)
+		return 0;
+
+	item = xmalloc(sizeof(struct key_val_list));
+	item->key = xmalloc(len+1);
+	memcpy(item->key, var, len);
+	item->key[len] = 0;
+	item->val = xstrdup(value);
+	item->next = NULL;
+	*cb->next = item;
+	cb->next = &item->next;
+
+	return 0;
+}
+
+static const char *local_URL(const char *remote, const char *url)
+{
+	static char local_url[PATH_MAX];
+
+	if (!prefixcmp(url, "https://"))
+		return url;
+
+	if (!prefixcmp(url, "http://"))
+		return url;
+
+	if (!prefixcmp(url, "ftp://"))
+		return url;
+
+	if (!prefixcmp(remote, "/"))
+		return url;
+
+	if (!prefixcmp(remote, "ssh://") && !prefixcmp(url, "/")) {
+		char *slash;
+		int len = strlen(url);
+
+		slash = strchr(remote+6, '/');
+		if (!slash || (slash-remote)+len+1 > sizeof(local_url))
+			return NULL;
+		memcpy(local_url, remote, slash-remote);
+		memcpy(local_url+(slash-remote), url, len+1);
+		return local_url;
+	}
+
+	return NULL;
+}
+
+static int fetch_submodule_urls(struct key_val_list **next_url)
+{
+	struct key_val_list *remotes = NULL;
+	struct collect_urls_data remotes_data = { &remotes, "remote" };
+	struct key_val_list *remote;
+	static char key[1024];
+
+	git_config(collect_urls, &remotes_data);
+	for (remote = remotes; remote; remote = remote->next) {
+		struct key_val_list *submodules = NULL;
+		struct collect_urls_data submodules_data =
+			{ &submodules, "submodule" };
+		struct key_val_list *submodule;
+		char *dest;
+
+		dest = xstrdup(remote->val);
+		git_config_from_remote(collect_urls, dest, &submodules_data);
+		free(dest);
+		for (submodule = submodules; submodule; submodule = submodule->next) {
+			const char *local_url;
+			struct key_val_list *item;
+
+			local_url = local_URL(remote->val, submodule->val);
+			if (!local_url)
+				continue;
+
+			if (snprintf(key, sizeof(key),
+			    "submodule.%s.url", submodule->key) > sizeof(key))
+				return error("submodule name too long");
+
+			git_config_set(key, local_url);
+
+			item = xmalloc(sizeof(struct key_val_list));
+			item->key = xstrdup(submodule->key);
+			item->val = xstrdup(local_url);
+			item->next = NULL;
+			*next_url = item;
+			next_url = &item->next;
+		}
+
+		free_key_val_list(submodules);
+	}
+
+	free_key_val_list(remotes);
+
+	return 0;
+}
+
+int clone_submodule(const char *submodule)
+{
+	struct key_val_list *submodules = NULL;
+	struct collect_urls_data submodules_data = { &submodules, "submodule" };
+	struct key_val_list *item;
+	char *path;
+	int err;
+	const char *gitdirenv;
+	const char *args[10];
+	int argc;
+
+	git_config(collect_urls, &submodules_data);
+	item = find_key_val_list(submodules, submodule);
+	if (!item) {
+		err = fetch_submodule_urls(submodules_data.next);
+		if (err)
+			return err;
+		item = find_key_val_list(*submodules_data.next, submodule);
+		if (!item)
+			return error("don't know where to get submodule '%s'",
+					submodule);
+	}
+
+	path = git_path("submodules/%s", submodule);
+
+	argc = 0;
+	args[argc++] = "clone";
+	args[argc++] = "--submodules";
+	args[argc++] = "-n";
+	args[argc++] = item->val;
+	args[argc++] = path;
+	args[argc] = NULL;
+
+	gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+	unsetenv(GIT_DIR_ENVIRONMENT);
+	err = run_command_v_opt(args, RUN_GIT_CMD);
+
+	setenv(GIT_DIR_ENVIRONMENT,
+		git_path("submodules/%s/.git", submodule), 1);
+
+	argc = 0;
+	args[argc++] = "update-ref";
+	args[argc++] = "--no-deref";
+	args[argc++] = "HEAD";
+	args[argc++] = "0000000000000000000000000000000000000000";
+	args[argc] = NULL;
+
+	if (!err)
+		err = run_command_v_opt(args, RUN_GIT_CMD);
+
+	setenv(GIT_DIR_ENVIRONMENT, gitdirenv, 1);
+
+	if (err)
+		return error("failed to clone submodule '%s'", submodule);
+
+	free_key_val_list(submodules);
+
+	return 0;
+}
diff --git a/submodules.h b/submodules.h
new file mode 100644
index 0000000..56590e7
--- /dev/null
+++ b/submodules.h
@@ -0,0 +1,6 @@
+#ifndef SUBMODULES_H
+#define SUBMODULES_H
+
+int clone_submodule(const char *submodule);
+
+#endif
diff --git a/unpack-trees.c b/unpack-trees.c
index 3dadebb..f9865b9 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -6,6 +6,7 @@
 #include "unpack-trees.h"
 #include "progress.h"
 #include "refs.h"
+#include "submodules.h"
 
 #define DBRT_DEBUG 1
 
@@ -808,6 +809,36 @@ int threeway_merge(struct cache_entry **stages,
 	return count;
 }
 
+static int ensure_submodule(struct cache_entry *ce,
+			    struct unpack_trees_options *o)
+{
+	struct stat st;
+	char *path;
+
+	if (!ce)
+		return 0;
+
+	if (!S_ISDIRLNK(ntohl(ce->ce_mode)))
+		return 0;
+
+	path = mkpath("%s/.git", ce->name);
+	fprintf(stderr, "path: %s\n", path);
+	if (lstat(path, &st)) {
+		path = git_path("submodules/%s/.git", ce->name);
+		fprintf(stderr, "path: %s\n", path);
+		if (lstat(path, &st)) {
+			int err;
+			err = clone_submodule(ce->name);
+			if (err)
+				return err;
+		}
+	}
+
+	/* Now check that the commit is available and fetch if needed */
+
+	return 0;
+}
+
 /*
  * Two-way merge.
  *
@@ -833,6 +864,17 @@ int twoway_merge(struct cache_entry **src,
 	if (newtree == o->df_conflict_entry)
 		newtree = NULL;
 
+	if (o->submodules && o->update) {
+		int err;
+		err = ensure_submodule(current, o);
+		if (!err)
+			err = ensure_submodule(oldtree, o);
+		if (!err)
+			err = ensure_submodule(newtree, o);
+		if (err)
+			return err;
+	}
+
 	if (current) {
 		if ((!oldtree && !newtree) || /* 4 and 5 */
 		    (!oldtree && newtree &&
@@ -909,6 +951,15 @@ int oneway_merge(struct cache_entry **src,
 		return error("Cannot do a oneway merge of %d trees",
 			     o->merge_size);
 
+	if (o->submodules && o->update) {
+		int err;
+		err = ensure_submodule(old, o);
+		if (!err)
+			err = ensure_submodule(a, o);
+		if (err)
+			return err;
+	}
+
 	if (!a)
 		return deleted_entry(old, old, o);
 	if (old && same(old, a)) {
-- 
1.5.2.rc3.815.g8fc2

^ permalink raw reply related

* [PATCH 07/15] unpack-trees.c: assume submodules are clean
From: skimo @ 2007-05-20 18:04 UTC (permalink / raw)
  To: git, Junio C Hamano
In-Reply-To: <11796842882917-git-send-email-skimo@liacs.nl>

From: Sven Verdoolaege <skimo@kotnet.org>

If the submodules are not clean, then we will get an error
when we actally do the checkout.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
---
 unpack-trees.c |   43 ++++++++++++++++++++++++++++++++++---------
 1 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/unpack-trees.c b/unpack-trees.c
index 4497a46..f3fe2dd 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -5,6 +5,7 @@
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "progress.h"
+#include "refs.h"
 
 #define DBRT_DEBUG 1
 
@@ -430,11 +431,24 @@ static void invalidate_ce_path(struct cache_entry *ce)
 		cache_tree_invalidate_path(active_cache_tree, ce->name);
 }
 
-static int verify_clean_subdirectory(const char *path, const char *action,
+/* Check that checking out ce->sha1 in subdir ce->name is not
+ * going to overwrite any working files.
+ *
+ * FIXME: implement this function, so we can detect problems
+ *        early, rather than waiting until we actually try to checkout
+ *        the submodules.
+ */
+static int verify_clean_submodule(struct cache_entry *ce, const char *action,
+				      struct unpack_trees_options *o)
+{
+	return 0;
+}
+
+static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
 				      struct unpack_trees_options *o)
 {
 	/*
-	 * we are about to extract "path"; we would not want to lose
+	 * we are about to extract "ce->name"; we would not want to lose
 	 * anything in the existing directory there.
 	 */
 	int namelen;
@@ -442,13 +456,24 @@ static int verify_clean_subdirectory(const char *path, const char *action,
 	struct dir_struct d;
 	char *pathbuf;
 	int cnt = 0;
+	unsigned char sha1[20];
+
+	if (S_ISDIRLNK(ntohl(ce->ce_mode)) &&
+	    resolve_gitlink_ref(ce->name, "HEAD", sha1) == 0) {
+		/* If we are not going to update the submodule, then
+		 * we don't care.
+		 */
+		if (!o->submodules || !hashcmp(sha1, ce->sha1))
+			return 0;
+		verify_clean_submodule(ce, action, o);
+	}
 
 	/*
 	 * First let's make sure we do not have a local modification
 	 * in that directory.
 	 */
-	namelen = strlen(path);
-	pos = cache_name_pos(path, namelen);
+	namelen = strlen(ce->name);
+	pos = cache_name_pos(ce->name, namelen);
 	if (0 <= pos)
 		return cnt; /* we have it as nondirectory */
 	pos = -pos - 1;
@@ -456,7 +481,7 @@ static int verify_clean_subdirectory(const char *path, const char *action,
 		struct cache_entry *ce = active_cache[i];
 		int len = ce_namelen(ce);
 		if (len < namelen ||
-		    strncmp(path, ce->name, namelen) ||
+		    strncmp(ce->name, ce->name, namelen) ||
 		    ce->name[namelen] != '/')
 			break;
 		/*
@@ -474,16 +499,16 @@ static int verify_clean_subdirectory(const char *path, const char *action,
 	 * present file that is not ignored.
 	 */
 	pathbuf = xmalloc(namelen + 2);
-	memcpy(pathbuf, path, namelen);
+	memcpy(pathbuf, ce->name, namelen);
 	strcpy(pathbuf+namelen, "/");
 
 	memset(&d, 0, sizeof(d));
 	if (o->dir)
 		d.exclude_per_dir = o->dir->exclude_per_dir;
-	i = read_directory(&d, path, pathbuf, namelen+1, NULL);
+	i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);
 	if (i)
 		die("Updating '%s' would lose untracked files in it",
-		    path);
+		    ce->name);
 	free(pathbuf);
 	return cnt;
 }
@@ -517,7 +542,7 @@ static void verify_absent(struct cache_entry *ce, const char *action,
 			 * files that are in "foo/" we would lose
 			 * it.
 			 */
-			cnt = verify_clean_subdirectory(ce->name, action, o);
+			cnt = verify_clean_subdirectory(ce, action, o);
 
 			/*
 			 * If this removed entries from the index,
-- 
1.5.2.rc3.815.g8fc2

^ permalink raw reply related

* [PATCH 14/15] entry.c: optionall checkout newly cloned submodules
From: skimo @ 2007-05-20 18:04 UTC (permalink / raw)
  To: git, Junio C Hamano
In-Reply-To: <11796842882917-git-send-email-skimo@liacs.nl>

From: Sven Verdoolaege <skimo@kotnet.org>

---
 entry.c |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/entry.c b/entry.c
index 8c70a47..24bf161 100644
--- a/entry.c
+++ b/entry.c
@@ -104,10 +104,63 @@ static int checkout_submodule(struct cache_entry *ce, const char *path, const st
 	return 0;
 }
 
+static const char *relativize_path(const char *path, const char *dest)
+{
+	static char relative_path[PATH_MAX];
+	int slashes;
+	const char *cp;
+	char *rp;
+
+	if (path[0] == '/')
+		return path;
+
+	for (slashes = 0, cp = strchr(dest, '/'); cp; cp = strchr(cp, '/')) {
+		++slashes;
+		while (*cp == '/')
+			++cp;
+	}
+	if (3 * slashes + strlen(path) + 1 > sizeof(relative_path))
+		die("path too long");
+
+	rp = relative_path;
+	while (slashes--) {
+		memcpy(rp, "../", 3);
+		rp += 3;
+	}
+	strcpy(rp, path);
+
+	return relative_path;
+}
+
+static int write_submodule(struct cache_entry *ce, char *path, const struct checkout *state)
+{
+	struct stat st;
+	const char *submodule_dir, *dest;
+
+	if (mkdir(path, 0777) < 0)
+		return error("git-checkout-index: cannot create subproject directory %s", path);
+
+	if (!state->submodules)
+		return 0;
+
+	submodule_dir = git_path("submodules/%s/.git", ce->name);
+	if (lstat(submodule_dir, &st))
+		return error("submodule '%s' unavailable", ce->name);
+
+	dest = mkpath("%s/.git", ce->name);
+	submodule_dir = relativize_path(submodule_dir, dest);
+
+	if (symlink(submodule_dir, dest))
+		return -1;
+
+	return checkout_submodule(ce, path, state);
+}
+
 static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile)
 {
 	int fd;
 	long wrote;
+	int err;
 
 	switch (ntohl(ce->ce_mode) & S_IFMT) {
 		char *buf, *new;
@@ -177,8 +230,9 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
 	case S_IFDIRLNK:
 		if (to_tempfile)
 			return error("git-checkout-index: cannot create temporary subproject %s", path);
-		if (mkdir(path, 0777) < 0)
-			return error("git-checkout-index: cannot create subproject directory %s", path);
+		err = write_submodule(ce, path, state);
+		if (err)
+			return err;
 		break;
 	default:
 		return error("git-checkout-index: unknown file mode for %s", path);
-- 
1.5.2.rc3.815.g8fc2

^ permalink raw reply related

* [PATCH 11/15] git-read-tree: treat null commit as empty tree
From: skimo @ 2007-05-20 18:04 UTC (permalink / raw)
  To: git, Junio C Hamano
In-Reply-To: <11796842882917-git-send-email-skimo@liacs.nl>

From: Sven Verdoolaege <skimo@kotnet.org>

---
 builtin-read-tree.c |    9 ++++++---
 unpack-trees.c      |    3 +++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 929dd95..b9fcff7 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -17,9 +17,12 @@ static struct object_list *trees;
 
 static int list_tree(unsigned char *sha1)
 {
-	struct tree *tree = parse_tree_indirect(sha1);
-	if (!tree)
-		return -1;
+	struct tree *tree = NULL;
+	if (!is_null_sha1(sha1)) {
+		tree = parse_tree_indirect(sha1);
+		if (!tree)
+			return -1;
+	}
 	object_list_append(&tree->object, &trees);
 	return 0;
 }
diff --git a/unpack-trees.c b/unpack-trees.c
index f3fe2dd..3dadebb 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -26,6 +26,9 @@ static struct tree_entry_list *create_tree_entry_list(struct tree *tree)
 	struct tree_entry_list *ret = NULL;
 	struct tree_entry_list **list_p = &ret;
 
+	if (!tree)
+		return ret;
+
 	if (!tree->object.parsed)
 		parse_tree(tree);
 
-- 
1.5.2.rc3.815.g8fc2

^ permalink raw reply related


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