Git development
 help / color / mirror / Atom feed
* Re: Why is --pretty=format: so slow?
From: Junio C Hamano @ 2007-11-04 11:48 UTC (permalink / raw)
  To: René Scharfe; +Cc: Paul Mackerras, git, Johannes Schindelin
In-Reply-To: <472D9F6E.8070609@lsrfire.ath.cx>

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

> Incidentally, I'm finishing a patch series to add git-describe style
> placeholders.  It needs such an optimization even more badly (and has
> it).  Speeding up other slow placeholder expansions falls out quite
> naturally.  Please wait just a few minutes..

Thanks, and take your time, as I am just going to bed, dreaming
for a perfect series from one of the few people on this list
whose patches I do not have to read to reject crap, but I do
read to get impressed and admire ;-)

^ permalink raw reply

* [PATCH 2/5] pretty describe: factor out describe_commit() from describe()
From: René Scharfe @ 2007-11-04 11:48 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

Factor out a new function, describe_commit(), out of describe().  All
arguments are passed as parameters, not globals.  Also move the clamping
of max_candidates from cmd_describe() into the new function, which makes
it ready to be used in a library.

Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
---
 builtin-describe.c |   64 +++++++++++++++++++++++++++++++++------------------
 1 files changed, 41 insertions(+), 23 deletions(-)

diff --git a/builtin-describe.c b/builtin-describe.c
index 82c25c3..e68a3d0 100644
--- a/builtin-describe.c
+++ b/builtin-describe.c
@@ -116,28 +116,26 @@ static unsigned long finish_depth_computation(
 	return seen_commits;
 }
 
-static void describe(const char *arg, int last_one)
+char *describe_commit(struct commit *cmit, int max_candidates, int debug, int *depthp)
 {
-	unsigned char sha1[20];
-	struct commit *cmit, *gave_up_on = NULL;
+	struct commit *gave_up_on = NULL;
 	struct commit_list *list;
 	struct possible_tag all_matches[MAX_TAGS];
 	unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
 	unsigned long seen_commits = 0;
 
-	if (get_sha1(arg, sha1))
-		die("Not a valid object name %s", arg);
-	cmit = lookup_commit_reference(sha1);
-	if (!cmit)
-		die("%s is not a valid '%s' object", arg, commit_type);
-
 	if (cmit->name) {
-		printf("%s\n", all ? cmit->name : cmit->name + 5);
-		return;
+		*depthp = 0;
+		return cmit->name;
 	}
 
 	if (debug)
-		fprintf(stderr, "searching to describe %s\n", arg);
+		fprintf(stderr, "searching...\n");
+
+	if (max_candidates < 1)
+		max_candidates = 1;
+	else if (max_candidates > MAX_TAGS)
+		max_candidates = MAX_TAGS;
 
 	list = NULL;
 	cmit->name_flags = SEEN;
@@ -149,7 +147,7 @@ static void describe(const char *arg, int last_one)
 		if (c->name) {
 			if (match_cnt < max_candidates) {
 				struct possible_tag *t = &all_matches[match_cnt++];
-				t->name = all ? c->name : c->name + 5;
+				t->name = c->name;
 				t->prio = c->name_prio;
 				t->depth = seen_commits - 1;
 				t->flag_within = 1u << match_cnt;
@@ -184,8 +182,11 @@ static void describe(const char *arg, int last_one)
 		}
 	}
 
-	if (!match_cnt)
-		die("cannot describe '%s'", sha1_to_hex(cmit->object.sha1));
+	if (!match_cnt) {
+		free_commit_list(list);
+		*depthp = -1;
+		return NULL;
+	}
 
 	qsort(all_matches, match_cnt, sizeof(all_matches[0]), compare_pt);
 
@@ -211,11 +212,32 @@ static void describe(const char *arg, int last_one)
 				sha1_to_hex(gave_up_on->object.sha1));
 		}
 	}
-	if (abbrev == 0)
-		printf("%s\n", all_matches[0].name);
+
+	*depthp = all_matches[0].depth;
+	return all_matches[0].name;
+}
+
+static void describe(const char *arg, int last_one)
+{
+	unsigned char sha1[20];
+	struct commit *cmit;
+	char *name;
+	int depth = 0;
+
+	if (get_sha1(arg, sha1))
+		die("Not a valid object name %s", arg);
+	cmit = lookup_commit_reference(sha1);
+	if (!cmit)
+		die("%s is not a valid '%s' object", arg, commit_type);
+
+	name = describe_commit(cmit, max_candidates, debug, &depth);
+	if (!name)
+		die("cannot describe '%s'", sha1_to_hex(cmit->object.sha1));
+
+	if (abbrev == 0 || depth == 0)
+		printf("%s\n", all ? name : name + 5);
 	else
-		printf("%s-%d-g%s\n", all_matches[0].name,
-		       all_matches[0].depth,
+		printf("%s-%d-g%s\n", all ? name : name + 5, depth,
 		       find_unique_abbrev(cmit->object.sha1, abbrev));
 
 	if (!last_one)
@@ -237,10 +259,6 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 	};
 
 	argc = parse_options(argc, argv, options, describe_usage, 0);
-	if (max_candidates < 1)
-		max_candidates = 1;
-	else if (max_candidates > MAX_TAGS)
-		max_candidates = MAX_TAGS;
 
 	save_commit_buffer = 0;
 
-- 
1.5.3.5.529.ge3d6d

^ permalink raw reply related

* [PATCH 1/5] pretty describe: add name info to struct commit
From: René Scharfe @ 2007-11-04 11:48 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

This patch prepares the lib'ification of git-describe.  As a library
function, it can't use commit marks or the util field, as they might
already be used by the caller.

Convert all usage of commit marks and the util field to use the three
new members of struct commit (name, name_flags, name_prio) instead.
A new function, clear_commit_name_flags(), should be used to clear
them after the work is done.

add_to_known_names() is merged into get_name(); struct commit_name is
merged into struct possible_tag; loading the name is done once before
describe() is called instead of doing it inside, but protected by a
static variable.

The name unconditionally has the prefix "refs/" cut from it, but not
more, so a prefix of "tags/" remains for names found under
"refs/tags/".  This is dealt with when displaying.  Together with the
change to pass a minimum name "priority" via the cb_data pointer,
this cleans get_name() from any use of global variables, making it
ready to serve as a library function (or rather its wrapper, the new
function load_commit_names()).

Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
---
 builtin-describe.c |  103 ++++++++++++++++++++++------------------------------
 commit.c           |   21 +++++++++++
 commit.h           |    4 ++
 3 files changed, 69 insertions(+), 59 deletions(-)

diff --git a/builtin-describe.c b/builtin-describe.c
index 6eeb9b5..82c25c3 100644
--- a/builtin-describe.c
+++ b/builtin-describe.c
@@ -20,42 +20,21 @@ static int tags;	/* But allow any tags if --tags is specified */
 static int abbrev = DEFAULT_ABBREV;
 static int max_candidates = 10;
 
-struct commit_name {
-	int prio; /* annotated tag = 2, tag = 1, head = 0 */
-	char path[FLEX_ARRAY]; /* more */
-};
 static const char *prio_names[] = {
 	"head", "lightweight", "annotated",
 };
 
-static void add_to_known_names(const char *path,
-			       struct commit *commit,
-			       int prio)
-{
-	struct commit_name *e = commit->util;
-	if (!e || e->prio < prio) {
-		size_t len = strlen(path)+1;
-		free(e);
-		e = xmalloc(sizeof(struct commit_name) + len);
-		e->prio = prio;
-		memcpy(e->path, path, len);
-		commit->util = e;
-	}
-}
-
 static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	struct object *object;
+	int min_prio = *((int *)cb_data);
 	int prio;
 
 	if (!commit)
 		return 0;
 	object = parse_object(sha1);
-	/* If --all, then any refs are used.
-	 * If --tags, then any tags are used.
-	 * Otherwise only annotated tags are used.
-	 */
+
 	if (!prefixcmp(path, "refs/tags/")) {
 		if (object->type == OBJ_TAG)
 			prio = 2;
@@ -64,19 +43,28 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
 	}
 	else
 		prio = 0;
+	if (prio < min_prio)
+		return 0;
 
-	if (!all) {
-		if (!prio)
-			return 0;
-		if (!tags && prio < 2)
+	if (commit->name) {
+		if (commit->name_prio >= prio)
 			return 0;
+		free(commit->name);
 	}
-	add_to_known_names(all ? path + 5 : path + 10, commit, prio);
+	commit->name = xstrdup(path + 5);
+	commit->name_prio = prio;
+
 	return 0;
 }
 
+void load_commit_names(int min_prio)
+{
+	for_each_ref(get_name, &min_prio);
+}
+
 struct possible_tag {
-	struct commit_name *name;
+	char *name;
+	int prio; /* annotated tag = 2, tag = 1, head = 0 */
 	int depth;
 	int found_order;
 	unsigned flag_within;
@@ -86,8 +74,8 @@ static int compare_pt(const void *a_, const void *b_)
 {
 	struct possible_tag *a = (struct possible_tag *)a_;
 	struct possible_tag *b = (struct possible_tag *)b_;
-	if (a->name->prio != b->name->prio)
-		return b->name->prio - a->name->prio;
+	if (a->prio != b->prio)
+		return b->prio - a->prio;
 	if (a->depth != b->depth)
 		return a->depth - b->depth;
 	if (a->found_order != b->found_order)
@@ -104,11 +92,11 @@ static unsigned long finish_depth_computation(
 		struct commit *c = pop_commit(list);
 		struct commit_list *parents = c->parents;
 		seen_commits++;
-		if (c->object.flags & best->flag_within) {
+		if (c->name_flags & best->flag_within) {
 			struct commit_list *a = *list;
 			while (a) {
 				struct commit *i = a->item;
-				if (!(i->object.flags & best->flag_within))
+				if (!(i->name_flags & best->flag_within))
 					break;
 				a = a->next;
 			}
@@ -119,9 +107,9 @@ static unsigned long finish_depth_computation(
 		while (parents) {
 			struct commit *p = parents->item;
 			parse_commit(p);
-			if (!(p->object.flags & SEEN))
+			if (!(p->name_flags & SEEN))
 				insert_by_date(p, list);
-			p->object.flags |= c->object.flags;
+			p->name_flags |= c->name_flags;
 			parents = parents->next;
 		}
 	}
@@ -133,8 +121,6 @@ static void describe(const char *arg, int last_one)
 	unsigned char sha1[20];
 	struct commit *cmit, *gave_up_on = NULL;
 	struct commit_list *list;
-	static int initialized = 0;
-	struct commit_name *n;
 	struct possible_tag all_matches[MAX_TAGS];
 	unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
 	unsigned long seen_commits = 0;
@@ -145,14 +131,8 @@ static void describe(const char *arg, int last_one)
 	if (!cmit)
 		die("%s is not a valid '%s' object", arg, commit_type);
 
-	if (!initialized) {
-		initialized = 1;
-		for_each_ref(get_name, NULL);
-	}
-
-	n = cmit->util;
-	if (n) {
-		printf("%s\n", n->path);
+	if (cmit->name) {
+		printf("%s\n", all ? cmit->name : cmit->name + 5);
 		return;
 	}
 
@@ -160,22 +140,22 @@ static void describe(const char *arg, int last_one)
 		fprintf(stderr, "searching to describe %s\n", arg);
 
 	list = NULL;
-	cmit->object.flags = SEEN;
+	cmit->name_flags = SEEN;
 	commit_list_insert(cmit, &list);
 	while (list) {
 		struct commit *c = pop_commit(&list);
 		struct commit_list *parents = c->parents;
 		seen_commits++;
-		n = c->util;
-		if (n) {
+		if (c->name) {
 			if (match_cnt < max_candidates) {
 				struct possible_tag *t = &all_matches[match_cnt++];
-				t->name = n;
+				t->name = all ? c->name : c->name + 5;
+				t->prio = c->name_prio;
 				t->depth = seen_commits - 1;
 				t->flag_within = 1u << match_cnt;
 				t->found_order = match_cnt;
-				c->object.flags |= t->flag_within;
-				if (n->prio == 2)
+				c->name_flags |= t->flag_within;
+				if (c->name_prio == 2)
 					annotated_cnt++;
 			}
 			else {
@@ -185,7 +165,7 @@ static void describe(const char *arg, int last_one)
 		}
 		for (cur_match = 0; cur_match < match_cnt; cur_match++) {
 			struct possible_tag *t = &all_matches[cur_match];
-			if (!(c->object.flags & t->flag_within))
+			if (!(c->name_flags & t->flag_within))
 				t->depth++;
 		}
 		if (annotated_cnt && !list) {
@@ -197,9 +177,9 @@ static void describe(const char *arg, int last_one)
 		while (parents) {
 			struct commit *p = parents->item;
 			parse_commit(p);
-			if (!(p->object.flags & SEEN))
+			if (!(p->name_flags & SEEN))
 				insert_by_date(p, &list);
-			p->object.flags |= c->object.flags;
+			p->name_flags |= c->name_flags;
 			parents = parents->next;
 		}
 	}
@@ -220,8 +200,7 @@ static void describe(const char *arg, int last_one)
 		for (cur_match = 0; cur_match < match_cnt; cur_match++) {
 			struct possible_tag *t = &all_matches[cur_match];
 			fprintf(stderr, " %-11s %8d %s\n",
-				prio_names[t->name->prio],
-				t->depth, t->name->path);
+				prio_names[t->prio], t->depth, t->name);
 		}
 		fprintf(stderr, "traversed %lu commits\n", seen_commits);
 		if (gave_up_on) {
@@ -233,14 +212,14 @@ static void describe(const char *arg, int last_one)
 		}
 	}
 	if (abbrev == 0)
-		printf("%s\n", all_matches[0].name->path );
+		printf("%s\n", all_matches[0].name);
 	else
-		printf("%s-%d-g%s\n", all_matches[0].name->path,
+		printf("%s-%d-g%s\n", all_matches[0].name,
 		       all_matches[0].depth,
 		       find_unique_abbrev(cmit->object.sha1, abbrev));
 
 	if (!last_one)
-		clear_commit_marks(cmit, -1);
+		clear_commit_name_flags(cmit);
 }
 
 int cmd_describe(int argc, const char **argv, const char *prefix)
@@ -275,6 +254,12 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 		return cmd_name_rev(3 + argc, args, prefix);
 	}
 
+	/* If --all, then any refs are used.
+	 * If --tags, then any tags are used.
+	 * Otherwise only annotated tags are used.
+	 */
+	load_commit_names(all ? 0 : (tags ? 1 : 2));
+
 	if (argc == 0) {
 		describe("HEAD", 1);
 	} else {
diff --git a/commit.c b/commit.c
index ac24266..24b7268 100644
--- a/commit.c
+++ b/commit.c
@@ -460,6 +460,27 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
 	}
 }
 
+void clear_commit_name_flags(struct commit *commit)
+{
+	while (commit) {
+		struct commit_list *parents;
+
+		if (!commit->name_flags)
+			return;
+
+		commit->name_flags = 0;
+
+		parents = commit->parents;
+		if (!parents)
+			return;
+
+		while ((parents = parents->next))
+			clear_commit_name_flags(parents->item);
+
+		commit = commit->parents->item;
+	}
+}
+
 /*
  * Generic support for pretty-printing the header
  */
diff --git a/commit.h b/commit.h
index b661503..80e94b9 100644
--- a/commit.h
+++ b/commit.h
@@ -18,6 +18,9 @@ struct commit {
 	struct commit_list *parents;
 	struct tree *tree;
 	char *buffer;
+	char *name;
+	unsigned int name_flags;
+	char name_prio;
 };
 
 extern int save_commit_buffer;
@@ -78,6 +81,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
 struct commit *pop_commit(struct commit_list **stack);
 
 void clear_commit_marks(struct commit *commit, unsigned int mark);
+void clear_commit_name_flags(struct commit *commit);
 
 /*
  * Performs an in-place topological sort of list supplied.
-- 
1.5.3.5.529.ge3d6d

^ permalink raw reply related

* Re: [PATCH] status&commit: Teach them to show commits of modified submodules.
From: Junio C Hamano @ 2007-11-04 11:41 UTC (permalink / raw)
  To: Yin Ping; +Cc: git
In-Reply-To: <46dff0320711040145k1edb1fcaq1daa5469c1158e81@mail.gmail.com>

"Yin Ping" <pkufranky@gmail.com> writes:

> In both case, i think the user should be notified about the inconsistence.
> My patch given in the first letter handles this by two warning messages as
> follows (where $name is module name)
>
> +                       cd $name >&/dev/null || { echo "  Warning: fail to
> chdir to $name" && exit; }

My point was that it is wrong to make this "you do not have that
submodule checked out" a warning.

Think about somebody who does _not_ care about that particular
submodule.  He is working on one branch, and tries to merge
another branch that has some interesting changes outside the
submodule, but that branch also has updates to the submodule.

As he is _not_ interested in the submodule, he does not have it
checked out.  He has not changed the commit bound in his index
with 160000 mode bits for that submodule since the common
ancestor, either (that's what "he does not care about the
submodule" means).

The merge will take the submodule commit object name from the
other branches change, just like the ordinary three-way merge
rule would do (one side changed, the other did not do anything,
so take the change).  Suppose some files in the project proper,
outside the submodule, had conflicts.  He has an unmerged index,
that has the submodule already correctly merged.  But other
parts of his index are unmerged.  git-status would guide him
what are conflicting, and git-commit would show him what he
would be committing.

In that situation, all he needs to know, with respect to the
submodule, is that the submodule has been updated since his HEAD
(and that is given by the runstatus output).  He does not _care_
about what the individual commits in the submodule were.  It is
not an error that the information from the submodule cannot be
shown to him.  He _chose_ to ignore the details of that
submodule by not checking it out to begin with.

Something like this, to be totally quiet, would be more
appropriate.

	for name in $modules
        do
                (
                	... do the range, indexone, headone stuff
                        cd "$name" 2>/dev/null || exit 0
                	echo "* $name $headone...$indexone:"
			... whatever log you show
		) | sed ...
	done

By the way, I do not know about the quoting issues with $modules
variable in the above illustration, as I am not (yet) discussing
about the implementation level of details.

^ permalink raw reply

* Re: What's cooking in git.git (topics)
From: Pierre Habouzit @ 2007-11-04 11:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vr6j6ve90.fsf@gitster.siamese.dyndns.org>

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

On Sun, Nov 04, 2007 at 04:14:19AM +0000, Junio C Hamano wrote:
> * ph/parseopt-sh (Fri Nov 2 23:39:52 2007 +0100) 5 commits
>  - Migrate git-am.sh to use git-rev-parse --parseopt
>  - Migrate git-clone to use git-rev-parse --parseopt
>  - Migrate git-clean.sh to use git-rev-parse --parseopt.
>  - Update git-sh-setup(1) to allow transparent use of git-rev-parse -
>    -parseopt
>  - Add a parseopt mode to git-rev-parse to bring parse-options to
>    shell scripts.
> 
> Together with today's batch which is missing from the above
> list, hopefully merge to 'next' over the weekend.

  Please note that the last resend has the issues you raised fixed and
that it modifies git-clone and git-sh-setup commits from above.

  Someone proposed many fixes in the documentation too, I wont do it
because (again) I'm not a native speaker so I let that ungrateful job to
someone actually able to do it.

Cheers,
-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* [PATCH] RelNotes-1.5.3.5: fix typos
From: David D Kilzer @ 2007-11-04 11:33 UTC (permalink / raw)
  To: git; +Cc: David D Kilzer

Signed-off-by: David D Kilzer <ddkilzer@kilzer.net>
---

On Sat, 3 Nov 2007 at 06:56:36 -0700, David D. Kilzer wrote:
> Documentation/RelNotes-1.5.3.5.txt |    4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)

Oops.  Found another typo.

 Documentation/RelNotes-1.5.3.5.txt |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/RelNotes-1.5.3.5.txt b/Documentation/RelNotes-1.5.3.5.txt
index 4e46d2c..7ff1d5d 100644
--- a/Documentation/RelNotes-1.5.3.5.txt
+++ b/Documentation/RelNotes-1.5.3.5.txt
@@ -63,8 +63,8 @@ Fixes since v1.5.3.4
 
  * Git segfaulted when reading an invalid .gitattributes file.  Fixed.
 
- * post-receive-email example hook fixed was fixed for
-   non-fast-forward updates.
+ * post-receive-email example hook was fixed for non-fast-forward
+   updates.
 
  * Documentation updates for supported (but previously undocumented)
    options of "git-archive" and "git-reflog".
@@ -90,5 +90,5 @@ Fixes since v1.5.3.4
  * "git-send-pack $remote frotz" segfaulted when there is nothing
    named 'frotz' on the local end.
 
- * "git-rebase -interactive" did not handle its "--strategy" option
+ * "git-rebase --interactive" did not handle its "--strategy" option
    properly.
-- 
1.5.3.5

^ permalink raw reply related

* Re: [PATCH 01/10] Add a parseopt mode to git-rev-parse to bring parse-options to shell scripts.
From: Ralf Wildenhues @ 2007-11-04 11:31 UTC (permalink / raw)
  To: Pierre Habouzit, gitster, git
In-Reply-To: <20071104112931.GB2119@ins.uni-bonn.de>

* Ralf Wildenhues wrote on Sun, Nov 04, 2007 at 12:29:31PM CET:
> A couple of language nits:
> 
> * Pierre Habouzit wrote on Sun, Nov 04, 2007 at 11:30:53AM CET:
[...]
> > +It takes on the standard input the specification of the options to parse and
> > +understand, and echoes on the standard ouput a line suitable for `sh(1)` `eval`

Missed another  s/ouput/output/  here.

> > +to replace the arguments with normalized ones.  In case of error, it ouputs
> 
> s/ouputs/outputs/

^ permalink raw reply

* Re: [PATCH 01/10] Add a parseopt mode to git-rev-parse to bring parse-options to shell scripts.
From: Ralf Wildenhues @ 2007-11-04 11:29 UTC (permalink / raw)
  To: Pierre Habouzit; +Cc: gitster, git
In-Reply-To: <1194172262-1563-2-git-send-email-madcoder@debian.org>

Hello Pierre,

A couple of language nits:

* Pierre Habouzit wrote on Sun, Nov 04, 2007 at 11:30:53AM CET:
> +PARSEOPT
> +--------
> +
> +In `--parseopt` mode, `git-rev-parse` helps massaging options to bring to shell
> +scripts the same facilities C builtins have. It works as an option normalizer
> +(e.g. splits single switches aggregate values), a bit like `getopt(1)` does.
> +
> +It takes on the standard input the specification of the options to parse and
> +understand, and echoes on the standard ouput a line suitable for `sh(1)` `eval`
> +to replace the arguments with normalized ones.  In case of error, it ouputs

s/ouputs/outputs/

> +usage on the standard error stream, and exits with code 129.
> +
> +Input Format
> +~~~~~~~~~~~~
> +
> +`git-ref-parse --parseopt` input format is fully text based. It has two parts,

s/^/The /
s/git-ref-parse/git-rev-parse/

> +separated by a line that contains only `--`. The lines before (should be more
> +than one) are used for the usage. The lines after describe the options.

I would write
  s/before/& the `--`/
  s/after/& the `--`/

or maybe write "separator" instead of `--`.

[...]
> +`<opt_spec>`::
> +	its format is the short option character, then the long option name
> +        separated by a comma. Both parts are not required, though at least one
> +        is necessary. `h,help`, `dry-run` and `f` are all three correct
> +        `<opt_spec>`.
> +
> +`<arg_spec>`::
> +	an `<arg_spec>` tells the option parser if the option has an argument
> +        (`=`), an optionnal one (`?` though its use is discouraged) or none

s/optionnal/optional/

> +        (no `<arg_spec>` in that case).
> +
> +The rest of the line after as many spaces up to the ending line feed is used
> +as the help associated to the option.

I'd write (in case that is technically correct):
  After following white space, the rest of the line after is used as the
  help associated to the option.

> +Blank lines are ignored, and lines that don't match this specification are used
> +as option group headers (start the line with a space to purposely create such
> +lines).

I'd write:
  ... to create such lines on purpose.

> +Example
> +~~~~~~~
> +
> +------------
> +OPTS_SPEC="\
> +some-command [options] <args>...
> +
> +some-command does foo and bar !

Please no white space before "!".

> +--
> +h,help    show the help
> +
> +foo       some nifty option --foo
> +bar=      some cool option --bar with an argument
> +
> +  An option group Header
> +C?        option C with an optionnal argument"

s/optionnal/optional/

Cheers,
Ralf

^ permalink raw reply

* Re: [RFC PATCH] Make gitk use --early-output
From: Paul Mackerras @ 2007-11-04 11:04 UTC (permalink / raw)
  To: Marco Costalba; +Cc: Linus Torvalds, git
In-Reply-To: <e5bfff550711040237s250bcec0iddf1ebdc616e0bbf@mail.gmail.com>

Marco Costalba writes:

> On 11/4/07, Paul Mackerras <paulus@samba.org> wrote:
> >
> >      set vnextroot($view) 0
> > -    set order "--topo-order"
> > +    set order "--early-output=50"
> 
> But --early-output does not imply --topo-order, I guess...

Look here in Linus' patch:

+			if (!prefixcmp(arg, "--early-output")) {
+				int count = 100;
+				switch (arg[14]) {
+				case '=':
+					count = atoi(arg+15);
+					/* Fallthrough */
+				case 0:
+					revs->topo_order = 1;
+					revs->early_output = count;
+					continue;
+				}
+			}

So yes, --early-output does imply --topo-order.

> P.S: Why did you choose not let git log (i.e. Linus) to handle the
> default number of commits?
> 
> "--early-output=50" instead of just "--early-output"

Because I was thinking of adding a control in the edit/preferences
window for it later on.

Paul.

^ permalink raw reply

* Re: [PATCH] user-manual: add advanced topic "bisecting merges"
From: Ralf Wildenhues @ 2007-11-04 11:23 UTC (permalink / raw)
  To: Steffen Prohaska; +Cc: git
In-Reply-To: <11941677732664-git-send-email-prohaska@zib.de>

Hello Steffen,

A couple of language nits:

* Steffen Prohaska wrote on Sun, Nov 04, 2007 at 10:16:13AM CET:
> +Suppose that on the upper development line, the meaning of one
> +of the functions existed at Z was changed at commit X.  The

s/functions/& that/

> +commits from Z leading to A change both the function's
> +implementation and all calling sites that existed at Z, as well
> +as new calling sites they add, to be consistent.  There is no
> +bug at A.
[...]
> +You merge to create C.  There is no textual conflict with this
> +three way merge, and the result merges cleanly.  You bisect
> +this, because you found D is bad and you know Z was good.  Your
> +bisect will find that C (merge) is broken.  Understandably so,
> +as at C, the new calling site of the function added by the lower
> +branch is not converted to the new semantics, while all the
> +other calling sites that already existed at Z would have been
> +converted by the merge.  The new calling site has semantic
> +adjustment needed, but you do not know that yet.  You need to
> +find out that is the cause of the breakage by looking at the

s/that/that that/

> +merge commit C and the history leading to it.
[...]
> +If you linearlize the history by rebasing the lower branch on
> +top of upper, instead of merging, the bug becomes much easier to

s/upper/the &/

> +find and understand.  Your history would instead be:
[...]

Cheers,
Ralf

^ permalink raw reply

* gitk graph routing problem
From: Alex Riesen @ 2007-11-04 10:46 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: git, Junio C Hamano

To reproduce, try running in git repo:

    gitk 02f630448e5d48e..06ea6ba9cf46ef5

Than go some pages (around 5) forward. You should notice system load
going up rapidly. Now try paging back - and graph starts stretching
to the right, to the point nothing fits on the screen anymore.

Gitk as of commit 7388bcbc5431552718dde5c3259d861d2fa75a12 in git
repository. Git - v1.5.3.5-551-g02f6304 (terse fetch output and some
*really* unrelated local modifications. Anyway, the gitk is the same).
Bisect points to or around 6e8c87070306a757c4d7fd2c55cca3a90fe140c7
"gitk: Establish and use global left-to-right ordering for commits".
It loops heavily at this commit and looks broken in all subsequent
commits.

Last know good was 3244729aac7515c. The master of gitk repo is ok too.

^ permalink raw reply

* Re: [RFC PATCH] Make gitk use --early-output
From: Marco Costalba @ 2007-11-04 10:37 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Linus Torvalds, git
In-Reply-To: <18221.2285.259487.655684@cargo.ozlabs.ibm.com>

On 11/4/07, Paul Mackerras <paulus@samba.org> wrote:
>
>      set vnextroot($view) 0
> -    set order "--topo-order"
> +    set order "--early-output=50"

But --early-output does not imply --topo-order, I guess...

I would think you need _both_ in git log:

git log --early-output --topo-order <...remaining stuff...>

Am I missing something?

Marco


P.S: Why did you choose not let git log (i.e. Linus) to handle the
default number of commits?

"--early-output=50" instead of just "--early-output"

I would say, he added this feature mainly for his personal use, so why
don't let him to tweak git-log defaults to his wishes ;-)

^ permalink raw reply

* Re: Why is --pretty=format: so slow?
From: René Scharfe @ 2007-11-04 10:31 UTC (permalink / raw)
  To: git; +Cc: Paul Mackerras, git, Johannes Schindelin
In-Reply-To: <7vmytuvdvq.fsf@gitster.siamese.dyndns.org>

Junio C Hamano schrieb:
> Paul Mackerras <paulus@samba.org> writes:
> 
>> Strace seems to indicate that git log is doing at least one sequence
>> of open, fstat64, fcntl64, getdents64 and close for each line of
>> output in the --pretty=format: cases, but not in the other cases.
> 
> I bet that is coming from doing find_unique_abbrev() to fill
> fields %h, %t and %p, even when the output format does not ask
> for any of them.
> 
> Dscho, can we stop calling find_unique_abbrev() unconditionally
> before being asked?

Incidentally, I'm finishing a patch series to add git-describe style
placeholders.  It needs such an optimization even more badly (and has
it).  Speeding up other slow placeholder expansions falls out quite
naturally.  Please wait just a few minutes..

René

^ permalink raw reply

* [PATCH 08/10] Migrate git-checkout.sh to use git-rev-parse --parseopt --keep-dashdash
From: Pierre Habouzit @ 2007-11-04 10:31 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-8-git-send-email-madcoder@debian.org>

Also fix some space versus tabs issues.
---
 git-checkout.sh |   99 +++++++++++++++++++++++++++----------------------------
 1 files changed, 49 insertions(+), 50 deletions(-)

diff --git a/git-checkout.sh b/git-checkout.sh
index 8993920..c00cedd 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -1,6 +1,16 @@
 #!/bin/sh
 
-USAGE='[-q] [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
+OPTIONS_KEEPDASHDASH=t
+OPTIONS_SPEC="\
+git-branch [options] [<branch>] [<paths>...]
+--
+b=          create a new branch started at <branch>
+l           create the new branchs reflog
+track       tells if the new branch should track the remote branch
+f           proceed even if the index or working tree is not HEAD
+m           performa  three-way merge on local modifications if needed
+q,quiet     be quiet
+"
 SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 require_work_tree
@@ -20,13 +30,12 @@ quiet=
 v=-v
 LF='
 '
-while [ "$#" != "0" ]; do
-    arg="$1"
-    shift
-    case "$arg" in
-	"-b")
-		newbranch="$1"
+
+while test $# != 0; do
+	case "$1" in
+	-b)
 		shift
+		newbranch="$1"
 		[ -z "$newbranch" ] &&
 			die "git checkout: -b needs a branch name"
 		git show-ref --verify --quiet -- "refs/heads/$newbranch" &&
@@ -34,64 +43,54 @@ while [ "$#" != "0" ]; do
 		git check-ref-format "heads/$newbranch" ||
 			die "git checkout: we do not like '$newbranch' as a branch name."
 		;;
-	"-l")
+	-l)
 		newbranch_log=-l
 		;;
-	"--track"|"--no-track")
-		track="$arg"
+	--track|--no-track)
+		track="$1"
 		;;
-	"-f")
+	-f)
 		force=1
 		;;
 	-m)
 		merge=1
 		;;
-	"-q")
+	-q|--quiet)
 		quiet=1
 		v=
 		;;
 	--)
+		shift
 		break
 		;;
-	-*)
-		usage
-		;;
 	*)
-		if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null)
-		then
-			if [ -z "$rev" ]; then
-				echo "unknown flag $arg"
-				exit 1
-			fi
-			new_name="$arg"
-			if git show-ref --verify --quiet -- "refs/heads/$arg"
-			then
-				rev=$(git rev-parse --verify "refs/heads/$arg^0")
-				branch="$arg"
-			fi
-			new="$rev"
-		elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null)
-		then
-			# checking out selected paths from a tree-ish.
-			new="$rev"
-			new_name="$arg^{tree}"
-			branch=
-		else
-			new=
-			new_name=
-			branch=
-			set x "$arg" "$@"
-			shift
-		fi
-		case "$1" in
-		--)
-			shift ;;
-		esac
-		break
+		usage
 		;;
-    esac
+	esac
+	shift
 done
 
+arg="$1"
+if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null)
+then
+	[ -z "$rev" ] && die "unknown flag $arg"
+	new_name="$arg"
+	if git show-ref --verify --quiet -- "refs/heads/$arg"
+	then
+		rev=$(git rev-parse --verify "refs/heads/$arg^0")
+		branch="$arg"
+	fi
+	new="$rev"
+	shift
+elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null)
+then
+	# checking out selected paths from a tree-ish.
+	new="$rev"
+	new_name="$arg^{tree}"
+	shift
+fi
+[ "$1" = "--" ] && shift
+
 case "$newbranch,$track" in
 ,--*)
 	die "git checkout: --track and --no-track require -b"
@@ -138,8 +137,8 @@ Did you intend to checkout '$@' which can not be resolved as commit?"
 	git ls-files -- "$@" |
 	git checkout-index -f -u --stdin
 
-        # Run a post-checkout hook -- the HEAD does not change so the
-        # current HEAD is passed in for both args
+	# Run a post-checkout hook -- the HEAD does not change so the
+	# current HEAD is passed in for both args
 	if test -x "$GIT_DIR"/hooks/post-checkout; then
 	    "$GIT_DIR"/hooks/post-checkout $old $old 0
 	fi
@@ -294,5 +293,5 @@ fi
 
 # Run a post-checkout hook
 if test -x "$GIT_DIR"/hooks/post-checkout; then
-        "$GIT_DIR"/hooks/post-checkout $old $new 1
+	"$GIT_DIR"/hooks/post-checkout $old $new 1
 fi
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* [PATCH 09/10] Migrate git-quiltimport.sh to use git-rev-parse --parseopt
From: Pierre Habouzit @ 2007-11-04 10:31 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-9-git-send-email-madcoder@debian.org>

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 git-quiltimport.sh |   38 +++++++++++++++-----------------------
 1 files changed, 15 insertions(+), 23 deletions(-)

diff --git a/git-quiltimport.sh b/git-quiltimport.sh
index 880c81d..b6c24c8 100755
--- a/git-quiltimport.sh
+++ b/git-quiltimport.sh
@@ -1,5 +1,11 @@
 #!/bin/sh
-USAGE='--dry-run --author <author> --patches </path/to/quilt/patch/directory>'
+OPTIONS_SPEC="\
+git-quiltimport [options]
+--
+n,dry-run     dry run
+author=       author name and email address for patches without any
+patches=      path to the quilt series and patches
+"
 SUBDIRECTORY_ON=Yes
 . git-sh-setup
 
@@ -8,39 +14,25 @@ quilt_author=""
 while test $# != 0
 do
 	case "$1" in
-	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
-		quilt_author=$(expr "z$1" : 'z-[^=]*\(.*\)')
-		shift
-		;;
-
-	--au|--aut|--auth|--autho|--author)
-		case "$#" in 1) usage ;; esac
+	--author)
 		shift
 		quilt_author="$1"
-		shift
 		;;
-
-	--dry-run)
-		shift
+	-n|--dry-run)
 		dry_run=1
 		;;
-
-	--pa=*|--pat=*|--patc=*|--patch=*|--patche=*|--patches=*)
-		QUILT_PATCHES=$(expr "z$1" : 'z-[^=]*\(.*\)')
-		shift
-		;;
-
-	--pa|--pat|--patc|--patch|--patche|--patches)
-		case "$#" in 1) usage ;; esac
-		shift
+	--patches)
 		QUILT_PATCHES="$1"
 		shift
 		;;
-
+	--)
+		shift
+		break;;
 	*)
-		break
+		usage
 		;;
 	esac
+	shift
 done
 
 # Quilt Author
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* [PATCH 10/10] Migrate git-repack.sh to use git-rev-parse --parseopt
From: Pierre Habouzit @ 2007-11-04 10:31 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-10-git-send-email-madcoder@debian.org>

---
 git-repack.sh |   23 ++++++++++++++++++-----
 1 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/git-repack.sh b/git-repack.sh
index 7220635..4d4840e 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -3,7 +3,21 @@
 # Copyright (c) 2005 Linus Torvalds
 #
 
-USAGE='[-a|-A] [-d] [-f] [-l] [-n] [-q] [--max-pack-size=N] [--window=N] [--window-memory=N] [--depth=N]'
+OPTIONS_SPEC="\
+git-repack [options]
+--
+a               pack everything in a single pack
+A               same as -a, and keep unreachable objects too
+d               remove redundant packs, and run git-prune-packed
+f               pass --no-reuse-delta to git-pack-objects
+q,quiet         be quiet
+l               pass --local to git-pack-objects
+ Packing constraints
+window=         size of the window used for delta compression
+window-memory=  same as the above, but limit memory size instead of entries count
+depth=          limits the maximum delta depth
+max-pack-size=  maximum size of each packfile
+"
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
@@ -20,10 +34,9 @@ do
 	-q)	quiet=-q ;;
 	-f)	no_reuse=--no-reuse-object ;;
 	-l)	local=--local ;;
-	--max-pack-size=*) extra="$extra $1" ;;
-	--window=*) extra="$extra $1" ;;
-	--window-memory=*) extra="$extra $1" ;;
-	--depth=*) extra="$extra $1" ;;
+	--max-pack-size|--window|--window-memory|--depth)
+		extra="$extra $1=$2"; shift ;;
+	--) shift; break;;
 	*)	usage ;;
 	esac
 	shift
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* [PATCH 07/10] Migrate git-instaweb.sh to use git-rev-parse --parseopt
From: Pierre Habouzit @ 2007-11-04 10:30 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-7-git-send-email-madcoder@debian.org>

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 git-instaweb.sh |   73 ++++++++++++++++++++++---------------------------------
 1 files changed, 29 insertions(+), 44 deletions(-)

diff --git a/git-instaweb.sh b/git-instaweb.sh
index 95c3e5a..d912bf5 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -2,9 +2,20 @@
 #
 # Copyright (c) 2006 Eric Wong
 #
-USAGE='[--start] [--stop] [--restart]
-  [--local] [--httpd=<httpd>] [--port=<port>] [--browser=<browser>]
-  [--module-path=<path> (for Apache2 only)]'
+
+OPTIONS_SPEC="\
+git-instaweb [options] (--start | --stop | --restart)
+--
+l,local        only bind on 127.0.0.1
+p,port=        the port to bind to
+d,httpd=       the command to launch
+b,browser=     the browser to launch
+m,module-path= the module path (only needed for apache2)
+ Action
+stop           stop the web server
+start          start the web server
+restart        restart the web server
+"
 
 . git-sh-setup
 
@@ -78,52 +89,26 @@ do
 		start_httpd
 		exit 0
 		;;
-	--local|-l)
+	-l|--local)
 		local=true
 		;;
-	-d|--httpd|--httpd=*)
-		case "$#,$1" in
-		*,*=*)
-			httpd=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-		1,*)
-			usage ;;
-		*)
-			httpd="$2"
-			shift ;;
-		esac
+	-d|--httpd)
+		shift
+		httpd="$1"
+		;;
+	-b|--browser)
+		shift
+		browser="$1"
 		;;
-	-b|--browser|--browser=*)
-		case "$#,$1" in
-		*,*=*)
-			browser=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-		1,*)
-			usage ;;
-		*)
-			browser="$2"
-			shift ;;
-		esac
+	-p|--port)
+		shift
+		port="$1"
 		;;
-	-p|--port|--port=*)
-		case "$#,$1" in
-		*,*=*)
-			port=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-		1,*)
-			usage ;;
-		*)
-			port="$2"
-			shift ;;
-		esac
+	-m|--module-path)
+		shift
+		module_path="$1"
 		;;
-	-m|--module-path=*|--module-path)
-		case "$#,$1" in
-		*,*=*)
-			module_path=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-		1,*)
-			usage ;;
-		*)
-			module_path="$2"
-			shift ;;
-		esac
+	--)
 		;;
 	*)
 		usage
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* [PATCH 05/10] Migrate git-am.sh to use git-rev-parse --parseopt
From: Pierre Habouzit @ 2007-11-04 10:30 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-5-git-send-email-madcoder@debian.org>

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 git-am.sh |   93 +++++++++++++++++++++++++++++++-----------------------------
 1 files changed, 48 insertions(+), 45 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 2514d07..2d2b1c6 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -2,11 +2,25 @@
 #
 # Copyright (c) 2005, 2006 Junio C Hamano
 
-USAGE='[--signoff] [--dotest=<dir>] [--keep] [--utf8 | --no-utf8]
-  [--3way] [--interactive] [--binary]
-  [--whitespace=<option>] [-C<n>] [-p<n>]
-  <mbox>|<Maildir>...
-  or, when resuming [--skip | --resolved]'
+OPTIONS_SPEC="\
+git-am [options] <mbox>|<Maildir>...
+git-am [options] --resolved
+git-am [options] --skip
+--
+d,dotest=       use <dir> and not .dotest
+i,interactive=  run interactively
+b,binary        pass --allo-binary-replacement to git-apply
+3,3way          allow fall back on 3way merging if needed
+s,signoff       add a Signed-off-by line to the commit message
+u,utf8          recode into utf8 (default)
+k,keep          pass -k flagg to git-mailinfo
+whitespace=     pass it through git-apply
+C=              pass it through git-apply
+p=              pass it through git-apply
+resolvemsg=     override error message when patch failure occurs
+r,resolved      to be used after a patch failure
+skip            skip the current patch"
+
 . git-sh-setup
 set_reflog_action am
 require_work_tree
@@ -110,49 +124,38 @@ git_apply_opt=
 while test $# != 0
 do
 	case "$1" in
-	-d=*|--d=*|--do=*|--dot=*|--dote=*|--dotes=*|--dotest=*)
-	dotest=`expr "z$1" : 'z-[^=]*=\(.*\)'`; shift ;;
-	-d|--d|--do|--dot|--dote|--dotes|--dotest)
-	case "$#" in 1) usage ;; esac; shift
-	dotest="$1"; shift;;
-
-	-i|--i|--in|--int|--inte|--inter|--intera|--interac|--interact|\
-	--interacti|--interactiv|--interactive)
-	interactive=t; shift ;;
-
-	-b|--b|--bi|--bin|--bina|--binar|--binary)
-	binary=t; shift ;;
-
-	-3|--3|--3w|--3wa|--3way)
-	threeway=t; shift ;;
-	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
-	sign=t; shift ;;
-	-u|--u|--ut|--utf|--utf8)
-	utf8=t; shift ;; # this is now default
-	--no-u|--no-ut|--no-utf|--no-utf8)
-	utf8=; shift ;;
-	-k|--k|--ke|--kee|--keep)
-	keep=t; shift ;;
-
-	-r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved)
-	resolved=t; shift ;;
-
-	--sk|--ski|--skip)
-	skip=t; shift ;;
-
-	--whitespace=*|-C*|-p*)
-	git_apply_opt="$git_apply_opt $1"; shift ;;
-
-	--resolvemsg=*)
-	resolvemsg=${1#--resolvemsg=}; shift ;;
-
+	-i|--interactive)
+		interactive=t ;;
+	-b|--binary)
+		binary=t ;;
+	-3|--3way)
+		threeway=t ;;
+	-s--signoff)
+		sign=t ;;
+	-u|--utf8)
+		utf8=t ;; # this is now default
+	--no-utf8)
+		utf8= ;;
+	-k|--keep)
+		keep=t ;;
+	-r|--resolved)
+		resolved=t ;;
+	--skip)
+		skip=t ;;
+	-d|--dotest)
+		shift; dotest=$1;;
+	--resolvemsg)
+		shift; resolvemsg=$1 ;;
+	--whitespace)
+		git_apply_opt="$git_apply_opt $1=$2"; shift ;;
+	-C|-p)
+		git_apply_opt="$git_apply_opt $1$2"; shift ;;
 	--)
-	shift; break ;;
-	-*)
-	usage ;;
+		shift; break ;;
 	*)
-	break ;;
+		usage ;;
 	esac
+	shift
 done
 
 # If the dotest directory exists, but we have finished applying all the
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* [PATCH 06/10] Migrate git-merge.sh to use git-rev-parse --parseopt
From: Pierre Habouzit @ 2007-11-04 10:30 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-6-git-send-email-madcoder@debian.org>

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 git-merge.sh |  125 ++++++++++++++++++++++++---------------------------------
 1 files changed, 53 insertions(+), 72 deletions(-)

diff --git a/git-merge.sh b/git-merge.sh
index b9f0519..d19bfc2 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -3,7 +3,18 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-USAGE='[-n] [--summary] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s <strategy>] [-m=<merge-message>] <commit>+'
+OPTIONS_SPEC="\
+git-merge [options] <remote>...
+git-merge [options] <msg> HEAD <remote>
+--
+summary              show a diffstat at the end of the merge
+n,no-summary         don't show a diffstat at the end of the merge
+squash               create a single commit instead of doing a merge
+commit               perform a commit if the merge sucesses (default)
+ff                   allow fast forward (default)
+s,strategy=          merge strategy to use
+m,message=           message to be used for the merge commit (if any)
+"
 
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
@@ -132,72 +143,47 @@ merge_name () {
 	fi
 }
 
-parse_option () {
-	case "$1" in
-	-n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\
-		--no-summa|--no-summar|--no-summary)
-		show_diffstat=false ;;
-	--summary)
-		show_diffstat=t ;;
-	--sq|--squ|--squa|--squas|--squash)
-		allow_fast_forward=t squash=t no_commit=t ;;
-	--no-sq|--no-squ|--no-squa|--no-squas|--no-squash)
-		allow_fast_forward=t squash= no_commit= ;;
-	--c|--co|--com|--comm|--commi|--commit)
-		allow_fast_forward=t squash= no_commit= ;;
-	--no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)
-		allow_fast_forward=t squash= no_commit=t ;;
-	--ff)
-		allow_fast_forward=t squash= no_commit= ;;
-	--no-ff)
-		allow_fast_forward=false squash= no_commit= ;;
-	-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
-		--strateg=*|--strategy=*|\
-	-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
-		case "$#,$1" in
-		*,*=*)
-			strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
-		1,*)
-			usage ;;
-		*)
-			strategy="$2"
-			shift ;;
-		esac
-		case " $all_strategies " in
-		*" $strategy "*)
-			use_strategies="$use_strategies$strategy " ;;
-		*)
-			die "available strategies are: $all_strategies" ;;
-		esac
-		;;
-	-m=*|--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-		merge_msg=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		have_message=t
-		;;
-	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
-		shift
-		case "$#" in
-		1)	usage ;;
-		esac
-		merge_msg="$1"
-		have_message=t
-		;;
-	-*)	usage ;;
-	*)	return 1 ;;
-	esac
-	shift
-	args_left=$#
-}
-
 parse_config () {
-	while test $# -gt 0
-	do
-		parse_option "$@" || usage
-		while test $args_left -lt $#
-		do
+	while test $# != 0; do
+		case "$1" in
+		-n|--no-summary)
+			show_diffstat=false ;;
+		--summary)
+			show_diffstat=t ;;
+		--squash)
+			allow_fast_forward=t squash=t no_commit=t ;;
+		--no-squash)
+			allow_fast_forward=t squash= no_commit= ;;
+		--commit)
+			allow_fast_forward=t squash= no_commit= ;;
+		--no-commit)
+			allow_fast_forward=t squash= no_commit=t ;;
+		--ff)
+			allow_fast_forward=t squash= no_commit= ;;
+		--no-ff)
+			allow_fast_forward=false squash= no_commit= ;;
+		-s|--strategy)
+			shift
+			case " $all_strategies " in
+			*" $1 "*)
+				use_strategies="$use_strategies$1 " ;;
+			*)
+				die "available strategies are: $all_strategies" ;;
+			esac
+			;;
+		-m|--message)
 			shift
-		done
+			merge_msg="$1"
+			have_message=t
+			;;
+		--)
+			shift
+			break ;;
+		*)	usage ;;
+		esac
+		shift
 	done
+	args_left=$#
 }
 
 test $# != 0 || usage
@@ -209,17 +195,12 @@ then
 	mergeopts=$(git config "branch.${branch#refs/heads/}.mergeoptions")
 	if test -n "$mergeopts"
 	then
-		parse_config $mergeopts
+		parse_config $mergeopts --
 	fi
 fi
 
-while parse_option "$@"
-do
-	while test $args_left -lt $#
-	do
-		shift
-	done
-done
+parse_config "$@"
+while test $args_left -lt $#; do shift; done
 
 if test -z "$show_diffstat"; then
     test "$(git config --bool merge.diffstat)" = false && show_diffstat=false
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* [PATCH 01/10] Add a parseopt mode to git-rev-parse to bring parse-options to shell scripts.
From: Pierre Habouzit @ 2007-11-04 10:30 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-1-git-send-email-madcoder@debian.org>

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 Documentation/git-rev-parse.txt |   75 ++++++++++++++++++++++-
 builtin-rev-parse.c             |  126 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 199 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 4758c33..6811656 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -23,6 +23,13 @@ distinguish between them.
 
 OPTIONS
 -------
+--parseopt::
+        Use `git-rev-parse` in option parsing mode (see PARSEOPT section below).
+
+--keep-dash-dash::
+	Only meaningful in `--parseopt` mode. Tells the option parser to echo
+        out the first `--` met instead of skipping it.
+
 --revs-only::
 	Do not output flags and parameters not meant for
 	`git-rev-list` command.
@@ -288,10 +295,74 @@ Here are a handful examples:
    C^@              I J F
    F^! D            G H D F
 
+PARSEOPT
+--------
+
+In `--parseopt` mode, `git-rev-parse` helps massaging options to bring to shell
+scripts the same facilities C builtins have. It works as an option normalizer
+(e.g. splits single switches aggregate values), a bit like `getopt(1)` does.
+
+It takes on the standard input the specification of the options to parse and
+understand, and echoes on the standard ouput a line suitable for `sh(1)` `eval`
+to replace the arguments with normalized ones.  In case of error, it ouputs
+usage on the standard error stream, and exits with code 129.
+
+Input Format
+~~~~~~~~~~~~
+
+`git-ref-parse --parseopt` input format is fully text based. It has two parts,
+separated by a line that contains only `--`. The lines before (should be more
+than one) are used for the usage. The lines after describe the options.
+
+Each line of options has this format:
+
+------------
+<opt_spec><arg_spec>? SP+ help LF
+------------
+
+`<opt_spec>`::
+	its format is the short option character, then the long option name
+        separated by a comma. Both parts are not required, though at least one
+        is necessary. `h,help`, `dry-run` and `f` are all three correct
+        `<opt_spec>`.
+
+`<arg_spec>`::
+	an `<arg_spec>` tells the option parser if the option has an argument
+        (`=`), an optionnal one (`?` though its use is discouraged) or none
+        (no `<arg_spec>` in that case).
+
+The rest of the line after as many spaces up to the ending line feed is used
+as the help associated to the option.
+
+Blank lines are ignored, and lines that don't match this specification are used
+as option group headers (start the line with a space to purposely create such
+lines).
+
+Example
+~~~~~~~
+
+------------
+OPTS_SPEC="\
+some-command [options] <args>...
+
+some-command does foo and bar !
+--
+h,help    show the help
+
+foo       some nifty option --foo
+bar=      some cool option --bar with an argument
+
+  An option group Header
+C?        option C with an optionnal argument"
+
+eval `echo "$OPTS_SPEC" | git-rev-parse --parseopt -- "$@" || echo exit $?`
+------------
+
+
 Author
 ------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>
+Written by Linus Torvalds <torvalds@osdl.org> .
+Junio C Hamano <junkio@cox.net> and Pierre Habouzit <madcoder@debian.org>
 
 Documentation
 --------------
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 8d78b69..054519b 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -8,6 +8,7 @@
 #include "refs.h"
 #include "quote.h"
 #include "builtin.h"
+#include "parse-options.h"
 
 #define DO_REVS		1
 #define DO_NOREV	2
@@ -209,6 +210,128 @@ static int try_difference(const char *arg)
 	return 0;
 }
 
+static int parseopt_dump(const struct option *o, const char *arg, int unset)
+{
+	struct strbuf *parsed = o->value;
+	if (unset)
+		strbuf_addf(parsed, " --no-%s", o->long_name);
+	else if (o->short_name)
+		strbuf_addf(parsed, " -%c", o->short_name);
+	else
+		strbuf_addf(parsed, " --%s", o->long_name);
+	if (arg) {
+		strbuf_addch(parsed, ' ');
+		sq_quote_buf(parsed, arg);
+	}
+	return 0;
+}
+
+static const char *skipspaces(const char *s)
+{
+	while (isspace(*s))
+		s++;
+	return s;
+}
+
+static int cmd_parseopt(int argc, const char **argv, const char *prefix)
+{
+	static int keep_dashdash = 0;
+	static char const * const parseopt_usage[] = {
+		"git-rev-parse --parseopt [options] -- [<args>...]",
+		NULL
+	};
+	static struct option parseopt_opts[] = {
+		OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
+					"keep the `--` passed as an arg"),
+		OPT_END(),
+	};
+
+	struct strbuf sb, parsed;
+	const char **usage = NULL;
+	struct option *opts = NULL;
+	int onb = 0, osz = 0, unb = 0, usz = 0;
+
+	strbuf_init(&parsed, 0);
+	strbuf_addstr(&parsed, "set --");
+	argc = parse_options(argc, argv, parseopt_opts, parseopt_usage,
+	                     PARSE_OPT_KEEP_DASHDASH);
+	if (argc < 1 || strcmp(argv[0], "--"))
+		usage_with_options(parseopt_usage, parseopt_opts);
+
+	strbuf_init(&sb, 0);
+	/* get the usage up to the first line with a -- on it */
+	for (;;) {
+		if (strbuf_getline(&sb, stdin, '\n') == EOF)
+			die("premature end of input");
+		ALLOC_GROW(usage, unb + 1, usz);
+		if (!strcmp("--", sb.buf)) {
+			if (unb < 1)
+				die("no usage string given before the `--' separator");
+			usage[unb] = NULL;
+			break;
+		}
+		usage[unb++] = strbuf_detach(&sb, NULL);
+	}
+
+	/* parse: (<short>|<short>,<long>|<long>)[=?]? SP+ <help> */
+	while (strbuf_getline(&sb, stdin, '\n') != EOF) {
+		const char *s;
+		struct option *o;
+
+		if (!sb.len)
+			continue;
+
+		ALLOC_GROW(opts, onb + 1, osz);
+		memset(opts + onb, 0, sizeof(opts[onb]));
+
+		o = &opts[onb++];
+		s = strchr(sb.buf, ' ');
+		if (!s || *sb.buf == ' ') {
+			o->type = OPTION_GROUP;
+			o->help = xstrdup(skipspaces(s));
+			continue;
+		}
+
+		o->type = OPTION_CALLBACK;
+		o->help = xstrdup(skipspaces(s));
+		o->value = &parsed;
+		o->callback = &parseopt_dump;
+		switch (s[-1]) {
+		case '=':
+			s--;
+			break;
+		case '?':
+			o->flags = PARSE_OPT_OPTARG;
+			s--;
+			break;
+		default:
+			o->flags = PARSE_OPT_NOARG;
+			break;
+		}
+
+		if (s - sb.buf == 1) /* short option only */
+			o->short_name = *sb.buf;
+		else if (sb.buf[1] != ',') /* long option only */
+			o->long_name = xmemdupz(sb.buf, s - sb.buf);
+		else {
+			o->short_name = *sb.buf;
+			o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2);
+		}
+	}
+	strbuf_release(&sb);
+
+	/* put an OPT_END() */
+	ALLOC_GROW(opts, onb + 1, osz);
+	memset(opts + onb, 0, sizeof(opts[onb]));
+	argc = parse_options(argc, argv, opts, usage,
+	                     keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0);
+
+	strbuf_addf(&parsed, " --");
+	sq_quote_argv(&parsed, argv, argc, 0);
+	puts(parsed.buf);
+	return 0;
+}
+
 int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 {
 	int i, as_is = 0, verify = 0;
@@ -216,6 +339,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 
 	git_config(git_default_config);
 
+	if (argc > 1 && !strcmp("--parseopt", argv[1]))
+		return cmd_parseopt(argc - 1, argv + 1, prefix);
+
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* [PATCH 04/10] Migrate git-clone to use git-rev-parse --parseopt
From: Pierre Habouzit @ 2007-11-04 10:30 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-4-git-send-email-madcoder@debian.org>

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 git-clone.sh |  102 +++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 58 insertions(+), 44 deletions(-)

diff --git a/git-clone.sh b/git-clone.sh
index 0ea3c24..52c5601 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -8,15 +8,36 @@
 # See git-sh-setup why.
 unset CDPATH
 
+OPTIONS_SPEC="\
+git-clone [options] <repo> [<dir>]
+--
+n,no-checkout        don't create a checkout
+bare                 create a bare repository
+naked                create a bare repository
+l,local              to clone from a local repository
+no-hardlinks         don't use local hardlinks, always copy
+s,shared             setup as a shared repository
+template=            path to the template directory
+q,quiet              be quiet
+reference=           reference repository
+o,origin=            use <name> instead of 'origin' to track upstream
+u,upload-pack=       path to git-upload-pack on the remote
+depth=               create a shallow clone of that depth
+
+use-separate-remote  compatibility, do not use
+no-separate-remote   compatibility, do not use"
+
 die() {
 	echo >&2 "$@"
 	exit 1
 }
 
 usage() {
-	die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] <repo> [<dir>]"
+	exec "$0" -h
 }
 
+eval `echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?`
+
 get_repo_base() {
 	(
 		cd "`/bin/pwd`" &&
@@ -106,64 +127,57 @@ depth=
 no_progress=
 local_explicitly_asked_for=
 test -t 1 || no_progress=--no-progress
-while
-	case "$#,$1" in
-	0,*) break ;;
-	*,-n|*,--no|*,--no-|*,--no-c|*,--no-ch|*,--no-che|*,--no-chec|\
-	*,--no-check|*,--no-checko|*,--no-checkou|*,--no-checkout)
-	  no_checkout=yes ;;
-	*,--na|*,--nak|*,--nake|*,--naked|\
-	*,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;;
-	*,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local)
-	  local_explicitly_asked_for=yes
-	  use_local_hardlink=yes ;;
-	*,--no-h|*,--no-ha|*,--no-har|*,--no-hard|*,--no-hardl|\
-	*,--no-hardli|*,--no-hardlin|*,--no-hardlink|*,--no-hardlinks)
-	  use_local_hardlink=no ;;
-        *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
-          local_shared=yes; ;;
-	1,--template) usage ;;
-	*,--template)
+
+while test $# != 0
+do
+	case "$1" in
+	-n|--no-checkout)
+		no_checkout=yes ;;
+	--naked|--bare)
+		bare=yes ;;
+	-l|--local)
+		local_explicitly_asked_for=yes
+		use_local_hardlink=yes
+		;;
+	--no-hardlinks)
+		use_local_hardlink=no ;;
+	-s|--shared)
+		local_shared=yes ;;
+	--template)
 		shift; template="--template=$1" ;;
-	*,--template=*)
-	  template="$1" ;;
-	*,-q|*,--quiet) quiet=-q ;;
-	*,--use-separate-remote) ;;
-	*,--no-separate-remote)
+	-q|--quiet)
+		quiet=-q ;;
+	--use-separate-remote|--no-separate-remote)
 		die "clones are always made with separate-remote layout" ;;
-	1,--reference) usage ;;
-	*,--reference)
+	--reference)
 		shift; reference="$1" ;;
-	*,--reference=*)
-		reference=`expr "z$1" : 'z--reference=\(.*\)'` ;;
-	*,-o|*,--or|*,--ori|*,--orig|*,--origi|*,--origin)
-		case "$2" in
+	-o,--origin)
+		shift;
+		case "$1" in
 		'')
 		    usage ;;
 		*/*)
-		    die "'$2' is not suitable for an origin name"
+		    die "'$1' is not suitable for an origin name"
 		esac
-		git check-ref-format "heads/$2" ||
-		    die "'$2' is not suitable for a branch name"
+		git check-ref-format "heads/$1" ||
+		    die "'$1' is not suitable for a branch name"
 		test -z "$origin_override" ||
 		    die "Do not give more than one --origin options."
 		origin_override=yes
-		origin="$2"; shift
+		origin="$1"
 		;;
-	1,-u|1,--upload-pack) usage ;;
-	*,-u|*,--upload-pack)
+	-u|--upload-pack)
 		shift
 		upload_pack="--upload-pack=$1" ;;
-	*,--upload-pack=*)
-		upload_pack=--upload-pack=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
-	1,--depth) usage;;
-	*,--depth)
+	--depth)
+		shift
+		depth="--depth=$1" ;;
+	--)
 		shift
-		depth="--depth=$1";;
-	*,-*) usage ;;
-	*) break ;;
+		break ;;
+	*)
+		usage ;;
 	esac
-do
 	shift
 done
 
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* ph/parseopt-sh reloaded
From: Pierre Habouzit @ 2007-11-04 10:30 UTC (permalink / raw)
  To: gitster; +Cc: git

Okay here is a fixed series wrt the security issue Junio raised.
Instead of the old PARSEOPT_OPTS variable, I now only have
OPTIONS_KEEPDASHDASH to be set to non empty if you want to add
--keep-dashdash. The reason for that is that I dislike that every single
git-rev-parse --parseopt user had to do a `PASREOPT_OPTS=` at the
begining of each script, it's error prone, and ugly.

PARSEOPT_OPTS was an overkill as it wasn't really used for anything else
than OPTIONS_KEEPDASHDASH, and if it has to be used for more, it'll be
easy to extend the specification parser to take options on stdin rather
than through parameters.

I also removed the PARSEOPT_OPTS from git-clone.sh as it was a spurious
use, I don't intend users to override this variable, it's indeed an
internal that changes git-rev-parse --parseopt behaviour in a
incompatible way for the scripts that uses it, it should not be
user-tweakable anyway.

The 10 patch series (and not 11, I forgot about 7 when I incrementally
sent the previous one) is fetcheable from my repository:

  git://git.madism.org/git.git on branch ph/parseopt-sh

(ph/parseopt has the remaining patches that are problematic right now
either because of the small change -h vs. -H or the patches that
conflicts with git-fetch series right now, but in the spirit this is
definitely a ph/parseopt series).

Cheers,

^ permalink raw reply

* [PATCH 03/10] Migrate git-clean.sh to use git-rev-parse --parseopt.
From: Pierre Habouzit @ 2007-11-04 10:30 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-3-git-send-email-madcoder@debian.org>

Also minor consistency tweaks in how errors are caught.

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 git-clean.sh |   38 ++++++++++++++++++++------------------
 1 files changed, 20 insertions(+), 18 deletions(-)

diff --git a/git-clean.sh b/git-clean.sh
index 4491738..6959433 100755
--- a/git-clean.sh
+++ b/git-clean.sh
@@ -3,16 +3,21 @@
 # Copyright (c) 2005-2006 Pavel Roskin
 #
 
-USAGE="[-d] [-f] [-n] [-q] [-x | -X] [--] <paths>..."
-LONG_USAGE='Clean untracked files from the working directory
-	-d	remove directories as well
-	-f	override clean.requireForce and clean anyway
-	-n 	don'\''t remove anything, just show what would be done
-	-q	be quiet, only report errors
-	-x	remove ignored files as well
-	-X	remove only ignored files
+OPTIONS_SPEC="\
+git-clean [options] <paths>...
+
+Clean untracked files from the working directory
+
 When optional <paths>... arguments are given, the paths
-affected are further limited to those that match them.'
+affected are further limited to those that match them.
+--
+d remove directories as well
+f override clean.requireForce and clean anyway
+n don't remove anything, just show what would be done
+q be quiet, only report errors
+x remove ignored files as well
+X remove only ignored files"
+
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
 require_work_tree
@@ -55,23 +60,20 @@ do
 		shift
 		break
 		;;
-	-*)
-		usage
-		;;
 	*)
-		break
+		usage # should not happen
+		;;
 	esac
 	shift
 done
 
 if [ "$disabled" = true ]; then
-	echo "clean.requireForce set and -n or -f not given; refusing to clean"
-	exit 1
+	die "clean.requireForce set and -n or -f not given; refusing to clean"
 fi
 
-case "$ignored,$ignoredonly" in
-	1,1) usage;;
-esac
+if [ "$ignored,$ignoredonly" = "1,1" ]; then
+	die "-x and -X cannot be set together"
+fi
 
 if [ -z "$ignored" ]; then
 	excl="--exclude-per-directory=.gitignore"
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* [PATCH 02/10] Update git-sh-setup(1) to allow transparent use of git-rev-parse --parseopt
From: Pierre Habouzit @ 2007-11-04 10:30 UTC (permalink / raw)
  To: gitster, Junio C Hamano; +Cc: git, Pierre Habouzit
In-Reply-To: <1194172262-1563-2-git-send-email-madcoder@debian.org>

If you set OPTIONS_SPEC, git-sh-setups uses git-rev-parse --parseopt
automatically.

It also diverts usage to re-exec $0 with the -h option as parse-options.c
will catch that.

If you need git-rev-parse --parseopt to keep the `--` the user may have
passed to your command, just set OPTIONS_KEEPDASHDASH to a non empty value.

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 git-sh-setup.sh |   48 ++++++++++++++++++++++++++++++------------------
 1 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 86d7d4c..e1cf885 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -16,9 +16,36 @@ die() {
 	exit 1
 }
 
-usage() {
-	die "Usage: $0 $USAGE"
-}
+if test -n "$OPTIONS_SPEC"; then
+	usage() {
+		exec "$0" -h
+	}
+
+	parseopt_extra=
+	[ -n "$OPTIONS_KEEPDASHDASH" ] &&
+		parseopt_extra="$parseopt_extra --keep-dashdash"
+
+	eval `echo "$OPTIONS_SPEC" | git rev-parse --parseopt $parseopt_extra -- "$@" || echo exit $?`
+else
+	usage() {
+		die "Usage: $0 $USAGE"
+	}
+
+	if [ -z "$LONG_USAGE" ]
+	then
+		LONG_USAGE="Usage: $0 $USAGE"
+	else
+		LONG_USAGE="Usage: $0 $USAGE
+
+$LONG_USAGE"
+	fi
+
+	case "$1" in
+		-h|--h|--he|--hel|--help)
+		echo "$LONG_USAGE"
+		exit
+	esac
+fi
 
 set_reflog_action() {
 	if [ -z "${GIT_REFLOG_ACTION:+set}" ]
@@ -91,21 +118,6 @@ get_author_ident_from_commit () {
 	LANG=C LC_ALL=C sed -ne "$pick_author_script"
 }
 
-if [ -z "$LONG_USAGE" ]
-then
-	LONG_USAGE="Usage: $0 $USAGE"
-else
-	LONG_USAGE="Usage: $0 $USAGE
-
-$LONG_USAGE"
-fi
-
-case "$1" in
-	-h|--h|--he|--hel|--help)
-	echo "$LONG_USAGE"
-	exit
-esac
-
 # Make sure we are in a valid repository of a vintage we understand.
 if [ -z "$SUBDIRECTORY_OK" ]
 then
-- 
1.5.3.5.1509.g66d41


^ permalink raw reply related

* [PATCH qgit] Add support for --early-output option of git log command
From: Marco Costalba @ 2007-11-04 10:25 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Linus Torvalds

With this option 'git log' outputs the first commits
as soon as they are ready in order to be able to show at
least something quickly, even if the full output may take
longer to generate.

At the end of the reordering correct revisions are re-sent.

This avoid the user to wait in front a blank screen for
several seconds in case of big repos and cold chaches.

STGit repositories are still not correctly handled, and
file history (annotation) does not uses, still, this new
--early-output feature.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
---

Patch to apply on top of current qgit-2.0 at

git://git.kernel.org/pub/scm/qgit/qgit4.git


 src/common.h        |    2 +-
 src/git.cpp         |   12 ++++++++----
 src/git.h           |    3 ++-
 src/git_startup.cpp |   39 +++++++++++++++----
 4 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/src/common.h b/src/common.h
index 198348e..de3cb7d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -289,7 +289,7 @@ namespace QGit {
 class Rev {
 	// prevent implicit C++ compiler defaults
 	Rev();
-	Rev(const Rev&);
+// 	Rev(const Rev&);
 	Rev& operator=(const Rev&);
 public:
 	Rev(const QByteArray& b, uint s, int idx, int* next, bool withDiff)
diff --git a/src/git.cpp b/src/git.cpp
index d273c60..ef9b627 100644
--- a/src/git.cpp
+++ b/src/git.cpp
@@ -73,9 +73,11 @@ const QString FileHistory::sha(int row) const {
 	return (row < 0 || row >= _rowCnt ? "" : revOrder.at(row));
 }

-void FileHistory::clear() {
+void FileHistory::clear(bool earlyOutput) {
+
+	if (!earlyOutput)
+		git->cancelDataLoading(this);

-	git->cancelDataLoading(this);
 	qDeleteAll(revs);
 	revs.clear();
 	revOrder.clear();
@@ -83,9 +85,11 @@ void FileHistory::clear() {
 	lns->clear();
 	fNames.clear();
 	curFNames.clear();
-	qDeleteAll(rowData);
-	rowData.clear();

+	if (!earlyOutput) {
+		qDeleteAll(rowData);
+		rowData.clear();
+	}
 	if (testFlag(REL_DATE_F)) {
 		_secs = QDateTime::currentDateTime().toTime_t();
 		_headerInfo[4] = "Last Change";
diff --git a/src/git.h b/src/git.h
index de014e0..92879fb 100644
--- a/src/git.h
+++ b/src/git.h
@@ -27,7 +27,7 @@ Q_OBJECT
 public:
 	FileHistory(QObject* parent, Git* git);
 	~FileHistory();
-	void clear();
+	void clear(bool earlyOutput = false);
 	const QString sha(int row) const;
 	int row(SCRef sha) const;
 	const QStringList fileNames() const { return fNames; }
@@ -251,6 +251,7 @@ private:
 	bool startParseProc(SCList initCmd, FileHistory* fh, SCRef buf);
 	bool tryFollowRenames(FileHistory* fh);
 	bool populateRenamedPatches(SCRef sha, SCList nn, FileHistory* fh,
QStringList* on, bool bt);
+	void doEarlyOutput(Rev* rev, int* start);
 	int addChunk(FileHistory* fh, const QByteArray& ba, int ofs);
 	void parseDiffFormat(RevFile& rf, SCRef buf);
 	void parseDiffFormatLine(RevFile& rf, SCRef line, int parNum);
diff --git a/src/git_startup.cpp b/src/git_startup.cpp
index 3faa059..df272fc 100644
--- a/src/git_startup.cpp
+++ b/src/git_startup.cpp
@@ -492,7 +492,9 @@ bool Git::startRevList(SCList args, FileHistory* fh) {
 	   the file deletion revision.
 	*/
 		initCmd << QString("-r -m -p --full-index").split(' ');
-	}
+	} else
+		initCmd << QString("--early-output");
+
 	return startParseProc(initCmd + args, fh, QString());
 }

@@ -839,13 +841,38 @@ void Git::loadFileNames() {
 	indexTree();
 }

+void Git::doEarlyOutput(Rev* rev, int* start) {
+
+	delete rev;
+	*start += QString("Final output:\n").length();
+
+	Rev* cl = NULL;
+	const Rev* r = revLookup(ZERO_SHA);
+	if (r)
+		cl = new Rev(*r); // copy working dir revision
+
+	revData->clear(true); // keep row QByteArray data
+
+	if (cl) { // re-add working dir revision
+		revData->revs.insert(ZERO_SHA, cl);
+		revData->revOrder.append(ZERO_SHA);
+	}
+}
+
 int Git::addChunk(FileHistory* fh, const QByteArray& ba, int start) {

 	RevMap& r = fh->revs;
 	int nextStart;
+	Rev* rev;

-	// only here we create a new rev
-	Rev* rev = new Rev(ba, start, fh->revOrder.count(), &nextStart,
!isMainHistory(fh));
+	do {
+		// only here we create a new rev
+		rev = new Rev(ba, start, fh->revOrder.count(), &nextStart,
!isMainHistory(fh));
+
+		if (nextStart == -2)
+			doEarlyOutput(rev, &start);
+
+	} while (nextStart == -2);

 	if (nextStart == -1) { // half chunk detected
 		delete rev;
@@ -1331,6 +1358,7 @@ int Rev::indexData(bool quick, bool withDiff) const {
 /*
   This is what 'git log' produces:

+	- a possible one line with "Final output:\n" in case of --early-output option
 	- one line with "commit" + sha + an arbitrary amount of parent's sha, in case
 	  of a merge in file history the line terminates with "(from <sha of parent>)"
 	- one line with "log size" + len of this record
@@ -1346,9 +1374,12 @@ int Rev::indexData(bool quick, bool withDiff) const {
 	- a terminating '\0'
 */
 	int last = ba.size() - 1;
-	if (start > last)
+	if (start > last) // offset 'start' points to the char after "commit "
 		return -1;

+	if (uint(ba.at(start) == 'u'))
+		return -2; // "Final output:", let caller handle this
+
 	// take in account --boundary and --left-right options
 	startOfs = uint(ba.at(start) == '-' || ba.at(start) == '<' ||
ba.at(start) == '>');
 	boundary = startOfs && ba.at(start) == '-';
-- 
1.5.3.5.532.g5c38-dirty

^ permalink raw reply related


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