Git development
 help / color / mirror / Atom feed
* [zooko@zooko.com: [Revctrl] colliding md5 hashes of human-meaningful documents]
From: Petr Baudis @ 2005-06-12  8:25 UTC (permalink / raw)
  To: git; +Cc: torvalds

----- Forwarded message from zooko@zooko.com -----

There is nothing theoretically surprising about this, but hopefully its
concreteness and the accompanying scenario will make an impression on people
on people.  The same technique should work to generate two documents with
identical SHA1 hashes.

http://www.cits.rub.de/MD5Collisions/

----- End forwarded message -----

I expected the two postscript files differing in some huge binary blob,
but it turns out the binary part is very small (about 256 bytes) and
only few (about nine) bytes are different, contrary to how people have
predicted the collisions. This is much more close to finding a collision
between similar pure C files, I think. Rather unsettling.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
<Espy> be careful, some twit might quote you out of context..

^ permalink raw reply

* Re: [PATCH] Rewrite cg-diff colorization, add diffstat and reverse
From: Petr Baudis @ 2005-06-12  7:29 UTC (permalink / raw)
  To: Dan Holmsand; +Cc: git
In-Reply-To: <42AAF54C.3010908@gmail.com>

Dear diary, on Sat, Jun 11, 2005 at 04:29:32PM CEST, I got a letter
where Dan Holmsand <holmsand@gmail.com> told me that...
> Petr Baudis wrote:
> >Dear diary, on Thu, Jun 09, 2005 at 01:24:07PM CEST, I got a letter
> >where Dan Holmsand <holmsand@gmail.com> told me that...
> >
> >I'm sorry, but those two patches are still way too big and therefore
> >basically unreviewable. Could you please split them further to a
> >per-feature patches?
> >
> >A good place to start would be changing the [PATCH 2/6] color refactor
> >to actually _replace_ the color stuff of cg-log and cg-diff with the new
> >common cg-Xlib code - but please don't change the default colors in that
> >patch yet (that is because you shouldn't assume in your earlier patches
> >that later patches will be applied, or applied in the form you send
> >them; I don't know about the less search thing yet, since I didn't test
> >it, since I don't have a focused patch for it).,
> 
> Ok, here's another one to start with.
> 
> cg-diff only, this time around. It's much simpler, since cg-diff got a 
> lot more similar to your stuff due to your excellent optparse-ification.
> 
> If this is still too big, I'm not really sure how to go about this.

Well, would it be a problem to first do the color handling separately,
as I suggested? Also, you bundle in a bunch of non-vital cleanups -
nothing wrong about them but they are really cluttering the patch up and
you could do them separately.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
<Espy> be careful, some twit might quote you out of context..

^ permalink raw reply

* [PATCH] Add --diff-filter= output restriction to diff-* family.
From: Junio C Hamano @ 2005-06-12  3:57 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7vfyvpxlqi.fsf@assigned-by-dhcp.cox.net>

This is a halfway between debugging aid and a helper to write an
ultra-smart merge scripts.  The new option takes a string that
consists of a list of "status" letters, and limits the diff
output to only those classes of changes, with two exceptions:

 - A broken pair (aka "complete rewrite"), does not match D
   (deleted) or N (created).  Use B to look for them.

 - The letter "A" in the diff-filter string does not match
   anything itself, but causes the entire diff that contains
   selected patches to be output (this behaviour is similar to
   that of --pickaxe-all for the -S option).

For example,

    $ git-rev-list HEAD |
      git-diff-tree --stdin -s -v -B -C --diff-filter=BCR

shows a list of commits that have complete rewrite, copy, or
rename.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 diff.h        |    8 +++++--
 diff-cache.c  |    9 ++++++-
 diff-files.c  |    7 ++++--
 diff-helper.c |   15 +++++++-----
 diff-stages.c |    8 +++++--
 diff-tree.c   |   12 +++++++---
 diff.c        |   70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 7 files changed, 108 insertions(+), 21 deletions(-)

diff --git a/diff.h b/diff.h
--- a/diff.h
+++ b/diff.h
@@ -47,7 +47,11 @@ extern void diffcore_std(const char **pa
 			 int detect_rename, int rename_score,
 			 const char *pickaxe, int pickaxe_opts,
 			 int break_opt,
-			 const char *orderfile);
+			 const char *orderfile, const char *filter);
+
+extern void diffcore_std_no_resolve(const char **paths,
+				    const char *pickaxe, int pickaxe_opts,
+				    const char *orderfile, const char *filter);
 
 extern int diff_queue_is_empty(void);
 
@@ -56,6 +60,6 @@ extern int diff_queue_is_empty(void);
 #define DIFF_FORMAT_PATCH	2
 #define DIFF_FORMAT_NO_OUTPUT	3
 
-extern void diff_flush(int output_style, int resolve_rename_copy);
+extern void diff_flush(int output_style);
 
 #endif /* DIFF_H */
diff --git a/diff-cache.c b/diff-cache.c
--- a/diff-cache.c
+++ b/diff-cache.c
@@ -11,6 +11,7 @@ static const char *pickaxe = NULL;
 static int pickaxe_opts = 0;
 static int diff_break_opt = -1;
 static const char *orderfile = NULL;
+static const char *diff_filter = NULL;
 
 /* A file entry went away or appeared */
 static void show_file(const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
@@ -224,6 +225,10 @@ int main(int argc, const char **argv)
 			pickaxe = arg + 2;
 			continue;
 		}
+		if (!strncmp(arg, "--diff-filter=", 14)) {
+			diff_filter = arg + 14;
+			continue;
+		}
 		if (!strncmp(arg, "-O", 2)) {
 			orderfile = arg + 2;
 			continue;
@@ -263,7 +268,7 @@ int main(int argc, const char **argv)
 		     detect_rename, diff_score_opt,
 		     pickaxe, pickaxe_opts,
 		     diff_break_opt,
-		     orderfile);
-	diff_flush(diff_output_format, 1);
+		     orderfile, diff_filter);
+	diff_flush(diff_output_format);
 	return ret;
 }
diff --git a/diff-files.c b/diff-files.c
--- a/diff-files.c
+++ b/diff-files.c
@@ -17,6 +17,7 @@ static const char *pickaxe = NULL;
 static int pickaxe_opts = 0;
 static int diff_break_opt = -1;
 static const char *orderfile = NULL;
+static const char *diff_filter = NULL;
 static int silent = 0;
 
 static void show_unmerge(const char *path)
@@ -59,6 +60,8 @@ int main(int argc, const char **argv)
 			pickaxe = argv[1] + 2;
 		else if (!strncmp(argv[1], "-O", 2))
 			orderfile = argv[1] + 2;
+		else if (!strncmp(argv[1], "--diff-filter=", 14))
+			diff_filter = argv[1] + 14;
 		else if (!strcmp(argv[1], "--pickaxe-all"))
 			pickaxe_opts = DIFF_PICKAXE_ALL;
 		else if (!strncmp(argv[1], "-B", 2)) {
@@ -131,7 +134,7 @@ int main(int argc, const char **argv)
 		     detect_rename, diff_score_opt,
 		     pickaxe, pickaxe_opts,
 		     diff_break_opt,
-		     orderfile);
-	diff_flush(diff_output_format, 1);
+		     orderfile, diff_filter);
+	diff_flush(diff_output_format);
 	return 0;
 }
diff --git a/diff-helper.c b/diff-helper.c
--- a/diff-helper.c
+++ b/diff-helper.c
@@ -8,17 +8,16 @@
 static const char *pickaxe = NULL;
 static int pickaxe_opts = 0;
 static const char *orderfile = NULL;
+static const char *diff_filter = NULL;
 static int line_termination = '\n';
 static int inter_name_termination = '\t';
 
 static void flush_them(int ac, const char **av)
 {
-	diffcore_std(av + 1,
-		     0, 0, /* no renames */
-		     pickaxe, pickaxe_opts,
-		     -1, /* no breaks */
-		     orderfile);
-	diff_flush(DIFF_FORMAT_PATCH, 0);
+	diffcore_std_no_resolve(av + 1,
+				pickaxe, pickaxe_opts,
+				orderfile, diff_filter);
+	diff_flush(DIFF_FORMAT_PATCH);
 }
 
 static const char *diff_helper_usage =
@@ -38,6 +37,10 @@ int main(int ac, const char **av) {
 		}
 		else if (!strcmp(av[1], "--pickaxe-all"))
 			pickaxe_opts = DIFF_PICKAXE_ALL;
+		else if (!strncmp(av[1], "--diff-filter=", 14))
+			diff_filter = av[1] + 14;
+		else if (!strncmp(av[1], "-O", 2))
+			orderfile = av[1] + 2;
 		else
 			usage(diff_helper_usage);
 		ac--; av++;
diff --git a/diff-stages.c b/diff-stages.c
--- a/diff-stages.c
+++ b/diff-stages.c
@@ -13,6 +13,7 @@ static const char *pickaxe = NULL;
 static int pickaxe_opts = 0;
 static int diff_break_opt = -1;
 static const char *orderfile = NULL;
+static const char *diff_filter = NULL;
 
 static char *diff_stages_usage =
 "git-diff-stages [-p] [-r] [-z] [-M] [-C] [-R] [-S<string>] [-O<orderfile>] <stage1> <stage2> [<path>...]";
@@ -88,6 +89,8 @@ int main(int ac, const char **av)
 			pickaxe = arg + 2;
 		else if (!strncmp(arg, "-O", 2))
 			orderfile = arg + 2;
+		else if (!strncmp(arg, "--diff-filter=", 14))
+			diff_filter = arg + 14;
 		else if (!strcmp(arg, "--pickaxe-all"))
 			pickaxe_opts = DIFF_PICKAXE_ALL;
 		else
@@ -111,7 +114,8 @@ int main(int ac, const char **av)
 		     detect_rename, diff_score_opt,
 		     pickaxe, pickaxe_opts,
 		     diff_break_opt,
-		     orderfile);
-	diff_flush(diff_output_format, 1);
+		     orderfile,
+		     diff_filter);
+	diff_flush(diff_output_format);
 	return 0;
 }
diff --git a/diff-tree.c b/diff-tree.c
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -18,6 +18,7 @@ static const char *pickaxe = NULL;
 static int pickaxe_opts = 0;
 static int diff_break_opt = -1;
 static const char *orderfile = NULL;
+static const char *diff_filter = NULL;
 static const char *header = NULL;
 static const char *header_prefix = "";
 static enum cmit_fmt commit_format = CMIT_FMT_RAW;
@@ -272,9 +273,10 @@ static int call_diff_flush(void)
 		     detect_rename, diff_score_opt,
 		     pickaxe, pickaxe_opts,
 		     diff_break_opt,
-		     orderfile);
+		     orderfile,
+		     diff_filter);
 	if (diff_queue_is_empty()) {
-		diff_flush(DIFF_FORMAT_NO_OUTPUT, 0);
+		diff_flush(DIFF_FORMAT_NO_OUTPUT);
 		return 0;
 	}
 	if (header) {
@@ -285,7 +287,7 @@ static int call_diff_flush(void)
 		printf(fmt, header, 0);
 		header = NULL;
 	}
-	diff_flush(diff_output_format, 1);
+	diff_flush(diff_output_format);
 	return 1;
 }
 
@@ -455,6 +457,10 @@ int main(int argc, const char **argv)
 			orderfile = arg + 2;
 			continue;
 		}
+		if (!strncmp(arg, "--diff-filter=", 14)) {
+			diff_filter = arg + 14;
+			continue;
+		}
 		if (!strcmp(arg, "--pickaxe-all")) {
 			pickaxe_opts = DIFF_PICKAXE_ALL;
 			continue;
diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -920,7 +920,7 @@ static void diff_resolve_rename_copy(voi
 	diff_debug_queue("resolve-rename-copy done", q);
 }
 
-void diff_flush(int diff_output_style, int resolve_rename_copy)
+void diff_flush(int diff_output_style)
 {
 	struct diff_queue_struct *q = &diff_queued_diff;
 	int i;
@@ -929,8 +929,6 @@ void diff_flush(int diff_output_style, i
 
 	if (diff_output_style == DIFF_FORMAT_MACHINE)
 		line_termination = inter_name_termination = 0;
-	if (resolve_rename_copy)
-		diff_resolve_rename_copy();
 
 	for (i = 0; i < q->nr; i++) {
 		struct diff_filepair *p = q->queue[i];
@@ -957,11 +955,58 @@ void diff_flush(int diff_output_style, i
 	q->nr = q->alloc = 0;
 }
 
+static void diffcore_apply_filter(const char *filter)
+{
+	int i;
+	struct diff_queue_struct *q = &diff_queued_diff;
+	struct diff_queue_struct outq;
+	outq.queue = NULL;
+	outq.nr = outq.alloc = 0;
+
+	if (!filter)
+		return;
+
+	if (strchr(filter, 'A')) {
+		/* All-or-none */
+		int found;
+		for (i = found = 0; !found && i < q->nr; i++) {
+			struct diff_filepair *p = q->queue[i];
+			if ((p->broken_pair && strchr(filter, 'B')) ||
+			    (!p->broken_pair && strchr(filter, p->status)))
+				found++;
+		}
+		if (found)
+			return;
+
+		/* otherwise we will clear the whole queue
+		 * by copying the empty outq at the end of this
+		 * function, but first clear the current entries
+		 * in the queue.
+		 */
+		for (i = 0; i < q->nr; i++)
+			diff_free_filepair(q->queue[i]);
+	}
+	else {
+		/* Only the matching ones */
+		for (i = 0; i < q->nr; i++) {
+			struct diff_filepair *p = q->queue[i];
+			if ((p->broken_pair && strchr(filter, 'B')) ||
+			    (!p->broken_pair && strchr(filter, p->status)))
+				diff_q(&outq, p);
+			else
+				diff_free_filepair(p);
+		}
+	}
+	free(q->queue);
+	*q = outq;
+}
+
 void diffcore_std(const char **paths,
 		  int detect_rename, int rename_score,
 		  const char *pickaxe, int pickaxe_opts,
 		  int break_opt,
-		  const char *orderfile)
+		  const char *orderfile,
+		  const char *filter)
 {
 	if (paths && paths[0])
 		diffcore_pathspec(paths);
@@ -975,6 +1020,23 @@ void diffcore_std(const char **paths,
 		diffcore_pickaxe(pickaxe, pickaxe_opts);
 	if (orderfile)
 		diffcore_order(orderfile);
+	diff_resolve_rename_copy();
+	diffcore_apply_filter(filter);
+}
+
+
+void diffcore_std_no_resolve(const char **paths,
+			     const char *pickaxe, int pickaxe_opts,
+			     const char *orderfile,
+			     const char *filter)
+{
+	if (paths && paths[0])
+		diffcore_pathspec(paths);
+	if (pickaxe)
+		diffcore_pickaxe(pickaxe, pickaxe_opts);
+	if (orderfile)
+		diffcore_order(orderfile);
+	diffcore_apply_filter(filter);
 }
 
 void diff_addremove(int addremove, unsigned mode,
------------


^ permalink raw reply

* [PATCH] Fix rename/copy when dealing with temporarily broken pairs.
From: Junio C Hamano @ 2005-06-12  3:55 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7vfyvpxlqi.fsf@assigned-by-dhcp.cox.net>

When rename/copy uses a file that was broken by diffcore-break
as the source, and the broken filepair gets merged back later,
the output was mislabeled as a rename.  In this case, the source
file ends up staying in the output, so we should label it as a
copy instead.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 diff.c            |    1 +
 diffcore-rename.c |   10 ++++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -661,6 +661,7 @@ struct diff_filepair *diff_queue(struct 
 	dp->one = one;
 	dp->two = two;
 	dp->score = 0;
+	dp->status = 0;
 	dp->source_stays = 0;
 	dp->broken_pair = 0;
 	diff_q(queue, dp);
diff --git a/diffcore-rename.c b/diffcore-rename.c
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -249,8 +249,14 @@ void diffcore_rename(int detect_rename, 
 				continue; /* unmerged */
 			else
 				locate_rename_dst(p->two, 1);
-		else if (!DIFF_FILE_VALID(p->two))
-			register_rename_src(p->one, 0);
+		else if (!DIFF_FILE_VALID(p->two)) {
+			/* If the source is a broken "delete", and
+			 * they did not really want to get broken,
+			 * that means the source actually stays.
+			 */
+			int stays = (p->broken_pair && !p->score);
+			register_rename_src(p->one, stays);
+		}
 		else if (detect_rename == DIFF_DETECT_COPY)
 			register_rename_src(p->one, 1);
 	}
------------


^ permalink raw reply

* [PATCH] apply.c: tolerate diff from a dirty but unchanged path
From: Junio C Hamano @ 2005-06-11 23:27 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0505291151250.10545@ppc970.osdl.org>

I just noticed a problem with empty "diff --git" header a dirty
but otherwise unmodified path spits out.  The problem is related
to an old topic:

    Re: [PATCH] Do not show empty diff in diff-cache uncached.
    >>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:

    LT> On Sat, 28 May 2005, Junio C Hamano wrote:
    >> Recent diff-cache produces "diff --git" header internally before
    >> calling the "diff" command, which results in an empty diff for
    >> such a file, cluttering the output.  This patch fixes this.

    LT> I actually _expect_ that "git-diff-files" will show
    LT> files that don't match the index, even if they happen to
    LT> have the exact content that the index points to. It's
    LT> how I know whether the index is up-to-date or not.

I now agree with the reasoning and think showing an empty "diff
--git" header is a good thing.  I had something like this, while
fixing a rename/copy bug:

    ...
     #endif

     static void diff_resolve_rename_copy(void)
    diff --git a/diffcore-break.c b/diffcore-break.c
    diff --git a/diffcore-rename.c b/diffcore-rename.c
    --- a/diffcore-rename.c
    +++ b/diffcore-rename.c
    @@ -249,8 +249,12 @@ void diffcore_rename(int detect_rename, 
    ...

I touched diffcore-break.c and decided I should not change it so
I reverted, which is why the empty "diff --git" for that file
shows that the cache is dirty.  The problem is that currently,
"git-apply --stat" seems to barf reading such a patch.

Here is a proposed fix.

------------
apply.c: tolerate diff from a dirty but otherwise unchanged cache.

For such an entry, "diff --git" line without anything else is
output, but the next "diff --git" header is not really treated
as an unrecognized diff.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
diff --git a/apply.c b/apply.c
--- a/apply.c
+++ b/apply.c
@@ -343,7 +343,7 @@ static int gitdiff_dissimilarity(const c
  */
 static int gitdiff_unrecognized(const char *line, struct patch *patch)
 {
-	return -1;
+	return -2;
 }
 
 static char *git_header_name(char *line)
@@ -453,8 +453,12 @@ static int parse_git_header(char *line, 
 			int oplen = strlen(p->str);
 			if (len < oplen || memcmp(p->str, line, oplen))
 				continue;
-			if (p->fn(line + oplen, patch) < 0)
+			switch (p->fn(line + oplen, patch)) {
+			case -1:
 				return offset;
+			case -2:
+				return -1;
+			}
 			break;
 		}
 	}


^ permalink raw reply

* Re: [OT] mutually supervised developers
From: Linus Torvalds @ 2005-06-11 23:14 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Petr Baudis
In-Reply-To: <7vy89gsiak.fsf@assigned-by-dhcp.cox.net>



On Sat, 11 Jun 2005, Junio C Hamano wrote:
> 
> I am wondering if the world would be a better place if this
> fictitious project sets up public repositories in the following
> way:
> 
>  (1) each developer's own repository is public;
> 
>  (2) these developers pull from each other "only good stuff",
>      rejecting things he or she feels questionable.  Let's
>      forget that current GIT does not give a direct support for
>      cherrypicking for now.
> 
>  (3) the public canonical repository is updated to contain the
>      intersection (_not_ union) of these developer repositories.
>      Let's also forget that current GIT does not have automated
>      way to do such a thing.

I've thought about it, but one problem ends up being the history.

Even if both developers have the same patches, they may not have gotten 
them in the same order, which means that it's basically impossible to 
retain history when doign an intersection. Unions are different - we can 
just add the new history when we create a union.

> Would people find something like this arrangement workable and
> worthwhile?

If you can explain how it would actually work.. 

		Linus

^ permalink raw reply

* Re: Cogito: split Makefile targets of Cogito/git
From: Junio C Hamano @ 2005-06-11 22:09 UTC (permalink / raw)
  To: Kay Sievers; +Cc: git
In-Reply-To: <20050611195033.GA22713@vrfy.org>

>>>>> "KS" == Kay Sievers <kay.sievers@vrfy.org> writes:

KS> -
KS> -all: $(PROG) $(GEN_SCRIPT)
KS> -
KS> +.PHONY: all it cogito
KS> +all: git cogito
KS> +git: $(PROG)
KS> +cogito: $(GEN_SCRIPT)
 
(Tongue in cheek)  How about this instead ;^) 

    -
    -all: $(PROG) $(GEN_SCRIPT)
    -
    +.PHONY: all git coo
    +all: git coo
    +git: $(PROG)
    +coo: $(GEN_SCRIPT)



^ permalink raw reply

* [OT] mutually supervised developers
From: Junio C Hamano @ 2005-06-11 21:19 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds, Petr Baudis

I think this is somewhat offtopic here, but I was wondering:

 - if a development model like this would make sense,

 - and if so if we would want GIT to support such a model,

 - and if so if the current GIT already offers such support,

 - and if not what kind of primitives at the core layer we would
   need to add.

Let's assume that a project is co-managed by a handful top-tier
developers and has an active development community.  There is
_the_ public repository that all users consider the canonical
starting point to base their work off of.  It would be like -git
snapshot tree or -mm tree in Linux 2.6 kernel.

These developers are all active in the community, and at times
are overenthusiastic.  Their own changes are usually quite good,
they also have good taste when accepting outside patches, but
they all tend to commit not-so-well-thought-out crapola of their
own from time to time to their own repository.

I am wondering if the world would be a better place if this
fictitious project sets up public repositories in the following
way:

 (1) each developer's own repository is public;

 (2) these developers pull from each other "only good stuff",
     rejecting things he or she feels questionable.  Let's
     forget that current GIT does not give a direct support for
     cherrypicking for now.

 (3) the public canonical repository is updated to contain the
     intersection (_not_ union) of these developer repositories.
     Let's also forget that current GIT does not have automated
     way to do such a thing.

This would give each developer an "adult supervision" by all the
other developers, because any stuff that somebody finds
questionable will not be included in the "intersection".  The
public canonical repository is essentially to contain the
community "concensus".

Applying the above outline literally is inpractical in that it
gives any slow (or just otherwise busy) developer an unintended
"veto" power to freeze the canonical tree, so the management of
the canonical repository part may need to be tweaked with
something like majority rule, but the basic idea is to help
people get mutual supervision to prevent them from spreading
crap they may later regret.

Would people find something like this arrangement workable and
worthwhile?


^ permalink raw reply

* Re: Cogito: split Makefile targets of Cogito/git
From: Petr Baudis @ 2005-06-11 21:11 UTC (permalink / raw)
  To: Kay Sievers; +Cc: git
In-Reply-To: <20050611201933.GC22991@vrfy.org>

Dear diary, on Sat, Jun 11, 2005 at 10:19:33PM CEST, I got a letter
where Kay Sievers <kay.sievers@vrfy.org> told me that...
> On Sat, Jun 11, 2005 at 09:50:33PM +0200, Kay Sievers wrote:
> > This splits the targets of Cogito/git to be able to call it
> > independently. This way we can easily make Cogito a separate
> > package, which just requires git.
> 
> > +.PHONY: all it cogito
> 
> "all it cogito" sounds funny, but is obviously wrong. :)
> New patch attached.

Could you please sign off the patch?

Thanks,

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
<Espy> be careful, some twit might quote you out of context..

^ permalink raw reply

* Re: Cogito: split Makefile targets of Cogito/git
From: Kay Sievers @ 2005-06-11 20:19 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20050611195033.GA22713@vrfy.org>

[-- Attachment #1: Type: text/plain, Size: 345 bytes --]

On Sat, Jun 11, 2005 at 09:50:33PM +0200, Kay Sievers wrote:
> This splits the targets of Cogito/git to be able to call it
> independently. This way we can easily make Cogito a separate
> package, which just requires git.

> +.PHONY: all it cogito

"all it cogito" sounds funny, but is obviously wrong. :)
New patch attached.

Thanks Dave!

Kay

[-- Attachment #2: cogito-Makefile-split-install.patch --]
[-- Type: text/plain, Size: 1044 bytes --]

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -112,9 +112,10 @@ endif
 
 CFLAGS += '-DSHA1_HEADER=$(SHA1_HEADER)'
 
-
-all: $(PROG) $(GEN_SCRIPT)
-
+.PHONY: all git cogito
+all: git cogito
+git: $(PROG)
+cogito: $(GEN_SCRIPT)
 
 test-delta: test-delta.c diff-delta.o patch-delta.o
 	$(CC) $(CFLAGS) -o $@ $^
@@ -169,9 +170,16 @@ test: all
 
 sedlibdir=$(shell echo $(libdir) | sed 's/\//\\\//g')
 
-install: $(PROG) $(SCRIPTS) $(SCRIPT) $(LIB_SCRIPT) $(GEN_SCRIPT)
+.PHONY: install install-git install-cogito
+install: install-git install-cogito
+
+install-git: $(PROG) $(SCRIPTS)
+	$(INSTALL) -m755 -d $(DESTDIR)$(bindir)
+	$(INSTALL) $(PROG) $(SCRIPTS) $(DESTDIR)$(bindir)
+
+install-cogito: $(SCRIPT) $(LIB_SCRIPT) $(GEN_SCRIPT)
 	$(INSTALL) -m755 -d $(DESTDIR)$(bindir)
-	$(INSTALL) $(PROG) $(SCRIPTS) $(SCRIPT) $(GEN_SCRIPT) $(DESTDIR)$(bindir)
+	$(INSTALL) $(SCRIPT) $(GEN_SCRIPT) $(DESTDIR)$(bindir)
 	$(INSTALL) -m755 -d $(DESTDIR)$(libdir)
 	$(INSTALL) $(LIB_SCRIPT) $(DESTDIR)$(libdir)
 	cd $(DESTDIR)$(bindir); \

^ permalink raw reply

* Re: Cogito: split Makefile targets of Cogito/git
From: Sven Verdoolaege @ 2005-06-11 20:06 UTC (permalink / raw)
  To: Kay Sievers; +Cc: Petr Baudis, git
In-Reply-To: <20050611195033.GA22713@vrfy.org>

On Sat, Jun 11, 2005 at 09:50:33PM +0200, Kay Sievers wrote:
> +.PHONY: all it cogito

I suppose this should be

+.PHONY: all git cogito

skimo

^ permalink raw reply

* Cogito: split Makefile targets of Cogito/git
From: Kay Sievers @ 2005-06-11 19:50 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 168 bytes --]

This splits the targets of Cogito/git to be able to call it
independently. This way we can easily make Cogito a separate
package, which just requires git.

Thanks,
Kay

[-- Attachment #2: cogito-Makefile-split-install.patch --]
[-- Type: text/plain, Size: 1043 bytes --]

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -112,9 +112,10 @@ endif
 
 CFLAGS += '-DSHA1_HEADER=$(SHA1_HEADER)'
 
-
-all: $(PROG) $(GEN_SCRIPT)
-
+.PHONY: all it cogito
+all: git cogito
+git: $(PROG)
+cogito: $(GEN_SCRIPT)
 
 test-delta: test-delta.c diff-delta.o patch-delta.o
 	$(CC) $(CFLAGS) -o $@ $^
@@ -169,9 +170,16 @@ test: all
 
 sedlibdir=$(shell echo $(libdir) | sed 's/\//\\\//g')
 
-install: $(PROG) $(SCRIPTS) $(SCRIPT) $(LIB_SCRIPT) $(GEN_SCRIPT)
+.PHONY: install install-git install-cogito
+install: install-git install-cogito
+
+install-git: $(PROG) $(SCRIPTS)
+	$(INSTALL) -m755 -d $(DESTDIR)$(bindir)
+	$(INSTALL) $(PROG) $(SCRIPTS) $(DESTDIR)$(bindir)
+
+install-cogito: $(SCRIPT) $(LIB_SCRIPT) $(GEN_SCRIPT)
 	$(INSTALL) -m755 -d $(DESTDIR)$(bindir)
-	$(INSTALL) $(PROG) $(SCRIPTS) $(SCRIPT) $(GEN_SCRIPT) $(DESTDIR)$(bindir)
+	$(INSTALL) $(SCRIPT) $(GEN_SCRIPT) $(DESTDIR)$(bindir)
 	$(INSTALL) -m755 -d $(DESTDIR)$(libdir)
 	$(INSTALL) $(LIB_SCRIPT) $(DESTDIR)$(libdir)
 	cd $(DESTDIR)$(bindir); \

^ permalink raw reply

* Re: reducing line crossings in gitk
From: Junio C Hamano @ 2005-06-11 18:26 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: git
In-Reply-To: <17066.53047.660907.453399@cargo.ozlabs.ibm.com>

>>>>> "PM" == Paul Mackerras <paulus@samba.org> writes:

PM> I could add a heuristic to look for this case and reverse the order of
PM> the parents, which would reduce the line crossings and make the graph
PM> look neater.  Would this be worth the slight loss of information (in
PM> that the stuff pulled in would no longer always be to the right)?

Personally I find the current "crossing lines" display makes
what happened more visually obvious than "reverse order of the
parents", so I'd be happier if you keep things as they are.

Thanks for a wonderful tool.  May I ask for more?  Some are
minor UI enhancements, some are feature ideas.

 - The first time I tried it from somewhere random without
   having GIT_DIR environment, it just gave error and exited.
   Which is correct but could have been nicer.

   Adding a "Browse Repo" in the "File" menu to let the user
   switch which repository to browse (and when chosen start
   afresh, of course) would be nicer, while keeping the default
   of showing the current ${GIT_DIR:=.git} upon start-up.

 - What support from the core GIT side would you need if you
   wanted to let users browse a remote repo?  A way to inspect
   what is under ".git/refs/" hierarchy on the remote side?
   Anything else?

 - Pasting into the SHA1 field to "Go To" was a nuisance when
   the field already had a string in it.  Clearing the SHA1
   field when focus gets in would be one way to solve it, but
   then you would lose the way to pasting out of that field, so
   I do not know what to suggest offhand.

 - How do I "Find" backwards?  Not being able to find a way to
   do this was the most annoying thing for me.

 - After typing something in "Find" and hitting <ENTER>, if the
   focus stays in it and lets me hit <ENTER> again to go to the
   next one would be nicer.  Somehow hitting <ENTER> again would
   not do this for me right now.

 - Indicaing "Find" wrapping around without annoying the user
   too much (i.e. I do _not_ want you to add "Find reached the
   beginning of time, wrapping around and continuing from the
   top" pop-up window) would be nicer.  Currently I can tell by
   looking at the scrollbar on the history pane jumping back, so
   this is not a big issue, though.

 - Can I have a way to "Find" next commit that touches a given
   pathname?

    $ git-rev-list | git-diff-tree -s -r --stdin '<that pathname>'

   which would give you a sequence of lines that look like:
       "commit-SHA1 (from parent-commit-SHA1)"

   you would pick the commit-SHA1 from the output and jump to it.

 - In addition to "Find" which looks at the commit message, can I
   have one that uses pickaxe to find changes?

   Add a new choice "In Patch" to the list of choices ("All
   fields", etc); sorry, but currently pickaxe can only do exact
   matches.  When you are operating in that mode, run

    $ git-rev-list | git-diff-tree -s -r --stdin -S'<that string>'

   which would give you a sequence of lines that look like:
       "commit-SHA1 (from parent-commit-SHA1)"

   you would pick the commit-SHA1 from the output and jump to it.

 - Can I have an option to use diffcore options to tweak the
   diff that is shown in the lower-left pane?

   Add "Diff" menu next to "File" menu, and have the following
   options: "Find Renames", "Find Copies", "Find Rewrites".

   The first two are mutually exclusive so you can have (1) both
   off, (2) Renames, or (3) Copies.  "Rewrites" is independent,
   so you end up with 6 combinations.  Give "-M", "-C", and "-B"
   option to git-diff-tree you run on the commit when these
   "Find foo" options are in effect, respectively.

   A good test case in GIT repository itself to try these are:

    418aaf847a8b3ffffb4f777a2dd5262ca5ce0ef7 (for -M)
	This renames rpull.c to ssh-pull.c etc.  Four renames in
	total.

    7ef76925d9c19ef74874e1735e2436e56d0c4897 (for -C)
	This creates git-fetch-script out of git-pull-script
        by copying.

    6af1f0192ff8740fe77db7cf02c739ccfbdf119c (for -B)
	This rewrites ls-tree.c

This list is based on gitk-1.1 (I downloaded this morning) so you
may already have unpublished solutions.


^ permalink raw reply

* new gitweb.cgi installed
From: Kay Sievers @ 2005-06-11 18:05 UTC (permalink / raw)
  To: git

The kernel.org boxes got the new git-binaries installed yesterday, so I've
updated gitweb.cgi:

The cgi itself is available here:
  ftp://www.kernel.org/pub/software/scm/gitweb/

Along with a few cosmetical changes, it:

o shows renames:
    http://www.kernel.org/git/?p=git/git.git;a=commit;h=418aaf847a8b3ffffb4f777a2dd5262ca5ce0ef7

o strips the merge messages down, that they actually readable the commit title
  Thanks to Tony Luck for the hint.

o has new RSS feed format, that hopefully prints the commit in the right
  format while still be valid XML
  Thanks to Jan Blunck for the patch and testing.

o shows now the right 8-space tab indentation for for the blob and diffs.
  Thanks to Matthijs Melchior for his help fixing it.

o has the  diff-link in the history renamed to "diff to current"
  this hopefully makes the intended behavior more obvious
  Thanks to Sean.

o has a link for a text/plain view of files and diffs

o does not use the old environment variables anymore

Best,
Kay

^ permalink raw reply

* Re: do people use the 'git' command?
From: Sebastian Kuzminsky @ 2005-06-11 17:14 UTC (permalink / raw)
  To: Kay Sievers; +Cc: git
In-Reply-To: <20050610185945.GB13102@vrfy.org>

Kay Sievers <kay.sievers@suse.de> wrote:
> On Fri, Jun 10, 2005 at 12:53:32PM -0600, Sebastian Kuzminsky wrote:
> > What good is the 'git' command?  It's a shortcut to run the
> > "git-$FUNCTION-script" programs, but it doesnt do the "git-$FUNCTION"
> > programs.  It just doesnt seem worth its inode, to me.  And it doesnt seem
> > worth the pain to distribution maintainers (like me) to avoid the naming
> > conflict with GNU Interactive Tools' /usr/bin/git.
> 
> Well, drop the GNU Interactive Tools instead. We've removed it from the
> SuSE packages and have a "real" git package now. :)

That sounds nice!  If only it weren't for all those pesky users...


-- 
Sebastian Kuzminsky

^ permalink raw reply

* Re: do people use the 'git' command?
From: Russ Allbery @ 2005-06-11 16:45 UTC (permalink / raw)
  To: git
In-Reply-To: <7v7jh1xli5.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> writes:
>>>>>> "RA" == Russ Allbery <rra@stanford.edu> writes:

> RA> ... it turns out in discussion on the Debian mailing lists
> RA> that people actually do use GIT.

> I thought the Debian way to resolve this kind of naming conflict
> was to rename _both_ commands involved.  Sorry if this was a
> misconception, but I think I read that somewhere in the
> developer's guide.

There are various ways in which you can deal with the problem, but then
you end up making that distribution different possibly than any other and
certainly different than the behavior people get when they build the
package themselves.  Then users ask questions here talking about running
"cogito-git" or the like and developers go "I've never heard of that
program," users try to use recipes off the net and the command isn't
found, etc.

Users of a tool like git are in a better position to figure this sort of
thing out, but it's still rather annoying and frustrating.

-- 
Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>

^ permalink raw reply

* Re: do people use the 'git' command?
From: Tommy M. McGuire @ 2005-06-11 16:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: jon, Sebastian Kuzminsky, git
In-Reply-To: <7vpsutz88z.fsf@assigned-by-dhcp.cox.net>

On Sat, Jun 11, 2005 at 12:02:20AM -0700, Junio C Hamano wrote:
> But the real point of "git" wrapper is merely to present CVS and SVN
> refugees the structure they are familiar with: a single command having
> a set of subcommands.

CVS and SVN refugees (like me :-)) should probably be pointed to
porcelain.  Showing them a mixture of relatively unpolished "git
<subcommand>" and "git-*" commands is not likely to impress them with
the simplicity and elegance of the tool.  I don't think the surface
structure of "<command> <subcommand>" is an important factor, and
the first time they see a 40-hex-digit number, they'll be headed for the
hills.

> Personally I think removal of "git" script is a bad idea.

I'd agree, for the opposite reason: the git script is a decent interface
for power users who don't want to use anything porcelainish.  It also
provides a good place to hang custom functionality.

-- 
Tommy McGuire

^ permalink raw reply

* [PATCH] Rewrite cg-diff colorization, add diffstat and reverse
From: Dan Holmsand @ 2005-06-11 14:29 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20050611000255.GI22111@pasky.ji.cz>

[-- Attachment #1: Type: text/plain, Size: 1888 bytes --]

Petr Baudis wrote:
> Dear diary, on Thu, Jun 09, 2005 at 01:24:07PM CEST, I got a letter
> where Dan Holmsand <holmsand@gmail.com> told me that...
> 
> I'm sorry, but those two patches are still way too big and therefore
> basically unreviewable. Could you please split them further to a
> per-feature patches?
> 
> A good place to start would be changing the [PATCH 2/6] color refactor
> to actually _replace_ the color stuff of cg-log and cg-diff with the new
> common cg-Xlib code - but please don't change the default colors in that
> patch yet (that is because you shouldn't assume in your earlier patches
> that later patches will be applied, or applied in the form you send
> them; I don't know about the less search thing yet, since I didn't test
> it, since I don't have a focused patch for it).,

Ok, here's another one to start with.

cg-diff only, this time around. It's much simpler, since cg-diff got a 
lot more similar to your stuff due to your excellent optparse-ification.

If this is still too big, I'm not really sure how to go about this.

And I'm gonna get into even more trouble with cg-log. My code is 
essentially a rewrite, in order to reduce the incredible amount of 
forking going on in the current code.

But let's take it one step at a time...

/dan

---

[PATCH] Rewrite cg-diff colorization, add diffstat and reverse

This collects all of the colorization logic into the setup_colors
method, in preparation for codesharing with cg-log. In the process, we 
go from awk to sed.

This also cleans up option handling, in order to provide better error 
checking and error messages. And skip the rather unncessary xargs usage.

diffstat and "reverse diff" output options are added. diffstat output 
requires a small fix of "pager" in cg-Xlib, in order not to lose leading 
whitespace when color isn't used.

Signed-off-by: Dan Holmsand <holmsand@gmail.com>

---

[-- Attachment #2: diff.patch.txt --]
[-- Type: text/plain, Size: 6380 bytes --]

 cg-Xlib |    2 -
 cg-diff |  166 ++++++++++++++++++++++++++++++---------------------------------
 2 files changed, 79 insertions(+), 89 deletions(-)

diff --git a/cg-Xlib b/cg-Xlib
--- a/cg-Xlib
+++ b/cg-Xlib
@@ -24,7 +24,7 @@ usage() {
 pager () {
 	local line
 	# Invoke pager only if there's any actual output
-	if read -r line; then
+	if IFS='' read -r line; then
 		( echo "$line"; cat; ) | LESS="R$LESS" ${PAGER:-less} $PAGER_FLAGS
 	fi
 }
diff --git a/cg-diff b/cg-diff
--- a/cg-diff
+++ b/cg-diff
@@ -13,6 +13,9 @@
 # -c::
 #	Colorize the diff output
 #
+# -d, --diffstat::
+#	Show `diffstat' output before diff.
+#
 # -p::
 #	Instead of one ID denotes a parent commit to the specified ID
 #	(which must not be a tree, obviously).
@@ -26,7 +29,10 @@
 #
 # -m::
 #	Base the diff at the merge base of the -r arguments (defaulting
-#	to master and origin).
+#	to HEAD and origin).
+#
+# -R::
+#	Output diff in reverse.
 #
 # ENVIRONMENT VARIABLES
 # ---------------------
@@ -37,132 +43,116 @@
 #	Flags to pass to the pager. By default `R` is added to the `LESS`
 #	environment variable to allow displaying of colorized output.
 
-USAGE="cg-diff [-c] [-m] [-p] [-r FROM_ID[:TO_ID]] [FILE]..."
+USAGE="cg-diff [-c] [-d] [-m] [-p] [-R] [-r FROM_ID[:TO_ID]] [FILE]..."
 
 . ${COGITO_LIB}cg-Xlib
 
 
-id1=" "
-id2=" "
-parent=
-opt_color=
-mergebase=
+unset id1 id2 parent opt_color mergebase diffprog sedprog diffstat difftmp
+dtargs=()
 
 # TODO: Make cg-log use this too.
 setup_colors()
 {
-	local C="diffhdr=1;36:diffhdradd=1;32:diffadd=32:diffhdrmod=1;35:diffmod=35:diffhdrrem=1;31:diffrem=31:diffhunk=36:diffctx=34:diffcctx=33:default=0"
+	local C="diffhdr=1;36:diffhdradd=1;32:diffadd=32:diffhdrmod=1;35"
+	C="$C:diffmod=35:diffhdrrem=1;31:diffrem=31:diffhunk=36:diffctx=34"
+	C="$C:files=34:default=0"
 	[ -n "$COGITO_COLORS" ] && C="$C:$COGITO_COLORS"
 
 	C=${C//=/=\'$'\e'[}
 	C=col${C//:/m\'; col}m\'
-	#coldefault=$(tput op)
 	eval $C
+
+	color_rules="
+s,^+++.*,$coldiffhdradd&$coldefault,
+s,^new file mode.*,$coldiffhdradd&$coldefault,
+s,^---.*,$coldiffhdrrem&$coldefault,
+s,^deleted file mode.*,$coldiffhdrrem&$coldefault,
+s,^[+].*,$coldiffadd&$coldefault,
+s,^[-].*,$coldiffrem&$coldefault,
+s,^\\(@@.*@@\\)\\(.*\\),$coldiffhunk\\1$coldiffctx\\2$coldefault,
+s,^\\(diff\\) .*,$coldiffhdr&$coldefault,"
+}
+
+show_diffstat() {
+	[ -s "$difftmp" ] || return
+	git-apply --stat "$difftmp"
+	echo
+	cat "$difftmp"
 }
 
 while optparse; do
 	if optparse -c; then
 		opt_color=1
-		setup_colors
 	elif optparse -p; then
+		[ "$mergebase" ] && optconflict
 		parent=1
 	elif optparse -r=; then
-		if echo "$OPTARG" | grep -q ':'; then
-			id2=$(echo "$OPTARG" | cut -d : -f 2)
-			[ "$id2" ] || log_end="HEAD"
-			id1=$(echo "$OPTARG" | cut -d : -f 1)
-		elif [ "$id1" = " " ]; then
-			id1="$OPTARG"
+		if [ ! "${id1+set}" ]; then
+			id1=$OPTARG
+			if [[ "$id1" == *:* ]]; then
+				id2=${id1#*:}
+				id1=${id1%:*}
+			fi
 		else
-			id2="$OPTARG"
+			[ "${id2+set}" ] && die "too many revisions"
+			id2=$OPTARG
 		fi
 	elif optparse -m; then
+		[ "$parent" ] && optconflict
 		mergebase=1
+	elif optparse -d || optparse --diffstat; then
+		diffstat=1
+	elif optparse -R; then
+		dtargs[${#dtargs[@]}]="-R"
 	else
 		optfail
 	fi
 done
 
-colorize() {
-	if [ "$opt_color" ]; then
-		gawk '
-		{ if (/^(Index:|diff --git) /)
-		    print "'$coldiffhdr'" $0 "'$coldefault'"
-		  else if (/^======*$/)
-		    print "'$coldiffhdr'" $0 "'$coldefault'"
-		  else if (/^\+\+\+/)
-		    print "'$coldiffhdradd'" $0 "'$coldefault'"
-		  else if (/^\*\*\*/)
-		    print "'$coldiffhdrmod'" $0 "'$coldefault'"
-		  else if (/^---/)
-		    print "'$coldiffhdrrem'" $0 "'$coldefault'"
-		  else if (/^(\+|new( file)? mode )/)
-		    print "'$coldiffadd'" $0 "'$coldefault'"
-		  else if (/^(-|(deleted file|old) mode )/)
-		    print "'$coldiffrem'" $0 "'$coldefault'"
-		  else if (/^!/)
-		    print "'$coldiffmod'" $0 "'$coldefault'"
-		  else if (/^@@ \-[0-9]+(,[0-9]+)? \+[0-9]+(,[0-9]+)? @@/)
-		    print gensub(/^(@@[^@]*@@)([ \t]*)(.*)/,
-		         "'$coldiffhunk'" "\\1" "'$coldefault'" \
-			 "\\2" \
-			 "'$coldiffctx'" "\\3" "'$coldefault'", "")
-		  else if (/^\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/)
-		    print "'$coldiffcctx'" $0 "'$coldefault'"
-		  else
-		    print
-		}'
-	else
-		cat
-	fi
-}
-
 if [ "$parent" ]; then
+	[ "${id2+set}" ] && die "too many revisions"
 	id2="$id1"
-	id="$id2"; [ "$id" = " " ] && id=""
-	id1=$(parent-id "$id" | head -n 1) || exit 1
+	id1=$(parent-id "$id2" | head -n 1) || exit 1
+elif [ "$mergebase" ]; then
+	id1="$(commit-id "${id1:-HEAD}")" || exit 1
+	id2="$(commit-id "${id2:-origin}")" || exit 1
+	id1="$(git-merge-base "$id1" "$id2")" || exit 1
+else
+	id1=$(tree-id "$id1") || exit 1
 fi
 
-if [ "$mergebase" ]; then
-	[ "$id1" != " " ] || id1="master"
-	[ "$id2" != " " ] || id2="origin"
-	id1=$(git-merge-base $(commit-id "$id1") $(commit-id "$id2"))
-fi
-
-
-filter=$(mktemp -t gitdiff.XXXXXX)
-for file in "${ARGS[@]}"; do
-	echo "$file" >>$filter
-done
-
-if [ "$id2" = " " ]; then
-	if [ "$id1" != " " ]; then
-		tree=$(tree-id "$id1") || exit 1
-	else
-		tree=$(tree-id) || exit 1
-	fi
+diffprog=git-diff-tree
 
+if [ ! "${id2+set}" ]; then
 	# Ensure to only diff modified files
 	git-update-cache --refresh >/dev/null
-
-	# FIXME: Update ret based on what did we match. And take "$@"
-	# to account after all.
-	ret=
-	cat $filter | xargs git-diff-cache -r -p $tree | colorize | pager
-
-	rm $filter
-
-	[ "$ret" ] && die "no files matched"
-	exit $ret
+	diffprog=git-diff-cache
+else
+	id2=$(tree-id "$id2") || exit 1
 fi
 
-
-id1=$(tree-id "$id1") || exit 1
-id2=$(tree-id "$id2") || exit 1
-
 [ "$id1" = "$id2" ] && die "trying to diff $id1 against itself"
+diffopts=(-r -p "${dtargs[@]}" $id1 $id2 "${ARGS[@]}")
 
-cat $filter | xargs git-diff-tree -r -p $id1 $id2 | colorize | pager
+if [ "$diffstat" ]; then
+	difftmp=$(mktemp -t cgdiff.XXXXXX) || exit 1
+	trap "rm '$difftmp'" SIGTERM EXIT
+	$diffprog "${diffopts[@]}" > $difftmp
 
-rm $filter
-exit 0
+	diffprog=show_diffstat
+	diffopts=
+fi
+
+if [ "$opt_color" ]; then
+	setup_colors
+	sedprog="$color_rules"
+
+	[ "$diffstat" ] && sedprog="$sedprog
+s,^\\( [^ ].*\\)\\( |  *[0-9][0-9]* \\),$colfiles\\1$coldefault\\2,"
+
+	$diffprog "${diffopts[@]}" | sed -e "$sedprog" | pager
+	exit $PIPESTATUS
+else
+	$diffprog "${diffopts[@]}" | pager
+fi

^ permalink raw reply

* [PATCH] cg-help: dynamically list commands
From: Jonas Fonseca @ 2005-06-11 12:37 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

Use code from the make-cogito-asciidoc script to make the command
listing dynamic and hopefully always up-to-date by grepping the
USAGE strings.

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---

 cg-commit |    2 +-
 cg-help   |   47 +++++++++++++++++++++--------------------------
 2 files changed, 22 insertions(+), 27 deletions(-)

diff --git a/cg-commit b/cg-commit
--- a/cg-commit
+++ b/cg-commit
@@ -72,7 +72,7 @@
 # EDITOR::
 #	The editor used for entering revision log information.
 
-USAGE="cg-commit [-mMESSAGE]... [-C] [-e | -E] [FILE]..."
+USAGE="cg-commit [-mMESSAGE]... [-C] [-e | -E] [FILE]... < MESSAGE"
 
 . ${COGITO_LIB}cg-Xlib
 
diff --git a/cg-help b/cg-help
--- a/cg-help
+++ b/cg-help
@@ -25,6 +25,25 @@ if [ "$1" ]; then
 	exit 1
 fi
 
+bin_path="$(dirname $0)"
+
+REGULAR_COMMANDS="$(ls $bin_path/cg-* | grep -v cg-admin- | grep -v cg-X)"
+ADVANCED_COMMANDS="$(ls $bin_path/cg-admin-*)"
+
+print_command_listing()
+{
+	for command in "$@"; do
+		cmdname=$(basename $command)
+
+		usage=$(sed -n '/^USAGE=/,0s/.*\(cg-.*\)"/\1/p' < $command)
+		# Some minimal sanity check that we didn't pick up some
+		# random binary named cg-*
+		[ "$usage" ] || continue
+		usage=$(echo "$usage" | sed 's/cg-[^ ]*//')
+		printf "	%-17s %s\n" "$cmdname" "$usage"
+	done
+}
+
 
 cat <<__END__
 The Cogito version control system  $(cg-version)
@@ -32,34 +51,10 @@ The Cogito version control system  $(cg-
 Usage: cg-COMMAND [ARG]...
 
 Available commands:
-	cg-add		FILE...
-	cg-branch-add	BNAME SOURCE_LOC
-	cg-branch-ls
-	cg-cancel
-	cg-clone	[-s] SOURCE_LOC [DESTDIR]
-	cg-commit	[-m"Commit message"]... [-e | -E] [FILE]... < log message
-	cg-diff		[-c] [-m] [-p] [-r FROM_ID[:TO_ID]] [FILE]...
-	cg-export	DEST [TREE_ID]
-	cg-help		[COMMAND]
-	cg-init
-	cg-log		[-c] [-f] [-m] [-r FROM_ID[:TO_ID]] [FILE]...
-	cg-merge	[-c] [-b BASE_ID] FROM_ID
-	cg-mkpatch	[-m] [-s] [-r FROM_ID[:TO_ID]]
-	cg-patch			< patch on stdin
-	cg-pull		[BNAME]
-	cg-restore	[FILE]...
-	cg-rm		FILE...
-	cg-seek		[COMMIT_ID]
-	cg-status
-	cg-tag		TNAME [COMMIT_ID]
-	cg-tag-ls
-	cg-update	[BNAME]
-	cg-version
+$(print_command_listing $REGULAR_COMMANDS)
 
 Advanced (low-level or dangerous) commands:
-	cg-admin-ls	[-t TREE_ID] [PATH]
-	cg-admin-lsobj	[OBJTYPE]
-	cg-admin-uncommit [-t] [COMMIT_ID]
+$(print_command_listing $ADVANCED_COMMANDS)
 
 These expressions can be used interchangably as "ID"s:
 	empty string, "this" or "HEAD" (current HEAD)
-- 
Jonas Fonseca

^ permalink raw reply

* reducing line crossings in gitk
From: Paul Mackerras @ 2005-06-11 11:47 UTC (permalink / raw)
  To: git

At the moment, the commit graph that gitk draws always displays the
parents of a merge in left-to-right order as they are listed in the
commit (provided that none of the parents already has a line, i.e., is
the parent of an previously drawn commit).  That means that for the
typical merge, the branch coming out to the right is the stuff that
was pulled in by the merge.

That can lead to a later line crossing if an ancestor of the stuff
being pulled in already has a line that is to the left of the merge.
For an example of what I mean, look at the kernel repository with gitk
at around commit 5ea6f2c33f0c8b126136dbf1776ffbc444772cd7 (Automatic
merge of /spare/repo/netdev-2.6 branch natsemi).

I could add a heuristic to look for this case and reverse the order of
the parents, which would reduce the line crossings and make the graph
look neater.  Would this be worth the slight loss of information (in
that the stuff pulled in would no longer always be to the right)?

Paul.

^ permalink raw reply

* Re: do people use the 'git' command?
From: Junio C Hamano @ 2005-06-11  9:58 UTC (permalink / raw)
  To: Russ Allbery; +Cc: git
In-Reply-To: <87r7f9xsux.fsf@windlord.stanford.edu>

>>>>> "RA" == Russ Allbery <rra@stanford.edu> writes:

RA> ... it turns out in discussion on the Debian mailing lists
RA> that people actually do use GIT.

I thought the Debian way to resolve this kind of naming conflict
was to rename _both_ commands involved.  Sorry if this was a
misconception, but I think I read that somewhere in the
developer's guide.


^ permalink raw reply

* [PATCH 5/3] read-tree: loosen too strict index requirements
From: Junio C Hamano @ 2005-06-11  9:53 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

This patch teaches read-tree 3-way merge that, when only "the
other tree" changed a path, and if the index file already has
the same change, we are not in a situation that would clobber
the index and the work tree, and lets the merge succeed; this is
case #14ALT in t1000 test.  It does not change the result of the
merge, but prevents it from failing when it does not have to.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** This is another leftover bits from the earlier 3-piece series.
*** This is not necessary for the --emu23 two-way improvements,
*** but rather help a case that would not be so uncommon in the
*** 3-way merge case.

 read-tree.c                 |    6 ++++++
 t/t1000-read-tree-m-3way.sh |    9 +++++++++
 2 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/read-tree.c b/read-tree.c
--- a/read-tree.c
+++ b/read-tree.c
@@ -280,6 +280,12 @@ static int threeway_merge(struct cache_e
 		}
 		/* otherwise we will apply the original rule */
 	}
+	/* #14ALT */
+	if (a && b && c && same(a, b) && !same(a, c)) {
+		if (old && same(old, c))
+			return merged_entry_allow_dirty(c, old, dst);
+		/* otherwise the regular rule applies */
+	}
 	/*
 	 * If we have an entry in the index cache ("old"), then we want
 	 * to make sure that it matches any entries in stage 2 ("first
diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh
--- a/t/t1000-read-tree-m-3way.sh
+++ b/t/t1000-read-tree-m-3way.sh
@@ -464,6 +464,15 @@ test_expect_success \
      git-read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
+test_expect_success \
+    '14 - may match B in O && A && B && O==A && O!=B case' \
+    "rm -f .git/index NM &&
+     cp .orig-B/NM NM &&
+     git-update-cache --add NM &&
+     echo extra >>NM &&
+     git-read-tree -m $tree_O $tree_A $tree_B &&
+     check_result"
+
 test_expect_failure \
     '14 (fail) - must match and be up-to-date in O && A && B && O==A && O!=B case' \
     "rm -f .git/index NM &&
------------


^ permalink raw reply

* [PATCH 4/3] Finish making --emu23 equivalent to pure 2-way merge.
From: Junio C Hamano @ 2005-06-11  9:50 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

This adds #3ALT rule (and #2ALT rule for symmetry) to the
read-tree 3-way merge logic that collapses paths that are added
only in one branch and not in the other internally.

This makes --emu23 to succeed in the last remaining case where
the pure 2-way merge succeeded and earlier one failed.  Running
diff between t1001 and t1005 test scripts shows that the only
difference between the two is that --emu23 can leave the states
into separate stages so that the user can use usual 3-way merge
resolution techniques to carry forward the local changes when
pure 2-way merge would have refused to run.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

*** This is leftover bits from the earlier 3-piece series.

 read-tree.c                       |  137 ++++++++++++++++++++++++++++++++++++-
 t/t1000-read-tree-m-3way.sh       |   32 +++++----
 t/t1005-read-tree-m-2way-emu23.sh |   20 ++++-
 3 files changed, 168 insertions(+), 21 deletions(-)

diff --git a/read-tree.c b/read-tree.c
--- a/read-tree.c
+++ b/read-tree.c
@@ -143,7 +143,72 @@ static int deleted_entry(struct cache_en
 	return 1;
 }
 
-static int threeway_merge(struct cache_entry *stages[4], struct cache_entry **dst)
+static int causes_df_conflict(struct cache_entry *ce, int stage,
+			      struct cache_entry **dst_,
+			      struct cache_entry **next_,
+			      int tail)
+{
+	/* This is called during the merge operation and walking
+	 * the active_cache[] array is messy, because it is in the
+	 * middle of overlapping copy operation.  The invariants
+	 * are:
+	 * (1) active_cache points at the first (zeroth) entry.
+	 * (2) up to dst pointer are resolved entries.
+	 * (3) from the next pointer (head-inclusive) to the tail
+	 *     of the active_cache array have the remaining paths
+	 *     to be processed.  There can be a gap between dst
+	 *     and next.  Note that next is called "src" in the
+	 *     merge_cache() function, and tail is the original
+	 *     end of active_cache array when merge_cache() started.
+	 * (4) the path corresponding to *ce is not found in (2)
+	 *     or (3).  It is in the gap.
+	 *
+	 *  active_cache -----......+++++++++++++.
+	 *                    ^dst  ^next        ^tail
+	 */
+	int i, next, dst;
+	const char *path = ce->name;
+	int namelen = ce_namelen(ce);
+
+	next = next_ - active_cache;
+	dst = dst_ - active_cache;
+
+	for (i = 0; i < tail; i++) {
+		int entlen, len;
+		const char *one, *two;
+		if (dst <= i && i < next)
+			continue;
+		ce = active_cache[i];
+		if (ce_stage(ce) != stage)
+			continue;
+		/* If ce->name is a prefix of path, then path is a file
+		 * that hangs underneath ce->name, which is bad.
+		 * If path is a prefix of ce->name, then it is the
+		 * other way around which also is bad.
+		 */
+		entlen = ce_namelen(ce);
+		if (namelen == entlen)
+			continue;
+		if (namelen < entlen) {
+			len = namelen;
+			one = path;
+			two = ce->name;
+		} else {
+			len = entlen;
+			one = ce->name;
+			two = path;
+		}
+		if (memcmp(one, two, len))
+			continue;
+		if (two[len] == '/')
+			return 1;
+	}
+	return 0;
+}
+
+static int threeway_merge(struct cache_entry *stages[4],
+			  struct cache_entry **dst,
+			  struct cache_entry **next, int tail)
 {
 	struct cache_entry *old = stages[0];
 	struct cache_entry *a = stages[1], *b = stages[2], *c = stages[3];
@@ -156,6 +221,65 @@ static int threeway_merge(struct cache_e
 			return -1;
 		return merged_entry_allow_dirty(b, old, dst);
 	}
+	/* #2ALT and #3ALT */
+	if (!a && (!!b != !!c)) {
+		/*
+		 * The reason we need to worry about directory/file
+		 * conflicts only in #2ALT and #3ALT case is this:
+		 *
+		 * (1) For all other cases that read-tree internally
+		 *     resolves a path, we always have such a path in
+		 *     *both* stage2 and stage3 when we begin.
+		 *     Traditionally, the behaviour has been even
+		 *     stricter and we did not resolve a path without
+		 *     initially being in all of stage1, 2, and 3.
+		 *
+		 * (2) When read-tree finishes, all resolved paths (i.e.
+		 *     the paths that are in stage0) must have come from
+		 *     either stage2 or stage3.  It is not possible to
+		 *     have a stage0 path as a result of a merge if
+		 *     neither stage2 nor stage3 had that path.
+		 *
+		 * (3) It is guaranteed that just after reading the
+		 *     stages, each stage cannot have directory/file
+		 *     conflicts on its own, because they are populated
+		 *     by reading hierarchy of a tree.  Combined with
+		 *     (1) and (2) above, this means that no matter what
+		 *     combination of paths we take from stage2 and
+		 *     stage3 as a result of a merge, they cannot cause
+		 *     a directory/file conflict situation (otherwise
+		 *     the "guilty" path would have already had such a
+		 *     conflict in the original stage, either stage2
+		 *     or stage3).  Although its stage2 is synthesized
+		 *     by overlaying the current index on top of "our
+		 *     head" tree, --emu23 case also has this guarantee,
+		 *     by calling add_cache_entry() to create such stage2
+		 *     entries.
+		 *
+		 * (4) Only #2ALT and #3ALT lack the guarantee (1).
+		 *     They resolve paths that exist only in stage2
+		 *     or stage3.  The stage2 tree may have a file DF
+		 *     while stage3 tree may have a file DF/DF.  If
+		 *     #2ALT and #3ALT rules happen to apply to both
+		 *     of them, we would end up having DF (coming from
+		 *     stage2) and DF/DF (from stage3) in the result.
+		 *     When we attempt to resolve a path that exists
+		 *     only in stage2, we need to make sure there is
+		 *     no path that would conflict with it in stage3
+		 *     and vice versa.
+		 */
+		if (c) { /* #2ALT */
+			if (!causes_df_conflict(c, 2, dst, next, tail) &&
+			    (!old || same(c, old)))
+				return merged_entry_allow_dirty(c, old, dst);
+		}
+		else { /* #3ALT */
+			if (!causes_df_conflict(b, 3, dst, next, tail) &&
+			    (!old || same(b, old)))
+				return merged_entry_allow_dirty(b, old, dst);
+		}
+		/* otherwise we will apply the original rule */
+	}
 	/*
 	 * If we have an entry in the index cache ("old"), then we want
 	 * to make sure that it matches any entries in stage 2 ("first
@@ -186,7 +310,8 @@ static int threeway_merge(struct cache_e
  * "carry forward" rule, please see <Documentation/git-read-tree.txt>.
  *
  */
-static int twoway_merge(struct cache_entry **src, struct cache_entry **dst)
+static int twoway_merge(struct cache_entry **src, struct cache_entry **dst,
+			struct cache_entry **next, int tail)
 {
 	struct cache_entry *current = src[0];
 	struct cache_entry *oldtree = src[1], *newtree = src[2];
@@ -283,7 +408,8 @@ static void setup_emu23(void)
  * The rule is:
  * - take the stat information from stage0, take the data from stage1
  */
-static int oneway_merge(struct cache_entry **src, struct cache_entry **dst)
+static int oneway_merge(struct cache_entry **src, struct cache_entry **dst,
+			struct cache_entry **next, int tail)
 {
 	struct cache_entry *old = src[0];
 	struct cache_entry *a = src[1];
@@ -324,11 +450,12 @@ static void check_updates(struct cache_e
 	}
 }
 
-typedef int (*merge_fn_t)(struct cache_entry **, struct cache_entry **);
+typedef int (*merge_fn_t)(struct cache_entry **, struct cache_entry **, struct cache_entry **, int);
 
 static void merge_cache(struct cache_entry **src, int nr, merge_fn_t fn)
 {
 	struct cache_entry **dst = src;
+	int tail = nr;
 
 	while (nr) {
 		int entries;
@@ -346,7 +473,7 @@ static void merge_cache(struct cache_ent
 				break;
 		}
 
-		entries = fn(stages, dst);
+		entries = fn(stages, dst, src, tail);
 		if (entries < 0)
 			reject_merge(name);
 		dst += entries;
diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh
--- a/t/t1000-read-tree-m-3way.sh
+++ b/t/t1000-read-tree-m-3way.sh
@@ -75,13 +75,13 @@ In addition:
 . ../lib-read-tree-m-3way.sh
 
 ################################################################
-# Trivial "majority when 3 stages exist" merge plus #5ALT trivial
-# merge.
+# Trivial "majority when 3 stages exist" merge plus #2ALT, #3ALT
+# and #5ALT trivial merges.
 
 cat >expected <<\EOF
 100644 X 2	AA
 100644 X 3	AA
-100644 X 2	AN
+100644 X 0	AN
 100644 X 1	DD
 100644 X 3	DF
 100644 X 2	DF/DF
@@ -96,7 +96,7 @@ cat >expected <<\EOF
 100644 X 2	MM
 100644 X 3	MM
 100644 X 0	MN
-100644 X 3	NA
+100644 X 0	NA
 100644 X 1	ND
 100644 X 2	ND
 100644 X 0	NM
@@ -107,7 +107,7 @@ cat >expected <<\EOF
 100644 X 3	TT
 100644 X 2	Z/AA
 100644 X 3	Z/AA
-100644 X 2	Z/AN
+100644 X 0	Z/AN
 100644 X 1	Z/DD
 100644 X 1	Z/DM
 100644 X 3	Z/DM
@@ -119,7 +119,7 @@ cat >expected <<\EOF
 100644 X 2	Z/MM
 100644 X 3	Z/MM
 100644 X 0	Z/MN
-100644 X 3	Z/NA
+100644 X 0	Z/NA
 100644 X 1	Z/ND
 100644 X 2	Z/ND
 100644 X 0	Z/NM
@@ -233,23 +233,31 @@ test_expect_failure \
      git-update-cache --add XX &&
      git-read-tree -m $tree_O $tree_A $tree_B"
 
-test_expect_failure \
-    '2 - must not have an entry not in A.' \
+test_expect_success \
+    '2 - must match B in !O && !A && B case.' \
+    "rm -f .git/index NA &&
+     cp .orig-B/NA NA &&
+     git-update-cache --add NA &&
+     git-read-tree -m $tree_O $tree_A $tree_B"
+
+test_expect_success \
+    '2 - matching B alone is OK in !O && !A && B case.' \
     "rm -f .git/index NA &&
      cp .orig-B/NA NA &&
      git-update-cache --add NA &&
+     echo extra >>NA &&
      git-read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
-    '3 - must match and be up-to-date in !O && A && !B case.' \
+    '3 - must match A in !O && A && !B case.' \
     "rm -f .git/index AN &&
      cp .orig-A/AN AN &&
      git-update-cache --add AN &&
      git-read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
-test_expect_failure \
-    '3 (fail) - must match and be up-to-date in !O && A && !B case.' \
+test_expect_success \
+    '3 - matching A alone is OK in !O && A && !B case.' \
     "rm -f .git/index AN &&
      cp .orig-A/AN AN &&
      git-update-cache --add AN &&
@@ -257,7 +265,7 @@ test_expect_failure \
      git-read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
-    '3 (fail) - must match and be up-to-date in !O && A && !B case.' \
+    '3 (fail) - must match A in !O && A && !B case.' \
     "rm -f .git/index AN &&
      cp .orig-A/AN AN &&
      echo extra >>AN &&
diff --git a/t/t1005-read-tree-m-2way-emu23.sh b/t/t1005-read-tree-m-2way-emu23.sh
--- a/t/t1005-read-tree-m-2way-emu23.sh
+++ b/t/t1005-read-tree-m-2way-emu23.sh
@@ -80,6 +80,17 @@ test_expect_success \
      git-ls-tree $treeM &&
      git-diff-tree $treeH $treeM'
 
+# "read-tree -m H I+H M" but I is empty so this is "read-tree -m H H M".
+#
+# bozbar [O && A && B && O==A && O!=B (#14) ==> B] take M by read-tree
+# frotz  [!O && !A && B (#2) ==> B]                take M by read-tree
+# nitfol [O && A && B && O==A && O==B (#15) ==> B] take M by read-tree
+# rezrov [O && A && !B && O==A (#10) ==> no merge] removed by script
+#
+# Earlier one did not have #2ALT so taking M was done by the script,
+# which also updated the work tree and making frotz clean.  With #2ALT,
+# this is resolved by read-tree itself and the path is left dirty
+# because we are not testing "read-tree -u --emu23".
 test_expect_success \
     '1, 2, 3 - no carry forward' \
     'rm -f .git/index &&
@@ -87,7 +98,7 @@ test_expect_success \
      git-ls-files --stage >1-3.out &&
      diff -u M.out 1-3.out &&
      check_cache_at bozbar dirty &&
-     check_cache_at frotz clean && # different from pure 2-way
+     check_cache_at frotz dirty && # same as pure 2-way again.
      check_cache_at nitfol dirty'
 
 echo '+100644 X 0	yomin' >expected
@@ -103,8 +114,8 @@ test_expect_success \
      check_cache_at yomin clean'
 
 # "read-tree -m H I+H M" where !H && !M; so (I+H) not being up-to-date
-# should not matter, but without #3ALT this does not work.
-: test_expect_success \
+# should not matter.  Thanks to #3ALT, this is now possible.
+test_expect_success \
     '5 - carry forward local addition.' \
     'rm -f .git/index &&
      echo yomin >yomin &&
@@ -218,6 +229,7 @@ test_expect_success \
 # This is different from straight 2-way merge in that it leaves
 # three stages of bozbar in the index file without failing, so
 # the user can run git-diff-stages to examine the situation.
+# With #2ALT, frotz is resolved internally.
 test_expect_success \
     '16 - conflicting local change.' \
     'rm -f .git/index &&
@@ -228,7 +240,7 @@ test_expect_success \
 100644 X 1	bozbar
 100644 X 2	bozbar
 100644 X 3	bozbar
-100644 X 3	frotz
+100644 X 0	frotz
 100644 X 0	nitfol
 100644 X 1	rezrov
 100644 X 2	rezrov
------------


^ permalink raw reply

* porcelain question: state of the art for undo-redo?
From: Jon Seymour @ 2005-06-11  8:51 UTC (permalink / raw)
  To: Git Mailing List

What porcelain layer solutions currently exist for effective undo-edit-redo?

For example, if you are working on a series of patches in a series,
then realise there is a mistake in a patch early in the series, how
does one mod that patch, then reapply all the following patches to
produce a slightly modified patch series with as little stuffing
around as possible?

jon.
-- 
homepage: http://www.zeta.org.au/~jon/
blog: http://orwelliantremors.blogspot.com/

^ permalink raw reply

* Re: do people use the 'git' command?
From: Jon Seymour @ 2005-06-11  8:48 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Sebastian Kuzminsky, Git Mailing List
In-Reply-To: <7vu0k5xrfz.fsf@assigned-by-dhcp.cox.net>

> I grant you that what the current "git" wrapper offers is not
> Porcelain enough, and to perform anything meaningful you either
> need to use Porcelain or bare Plumbing commands yourself.  But
> when that day comes, "git update-cache" is not something you
> would want to have anyway.  You would rather want to have things
> like "git add" and "git remove", which are written in terms of
> git-update-cache.
> 
> See what I am saying?

Ok, that's fair enough. It is a sound to expose bits of plumbing to
the porcelain in a very slow and deliberate way as the porcelain is
polished, rather than automatically surfacing plumbing as it gets
created by over-enthusiastic plumbers.

My own learning experience has been exactly the other way around to
the intended use of the git script - I have been learning to use the
core git commands, writing my own wrappers where that is convenient
and adopting those of others only when I completely understand what
they are doing - I have been learning it inside out, I guess.

For example, I only recently discovered what git-commit-script does  [
and I like it - btw - nice behaviour ]!

jon.
-- 
homepage: http://www.zeta.org.au/~jon/
blog: http://orwelliantremors.blogspot.com/

^ 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