* Re: cygwin: push/pull takes very long time
From: Christopher Faylor @ 2006-03-03 0:28 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <20060302215408.GC6183@steel.home>
On Thu, Mar 02, 2006 at 10:54:08PM +0100, Alex Riesen wrote:
>Alex Riesen, Thu, Mar 02, 2006 18:09:23 +0100:
>>I'll cleanup the profiling code and send it as well soon (I had to
>>instrument x*alloc).
>
>This is not exactly the same. It counts free as well, even if that is
>not really interesting - there are places were there is more frees than
>allocs. Probably something missed or a result coming from libc.
>
>Also it is _not_ the code I used for windows. I had to have a global
>variable for argv[0], which needs modification of all main()s, which
>gets too easily out of sync.
I wasn't following this discussion closely so maybe this is useless
information, but for Cygwin you can either use the undocumented global
__argv or you can use /proc/cmdline. /proc/self/cmdline is going to be
pretty slow, however.
It looks like pure Windows console apps define _argv in stdlib.h also
but I've never used this and don't know if it is what it looks like.
cgf
^ permalink raw reply
* Re: [PATCH] fmt-merge-msg: avoid open "-|" list form for Perl 5.6
From: Christopher Faylor @ 2006-03-03 0:14 UTC (permalink / raw)
To: git
In-Reply-To: <20060302220930.GE6183@steel.home>
On Thu, Mar 02, 2006 at 11:09:30PM +0100, Alex Riesen wrote:
>Shawn Pearce, Thu, Mar 02, 2006 17:55:10 +0100:
>>Maybe I missed this but why are people using the native Windows
>>ActiveState Perl with GIT+Cygwin when Cygwin has a Cygwin-ized Perl
>>installation available?
>
>because the people _can't_ use cygwin's perl. There are a lot of
>reasons mainly: administrative, perl script incompatibilities and
>cygwin.dll incompatibilities (if you use perl from cygwin, it'll need
>the correct cygwin.dll. And if a build process uses cygwin tools from,
>for example, QNX Momentics it often comes to clashes).
(Hmm. I wonder if QNX Momentics is YA GPL violator)
If you have multiple versions of the Cygwin DLL on your system and try
to use them all jumbled up together then, yes, you will have problems.
This isn't a perl-specific issue. The solution is to put the latest
version of your Cygwin DLL in your path (presumably in /bin) and delete
all of the older ones.
The newest version is undoubtedly going to be the one downloaded from
the Cygwin web site (http://cygwin.com/) but you can get version
information from the cygwin DLL by using grep:
grep -a "^%%% Cygwin" WHEREEVER/cygwin1.dll
if you are not inclined to install the newest version of Cygwin.
I'm sure that there are incompatibilities between ActiveState perl and
Cygwin's perl which make it hard to use the same scripts in each so I am
not doubting that some people might want to use only ActiveState perl.
I don't see how the multiple Cygwin DLL issue can be a problem only for
Cygwin perl vs. ActiveState perl.
cgf
(who sees a new full-time job looming in the git list)
^ permalink raw reply
* Re: Problems with using git
From: Greg KH @ 2006-03-02 23:58 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Andreas Ericsson, git
In-Reply-To: <7vr75k5s4y.fsf@assigned-by-dhcp.cox.net>
On Thu, Mar 02, 2006 at 03:44:13PM -0800, Junio C Hamano wrote:
> Andreas Ericsson <ae@op5.se> writes:
>
> > Joseph Wakeling wrote:
> >> Thanks very much to all who offered advice on this. :-)
> >> Unfortunately openSUSE is somewhat out of sync not just with git but
> >> in
> >> libraries necessary to install the latest version (libcrypto.so.4,
> >> libssl.so.4). The openssl (0.9.7g-2.4) and openssl-devel (0.9.7g-2)
> >> packages don't contain these but rather contain libcrypto.so.0.9.7 and
> >> libssl.0.9.7. Just in case it's important to future git development.
> >
> > It might be useful for the openSuSE developers, but for git this is
> > totally irrelevant.
>
> True, but I had an impression that we had active developers in
> git community who are close to Suse, and I wonder why this
> hadn't come up earlier. Maybe our userbase and Suse's userbase
> do not overlap much?
Yes, some of us are quite close to SuSE :)
Anyway, the issue is that 10.0 was released about 6 months ago, and
contains the version of git at that time. The latest development tree,
and the latest public betas contain 1.1.3. If you think this should be
newer, I can easily go poke the proper people...
thanks,
greg k-h
^ permalink raw reply
* Re: Problems with using git
From: Junio C Hamano @ 2006-03-02 23:44 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: git
In-Reply-To: <4406FA46.7080608@op5.se>
Andreas Ericsson <ae@op5.se> writes:
> Joseph Wakeling wrote:
>> Thanks very much to all who offered advice on this. :-)
>> Unfortunately openSUSE is somewhat out of sync not just with git but
>> in
>> libraries necessary to install the latest version (libcrypto.so.4,
>> libssl.so.4). The openssl (0.9.7g-2.4) and openssl-devel (0.9.7g-2)
>> packages don't contain these but rather contain libcrypto.so.0.9.7 and
>> libssl.0.9.7. Just in case it's important to future git development.
>
> It might be useful for the openSuSE developers, but for git this is
> totally irrelevant.
True, but I had an impression that we had active developers in
git community who are close to Suse, and I wonder why this
hadn't come up earlier. Maybe our userbase and Suse's userbase
do not overlap much?
^ permalink raw reply
* Re: Problems with using git
From: Greg KH @ 2006-03-02 23:21 UTC (permalink / raw)
To: Joseph Wakeling; +Cc: git
In-Reply-To: <4406F8B1.9050303@webdrake.net>
On Thu, Mar 02, 2006 at 01:52:49PM +0000, Joseph Wakeling wrote:
> Thanks very much to all who offered advice on this. :-)
>
> Unfortunately openSUSE is somewhat out of sync not just with git but in
> libraries necessary to install the latest version (libcrypto.so.4,
> libssl.so.4). The openssl (0.9.7g-2.4) and openssl-devel (0.9.7g-2)
> packages don't contain these but rather contain libcrypto.so.0.9.7 and
> libssl.0.9.7. Just in case it's important to future git development.
If you use the latest openSUSE betas or the FACTORY tree, git 1.1.3 is
available there.
10.0 was released six months or so ago, so that is why it contains an
older version of git.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH] fmt-merge-msg: avoid open "-|" list form for Perl 5.6
From: Linus Torvalds @ 2006-03-02 23:27 UTC (permalink / raw)
To: Alex Riesen; +Cc: Shawn Pearce, git
In-Reply-To: <20060302220930.GE6183@steel.home>
On Thu, 2 Mar 2006, Alex Riesen wrote:
> Shawn Pearce, Thu, Mar 02, 2006 17:55:10 +0100:
>
> > I've been using the Cygwin Perl with GIT without any problems
> > whatsoever. Including the open(I, "-|")... exec(@argv) code that
> > doesn't work correctly in ActiveState and started this whole thread.
>
> Unfortunately...
Here's a stupid first cut at git-fmt-merge-msg in C using the new revlist
library interface.
It's not actually doing exactly the same thing, because I'm a lazy
bastard, but some things it does better.
For example, afaik, when merging multiple branches that had partially been
merged already (ie they had overlapping new stuff), if I read the old perl
code correctly, it would talk about the new stuff multiple times. This one
doesn't.
The things it doesn't do:
- the old one had a limit of 20, the new one has a limit of 10 commits
reported
- the old one was tested, the new one is written by me.
- the old one honored the "merge.summary" git config option. The new one
doesn't.
- the old one did some formatting of the branch message that I don't
follow because I'm not a perl user. The new one just takes the
explanatory message for the branch merging as-is.
But hey, this is all part of my cunning plan to make people get involved
with the new rev-list libification, by giving them things that _almost_
work, but might need some tweaking.
Linus
--- snip snip for "fmt-merge-msg.c" snip snip---
/*
* fmt-merge-msg.c
*
* Magic auto-generation of merge messages.
*
* Copyright (C) 2006 Linus Torvalds and his army of programming ferrets
*/
#include "cache.h"
#include "commit.h"
#include "revision.h"
static void show_commit(struct commit *commit)
{
char buffer[256];
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, buffer, sizeof(buffer), 0);
printf(" * %s\n", buffer);
}
int main(int argc, char **argv)
{
struct rev_info revs;
struct commit *commit;
unsigned char sha1[20];
char buffer[256];
setup_revisions(0, NULL, &revs, NULL);
if (get_sha1("HEAD", sha1) < 0)
die("no HEAD revision");
commit = lookup_commit_reference(sha1);
if (!commit)
die("no HEAD revision");
commit->object.flags |= UNINTERESTING;
insert_by_date(commit, &revs.commits);
revs.topo_order = 1;
revs.limited = 1;
while (fgets(buffer, sizeof(buffer), stdin)) {
int max;
char *marker;
if (get_sha1_hex(buffer, sha1) < 0)
continue;
commit = lookup_commit_reference(sha1);
if (!commit)
continue;
/*
* Format after the SHA1:
* <tab>marker<tab><type>'<name>' of <src>'
*
* where string is "not-for-merge" if
* we're not interested in this one,
* and empty otherwise.
*/
marker = buffer + 40;
if (*marker++ != '\t')
continue;
if (*marker++ != '\t')
continue;
printf("Merge %s", marker);
insert_by_date(commit, &revs.commits);
prepare_revision_walk(&revs);
max = 10;
while ((commit = get_revision(&revs)) != NULL) {
int n = --max;
if (n > 0)
show_commit(commit);
else if (!n)
printf(" ...");
}
}
}
^ permalink raw reply
* [PATCH] annotate should number lines starting with 1
From: Luck, Tony @ 2006-03-02 23:27 UTC (permalink / raw)
To: git
C programmers are well used to counting from zero, but every
other text file tool starts counting from 1.
Signed-off-by: Tony Luck <tony.luck@intel.com>
---
diff --git a/git-annotate.perl b/git-annotate.perl
index 08d479f..d93ee19 100755
--- a/git-annotate.perl
+++ b/git-annotate.perl
@@ -128,7 +128,7 @@ foreach my $l (@filelines) {
}
printf("%s\t(%10s\t%10s\t%d)%s\n", $rev, $committer,
- format_date($date), $i++, $output);
+ format_date($date), ++$i, $output);
}
sub init_claim {
^ permalink raw reply related
* Re: git-cvsimport broken?
From: Martin Langhoff @ 2006-03-02 22:56 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: git
In-Reply-To: <440775FB.4000300@zytor.com>
On 3/3/06, H. Peter Anvin <hpa@zytor.com> wrote:
> Have other people seen this problem?
Been running imports recently (with a cvsimport not more that 3 days
old). No problem.
m
^ permalink raw reply
* Re: git-cvsimport broken?
From: H. Peter Anvin @ 2006-03-02 22:54 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: git
In-Reply-To: <440775FB.4000300@zytor.com>
H. Peter Anvin wrote:
> I have started consistently getting the following error trying to do a
> git-cvsimport into an empty directory:
>
> + git cvsimport -C /home/hpa/local/kernel-cvs-import -k -u -m -A
> /home/hpa/local/authors -d /home/hpa/local/cvsroot
> project/sw/kernel/linux-2.6
> cp: cannot stat `/export/hpa/kernel-cvs-import/.git/refs/heads/origin':
> No such file or directory
> fatal: master: not a valid SHA1
> fatal: 'HEAD': No such file or directory
> usage: git-read-tree (<sha> | -m [-u | -i] <sha1> [<sha2> [<sha3>]])
> checkout failed: 256
>
Turns out to be user error (the CVS module is "projects", not
"project"), but that probably indicates something that could use a
better error message, in particular: if there are zero changesets.
-hpa
^ permalink raw reply
* git-cvsimport broken?
From: H. Peter Anvin @ 2006-03-02 22:47 UTC (permalink / raw)
To: git
I have started consistently getting the following error trying to do a
git-cvsimport into an empty directory:
+ git cvsimport -C /home/hpa/local/kernel-cvs-import -k -u -m -A
/home/hpa/local/authors -d /home/hpa/local/cvsroot
project/sw/kernel/linux-2.6
cp: cannot stat `/export/hpa/kernel-cvs-import/.git/refs/heads/origin':
No such file or directory
fatal: master: not a valid SHA1
fatal: 'HEAD': No such file or directory
usage: git-read-tree (<sha> | -m [-u | -i] <sha1> [<sha2> [<sha3>]])
checkout failed: 256
After failing, the directory in question contains the output of
git-init-db, including a HEAD file which contains a symbolic reference
to a nonexistent branch (which makes sense, since there has been no
checkins yet.)
Have other people seen this problem?
-hpa
^ permalink raw reply
* Re: impure renames / history tracking
From: linux @ 2006-03-02 22:24 UTC (permalink / raw)
To: git, paul
>> Yes, but imo a poor one, as you're losing all the history.
>
> Well, not per se. You might keep the original 'detail' branch. It's a
> terminal branch obviously, you can't pull master's changes to it once
> the aggregate patch goes into master. But you can keep it around.
Actually, you can! That's what the "ours" merge stratgy is for!
It creates a merge whose result is a verbatim copy of the first parent.
The intended use is for when you've cherry-picked or otherwise manually
merged everything interesting from a branch and want to tie up the loose
end so you can delete the branch name.
^ permalink raw reply
* Re: fatal: unexpected EOF
From: Alex Riesen @ 2006-03-02 22:23 UTC (permalink / raw)
To: Tony Luck; +Cc: Brian Gerst, Linus Torvalds, Git Mailing List, Junio C Hamano
In-Reply-To: <12c511ca0602280759t2e584a4bkd7b6f4d97ade92f7@mail.gmail.com>
Tony Luck, Tue, Feb 28, 2006 16:59:09 +0100:
> > I doubt it is a problem with mirroring, since it affects all repos
> > (kernel, git, cogito, etc.) at the same time.
>
> Ditto. Jes has been grumbling overnight that he can't get a reliable pull
> from my kernel repo ... and that hasn't been updated in 10 days, so the
> mirror code shouldn't be touching it. His error was:
>
> fatal: read error (Connection reset by peer)
> Fetch failure: git://git.kernel.org/pub/...
>
> He also reported that after a few retries it worked.
I had the problems too and even made the patch (below) to see what it
was. I saw to A-records for zeus-pub.kernel.org (git.kernel.org is an
alias of it) where one of them (I believe it was 204.152.191.37)
sometimes didn't answer or dropped connection.
---
connect.c | 41 +++++++++++++++++++++++++++++++++++++++--
1 files changed, 39 insertions(+), 2 deletions(-)
b5ceb5f3f1c6ff62a3ccb13f360a34b07b9c8482
diff --git a/connect.c b/connect.c
index 3f2d65c..e911fde 100644
--- a/connect.c
+++ b/connect.c
@@ -322,6 +322,23 @@ static enum protocol get_protocol(const
#ifndef NO_IPV6
+static const char *ai_name(const struct addrinfo *ai)
+{
+ static char addr[INET_ADDRSTRLEN];
+ if ( AF_INET == ai->ai_family ) {
+ struct sockaddr_in *in;
+ in = (struct sockaddr_in *)ai->ai_addr;
+ inet_ntop(ai->ai_family, &in->sin_addr, addr, sizeof(addr));
+ } else if ( AF_INET6 == ai->ai_family ) {
+ struct sockaddr_in6 *in;
+ in = (struct sockaddr_in6 *)ai->ai_addr;
+ inet_ntop(ai->ai_family, &in->sin6_addr, addr, sizeof(addr));
+ } else {
+ strcpy(addr, "(unknown)");
+ }
+ return addr;
+}
+
static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
{
int sockfd = -1;
@@ -329,6 +346,7 @@ static int git_tcp_connect(int fd[2], co
char *port = STR(DEFAULT_GIT_PORT);
struct addrinfo hints, *ai0, *ai;
int gai;
+ int cnt = 0;
if (host[0] == '[') {
end = strchr(host + 1, ']');
@@ -355,15 +373,23 @@ static int git_tcp_connect(int fd[2], co
if (gai)
die("Unable to look up %s (%s)", host, gai_strerror(gai));
- for (ai0 = ai; ai; ai = ai->ai_next) {
+ for (ai0 = ai; ai; ++cnt, ai = ai->ai_next) {
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sockfd < 0)
continue;
if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
+ fprintf(stderr, "%s: %s[%d: %s]: net=%s, errno=%s\n",
+ argv0,
+ host,
+ cnt,
+ ai_name(ai),
+ hstrerror(h_errno),
+ strerror(errno));
close(sockfd);
sockfd = -1;
continue;
}
+ fprintf(stderr, "using %s[%s]\n", host, ai_name(ai));
break;
}
@@ -389,6 +415,7 @@ static int git_tcp_connect(int fd[2], co
struct sockaddr_in sa;
char **ap;
unsigned int nport;
+ int cnt;
if (host[0] == '[') {
end = strchr(host + 1, ']');
@@ -420,7 +447,7 @@ static int git_tcp_connect(int fd[2], co
nport = se->s_port;
}
- for (ap = he->h_addr_list; *ap; ap++) {
+ for (cnt = 0, ap = he->h_addr_list; *ap; ap++, cnt++) {
sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);
if (sockfd < 0)
continue;
@@ -431,10 +458,20 @@ static int git_tcp_connect(int fd[2], co
memcpy(&sa.sin_addr, *ap, he->h_length);
if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
+ fprintf(stderr, "%s: %s[%d: %s]: net=%s, errno=%s\n",
+ argv0,
+ host,
+ cnt,
+ inet_ntoa(*(struct in_addr *)&sa.sin_addr),
+ hstrerror(h_errno),
+ strerror(errno));
close(sockfd);
sockfd = -1;
continue;
}
+ fprintf(stderr, "using %s[%s]\n",
+ host,
+ inet_ntoa(*(struct in_addr *)&sa.sin_addr));
break;
}
--
1.2.3.g3987
^ permalink raw reply related
* Re: [PATCH] fmt-merge-msg: avoid open "-|" list form for Perl 5.6
From: Alex Riesen @ 2006-03-02 22:09 UTC (permalink / raw)
To: Shawn Pearce; +Cc: git
In-Reply-To: <20060302165510.GB18929@spearce.org>
Shawn Pearce, Thu, Mar 02, 2006 17:55:10 +0100:
> Maybe I missed this but why are people using the native Windows
> ActiveState Perl with GIT+Cygwin when Cygwin has a Cygwin-ized Perl
> installation available?
because the people _can't_ use cygwin's perl. There are a lot of
reasons mainly: administrative, perl script incompatibilities and
cygwin.dll incompatibilities (if you use perl from cygwin, it'll need
the correct cygwin.dll. And if a build process uses cygwin tools from,
for example, QNX Momentics it often comes to clashes).
> I've been using the Cygwin Perl with GIT without any problems
> whatsoever. Including the open(I, "-|")... exec(@argv) code that
> doesn't work correctly in ActiveState and started this whole thread.
Unfortunately...
^ permalink raw reply
* Re: impure renames / history tracking
From: Andreas Ericsson @ 2006-03-02 22:06 UTC (permalink / raw)
To: Paul Jakma; +Cc: git list
In-Reply-To: <Pine.LNX.4.64.0603012129310.13612@sheen.jakma.org>
Paul Jakma wrote:
> On Wed, 1 Mar 2006, Andreas Ericsson wrote:
>
>> It's completely impossible to fold *ALL* the history into a single
>> commit, and since you want heuristics I would imagine you wouldn't
>> want that either.
>
>
> I want to know whether additional meta-data to help the existing
> heuristics would be acceptable. From a discussion on #git yesterday I
> gather the best way forward would to be to first prototype something
> keeping state in a file in .git.
>
> All that's needed really is something that relates the following 3 things:
>
> commit-id obj1-id obj2-id
>
> Ie: For <commit-id>, <obj1-id> is similar to <obj2-id>.
>
> Maintaining this state could be done via the git-mv/rename wrappers and
> an additional git-edit wrapper. Those who are quite happy with the
> existing diff-input only similarity heuristics wouldn't have to bother
> using a git-edit wrapper obviously, those who want to let git gather
> additional 'similarity hint' in this way could.
>
> Aside:
>
> Git might be easier to extend generally if it adopted just /one/ new
> core header, say "see-also" - that could serve as a pointer to arbitrary
> commit-related meta-info objects that aren't of immediate interest to
> either:
>
> a) core git
>
> or
>
> b) the user
>
Things that aren't of interest to either core git or the user is already
handled properly. It's called "cruft". ;)
However, I see what you're trying for here. Something like the X-*
headers inside a mailer. Not all MUA's understand them, but if they do
they can make use of them to the users benefit.
> Format:
>
> see-also <word> <obj-id>
>
> E.g.:
>
> see-also similars <obj-id>
>
> Where <obj-id> would list the 'commit obj1 obj2', but just as:
>
> obj1 obj2
>
> Would ultimately be neater than fishing around in .git/, and would allow
> other extensions in the future too.
>
> The <word> identifier preferably would need to be centrally co-ordinated.
>
With X-* headers I don't see why it should have to be. Only the X-* part
is mentioned in the RFC, so with a proper format Junio won't have to
coordinate cross-SCM tools, git-tortoise, etc, etc...
>> I'm confused. First you say you want to have one single mega-patch for
>> each commit, then you say you want to be able to follow history back.
>> It's like deciding to throw away your wallet and then trying to get
>> someone to pick it up and carry it around for you.
>
>
> I'm not sure why think mega-patch. Collapsing a bunch of commits related
> to one project need not result in a big patch relative to the repository
> as a whole.
>
Mainly I think it's because you mentioned several renames of a single
file and many files renamed + rewritten (beyond gits current ability of
recognizing it). That's definitely a mega-patch in my book.
> Where the project concerned is like BSD, not
> just a kernel but a complete userland (so 1.1GB of source code).
>
<just curious>
Such a large project surely must be split in several smaller
sub-projects? GNU is, after all, several small (and not so small)
components. X works the same way. Linux is a large project, but each
compartment of code can be managed on its own, so long as they adhere to
the ABI hooking them back in to the kernel core.
</just curious>
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* Re: [PATCH] fmt-merge-msg: avoid open "-|" list form for Perl 5.6
From: Alex Riesen @ 2006-03-02 22:01 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: Christopher Faylor, git
In-Reply-To: <44072DEF.1070906@op5.se>
Andreas Ericsson, Thu, Mar 02, 2006 18:39:59 +0100:
> Ye gawds, Alex. If you complained this much to your employer you'd get
> to run whatever OS you want.
I never stopped. I usually manage to convince them, it just hasn't
happened here yet.
^ permalink raw reply
* Re: cygwin: push/pull takes very long time
From: Alex Riesen @ 2006-03-02 21:54 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <81b0412b0603020909p179ed9bx4ed8fc2ddf77e868@mail.gmail.com>
Alex Riesen, Thu, Mar 02, 2006 18:09:23 +0100:
> I'll cleanup the profiling code and send it as well soon
> (I had to instrument x*alloc).
This is not exactly the same. It counts free as well, even if that is
not really interesting - there are places were there is more frees
than allocs. Probably something missed or a result coming from libc.
Also it is _not_ the code I used for windows. I had to have a global
variable for argv[0], which needs modification of all main()s, which
gets too easily out of sync.
BTW, maybe someone has an idea as to how attach valgrind to everything?
(I mean, without changing every script. Maybe modify git.c?)
Anyway, here it is, could be useful for something.
---
diff --git a/Makefile b/Makefile
index a5eb0c4..18fc802 100644
--- a/Makefile
+++ b/Makefile
@@ -206,7 +206,7 @@ LIB_OBJS = \
quote.o read-cache.o refs.o run-command.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
- fetch-clone.o \
+ fetch-clone.o alloc.o \
$(DIFF_OBJS)
LIBS = $(LIB_FILE)
diff --git a/alloc.c b/alloc.c
new file mode 100644
index 0000000..76727e6
--- /dev/null
+++ b/alloc.c
@@ -0,0 +1,108 @@
+/* simple allocation logging */
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "git-compat-util.h"
+
+#undef free
+
+#define SHIFT 2
+static unsigned cnts[12] = {0,0,0,0, 0,0,0,0};
+static unsigned fcnt = 0;
+
+static int exit_hook = 1;
+
+static void alloc_profile()
+{
+ char argv0[PATH_MAX];
+ FILE *fp;
+ fp = fopen("/proc/self/cmdline", "r");
+ if ( !fp ) {
+ sprintf(argv0, "%d", getpid());
+ } else {
+ fread(argv0, sizeof(argv0), 1, fp);
+ fclose(fp);
+ char *s = strrchr(argv0, '/');
+ if ( s )
+ memmove(argv0, s + 1, strlen(s));
+ }
+ fp = fopen("/tmp/git-alloc", "ab");
+ if ( !fp )
+ return;
+ unsigned i, c = 0;
+ for ( i = 0; i < sizeof(cnts)/sizeof(*cnts); ++i ) {
+ if ( !cnts[i] )
+ continue;
+ fprintf(fp, "%s %u %u:%u %u times\n",
+ argv0,
+ i,
+ i ? 1 << i * SHIFT: 0,
+ 1 << (i+1) * SHIFT,
+ cnts[i]);
+ c += cnts[i];
+ }
+ fprintf(fp, "%s alloc-free = %u\n", argv0, c - fcnt);
+ fclose(fp);
+}
+
+static inline void count(size_t size)
+{
+ if ( exit_hook ) {
+ exit_hook = 0;
+ atexit(alloc_profile);
+ }
+ unsigned i = 0;
+ while ( size && i < sizeof(cnts)/sizeof(*cnts) ) {
+ size >>= SHIFT;
+ if ( size )
+ ++i;
+ else {
+ ++cnts[i];
+ return;
+ }
+ }
+ ++cnts[sizeof(cnts)/sizeof(*cnts)-1];
+}
+
+void *xmalloc(size_t size)
+{
+ void *ret = malloc(size);
+ count(size);
+ if (!ret && !size)
+ ret = malloc(1);
+ if (!ret)
+ die("Out of memory, malloc failed, %u bytes requested", size);
+ return ret;
+}
+
+void *xrealloc(void *ptr, size_t size)
+{
+ void *ret = realloc(ptr, size);
+ count(size);
+ if (!ret && !size)
+ ret = realloc(ptr, 1);
+ if (!ret)
+ die("Out of memory, realloc failed, %u bytes requested", size);
+ return ret;
+}
+
+void *xcalloc(size_t nmemb, size_t size)
+{
+ void *ret = calloc(nmemb, size);
+ count(size);
+ if (!ret && (!nmemb || !size))
+ ret = calloc(1, 1);
+ if (!ret)
+ die("Out of memory, calloc failed");
+ return ret;
+}
+
+void xfree(void *ptr)
+{
+ if ( !ptr )
+ return;
+ free(ptr);
+ ++fcnt;
+}
+
diff --git a/git-compat-util.h b/git-compat-util.h
index f982b8e..ab4f855 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -73,35 +73,11 @@ extern void gitunsetenv(const char *);
extern char *gitstrcasestr(const char *haystack, const char *needle);
#endif
-static inline void *xmalloc(size_t size)
-{
- void *ret = malloc(size);
- if (!ret && !size)
- ret = malloc(1);
- if (!ret)
- die("Out of memory, malloc failed");
- return ret;
-}
-
-static inline void *xrealloc(void *ptr, size_t size)
-{
- void *ret = realloc(ptr, size);
- if (!ret && !size)
- ret = realloc(ptr, 1);
- if (!ret)
- die("Out of memory, realloc failed");
- return ret;
-}
-
-static inline void *xcalloc(size_t nmemb, size_t size)
-{
- void *ret = calloc(nmemb, size);
- if (!ret && (!nmemb || !size))
- ret = calloc(1, 1);
- if (!ret)
- die("Out of memory, calloc failed");
- return ret;
-}
+void *xmalloc(size_t size);
+void *xrealloc(void *ptr, size_t size);
+void *xcalloc(size_t nmemb, size_t size);
+void xfree(void *ptr);
+#define free(p) xfree(p)
static inline ssize_t xread(int fd, void *buf, size_t len)
{
diff --git a/prof-decode.sh b/prof-decode.sh
new file mode 100755
index 0000000..9c07e05
--- /dev/null
+++ b/prof-decode.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+if [ $# = 0 ]; then
+ set -- /tmp/git-alloc
+fi
+cat "$@" | perl -e '
+ while(<>) {
+ if (/(\S*) \d+ (\d+:\d+) (\d+)/) {
+ $c{$1}->{$2} += $3;
+ $c{$1}->{all} += $3
+ }
+ if (/(\S*) alloc-free = (\d+)/) { $d{$1} += $2 }
+ }
+ foreach $k (sort {$c{$b}->{all} <=> $c{$a}->{all}} grep {$c{$_}} keys %c) {
+ for ( sort {
+ if ( $a eq "all" ) { -1 }
+ elsif ( $b eq "all" ) { 1 }
+ else {
+ "$a $b" =~ /(\d+):\d+ (\d+):\d+/;
+ $1 <=> $2 }
+ } grep { $c{$k}->{$_} } keys %{$c{$k}} ) {
+ printf "%20s\t%20s\t%d\n", $k, $_, $c{$k}->{$_}
+ }
+ printf "%20s\t%d leaks\n\n", $k, $d{$k}
+ }
+'
^ permalink raw reply related
* Re: [PATCH] git-blame, take 2
From: Linus Torvalds @ 2006-03-02 21:45 UTC (permalink / raw)
To: Fredrik Kuivinen; +Cc: git, junkio
In-Reply-To: <20060302212816.GA11015@c165.ib.student.liu.se>
On Thu, 2 Mar 2006, Fredrik Kuivinen wrote:
>
> Here is an updated version of git-blame. The main changes compared to
> the first version are:
>
> * Use the new revision.h interface to do the revision walking
...
> +
> + num_args = 0;
> + args[num_args++] = NULL;
> + args[num_args++] = "--topo-order";
> + args[num_args++] = "--remove-empty";
> + args[num_args++] = argv[1];
> + args[num_args++] = "--";
> + args[num_args++] = filename;
> + args[num_args] = NULL;
> +
> + setup_revisions(num_args, args, &rev, "HEAD");
Ok, that wasn't really supposed to be necessary.
I guess the above works fine, but it should be perfectly fine to also just
do a nicer helper function that just initializes rev_info with something
like
memset(revs, 0, sizeof(*revs));
revs->max_count = -1;
revs->min_date = -1;
revs->max_date = -1;
revs->dense = 1;
and then you can just fill in the things you want to directly. Just add
the commits you want to populate things with to the "revs->commits" list,
the paths to "revs->paths", set "revs->limited" to 1, and then do the
"prepare_revision_walk()" and start walking.
But hey, the above "fake the arguments" thing also works. It makes me
wince a bit, though.
Linus
^ permalink raw reply
* [PATCH] git-blame, take 2
From: Fredrik Kuivinen @ 2006-03-02 21:28 UTC (permalink / raw)
To: git; +Cc: junkio
Hi,
Here is an updated version of git-blame. The main changes compared to
the first version are:
* Use the new revision.h interface to do the revision walking
* Do the right thing in a lot of more cases than before. In particular
parallel development tracks are hopefully handled sanely.
* Lots of clean-up
It still won't follow file renames though. The patch is against
current pu.
There are still some differences in the output between git-blame and
git-annotate. For example, in 'Makefile' git-blame assigns lines
354-358 to 455a7f3275d264f6e66045b92c83747ec461dda5 and git-annotate
assigns the same lines to 79a9d8ea0d88a3667ad19be8e705405ab5d896f1.
I think git-blame is correct in this case. This patterns occur in
several other places, git-annotate seems to sometimes assign lines to
merge commits when the lines actually changed in some other commit
which precedes the merge.
- Fredrik
Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
---
blame.c | 888 ++++++++++++++++++++++++++++++++++++---------------------------
1 files changed, 504 insertions(+), 384 deletions(-)
3a81d6759da19a4776102a405505f35811320d61
diff --git a/blame.c b/blame.c
index dbce7e2..0b5d6bd 100644
--- a/blame.c
+++ b/blame.c
@@ -1,4 +1,10 @@
+/*
+ * Copyright (C) 2006, Fredrik Kuivinen <freku045@student.liu.se>
+ */
+
#include <assert.h>
+#include <time.h>
+#include <sys/time.h>
#include "cache.h"
#include "refs.h"
@@ -7,436 +13,550 @@
#include "tree.h"
#include "blob.h"
#include "diff.h"
+#include "revision.h"
#define DEBUG 0
-struct commit** blame_lines;
+struct commit **blame_lines;
int num_blame_lines;
-struct util_info
-{
- int* line_map;
- int num_lines;
- unsigned char sha1[20]; /* blob sha, not commit! */
- char* buf;
- unsigned long size;
+struct util_info {
+ int *line_map;
+ unsigned char sha1[20]; /* blob sha, not commit! */
+ char *buf;
+ unsigned long size;
+ int num_lines;
// const char* path;
};
-struct chunk
-{
- int off1, len1; // ---
- int off2, len2; // +++
+struct chunk {
+ int off1, len1; // ---
+ int off2, len2; // +++
};
-struct patch
-{
- struct chunk* chunks;
- int num;
+struct patch {
+ struct chunk *chunks;
+ int num;
};
-static void get_blob(struct commit* commit);
-
-int num_get_patch = 0;
-int num_commits = 0;
-
-struct patch* get_patch(struct commit* commit, struct commit* other)
-{
- struct patch* ret = xmalloc(sizeof(struct patch));
- ret->chunks = NULL;
- ret->num = 0;
-
- struct util_info* info_c = (struct util_info*) commit->object.util;
- struct util_info* info_o = (struct util_info*) other->object.util;
-
- if(!memcmp(info_c->sha1, info_o->sha1, 20))
- return ret;
-
- get_blob(commit);
- get_blob(other);
-
- FILE* fout = fopen("/tmp/git-blame-tmp1", "w");
- if(!fout)
- die("fopen tmp1 failed: %s", strerror(errno));
-
- if(fwrite(info_c->buf, info_c->size, 1, fout) != 1)
- die("fwrite 1 failed: %s", strerror(errno));
- fclose(fout);
-
- fout = fopen("/tmp/git-blame-tmp2", "w");
- if(!fout)
- die("fopen tmp2 failed: %s", strerror(errno));
-
- if(fwrite(info_o->buf, info_o->size, 1, fout) != 1)
- die("fwrite 2 failed: %s", strerror(errno));
- fclose(fout);
-
- FILE* fin = popen("diff -u0 /tmp/git-blame-tmp1 /tmp/git-blame-tmp2", "r");
- if(!fin)
- die("popen failed: %s", strerror(errno));
-
- char buf[1024];
- while(fgets(buf, sizeof(buf), fin)) {
- if(buf[0] != '@' || buf[1] != '@')
- continue;
-
- if(DEBUG)
- printf("chunk line: %s", buf);
- ret->num++;
- ret->chunks = xrealloc(ret->chunks, sizeof(struct chunk)*ret->num);
- struct chunk* chunk = &ret->chunks[ret->num-1];
-
- assert(!strncmp(buf, "@@ -", 4));
-
- char* start = buf+4;
- char* sp = index(start, ' ');
- *sp = '\0';
- if(index(start, ',')) {
- int ret = sscanf(start, "%d,%d", &chunk->off1, &chunk->len1);
- assert(ret == 2);
- } else {
- int ret = sscanf(start, "%d", &chunk->off1);
- assert(ret == 1);
- chunk->len1 = 1;
- }
- *sp = ' ';
-
- start = sp+1;
- sp = index(start, ' ');
- *sp = '\0';
- if(index(start, ',')) {
- int ret = sscanf(start, "%d,%d", &chunk->off2, &chunk->len2);
- assert(ret == 2);
- } else {
- int ret = sscanf(start, "%d", &chunk->off2);
- assert(ret == 1);
- chunk->len2 = 1;
- }
- *sp = ' ';
-
- if(chunk->off1 > 0)
- chunk->off1 -= 1;
- if(chunk->off2 > 0)
- chunk->off2 -= 1;
-
- assert(chunk->off1 >= 0);
- assert(chunk->off2 >= 0);
- }
- fclose(fin);
-
- num_get_patch++;
- return ret;
-}
-
-void free_patch(struct patch* p)
-{
- free(p->chunks);
- free(p);
-}
-
-static int get_blob_sha1_internal(unsigned char *sha1, const char *base, int baselen,
- const char *pathname, unsigned mode, int stage);
+static void get_blob(struct commit *commit);
+/* Only used for statistics */
+static int num_get_patch = 0;
+static int num_commits = 0;
+static int patch_time = 0;
+
+#define TEMPFILE_PATH_LEN 60
+static struct patch *get_patch(struct commit *commit, struct commit *other)
+{
+ struct patch *ret;
+ struct util_info *info_c = (struct util_info *)commit->object.util;
+ struct util_info *info_o = (struct util_info *)other->object.util;
+ char tmp_path1[TEMPFILE_PATH_LEN], tmp_path2[TEMPFILE_PATH_LEN];
+ char diff_cmd[TEMPFILE_PATH_LEN*2 + 20];
+ struct timeval tv_start, tv_end;
+ int fd;
+ FILE *fin;
+ char buf[1024];
+
+ ret = xmalloc(sizeof(struct patch));
+ ret->chunks = NULL;
+ ret->num = 0;
+
+ get_blob(commit);
+ get_blob(other);
+
+ gettimeofday(&tv_start, NULL);
+
+ fd = git_mkstemp(tmp_path1, TEMPFILE_PATH_LEN, "git-blame-XXXXXX");
+ if (fd < 0)
+ die("unable to create temp-file: %s", strerror(errno));
+
+ if (xwrite(fd, info_c->buf, info_c->size) != info_c->size)
+ die("write failed: %s", strerror(errno));
+ close(fd);
+
+ fd = git_mkstemp(tmp_path2, TEMPFILE_PATH_LEN, "git-blame-XXXXXX");
+ if (fd < 0)
+ die("unable to create temp-file: %s", strerror(errno));
+
+ if (xwrite(fd, info_o->buf, info_o->size) != info_o->size)
+ die("write failed: %s", strerror(errno));
+ close(fd);
+
+ sprintf(diff_cmd, "diff -u0 %s %s", tmp_path1, tmp_path2);
+ fin = popen(diff_cmd, "r");
+ if (!fin)
+ die("popen failed: %s", strerror(errno));
+
+ while (fgets(buf, sizeof(buf), fin)) {
+ struct chunk *chunk;
+ char *start, *sp;
+
+ if (buf[0] != '@' || buf[1] != '@')
+ continue;
+
+ if (DEBUG)
+ printf("chunk line: %s", buf);
+ ret->num++;
+ ret->chunks = xrealloc(ret->chunks,
+ sizeof(struct chunk) * ret->num);
+ chunk = &ret->chunks[ret->num - 1];
+
+ assert(!strncmp(buf, "@@ -", 4));
+
+ start = buf + 4;
+ sp = index(start, ' ');
+ *sp = '\0';
+ if (index(start, ',')) {
+ int ret =
+ sscanf(start, "%d,%d", &chunk->off1, &chunk->len1);
+ assert(ret == 2);
+ } else {
+ int ret = sscanf(start, "%d", &chunk->off1);
+ assert(ret == 1);
+ chunk->len1 = 1;
+ }
+ *sp = ' ';
+
+ start = sp + 1;
+ sp = index(start, ' ');
+ *sp = '\0';
+ if (index(start, ',')) {
+ int ret =
+ sscanf(start, "%d,%d", &chunk->off2, &chunk->len2);
+ assert(ret == 2);
+ } else {
+ int ret = sscanf(start, "%d", &chunk->off2);
+ assert(ret == 1);
+ chunk->len2 = 1;
+ }
+ *sp = ' ';
+
+ if (chunk->len1 == 0)
+ chunk->off1++;
+ if (chunk->len2 == 0)
+ chunk->off2++;
+
+ if (chunk->off1 > 0)
+ chunk->off1--;
+ if (chunk->off2 > 0)
+ chunk->off2--;
+
+ assert(chunk->off1 >= 0);
+ assert(chunk->off2 >= 0);
+ }
+ pclose(fin);
+ unlink(tmp_path1);
+ unlink(tmp_path2);
+
+ gettimeofday(&tv_end, NULL);
+ patch_time += 1000000 * (tv_end.tv_sec - tv_start.tv_sec) +
+ tv_end.tv_usec - tv_start.tv_usec;
+
+ num_get_patch++;
+ return ret;
+}
+
+static void free_patch(struct patch *p)
+{
+ free(p->chunks);
+ free(p);
+}
+
+static int get_blob_sha1_internal(unsigned char *sha1, const char *base,
+ int baselen, const char *pathname,
+ unsigned mode, int stage);
static unsigned char blob_sha1[20];
-static int get_blob_sha1(struct tree* t, const char* pathname, unsigned char* sha1)
+static int get_blob_sha1(struct tree *t, const char *pathname,
+ unsigned char *sha1)
{
- const char *pathspec[2];
- pathspec[0] = pathname;
- pathspec[1] = NULL;
- memset(blob_sha1, 0, sizeof(blob_sha1));
- read_tree_recursive(t, "", 0, 0, pathspec, get_blob_sha1_internal);
+ int i;
+ const char *pathspec[2];
+ pathspec[0] = pathname;
+ pathspec[1] = NULL;
+ memset(blob_sha1, 0, sizeof(blob_sha1));
+ read_tree_recursive(t, "", 0, 0, pathspec, get_blob_sha1_internal);
- int i;
- for(i = 0; i < 20; i++) {
- if(blob_sha1[i] != 0)
- break;
- }
+ for (i = 0; i < 20; i++) {
+ if (blob_sha1[i] != 0)
+ break;
+ }
- if(i == 20)
- return -1;
+ if (i == 20)
+ return -1;
- memcpy(sha1, blob_sha1, 20);
- return 0;
+ memcpy(sha1, blob_sha1, 20);
+ return 0;
}
-static int get_blob_sha1_internal(unsigned char *sha1, const char *base, int baselen,
- const char *pathname, unsigned mode, int stage)
+static int get_blob_sha1_internal(unsigned char *sha1, const char *base,
+ int baselen, const char *pathname,
+ unsigned mode, int stage)
{
-// printf("Got blob: %s base: '%s' baselen: %d pathname: '%s' mode: %o stage: %d\n",
-// sha1_to_hex(sha1), base, baselen, pathname, mode, stage);
-
- if(S_ISDIR(mode))
- return READ_TREE_RECURSIVE;
+ if (S_ISDIR(mode))
+ return READ_TREE_RECURSIVE;
- memcpy(blob_sha1, sha1, 20);
- return -1;
+ memcpy(blob_sha1, sha1, 20);
+ return -1;
}
-static void get_blob(struct commit* commit)
+static void get_blob(struct commit *commit)
{
- struct util_info* info = commit->object.util;
- char type[20];
+ struct util_info *info = commit->object.util;
+ char type[20];
- if(info->buf)
- return;
+ if (info->buf)
+ return;
- info->buf = read_sha1_file(info->sha1, type, &info->size);
- assert(!strcmp(type, "blob"));
-}
+ info->buf = read_sha1_file(info->sha1, type, &info->size);
-void print_patch(struct patch* p)
-{
- printf("Num chunks: %d\n", p->num);
- int i;
- for(i = 0; i < p->num; i++) {
- printf("%d,%d %d,%d\n", p->chunks[i].off1, p->chunks[i].len1, p->chunks[i].off2, p->chunks[i].len2);
- }
+ assert(!strcmp(type, "blob"));
}
-
-// p is a patch from commit to other.
-void fill_line_map(struct commit* commit, struct commit* other, struct patch* p)
+/* For debugging only */
+static void print_patch(struct patch *p)
{
- int num_lines = ((struct util_info*) commit->object.util)->num_lines;
- int* line_map = ((struct util_info*) commit->object.util)->line_map;
- int num_lines2 = ((struct util_info*) other->object.util)->num_lines;
- int* line_map2 = ((struct util_info*) other->object.util)->line_map;
- int cur_chunk = 0;
- int i1, i2;
-
- if(p->num && DEBUG)
- print_patch(p);
-
- for(i1 = 0; i1 < num_lines; i1++)
- line_map[i1] = -1;
-
- if(DEBUG)
- printf("num lines 1: %d num lines 2: %d\n", num_lines, num_lines2);
-
- for(i1 = 0, i2 = 0; i1 < num_lines; i1++, i2++) {
- if(DEBUG > 1)
- printf("%d %d\n", i1, i2);
-
- if(i2 >= num_lines2)
- break;
-
- line_map[i1] = line_map2[i2];
-
- struct chunk* chunk = NULL;
- if(cur_chunk < p->num)
- chunk = &p->chunks[cur_chunk];
-
- if(chunk && chunk->off1 == i1) {
- i2 = chunk->off2;
-
- if(chunk->len1 > 0)
- i1 += chunk->len1-1;
- if(chunk->len2 > 0)
- i2 += chunk->len2-1;
- cur_chunk++;
- }
- }
-}
-
-int map_line(struct commit* commit, int line)
-{
- struct util_info* info = commit->object.util;
- assert(line >= 0 && line < info->num_lines);
- return info->line_map[line];
+ int i;
+ printf("Num chunks: %d\n", p->num);
+ for (i = 0; i < p->num; i++) {
+ printf("%d,%d %d,%d\n", p->chunks[i].off1, p->chunks[i].len1,
+ p->chunks[i].off2, p->chunks[i].len2);
+ }
}
-int fill_util_info(struct commit* commit, const char* path)
+/* For debugging only */
+static void print_map(struct commit *cmit, struct commit *other)
{
- if(commit->object.util)
- return 0;
-
- struct util_info* util = xmalloc(sizeof(struct util_info));
- util->buf = NULL;
- util->size = 0;
- util->num_lines = -1;
- util->line_map = NULL;
+ struct util_info *util = cmit->object.util;
+ struct util_info *util2 = other->object.util;
- commit->object.util = util;
+ int i;
+ int max =
+ util->num_lines >
+ util2->num_lines ? util->num_lines : util2->num_lines;
+ int num;
- if(get_blob_sha1(commit->tree, path, util->sha1))
- return -1;
+ for (i = 0; i < max; i++) {
+ printf("i: %d ", i);
+ num = -1;
- return 0;
-}
-
-void alloc_line_map(struct commit* commit)
-{
- struct util_info* util = commit->object.util;
+ if (i < util->num_lines) {
+ num = util->line_map[i];
+ printf("%d\t", num);
+ } else
+ printf("\t");
- if(util->line_map)
- return;
+ if (i < util2->num_lines) {
+ int num2 = util2->line_map[i];
+ printf("%d\t", num2);
+ if (num != -1 && num2 != num)
+ printf("---");
+ } else
+ printf("\t");
- get_blob(commit);
-
- int i;
- util->num_lines = 0;
- for(i = 0; i < util->size; i++) {
- if(util->buf[i] == '\n')
- util->num_lines++;
- }
- util->line_map = xmalloc(sizeof(int)*util->num_lines);
+ printf("\n");
+ }
}
-void copy_line_map(struct commit* dst, struct commit* src)
-{
- struct util_info* u_dst = dst->object.util;
- struct util_info* u_src = src->object.util;
-
- u_dst->line_map = u_src->line_map;
- u_dst->num_lines = u_src->num_lines;
- u_dst->buf = u_src->buf;
- u_dst->size = u_src->size;
-}
-
-void process_commits(struct commit_list* list, const char* path)
-{
- int i;
-
- while(list) {
- struct commit* commit = pop_commit(&list);
- struct commit_list* parents;
- struct util_info* info;
-
- info = commit->object.util;
- num_commits++;
- if(DEBUG)
- printf("\nProcessing commit: %d %s\n", num_commits, sha1_to_hex(commit->object.sha1));
- for(parents = commit->parents;
- parents != NULL; parents = parents->next) {
- struct commit* parent = parents->item;
-
- if(parse_commit(parent) < 0)
- die("parse_commit error");
-
- if(DEBUG)
- printf("parent: %s\n", sha1_to_hex(parent->object.sha1));
-
- if(fill_util_info(parent, path))
- continue;
-
- // Temporarily assign everything to the parent.
- int num_blame = 0;
- for(i = 0; i < num_blame_lines; i++) {
- if(blame_lines[i] == commit) {
- num_blame++;
- blame_lines[i] = parent;
- }
- }
-
- if(num_blame == 0)
- continue;
-
- struct patch* patch = get_patch(parent, commit);
- if(patch->num == 0) {
- copy_line_map(parent, commit);
- } else {
- alloc_line_map(parent);
- fill_line_map(parent, commit, patch);
- }
-
- for(i = 0; i < patch->num; i++) {
- int l;
- for(l = 0; l < patch->chunks[i].len2; l++) {
- int mapped_line = map_line(commit, patch->chunks[i].off2 + l);
- if(mapped_line != -1 && blame_lines[mapped_line] == parent)
- blame_lines[mapped_line] = commit;
- }
- }
- free_patch(patch);
- }
- }
-}
-
-#define SEEN 1
-struct commit_list* get_commit_list(struct commit* commit, const char* pathname)
+// p is a patch from commit to other.
+static void fill_line_map(struct commit *commit, struct commit *other,
+ struct patch *p)
{
- struct commit_list* ret = NULL;
- struct commit_list* process = NULL;
- unsigned char sha1[20];
-
- commit_list_insert(commit, &process);
-
- while(process) {
- struct commit* com = pop_commit(&process);
- if(com->object.flags & SEEN)
- continue;
-
- com->object.flags |= SEEN;
- commit_list_insert(com, &ret);
- struct commit_list* parents;
-
- parse_commit(com);
-
- for(parents = com->parents;
- parents != NULL; parents = parents->next) {
- struct commit* parent = parents->item;
-
- parse_commit(parent);
-
- if(!get_blob_sha1(parent->tree, pathname, sha1))
- commit_list_insert(parent, &process);
- }
- }
-
- return ret;
+ struct util_info *util = commit->object.util;
+ struct util_info *util2 = other->object.util;
+ int *map = util->line_map;
+ int *map2 = util2->line_map;
+ int cur_chunk = 0;
+ int i1, i2;
+
+ if (p->num && DEBUG)
+ print_patch(p);
+
+ if (DEBUG)
+ printf("num lines 1: %d num lines 2: %d\n", util->num_lines,
+ util2->num_lines);
+
+ for (i1 = 0, i2 = 0; i1 < util->num_lines; i1++, i2++) {
+ struct chunk *chunk = NULL;
+ if (cur_chunk < p->num)
+ chunk = &p->chunks[cur_chunk];
+
+ if (chunk && chunk->off1 == i1) {
+ if (DEBUG && i2 != chunk->off2)
+ printf("i2: %d off2: %d\n", i2, chunk->off2);
+
+ assert(i2 == chunk->off2);
+
+ i1--;
+ i2--;
+ if (chunk->len1 > 0)
+ i1 += chunk->len1;
+
+ if (chunk->len2 > 0)
+ i2 += chunk->len2;
+
+ cur_chunk++;
+ } else {
+ if (i2 >= util2->num_lines)
+ break;
+
+ if (map[i1] != map2[i2] && map[i1] != -1) {
+ if (DEBUG)
+ printf("map: i1: %d %d %p i2: %d %d %p\n",
+ i1, map[i1],
+ i1 != -1 ? blame_lines[map[i1]] : NULL,
+ i2, map2[i2],
+ i2 != -1 ? blame_lines[map2[i2]] : NULL);
+ if (map2[i2] != -1 &&
+ blame_lines[map[i1]] &&
+ !blame_lines[map2[i2]])
+ map[i1] = map2[i2];
+ }
+
+ if (map[i1] == -1 && map2[i2] != -1)
+ map[i1] = map2[i2];
+ }
+
+ if (DEBUG > 1)
+ printf("l1: %d l2: %d i1: %d i2: %d\n",
+ map[i1], map2[i2], i1, i2);
+ }
+}
+
+static int map_line(struct commit *commit, int line)
+{
+ struct util_info *info = commit->object.util;
+ assert(line >= 0 && line < info->num_lines);
+ return info->line_map[line];
+}
+
+static int fill_util_info(struct commit *commit, const char *path)
+{
+ struct util_info *util;
+ if (commit->object.util)
+ return 0;
+
+ util = xmalloc(sizeof(struct util_info));
+
+ if (get_blob_sha1(commit->tree, path, util->sha1)) {
+ free(util);
+ return 1;
+ } else {
+ util->buf = NULL;
+ util->size = 0;
+ util->line_map = NULL;
+ util->num_lines = -1;
+ commit->object.util = util;
+ return 0;
+ }
+}
+
+static void alloc_line_map(struct commit *commit)
+{
+ struct util_info *util = commit->object.util;
+ int i;
+
+ if (util->line_map)
+ return;
+
+ get_blob(commit);
+
+ util->num_lines = 0;
+ for (i = 0; i < util->size; i++) {
+ if (util->buf[i] == '\n')
+ util->num_lines++;
+ }
+ if(util->buf[util->size - 1] != '\n')
+ util->num_lines++;
+
+ util->line_map = xmalloc(sizeof(int) * util->num_lines);
+
+ for (i = 0; i < util->num_lines; i++)
+ util->line_map[i] = -1;
+}
+
+static void init_first_commit(struct commit* commit, const char* filename)
+{
+ struct util_info* util;
+ int i;
+
+ if (fill_util_info(commit, filename))
+ die("fill_util_info failed");
+
+ alloc_line_map(commit);
+
+ util = commit->object.util;
+ num_blame_lines = util->num_lines;
+
+ for (i = 0; i < num_blame_lines; i++)
+ util->line_map[i] = i;
+}
+
+
+static void process_commits(struct rev_info *rev, const char *path,
+ struct commit** initial)
+{
+ int i;
+ struct util_info* util;
+ int lines_left;
+ int *blame_p;
+ int *new_lines;
+ int new_lines_len;
+
+ struct commit* commit = get_revision(rev);
+ assert(commit);
+ init_first_commit(commit, path);
+
+ util = commit->object.util;
+ num_blame_lines = util->num_lines;
+ blame_lines = xmalloc(sizeof(struct commit *) * num_blame_lines);
+ for (i = 0; i < num_blame_lines; i++)
+ blame_lines[i] = NULL;
+
+ lines_left = num_blame_lines;
+ blame_p = xmalloc(sizeof(int) * num_blame_lines);
+ new_lines = xmalloc(sizeof(int) * num_blame_lines);
+ do {
+ struct commit_list *parents;
+ int num_parents;
+ struct util_info *util;
+
+ if (DEBUG)
+ printf("\nProcessing commit: %d %s\n", num_commits,
+ sha1_to_hex(commit->object.sha1));
+
+ if (lines_left == 0)
+ return;
+
+ num_commits++;
+ memset(blame_p, 0, sizeof(int) * num_blame_lines);
+ new_lines_len = 0;
+ num_parents = 0;
+ for (parents = commit->parents;
+ parents != NULL; parents = parents->next)
+ num_parents++;
+
+ if(num_parents == 0)
+ *initial = commit;
+
+ if(fill_util_info(commit, path))
+ continue;
+
+ alloc_line_map(commit);
+ util = commit->object.util;
+
+ for (parents = commit->parents;
+ parents != NULL; parents = parents->next) {
+ struct commit *parent = parents->item;
+ struct patch *patch;
+
+ if (parse_commit(parent) < 0)
+ die("parse_commit error");
+
+ if (DEBUG)
+ printf("parent: %s\n",
+ sha1_to_hex(parent->object.sha1));
+
+ if(fill_util_info(parent, path)) {
+ num_parents--;
+ continue;
+ }
+
+ patch = get_patch(parent, commit);
+ alloc_line_map(parent);
+ fill_line_map(parent, commit, patch);
+
+ for (i = 0; i < patch->num; i++) {
+ int l;
+ for (l = 0; l < patch->chunks[i].len2; l++) {
+ int mapped_line =
+ map_line(commit, patch->chunks[i].off2 + l);
+ if (mapped_line != -1) {
+ blame_p[mapped_line]++;
+ if (blame_p[mapped_line] == num_parents)
+ new_lines[new_lines_len++] = mapped_line;
+ }
+ }
+ }
+ free_patch(patch);
+ }
+
+ if (DEBUG)
+ printf("parents: %d\n", num_parents);
+
+ for (i = 0; i < new_lines_len; i++) {
+ int mapped_line = new_lines[i];
+ if (blame_lines[mapped_line] == NULL) {
+ blame_lines[mapped_line] = commit;
+ lines_left--;
+ if (DEBUG)
+ printf("blame: mapped: %d i: %d\n",
+ mapped_line, i);
+ }
+ }
+ } while ((commit = get_revision(rev)) != NULL);
}
int main(int argc, const char **argv)
{
- unsigned char sha1[20];
- struct commit *commit;
- const char* filename;
- int i;
-
- setup_git_directory();
-
- if (argc != 3)
- die("Usage: blame commit-ish file");
-
- if (get_sha1(argv[1], sha1))
- die("get_sha1 failed");
-
- commit = lookup_commit_reference(sha1);
-
- filename = argv[2];
-
- struct commit_list* list = get_commit_list(commit, filename);
- sort_in_topological_order(&list, 1);
-
- if(fill_util_info(commit, filename)) {
- printf("%s not found in %s\n", filename, argv[1]);
- return 0;
- }
- alloc_line_map(commit);
-
- struct util_info* util = commit->object.util;
- num_blame_lines = util->num_lines;
- blame_lines = xmalloc(sizeof(struct commit*)*num_blame_lines);
-
-
- for(i = 0; i < num_blame_lines; i++) {
- blame_lines[i] = commit;
-
- ((struct util_info*) commit->object.util)->line_map[i] = i;
- }
-
- process_commits(list, filename);
-
- for(i = 0; i < num_blame_lines; i++) {
- printf("%d %s\n", i+1-1, sha1_to_hex(blame_lines[i]->object.sha1));
-// printf("%d %s\n", i+1-1, find_unique_abbrev(blame_lines[i]->object.sha1, 6));
- }
-
- if(DEBUG) {
- printf("num get patch: %d\n", num_get_patch);
- printf("num commits: %d\n", num_commits);
- }
+ int i;
+ struct commit *initial = NULL;
+ unsigned char sha1[20];
+ const char* filename;
+ int num_args;
+ const char* args[10];
+ struct rev_info rev;
+
+ setup_git_directory();
+
+ if (argc != 3)
+ die("Usage: blame commit-ish file");
+
+
+ filename = argv[2];
+
+ {
+ struct commit* commit;
+ if (get_sha1(argv[1], sha1))
+ die("get_sha1 failed");
+ commit = lookup_commit_reference(sha1);
+
+ if (fill_util_info(commit, filename)) {
+ printf("%s not found in %s\n", filename, argv[1]);
+ return 1;
+ }
+ }
+
+ num_args = 0;
+ args[num_args++] = NULL;
+ args[num_args++] = "--topo-order";
+ args[num_args++] = "--remove-empty";
+ args[num_args++] = argv[1];
+ args[num_args++] = "--";
+ args[num_args++] = filename;
+ args[num_args] = NULL;
+
+ setup_revisions(num_args, args, &rev, "HEAD");
+ prepare_revision_walk(&rev);
+ process_commits(&rev, filename, &initial);
+
+ for (i = 0; i < num_blame_lines; i++) {
+ struct commit *c = blame_lines[i];
+ if (!c)
+ c = initial;
+
+ printf("%d %.8s\n", i, sha1_to_hex(c->object.sha1));
+// printf("%d %s\n", i, find_unique_abbrev(blame_lines[i]->object.sha1, 6));
+ }
+
+ if (DEBUG) {
+ printf("num get patch: %d\n", num_get_patch);
+ printf("num commits: %d\n", num_commits);
+ printf("patch time: %f\n", patch_time / 1000000.0);
+ printf("initial: %s\n", sha1_to_hex(initial->object.sha1));
+ }
- return 0;
+ return 0;
}
--
1.2.4.g90ab-dirty
^ permalink raw reply related
* Re: [PATCH] contrib/git-svn: use refs/remotes/git-svn instead of git-svn-HEAD
From: Nicolas Vilz 'niv' @ 2006-03-02 21:17 UTC (permalink / raw)
To: Eric Wong; +Cc: git list, Junio C Hamano
In-Reply-To: <20060302055831.GA16600@localdomain>
> After reading a lengthy discussion on the list, I've come to the
> conclusion that creating a 'remotes' directory in refs isn't
> such a bad idea.
>
> You can still branch from it by specifying remotes/git-svn (not
> needing the leading 'refs/'), and the documentation has been
> updated to reflect that.
i got stuck in that.
git-svn does the remotes/svn-git reference good, git pull hasn't
recognized it, yet. So i had to do a symlink from .git/refs/remotes to
.git/refs/heads/ to do the git pull...
then i got a bit stuck because of conflicts.... which i resolved (thank god).
the third thing is that the git-svn commit command does deletions of
certain files very often, when i commit some patches i pulled into my
private-talk-to-svn-branch. in on of the next commits the same files are
added again.. but i thought "o my god, i am screwed", when i saw the
scheduled deletions the first time... that is a bit confusing for the
users.
so in conclusion, i think, you should teach git pull to recognize
refs/remotes as heads to be pulled from (not to be pulled at)...
btw, i like the visualization of the remotes-refs in gitk.
Nicolas
^ permalink raw reply
* Re: impure renames / history tracking
From: Paul Jakma @ 2006-03-02 21:10 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: git list
In-Reply-To: <4405DD35.8060804@op5.se>
On Wed, 1 Mar 2006, Andreas Ericsson wrote:
> Yes, but imo a poor one, as you're losing all the history.
Well, not per se. You might keep the original 'detail' branch. It's a
terminal branch obviously, you can't pull master's changes to it once
the aggregate patch goes into master. But you can keep it around.
> git *can* do what you want, but it was designed to maintain a long
> history so that everyone can see it and improve on the code with
> many chains of small and simultanous changes.
Indeed, and I appreciate that.
> Perhpas we have a nomenclature clash here. When you say "one single
> commit", I can't help but thinking "snapshot".
I mean:
git diff upstream..bugfix_xyz
or:
git diff upstream..project_foo_phase1
type of thing.
> It's completely impossible to fold *ALL* the history into a single
> commit, and since you want heuristics I would imagine you wouldn't
> want that either.
I want to know whether additional meta-data to help the existing
heuristics would be acceptable. From a discussion on #git yesterday I
gather the best way forward would to be to first prototype something
keeping state in a file in .git.
All that's needed really is something that relates the following 3
things:
commit-id obj1-id obj2-id
Ie: For <commit-id>, <obj1-id> is similar to <obj2-id>.
Maintaining this state could be done via the git-mv/rename wrappers
and an additional git-edit wrapper. Those who are quite happy with
the existing diff-input only similarity heuristics wouldn't have to
bother using a git-edit wrapper obviously, those who want to let git
gather additional 'similarity hint' in this way could.
Aside:
Git might be easier to extend generally if it adopted just /one/ new
core header, say "see-also" - that could serve as a pointer to
arbitrary commit-related meta-info objects that aren't of immediate
interest to either:
a) core git
or
b) the user
Format:
see-also <word> <obj-id>
E.g.:
see-also similars <obj-id>
Where <obj-id> would list the 'commit obj1 obj2', but just as:
obj1 obj2
Would ultimately be neater than fishing around in .git/, and would
allow other extensions in the future too.
The <word> identifier preferably would need to be centrally
co-ordinated.
> I'm confused. First you say you want to have one single mega-patch
> for each commit, then you say you want to be able to follow history
> back. It's like deciding to throw away your wallet and then trying
> to get someone to pick it up and carry it around for you.
I'm not sure why think mega-patch. Collapsing a bunch of commits
related to one project need not result in a big patch relative to the
repository as a whole.
In Linux terms think project == "Add ATAPI support to SATA" or
"Change the foo VFS method and update its filesystem users" type of
thing (ok, the latter would be big enough, but still not /that/ big
in terms of the whole Linux source base). Where the project concerned
is like BSD, not just a kernel but a complete userland (so 1.1GB of
source code).
I'm aware of the workflow arguments, I /do/ intend to make those but
elsewhere ;).
> As for convincing others, shove git-bisect under their noses and
> ask them if they'd like a tool to find their bugs for them.
;)
[snip - thanks, interesting]
> The code is mightier than the mail. Perhaps if I see an implementation of
> this I could wrap my head around what you really mean. I'm sure I must
> misunderstand you one way or another.
Yes, you're right. I think Junio gave me the required hints on
directions last night on #git.
I think now at least it's quite possible to achieve without violating
git's "track the /content/" philosophy, via .git.
Thanks!
regards,
--
Paul Jakma paul@clubi.ie paul@jakma.org Key ID: 64A2FF6A
Fortune:
Factorials were someone's attempt to make math LOOK exciting.
^ permalink raw reply
* [PATCH] git-branch: add -r switch to list refs/remotes/*
From: Eric Wong @ 2006-03-02 20:23 UTC (permalink / raw)
To: git list, Junio C Hamano
In-Reply-To: <20060302055831.GA16600@localdomain>
If we decide to use refs/remotes/, having a convenient way to
list them would be nice.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
git-branch.sh | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
05fb74c2a8d4bf3692a7553c5225d25ab54f358a
diff --git a/git-branch.sh b/git-branch.sh
index 6ac961e..663a3a3 100755
--- a/git-branch.sh
+++ b/git-branch.sh
@@ -48,6 +48,12 @@ If you are sure you want to delete it, r
exit 0
}
+ls_remote_branches () {
+ git-rev-parse --symbolic --all |
+ sed -ne 's|^refs/\(remotes/\)|\1|p' |
+ sort
+}
+
force=
while case "$#,$1" in 0,*) break ;; *,-*) ;; *) break ;; esac
do
@@ -56,6 +62,10 @@ do
delete_branch "$@"
exit
;;
+ -r)
+ ls_remote_branches
+ exit
+ ;;
-f)
force="$1"
;;
--
1.2.3.gc55f
^ permalink raw reply related
* Re: windows problems summary
From: Andreas Ericsson @ 2006-03-02 20:07 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <20060302195948.GA10740@trixie.casa.cgf.cx>
Christopher Faylor wrote:
> On Thu, Mar 02, 2006 at 08:54:50PM +0100, Alex Riesen wrote:
>
>>Bertrand Jacquin, Thu, Mar 02, 2006 16:57:42 +0100:
>>
>>>Is the goal to have something like a git-turtoise (as
>>>{svn,cvs}-turtoise) ? I personaly think that is could be benefic.
>>
>>Not in the original post. It just about making git faster and more
>>stable in Windows.
>
>
> Can I request that people stop cc'ing me in this thread?
>
That's most likely because people hit "reply all" so the reply goes to
the list as well. A "normal" reply would go only to you.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* Re: windows problems summary
From: Christopher Faylor @ 2006-03-02 19:59 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <20060302195450.GB6183@steel.home>
On Thu, Mar 02, 2006 at 08:54:50PM +0100, Alex Riesen wrote:
>Bertrand Jacquin, Thu, Mar 02, 2006 16:57:42 +0100:
>>Is the goal to have something like a git-turtoise (as
>>{svn,cvs}-turtoise) ? I personaly think that is could be benefic.
>
>Not in the original post. It just about making git faster and more
>stable in Windows.
Can I request that people stop cc'ing me in this thread?
I'd like to cut down on the blood pressure medication if I can.
cgf
^ permalink raw reply
* Re: windows problems summary
From: Alex Riesen @ 2006-03-02 19:54 UTC (permalink / raw)
To: Bertrand Jacquin; +Cc: Christopher Faylor, Git Mailing List
In-Reply-To: <4fb292fa0603020757q4cd3e80cjbb63d0dc58d19756@mail.gmail.com>
Bertrand Jacquin, Thu, Mar 02, 2006 16:57:42 +0100:
>
> Is the goal to have something like a git-turtoise (as {svn,cvs}-turtoise) ?
> I personaly think that is could be benefic.
>
Not in the original post.
It just about making git faster and more stable in Windows.
^ permalink raw reply
* Re: [PATCH] fmt-merge-msg: avoid open "-|" list form for Perl 5.6
From: Andreas Ericsson @ 2006-03-02 17:39 UTC (permalink / raw)
To: Alex Riesen; +Cc: Christopher Faylor, git
In-Reply-To: <81b0412b0603020810l57f9ee5p270f9c288770d1a7@mail.gmail.com>
Ye gawds, Alex. If you complained this much to your employer you'd get
to run whatever OS you want.
Alex Riesen wrote:
[ lots of things ]
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox