# git as an sfc member project

21 messages from 2010-10-22 to 2010-11-02. Participants: Jeff King, Shawn Pearce, Sverre Rabbelier, Junio C Hamano, Brandon Casey, Ævar Arnfjörð Bjarmason, A Large Angry SCM, Tait, Bradley M. Kuhn.
Thread: https://gitlist.dev/t/25528

## Jeff King, 2010-10-22 18:30

Subject: git as an sfc member project
Message-ID: <20101022183027.GA12124@sigill.intra.peff.net>
URL: https://gitlist.dev/e/20101022183027.GA12124%40sigill.intra.peff.net

```
It's been a while since I last sent an update; the reason is that
nothing was happening. :) The SFC didn't have a board meeting to vote on
new projects until September, and then spent a few weeks getting
paperwork together. But now we have official word: git has been accepted
as a member project.

Basically, the utility of this is that the Software Freedom Conservancy
will handle any money that goes to the project, especially with respect
to tax implications (the SFC is a registered non-profit and has actual
accountants and such). In the past, the only money has ever been Summer
of Code money, and some unlucky soul had to handle the money (and tax
implications) each year by themselves. Joining the SFC will also make it
easier for people to give tax-deductible donations to the project. Of
course I have no idea what we would spend such money on, but that is a
problem we can perhaps deal with later.

There is one slight caveat, which is that JGit was not accepted, due to
the complexity of their ties with the Eclipse Foundation. In practice, I
don't think this will matter much at all. The only way that Git operates
in any legal capacity as a group is when we do Summer of Code. This
could impact us, e.g., if were to have a JGit-specific SoC project.
Probably the money that goes to the organization for such a project
should _not_ go through the SFC, and would have to be handled
separately. Which is no worse than JGit has it today; they just can't
receive the SFC services as regular git can.

Note that we're not officially a member project yet, as nothing has been
signed. So if people have objections, it's not too late to say
something. If we do want to go ahead, we need to fill in some details
that will go in the agreement.

The draft agreement is here:

  http://peff.net/git-sponsorship-agreement.pdf

Apologies for not simply attaching it, but it is larger than vger's 100K
message limit.

Bradley Kuhn also provided a some discussion of the various points in
the agreement, including deciphering the legalese and explaining the
motivation for each paragraph. I'll include it at the end of this email.

Basically what we need to decide on before signing is:

  1. Who should sign? These people are basically speaking for git as a
     community. Related to (2) below.

  2. What is the leadership structure of git as a legal entity? In other
     words, if we get some money that goes to the SFC (from SoC or from
     donations), who should have authority to tell the SFC to do
     something with it?

     The obvious choices (to me) are:

       a. Junio as benevolent dictator^W maintainer.

       b. Somebody else as benevolent SFC liaison.

       c. Some committee of core people (I'd say no more than 3-5) who
          would all need to agree (or perhaps some majority).

     For (b) and (c), we would need to figure out who the somebody or
     somebodies would be, and perhaps more importantly, the process for
     selecting them. As time goes on, core people may leave, and new
     core people may replace them.

     We could go as complicated as having elections, or as simple as
     "liaison appoints successor".

     Personally, I favor a small group which can approve new people to
     join, and which can leave at will. Having more than one person
     avoids hit-by-bus problems (or even just dropped-off-net problems).
     There is little enough power in such a position that I'm not too
     worried about some crazed egomaniac becoming the Git-SFC liaison.

  3. How much money should we give to the SFC?

     A big chunk of their budget comes from taking a percentage of
     member project money. As a project, we set the percentage we give
     them. So we can give them nothing if we want. But they do provide
     useful services, and even without direct benefit to git, the SFC is
     promoting free software. So probably it makes sense to choose some
     non-zero number.

More details are in the agreement linked above, or in Bradley's
explanation below.

-Peff

-- >8 --
I'm glad that you are considering joining the Conservancy and I am
pleased to extend an invitation to Git.  Attached is a draft of the
fiscal sponsorship agreement that representatives of Git will need to
sign in order to join the Conservancy.  (Both LaTeX source and PDF are
included.) Please read this agreement and share and discuss it with all
of the key people involved in Git.

As mentioned in my previous email, generally, we leave it for the Git
community to decide how you'd like to discuss the document, as signing
such an agreement is a big step for the project and you should consider
the agreement in whatever forum is most appropriate for your community.
I'm happy to answer questions from the community as you consider the
document, and you should feel comfortable cc'ing me on any threads you
think I should comment on.  (However, before doing so, please make sure
I can post back to any lists included in the Cc without being formally
subscribed.)  Meanwhile, you are also welcome to batch questions into
one group as well and email them to me directly, and just repost my
responses.  Basically, whatever works well for you works fine for me.

I strongly suggest that you share the agreement draft as wide as
possible throughout the community, and make sure anyone who has ever
been a serious contributor to the project in the past or currently is
made aware of your plans to join Conservancy.  We very much rely on you
to make sure that your entire community is in agreement with joining
Conservancy, so please make efforts to be sure everyone has had their
say.


Regarding the agreement, some of the more complex provisions of the
agreement reflect the special considerations necessary to support the
Conservancy's tax exempt status.  However, on the whole, I believe that
this agreement fairly and clearly sets out an advantageous relationship
for the Conservancy's member projects.  As some of the paragraphs
specifically indicate, the agreement can be tailored to reflect Git's
particular needs.  To help you in your review, below is a
section-by-section walk through, giving an explanation of the
significance of each provision.  If there are any sections that seem
confusing or that you feel should be changed to reflect Git's needs,
please let me know and we can discuss them.


Introductory Paragraph

This paragraph identifies the parties to the contract.  It's more
thoroughly explained in paragraph 6, but the point of this paragraph is
to name the people who sign the agreement.

Recitals (the "WHEREAS" section)

These paragraphs set forth the basic understandings of the parties.
Similar to the "preamble" found in the GPL and other Free Software
licenses, these are *not* operative provisions of the document.
Instead, they give the context of the agreement.

In this specific case, the key points of understanding are that the
purpose of Git is to forward Free, Libre and Open Source Software
(FLOSS) and that both the Conservancy and Git want Git to join the
Conservancy.  The Conservancy's mission (and charitable purpose) is to
advance only FLOSS development, documentation, and usage, so it is
important that this context be stated clearly.

Paragraph 1 - Term of Agreement

This paragraph says that Git is part of the Conservancy as of the
signing date of the agreement.  It cross references the terminations
provisions in paragraph 7 (which is explained in greater detail below).
Note, though, that Git can choose to leave the Conservancy at any time.

Paragraph 2 - Project Management and Activities

a) Both parties agree that Git will be FLOSS.  As noted above, this is
   the fundamental goal and charitable purpose of the Conservancy.  The
   Conservancy will not and cannot sponsor proprietary projects.

b) This clearly sets out the limits of the Conservancy's management over
   Git.  Due to requirements connected to Conservancy's tax exempt
   status, the ultimate legal control of the projects must be with the
   Conservancy.  From the IRS's perspective, the projects are part of
   the Conservancy, and the purpose of its tax exemption is to forward
   the FLOSS mission of those projects.

   However, the Conservancy does not want to interfere with the
   successful software development, documentation and advocacy work
   already underway in member projects; such activity should continue
   after the agreement without interruption or interference.  This
   paragraph delegates some of Conservancy's legal authority back to the
   developers, so that Git can run itself in day-to-day matters.

   The only limitations that we must place are to prevent Git from
   producing non-free software (as per Conservancy's charitable purpose)
   and from spending money or conducting activities that would
   jeopardize the Conservancy's tax exempt status.  All the ordinary
   activities of FLOSS projects come well within these limitations.
   Some specific activities that are restricted include lobbying
   activities and spending money in ways other than consistent with the
   charitable purposes of the Conservancy (i.e., forwarding FOSS).

   Note that developers of Git in their capacity as individuals (when
   not representing Git still may engage in for-profit service
   businesses related to their FLOSS work.  The work of Git itself must
   fit the guidelines, but individuals are free to act in their own
   capacity in other endeavors, as long as they clearly state that they
   are not acting on behalf of the project when they do so.

   If you are ever concerned that a particular activity -- be it one
   carried out for Git or one that an individual developer engaged in
   independently -- might be a problem, you can always ask the
   Conservancy for clarification.

c) As discussed above in (b), this section describes the corporate
   relationship of the project and the Conservancy.  For clarity, it
   refers to section (b), which delegates the actual management of Git
   to the relevant developers.  Conservancy, when acting as a fiscal
   sponsor, must have the legal authority to manage Git even though
   section (b) delegates the day-to-day operations to the developers.

d) This section clarifies that Git can't represent the Conservancy
   without getting written authorization first.  If you'd like to
   represent the Conservancy at a conference or other such event, you
   can always talk to us about it.

Paragraph 3 - No Fees

It's just as it sounds.  The Conservancy provides services to projects
to benefit the FLOSS community and does demand member projects to bear
the overhead costs.  Projects are encouraged to make donations to the
Conservancy as a percentage of their funds to assist the Conservancy
with its operating expenses.  Please note, though, that Conservancy is
only able to provide its services to member projects because there is a
reasonably healthy general fund available.  Donations from our member
projects are not the only source of general fund revenue, but it is a
substantial component in Conservancy' sustainability plan.

Therefore, if you choose to do so, this section provides suggested
wording in brackets for donating a percentage of the Project's income to
be used towards keeping the Conservancy up and running (10% is a very
common rate that many umbrella organizations require for their fiscal
sponsorship services).

Paragraph 4 - Project Fund/Variance Power

This sets out the financial structure in connection with the
relationship described above in paragraph 2. Conservancy will separately
account for Git's revenue (and Git will have its own bank account at the
Conservancy once its balance reaches $3,500).  For tax purposes,
Conservancy will report all of the income to Git in its IRS and state
filings.  Git therefore will not need to file any separate tax documents
with the IRS.  Conservancy will keep the financial books for Git,
sending periodic reports to the project's developers.

The developers will direct the Conservancy to spend the money on behalf
of Git within the limitations imposed by the tax laws and Conservancy's
501(c)(3) mission.  Conservancy will receive any checks on behalf of
Git, and it will also write checks on behalf of Git.

Paragraph 5 - Project Fund Management/Performance of Charitable Purposes

This paragraph clarifies that all assets will be devoted to the
project's purposes, as those purposes are a subset of the Conservancy's
purposes.  Assets cannot be used in connection with activities that
would jeopardize the Conservancy's tax exempt status.  As discussed
above, in practice, most typical expenses of FLOSS projects will come
well within these limitations.  Activities that are restricted include
lobbying activities and spending money in ways other than consistent
with the charitable purposes of Conservancy (i.e., forwarding FLOSS).

Paragraph 6 - Representation of the Project in the Conservancy

As the note in this section indicates, we understand that each project
will have its own management structure that it has developed to reflect
its size and community.  This paragraph requires that certain
representatives be named as the individuals that can officially
communicate decisions on behalf of Git.  This can be a single
maintainer, a committee of developers or a few specified
representatives.

To the extent that it makes sense for Git to have a committee of
representatives, we should indicate how decisions can be made by that
committee.  For example, should all decisions be communicated to the
Conservancy by all members of the committee or would a simple majority
suffice?  Can any one representative communicate official decisions on
behalf of all?  Git should also consider adding a mechanism here for
adding and removing representatives over time.  We're happy to discuss
methods that have worked for other projects with you to help you select
the solution that is right for you.

We generally find this is the most difficult provisions for projects to
work out, as it does require that your project consider the form and
type of leadership structure it wants to have, and that structure will
be legally formalized in this document for perpetuity.

Paragraph 7 - Outstanding Liabilities

In this section, Git confirms that it has told the Conservancy about any
liabilities that might be outstanding prior to joining the Conservancy.
This gives the Conservancy some assurance that its due diligence process
has been complete and that the Conservancy's Board received all of the
information it needed to properly evaluate the project.  Liabilities
include, for example, financial obligations, such as any debts or
outstanding bills, or any legal claims that could be outstanding against
Git.

If you believe some liabilities exist, or that something may be a
liability and aren't sure, please err on the side of letting Conservancy
know about it.

Paragraph 8 - Termination

Projects can leave Conservancy at will.  This section sets out the
mechanisms for termination to make sure that when a project leaves the
Conservancy it does so without jeopardizing the tax exempt status of the
Conservancy (and, consequently, the status of all of the other projects
in the Conservancy).

There is a 60 day notice requirement so that a new tax exempt non-profit
can be found for Git to join.  If there isn't another fiscal sponsor or
other tax exempt non-profit to take over Git, Git can incorporate as a
separate entity and apply for tax exemption recognition.  If there is no
separate entity -- for example if a project loses momentum and has been
abandoned by its developers -- the Conservancy must be left with the
assets for use by the Conservancy for other FLOSS-related charitable
work.

These restrictions would also apply to any separate tax exempt entity,
so if Git were to incorporate and achieve tax exemption outside of
Conservancy, it would have to deal with the same considerations upon any
wind-up or distribution of assets.  Members of the Conservancy's board
are familiar with non-profit wind-down situations, and can assist in the
unlikely event that this unfortunate outcome occurs.

Paragraph 9 - Miscellaneous

These provisions are standard agreement boilerplate - they clarify the
enforceability of separate provisions, specify that the contract be
governed by New York Law and state that any amendments to this agreement
need to be agreed to in writing by all of the parties.

Paragraph 10 - Counterparts/Facsimile

Although it's good to have original signatures in the corporate records,
this allows you to simply scan a copy for the contract to take effect.


We hope this explanation document has made it clear why the agreement is
structured in this way.  If any provisions seem problematic to you, let
us know and we'll work with you to try to build an agreement that works
for both of us.  We look forward to Git joining the Conservancy!

```

## Shawn Pearce, 2010-10-22 19:19

Subject: Re: git as an sfc member project
Message-ID: <AANLkTi=6tvmTAfdyL-sKBsq+4OpFaQpZWT66ANESNapj@mail.gmail.com>
URL: https://gitlist.dev/e/AANLkTi%3D6tvmTAfdyL-sKBsq%2B4OpFaQpZWT66ANESNapj%40mail.gmail.com
In-Reply-To: <20101022183027.GA12124@sigill.intra.peff.net>

```
On Fri, Oct 22, 2010 at 11:30 AM, Jeff King <peff@peff.net> wrote:
> There is one slight caveat, which is that JGit was not accepted, due to
> the complexity of their ties with the Eclipse Foundation.

Yup.  Anytime you say "Eclipse Foundation", make sure you put
"complexity" into the same sentence.  Its required to make the
sentence accurate.  :-)

> In practice, I
> don't think this will matter much at all. The only way that Git operates
> in any legal capacity as a group is when we do Summer of Code. This
> could impact us, e.g., if were to have a JGit-specific SoC project.

We had a GSoC project, but through the Eclipse Foundation
participation in GSoC, not Git.  So the Eclipse Foundation received
our mentor stipend for us, and will spend it in some way that is
unknown to me.  Yay?

The decision to do JGit GSoC through Eclipse and not through Git this
year wasn't really mine.  I just didn't disagree loud enough to change
things.

> Probably the money that goes to the organization for such a project
> should _not_ go through the SFC, and would have to be handled
> separately. Which is no worse than JGit has it today; they just can't
> receive the SFC services as regular git can.

This is fine with the JGit folks, for now anyway.  We may revisit this
and have JGit join SFC at some point in the future.  We might not.

> Basically what we need to decide on before signing is:
>
>  1. Who should sign? These people are basically speaking for git as a
>     community. Related to (2) below.

The people listed in 2 as the leadership structure of git.

>  2. What is the leadership structure of git as a legal entity? In other
>     words, if we get some money that goes to the SFC (from SoC or from
>     donations), who should have authority to tell the SFC to do
>     something with it?
>
>     The obvious choices (to me) are:
>
>       a. Junio as benevolent dictator^W maintainer.
>
>       b. Somebody else as benevolent SFC liaison.
>
>       c. Some committee of core people (I'd say no more than 3-5) who
>          would all need to agree (or perhaps some majority).
...
>     Personally, I favor a small group which can approve new people to
>     join, and which can leave at will. Having more than one person
>     avoids hit-by-bus problems (or even just dropped-off-net problems).
>     There is little enough power in such a position that I'm not too
>     worried about some crazed egomaniac becoming the Git-SFC liaison.

I agree.

I think a committee of at least 3 people and at most 5, any of whom
can be a benevolent SFC liasion, is fine.  As far as selection goes,
the committee can elect or remove a member through a majority vote,
and should base its decisions based on surviving contributions to the
code base, but shouldn't be tied to that (just in case someone
contributes a lot of good code and then becomes a jerk).

But as you point out, there isn't much power involved here, so there
isn't a lot of concern of it being abused.  The important thing (the
copyright on the code) is still held by individual contributors, so
there is very little value involved (just the handful of GSoC dollars
each year).

>  3. How much money should we give to the SFC?
>
>     A big chunk of their budget comes from taking a percentage of
>     member project money. As a project, we set the percentage we give
>     them. So we can give them nothing if we want. But they do provide
>     useful services, and even without direct benefit to git, the SFC is
>     promoting free software. So probably it makes sense to choose some
>     non-zero number.

I agree, a non-zero number.  2-5%?  Any idea what is typical?

-- 
Shawn.

```

## Jeff King, 2010-10-22 19:35

Subject: Re: git as an sfc member project
Message-ID: <20101022193512.GB13059@sigill.intra.peff.net>
URL: https://gitlist.dev/e/20101022193512.GB13059%40sigill.intra.peff.net
In-Reply-To: <AANLkTi=6tvmTAfdyL-sKBsq+4OpFaQpZWT66ANESNapj@mail.gmail.com>

```
On Fri, Oct 22, 2010 at 12:19:00PM -0700, Shawn O. Pearce wrote:

> > Probably the money that goes to the organization for such a project
> > should _not_ go through the SFC, and would have to be handled
> > separately. Which is no worse than JGit has it today; they just can't
> > receive the SFC services as regular git can.
> 
> This is fine with the JGit folks, for now anyway.  We may revisit this
> and have JGit join SFC at some point in the future.  We might not.

Yeah, what I should have said to be more clear in my original email is:
JGit can do what they like with SFC, but there is no reason for this
caveat to prevent _Git_ from joining the SFC.  The JGit folks are no
worse off, and things are much better for Git.

I think it would be great if JGit could join SFC in the long run.

> > Basically what we need to decide on before signing is:
> >
> >  1. Who should sign? These people are basically speaking for git as a
> >     community. Related to (2) below.
> 
> The people listed in 2 as the leadership structure of git.

Agreed (I should have written point (2) first. ;) ).

> I think a committee of at least 3 people and at most 5, any of whom
> can be a benevolent SFC liasion, is fine.  As far as selection goes,
> the committee can elect or remove a member through a majority vote,
> and should base its decisions based on surviving contributions to the
> code base, but shouldn't be tied to that (just in case someone
> contributes a lot of good code and then becomes a jerk).

That sounds reasonable to me. I'm not sure what documentation, if any,
we need for such a structure. I guess we have to outline it in the
agreement with the SFC, so that may be sufficient. We can ask Bradley
about it, too.

> But as you point out, there isn't much power involved here, so there
> isn't a lot of concern of it being abused.  The important thing (the
> copyright on the code) is still held by individual contributors, so
> there is very little value involved (just the handful of GSoC dollars
> each year).

Yeah. I don't see any need to tie any decision on SFC interaction into
any other part of how git is run. It should have nothing to do with how
actual coding or release management works. I'm sure there will be some
overlap in who is prominent in both areas, but it doesn't need to be so.

> >  3. How much money should we give to the SFC?
> [...]
> I agree, a non-zero number.  2-5%?  Any idea what is typical?

Either in the draft agreement or in the notes the number 10% is thrown
out as a common value for umbrella organizations to charge. That sounds
reasonable to me, as they are probably saving us at least that much in
taxes by being a proper non-profit.

-Peff

```

## Shawn Pearce, 2010-10-22 20:06

Subject: Re: git as an sfc member project
Message-ID: <AANLkTim0EH0Qvwe6NHMBt831jHZV85=TSAx8k2ABnTdd@mail.gmail.com>
URL: https://gitlist.dev/e/AANLkTim0EH0Qvwe6NHMBt831jHZV85%3DTSAx8k2ABnTdd%40mail.gmail.com
In-Reply-To: <20101022193512.GB13059@sigill.intra.peff.net>

```
On Fri, Oct 22, 2010 at 12:35 PM, Jeff King <peff@peff.net> wrote:
>> >  3. How much money should we give to the SFC?
>> [...]
>> I agree, a non-zero number.  2-5%?  Any idea what is typical?
>
> Either in the draft agreement or in the notes the number 10% is thrown
> out as a common value for umbrella organizations to charge. That sounds
> reasonable to me, as they are probably saving us at least that much in
> taxes by being a proper non-profit.

OK, 10% does seem reasonable given they are saving us the taxes... or more.  :-)

-- 
Shawn.

```

## Sverre Rabbelier, 2010-10-22 20:59

Subject: Re: git as an sfc member project
Message-ID: <AANLkTim7gC6ckrN-yFGyT4KgPz2v9B+UqLBZj7GzaMpK@mail.gmail.com>
URL: https://gitlist.dev/e/AANLkTim7gC6ckrN-yFGyT4KgPz2v9B%2BUqLBZj7GzaMpK%40mail.gmail.com
In-Reply-To: <AANLkTim0EH0Qvwe6NHMBt831jHZV85=TSAx8k2ABnTdd@mail.gmail.com>

```
Heya,

On Fri, Oct 22, 2010 at 12:19, Shawn Pearce <spearce@spearce.org> wrote:
> I think a committee of at least 3 people and at most 5, any of whom
> can be a benevolent SFC liasion, is fine.  As far as selection goes,
> the committee can elect or remove a member through a majority vote,
> and should base its decisions based on surviving contributions to the
> code base, but shouldn't be tied to that (just in case someone
> contributes a lot of good code and then becomes a jerk).

Sounds good. Something like Junio (Duh), Shawn (based on commit
count), Peff (Handled GSoC money last year), and Jonathan Nieder
(based on list activity)?

On Fri, Oct 22, 2010 at 13:06, Shawn Pearce <spearce@spearce.org> wrote:
> OK, 10% does seem reasonable given they are saving us the taxes... or more.  :-)

LGTM.

-- 
Cheers,

Sverre Rabbelier

```

## Junio C Hamano, 2010-10-22 21:48

Subject: Re: git as an sfc member project
Message-ID: <7vd3r1lx0m.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vd3r1lx0m.fsf%40alter.siamese.dyndns.org
In-Reply-To: <AANLkTi=6tvmTAfdyL-sKBsq+4OpFaQpZWT66ANESNapj@mail.gmail.com>

```
Shawn Pearce <spearce@spearce.org> writes:

> The people listed in 2 as the leadership structure of git.
> ...
>>     Personally, I favor a small group which can approve new people to
>>     join, and which can leave at will. Having more than one person
>>     avoids hit-by-bus problems (or even just dropped-off-net problems).
>>     There is little enough power in such a position that I'm not too
>>     worried about some crazed egomaniac becoming the Git-SFC liaison.
>
> I agree.
>
> I think a committee of at least 3 people and at most 5, any of whom
> can be a benevolent SFC liasion, is fine.  As far as selection goes,
> the committee can elect or remove a member through a majority vote,
> and should base its decisions based on surviving contributions to the
> code base, but shouldn't be tied to that (just in case someone
> contributes a lot of good code and then becomes a jerk).

Small group like 3 to 5 to avoid bus factor sounds reasonable to me.

Because my involvement in the project does not relate to monetizing git, I
can safely be included in them, I think.  If people do not mind me being
that jerk you meantioned, that is ;-)

>>  3. How much money should we give to the SFC?
>>
>>     A big chunk of their budget comes from taking a percentage of
>>     member project money. As a project, we set the percentage we give
>>     them. So we can give them nothing if we want. But they do provide
>>     useful services, and even without direct benefit to git, the SFC is
>>     promoting free software. So probably it makes sense to choose some
>>     non-zero number.
>
> I agree, a non-zero number.  2-5%?  Any idea what is typical?

As you two agreed 10% sounds fair to me.

```

## Junio C Hamano, 2010-10-22 22:59

Subject: Re: git as an sfc member project
Message-ID: <7vocalkf53.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vocalkf53.fsf%40alter.siamese.dyndns.org
In-Reply-To: <AANLkTi=6tvmTAfdyL-sKBsq+4OpFaQpZWT66ANESNapj@mail.gmail.com>

```
Shawn Pearce <spearce@spearce.org> writes:

> I think a committee of at least 3 people and at most 5, any of whom
> can be a benevolent SFC liasion, is fine.  As far as selection goes,
> the committee can elect or remove a member through a majority vote,
> and should base its decisions based on surviving contributions to the
> code base, but shouldn't be tied to that (just in case someone
> contributes a lot of good code and then becomes a jerk).

Just a datapoint from quick "blame -C -C -w" run as of 1.7.3.2, counting
surviving lines, 7 top from each area, excluding Documentation/RelNotes.


** Everything else **

77212        Junio C Hamano
41388        Shawn O. Pearce
32676        Linus Torvalds
28618        Johannes Schindelin
22120        Ævar Arnfjörð Bjarmason
20190        Paul Mackerras
15518        Marius Storm-Olsen


** t/ **

59572        Junio C Hamano
9646         Johannes Schindelin
7606         Eric Wong
7342         Jonathan Nieder
5733         Jeff King
4978         Shawn O. Pearce
4828         Johan Herland


** Documentation/ **

22092        Junio C Hamano
10830        J. Bruce Fields
5566         Christian Couder
3904         Shawn O. Pearce
3664         Thomas Rast
3388         Johannes Schindelin
2888         David Greaves


** contrib/ **

7180         Junio C Hamano
3960         Shawn O. Pearce
3378         Alexandre Julliard
2948         Marius Storm-Olsen
2668         Aneesh Kumar K.V
2624         Simon Hausmann
1254         Matthias Urlichs

```

## Jeff King, 2010-10-22 23:18

Subject: Re: git as an sfc member project
Message-ID: <20101022231820.GB25520@sigill.intra.peff.net>
URL: https://gitlist.dev/e/20101022231820.GB25520%40sigill.intra.peff.net
In-Reply-To: <7vocalkf53.fsf@alter.siamese.dyndns.org>

```
On Fri, Oct 22, 2010 at 03:59:36PM -0700, Junio C Hamano wrote:

> Shawn Pearce <spearce@spearce.org> writes:
> 
> > I think a committee of at least 3 people and at most 5, any of whom
> > can be a benevolent SFC liasion, is fine.  As far as selection goes,
> > the committee can elect or remove a member through a majority vote,
> > and should base its decisions based on surviving contributions to the
> > code base, but shouldn't be tied to that (just in case someone
> > contributes a lot of good code and then becomes a jerk).
> 
> Just a datapoint from quick "blame -C -C -w" run as of 1.7.3.2, counting
> surviving lines, 7 top from each area, excluding Documentation/RelNotes.
> 
> 
> ** Everything else **
> 
> 77212        Junio C Hamano
> 41388        Shawn O. Pearce
> 32676        Linus Torvalds
> 28618        Johannes Schindelin
> 22120        Ævar Arnfjörð Bjarmason
> 20190        Paul Mackerras
> 15518        Marius Storm-Olsen

How did you calculate this? I don't see how it could be right. For
example, Ævar's contribution, while being impressively large lately, is
only 12877 lines total over all commits, let alone surviving lines:

  $ git log --pretty=format: --numstat --author=Bjarmason |
    perl -ne '/^\d+/ and $total += $&; END { print "$total\n"; }'
  12877

-Peff

```

## Brandon Casey, 2010-10-22 23:21

Subject: Re: git as an sfc member project
Message-ID: <S3I346LWUOykFBiCrFLgbfYptyYvHyj1Jcdo6EHe-2fWosEUh4Va3g@cipher.nrlssc.navy.mil>
URL: https://gitlist.dev/e/S3I346LWUOykFBiCrFLgbfYptyYvHyj1Jcdo6EHe-2fWosEUh4Va3g%40cipher.nrlssc.navy.mil
In-Reply-To: <20101022231820.GB25520@sigill.intra.peff.net>

```
On 10/22/2010 06:18 PM, Jeff King wrote:
> On Fri, Oct 22, 2010 at 03:59:36PM -0700, Junio C Hamano wrote:
> 
>> Shawn Pearce <spearce@spearce.org> writes:
>>
>>> I think a committee of at least 3 people and at most 5, any of whom
>>> can be a benevolent SFC liasion, is fine.  As far as selection goes,
>>> the committee can elect or remove a member through a majority vote,
>>> and should base its decisions based on surviving contributions to the
>>> code base, but shouldn't be tied to that (just in case someone
>>> contributes a lot of good code and then becomes a jerk).
>>
>> Just a datapoint from quick "blame -C -C -w" run as of 1.7.3.2, counting
>> surviving lines, 7 top from each area, excluding Documentation/RelNotes.
>>
>>
>> ** Everything else **
>>
>> 77212        Junio C Hamano
>> 41388        Shawn O. Pearce
>> 32676        Linus Torvalds
>> 28618        Johannes Schindelin
>> 22120        Ævar Arnfjörð Bjarmason
>> 20190        Paul Mackerras
>> 15518        Marius Storm-Olsen
> 
> How did you calculate this? I don't see how it could be right. For
> example, Ævar's contribution, while being impressively large lately, is
> only 12877 lines total over all commits, let alone surviving lines:
> 
>   $ git log --pretty=format: --numstat --author=Bjarmason |
>     perl -ne '/^\d+/ and $total += $&; END { print "$total\n"; }'
>   12877

I was just going to craft a reply too.  I think Junio's number are
all doubled.

Here are Junio's numbers for contrib/:

7180         Junio C Hamano
3960         Shawn O. Pearce
3378         Alexandre Julliard
2948         Marius Storm-Olsen
2668         Aneesh Kumar K.V
2624         Simon Hausmann
1254         Matthias Urlichs

and here's what I get for contrib/:

3590         Junio C Hamano
1980         Shawn O. Pearce
1689         Alexandre Julliard
1473         Marius Storm-Olsen
1334         Aneesh Kumar K.V
1312         Simon Hausmann
627          Matthias Urlichs

-Brandon

```

## Junio C Hamano, 2010-10-22 23:22

Subject: Re: git as an sfc member project
Message-ID: <7vk4l9ke3o.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vk4l9ke3o.fsf%40alter.siamese.dyndns.org
In-Reply-To: <20101022231820.GB25520@sigill.intra.peff.net>

```
Jeff King <peff@peff.net> writes:

> How did you calculate this? I don't see how it could be right. For
> example, Ævar's contribution, while being impressively large lately, is
> only 12877 lines total over all commits, let alone surviving lines:

Yeah, there seems to be something fishy in my math, adding up numbers from
blame output.

```

## Junio C Hamano, 2010-10-22 23:26

Subject: Re: git as an sfc member project
Message-ID: <7vd3r1kdvy.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vd3r1kdvy.fsf%40alter.siamese.dyndns.org
In-Reply-To: <S3I346LWUOykFBiCrFLgbfYptyYvHyj1Jcdo6EHe-2fWosEUh4Va3g@cipher.nrlssc.navy.mil>

```
Brandon Casey <brandon.casey.ctr@nrlssc.navy.mil> writes:

> ...  I think Junio's number are
> all doubled.

Yeah, I think you are right.

```

## Brandon Casey, 2010-10-23 00:09

Subject: Re: git as an sfc member project
Message-ID: <7KKnonc5d5_rj_95MtHHlpKzcnmvDte62cL2vYgfQQkHguIG9qjT2A@cipher.nrlssc.navy.mil>
URL: https://gitlist.dev/e/7KKnonc5d5_rj_95MtHHlpKzcnmvDte62cL2vYgfQQkHguIG9qjT2A%40cipher.nrlssc.navy.mil
In-Reply-To: <hh0bQq8TcM0saDTuJo6qVdOMgn-14aysvhF_S70syB678Of7zQOsY9jLajG2WpeGXid8jtG4kVA@cipher.nrlssc.navy.mil>

```

I was curious about something like this earlier this week,
and I wrote this little hack.

Got anything better?

---- >8 ----
#!/usr/bin/perl -w

use lib (split(/:/, $ENV{GITPERLLIB} || "/your/git/installation/lib/perl5/site_perl/5.8.8"));

use strict;
use Git;

use Getopt::Std;
$Getopt::Std::STANDARD_HELP_VERSION = 1;

$main::VERSION = 0.1;

sub usage {
	my $name;

	eval {
		require File::Basename;
		$name = File::Basename::basename($0);
	} or do {
		$name = substr $0, rindex($0, '/') + 1;
	};

	print "Usage: $name [--help] [-flstv] <tree-ish> [paths...]\n";
}

sub main::HELP_MESSAGE {

	usage;

	print "\nOPTIONS\n\n",
	      " -f  use file centric view\n",
	      " -l  use longer format\n",
	      " -s  use short format\n",
	      " Both -l and -s produce an even longer format\n",
	      " -t  print total lines at the end\n",
	      " -v  print more information while processing\n",
	      "\n";
}

sub new_parser {
	my $fh = shift;
	my $ctx = shift;
	return { FH => $fh, CTX => $ctx, buf => ''};
}

sub get_next_line {
	my $obj = shift;
	my $fh = $obj->{'FH'};

	defined($obj->{'buf'} = <$fh>);
}

sub parse_blame_entry {
	my $obj = shift;

	return () unless get_next_line $obj;
	$_ = $obj->{'buf'};
	chomp;

	my ($sha1, $sourceline, $resultline, $num_lines) = split ' ', $_, 4;

	return () unless defined $num_lines;

	my %h = ( sha1 => $sha1, sourceline => $sourceline,
		  resultline => $resultline, lines => $num_lines );
	while (get_next_line $obj) {
		$_ = $obj->{'buf'};
		chomp;
		my ($key, $val) = split ' ', $_, 2;
		$h{$key} = $val;
		last if m/^filename /;
	}

	return %h;
}

sub parse_blame {
	my $obj = shift;
        my $authors = shift;

	my %commits;
	while (my %h = parse_blame_entry $obj) {

		if (! exists $commits{$h{'sha1'}}) {

			if (! exists $authors->{$h{'author'}}->{$obj->{'filename'}}) {
				$authors->{$h{'author'}}->{$obj->{'filename'}} = 0;
			}
			$commits{$h{'sha1'}} =
				\$authors->{$h{'author'}}->{$obj->{'filename'}};
		}

		${$commits{$h{'sha1'}}} += $h{'lines'};
	}
}

sub count_total_lines {
	my $authors = shift;

	my $lines = 0;

	for (values %{$authors}) {
		for (values %{$_}) { $lines += $_; }
	}

	return $lines;
}

sub count_author_lines {
	my $authors = shift;

	my %alines;

	foreach my $author (keys %{$authors}) {
		my $lines = 0;
		for (values %{$authors->{$author}}) { $lines += $_; }
		$alines{$author} = $lines;
	}

	return %alines;
}

sub count_file_lines {
	my $authors = shift;

	my %flines;

	for (values %{$authors}) {
		foreach my $file (keys %{$_}) {
			$flines{$file} += $_->{$file};
		}
	}

	return %flines;
}

sub print_short {
	my $authors = shift;

	my %alines = count_author_lines $authors;

	foreach my $author (sort {$alines{$b} <=> $alines{$a}} keys %alines) {
		printf "%6d  %s\n", $alines{$author}, $author;
	}
}

sub print_long {
	my $authors = shift;

	my %alines = count_author_lines $authors;

	foreach my $author (sort {$alines{$b} <=> $alines{$a}} keys %alines) {
		print "$author (", $alines{$author}, "):\n";
		foreach my $file (sort
		    {$authors->{$author}->{$b} <=> $authors->{$author}->{$a}}
		    keys %{$authors->{$author}}) {
			printf "  %10d %s\n", $authors->{$author}->{$file},
			      $file;
		}
	}
}

sub print_longer {
	my $authors = shift;

	my %alines = count_author_lines $authors;
	my $total_lines = count_total_lines $authors;

	foreach my $author (sort {$alines{$b} <=> $alines{$a}} keys %alines) {
		printf "%s (%d, %.2f%%):\n", $author, $alines{$author},
			100. * $alines{$author} / $total_lines;
		foreach my $file (sort
		    {$authors->{$author}->{$b} <=> $authors->{$author}->{$a}}
		    keys %{$authors->{$author}}) {
			printf "  %10d (%5.2f%%) %s\n",
			       $authors->{$author}->{$file},
			       100. *
			       $authors->{$author}->{$file} / $alines{$author},
			       $file;
		}
	}
}

sub print_with_file_percentage {
	my $authors = shift;

	my %alines = count_author_lines $authors;
	my %flines = count_file_lines $authors;
	my $total_lines = count_total_lines $authors;
	my $total_files = scalar(keys %flines);

	foreach my $author (sort {$alines{$b} <=> $alines{$a}} keys %alines) {
		printf "%s (%d lines in %d files, " .
		       "%.2f%% of all lines, %.2f%% of all files):\n",
		       $author, $alines{$author},
		       scalar(keys %{$authors->{$author}}),
		       100. * $alines{$author} / $total_lines,
		       100. * scalar(keys %{$authors->{$author}})/$total_files;
		foreach my $file (sort
		    {$authors->{$author}->{$b} <=> $authors->{$author}->{$a}}
		    keys %{$authors->{$author}}) {
			printf "  %10d (%6.2f%%) of %6d (%6.2f%%) %s\n",
			       $authors->{$author}->{$file},
			       100. *
			       $authors->{$author}->{$file} / $flines{$file},
			       $flines{$file},
			       100. *
			       $authors->{$author}->{$file} / $alines{$author},
			       $file;
		}
	}
}

sub print_with_file_perspective {
	my $authors = shift;

	my %flines = count_file_lines $authors;

	foreach my $file (sort keys %flines) {
		my @auths = grep {exists $authors->{$_}->{$file}}
			keys %{$authors};
		print "$file ($flines{$file}):\n";
		foreach my $author (sort
		    {$authors->{$b}->{$file} <=> $authors->{$a}->{$file}}
		    @auths) {
			printf " %10d %s\n", $authors->{$author}->{$file},
				$author;
		}
	}
}


my $verbose = 0;
my $output_format = 0;
my $show_total = 0;

our ($opt_f, $opt_l, $opt_s, $opt_t, $opt_v);
getopts("flstv") or die "Invalid options specified";

	if ($opt_f) {
		$output_format = 4;
	} elsif ($opt_l && $opt_s) {
		$output_format = 3;
	} elsif ($opt_l) {
		$output_format = 2;
	} elsif ($opt_s) {
		$output_format = 1;
	}
	if ($opt_t) {
		$show_total = 1;
	}
	if ($opt_v) {
		$verbose = 1;
	}

eval {select STDERR; usage; exit 1;} unless $#ARGV >= 0;

my %authors;
my $repo = Git->repository();

my ($fh, $ctx) = $repo->command_output_pipe('ls-tree', '-r', '--name-only', '--', @ARGV);
my $ls_tree = new_parser $fh, $ctx;
while (get_next_line $ls_tree) {
	chomp $ls_tree->{'buf'};

        my $is_text = `file "$ls_tree->{'buf'}"` =~ m/text/;

	if ($is_text) {
		if ($verbose) {
			print STDERR "Processing file: ", $ls_tree->{'buf'},
				"\n";
		}
	} else {
		if ($verbose) {
			print STDERR "Skipping non-text file: ",
				$ls_tree->{'buf'}, "\n";
		}
		next;
	}

	($fh, $ctx) =
	    $repo->command_output_pipe('blame', '-C', '-C', '-w', '--incremental',
		'--', $ls_tree->{'buf'});
	my $blame_obj = new_parser $fh, $ctx;
	$blame_obj->{'filename'} = $ls_tree->{'buf'};

	parse_blame $blame_obj, \%authors;

	$repo->command_close_pipe($blame_obj->{'FH'}, $blame_obj->{'CTX'});
}
$repo->command_close_pipe($ls_tree->{'FH'}, $ls_tree->{'CTX'});


if ($output_format == 0) {
	print_long \%authors;
} elsif ($output_format == 1) {
	print_short \%authors;
} elsif ($output_format == 2) {
	print_longer \%authors;
} elsif ($output_format == 3) {
	print_with_file_percentage \%authors;
} elsif ($output_format == 4) {
	print_with_file_perspective \%authors;
}

print count_total_lines(\%authors), " total lines.\n" if ($show_total);

exit;

```

## Brandon Casey, 2010-10-23 01:30

Subject: Re: git as an sfc member project
Message-ID: <cs0GhwZZ9W-pJdXPmTo0di_hrUwMa14GE8dSJeIQtOwrvDdl4KxJ_g@cipher.nrlssc.navy.mil>
URL: https://gitlist.dev/e/cs0GhwZZ9W-pJdXPmTo0di_hrUwMa14GE8dSJeIQtOwrvDdl4KxJ_g%40cipher.nrlssc.navy.mil
In-Reply-To: <7KKnonc5d5_rj_95MtHHlpKzcnmvDte62cL2vYgfQQkHguIG9qjT2A@cipher.nrlssc.navy.mil>

```
On 10/22/2010 07:09 PM, Brandon Casey wrote:

> 	($fh, $ctx) =
> 	    $repo->command_output_pipe('blame', '-C', '-C', '-w', '--incremental',
> 		'--', $ls_tree->{'buf'});

I forgot to pass the revision to git-blame.

It should look like this:

 	($fh, $ctx) =
 	    $repo->command_output_pipe('blame', '-C', '-C', '-w', '--incremental',
 		$ARGV[0], '--', $ls_tree->{'buf'});

-Brandon

```

## Ævar Arnfjörð Bjarmason, 2010-10-23 11:52

Subject: Re: git as an sfc member project
Message-ID: <AANLkTikxMtdvppLur4kuXffRn0G29NFv6ameTpaeY46G@mail.gmail.com>
URL: https://gitlist.dev/e/AANLkTikxMtdvppLur4kuXffRn0G29NFv6ameTpaeY46G%40mail.gmail.com
In-Reply-To: <20101022231820.GB25520@sigill.intra.peff.net>

```
On Fri, Oct 22, 2010 at 23:18, Jeff King <peff@peff.net> wrote:
> On Fri, Oct 22, 2010 at 03:59:36PM -0700, Junio C Hamano wrote:
>
>> Shawn Pearce <spearce@spearce.org> writes:
>>
>> > I think a committee of at least 3 people and at most 5, any of whom
>> > can be a benevolent SFC liasion, is fine.  As far as selection goes,
>> > the committee can elect or remove a member through a majority vote,
>> > and should base its decisions based on surviving contributions to the
>> > code base, but shouldn't be tied to that (just in case someone
>> > contributes a lot of good code and then becomes a jerk).
>>
>> Just a datapoint from quick "blame -C -C -w" run as of 1.7.3.2, counting
>> surviving lines, 7 top from each area, excluding Documentation/RelNotes.
>>
>>
>> ** Everything else **
>>
>> 77212        Junio C Hamano
>> 41388        Shawn O. Pearce
>> 32676        Linus Torvalds
>> 28618        Johannes Schindelin
>> 22120        Ævar Arnfjörð Bjarmason
>> 20190        Paul Mackerras
>> 15518        Marius Storm-Olsen
>
> How did you calculate this? I don't see how it could be right. For
> example, Ævar's contribution, while being impressively large lately, is
> only 12877 lines total over all commits, let alone surviving lines:
>
>  $ git log --pretty=format: --numstat --author=Bjarmason |
>    perl -ne '/^\d+/ and $total += $&; END { print "$total\n"; }'
>  12877

Either way it doesn't matter, since I'm not interested in being a SFC
liasion. I just want to hack, not deal with issues like these (but
more power to people who want to).

But I think picking people for anything based on the number of lines
that git-blame thinks people "own" is a bad criteria. My contributions
to Git are relatively small, but I've happened to pick projects (the
test suit, gettext) that have touched a lot of lines of code.

But other people who've done 10x more work than I have (both in time &
importance) probably have 10x less lines of code assigned to them.

If I keep it up I'll probably "own" more lines of code than Linus, but
I think any criteria that brings me within an order of magnitute of
importance of him and Junio is pretty much broken by defintion :)

```

## Jeff King, 2010-10-23 13:39

Subject: Re: git as an sfc member project
Message-ID: <20101023133948.GA2002@sigill.intra.peff.net>
URL: https://gitlist.dev/e/20101023133948.GA2002%40sigill.intra.peff.net
In-Reply-To: <AANLkTikxMtdvppLur4kuXffRn0G29NFv6ameTpaeY46G@mail.gmail.com>

```
On Sat, Oct 23, 2010 at 11:52:26AM +0000, Ævar Arnfjörð Bjarmason wrote:

> Either way it doesn't matter, since I'm not interested in being a SFC
> liasion. I just want to hack, not deal with issues like these (but
> more power to people who want to).

I didn't mean to pick on you, btw. It's just that I was surprised to see
you, whose first commit was only 6 months ago, in the list of top
contributors by lines of code. You're productive, but not _that_
productive. :)

As it turns out, even though Junio's numbers are doubled, you are in
fact high by line count. It's because of compat/regex:

  $ git log --pretty=format: --numstat --author=Bjarmason compat/regex/* |
    perl -ne '/^\d+/ and $total += $&; END { print "$total\n"; }'
  11186

which accounts for 85% of your contribution. :)

> But I think picking people for anything based on the number of lines
> that git-blame thinks people "own" is a bad criteria. My contributions
> to Git are relatively small, but I've happened to pick projects (the
> test suit, gettext) that have touched a lot of lines of code.
> 
> But other people who've done 10x more work than I have (both in time &
> importance) probably have 10x less lines of code assigned to them.

I think counting surviving lines via git-blame is not that bad a metric
for importance. It's certainly better than counting added lines (as I
did above), as it measures lines that people are actually still using.
The problem here is that we have quite large chunks of "uninteresting".
Junio made some attempt to account for this by counting various parts of
the codebase separately. Probably compat/ should have been removed from
the core count (ditto for Marius Storm-Olsen, whose line count is
inflated by importing nedmalloc; which isn't to say that any of these
contributions aren't important. They just aren't the same as sitting
down and writing 10,000 lines of custom git code).

In general, any line count of code (surviving or otherwise) will favor
people who are adding features rather than fixing bugs. I prefer commit
count, where I personally fare much better. :)

One interesting metric to me is the ratio of commit log lines to code
lines. A high ratio implies (to some degree) working on bugfixes, where
the actual changed lines of code are less important than the time you
spend figuring out _which_ lines to change.

You can measure it with something like:

  $ git log  --format='Author: %an%n%w(0,4,4)%B' --numstat --no-merges |
    perl -ne '
      if (/^Author: (.*)/) { $author = $1 }
      elsif (/^\s{4}.+/) { $commit{$author}++ }
      elsif (/^\d+/) { $code{$author} += $& }
      END {
        print($commit{$_} / $code{$_}, " $_\n")
          for grep { $code{$_} } keys(%code)
      }
    ' | sort -rn

Of course it has its own set of flaws. One giant feature contribution
can outweight a lot of bugfixes in the average.

-Peff

```

## A Large Angry SCM, 2010-10-23 16:03

Subject: Re: git as an sfc member project
Message-ID: <4CC3076E.7050707@gmail.com>
URL: https://gitlist.dev/e/4CC3076E.7050707%40gmail.com
In-Reply-To: <20101023133948.GA2002@sigill.intra.peff.net>

```
On 10/23/2010 09:39 AM, Jeff King wrote:
> On Sat, Oct 23, 2010 at 11:52:26AM +0000, Ævar Arnfjörð Bjarmason wrote:
>
>> Either way it doesn't matter, since I'm not interested in being a SFC
>> liasion. I just want to hack, not deal with issues like these (but
>> more power to people who want to).
>
> I didn't mean to pick on you, btw. It's just that I was surprised to see
> you, whose first commit was only 6 months ago, in the list of top
> contributors by lines of code. You're productive, but not _that_
> productive. :)

For what it's worth: my nominees are:

	Junio
	Shawn
	Jeff
	?
	?

This group has been involved a long time and each is or has been THE 
maintainer at some point. More importantly, they have consistently 
demonstrated critical thinking with a long term view and the ability to 
handle the "politics" of the mailing list.

In addition to the above, I would like to 2 of the newer members of our 
community in order to bring a different perspective to the 
deliberations. Even better if they are USA based.

```

## Brandon Casey, 2010-10-23 22:48

Subject: Re: git as an sfc member project
Message-ID: <1287874109-15565-1-git-send-email-drafnel@gmail.com>
URL: https://gitlist.dev/e/1287874109-15565-1-git-send-email-drafnel%40gmail.com
In-Reply-To: <cs0GhwZZ9W-pJdXPmTo0di_hrUwMa14GE8dSJeIQtOwrvDdl4KxJ_g@cipher.nrlssc.navy.mil>

```
Here's an updated version of this script if anyone is interested.

It can now do the git-blame calls in parallel.  Use -t #threads.

Here's the usage info:

      ' -c     print count of all lines in all files at the end',
      ' -f     produce file centric output (overrides -l and -s)',
      ' -l     produce longer format',
      ' -s     produce short format, line count and author only',
      ' -ls    Both -l and -s produce an even longer long format',
      ' -t n   set number of threads to use',
      ' -x re  exclude files matching regex',
      ' -v     be more verbose',

Enjoy.

-Brandon

---
 git_blame_stats.perl |  387 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 387 insertions(+), 0 deletions(-)
 create mode 100755 git_blame_stats.perl

diff --git a/git_blame_stats.perl b/git_blame_stats.perl
new file mode 100755
index 0000000..618cf0a
--- /dev/null
+++ b/git_blame_stats.perl
@@ -0,0 +1,387 @@
+#!/usr/bin/perl -w
+
+use lib (split(/:/, $ENV{GITPERLLIB} || '/path/to/git/lib/perl5/site_perl/5.10.0'));
+
+use strict;
+use threads;
+use Thread::Queue;
+use Getopt::Std;
+use Git;
+
+my @LSTREE_OPTS = ('-r', '--name-only');
+my @BLAME_OPTS = ('-C', '-C', '-w', '--incremental');
+
+$Getopt::Std::STANDARD_HELP_VERSION = 1;
+$main::VERSION = 1.0;
+
+sub usage {
+	my $name;
+
+	eval {
+		require File::Basename;
+		$name = File::Basename::basename($0);
+	} or do {
+		$name = substr $0, rindex($0, '/') + 1;
+	};
+
+	print 'Usage: ', $name, ' [--help] [-cflstvx] <rev> [paths...]', "\n";
+}
+
+sub main::HELP_MESSAGE {
+	my $fh = shift;
+
+	eval {select $fh; usage};
+
+	local $\ = "\n";
+	local $, = "\n";
+
+	print $fh '',
+	      'Generate authorship statistics from a git repository.',
+	      '',
+	      'OPTIONS',
+	      ' -c     print count of all lines in all files at the end',
+	      ' -f     produce file centric output (overrides -l and -s)',
+	      ' -l     produce longer format',
+	      ' -s     produce short format, line count and author only',
+	      ' -ls    Both -l and -s produce an even longer long format',
+	      ' -t n   set number of threads to use',
+	      ' -x re  exclude files matching regex',
+	      ' -v     be more verbose',
+	      ' --help this text',
+	      '';
+}
+
+sub parse_blame_entry {
+	my $fh = shift;
+
+	return () unless defined($_ = <$fh>);
+	chomp;
+
+	my ($sha1, $sourceline, $resultline, $num_lines) = split;
+
+	return () unless defined $num_lines;
+
+	my %h = (sha1 => $sha1, sourceline => $sourceline,
+		 resultline => $resultline, lines => $num_lines);
+	while (<$fh>) {
+		chomp;
+		my ($key, $val) = split ' ', $_, 2;
+		$h{$key} = $val;
+		last if m/^filename /;
+	}
+
+	return %h;
+}
+
+sub blame_file {
+	my $repo = shift;
+	my $ref = shift;
+	my $filename = shift;
+	my $authors = shift;
+
+	my ($fh, $ctx) = $repo->command_output_pipe('blame', @BLAME_OPTS,
+		$ref, '--', $filename);
+
+	my %commits;
+	while (my %h = parse_blame_entry $fh) {
+
+		if (! exists $commits{$h{'sha1'}}) {
+
+			if (! exists $authors->{$h{'author'}}->{$filename}) {
+				$authors->{$h{'author'}}->{$filename} = 0;
+			}
+			$commits{$h{'sha1'}} =
+				\$authors->{$h{'author'}}->{$filename};
+		}
+
+		${$commits{$h{'sha1'}}} += $h{'lines'};
+	}
+
+	$repo->command_close_pipe($fh, $ctx);
+}
+
+sub count_total_lines {
+	my $authors = shift;
+
+	my $lines = 0;
+
+	for (values %{$authors}) {
+		for (values %{$_}) { $lines += $_; }
+	}
+
+	return $lines;
+}
+
+# Returns hash
+# key: author name
+# value: authored lines
+sub count_author_lines {
+	my $authors = shift;
+
+	my %alines;
+
+	foreach my $author (keys %{$authors}) {
+		my $lines = 0;
+		for (values %{$authors->{$author}}) { $lines += $_; }
+		$alines{$author} = $lines;
+	}
+
+	return %alines;
+}
+
+# Returns hash
+# key: filename
+# value: lines in file
+sub count_file_lines {
+	my $authors = shift;
+
+	my %flines;
+
+	for (values %{$authors}) {
+		foreach my $file (keys %{$_}) {
+			$flines{$file} += $_->{$file};
+		}
+	}
+
+	return %flines;
+}
+
+# Short format
+#   lines author
+sub print_short {
+	my $authors = shift;
+
+	my %alines = count_author_lines $authors;
+
+	foreach my $author (sort {$alines{$b} <=> $alines{$a}} keys %alines) {
+		printf "%6d  %s\n", $alines{$author}, $author;
+	}
+}
+
+# Long format
+# author (lines):
+#    file_lines filename
+#    file_lines filename
+#    file_lines filename
+sub print_long {
+	my $authors = shift;
+
+	my %alines = count_author_lines $authors;
+
+	foreach my $author (sort {$alines{$b} <=> $alines{$a}} keys %alines) {
+		print $author, ' (', $alines{$author}, '):', "\n";
+		foreach my $file (sort
+		    {$authors->{$author}->{$b} <=> $authors->{$author}->{$a}}
+		    keys %{$authors->{$author}}) {
+			printf "  %10d %s\n", $authors->{$author}->{$file},
+			      $file;
+		}
+	}
+}
+
+# Longer format
+# author (lines, % of all lines):
+#    file_lines (% of author lines) filename
+#    file_lines (% of author lines) filename
+sub print_longer {
+	my $authors = shift;
+
+	my %alines = count_author_lines $authors;
+	my $total_lines = count_total_lines $authors;
+
+	foreach my $author (sort {$alines{$b} <=> $alines{$a}} keys %alines) {
+		printf "%s (%d, %.2f%%):\n", $author, $alines{$author},
+			100. * $alines{$author} / $total_lines;
+		foreach my $file (sort
+		    {$authors->{$author}->{$b} <=> $authors->{$author}->{$a}}
+		    keys %{$authors->{$author}}) {
+			printf "  %10d (%5.2f%%) %s\n",
+			       $authors->{$author}->{$file},
+			       100. *
+			       $authors->{$author}->{$file} / $alines{$author},
+			       $file;
+		}
+	}
+}
+
+# Longer format
+# author (# lines in X files, % of all lines, % of all files):
+#    lines (% of file) file_lines (% of author lines) filename
+#    lines (% of file) file_lines (% of author lines) filename
+sub print_with_file_percentage {
+	my $authors = shift;
+
+	my %alines = count_author_lines $authors;
+	my %flines = count_file_lines $authors;
+	my $total_lines = count_total_lines $authors;
+	my $total_files = scalar(keys %flines);
+
+	foreach my $author (sort {$alines{$b} <=> $alines{$a}} keys %alines) {
+		printf "%s (%d lines in %d files, " .
+		       "%.2f%% of all lines, %.2f%% of all files):\n",
+		       $author, $alines{$author},
+		       scalar(keys %{$authors->{$author}}),
+		       100. * $alines{$author} / $total_lines,
+		       100. * scalar(keys %{$authors->{$author}})/$total_files;
+		foreach my $file (sort
+		    {$authors->{$author}->{$b} <=> $authors->{$author}->{$a}}
+		    keys %{$authors->{$author}}) {
+			printf "  %10d (%6.2f%%) of %6d (%6.2f%%) %s\n",
+			       $authors->{$author}->{$file},
+			       100. *
+			       $authors->{$author}->{$file} / $flines{$file},
+			       $flines{$file},
+			       100. *
+			       $authors->{$author}->{$file} / $alines{$author},
+			       $file;
+		}
+	}
+}
+
+# File perspective format
+# filename (lines):
+#    lines author
+#    lines author
+sub print_with_file_perspective {
+	my $authors = shift;
+
+	my %flines = count_file_lines $authors;
+
+	foreach my $file (sort keys %flines) {
+		my @auths = grep {exists $authors->{$_}->{$file}}
+			keys %{$authors};
+		print $file, ' (', $flines{$file}, '):', "\n";
+		foreach my $author (sort
+		    {$authors->{$b}->{$file} <=> $authors->{$a}->{$file}}
+		    @auths) {
+			printf " %10d %s\n", $authors->{$author}->{$file},
+				$author;
+		}
+	}
+}
+
+
+my $verbose = 0;
+my $output_format = 0;
+my $show_total = 0;
+my $exclude_pattern;
+my $nthreads = 1;
+
+our ($opt_c, $opt_f, $opt_l, $opt_s, $opt_t, $opt_v, $opt_x);
+getopts('cflst:vx:') or die 'Invalid options specified';
+
+	if ($opt_c) {
+		$show_total = 1;
+	}
+	if ($opt_f) {
+		$output_format = 4;
+	} elsif ($opt_l && $opt_s) {
+		$output_format = 3;
+	} elsif ($opt_l) {
+		$output_format = 2;
+	} elsif ($opt_s) {
+		$output_format = 1;
+	}
+	if (defined $opt_t) {
+		$nthreads = $opt_t;
+		if ($nthreads !~ /^\d+$/ || $nthreads < 0) {
+			die 'Error: argument to -t must be integer >= 0';
+		}
+		if ($nthreads == 0) {
+			eval {
+				require Sys::CPU;
+				$nthreads = Sys::CPU::cpu_count();
+			} or $nthreads = 1;
+		}
+	}
+	if ($opt_v) {
+		$verbose = 1;
+	}
+	if ($opt_x) {
+		$exclude_pattern = $opt_x;
+	}
+
+eval {select STDERR; usage; exit 1} unless $#ARGV >= 0;
+
+my %authors;
+my @thr;
+my $repo = Git->repository();
+
+# Spawn ls-tree now, so it can fail before creating the threads
+my ($fh, $ctx) = $repo->command_output_pipe('ls-tree', @LSTREE_OPTS,
+	'--', @ARGV);
+
+print STDERR 'Using ', $nthreads, ' thread(s).', "\n" if $verbose;
+
+my $DataQueue = Thread::Queue->new();
+
+# start the threads
+for (my $i = 0; $i < $nthreads; $i++) {
+	($thr[$i]) = threads->create(sub {
+		my $tid = threads->tid();
+		my %a;
+		while (my $f = $DataQueue->dequeue()) {
+			print STDERR "[$tid]Processing file: $f\n" if $verbose;
+			blame_file $repo, $ARGV[0], $f, \%a;
+		}
+		return %a;
+	});
+}
+
+# now queue up the files
+while (<$fh>) {
+	chomp;
+
+	if ($exclude_pattern && m/$exclude_pattern/o) {
+		print STDERR "Skipping file: $_\n" if $verbose;
+		next;
+	} else {
+		print STDERR "Queuing file: $_\n" if $verbose;
+	}
+
+	$DataQueue->enqueue($_);
+}
+$repo->command_close_pipe($fh, $ctx);
+
+# queue up an undef entry for each thread
+for (my $i = 0; $i < $nthreads; $i++) {
+	$DataQueue->enqueue(undef);
+}
+
+# merge the author hash from each thread
+for (my $i = 0; $i < $nthreads; $i++) {
+	my %th_authors = $thr[$i]->join;
+
+	foreach my $author (keys %th_authors) {
+		if (! exists $authors{$author}) {
+			$authors{$author} = $th_authors{$author};
+			next;
+		}
+		foreach my $filename (keys %{$th_authors{$author}}) {
+			if (! exists $authors{$author}->{$filename}) {
+				$authors{$author}->{$filename} =
+					$th_authors{$author}->{$filename};
+			} else {
+				$authors{$author}->{$filename} +=
+					$th_authors{$author}->{$filename};
+			}
+		}
+	}
+}
+
+
+if ($output_format == 0) {
+	print_long \%authors;
+} elsif ($output_format == 1) {
+	print_short \%authors;
+} elsif ($output_format == 2) {
+	print_longer \%authors;
+} elsif ($output_format == 3) {
+	print_with_file_percentage \%authors;
+} elsif ($output_format == 4) {
+	print_with_file_perspective \%authors;
+}
+
+printf "%6d  total lines\n", count_total_lines(\%authors) if $show_total;
+
+exit;
-- 
1.7.3.1.45.g9855b

```

## Jeff King, 2010-10-26 22:39

Subject: Re: git as an sfc member project
Message-ID: <20101026223925.GA29332@sigill.intra.peff.net>
URL: https://gitlist.dev/e/20101026223925.GA29332%40sigill.intra.peff.net
In-Reply-To: <20101022183027.GA12124@sigill.intra.peff.net>

```
On Fri, Oct 22, 2010 at 02:30:28PM -0400, Jeff King wrote:

> The draft agreement is here:
> 
>   http://peff.net/git-sponsorship-agreement.pdf

OK, this thread seems to have died, which I'll take to mean that
everybody either agrees or doesn't care.

So let's do this:

  1. There will be a committee of 3-5 Gits who will act as liaisons to
     the SFC. A simple majority of that committee is required to
     authorize SFC to do stuff (like disburse money). Existing members
     can be removed from and new members can be added to the committee
     by simple majority vote of the existing committee.

     As for the initial committee, Gitzilla already nominated Junio,
     Shawn, and me. Those sound like a good start to me (assuming the
     other two accept). I'm happy to hear other nominations. I think
     starting with the 3 of us would be fine, too, and we can add people
     who become interested in the management of git and the sfc (and if
     there _is_ anybody who is interested now, please speak up and/or
     nominate yourself; I can think of many people on the list who would
     be good candidates, but the main issue seems to me that nobody is
     interested. :) ).

  2. We'll give 10% of incoming Git money to the SFC for their
     operations (where incoming git money is basically SoC money plus
     any donations SFC collects on our behalf).

Unless I hear objections on the list, this is what I'll present to the
SFC as our plan.

-Peff

```

## Tait, 2010-10-27 07:03

Subject: Re: git as an sfc member project
Message-ID: <20101027070348.GF15635@ece.pdx.edu>
URL: https://gitlist.dev/e/20101027070348.GF15635%40ece.pdx.edu
In-Reply-To: <20101022183027.GA12124@sigill.intra.peff.net>

```
> The draft agreement is here:
>   http://peff.net/git-sponsorship-agreement.pdf

Sorry I'm late to the thread. This agreement brings up one concern for
me. It would make officially make git a United States project based out
of New York, and therefore subject to the laws of New York and the United
States. Among whatever other laws apply, will be export restrictions and
patent law. I don't know whether any part(s) of git would be a concern
under those laws (and I haven't needed to care, until now). Is legal
advice for issues like this part of the services SFC can provide?

```

## Jeff King, 2010-10-27 11:08

Subject: Re: git as an sfc member project
Message-ID: <20101027110807.GB3995@sigill.intra.peff.net>
URL: https://gitlist.dev/e/20101027110807.GB3995%40sigill.intra.peff.net
In-Reply-To: <20101027070348.GF15635@ece.pdx.edu>

```
On Wed, Oct 27, 2010 at 12:03:48AM -0700, Tait wrote:

> > The draft agreement is here:
> >   http://peff.net/git-sponsorship-agreement.pdf
> 
> Sorry I'm late to the thread. This agreement brings up one concern for
> me. It would make officially make git a United States project based out
> of New York, and therefore subject to the laws of New York and the United
> States. Among whatever other laws apply, will be export restrictions and
> patent law. I don't know whether any part(s) of git would be a concern
> under those laws (and I haven't needed to care, until now). Is legal
> advice for issues like this part of the services SFC can provide?

I am not sure that joining the SFC is going to make any difference with
respect to those things. Developers and distributors of the software in
the United States were already subject to such laws, and I don't see how
our dealing with the SFC would create any special obligation for those
outside the US. In particular, it seems to me that git as a legal entity
signing this agreement as the SFC (which legally is really just an
agreement between the SFC and a few members of the project) is different
from git as a community of individuals who happen to contribute and
distribute code.  SFC will not own any copyrights, nor take any
responsibility for distribution.

But I am not a lawyer, of course, and yes, this seems like exactly the
sort of thing we can ask them about. So I've cc'd Bradley. :)

-Peff

```

## Bradley M. Kuhn, 2010-11-02 23:03

Subject: Re: git as an sfc member project
Message-ID: <87wrovpbtw.fsf@ebb.org>
URL: https://gitlist.dev/e/87wrovpbtw.fsf%40ebb.org
In-Reply-To: <20101027110807.GB3995@sigill.intra.peff.net>

```
>> > The draft agreement is here:
>> >   http://peff.net/git-sponsorship-agreement.pdf

> On Wed, Oct 27, 2010 at 12:03:48AM -0700, Tait wrote:

>> This agreement brings up one concern for me. It would make officially
>> make git a United States project based out of New York, and therefore
>> subject to the laws of New York and the United States. Among whatever
>> other laws apply, will be export restrictions and patent law. I don't
>> know whether any part(s) of git would be a concern under those laws
>> (and I haven't needed to care, until now). Is legal advice for issues
>> like this part of the services SFC can provide?

Jeff King wrote on the 27th of October:

> I am not sure that joining the SFC is going to make any difference
> with respect to those things. Developers and distributors of the
> software in the United States were already subject to such laws, and I
> don't see how our dealing with the SFC would create any special
> obligation for those outside the US. In particular, it seems to me
> that git as a legal entity signing this agreement as the SFC (which
> legally is really just an agreement between the SFC and a few members
> of the project) is different from git as a community of individuals
> who happen to contribute and distribute code.  SFC will not own any
> copyrights, nor take any responsibility for distribution.

I believe what Jeff says is basically correct.  The "Git Project" will
be part of a non-profit in New York, and it's true that the Git Project
could be therefore be subject to the laws of New York.  However, it
isn't that much different of some Git developers being in New York and
being subject thereto.  Developers outside the USA continue to operate
as volunteers for the project and aren't impacted any more than they
already are participating in an unincorporated project.

Nevertheless, I'm going to check in with Conservancy's lawyers to verify
there are no serious disadvantages to Git joining a USA non-profit that
weren't already the case anyway since some developers are in the USA
anyway.  I'll respond back when I hear from them.
-- 
Bradley M. Kuhn, Executive Director, Software Freedom Conservancy

```
