Git development
 help / color / mirror / Atom feed
* Re: contrib/ status
From: Eric Wong @ 2006-07-03  8:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vmzbrwi3c.fsf_-_@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> wrote:
> Junio C Hamano <junkio@cox.net> writes:
> 
> > ... the
> > things under contrib/ are not part of git.git but are there only
> > for convenience....
> 
> This reminds me of something quite different.  I am getting an
> impression that enough people have been helped by git-svn and it
> might be a good idea to have it outside contrib/ area.

That would be great.  IMHO, it puts git in a position to supplant
centralized SVN usage one developer at a time, making it easier
to make a gradual transition to git.  Of course, there's also svk
in a similar position...

-- 
Eric Wong

^ permalink raw reply

* Re: [POLL] Who likes running Git without make install?
From: Junio C Hamano @ 2006-07-03  8:08 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20060703075850.GL29115@pasky.or.cz>

Petr Baudis <pasky@suse.cz> writes:

> Dear diary, on Mon, Jul 03, 2006 at 08:54:47AM CEST, I got a letter
> where Junio C Hamano <junkio@cox.net> said that...
>> -- >8 --
>> INSTALL: a tip for running after building but without installing.
>> 
>> Signed-off-by: Junio C Hamano <junkio@cox.net>
>
> Acked-by: Petr Baudis <pasky@suse.cz>
>
> I can live with this "weak (D3)". 99% of Git users probably use
> installed Git instance anyway and most of the rest are likely to be Git
> developers testing new code who can do this extra environment setup.

You earlier had to set two environment variables anyway but you
have added another.  I do not see what's weak about it.

^ permalink raw reply

* Re: [PATCH] consider previous pack undeltified object state only when reusing delta data
From: Andreas Ericsson @ 2006-07-03  8:11 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: Johannes Schindelin, Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.64.0606301132510.1213@localhost.localdomain>

Nicolas Pitre wrote:
> On Fri, 30 Jun 2006, Andreas Ericsson wrote:
> 
>>Johannes Schindelin wrote:
>>>
>>>>Without this there would never be a chance to improve packing for
>>>>previously undeltified objects.
>>>
>>>
>>>Earlier this year, I was quite surprised to learn that multiple repackings
>>>actually improved packing. Does that patch mean this feature is gone?
>>>
>>
>>The patch Linus sent removes that feature. This one re-introduces it.
> 
> 
> Not really.
> 
> Actually that multiple repacking "feature" was rather an artifact of the 
> delta data reuse code and not really by design.  Here's what happened 
> before:
> 

Thanks for the extensive and very clear info. Lovely to see a competent 
programmer who can also explain how things work. :)

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply

* Re: [POLL] Who likes running Git without make install?
From: Petr Baudis @ 2006-07-03  8:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vmzbrrtz4.fsf@assigned-by-dhcp.cox.net>

Dear diary, on Mon, Jul 03, 2006 at 10:08:31AM CEST, I got a letter
where Junio C Hamano <junkio@cox.net> said that...
> Petr Baudis <pasky@suse.cz> writes:
> 
> > Dear diary, on Mon, Jul 03, 2006 at 08:54:47AM CEST, I got a letter
> > where Junio C Hamano <junkio@cox.net> said that...
> >> -- >8 --
> >> INSTALL: a tip for running after building but without installing.
> >> 
> >> Signed-off-by: Junio C Hamano <junkio@cox.net>
> >
> > Acked-by: Petr Baudis <pasky@suse.cz>
> >
> > I can live with this "weak (D3)". 99% of Git users probably use
> > installed Git instance anyway and most of the rest are likely to be Git
> > developers testing new code who can do this extra environment setup.
> 
> You earlier had to set two environment variables anyway but you
> have added another.  I do not see what's weak about it.

I don't usually use the git wrapper so I got away without setting
GIT_EXEC_PATH yet. ;-)

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Snow falling on Perl. White noise covering line noise.
Hides all the bugs too. -- J. Putnam

^ permalink raw reply

* Re: [POLL] Who likes running Git without make install?
From: Johannes Schindelin @ 2006-07-03  8:37 UTC (permalink / raw)
  To: Petr Baudis; +Cc: Junio C Hamano, git
In-Reply-To: <20060703081725.GM29115@pasky.or.cz>

Hi,

On Mon, 3 Jul 2006, Petr Baudis wrote:

> Dear diary, on Mon, Jul 03, 2006 at 10:08:31AM CEST, I got a letter
> where Junio C Hamano <junkio@cox.net> said that...
> > Petr Baudis <pasky@suse.cz> writes:
> > 
> > > Dear diary, on Mon, Jul 03, 2006 at 08:54:47AM CEST, I got a letter
> > > where Junio C Hamano <junkio@cox.net> said that...
> > >> -- >8 --
> > >> INSTALL: a tip for running after building but without installing.
> > >> 
> > >> Signed-off-by: Junio C Hamano <junkio@cox.net>
> > >
> > > Acked-by: Petr Baudis <pasky@suse.cz>
> > >
> > > I can live with this "weak (D3)". 99% of Git users probably use
> > > installed Git instance anyway and most of the rest are likely to be Git
> > > developers testing new code who can do this extra environment setup.
> > 
> > You earlier had to set two environment variables anyway but you
> > have added another.  I do not see what's weak about it.
> 
> I don't usually use the git wrapper so I got away without setting
> GIT_EXEC_PATH yet. ;-)

This is the config.mak I use everywhere:

-- snip --
bindir = $(shell pwd)
template_dir = $(bindir)/templates/blt
GIT_PYTHON_DIR = $(bindir)/compat
-- snap --

No environment variable.

Ciao,
Dscho

^ permalink raw reply

* Re: There you have it. Git.pm breaks pull.
From: Johannes Schindelin @ 2006-07-03  8:39 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Petr Baudis
In-Reply-To: <7v1wt3uvvq.fsf@assigned-by-dhcp.cox.net>

Hi,

On Sun, 2 Jul 2006, Junio C Hamano wrote:

> Junio C Hamano <junkio@cox.net> writes:
> 
> > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> >
> >> Can't locate Git.pm in @INC (@INC contains: 
> >> /home/gene099/lib/perl5/site_perl/5.8.0/i586-linux-thread-multi 
> >>...
> >
> >         PERL5LIB=`pwd`/perl/blib/lib:`pwd`/perl/blib/arch/auto/Git
> >         export PERL5LIB
> 
> ... and I tested the above -- it works fine.

Thank you. It works fine, here, too.

Ciao,
Dscho

^ permalink raw reply

* Re: [RFC/PATCH] consistently try VISUAL, EDITOR and vi in this order.
From: Jakub Narebski @ 2006-07-03  9:24 UTC (permalink / raw)
  To: git
In-Reply-To: <7vmzbrv1yc.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:

> git grep -e VISUAL -e EDITOR revealed this inconsistency.  All
> other commands seem to check VISUAL and then EDITOR as they should.
> 

> +     my $editor = $ENV{VISUAL} || $ENV{EDITOR} || 'vi';
>       system($editor, $compose_filename);

Shouldn't we check if we are in visual (non CLI-only) environment,
like X-Window, MS Windows or MacOS X, before trying to use VISUAL?
How other parts solve it? </me checks> Ah, we use VISUAL unconditionally,
at least in scripts...

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Re: [PATCH 3/3] Make clear_commit_marks() clean harder
From: Junio C Hamano @ 2006-07-03  9:32 UTC (permalink / raw)
  To: Rene Scharfe; +Cc: git, Johannes Schindelin, Linus Torvalds
In-Reply-To: <20060701232958.GC2513@lsrfire.ath.cx>

Rene Scharfe <rene.scharfe@lsrfire.ath.cx> writes:

> Don't care if objects have been parsed or not and don't stop when we
> reach a commit that is already clean -- its parents could be dirty.

There is something quite wrong with this patch.  When you are
dealing with complex commit ancestry, this ends up traversing
the same parent over and over again.

I tried to do a merge in linux-2.6 history with these two
commits:

	v2.6.17-g29454dd
	v2.6.17-gd6b0c53

The former is Linus's head at this writing, and the latter is
James Bottomley's scsi-misc head.

	git describe 29454dd d6b0c53

from the "master" branch returns immediately (the use there can
assume that the mark is set and contiguous, I think) while the
one with this patch takes forever.

Another example is to try changing get_merge_bases() to always
clean-up as Johannes had originally and try computing the merge
base between the two.  Just before it starts to clean-up, it has
only seen 5983 objects (object.c::nr_objs) and it definitely
would be faster to clean flags from all these objects than to
wait for the two calls to clear_commit_marks() to complete,
which seems to also take forever.

^ permalink raw reply

* Re: [PATCH 2] autoconf: Use ./configure script in git *.spec file
From: Jakub Narebski @ 2006-07-03 11:05 UTC (permalink / raw)
  To: git
In-Reply-To: <7vslljwiat.fsf@assigned-by-dhcp.cox.net>

As I see it, we have the following options with respect to autoconf related
files and use of ./configure script


1. Use autoconf and ./configure script generated by it as optional way to
configure installation process. Have configure.ac and config.mak.in in main
directory of git.git repository. Do not use ./configure script in
git.spec.in, i.e. do not apply this patch... perhaps put _patch_ in the
contrib/. Leave changes to *.spec file to distributions, documenting it
somewhere.

2. Use autoconf and ./configure script generated by it as optional way to
configure installation process _and_ in git.spec.in, i.e. in the RPM
building. Ship generated 'configure' script with distribution (source)
tarball or make patch creating 'configure' script and use it instead in
git.spec.in (avoids shipping 'configure' in source tarball). This has the
consequence that autoconf would be build dependence for creating RPM at
least. Perhaps we can have automatically build configure script in separate
branch, similarly to 'man' and 'html branches of git.git.

3. Write our own ./configure script, put it under version control, and put
autoconf related files in contrib/ as an alternative. Advantages: we can
customize it to git needs and git build process conventions. Disadvantages:
duplication of work put into autoconf to make generated ./configure script
portable (which is also the case why atoconf generated shel script
'configure' is not very readable, and probably should be not under version
control; html and man documentation aren't either). Use %configure in
git.spec.in file. Plan for the future? 


I am partially to [*1*], if just because I wouldn't need to take care
autoconf in git. [*2*] has disadvantage in that generated ./configure needs
to be put in main directory to work, either by hand (which complicates
using this way of building and installing git) or by script (which violates
unsaid rule that contrib/ doesn't interfere in top directory). [*3*] would
be probably the best, but it is additional work, duplication of autoconf
efforts, and need someone (not me) well versed in git compiling woes _and_
shell script portability.

-- 
Jakub Narębski
ShadeHawk on #git

^ permalink raw reply

* Compression speed for large files
From: Joachim B Haga @ 2006-07-03 11:13 UTC (permalink / raw)
  To: git

I'm looking at doing version control of data files, potentially very large,
often binary. In git, committing of large files is very slow; I have tested with
a 45MB file, which takes about 1 minute to check in (on an intel core-duo 2GHz).

Now, most of the time is spent in compressing the file. Would it be a good idea
to change the Z_BEST_COMPRESSION flag to zlib, at least for large files? I have
measured the time spent by git-commit with different flags in sha1_file.c:

  method                 time (s)  object size (kB)
  Z_BEST_COMPRESSION     62.0      17136
  Z_DEFAULT_COMPRESSION  10.4      16536
  Z_BEST_SPEED            4.8      17071

In this case Z_BEST_COMPRESSION also compresses worse, but that's not the major
issue: the time is. Here's a couple of other data points, measured with gzip -9,
-6 and -1 (comparable to the Z_ flags above):

129MB ascii data file
  method    time (s)  object size (kB)
  gzip -9   158       23066
  gzip -6    18       23619
  gzip -1     6       32304

3MB ascii data file
  gzip -9   2.2        887
  gzip -6   0.7        912
  gzip -1   0.3       1134

So: is it a good idea to change to faster compression, at least for larger
files? From my (limited) testing I would suggest using Z_BEST_COMPRESSION only
for small files (perhaps <1MB?) and Z_DEFAULT_COMPRESSION/Z_BEST_SPEED for
larger ones.


-j.

^ permalink raw reply

* Re: qgit idea: interface for cherry-picking
From: Marco Costalba @ 2006-07-03 11:18 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jakub Narebski
In-Reply-To: <7vzmfrrxyp.fsf@assigned-by-dhcp.cox.net>

On 7/3/06, Junio C Hamano <junkio@cox.net> wrote:
> "Marco Costalba" <mcostalba@gmail.com> writes:
>
> > When I need to modify the patch/revision before to import I usaually
> > drag&drop and then I call git-reset --soft, then I edit working
> > directory and commit again.
>
> These days, I tend to just let "am" or "pull" do its thing, edit
> working tree and retest, and run "commit --amend".  Before we
> added "commit --amend", I used to do soft reset and recommit
> like you described above.  One advantage of "commit --amend" is
> that it can even amend a merge, but I do not think it applies to
> what Jakub wants in this thread.
>

I cannot test your patch now, so I'm just guessing, what if we have a
series of patches?
Is it possible that for two patches A and B happens that

git-am A
git-am B
git-reset --soft HEAD^^

gives a different result then

git-am --fail A
git-am --fail B

As example, if B modify the same file of A then could happen that in
the latter case git-am --fail B stops with conflicts because the
working dir is not synced with the index (this happens only in the
latter case) ?

Put in other words, I don't know if the two procedures are
_equivalent_ because in the first case you operate under the
assumption that working dir and index are always synced before and
after to apply, in the second case this assumption is broken so I
don't know if this could have side effects.

      Marco

^ permalink raw reply

* Re: Compression speed for large files
From: Alex Riesen @ 2006-07-03 12:03 UTC (permalink / raw)
  To: Joachim B Haga; +Cc: git
In-Reply-To: <loom.20060703T124601-969@post.gmane.org>

On 7/3/06, Joachim B Haga <cjhaga@fys.uio.no> wrote:
> So: is it a good idea to change to faster compression, at least for larger
> files? From my (limited) testing I would suggest using Z_BEST_COMPRESSION only
> for small files (perhaps <1MB?) and Z_DEFAULT_COMPRESSION/Z_BEST_SPEED for
> larger ones.

Probably yes, as a per-repo config option.

^ permalink raw reply

* Re: Compression speed for large files
From: Elrond @ 2006-07-03 12:42 UTC (permalink / raw)
  To: git
In-Reply-To: <81b0412b0607030503p63b4ee31v7776bd155d3dab29@mail.gmail.com>

Joachim B Haga <cjhaga <at> fys.uio.no> writes:
[...]
>   method                 time (s)  object size (kB)
>   Z_BEST_COMPRESSION     62.0      17136
>   Z_DEFAULT_COMPRESSION  10.4      16536
>   Z_BEST_SPEED            4.8      17071
> 
> In this case Z_BEST_COMPRESSION also compresses worse,
[...]

I personally find that very interesting, is this a known "issue" with zlib?
It suggests, that with different options, it's possible to create smaller
repositories, despite the 'advertised' (by zlib, not git) "best" compression.


Alex Riesen <raa.lkml <at> gmail.com> writes:
[...]
> Probably yes, as a per-repo config option.

The option probably should be the size for which to start using
"default" compression.


    Elrond

^ permalink raw reply

* [PATCH] Make git-fmt-merge-msg a builtin
From: Johannes Schindelin @ 2006-07-03 13:31 UTC (permalink / raw)
  To: git, junkio


Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

	This does not (yet) remove the Perl version.

 Makefile                |    2 
 builtin-fmt-merge-msg.c |  357 +++++++++++++++++++++++++++++++++++++++++++++++
 builtin.h               |    1 
 git.c                   |    3 
 4 files changed, 361 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index c142bdd..c75b8a9 100644
--- a/Makefile
+++ b/Makefile
@@ -245,7 +245,7 @@ BUILTIN_OBJS = \
 	builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
 	builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
 	builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
-	builtin-update-ref.o
+	builtin-update-ref.o builtin-fmt-merge-msg.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 EXTLIBS = -lz
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
new file mode 100644
index 0000000..a73b322
--- /dev/null
+++ b/builtin-fmt-merge-msg.c
@@ -0,0 +1,357 @@
+#include "cache.h"
+#include "commit.h"
+#include "diff.h"
+#include "revision.h"
+#include "tag.h"
+
+static const char *fmt_merge_msg_usage =
+	"git-fmt-merge-msg [--summary] [--no-summary] [--file <file>]";
+
+static int merge_summary = 0;
+
+static int fmt_merge_msg_config(const char *key, const char *value)
+{
+	if (!strcmp("merge.summary", key))
+		merge_summary = git_config_bool(key, value);
+	return 0;
+}
+
+struct list {
+	char **list;
+	void **payload;
+	unsigned nr, alloc;
+};
+
+static void append_to_list(struct list *list, char *value)
+{
+	if (list->nr == list->alloc) {
+		list->alloc += 32;
+		list->list = realloc(list->list, sizeof(char *) * list->alloc);
+		list->payload = realloc(list->payload,
+				sizeof(char *) * list->alloc);
+	}
+	list->payload[list->nr] = NULL;
+	list->list[list->nr++] = value;
+}
+
+static int find_in_list(struct list *list, char *value)
+{
+	int i;
+
+	for (i = 0; i < list->nr; i++)
+		if (!strcmp(list->list[i], value))
+			return i;
+
+	return -1;
+}
+
+static void free_list(struct list *list)
+{
+	int i;
+
+	if (list->alloc == 0)
+		return;
+
+	for (i = 0; i < list->nr; i++) {
+		free(list->list[i]);
+		if (list->payload[i])
+			free(list->payload[i]);
+	}
+	free(list->list);
+	free(list->payload);
+	list->nr = list->alloc = 0;
+}
+
+struct src_data {
+	struct list branch, tag, r_branch, generic;
+	int head_status;
+};
+
+static struct list srcs = { NULL, NULL, 0, 0};
+static struct list origins = { NULL, NULL, 0, 0};
+
+static int handle_line(char *line)
+{
+	int i, len = strlen(line);
+	unsigned char *sha1;
+	char *src, *origin;
+	struct src_data *src_data;
+
+	if (len < 43 || line[40] != '\t')
+		return 1;
+
+	if (!strncmp(line + 41, "not-for-merge", 13))
+		return 0;
+
+	if (line[41] != '\t')
+		return 2;
+
+	line[40] = 0;
+	sha1 = xmalloc(20);
+	i = get_sha1(line, sha1);
+	line[40] = '\t';
+	if (i)
+		return 3;
+
+	if (line[len - 1] == '\n')
+		line[len - 1] = 0;
+	line += 42;
+
+	src = strstr(line, " of ");
+	if (src) {
+		*src = 0;
+		src += 4;
+	} else
+		src = "HEAD";
+
+	i = find_in_list(&srcs, src);
+	if (i < 0) {
+		i = srcs.nr;
+		append_to_list(&srcs, strdup(src));
+		srcs.payload[i] = xcalloc(1, sizeof(struct src_data));
+	}
+	src_data = srcs.payload[i];
+
+	if (!strncmp(line, "branch ", 7)) {
+		origin = strdup(line + 7);
+		append_to_list(&(src_data->branch), origin);
+		src_data->head_status |= 2;
+	} else if (!strncmp(line, "tag ", 4)) {
+		origin = line;
+		append_to_list(&(src_data->tag), strdup(origin + 4));
+		src_data->head_status |= 2;
+	} else if (!strncmp(line, "remote branch ", 14)) {
+		origin = strdup(line + 14);
+		append_to_list(&(src_data->r_branch), origin);
+		src_data->head_status |= 2;
+	} else if (!strcmp(line, "HEAD")) {
+		origin = strdup(src);
+		src_data->head_status |= 1;
+	} else {
+		origin = strdup(src);
+		append_to_list(&(src_data->generic), strdup(line));
+		src_data->head_status |= 2;
+	}
+
+	if (!strcmp(".", src) || !strcmp(src, origin)) {
+		int len = strlen(origin);
+		if (origin[0] == '\'' && origin[len - 1] == '\'') {
+			char *new_origin = malloc(len - 1);
+			memcpy(new_origin, origin + 1, len - 2);
+			new_origin[len - 1] = 0;
+			origin = new_origin;
+		} else
+			origin = strdup(origin);
+	} else {
+		char *new_origin = malloc(strlen(origin) + strlen(src) + 5);
+		sprintf(new_origin, "%s of %s", origin, src);
+		origin = new_origin;
+	}
+	append_to_list(&origins, origin);
+	origins.payload[origins.nr - 1] = sha1;
+	return 0;
+}
+
+static void print_joined(const char *singular, const char *plural,
+		struct list *list)
+{
+	if (list->nr == 0)
+		return;
+	if (list->nr == 1) {
+		printf("%s%s", singular, list->list[0]);
+	} else {
+		int i;
+		printf("%s", plural);
+		for (i = 0; i < list->nr - 1; i++)
+			printf("%s%s", i > 0 ? ", " : "", list->list[i]);
+		printf(" and %s", list->list[list->nr - 1]);
+	}
+}
+
+static void shortlog(const char *name, unsigned char *sha1,
+		struct commit *head, struct rev_info *rev, int limit)
+{
+	int i, count = 0;
+	struct commit *commit;
+	struct object *branch;
+	struct list subjects = { NULL, NULL, 0, 0 };
+	int flags = UNINTERESTING | TREECHANGE | SEEN | SHOWN | ADDED;
+
+	branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
+	if (!branch || branch->type != TYPE_COMMIT)
+		return;
+
+	setup_revisions(0, NULL, rev, NULL);
+	rev->ignore_merges = 1;
+	add_pending_object(rev, branch, name);
+	add_pending_object(rev, &(head->object), "^HEAD");
+	head->object.flags |= UNINTERESTING;
+        prepare_revision_walk(rev);
+	while ((commit = get_revision(rev)) != NULL) {
+		char *oneline, *bol, *eol;
+
+		/* ignore merges */
+		if (commit->parents && commit->parents->next)
+			continue;
+
+		count++;
+		if (subjects.nr > limit)
+			continue;
+
+		bol = strstr(commit->buffer, "\n\n");
+		if (!bol) {
+			append_to_list(&subjects, strdup(sha1_to_hex(
+							commit->object.sha1)));
+			continue;
+		}
+
+		bol += 2;
+		eol = strchr(bol, '\n');
+		
+		if (eol) {
+			int len = eol - bol;
+			oneline = malloc(len + 1);
+			memcpy(oneline, bol, len);
+			oneline[len] = 0;
+		} else
+			oneline = strdup(bol);
+		append_to_list(&subjects, oneline);
+	}
+
+	if (count > limit)
+		printf("\n* %s: (%d commits)\n", name, count);
+	else
+		printf("\n* %s:\n", name);
+
+	for (i = 0; i < subjects.nr; i++)
+		if (i >= limit)
+			printf("  ...\n");
+		else
+			printf("  %s\n", subjects.list[i]);
+
+	clear_commit_marks((struct commit *)branch, flags);
+	clear_commit_marks(head, flags);
+	free_commit_list(rev->commits);
+	rev->commits = NULL;
+	rev->pending.nr = 0;
+
+	free_list(&subjects);
+	
+}
+
+int cmd_fmt_merge_msg(int argc, char **argv, char **envp)
+{
+	int limit = 20, i = 0;
+	char line[1024];
+	FILE *in = stdin;
+	const char *sep = "";
+	unsigned char head_sha1[20];
+	const char *head, *current_branch;
+
+	git_config(fmt_merge_msg_config);
+
+	while (argc > 1) {
+		if (!strcmp(argv[1], "--summary"))
+			merge_summary = 1;
+		else if (!strcmp(argv[1], "--no-summary"))
+			merge_summary = 0;
+		else if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--file")) {
+			if (argc < 2)
+				die ("Which file?");
+			if (!strcmp(argv[2], "-"))
+				in = stdin;
+			else {
+				fclose(in);
+				in = fopen(argv[2], "r");
+			}
+			argc--; argv++;
+		} else
+			break;
+		argc--; argv++;
+	}
+
+	if (argc > 1)
+		usage(fmt_merge_msg_usage);
+
+	/* get current branch */
+	head = strdup(git_path("HEAD"));
+	current_branch = resolve_ref(head, head_sha1, 1);
+	current_branch += strlen(head) - 4;
+	free((char *)head);
+	if (!strncmp(current_branch, "refs/heads/", 11))
+		current_branch += 11;
+
+	while (fgets(line, sizeof(line), in)) {
+		i++;
+		if (line[0] == 0)
+			continue;
+		if (handle_line(line))
+			die ("Error in line %d: %s", i, line);
+	}
+
+	printf("Merge ");
+	for (i = 0; i < srcs.nr; i++) {
+		struct src_data *src_data = srcs.payload[i];
+		const char *subsep = "";
+
+		printf(sep);
+		sep = "; ";
+
+		if (src_data->head_status == 1) {
+			printf(srcs.list[i]);
+			continue;
+		}
+		if (src_data->head_status == 3) {
+			subsep = ", ";
+			printf("HEAD");
+		}
+		if (src_data->branch.nr) {
+			printf(subsep);
+			subsep = ", ";
+			print_joined("branch ", "branches ",
+					&(src_data->branch));
+		}
+		if (src_data->r_branch.nr) {
+			printf(subsep);
+			subsep = ", ";
+			print_joined("remote branch ", "remote branches ",
+					&(src_data->r_branch));
+		}
+		if (src_data->tag.nr) {
+			printf(subsep);
+			subsep = ", ";
+			print_joined("tag ", "tags ", &(src_data->tag));
+		}
+		if (src_data->generic.nr) {
+			printf(subsep);
+			print_joined("commit ", "commits ",
+					&(src_data->generic));
+		}
+		if (strcmp(".", srcs.list[i]))
+			printf(" of %s", srcs.list[i]);
+	}
+
+	printf(" into %s\n", current_branch);
+
+	if (merge_summary) {
+		struct commit *head;
+		struct rev_info rev;
+
+		head = lookup_commit(head_sha1);
+parse_object(head->object.sha1);
+head = head->parents->item;
+		init_revisions(&rev);
+		rev.commit_format = CMIT_FMT_ONELINE;
+		rev.ignore_merges = 1;
+		rev.limited = 1;
+
+		for (i = 0; i < origins.nr; i++)
+			shortlog(origins.list[i], origins.payload[i],
+					head, &rev, limit);
+	}
+
+	/* No cleanup yet; is standalone anyway */
+
+	return 0;
+}
+
diff --git a/builtin.h b/builtin.h
old mode 100644
new mode 100755
index f12d5e6..d9e5483
--- a/builtin.h
+++ b/builtin.h
@@ -49,6 +49,7 @@ extern int cmd_cat_file(int argc, const 
 extern int cmd_rev_parse(int argc, const char **argv, char **envp);
 extern int cmd_update_index(int argc, const char **argv, char **envp);
 extern int cmd_update_ref(int argc, const char **argv, char **envp);
+extern int cmd_fmt_merge_msg(int argc, const char **argv, char **envp);
 
 extern int cmd_write_tree(int argc, const char **argv, char **envp);
 extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
diff --git a/git.c b/git.c
index 512fa63..7cc826b 100644
--- a/git.c
+++ b/git.c
@@ -200,7 +200,8 @@ static void handle_internal_command(int 
 		{ "mailinfo", cmd_mailinfo },
 		{ "stripspace", cmd_stripspace },
 		{ "update-index", cmd_update_index },
-		{ "update-ref", cmd_update_ref }
+		{ "update-ref", cmd_update_ref },
+		{ "fmt-merge-msg", cmd_fmt_merge_msg }
 	};
 	int i;
 
-- 
1.4.1.ga246

^ permalink raw reply related

* Re: Compression speed for large files
From: Joachim Berdal Haga @ 2006-07-03 13:32 UTC (permalink / raw)
  To: Alex Riesen; +Cc: git
In-Reply-To: <81b0412b0607030503p63b4ee31v7776bd155d3dab29@mail.gmail.com>

Alex Riesen wrote:
> On 7/3/06, Joachim B Haga <cjhaga@fys.uio.no> wrote:
>> So: is it a good idea to change to faster compression, at least for 
>> larger files? From my (limited) testing I would suggest using 
>> Z_BEST_COMPRESSION only for small files (perhaps <1MB?) and 
>> Z_DEFAULT_COMPRESSION/Z_BEST_SPEED for
>> larger ones.
> 
> Probably yes, as a per-repo config option.

I can send a patch later. If it's to be a per-repo option, it's probably 
too confusing with several values. Is it ok with

core.compression = [-1..9]

where the numbers are the zlib/gzip constants,
   -1 = zlib default (currently 6)
    0 = no compression
1..9 = various speed/size tradeoffs (9 is git default)

Btw; I just tested the kernel sources. With gzip only, but files 
compressed individually:
   time find . -type f | xargs gzip -9 -c | wc -c

I found the space saving from -6 to -9 to be under 0.6%, at double the 
CPU time. So perhaps Z_DEFAULT_COMPRESSION would be good as default.

-j

^ permalink raw reply

* Re: Compression speed for large files
From: Joachim B Haga @ 2006-07-03 13:44 UTC (permalink / raw)
  To: git
In-Reply-To: <loom.20060703T143544-407@post.gmane.org>

Elrond <elrond+kernel.org <at> samba-tng.org> writes:

> 
> Joachim B Haga <cjhaga <at> fys.uio.no> writes:
> [...]
> > In this case Z_BEST_COMPRESSION also compresses worse,
> [...]
> 
> I personally find that very interesting, is this a known "issue" with zlib?
> It suggests, that with different options, it's possible to create smaller
> repositories, despite the 'advertised' (by zlib, not git) "best" compression.

There are also other tunables in zlib, such as the balance between Huffman
coding (good for data files) and string matching (good for text files). So with
more knowledge of the data it should be possible to compress even better. I'm
not advocating tuning this in git though ;)

> 
> Alex Riesen <raa.lkml <at> gmail.com> writes:
> [...]
> > Probably yes, as a per-repo config option.
> 
> The option probably should be the size for which to start using
> "default" compression.

That is possible, too. I'm open to any decision or consensus, as long as I get
my commits in less than 10s :)

-j.

^ permalink raw reply

* Re: [PATCH 3/3] Make clear_commit_marks() clean harder
From: Johannes Schindelin @ 2006-07-03 13:56 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Rene Scharfe, git, Linus Torvalds
In-Reply-To: <7vejx3rq33.fsf@assigned-by-dhcp.cox.net>

Hi,

On Mon, 3 Jul 2006, Junio C Hamano wrote:

> Rene Scharfe <rene.scharfe@lsrfire.ath.cx> writes:
> 
> > Don't care if objects have been parsed or not and don't stop when we
> > reach a commit that is already clean -- its parents could be dirty.
> 
> There is something quite wrong with this patch.

I always had the feeling that it was wrong to traverse not-yet-parsed 
parents: How could a revision walk possibly come to a certain commit 
without at least one continuous history of now-parsed objects?

Also, AFAIK the revision walk sets flags for each commit it touched, and 
we should not try to be smart-asses about the flags, but just unset these 
flags.

BTW some very quick tests showed that the clear_commit_marks() thing that 
I sent to the list was much faster than traversing all objects (which was 
in my original version).

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] Make git-fmt-merge-msg a builtin
From: Timo Hirvonen @ 2006-07-03 14:17 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, junkio
In-Reply-To: <Pine.LNX.4.63.0607031530380.29667@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:

> +struct list {
> +	char **list;
> +	void **payload;
> +	unsigned nr, alloc;
> +};

How about something like this instead to reduce mallocs to half and
simplify the code?

struct item {
	char *value;
	void *payload;
};

struct list {
	struct item *items;
	unsigned int nr, alloc;
};

(But I realize this isn't performance critical)

> +static void append_to_list(struct list *list, char *value)

Add void *payload parameter too, would simplify the code.

> +static void free_list(struct list *list)
> +{
> +	int i;
> +
> +	if (list->alloc == 0)
> +		return;

Unnecessary if nr is 0 too.

> +	for (i = 0; i < list->nr; i++) {
> +		free(list->list[i]);
> +		if (list->payload[i])
> +			free(list->payload[i]);

free(NULL) is safe.

> +	}
> +	free(list->list);
> +	free(list->payload);
> +	list->nr = list->alloc = 0;
> +}

> +	if (!strncmp(line, "branch ", 7)) {
> +		origin = strdup(line + 7);
> +		append_to_list(&(src_data->branch), origin);

Parenthesis isn't needed.

> +	head->object.flags |= UNINTERESTING;
> +        prepare_revision_walk(rev);

Spaces..

> +	if (merge_summary) {
> +		struct commit *head;
> +		struct rev_info rev;
> +
> +		head = lookup_commit(head_sha1);
> +parse_object(head->object.sha1);
> +head = head->parents->item;

Indentation.

-- 
http://onion.dynserv.net/~timo/

^ permalink raw reply

* Re: Compression speed for large files
From: Nicolas Pitre @ 2006-07-03 14:33 UTC (permalink / raw)
  To: Joachim Berdal Haga; +Cc: Alex Riesen, git
In-Reply-To: <44A91C7A.6090902@fys.uio.no>

On Mon, 3 Jul 2006, Joachim Berdal Haga wrote:

> Alex Riesen wrote:
> > On 7/3/06, Joachim B Haga <cjhaga@fys.uio.no> wrote:
> > > So: is it a good idea to change to faster compression, at least for larger
> > > files? From my (limited) testing I would suggest using Z_BEST_COMPRESSION
> > > only for small files (perhaps <1MB?) and
> > > Z_DEFAULT_COMPRESSION/Z_BEST_SPEED for
> > > larger ones.
> > 
> > Probably yes, as a per-repo config option.
> 
> I can send a patch later. If it's to be a per-repo option, it's probably too
> confusing with several values. Is it ok with
> 
> core.compression = [-1..9]
> 
> where the numbers are the zlib/gzip constants,
>   -1 = zlib default (currently 6)
>    0 = no compression
> 1..9 = various speed/size tradeoffs (9 is git default)

I think this makes a lot of sense, although IMHO I'd simply use 
Z_DEFAULT_COMPRESSION everywhere and be done with it without extra 
complexity which aren't worth the size difference.


Nicolas

^ permalink raw reply

* Re: [PATCH] Make git-fmt-merge-msg a builtin
From: Johannes Schindelin @ 2006-07-03 14:36 UTC (permalink / raw)
  To: Timo Hirvonen; +Cc: git, junkio
In-Reply-To: <20060703171751.2ed33220.tihirvon@gmail.com>

Hi,

On Mon, 3 Jul 2006, Timo Hirvonen wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> 
> > +struct list {
> > +	char **list;
> > +	void **payload;
> > +	unsigned nr, alloc;
> > +};
> 
> How about something like this instead to reduce mallocs to half and
> simplify the code?
> 
> struct item {
> 	char *value;
> 	void *payload;
> };
> 
> struct list {
> 	struct item *items;
> 	unsigned int nr, alloc;
> };
> 
> (But I realize this isn't performance critical)

I had in mind that I want to use path-list instead (which is cooking in 
the merge-recursive efforts ATM). And there, I would add a flag 
needs_payload. Opinions?

> > +static void append_to_list(struct list *list, char *value)
> 
> Add void *payload parameter too, would simplify the code.

Okay.

> > +static void free_list(struct list *list)
> > +{
> > +	int i;
> > +
> > +	if (list->alloc == 0)
> > +		return;
> 
> Unnecessary if nr is 0 too.

No. If nr == 0, alloc need not be 0, and if it is not, list and payload 
are still allocated.

> > +	for (i = 0; i < list->nr; i++) {
> > +		free(list->list[i]);
> > +		if (list->payload[i])
> > +			free(list->payload[i]);
> 
> free(NULL) is safe.

Is it? I vaguely remember that I had problems with this on some obscure 
platform.

> > +	if (!strncmp(line, "branch ", 7)) {
> > +		origin = strdup(line + 7);
> > +		append_to_list(&(src_data->branch), origin);
> 
> Parenthesis isn't needed.

Okay. Wanted to be on the safe side.

> > +	head->object.flags |= UNINTERESTING;
> > +        prepare_revision_walk(rev);
> 
> Spaces..

True. Will fix.

> > +	if (merge_summary) {
> > +		struct commit *head;
> > +		struct rev_info rev;
> > +
> > +		head = lookup_commit(head_sha1);
> > +parse_object(head->object.sha1);
> > +head = head->parents->item;
> 
> Indentation.

No. Bug. This was a leftover from my tests (with this, the summary is not 
done versus HEAD, but HEAD^).

Will fix and resubmit.

Ciao,
Dscho

^ permalink raw reply

* Re: Compression speed for large files
From: Yakov Lerner @ 2006-07-03 14:54 UTC (permalink / raw)
  Cc: git
In-Reply-To: <Pine.LNX.4.64.0607031030150.1213@localhost.localdomain>

On 7/3/06, Nicolas Pitre <nico@cam.org> wrote:
> On Mon, 3 Jul 2006, Joachim Berdal Haga wrote:
>
> > Alex Riesen wrote:
> > > On 7/3/06, Joachim B Haga <cjhaga@fys.uio.no> wrote:
> > > > So: is it a good idea to change to faster compression, at least for larger
> > > > files? From my (limited) testing I would suggest using Z_BEST_COMPRESSION
> > > > only for small files (perhaps <1MB?) and
> > > > Z_DEFAULT_COMPRESSION/Z_BEST_SPEED for
> > > > larger ones.
> > >
> > > Probably yes, as a per-repo config option.
> >
> > I can send a patch later. If it's to be a per-repo option, it's probably too
> > confusing with several values. Is it ok with
> >
> > core.compression = [-1..9]
> >
> > where the numbers are the zlib/gzip constants,
> >   -1 = zlib default (currently 6)
> >    0 = no compression
> > 1..9 = various speed/size tradeoffs (9 is git default)

It would be arguable whether, say, 10% better compression is worth
x(3-8) slower compression. But 3-4% better compression at the cost of
x(3-8) slower compression time as data suggest ? I think this begs
for switching the default to Z_DEFAULT_COMPRESSION

Yakov

^ permalink raw reply

* Re: Compression speed for large files
From: Johannes Schindelin @ 2006-07-03 15:17 UTC (permalink / raw)
  To: Yakov Lerner; +Cc: git
In-Reply-To: <f36b08ee0607030754k4d10548pfb71dc62c6ee0b21@mail.gmail.com>

Hi,

On Mon, 3 Jul 2006, Yakov Lerner wrote:

> It would be arguable whether, say, 10% better compression is worth 
> x(3-8) slower compression. But 3-4% better compression at the cost of 
> x(3-8) slower compression time as data suggest ? I think this begs for 
> switching the default to Z_DEFAULT_COMPRESSION

The real problem, of course, is that you cannot know before you tried, if 
your data is really well compressible or not.

Ciao,
Dscho

^ permalink raw reply

* [PATCH 2nd try] Make git-fmt-merge-msg a builtin
From: Johannes Schindelin @ 2006-07-03 15:18 UTC (permalink / raw)
  To: git, junio, Timo Hirvonen


Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---
	This retires git-fmt-merge-msg.perl, since it passes all the
	tests, but removes the Perl version not now. Did I mention it
	is very, very, very fast? (Even compared to the Git.pm version;
	measured on a cygwin setup.)

 Makefile                |    7 +
 builtin-fmt-merge-msg.c |  355 +++++++++++++++++++++++++++++++++++++++++++++++
 builtin.h               |    1 
 git.c                   |    3 
 4 files changed, 362 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile
index c142bdd..a551c33 100644
--- a/Makefile
+++ b/Makefile
@@ -147,7 +147,7 @@ SCRIPT_SH = \
 
 SCRIPT_PERL = \
 	git-archimport.perl git-cvsimport.perl git-relink.perl \
-	git-shortlog.perl git-fmt-merge-msg.perl git-rerere.perl \
+	git-shortlog.perl git-rerere.perl \
 	git-annotate.perl git-cvsserver.perl \
 	git-svnimport.perl git-mv.perl git-cvsexportcommit.perl \
 	git-send-email.perl
@@ -189,7 +189,8 @@ BUILT_INS = git-log$X git-whatchanged$X 
 	git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \
 	git-read-tree$X git-commit-tree$X git-write-tree$X \
 	git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
-	git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X
+	git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X \
+	git-fmt-merge-msg$X
 
 # what 'all' will build and 'install' will install, in gitexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -245,7 +246,7 @@ BUILTIN_OBJS = \
 	builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
 	builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
 	builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
-	builtin-update-ref.o
+	builtin-update-ref.o builtin-fmt-merge-msg.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 EXTLIBS = -lz
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
new file mode 100644
index 0000000..6527482
--- /dev/null
+++ b/builtin-fmt-merge-msg.c
@@ -0,0 +1,355 @@
+#include "cache.h"
+#include "commit.h"
+#include "diff.h"
+#include "revision.h"
+#include "tag.h"
+
+static const char *fmt_merge_msg_usage =
+	"git-fmt-merge-msg [--summary] [--no-summary] [--file <file>]";
+
+static int merge_summary = 0;
+
+static int fmt_merge_msg_config(const char *key, const char *value)
+{
+	if (!strcmp("merge.summary", key))
+		merge_summary = git_config_bool(key, value);
+	return 0;
+}
+
+struct list {
+	char **list;
+	void **payload;
+	unsigned nr, alloc;
+};
+
+static void append_to_list(struct list *list, char *value, void *payload)
+{
+	if (list->nr == list->alloc) {
+		list->alloc += 32;
+		list->list = realloc(list->list, sizeof(char *) * list->alloc);
+		list->payload = realloc(list->payload,
+				sizeof(char *) * list->alloc);
+	}
+	list->payload[list->nr] = payload;
+	list->list[list->nr++] = value;
+}
+
+static int find_in_list(struct list *list, char *value)
+{
+	int i;
+
+	for (i = 0; i < list->nr; i++)
+		if (!strcmp(list->list[i], value))
+			return i;
+
+	return -1;
+}
+
+static void free_list(struct list *list)
+{
+	int i;
+
+	if (list->alloc == 0)
+		return;
+
+	for (i = 0; i < list->nr; i++) {
+		free(list->list[i]);
+		if (list->payload[i])
+			free(list->payload[i]);
+	}
+	free(list->list);
+	free(list->payload);
+	list->nr = list->alloc = 0;
+}
+
+struct src_data {
+	struct list branch, tag, r_branch, generic;
+	int head_status;
+};
+
+static struct list srcs = { NULL, NULL, 0, 0};
+static struct list origins = { NULL, NULL, 0, 0};
+
+static int handle_line(char *line)
+{
+	int i, len = strlen(line);
+	unsigned char *sha1;
+	char *src, *origin;
+	struct src_data *src_data;
+
+	if (len < 43 || line[40] != '\t')
+		return 1;
+
+	if (!strncmp(line + 41, "not-for-merge", 13))
+		return 0;
+
+	if (line[41] != '\t')
+		return 2;
+
+	line[40] = 0;
+	sha1 = xmalloc(20);
+	i = get_sha1(line, sha1);
+	line[40] = '\t';
+	if (i)
+		return 3;
+
+	if (line[len - 1] == '\n')
+		line[len - 1] = 0;
+	line += 42;
+
+	src = strstr(line, " of ");
+	if (src) {
+		*src = 0;
+		src += 4;
+	} else
+		src = "HEAD";
+
+	i = find_in_list(&srcs, src);
+	if (i < 0) {
+		i = srcs.nr;
+		append_to_list(&srcs, strdup(src),
+				xcalloc(1, sizeof(struct src_data)));
+	}
+	src_data = srcs.payload[i];
+
+	if (!strncmp(line, "branch ", 7)) {
+		origin = strdup(line + 7);
+		append_to_list(&src_data->branch, origin, NULL);
+		src_data->head_status |= 2;
+	} else if (!strncmp(line, "tag ", 4)) {
+		origin = line;
+		append_to_list(&src_data->tag, strdup(origin + 4), NULL);
+		src_data->head_status |= 2;
+	} else if (!strncmp(line, "remote branch ", 14)) {
+		origin = strdup(line + 14);
+		append_to_list(&src_data->r_branch, origin, NULL);
+		src_data->head_status |= 2;
+	} else if (!strcmp(line, "HEAD")) {
+		origin = strdup(src);
+		src_data->head_status |= 1;
+	} else {
+		origin = strdup(src);
+		append_to_list(&src_data->generic, strdup(line), NULL);
+		src_data->head_status |= 2;
+	}
+
+	if (!strcmp(".", src) || !strcmp(src, origin)) {
+		int len = strlen(origin);
+		if (origin[0] == '\'' && origin[len - 1] == '\'') {
+			char *new_origin = malloc(len - 1);
+			memcpy(new_origin, origin + 1, len - 2);
+			new_origin[len - 1] = 0;
+			origin = new_origin;
+		} else
+			origin = strdup(origin);
+	} else {
+		char *new_origin = malloc(strlen(origin) + strlen(src) + 5);
+		sprintf(new_origin, "%s of %s", origin, src);
+		origin = new_origin;
+	}
+	append_to_list(&origins, origin, sha1);
+	return 0;
+}
+
+static void print_joined(const char *singular, const char *plural,
+		struct list *list)
+{
+	if (list->nr == 0)
+		return;
+	if (list->nr == 1) {
+		printf("%s%s", singular, list->list[0]);
+	} else {
+		int i;
+		printf("%s", plural);
+		for (i = 0; i < list->nr - 1; i++)
+			printf("%s%s", i > 0 ? ", " : "", list->list[i]);
+		printf(" and %s", list->list[list->nr - 1]);
+	}
+}
+
+static void shortlog(const char *name, unsigned char *sha1,
+		struct commit *head, struct rev_info *rev, int limit)
+{
+	int i, count = 0;
+	struct commit *commit;
+	struct object *branch;
+	struct list subjects = { NULL, NULL, 0, 0 };
+	int flags = UNINTERESTING | TREECHANGE | SEEN | SHOWN | ADDED;
+
+	branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
+	if (!branch || branch->type != TYPE_COMMIT)
+		return;
+
+	setup_revisions(0, NULL, rev, NULL);
+	rev->ignore_merges = 1;
+	add_pending_object(rev, branch, name);
+	add_pending_object(rev, &head->object, "^HEAD");
+	head->object.flags |= UNINTERESTING;
+	prepare_revision_walk(rev);
+	while ((commit = get_revision(rev)) != NULL) {
+		char *oneline, *bol, *eol;
+
+		/* ignore merges */
+		if (commit->parents && commit->parents->next)
+			continue;
+
+		count++;
+		if (subjects.nr > limit)
+			continue;
+
+		bol = strstr(commit->buffer, "\n\n");
+		if (!bol) {
+			append_to_list(&subjects, strdup(sha1_to_hex(
+							commit->object.sha1)),
+					NULL);
+			continue;
+		}
+
+		bol += 2;
+		eol = strchr(bol, '\n');
+
+		if (eol) {
+			int len = eol - bol;
+			oneline = malloc(len + 1);
+			memcpy(oneline, bol, len);
+			oneline[len] = 0;
+		} else
+			oneline = strdup(bol);
+		append_to_list(&subjects, oneline, NULL);
+	}
+
+	if (count > limit)
+		printf("\n* %s: (%d commits)\n", name, count);
+	else
+		printf("\n* %s:\n", name);
+
+	for (i = 0; i < subjects.nr; i++)
+		if (i >= limit)
+			printf("  ...\n");
+		else
+			printf("  %s\n", subjects.list[i]);
+
+	clear_commit_marks((struct commit *)branch, flags);
+	clear_commit_marks(head, flags);
+	free_commit_list(rev->commits);
+	rev->commits = NULL;
+	rev->pending.nr = 0;
+
+	free_list(&subjects);
+}
+
+int cmd_fmt_merge_msg(int argc, char **argv, char **envp)
+{
+	int limit = 20, i = 0;
+	char line[1024];
+	FILE *in = stdin;
+	const char *sep = "";
+	unsigned char head_sha1[20];
+	const char *head, *current_branch;
+
+	git_config(fmt_merge_msg_config);
+
+	while (argc > 1) {
+		if (!strcmp(argv[1], "--summary"))
+			merge_summary = 1;
+		else if (!strcmp(argv[1], "--no-summary"))
+			merge_summary = 0;
+		else if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--file")) {
+			if (argc < 2)
+				die ("Which file?");
+			if (!strcmp(argv[2], "-"))
+				in = stdin;
+			else {
+				fclose(in);
+				in = fopen(argv[2], "r");
+			}
+			argc--; argv++;
+		} else
+			break;
+		argc--; argv++;
+	}
+
+	if (argc > 1)
+		usage(fmt_merge_msg_usage);
+
+	/* get current branch */
+	head = strdup(git_path("HEAD"));
+	current_branch = resolve_ref(head, head_sha1, 1);
+	current_branch += strlen(head) - 4;
+	free((char *)head);
+	if (!strncmp(current_branch, "refs/heads/", 11))
+		current_branch += 11;
+
+	while (fgets(line, sizeof(line), in)) {
+		i++;
+		if (line[0] == 0)
+			continue;
+		if (handle_line(line))
+			die ("Error in line %d: %s", i, line);
+	}
+
+	printf("Merge ");
+	for (i = 0; i < srcs.nr; i++) {
+		struct src_data *src_data = srcs.payload[i];
+		const char *subsep = "";
+
+		printf(sep);
+		sep = "; ";
+
+		if (src_data->head_status == 1) {
+			printf(srcs.list[i]);
+			continue;
+		}
+		if (src_data->head_status == 3) {
+			subsep = ", ";
+			printf("HEAD");
+		}
+		if (src_data->branch.nr) {
+			printf(subsep);
+			subsep = ", ";
+			print_joined("branch ", "branches ", &src_data->branch);
+		}
+		if (src_data->r_branch.nr) {
+			printf(subsep);
+			subsep = ", ";
+			print_joined("remote branch ", "remote branches ",
+					&src_data->r_branch);
+		}
+		if (src_data->tag.nr) {
+			printf(subsep);
+			subsep = ", ";
+			print_joined("tag ", "tags ", &src_data->tag);
+		}
+		if (src_data->generic.nr) {
+			printf(subsep);
+			print_joined("commit ", "commits ", &src_data->generic);
+		}
+		if (strcmp(".", srcs.list[i]))
+			printf(" of %s", srcs.list[i]);
+	}
+
+	if (!strcmp("master", current_branch))
+		putchar('\n');
+	else
+		printf(" into %s\n", current_branch);
+
+	if (merge_summary) {
+		struct commit *head;
+		struct rev_info rev;
+
+		head = lookup_commit(head_sha1);
+		init_revisions(&rev);
+		rev.commit_format = CMIT_FMT_ONELINE;
+		rev.ignore_merges = 1;
+		rev.limited = 1;
+
+		for (i = 0; i < origins.nr; i++)
+			shortlog(origins.list[i], origins.payload[i],
+					head, &rev, limit);
+	}
+
+	/* No cleanup yet; is standalone anyway */
+
+	return 0;
+}
+
diff --git a/builtin.h b/builtin.h
old mode 100644
new mode 100755
index f12d5e6..d9e5483
--- a/builtin.h
+++ b/builtin.h
@@ -49,6 +49,7 @@ extern int cmd_cat_file(int argc, const 
 extern int cmd_rev_parse(int argc, const char **argv, char **envp);
 extern int cmd_update_index(int argc, const char **argv, char **envp);
 extern int cmd_update_ref(int argc, const char **argv, char **envp);
+extern int cmd_fmt_merge_msg(int argc, const char **argv, char **envp);
 
 extern int cmd_write_tree(int argc, const char **argv, char **envp);
 extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
diff --git a/git.c b/git.c
index 512fa63..7cc826b 100644
--- a/git.c
+++ b/git.c
@@ -200,7 +200,8 @@ static void handle_internal_command(int 
 		{ "mailinfo", cmd_mailinfo },
 		{ "stripspace", cmd_stripspace },
 		{ "update-index", cmd_update_index },
-		{ "update-ref", cmd_update_ref }
+		{ "update-ref", cmd_update_ref },
+		{ "fmt-merge-msg", cmd_fmt_merge_msg }
 	};
 	int i;
 
-- 
1.4.1.gb2dcd-dirty

^ permalink raw reply related

* Re: [PATCH] Make git-fmt-merge-msg a builtin
From: Timo Hirvonen @ 2006-07-03 15:26 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, junkio
In-Reply-To: <Pine.LNX.4.63.0607031632290.29667@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:

> I had in mind that I want to use path-list instead (which is cooking in 
> the merge-recursive efforts ATM). And there, I would add a flag 
> needs_payload. Opinions?

This code is so simple that making the path_list more complex
(needs_payload special case?) is not worth it.  I have not looked at the
code very closely though and have no idea what I'm talking about :)

> > > +static void free_list(struct list *list)
> > > +{
> > > +	int i;
> > > +
> > > +	if (list->alloc == 0)
> > > +		return;
> > 
> > Unnecessary if nr is 0 too.
> 
> No. If nr == 0, alloc need not be 0, and if it is not, list and payload 
> are still allocated.

If alloc is 0 then nr is 0 too (at least it _should_ be).  The code would
effectively become:

	for (i = 0; i < 0; i++) {
		...
	}
	free(NULL);
	free(NULL);
	list->nr = list->alloc = 0;

But this is not important...

> > free(NULL) is safe.
> 
> Is it? I vaguely remember that I had problems with this on some obscure 
> platform.

I don't think so.

-- 
http://onion.dynserv.net/~timo/

^ permalink raw reply

* Re: [PATCH] Make git-fmt-merge-msg a builtin
From: Johannes Schindelin @ 2006-07-03 15:45 UTC (permalink / raw)
  To: Timo Hirvonen; +Cc: git, junkio
In-Reply-To: <20060703182621.dbed5b5f.tihirvon@gmail.com>

Hi,

On Mon, 3 Jul 2006, Timo Hirvonen wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> 
> > I had in mind that I want to use path-list instead (which is cooking in 
> > the merge-recursive efforts ATM). And there, I would add a flag 
> > needs_payload. Opinions?
> 
> This code is so simple that making the path_list more complex 
> (needs_payload special case?) is not worth it.  I have not looked at the 
> code very closely though and have no idea what I'm talking about :)

Okay. But I'd rather go back to work on merge-recursive, and just reuse 
the path_list struct.

> > > free(NULL) is safe.
> > 
> > Is it? I vaguely remember that I had problems with this on some obscure 
> > platform.
> 
> I don't think so.

Well, after a little Googling, I am more convinced than ever that it is a 
BAD thing to rely on free(NULL) being a NOP.

Ciao,
Dscho

^ permalink raw reply


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