git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / code / Atom feed
* [PATCH 1/9] Enable wt-status output to a given FILE pointer.
@ 2007-09-06  0:23 Kristian Høgsberg
  2007-09-06  0:23 ` [PATCH 2/9] Enable wt-status to run against non-standard index file Kristian Høgsberg
  2007-09-06 16:27 ` [PATCH 1/9] Enable wt-status output to a given FILE pointer Johannes Schindelin
  0 siblings, 2 replies; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

Still defaults to stdout, but you can now override wt_status.fp after
calling wt_status_prepare().

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 color.c     |   18 ++++++------
 color.h     |    4 +-
 wt-status.c |   85 ++++++++++++++++++++++++++++++----------------------------
 wt-status.h |    3 ++
 4 files changed, 58 insertions(+), 52 deletions(-)

diff --git a/color.c b/color.c
index 09d82ee..124ba33 100644
--- a/color.c
+++ b/color.c
@@ -135,39 +135,39 @@ int git_config_colorbool(const char *var, const char *value)
 	return git_config_bool(var, value);
 }
 
-static int color_vprintf(const char *color, const char *fmt,
+static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
 		va_list args, const char *trail)
 {
 	int r = 0;
 
 	if (*color)
-		r += printf("%s", color);
-	r += vprintf(fmt, args);
+		r += fprintf(fp, "%s", color);
+	r += vfprintf(fp, fmt, args);
 	if (*color)
-		r += printf("%s", COLOR_RESET);
+		r += fprintf(fp, "%s", COLOR_RESET);
 	if (trail)
-		r += printf("%s", trail);
+		r += fprintf(fp, "%s", trail);
 	return r;
 }
 
 
 
-int color_printf(const char *color, const char *fmt, ...)
+int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
 {
 	va_list args;
 	int r;
 	va_start(args, fmt);
-	r = color_vprintf(color, fmt, args, NULL);
+	r = color_vfprintf(fp, color, fmt, args, NULL);
 	va_end(args);
 	return r;
 }
 
-int color_printf_ln(const char *color, const char *fmt, ...)
+int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
 {
 	va_list args;
 	int r;
 	va_start(args, fmt);
-	r = color_vprintf(color, fmt, args, "\n");
+	r = color_vfprintf(fp, color, fmt, args, "\n");
 	va_end(args);
 	return r;
 }
diff --git a/color.h b/color.h
index 88bb8ff..6809800 100644
--- a/color.h
+++ b/color.h
@@ -6,7 +6,7 @@
 
 int git_config_colorbool(const char *var, const char *value);
 void color_parse(const char *var, const char *value, char *dst);
-int color_printf(const char *color, const char *fmt, ...);
-int color_printf_ln(const char *color, const char *fmt, ...);
+int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
+int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
 
 #endif /* COLOR_H */
diff --git a/wt-status.c b/wt-status.c
index 5205420..65a7259 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -52,31 +52,33 @@ void wt_status_prepare(struct wt_status *s)
 	head = resolve_ref("HEAD", sha1, 0, NULL);
 	s->branch = head ? xstrdup(head) : NULL;
 	s->reference = "HEAD";
+	s->fp = stdout;
 }
 
-static void wt_status_print_cached_header(const char *reference)
+static void wt_status_print_cached_header(struct wt_status *s)
 {
 	const char *c = color(WT_STATUS_HEADER);
-	color_printf_ln(c, "# Changes to be committed:");
-	if (reference) {
-		color_printf_ln(c, "#   (use \"git reset %s <file>...\" to unstage)", reference);
+	color_fprintf_ln(s->fp, c, "# Changes to be committed:");
+	if (s->reference) {
+		color_fprintf_ln(s->fp, c, "#   (use \"git reset %s <file>...\" to unstage)", s->reference);
 	} else {
-		color_printf_ln(c, "#   (use \"git rm --cached <file>...\" to unstage)");
+		color_fprintf_ln(s->fp, c, "#   (use \"git rm --cached <file>...\" to unstage)");
 	}
-	color_printf_ln(c, "#");
+	color_fprintf_ln(s->fp, c, "#");
 }
 
-static void wt_status_print_header(const char *main, const char *sub)
+static void wt_status_print_header(struct wt_status *s,
+				   const char *main, const char *sub)
 {
 	const char *c = color(WT_STATUS_HEADER);
-	color_printf_ln(c, "# %s:", main);
-	color_printf_ln(c, "#   (%s)", sub);
-	color_printf_ln(c, "#");
+	color_fprintf_ln(s->fp, c, "# %s:", main);
+	color_fprintf_ln(s->fp, c, "#   (%s)", sub);
+	color_fprintf_ln(s->fp, c, "#");
 }
 
-static void wt_status_print_trailer(void)
+static void wt_status_print_trailer(struct wt_status *s)
 {
-	color_printf_ln(color(WT_STATUS_HEADER), "#");
+	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
 }
 
 static const char *quote_crlf(const char *in, char *buf, size_t sz)
@@ -108,7 +110,8 @@ static const char *quote_crlf(const char *in, char *buf, size_t sz)
 	return ret;
 }
 
-static void wt_status_print_filepair(int t, struct diff_filepair *p)
+static void wt_status_print_filepair(struct wt_status *s,
+				     int t, struct diff_filepair *p)
 {
 	const char *c = color(t);
 	const char *one, *two;
@@ -117,36 +120,36 @@ static void wt_status_print_filepair(int t, struct diff_filepair *p)
 	one = quote_crlf(p->one->path, onebuf, sizeof(onebuf));
 	two = quote_crlf(p->two->path, twobuf, sizeof(twobuf));
 
-	color_printf(color(WT_STATUS_HEADER), "#\t");
+	color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
 	switch (p->status) {
 	case DIFF_STATUS_ADDED:
-		color_printf(c, "new file:   %s", one);
+		color_fprintf(s->fp, c, "new file:   %s", one);
 		break;
 	case DIFF_STATUS_COPIED:
-		color_printf(c, "copied:     %s -> %s", one, two);
+		color_fprintf(s->fp, c, "copied:     %s -> %s", one, two);
 		break;
 	case DIFF_STATUS_DELETED:
-		color_printf(c, "deleted:    %s", one);
+		color_fprintf(s->fp, c, "deleted:    %s", one);
 		break;
 	case DIFF_STATUS_MODIFIED:
-		color_printf(c, "modified:   %s", one);
+		color_fprintf(s->fp, c, "modified:   %s", one);
 		break;
 	case DIFF_STATUS_RENAMED:
-		color_printf(c, "renamed:    %s -> %s", one, two);
+		color_fprintf(s->fp, c, "renamed:    %s -> %s", one, two);
 		break;
 	case DIFF_STATUS_TYPE_CHANGED:
-		color_printf(c, "typechange: %s", one);
+		color_fprintf(s->fp, c, "typechange: %s", one);
 		break;
 	case DIFF_STATUS_UNKNOWN:
-		color_printf(c, "unknown:    %s", one);
+		color_fprintf(s->fp, c, "unknown:    %s", one);
 		break;
 	case DIFF_STATUS_UNMERGED:
-		color_printf(c, "unmerged:   %s", one);
+		color_fprintf(s->fp, c, "unmerged:   %s", one);
 		break;
 	default:
 		die("bug: unhandled diff status %c", p->status);
 	}
-	printf("\n");
+	fprintf(s->fp, "\n");
 }
 
 static void wt_status_print_updated_cb(struct diff_queue_struct *q,
@@ -160,14 +163,14 @@ static void wt_status_print_updated_cb(struct diff_queue_struct *q,
 		if (q->queue[i]->status == 'U')
 			continue;
 		if (!shown_header) {
-			wt_status_print_cached_header(s->reference);
+			wt_status_print_cached_header(s);
 			s->commitable = 1;
 			shown_header = 1;
 		}
-		wt_status_print_filepair(WT_STATUS_UPDATED, q->queue[i]);
+		wt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);
 	}
 	if (shown_header)
-		wt_status_print_trailer();
+		wt_status_print_trailer(s);
 }
 
 static void wt_status_print_changed_cb(struct diff_queue_struct *q,
@@ -184,12 +187,12 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q,
 				msg = use_add_rm_msg;
 				break;
 			}
-		wt_status_print_header("Changed but not updated", msg);
+		wt_status_print_header(s, "Changed but not updated", msg);
 	}
 	for (i = 0; i < q->nr; i++)
-		wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
+		wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);
 	if (q->nr)
-		wt_status_print_trailer();
+		wt_status_print_trailer(s);
 }
 
 static void wt_read_cache(struct wt_status *s)
@@ -206,16 +209,16 @@ static void wt_status_print_initial(struct wt_status *s)
 	wt_read_cache(s);
 	if (active_nr) {
 		s->commitable = 1;
-		wt_status_print_cached_header(NULL);
+		wt_status_print_cached_header(s);
 	}
 	for (i = 0; i < active_nr; i++) {
-		color_printf(color(WT_STATUS_HEADER), "#\t");
-		color_printf_ln(color(WT_STATUS_UPDATED), "new file: %s",
+		color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
+		color_fprintf_ln(s->fp, color(WT_STATUS_UPDATED), "new file: %s",
 				quote_crlf(active_cache[i]->name,
 					   buf, sizeof(buf)));
 	}
 	if (active_nr)
-		wt_status_print_trailer();
+		wt_status_print_trailer(s);
 }
 
 static void wt_status_print_updated(struct wt_status *s)
@@ -281,12 +284,12 @@ static void wt_status_print_untracked(struct wt_status *s)
 		}
 		if (!shown_header) {
 			s->workdir_untracked = 1;
-			wt_status_print_header("Untracked files",
+			wt_status_print_header(s, "Untracked files",
 					       use_add_to_include_msg);
 			shown_header = 1;
 		}
-		color_printf(color(WT_STATUS_HEADER), "#\t");
-		color_printf_ln(color(WT_STATUS_UNTRACKED), "%.*s",
+		color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
+		color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%.*s",
 				ent->len, ent->name);
 	}
 }
@@ -316,14 +319,14 @@ void wt_status_print(struct wt_status *s)
 			branch_name = "";
 			on_what = "Not currently on any branch.";
 		}
-		color_printf_ln(color(WT_STATUS_HEADER),
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER),
 			"# %s%s", on_what, branch_name);
 	}
 
 	if (s->is_initial) {
-		color_printf_ln(color(WT_STATUS_HEADER), "#");
-		color_printf_ln(color(WT_STATUS_HEADER), "# Initial commit");
-		color_printf_ln(color(WT_STATUS_HEADER), "#");
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit");
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
 		wt_status_print_initial(s);
 	}
 	else {
@@ -337,7 +340,7 @@ void wt_status_print(struct wt_status *s)
 		wt_status_print_verbose(s);
 	if (!s->commitable) {
 		if (s->amend)
-			printf("# No changes\n");
+			fprintf(s->fp, "# No changes\n");
 		else if (s->workdir_dirty)
 			printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n");
 		else if (s->workdir_untracked)
diff --git a/wt-status.h b/wt-status.h
index cfea4ae..4f3a615 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -1,6 +1,8 @@
 #ifndef STATUS_H
 #define STATUS_H
 
+#include <stdio.h>
+
 enum color_wt_status {
 	WT_STATUS_HEADER,
 	WT_STATUS_UPDATED,
@@ -19,6 +21,7 @@ struct wt_status {
 	int commitable;
 	int workdir_dirty;
 	int workdir_untracked;
+	FILE *fp;
 };
 
 int git_status_config(const char *var, const char *value);
-- 
1.5.2.GIT

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 2/9] Enable wt-status to run against non-standard index file.
  2007-09-06  0:23 [PATCH 1/9] Enable wt-status output to a given FILE pointer Kristian Høgsberg
@ 2007-09-06  0:23 ` Kristian Høgsberg
  2007-09-06  0:23   ` [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf Kristian Høgsberg
  2007-09-06 16:27 ` [PATCH 1/9] Enable wt-status output to a given FILE pointer Johannes Schindelin
  1 sibling, 1 reply; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

We still default to get_index_file(), but this can be overridden
by setting wt_status.index_file after calling wt_status_prepare().

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 wt-status.c |    3 ++-
 wt-status.h |    1 +
 2 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/wt-status.c b/wt-status.c
index 65a7259..0cf9b81 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -53,6 +53,7 @@ void wt_status_prepare(struct wt_status *s)
 	s->branch = head ? xstrdup(head) : NULL;
 	s->reference = "HEAD";
 	s->fp = stdout;
+	s->index_file = get_index_file();
 }
 
 static void wt_status_print_cached_header(struct wt_status *s)
@@ -198,7 +199,7 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q,
 static void wt_read_cache(struct wt_status *s)
 {
 	discard_cache();
-	read_cache();
+	read_cache_from(s->index_file);
 }
 
 static void wt_status_print_initial(struct wt_status *s)
diff --git a/wt-status.h b/wt-status.h
index 4f3a615..7744932 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -21,6 +21,7 @@ struct wt_status {
 	int commitable;
 	int workdir_dirty;
 	int workdir_untracked;
+	const char *index_file;
 	FILE *fp;
 };
 
-- 
1.5.2.GIT

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf.
  2007-09-06  0:23 ` [PATCH 2/9] Enable wt-status to run against non-standard index file Kristian Høgsberg
@ 2007-09-06  0:23   ` Kristian Høgsberg
  2007-09-06  0:23     ` [PATCH 4/9] Introduce entry point for launching add--interactive Kristian Høgsberg
  2007-09-06  8:55     ` [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf Junio C Hamano
  0 siblings, 2 replies; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

Also, expose strbuf_add() and strbuf_add_char() to add raw data to the buffer.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 strbuf.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 strbuf.h |    3 ++
 2 files changed, 65 insertions(+), 7 deletions(-)

diff --git a/strbuf.c b/strbuf.c
index e33d06b..2805c11 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -11,16 +11,26 @@ static void strbuf_begin(struct strbuf *sb) {
 	strbuf_init(sb);
 }
 
-static void inline strbuf_add(struct strbuf *sb, int ch) {
-	if (sb->alloc <= sb->len) {
-		sb->alloc = sb->alloc * 3 / 2 + 16;
-		sb->buf = xrealloc(sb->buf, sb->alloc);
-	}
+static void inline strbuf_grow(struct strbuf *sb, size_t extra)
+{
+	ALLOC_GROW(sb->buf, sb->len + extra, sb->alloc);
+}
+
+void strbuf_add(struct strbuf *sb, const char *data, size_t len)
+{
+	strbuf_grow(sb, len);
+	memcpy(sb->buf + sb->len, data, len);
+	sb->len += len;
+}
+
+void strbuf_add_char(struct strbuf *sb, int ch)
+{
+	strbuf_grow(sb, 1);
 	sb->buf[sb->len++] = ch;
 }
 
 static void strbuf_end(struct strbuf *sb) {
-	strbuf_add(sb, 0);
+	strbuf_add_char(sb, 0);
 }
 
 void read_line(struct strbuf *sb, FILE *fp, int term) {
@@ -33,9 +43,54 @@ void read_line(struct strbuf *sb, FILE *fp, int term) {
 	while ((ch = fgetc(fp)) != EOF) {
 		if (ch == term)
 			break;
-		strbuf_add(sb, ch);
+		strbuf_add_char(sb, ch);
 	}
 	if (ch == EOF && sb->len == 0)
 		sb->eof = 1;
 	strbuf_end(sb);
 }
+
+void strbuf_printf(struct strbuf *sb, const char *fmt, ...)
+{
+	char buffer[2048];
+	va_list args;
+	int len, size = 2 * sizeof buffer;
+
+	va_start(args, fmt);
+	len = vsnprintf(buffer, sizeof(buffer), fmt, args);
+	va_end(args);
+
+	if (len > sizeof(buffer)) {
+		/*
+		 * Didn't fit in the buffer, but this vsnprintf at
+		 * least gives us the required length back.  Grow the
+		 * buffer acccordingly and try again.
+		 */
+		strbuf_grow(sb, len);
+		va_start(args, fmt);
+		len = vsnprintf(sb->buf + sb->len,
+				sb->alloc - sb->len, fmt, args);
+		va_end(args);
+	} else if (len >= 0) {
+		/*
+		 * The initial vsnprintf fit in the temp buffer, just
+		 * copy it to the strbuf.
+		 */
+		strbuf_add(sb, buffer, len);
+	} else {
+		/*
+		 * This vnsprintf sucks and just returns -1 when the
+		 * buffer is too small.  Keep doubling the size until
+		 * it fits.
+		 */
+		while (len < 0) {
+			strbuf_grow(sb, size);
+			va_start(args, fmt);
+			len = vsnprintf(sb->buf + sb->len,
+					sb->alloc - sb->len, fmt, args);
+			va_end(args);
+			size *= 2;
+		}
+	}
+}
+
diff --git a/strbuf.h b/strbuf.h
index 74cc012..1e5d09e 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -9,5 +9,8 @@ struct strbuf {
 
 extern void strbuf_init(struct strbuf *);
 extern void read_line(struct strbuf *, FILE *, int);
+extern void strbuf_add(struct strbuf *sb, const char *data, size_t len);
+extern void strbuf_add_char(struct strbuf *sb, int ch);
+extern void strbuf_printf(struct strbuf *sb, const char *fmt, ...);
 
 #endif /* STRBUF_H */
-- 
1.5.2.GIT

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 4/9] Introduce entry point for launching add--interactive.
  2007-09-06  0:23   ` [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf Kristian Høgsberg
@ 2007-09-06  0:23     ` Kristian Høgsberg
  2007-09-06  0:23       ` [PATCH 5/9] Introduce strbuf_read_fd() Kristian Høgsberg
  2007-09-06 16:31       ` [PATCH 4/9] Introduce entry point for launching add--interactive Johannes Schindelin
  2007-09-06  8:55     ` [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf Junio C Hamano
  1 sibling, 2 replies; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

This refactors builtin-add.c a little to provide a unique entry point
for launching git add --interactive, which will be used by
builtin-commit too.  If we later want to make add --interactive a
builtin or change how it is launched, we just start from this function.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 builtin-add.c |   15 ++++++++++-----
 commit.h      |    9 +++++++++
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/builtin-add.c b/builtin-add.c
index 3dd4ded..e79e8f7 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -12,6 +12,7 @@
 #include "diffcore.h"
 #include "commit.h"
 #include "revision.h"
+#include "run-command.h"
 
 static const char builtin_add_usage[] =
 "git-add [-n] [-v] [-f] [--interactive | -i] [-u] [--] <filepattern>...";
@@ -153,6 +154,13 @@ static int git_add_config(const char *var, const char *value)
 	return git_default_config(var, value);
 }
 
+int interactive_add(void)
+{
+	const char *argv[2] = { "add--interactive", NULL };
+
+	return run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
 static struct lock_file lock_file;
 
 static const char ignore_warning[] =
@@ -172,12 +180,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 			add_interactive++;
 	}
 	if (add_interactive) {
-		const char *args[] = { "add--interactive", NULL };
-
-		if (add_interactive != 1 || argc != 2)
+		if (argc != 2)
 			die("add --interactive does not take any parameters");
-		execv_git_cmd(args);
-		exit(1);
+		exit(interactive_add());
 	}
 
 	git_config(git_add_config);
diff --git a/commit.h b/commit.h
index 467872e..64e1d4b 100644
--- a/commit.h
+++ b/commit.h
@@ -122,4 +122,13 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
 		int depth, int shallow_flag, int not_shallow_flag);
 
 int in_merge_bases(struct commit *, struct commit **, int);
+
+extern const unsigned char *
+create_commit(const unsigned char *tree_sha1,
+	      unsigned char parent_sha1[][20], int parents,
+	      const char *author_info, const char *committer_info,
+	      const char *message, int length);
+
+extern int interactive_add(void);
+
 #endif /* COMMIT_H */
-- 
1.5.2.GIT

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 5/9] Introduce strbuf_read_fd().
  2007-09-06  0:23     ` [PATCH 4/9] Introduce entry point for launching add--interactive Kristian Høgsberg
@ 2007-09-06  0:23       ` Kristian Høgsberg
  2007-09-06  0:23         ` [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs Kristian Høgsberg
  2007-09-06 16:31       ` [PATCH 4/9] Introduce entry point for launching add--interactive Johannes Schindelin
  1 sibling, 1 reply; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

This function reads from a given fd into a strbuf until end of file.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 strbuf.c |   19 +++++++++++++++++++
 strbuf.h |    1 +
 2 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/strbuf.c b/strbuf.c
index 2805c11..fcfc05e 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -50,6 +50,25 @@ void read_line(struct strbuf *sb, FILE *fp, int term) {
 	strbuf_end(sb);
 }
 
+int strbuf_read_fd(struct strbuf *sb, int fd)
+{
+	int len, total = 0;
+
+	do {
+		strbuf_grow(sb, 1024);
+		len = xread(fd, sb->buf + sb->len, sb->alloc - sb->len);
+		if (len > 0) {
+			total += len;
+			sb->len += len;
+		}
+	} while (len > 0);
+
+	if (len < 0)
+		return len;
+
+	return total;
+}
+
 void strbuf_printf(struct strbuf *sb, const char *fmt, ...)
 {
 	char buffer[2048];
diff --git a/strbuf.h b/strbuf.h
index 1e5d09e..6e630ea 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -12,5 +12,6 @@ extern void read_line(struct strbuf *, FILE *, int);
 extern void strbuf_add(struct strbuf *sb, const char *data, size_t len);
 extern void strbuf_add_char(struct strbuf *sb, int ch);
 extern void strbuf_printf(struct strbuf *sb, const char *fmt, ...);
+extern int strbuf_read_fd(struct strbuf *sb, int fd);
 
 #endif /* STRBUF_H */
-- 
1.5.2.GIT

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs.
  2007-09-06  0:23       ` [PATCH 5/9] Introduce strbuf_read_fd() Kristian Høgsberg
@ 2007-09-06  0:23         ` Kristian Høgsberg
  2007-09-06  0:23           ` [PATCH 7/9] Add strbuf_read_path() Kristian Høgsberg
  2007-09-06 16:38           ` [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs Johannes Schindelin
  0 siblings, 2 replies; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 builtin-stripspace.c |   45 +++++++++++++-------------
 builtin-tag.c        |   84 +++++++++++++++++++++-----------------------------
 builtin.h            |    1 -
 strbuf.c             |   43 +++++---------------------
 strbuf.h             |    2 +
 5 files changed, 68 insertions(+), 107 deletions(-)

diff --git a/builtin-stripspace.c b/builtin-stripspace.c
index 916355c..f0264a8 100644
--- a/builtin-stripspace.c
+++ b/builtin-stripspace.c
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "strbuf.h"
 
 /*
  * Returns the length of a line, without trailing spaces.
@@ -34,34 +35,34 @@ static size_t cleanup(char *line, size_t len)
  * If the input has only empty lines and spaces,
  * no output will be produced.
  *
- * If last line has a newline at the end, it will be removed.
+ * If the last line does not have a newline, one will be added.
  *
  * Enable skip_comments to skip every line starting with "#".
  */
-size_t stripspace(char *buffer, size_t length, int skip_comments)
+size_t stripspace(struct strbuf *sb, int skip_comments)
 {
 	int empties = -1;
 	size_t i, j, len, newlen;
 	char *eol;
 
-	for (i = j = 0; i < length; i += len, j += newlen) {
-		eol = memchr(buffer + i, '\n', length - i);
-		len = eol ? eol - (buffer + i) + 1 : length - i;
+	for (i = j = 0; i < sb->len; i += len, j += newlen) {
+		eol = memchr(sb->buf + i, '\n', sb->len - i);
+		len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
 
-		if (skip_comments && len && buffer[i] == '#') {
+		if (skip_comments && len && sb->buf[i] == '#') {
 			newlen = 0;
 			continue;
 		}
-		newlen = cleanup(buffer + i, len);
+		newlen = cleanup(sb->buf + i, len);
 
 		/* Not just an empty line? */
 		if (newlen) {
 			if (empties != -1)
-				buffer[j++] = '\n';
+				sb->buf[j++] = '\n';
 			if (empties > 0)
-				buffer[j++] = '\n';
+				sb->buf[j++] = '\n';
 			empties = 0;
-			memmove(buffer + j, buffer + i, newlen);
+			memmove(sb->buf + j, sb->buf + i, newlen);
 			continue;
 		}
 		if (empties < 0)
@@ -69,31 +70,31 @@ size_t stripspace(char *buffer, size_t length, int skip_comments)
 		empties++;
 	}
 
-	return j;
+	sb->len = j;
+	if (j > 0)
+		strbuf_add_char(sb, '\n');
+
+	return sb->len;
 }
 
 int cmd_stripspace(int argc, const char **argv, const char *prefix)
 {
-	char *buffer;
-	unsigned long size;
+	struct strbuf sb;
 	int strip_comments = 0;
 
 	if (argc > 1 && (!strcmp(argv[1], "-s") ||
 				!strcmp(argv[1], "--strip-comments")))
 		strip_comments = 1;
 
-	size = 1024;
-	buffer = xmalloc(size);
-	if (read_fd(0, &buffer, &size)) {
-		free(buffer);
+	strbuf_init(&sb);
+	if (strbuf_read_fd(&sb, 0) < 0) {
+		strbuf_release(&sb);
 		die("could not read the input");
 	}
 
-	size = stripspace(buffer, size, strip_comments);
-	write_or_die(1, buffer, size);
-	if (size)
-		putc('\n', stdout);
+	stripspace(&sb, strip_comments);
+	write_or_die(1, sb.buf, sb.len);
+	strbuf_release(&sb);
 
-	free(buffer);
 	return 0;
 }
diff --git a/builtin-tag.c b/builtin-tag.c
index d6d38ad..1aff952 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -11,13 +11,14 @@
 #include "refs.h"
 #include "tag.h"
 #include "run-command.h"
+#include "strbuf.h"
 
 static const char builtin_tag_usage[] =
   "git-tag [-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg> | -F <file>] <tagname> [<head>]";
 
 static char signingkey[1000];
 
-static void launch_editor(const char *path, char **buffer, unsigned long *len)
+static void launch_editor(const char *path, struct strbuf *sb)
 {
 	const char *editor, *terminal;
 	struct child_process child;
@@ -55,10 +56,9 @@ static void launch_editor(const char *path, char **buffer, unsigned long *len)
 	fd = open(path, O_RDONLY);
 	if (fd < 0)
 		die("could not open '%s': %s", path, strerror(errno));
-	if (read_fd(fd, buffer, len)) {
-		free(*buffer);
+	if (strbuf_read_fd(sb, fd) < 0) {
 		die("could not read message file '%s': %s",
-						path, strerror(errno));
+		    path, strerror(errno));
 	}
 	close(fd);
 }
@@ -191,7 +191,7 @@ static int verify_tag(const char *name, const char *ref,
 	return 0;
 }
 
-static ssize_t do_sign(char *buffer, size_t size, size_t max)
+static int do_sign(struct strbuf *sb)
 {
 	struct child_process gpg;
 	const char *args[4];
@@ -219,17 +219,13 @@ static ssize_t do_sign(char *buffer, size_t size, size_t max)
 	if (start_command(&gpg))
 		return error("could not run gpg.");
 
-	write_or_die(gpg.in, buffer, size);
+	write_or_die(gpg.in, sb->buf, sb->len);
 	close(gpg.in);
 	gpg.close_in = 0;
-	len = read_in_full(gpg.out, buffer + size, max - size);
-
+	len = strbuf_read_fd(sb, gpg.out);
 	finish_command(&gpg);
 
-	if (len == max - size)
-		return error("could not read the entire signature from gpg.");
-
-	return size + len;
+	return len;
 }
 
 static const char tag_template[] =
@@ -258,26 +254,24 @@ static void create_tag(const unsigned char *object, const char *tag,
 		       char *message, int sign, unsigned char *result)
 {
 	enum object_type type;
-	char header_buf[1024], *buffer = NULL;
-	int header_len, max_size;
-	unsigned long size = 0;
+	struct strbuf sb;
+	int header_len;
 
 	type = sha1_object_info(object, NULL);
 	if (type <= OBJ_NONE)
 	    die("bad object type.");
 
-	header_len = snprintf(header_buf, sizeof(header_buf),
-			  "object %s\n"
-			  "type %s\n"
-			  "tag %s\n"
-			  "tagger %s\n\n",
-			  sha1_to_hex(object),
-			  typename(type),
-			  tag,
-			  git_committer_info(1));
-
-	if (header_len > sizeof(header_buf) - 1)
-		die("tag header too big.");
+	strbuf_init(&sb);
+	strbuf_printf(&sb,
+		      "object %s\n"
+		      "type %s\n"
+		      "tag %s\n"
+		      "tagger %s\n\n",
+		      sha1_to_hex(object),
+		      typename(type),
+		      tag,
+		      git_committer_info(1));
+	header_len = sb.len;
 
 	if (!message) {
 		char *path;
@@ -292,39 +286,31 @@ static void create_tag(const unsigned char *object, const char *tag,
 		write_or_die(fd, tag_template, strlen(tag_template));
 		close(fd);
 
-		launch_editor(path, &buffer, &size);
+		launch_editor(path, &sb);
 
 		unlink(path);
 		free(path);
 	}
 	else {
-		buffer = message;
-		size = strlen(message);
+		strbuf_add(&sb, message, strlen(message));
 	}
 
-	size = stripspace(buffer, size, 1);
-
-	if (!message && !size)
+	if (stripspace(&sb, 1) <= header_len && !message)
 		die("no tag message?");
 
-	/* insert the header and add the '\n' if needed: */
-	max_size = header_len + size + (sign ? MAX_SIGNATURE_LENGTH : 0) + 1;
-	buffer = xrealloc(buffer, max_size);
-	if (size)
-		buffer[size++] = '\n';
-	memmove(buffer + header_len, buffer, size);
-	memcpy(buffer, header_buf, header_len);
-	size += header_len;
-
-	if (sign) {
-		size = do_sign(buffer, size, max_size);
-		if (size < 0)
-			die("unable to sign the tag");
-	}
+	/* Debatable, but makes t7401-tag.sh pass.  Creates an extra
+	 * blank line after the header block for tags with empty
+	 * messages. */
+	if (sb.len < header_len)
+		strbuf_add_char(&sb, '\n');
 
-	if (write_sha1_file(buffer, size, tag_type, result) < 0)
+	if (sign && do_sign(&sb) < 0)
+		die("unable to sign the tag");
+
+	if (write_sha1_file(sb.buf, sb.len, tag_type, result) < 0)
 		die("unable to write tag file");
-	free(buffer);
+
+	strbuf_release(&sb);
 }
 
 int cmd_tag(int argc, const char **argv, const char *prefix)
diff --git a/builtin.h b/builtin.h
index bb72000..91bc595 100644
--- a/builtin.h
+++ b/builtin.h
@@ -7,7 +7,6 @@ extern const char git_version_string[];
 extern const char git_usage_string[];
 
 extern void help_unknown_cmd(const char *cmd);
-extern size_t stripspace(char *buffer, size_t length, int skip_comments);
 extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
 extern void prune_packed_objects(int);
 
diff --git a/strbuf.c b/strbuf.c
index fcfc05e..ed2afea 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -6,7 +6,8 @@ void strbuf_init(struct strbuf *sb) {
 	sb->eof = sb->alloc = sb->len = 0;
 }
 
-static void strbuf_begin(struct strbuf *sb) {
+void strbuf_release(struct strbuf *sb)
+{
 	free(sb->buf);
 	strbuf_init(sb);
 }
@@ -35,7 +36,7 @@ static void strbuf_end(struct strbuf *sb) {
 
 void read_line(struct strbuf *sb, FILE *fp, int term) {
 	int ch;
-	strbuf_begin(sb);
+	strbuf_release(sb);
 	if (feof(fp)) {
 		sb->eof = 1;
 		return;
@@ -73,43 +74,15 @@ void strbuf_printf(struct strbuf *sb, const char *fmt, ...)
 {
 	char buffer[2048];
 	va_list args;
-	int len, size = 2 * sizeof buffer;
+	int len;
 
 	va_start(args, fmt);
 	len = vsnprintf(buffer, sizeof(buffer), fmt, args);
 	va_end(args);
 
-	if (len > sizeof(buffer)) {
-		/*
-		 * Didn't fit in the buffer, but this vsnprintf at
-		 * least gives us the required length back.  Grow the
-		 * buffer acccordingly and try again.
-		 */
-		strbuf_grow(sb, len);
-		va_start(args, fmt);
-		len = vsnprintf(sb->buf + sb->len,
-				sb->alloc - sb->len, fmt, args);
-		va_end(args);
-	} else if (len >= 0) {
-		/*
-		 * The initial vsnprintf fit in the temp buffer, just
-		 * copy it to the strbuf.
-		 */
-		strbuf_add(sb, buffer, len);
-	} else {
-		/*
-		 * This vnsprintf sucks and just returns -1 when the
-		 * buffer is too small.  Keep doubling the size until
-		 * it fits.
-		 */
-		while (len < 0) {
-			strbuf_grow(sb, size);
-			va_start(args, fmt);
-			len = vsnprintf(sb->buf + sb->len,
-					sb->alloc - sb->len, fmt, args);
-			va_end(args);
-			size *= 2;
-		}
-	}
+	if (len > sizeof(buffer) || len < 0)
+		die("out of buffer space\n");
+
+	strbuf_add(sb, buffer, len);
 }
 
diff --git a/strbuf.h b/strbuf.h
index 6e630ea..a93b9e1 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -8,10 +8,12 @@ struct strbuf {
 };
 
 extern void strbuf_init(struct strbuf *);
+extern void strbuf_release(struct strbuf *);
 extern void read_line(struct strbuf *, FILE *, int);
 extern void strbuf_add(struct strbuf *sb, const char *data, size_t len);
 extern void strbuf_add_char(struct strbuf *sb, int ch);
 extern void strbuf_printf(struct strbuf *sb, const char *fmt, ...);
 extern int strbuf_read_fd(struct strbuf *sb, int fd);
+extern size_t stripspace(struct strbuf *sb, int skip_comments);
 
 #endif /* STRBUF_H */
-- 
1.5.2.GIT

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 7/9] Add strbuf_read_path().
  2007-09-06  0:23         ` [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs Kristian Høgsberg
@ 2007-09-06  0:23           ` Kristian Høgsberg
  2007-09-06  0:23             ` [PATCH 8/9] Export rerere() and launch_editor() Kristian Høgsberg
  2007-09-06 16:40             ` [PATCH 7/9] Add strbuf_read_path() Johannes Schindelin
  2007-09-06 16:38           ` [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs Johannes Schindelin
  1 sibling, 2 replies; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 builtin-tag.c |    7 +------
 strbuf.c      |   15 +++++++++++++++
 strbuf.h      |    1 +
 3 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/builtin-tag.c b/builtin-tag.c
index 1aff952..8724d49 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -53,14 +53,9 @@ static void launch_editor(const char *path, struct strbuf *sb)
 	if (run_command(&child))
 		die("There was a problem with the editor %s.", editor);
 
-	fd = open(path, O_RDONLY);
-	if (fd < 0)
-		die("could not open '%s': %s", path, strerror(errno));
-	if (strbuf_read_fd(sb, fd) < 0) {
+	if (strbuf_read_path(sb, path) < 0)
 		die("could not read message file '%s': %s",
 		    path, strerror(errno));
-	}
-	close(fd);
 }
 
 struct tag_filter {
diff --git a/strbuf.c b/strbuf.c
index ed2afea..1951a5b 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -70,6 +70,21 @@ int strbuf_read_fd(struct strbuf *sb, int fd)
 	return total;
 }
 
+int strbuf_read_path(struct strbuf *sb, const char *path)
+{
+	int fd, len;
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return -1;
+	len = strbuf_read_fd(sb, fd);
+	if (len < 0)
+		return -1;
+	close(fd);
+
+	return len;
+}
+
 void strbuf_printf(struct strbuf *sb, const char *fmt, ...)
 {
 	char buffer[2048];
diff --git a/strbuf.h b/strbuf.h
index a93b9e1..e852070 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -14,6 +14,7 @@ extern void strbuf_add(struct strbuf *sb, const char *data, size_t len);
 extern void strbuf_add_char(struct strbuf *sb, int ch);
 extern void strbuf_printf(struct strbuf *sb, const char *fmt, ...);
 extern int strbuf_read_fd(struct strbuf *sb, int fd);
+extern int strbuf_read_path(struct strbuf *sb, const char *path);
 extern size_t stripspace(struct strbuf *sb, int skip_comments);
 
 #endif /* STRBUF_H */
-- 
1.5.2.GIT

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 8/9] Export rerere() and launch_editor().
  2007-09-06  0:23           ` [PATCH 7/9] Add strbuf_read_path() Kristian Høgsberg
@ 2007-09-06  0:23             ` Kristian Høgsberg
  2007-09-06  0:23               ` [PATCH 9/9] Implement git commit as a builtin command Kristian Høgsberg
  2007-09-06 16:40             ` [PATCH 7/9] Add strbuf_read_path() Johannes Schindelin
  1 sibling, 1 reply; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 builtin-rerere.c |   16 ++++++++++++++++
 builtin-tag.c    |    3 +--
 commit.h         |    1 +
 strbuf.h         |    1 +
 4 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/builtin-rerere.c b/builtin-rerere.c
index 29d057c..eb22a28 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -415,6 +415,22 @@ static int is_rerere_enabled(void)
 	return 1;
 }
 
+/* Export for builtin-commit. */
+int rerere(void)
+{
+	struct path_list merge_rr = { NULL, 0, 0, 1 };
+	int fd;
+
+	git_config(git_rerere_config);
+	if (!is_rerere_enabled())
+		return 0;
+
+	merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR"));
+	fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
+	read_rr(&merge_rr);
+	return do_plain_rerere(&merge_rr, fd);
+}
+
 int cmd_rerere(int argc, const char **argv, const char *prefix)
 {
 	struct path_list merge_rr = { NULL, 0, 0, 1 };
diff --git a/builtin-tag.c b/builtin-tag.c
index 8724d49..3b181f5 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -18,12 +18,11 @@ static const char builtin_tag_usage[] =
 
 static char signingkey[1000];
 
-static void launch_editor(const char *path, struct strbuf *sb)
+void launch_editor(const char *path, struct strbuf *sb)
 {
 	const char *editor, *terminal;
 	struct child_process child;
 	const char *args[3];
-	int fd;
 
 	editor = getenv("GIT_EDITOR");
 	if (!editor && editor_program)
diff --git a/commit.h b/commit.h
index 64e1d4b..39934cc 100644
--- a/commit.h
+++ b/commit.h
@@ -130,5 +130,6 @@ create_commit(const unsigned char *tree_sha1,
 	      const char *message, int length);
 
 extern int interactive_add(void);
+extern int rerere(void);
 
 #endif /* COMMIT_H */
diff --git a/strbuf.h b/strbuf.h
index e852070..b009b4b 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -16,5 +16,6 @@ extern void strbuf_printf(struct strbuf *sb, const char *fmt, ...);
 extern int strbuf_read_fd(struct strbuf *sb, int fd);
 extern int strbuf_read_path(struct strbuf *sb, const char *path);
 extern size_t stripspace(struct strbuf *sb, int skip_comments);
+extern void launch_editor(const char *path, struct strbuf *sb);
 
 #endif /* STRBUF_H */
-- 
1.5.2.GIT

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 9/9] Implement git commit as a builtin command.
  2007-09-06  0:23             ` [PATCH 8/9] Export rerere() and launch_editor() Kristian Høgsberg
@ 2007-09-06  0:23               ` Kristian Høgsberg
  2007-09-06 16:59                 ` Johannes Schindelin
  0 siblings, 1 reply; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

Move git-commit.sh to contrib/examples.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 Makefile                       |    9 +-
 builtin-commit.c               |  742 ++++++++++++++++++++++++++++++++++++++++
 builtin.h                      |    3 +-
 contrib/examples/git-commit.sh |  665 +++++++++++++++++++++++++++++++++++
 git-commit.sh                  |  665 -----------------------------------
 git.c                          |    3 +-
 6 files changed, 1414 insertions(+), 673 deletions(-)
 create mode 100644 builtin-commit.c
 create mode 100755 contrib/examples/git-commit.sh
 delete mode 100755 git-commit.sh

diff --git a/Makefile b/Makefile
index 4eb4637..beb3cbb 100644
--- a/Makefile
+++ b/Makefile
@@ -201,7 +201,7 @@ BASIC_LDFLAGS =
 
 SCRIPT_SH = \
 	git-bisect.sh git-checkout.sh \
-	git-clean.sh git-clone.sh git-commit.sh \
+	git-clean.sh git-clone.sh \
 	git-fetch.sh \
 	git-ls-remote.sh \
 	git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
@@ -250,7 +250,7 @@ EXTRA_PROGRAMS =
 BUILT_INS = \
 	git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
 	git-get-tar-commit-id$X git-init$X git-repo-config$X \
-	git-fsck-objects$X git-cherry-pick$X \
+	git-fsck-objects$X git-cherry-pick$X git-status$X\
 	$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
@@ -322,6 +322,7 @@ BUILTIN_OBJS = \
 	builtin-check-attr.o \
 	builtin-checkout-index.o \
 	builtin-check-ref-format.o \
+	builtin-commit.o \
 	builtin-commit-tree.o \
 	builtin-count-objects.o \
 	builtin-describe.o \
@@ -357,7 +358,6 @@ BUILTIN_OBJS = \
 	builtin-rev-parse.o \
 	builtin-revert.o \
 	builtin-rm.o \
-	builtin-runstatus.o \
 	builtin-shortlog.o \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
@@ -797,9 +797,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
 	chmod +x $@+ && \
 	mv $@+ $@
 
-git-status: git-commit
-	$(QUIET_GEN)cp $< $@+ && mv $@+ $@
-
 gitweb/gitweb.cgi: gitweb/gitweb.perl
 	$(QUIET_GEN)$(RM) $@ $@+ && \
 	sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
diff --git a/builtin-commit.c b/builtin-commit.c
new file mode 100644
index 0000000..aca5ff8
--- /dev/null
+++ b/builtin-commit.c
@@ -0,0 +1,742 @@
+/*
+ * Builtin "git commit"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "cache.h"
+#include "cache-tree.h"
+#include "builtin.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "commit.h"
+#include "revision.h"
+#include "wt-status.h"
+#include "run-command.h"
+#include "refs.h"
+#include "log-tree.h"
+#include "strbuf.h"
+#include "utf8.h"
+
+void launch_editor(const char *path, struct strbuf *sb);
+int rerere(void);
+
+static const char builtin_commit_usage[] =
+	"[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]";
+
+static unsigned char head_sha1[20], merge_head_sha1[20];
+static char *use_message_buffer;
+static const char commit_editmsg[] = "COMMIT_EDITMSG";
+static struct lock_file lock_file;
+
+enum option_type {
+    OPTION_NONE,
+    OPTION_STRING,
+    OPTION_INTEGER,
+    OPTION_LAST,
+};
+
+struct option {
+    enum option_type type;
+    const char *long_name;
+    char short_name;
+    void *value;
+};
+
+static int scan_options(const char ***argv, struct option *options)
+{
+	const char *value, *eq;
+	int i;
+
+	if (**argv == NULL)
+		return 0;
+	if ((**argv)[0] != '-')
+		return 0;
+	if (!strcmp(**argv, "--"))
+		return 0;
+
+	value = NULL;
+	for (i = 0; options[i].type != OPTION_LAST; i++) {
+		if ((**argv)[1] == '-') {
+			if (!prefixcmp(options[i].long_name, **argv + 2)) {
+				if (options[i].type != OPTION_NONE)
+					value = *++(*argv);
+				goto match;
+			}
+
+			eq = strchr(**argv + 2, '=');
+			if (eq && options[i].type != OPTION_NONE &&
+			    !strncmp(**argv + 2, 
+				     options[i].long_name, eq - **argv - 2)) {
+				value = eq + 1;
+				goto match;
+			}
+		}
+
+		if ((**argv)[1] == options[i].short_name) {
+			if ((**argv)[2] == '\0') {
+				if (options[i].type != OPTION_NONE)
+					value = *++(*argv);
+				goto match;
+			}
+
+			if (options[i].type != OPTION_NONE) {
+				value = **argv + 2;
+				goto match;
+			}
+		}
+	}
+
+	usage(builtin_commit_usage);
+
+ match:
+	switch (options[i].type) {
+	case OPTION_NONE:
+		*(int *)options[i].value = 1;
+		break;
+	case OPTION_STRING:
+		if (value == NULL)
+			die("option %s requires a value.", (*argv)[-1]);
+		*(const char **)options[i].value = value;
+		break;
+	case OPTION_INTEGER:
+		if (value == NULL)
+			die("option %s requires a value.", (*argv)[-1]);
+		*(int *)options[i].value = atoi(value);
+		break;
+	default:
+		assert(0);
+	}
+
+	(*argv)++;
+
+	return 1;
+}
+
+static char *logfile, *force_author, *message, *template_file;
+static char *edit_message, *use_message;
+static int all, edit_flag, also, interactive, only, no_verify, amend, signoff;
+static int quiet, verbose, untracked_files;
+
+static int no_edit, initial_commit, in_merge;
+const char *only_include_assumed;
+
+static struct option commit_options[] = {
+	{ OPTION_STRING, "file", 'F', (void *) &logfile },
+	{ OPTION_NONE, "all", 'a', &all },
+	{ OPTION_STRING, "author", 0, (void *) &force_author },
+	{ OPTION_NONE, "edit", 'e', &edit_flag },
+	{ OPTION_NONE, "include", 'i', &also },
+	{ OPTION_NONE, "interactive", 0, &interactive },
+	{ OPTION_NONE, "only", 'o', &only },
+	{ OPTION_STRING, "message", 'm', &message },
+	{ OPTION_NONE, "no-verify", 'n', &no_verify },
+	{ OPTION_NONE, "amend", 0, &amend },
+	{ OPTION_STRING, "reedit-message", 'c', &edit_message },
+	{ OPTION_STRING, "reuse-message", 'C', &use_message },
+	{ OPTION_NONE, "signoff", 's', &signoff },
+	{ OPTION_NONE, "quiet", 'q', &quiet },
+	{ OPTION_NONE, "verbose", 'v', &verbose },
+	{ OPTION_NONE, "untracked-files", 0, &untracked_files },
+	{ OPTION_STRING, "template", 't', &template_file },
+	{ OPTION_LAST },
+};
+
+/* FIXME: Taken from builtin-add, should be shared. */
+
+static void update_callback(struct diff_queue_struct *q,
+			    struct diff_options *opt, void *cbdata)
+{
+	int i, verbose;
+
+	verbose = *((int *)cbdata);
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		const char *path = p->one->path;
+		switch (p->status) {
+		default:
+			die("unexpacted diff status %c", p->status);
+		case DIFF_STATUS_UNMERGED:
+		case DIFF_STATUS_MODIFIED:
+		case DIFF_STATUS_TYPE_CHANGED:
+			add_file_to_cache(path, verbose);
+			break;
+		case DIFF_STATUS_DELETED:
+			remove_file_from_cache(path);
+			cache_tree_invalidate_path(active_cache_tree, path);
+			if (verbose)
+				printf("remove '%s'\n", path);
+			break;
+		}
+	}
+}
+
+static void
+add_files_to_cache(int fd, const char **files, const char *prefix)
+{
+	struct rev_info rev;
+
+	init_revisions(&rev, "");
+	setup_revisions(0, NULL, &rev, NULL);
+	rev.prune_data = get_pathspec(prefix, files);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = update_callback;
+	rev.diffopt.format_callback_data = &verbose;
+
+	run_diff_files(&rev, 0);
+	refresh_cache(REFRESH_QUIET);
+
+	if (write_cache(fd, active_cache, active_nr) || close(fd))
+		die("unable to write new index file");
+}
+
+static char *
+prepare_index(const char **files, const char *prefix)
+{
+	int fd;
+	struct tree *tree;
+	struct lock_file *next_index_lock;
+
+	fd = hold_locked_index(&lock_file, 1);
+	if (read_cache() < 0)
+		die("index file corrupt");
+
+	if (all) {
+		add_files_to_cache(fd, files, NULL);
+		return lock_file.filename;
+	} else if (also) {
+		add_files_to_cache(fd, files, prefix);
+		return lock_file.filename;
+	}
+
+	if (interactive)
+		interactive_add();
+
+	if (*files == NULL) {
+		/* Commit index as-is. */
+		rollback_lock_file(&lock_file);
+		return get_index_file();
+	}
+
+	/*
+	 * FIXME: Warn on unknown files.  Shell script does
+	 *
+	 *   commit_only=`git-ls-files --error-unmatch -- "$@"`
+	 */
+
+	/*
+	 * FIXME: shell script does
+	 *
+	 *   git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
+	 *
+	 * which warns about unmerged files in the index.
+	 */
+
+	/* update the user index file */
+	add_files_to_cache(fd, files, prefix);
+
+	if (!initial_commit) {
+		tree = parse_tree_indirect(head_sha1);
+		if (!tree)
+			die("failed to unpack HEAD tree object");
+		if (read_tree(tree, 0, NULL))
+			die("failed to read HEAD tree object");
+	}
+
+	/* Uh oh, abusing lock_file to create a garbage collected file */
+	next_index_lock = xmalloc(sizeof(*next_index_lock));
+	fd = hold_lock_file_for_update(next_index_lock,
+				       git_path("next-index-%d", getpid()), 1);
+	add_files_to_cache(fd, files, prefix);
+
+	return next_index_lock->filename;
+}
+
+static int run_status(FILE *fp, const char *index_file)
+{
+	struct wt_status s;
+
+	wt_status_prepare(&s);
+
+	if (amend) {
+		s.amend = 1;
+		s.reference = "HEAD^1";
+	}
+	s.verbose = verbose;
+	s.untracked = untracked_files;
+	s.index_file = index_file;
+	s.fp = fp;
+
+	wt_status_print(&s);
+
+	return s.commitable;
+}
+
+static const char sign_off_header[] = "Signed-off-by: ";
+
+static int prepare_log_message(const char *index_file)
+{
+	struct stat statbuf;
+	int commitable;
+	struct strbuf sb;
+	char *buffer;
+	FILE *fp;
+
+	strbuf_init(&sb);
+	if (message) {
+		strbuf_add(&sb, message, strlen(message));
+	} else if (logfile && !strcmp(logfile, "-")) {
+		if (isatty(0))
+			fprintf(stderr, "(reading log message from standard input)\n");
+		if (strbuf_read_fd(&sb, 0) < 0)
+			die("could not read log from standard input");
+	} else if (logfile) {
+		if (strbuf_read_path(&sb, logfile) < 0)
+			die("could not read log file '%s': %s",
+			    logfile, strerror(errno));
+	} else if (use_message) {
+		buffer = strstr(use_message_buffer, "\n\n");
+		if (!buffer || buffer[2] == '\0')
+			die("commit has empty message");
+		strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
+	} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
+		if (strbuf_read_path(&sb, git_path("MERGE_MSG")) < 0)
+			die("could not read MERGE_MSG: %s", strerror(errno));
+	} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
+		if (strbuf_read_path(&sb, git_path("SQUASH_MSG")) < 0)
+			die("could not read SQUASH_MSG: %s", strerror(errno));
+	} else if (!stat(template_file, &statbuf)) {
+		if (strbuf_read_path(&sb, template_file) < 0)
+			die("could not read %s: %s",
+			    template_file, strerror(errno));
+	}
+
+	fp = fopen(git_path(commit_editmsg), "w");
+	if (fp == NULL)
+		die("could not open %s\n", git_path(commit_editmsg));
+		
+	stripspace(&sb, 0);
+	if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
+		die("could not write commit template: %s\n",
+		    strerror(errno));
+
+	if (signoff) {
+		const char *info, *bol;
+
+		info = git_committer_info(1);
+		strbuf_add_char(&sb, '\0');
+		bol = strrchr(sb.buf + sb.len - 1, '\n');
+		if (!bol || prefixcmp(bol, sign_off_header))
+			fprintf(fp, "\n");
+		fprintf(fp, "Signed-off-by: %s\n", git_committer_info(1));
+	}
+
+	strbuf_release(&sb);
+
+	if (in_merge && !no_edit) {
+		fprintf(fp,
+			"#\n"
+			"# It looks like you may be committing a MERGE.\n"
+			"# If this is not correct, please remove the file\n"
+			"#	%s\n"
+			"# and try again.\n"
+			"#\n",
+			git_path("MERGE_HEAD"));
+	}
+
+	fprintf(fp,
+		"\n"
+		"# Please enter the commit message for your changes.\n"
+		"# (Comment lines starting with '#' will not be included)\n");
+	if (only_include_assumed)
+		fprintf(fp, "# %s\n", only_include_assumed);
+
+	commitable = run_status(fp, index_file);
+
+	fclose(fp);
+
+	return commitable;
+}
+
+/* Find out if the message starting at position 'start' in the strbuf
+ * contains only whitespace and Signed-off-by lines. */
+static int message_is_empty(struct strbuf *sb, int start)
+{
+	static const char signed_off_by[] = "Signed-off-by: ";
+	struct strbuf tmpl;
+	const char *nl;
+	int eol, i;
+
+	/* See if the template is just a prefix of the message. */
+	strbuf_init(&tmpl);
+	if (template_file && strbuf_read_path(&tmpl, template_file) > 0) {
+		stripspace(&tmpl, 1);
+		if (start + tmpl.len <= sb->len &&
+		    memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
+			start += tmpl.len;
+	}
+	strbuf_release(&tmpl);
+
+	/* Check if the rest is just whitespace and Signed-of-by's. */
+	for (i = start; i < sb->len; i++) {
+		nl = memchr(sb->buf + i, '\n', sb->len - i);
+		if (nl)
+			eol = nl - sb->buf;
+		else
+			eol = sb->len;
+
+		if (strlen(signed_off_by) <= eol - i &&
+		    !prefixcmp(sb->buf + i, signed_off_by)) {
+			i = eol;
+			continue;
+		}
+		while (i < eol)
+			if (!isspace(sb->buf[i++]))
+				return 0;
+	}
+
+	return 1;
+}
+
+static void determine_author_info(struct strbuf *sb)
+{
+	char *p, *eol;
+	char *name = NULL, *email = NULL;
+
+	if (use_message) {
+		p = strstr(use_message_buffer, "\nauthor");
+		if (!p)
+			die("invalid commit: %s\n", use_message);
+		p++;
+		eol = strchr(p, '\n');
+		if (!eol)
+			die("invalid commit: %s\n", use_message);
+
+		strbuf_add(sb, p, eol + 1 - p);
+	} else if (force_author) {
+		const char *eoname = strstr(force_author, " <");
+		const char *eomail = strchr(force_author, '>');
+
+		if (!eoname || !eomail)
+			die("malformed --author parameter\n");
+		name = xstrndup(force_author, eoname - force_author);
+		email = xstrndup(eoname + 2, eomail - eoname - 2);
+		strbuf_printf(sb, "author %s\n",
+			      fmt_ident(name, email, 
+					getenv("GIT_AUTHOR_DATE"), 1));
+		free(name);
+		free(email);
+	} else {
+		strbuf_printf(sb, "author %s\n", git_author_info(1));
+	}
+}
+
+static void parse_and_validate_options(const char ***argv)
+{
+	int f = 0;
+
+	(*argv)++;
+	while (scan_options(argv, commit_options))
+		;
+
+	if (logfile || message || use_message)
+		no_edit = 1;
+	if (edit_flag)
+		no_edit = 0;
+
+	if (get_sha1("HEAD", head_sha1))
+		initial_commit = 1;
+
+	if (!get_sha1("MERGE_HEAD", merge_head_sha1))
+		in_merge = 1;
+
+	/* Sanity check options */
+	if (amend && initial_commit)
+		die("You have nothing to amend.");
+	if (amend && in_merge)
+		die("You are in the middle of a merger -- cannot amend.");
+
+	if (use_message)
+		f++;
+	if (edit_message)
+		f++;
+	if (logfile)
+		f++;
+	if (f > 1)
+		die("Only one of -c/-C/-F can be used.");
+	if (message && f > 0)
+		die("Option -m cannot be combined with -c/-C/-F.");
+	if (edit_message)
+		use_message = edit_message;
+	if (amend)
+		use_message = "HEAD";
+	if (use_message) {
+		unsigned char sha1[20];
+		static char utf8[] = "UTF-8";
+		char *enc, *end, *out_enc;
+		struct commit *commit;
+
+		if (get_sha1(use_message, sha1))
+			die("could not lookup commit %s", use_message);
+		commit = lookup_commit(sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse commit %s", use_message);
+
+		enc = strstr(commit->buffer, "\nencoding");
+		if (enc) {
+			end = strchr(enc + 10, '\n');
+			enc = xstrndup(enc + 10, end - (enc + 10));
+		} else {
+			enc = utf8;
+		}
+		out_enc = git_commit_encoding ? git_commit_encoding : utf8;
+
+		use_message_buffer =
+			reencode_string(commit->buffer, out_enc, enc);
+		if (enc != utf8)
+			free(enc);
+	}
+
+	if (also && only)
+		die("Only one of --include/--only can be used.");
+	if (!*argv && (also || (only && !amend)))
+		die("No paths with --include/--only does not make sense.");
+	if (!*argv && only && amend)
+		only_include_assumed = "Clever... amending the last one with dirty index.";
+	if (*argv && !also && !only) {
+		only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
+		also = 0;
+	}
+
+	if (all && interactive)
+		die("Cannot use -a, --interactive or -i at the same time.");
+	else if (all && **argv)
+		die("Paths with -a does not make sense.");
+	else if (interactive && **argv)
+		die("Paths with --interactive does not make sense.");
+}
+
+int cmd_status(int argc, const char **argv, const char *prefix)
+{
+	const char *index_file;
+	int commitable;
+
+	git_config(git_status_config);
+
+	parse_and_validate_options(&argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	commitable = run_status(stdout, index_file);
+
+	rollback_lock_file(&lock_file);
+
+	return commitable ? 0 : 1;
+}
+
+static int run_hook(const char *index_file, const char *name, const char *arg)
+{
+	struct child_process hook;
+	const char *argv[3], *env[2];
+	char index[PATH_MAX];
+
+	argv[0] = git_path("hooks/%s", name);
+	argv[1] = arg;
+	argv[2] = NULL;
+	snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+	env[0] = index;
+	env[1] = NULL;
+
+	if (access(argv[0], X_OK) < 0)
+		return 0;
+
+	memset(&hook, 0, sizeof(hook));
+	hook.argv = argv;
+	hook.no_stdin = 1;
+	hook.stdout_to_stderr = 1;
+	hook.env = env;
+
+	return run_command(&hook);
+}
+
+static void print_summary(const char *prefix, const unsigned char *sha1)
+{
+	struct rev_info rev;
+	struct commit *commit;
+
+	commit = lookup_commit(sha1);
+	if (!commit)
+		die("couldn't look up newly created commit\n");
+	if (!commit || parse_commit(commit))
+		die("could not parse newly created commit");
+
+	init_revisions(&rev, prefix);
+	setup_revisions(0, NULL, &rev, NULL);
+
+	rev.abbrev = 0;
+	rev.diff = 1;
+	rev.diffopt.output_format =
+		DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
+
+	rev.verbose_header = 1;
+	rev.show_root_diff = 1;
+	rev.commit_format = get_commit_format("format:%h: %s");
+	rev.always_show_header = 1;
+		
+	printf("Created %scommit ", initial_commit ? "initial " : "");
+
+	log_tree_commit(&rev, commit);
+}
+
+int git_commit_config(const char *k, const char *v)
+{
+	if (!strcmp(k, "commit.template")) {
+		template_file = xstrdup(v);
+		return 0;
+	}
+
+	return git_status_config(k, v);
+}
+
+static const char commit_utf8_warn[] =
+"Warning: commit message does not conform to UTF-8.\n"
+"You may want to amend it after fixing the message, or set the config\n"
+"variable i18n.commitencoding to the encoding your project uses.\n";
+
+int cmd_commit(int argc, const char **argv, const char *prefix)
+{
+	int header_len, parent_count = 0;
+	struct strbuf sb;
+	const char *index_file, *reflog_msg;
+	char *nl, *header_line;
+	unsigned char commit_sha1[20];
+	struct ref_lock *ref_lock;
+
+	git_config(git_commit_config);
+
+	parse_and_validate_options(&argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	if (run_hook(index_file, "pre-commit", NULL))
+		exit(1);
+
+	if (!prepare_log_message(index_file)) {
+		run_status(stdout, index_file);
+		unlink(commit_editmsg);
+		return 1;
+	}
+
+	strbuf_init(&sb);
+
+	/* Start building up the commit header */
+	read_cache_from(index_file);
+	active_cache_tree = cache_tree();
+	if (cache_tree_update(active_cache_tree,
+			      active_cache, active_nr, 0, 0) < 0)
+		die("Error building trees");
+	strbuf_printf(&sb, "tree %s\n",
+		      sha1_to_hex(active_cache_tree->sha1));
+
+	/* Determine parents */
+	if (initial_commit) {
+		reflog_msg = "commit (initial)"; 
+		parent_count = 0;
+	} else if (amend) {
+		struct commit_list *c;
+		struct commit *commit;
+
+		reflog_msg = "commit (amend)";
+		commit = lookup_commit(head_sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse HEAD commit");
+
+		for (c = commit->parents; c; c = c->next)
+			strbuf_printf(&sb, "parent %s\n",
+				      sha1_to_hex(c->item->object.sha1));
+	} else if (in_merge) {
+		struct strbuf m;
+		FILE *fp;
+
+		reflog_msg = "commit (merge)";
+		strbuf_printf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+		strbuf_init(&m);
+		fp = fopen(git_path("MERGE_HEAD"), "r");
+		if (fp == NULL)
+			die("could not open %s for reading: %s",
+			    git_path("MERGE_HEAD"), strerror(errno));
+		while (!m.eof) {
+			read_line(&m, fp, '\n');
+			if (!m.eof)
+				strbuf_printf(&sb, "parent %s\n", m.buf);
+		}
+		fclose(fp);
+		strbuf_release(&m);
+	} else {
+		reflog_msg = "commit";
+		strbuf_printf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+	}
+
+	determine_author_info(&sb);
+	strbuf_printf(&sb, "committer %s\n", git_committer_info(1));
+	if (!is_encoding_utf8(git_commit_encoding))
+		strbuf_printf(&sb, "encoding %s\n", git_commit_encoding);
+	strbuf_add_char(&sb, '\n');
+
+	/* Get the commit message and validate it */
+	header_len = sb.len;
+	if (!no_edit) {
+		fprintf(stderr, "launching editor, log %s\n", logfile);
+		launch_editor(git_path(commit_editmsg), &sb);
+	}
+	else if (strbuf_read_path(&sb, git_path(commit_editmsg)) < 0)
+		die("could not read commit message\n");
+	if (run_hook(index_file, "commit-msg", commit_editmsg))
+		exit(1);
+	if (stripspace(&sb, 1) < header_len ||
+	    message_is_empty(&sb, header_len))
+		die("* no commit message?  aborting commit.");
+	strbuf_add_char(&sb, '\0');
+	if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf))
+		fprintf(stderr, commit_utf8_warn);
+
+	if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1))
+		die("failed to write commit object");
+		       
+	ref_lock = lock_any_ref_for_update("HEAD",
+					   initial_commit ? NULL : head_sha1,
+					   0);
+
+	nl = strchr(sb.buf + header_len, '\n');
+	header_line = xstrndup(sb.buf + header_len,
+			       nl - (sb.buf + header_len));
+	strbuf_release(&sb);
+	strbuf_printf(&sb, "%s: %s\n", reflog_msg, header_line);
+	strbuf_add_char(&sb, '\0');
+	free(header_line);
+
+	if (!ref_lock)
+		die("cannot lock HEAD ref");
+	if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0)
+		die("cannot update HEAD ref");
+
+	unlink(git_path("MERGE_HEAD"));
+	unlink(git_path("MERGE_MSG"));
+
+	if (lock_file.filename[0] && commit_locked_index(&lock_file))
+		die("failed to write new index");
+
+	rerere();
+
+	run_hook(index_file, "post-commit", NULL);
+
+	if (!quiet)
+		print_summary(prefix, commit_sha1);
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index 91bc595..c23cd6d 100644
--- a/builtin.h
+++ b/builtin.h
@@ -23,6 +23,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
+extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_describe(int argc, const char **argv, const char *prefix);
@@ -63,10 +64,10 @@ extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
 extern int cmd_revert(int argc, const char **argv, const char *prefix);
 extern int cmd_rm(int argc, const char **argv, const char *prefix);
-extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
 extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_status(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_tag(int argc, const char **argv, const char *prefix);
diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh
new file mode 100755
index 0000000..d7e7028
--- /dev/null
+++ b/contrib/examples/git-commit.sh
@@ -0,0 +1,665 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+# Copyright (c) 2006 Junio C Hamano
+
+USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+require_work_tree
+
+git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
+
+case "$0" in
+*status)
+	status_only=t
+	;;
+*commit)
+	status_only=
+	;;
+esac
+
+refuse_partial () {
+	echo >&2 "$1"
+	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
+	exit 1
+}
+
+THIS_INDEX="$GIT_DIR/index"
+NEXT_INDEX="$GIT_DIR/next-index$$"
+rm -f "$NEXT_INDEX"
+save_index () {
+	cp -p "$THIS_INDEX" "$NEXT_INDEX"
+}
+
+run_status () {
+	# If TMP_INDEX is defined, that means we are doing
+	# "--only" partial commit, and that index file is used
+	# to build the tree for the commit.  Otherwise, if
+	# NEXT_INDEX exists, that is the index file used to
+	# make the commit.  Otherwise we are using as-is commit
+	# so the regular index file is what we use to compare.
+	if test '' != "$TMP_INDEX"
+	then
+		GIT_INDEX_FILE="$TMP_INDEX"
+		export GIT_INDEX_FILE
+	elif test -f "$NEXT_INDEX"
+	then
+		GIT_INDEX_FILE="$NEXT_INDEX"
+		export GIT_INDEX_FILE
+	fi
+
+	case "$status_only" in
+	t) color= ;;
+	*) color=--nocolor ;;
+	esac
+	git runstatus ${color} \
+		${verbose:+--verbose} \
+		${amend:+--amend} \
+		${untracked_files:+--untracked}
+}
+
+trap '
+	test -z "$TMP_INDEX" || {
+		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
+	}
+	rm -f "$NEXT_INDEX"
+' 0
+
+################################################################
+# Command line argument parsing and sanity checking
+
+all=
+also=
+interactive=
+only=
+logfile=
+use_commit=
+amend=
+edit_flag=
+no_edit=
+log_given=
+log_message=
+verify=t
+quiet=
+verbose=
+signoff=
+force_author=
+only_include_assumed=
+untracked_files=
+templatefile="`git config commit.template`"
+while case "$#" in 0) break;; esac
+do
+	case "$1" in
+	-F|--F|-f|--f|--fi|--fil|--file)
+		case "$#" in 1) usage ;; esac
+		shift
+		no_edit=t
+		log_given=t$log_given
+		logfile="$1"
+		shift
+		;;
+	-F*|-f*)
+		no_edit=t
+		log_given=t$log_given
+		logfile=`expr "z$1" : 'z-[Ff]\(.*\)'`
+		shift
+		;;
+	--F=*|--f=*|--fi=*|--fil=*|--file=*)
+		no_edit=t
+		log_given=t$log_given
+		logfile=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		shift
+		;;
+	-a|--a|--al|--all)
+		all=t
+		shift
+		;;
+	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
+		force_author=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		shift
+		;;
+	--au|--aut|--auth|--autho|--author)
+		case "$#" in 1) usage ;; esac
+		shift
+		force_author="$1"
+		shift
+		;;
+	-e|--e|--ed|--edi|--edit)
+		edit_flag=t
+		shift
+		;;
+	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
+		also=t
+		shift
+		;;
+	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
+	--interactiv|--interactive)
+		interactive=t
+		shift
+		;;
+	-o|--o|--on|--onl|--only)
+		only=t
+		shift
+		;;
+	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=m$log_given
+		if test "$log_message" = ''
+		then
+		    log_message="$1"
+		else
+		    log_message="$log_message
+
+$1"
+		fi
+		no_edit=t
+		shift
+		;;
+	-m*)
+		log_given=m$log_given
+		if test "$log_message" = ''
+		then
+		    log_message=`expr "z$1" : 'z-m\(.*\)'`
+		else
+		    log_message="$log_message
+
+`expr "z$1" : 'z-m\(.*\)'`"
+		fi
+		no_edit=t
+		shift
+		;;
+	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
+		log_given=m$log_given
+		if test "$log_message" = ''
+		then
+		    log_message=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		else
+		    log_message="$log_message
+
+`expr "z$1" : 'zq-[^=]*=\(.*\)'`"
+		fi
+		no_edit=t
+		shift
+		;;
+	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
+	--no-verify)
+		verify=
+		shift
+		;;
+	--a|--am|--ame|--amen|--amend)
+		amend=t
+		use_commit=HEAD
+		shift
+		;;
+	-c)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		shift
+		;;
+	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
+	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
+	--reedit-messag=*|--reedit-message=*)
+		log_given=t$log_given
+		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		no_edit=
+		shift
+		;;
+	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
+	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
+	--reedit-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		shift
+		;;
+	-C)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		shift
+		;;
+	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
+	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
+	--reuse-message=*)
+		log_given=t$log_given
+		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		no_edit=t
+		shift
+		;;
+	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
+	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		shift
+		;;
+	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
+		signoff=t
+		shift
+		;;
+	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
+		case "$#" in 1) usage ;; esac
+		shift
+		templatefile="$1"
+		no_edit=
+		shift
+		;;
+	-q|--q|--qu|--qui|--quie|--quiet)
+		quiet=t
+		shift
+		;;
+	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
+		verbose=t
+		shift
+		;;
+	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
+	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
+	--untracked-file|--untracked-files)
+		untracked_files=t
+		shift
+		;;
+	--)
+		shift
+		break
+		;;
+	-*)
+		usage
+		;;
+	*)
+		break
+		;;
+	esac
+done
+case "$edit_flag" in t) no_edit= ;; esac
+
+################################################################
+# Sanity check options
+
+case "$amend,$initial_commit" in
+t,t)
+	die "You do not have anything to amend." ;;
+t,)
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		die "You are in the middle of a merge -- cannot amend."
+	fi ;;
+esac
+
+case "$log_given" in
+tt*)
+	die "Only one of -c/-C/-F can be used." ;;
+*tm*|*mt*)
+	die "Option -m cannot be combined with -c/-C/-F." ;;
+esac
+
+case "$#,$also,$only,$amend" in
+*,t,t,*)
+	die "Only one of --include/--only can be used." ;;
+0,t,,* | 0,,t,)
+	die "No paths with --include/--only does not make sense." ;;
+0,,t,t)
+	only_include_assumed="# Clever... amending the last one with dirty index." ;;
+0,,,*)
+	;;
+*,,,*)
+	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
+	also=
+	;;
+esac
+unset only
+case "$all,$interactive,$also,$#" in
+*t,*t,*)
+	die "Cannot use -a, --interactive or -i at the same time." ;;
+t,,[1-9]*)
+	die "Paths with -a does not make sense." ;;
+,t,[1-9]*)
+	die "Paths with --interactive does not make sense." ;;
+,,t,0)
+	die "No paths with -i does not make sense." ;;
+esac
+
+if test ! -z "$templatefile" -a -z "$log_given"
+then
+	if test ! -f "$templatefile"
+	then
+		die "Commit template file does not exist."
+	fi
+fi
+
+################################################################
+# Prepare index to have a tree to be committed
+
+case "$all,$also" in
+t,)
+	if test ! -f "$THIS_INDEX"
+	then
+		die 'nothing to commit (use "git add file1 file2" to include for commit)'
+	fi
+	save_index &&
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git diff-files --name-only -z |
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,t)
+	save_index &&
+	git ls-files --error-unmatch -- "$@" >/dev/null || exit
+
+	git diff-files --name-only -z -- "$@"  |
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,)
+	if test "$interactive" = t; then
+		git add --interactive || exit
+	fi
+	case "$#" in
+	0)
+		;; # commit as-is
+	*)
+		if test -f "$GIT_DIR/MERGE_HEAD"
+		then
+			refuse_partial "Cannot do a partial commit during a merge."
+		fi
+		TMP_INDEX="$GIT_DIR/tmp-index$$"
+		commit_only=`git ls-files --error-unmatch -- "$@"` || exit
+
+		# Build a temporary index and update the real index
+		# the same way.
+		if test -z "$initial_commit"
+		then
+			GIT_INDEX_FILE="$THIS_INDEX" \
+			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
+		else
+			rm -f "$TMP_INDEX"
+		fi || exit
+
+		printf '%s\n' "$commit_only" |
+		GIT_INDEX_FILE="$TMP_INDEX" \
+		git update-index --add --remove --stdin &&
+
+		save_index &&
+		printf '%s\n' "$commit_only" |
+		(
+			GIT_INDEX_FILE="$NEXT_INDEX"
+			export GIT_INDEX_FILE
+			git update-index --remove --stdin
+		) || exit
+		;;
+	esac
+	;;
+esac
+
+################################################################
+# If we do as-is commit, the index file will be THIS_INDEX,
+# otherwise NEXT_INDEX after we make this commit.  We leave
+# the index as is if we abort.
+
+if test -f "$NEXT_INDEX"
+then
+	USE_INDEX="$NEXT_INDEX"
+else
+	USE_INDEX="$THIS_INDEX"
+fi
+
+case "$status_only" in
+t)
+	# This will silently fail in a read-only repository, which is
+	# what we want.
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
+	run_status
+	exit $?
+	;;
+'')
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
+	;;
+esac
+
+################################################################
+# Grab commit message, write out tree and make commit.
+
+if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
+then
+	if test "$TMP_INDEX"
+	then
+		GIT_INDEX_FILE="$TMP_INDEX" "$GIT_DIR"/hooks/pre-commit
+	else
+		GIT_INDEX_FILE="$USE_INDEX" "$GIT_DIR"/hooks/pre-commit
+	fi || exit
+fi
+
+if test "$log_message" != ''
+then
+	printf '%s\n' "$log_message"
+elif test "$logfile" != ""
+then
+	if test "$logfile" = -
+	then
+		test -t 0 &&
+		echo >&2 "(reading log message from standard input)"
+		cat
+	else
+		cat <"$logfile"
+	fi
+elif test "$use_commit" != ""
+then
+	encoding=$(git config i18n.commitencoding || echo UTF-8)
+	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
+	sed -e '1,/^$/d' -e 's/^    //'
+elif test -f "$GIT_DIR/MERGE_MSG"
+then
+	cat "$GIT_DIR/MERGE_MSG"
+elif test -f "$GIT_DIR/SQUASH_MSG"
+then
+	cat "$GIT_DIR/SQUASH_MSG"
+elif test "$templatefile" != ""
+then
+	cat "$templatefile"
+fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
+
+case "$signoff" in
+t)
+	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
+		s/>.*/>/
+		s/^/Signed-off-by: /
+		')
+	blank_before_signoff=
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
+'
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep "$sign"$ >/dev/null ||
+	printf '%s%s\n' "$blank_before_signoff" "$sign" \
+		>>"$GIT_DIR"/COMMIT_EDITMSG
+	;;
+esac
+
+if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
+	echo "#"
+	echo "# It looks like you may be committing a MERGE."
+	echo "# If this is not correct, please remove the file"
+	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
+	echo "# and try again"
+	echo "#"
+fi >>"$GIT_DIR"/COMMIT_EDITMSG
+
+# Author
+if test '' != "$use_commit"
+then
+	eval "$(get_author_ident_from_commit "$use_commit")"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+fi
+if test '' != "$force_author"
+then
+	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
+	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
+	test '' != "$GIT_AUTHOR_NAME" &&
+	test '' != "$GIT_AUTHOR_EMAIL" ||
+	die "malformed --author parameter"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
+fi
+
+PARENTS="-p HEAD"
+if test -z "$initial_commit"
+then
+	rloga='commit'
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		rloga='commit (merge)'
+		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
+	elif test -n "$amend"; then
+		rloga='commit (amend)'
+		PARENTS=$(git cat-file commit HEAD |
+			sed -n -e '/^$/q' -e 's/^parent /-p /p')
+	fi
+	current="$(git rev-parse --verify HEAD)"
+else
+	if [ -z "$(git ls-files)" ]; then
+		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
+		exit 1
+	fi
+	PARENTS=""
+	rloga='commit (initial)'
+	current=''
+fi
+set_reflog_action "$rloga"
+
+if test -z "$no_edit"
+then
+	{
+		echo ""
+		echo "# Please enter the commit message for your changes."
+		echo "# (Comment lines starting with '#' will not be included)"
+		test -z "$only_include_assumed" || echo "$only_include_assumed"
+		run_status
+	} >>"$GIT_DIR"/COMMIT_EDITMSG
+else
+	# we need to check if there is anything to commit
+	run_status >/dev/null
+fi
+if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" -a -z "$amend" ]
+then
+	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+	run_status
+	exit 1
+fi
+
+case "$no_edit" in
+'')
+	git-var GIT_AUTHOR_IDENT > /dev/null  || die
+	git-var GIT_COMMITTER_IDENT > /dev/null  || die
+	git_editor "$GIT_DIR/COMMIT_EDITMSG"
+	;;
+esac
+
+case "$verify" in
+t)
+	if test -x "$GIT_DIR"/hooks/commit-msg
+	then
+		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
+	fi
+esac
+
+if test -z "$no_edit"
+then
+    sed -e '
+        /^diff --git a\/.*/{
+	    s///
+	    q
+	}
+	/^#/d
+    ' "$GIT_DIR"/COMMIT_EDITMSG
+else
+    cat "$GIT_DIR"/COMMIT_EDITMSG
+fi |
+git stripspace >"$GIT_DIR"/COMMIT_MSG
+
+# Test whether the commit message has any content we didn't supply.
+have_commitmsg=
+grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
+	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
+
+# Is the commit message totally empty?
+if test -s "$GIT_DIR"/COMMIT_BAREMSG
+then
+	if test "$templatefile" != ""
+	then
+		# Test whether this is just the unaltered template.
+		if cnt=`sed -e '/^#/d' < "$templatefile" |
+			git stripspace |
+			diff "$GIT_DIR"/COMMIT_BAREMSG - |
+			wc -l` &&
+		   test 0 -lt $cnt
+		then
+			have_commitmsg=t
+		fi
+	else
+		# No template, so the content in the commit message must
+		# have come from the user.
+		have_commitmsg=t
+	fi
+fi
+
+rm -f "$GIT_DIR"/COMMIT_BAREMSG
+
+if test "$have_commitmsg" = "t"
+then
+	if test -z "$TMP_INDEX"
+	then
+		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
+	else
+		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
+		rm -f "$TMP_INDEX"
+	fi &&
+	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
+	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
+	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
+	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
+	if test -f "$NEXT_INDEX"
+	then
+		mv "$NEXT_INDEX" "$THIS_INDEX"
+	else
+		: ;# happy
+	fi
+else
+	echo >&2 "* no commit message?  aborting commit."
+	false
+fi
+ret="$?"
+rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+
+cd_to_toplevel
+
+git rerere
+
+if test "$ret" = 0
+then
+	if test -x "$GIT_DIR"/hooks/post-commit
+	then
+		"$GIT_DIR"/hooks/post-commit
+	fi
+	if test -z "$quiet"
+	then
+		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
+		       --summary --root HEAD --`
+		echo "Created${initial_commit:+ initial} commit $commit"
+	fi
+fi
+
+exit "$ret"
diff --git a/git-commit.sh b/git-commit.sh
deleted file mode 100755
index d7e7028..0000000
--- a/git-commit.sh
+++ /dev/null
@@ -1,665 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Linus Torvalds
-# Copyright (c) 2006 Junio C Hamano
-
-USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
-SUBDIRECTORY_OK=Yes
-. git-sh-setup
-require_work_tree
-
-git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
-
-case "$0" in
-*status)
-	status_only=t
-	;;
-*commit)
-	status_only=
-	;;
-esac
-
-refuse_partial () {
-	echo >&2 "$1"
-	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
-	exit 1
-}
-
-THIS_INDEX="$GIT_DIR/index"
-NEXT_INDEX="$GIT_DIR/next-index$$"
-rm -f "$NEXT_INDEX"
-save_index () {
-	cp -p "$THIS_INDEX" "$NEXT_INDEX"
-}
-
-run_status () {
-	# If TMP_INDEX is defined, that means we are doing
-	# "--only" partial commit, and that index file is used
-	# to build the tree for the commit.  Otherwise, if
-	# NEXT_INDEX exists, that is the index file used to
-	# make the commit.  Otherwise we are using as-is commit
-	# so the regular index file is what we use to compare.
-	if test '' != "$TMP_INDEX"
-	then
-		GIT_INDEX_FILE="$TMP_INDEX"
-		export GIT_INDEX_FILE
-	elif test -f "$NEXT_INDEX"
-	then
-		GIT_INDEX_FILE="$NEXT_INDEX"
-		export GIT_INDEX_FILE
-	fi
-
-	case "$status_only" in
-	t) color= ;;
-	*) color=--nocolor ;;
-	esac
-	git runstatus ${color} \
-		${verbose:+--verbose} \
-		${amend:+--amend} \
-		${untracked_files:+--untracked}
-}
-
-trap '
-	test -z "$TMP_INDEX" || {
-		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
-	}
-	rm -f "$NEXT_INDEX"
-' 0
-
-################################################################
-# Command line argument parsing and sanity checking
-
-all=
-also=
-interactive=
-only=
-logfile=
-use_commit=
-amend=
-edit_flag=
-no_edit=
-log_given=
-log_message=
-verify=t
-quiet=
-verbose=
-signoff=
-force_author=
-only_include_assumed=
-untracked_files=
-templatefile="`git config commit.template`"
-while case "$#" in 0) break;; esac
-do
-	case "$1" in
-	-F|--F|-f|--f|--fi|--fil|--file)
-		case "$#" in 1) usage ;; esac
-		shift
-		no_edit=t
-		log_given=t$log_given
-		logfile="$1"
-		shift
-		;;
-	-F*|-f*)
-		no_edit=t
-		log_given=t$log_given
-		logfile=`expr "z$1" : 'z-[Ff]\(.*\)'`
-		shift
-		;;
-	--F=*|--f=*|--fi=*|--fil=*|--file=*)
-		no_edit=t
-		log_given=t$log_given
-		logfile=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		shift
-		;;
-	-a|--a|--al|--all)
-		all=t
-		shift
-		;;
-	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
-		force_author=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		shift
-		;;
-	--au|--aut|--auth|--autho|--author)
-		case "$#" in 1) usage ;; esac
-		shift
-		force_author="$1"
-		shift
-		;;
-	-e|--e|--ed|--edi|--edit)
-		edit_flag=t
-		shift
-		;;
-	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
-		also=t
-		shift
-		;;
-	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
-	--interactiv|--interactive)
-		interactive=t
-		shift
-		;;
-	-o|--o|--on|--onl|--only)
-		only=t
-		shift
-		;;
-	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=m$log_given
-		if test "$log_message" = ''
-		then
-		    log_message="$1"
-		else
-		    log_message="$log_message
-
-$1"
-		fi
-		no_edit=t
-		shift
-		;;
-	-m*)
-		log_given=m$log_given
-		if test "$log_message" = ''
-		then
-		    log_message=`expr "z$1" : 'z-m\(.*\)'`
-		else
-		    log_message="$log_message
-
-`expr "z$1" : 'z-m\(.*\)'`"
-		fi
-		no_edit=t
-		shift
-		;;
-	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-		log_given=m$log_given
-		if test "$log_message" = ''
-		then
-		    log_message=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		else
-		    log_message="$log_message
-
-`expr "z$1" : 'zq-[^=]*=\(.*\)'`"
-		fi
-		no_edit=t
-		shift
-		;;
-	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
-	--no-verify)
-		verify=
-		shift
-		;;
-	--a|--am|--ame|--amen|--amend)
-		amend=t
-		use_commit=HEAD
-		shift
-		;;
-	-c)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		shift
-		;;
-	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
-	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
-	--reedit-messag=*|--reedit-message=*)
-		log_given=t$log_given
-		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		no_edit=
-		shift
-		;;
-	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
-	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
-	--reedit-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		shift
-		;;
-	-C)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		shift
-		;;
-	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
-	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
-	--reuse-message=*)
-		log_given=t$log_given
-		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		no_edit=t
-		shift
-		;;
-	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
-	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		shift
-		;;
-	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
-		signoff=t
-		shift
-		;;
-	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
-		case "$#" in 1) usage ;; esac
-		shift
-		templatefile="$1"
-		no_edit=
-		shift
-		;;
-	-q|--q|--qu|--qui|--quie|--quiet)
-		quiet=t
-		shift
-		;;
-	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
-		verbose=t
-		shift
-		;;
-	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
-	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
-	--untracked-file|--untracked-files)
-		untracked_files=t
-		shift
-		;;
-	--)
-		shift
-		break
-		;;
-	-*)
-		usage
-		;;
-	*)
-		break
-		;;
-	esac
-done
-case "$edit_flag" in t) no_edit= ;; esac
-
-################################################################
-# Sanity check options
-
-case "$amend,$initial_commit" in
-t,t)
-	die "You do not have anything to amend." ;;
-t,)
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		die "You are in the middle of a merge -- cannot amend."
-	fi ;;
-esac
-
-case "$log_given" in
-tt*)
-	die "Only one of -c/-C/-F can be used." ;;
-*tm*|*mt*)
-	die "Option -m cannot be combined with -c/-C/-F." ;;
-esac
-
-case "$#,$also,$only,$amend" in
-*,t,t,*)
-	die "Only one of --include/--only can be used." ;;
-0,t,,* | 0,,t,)
-	die "No paths with --include/--only does not make sense." ;;
-0,,t,t)
-	only_include_assumed="# Clever... amending the last one with dirty index." ;;
-0,,,*)
-	;;
-*,,,*)
-	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
-	also=
-	;;
-esac
-unset only
-case "$all,$interactive,$also,$#" in
-*t,*t,*)
-	die "Cannot use -a, --interactive or -i at the same time." ;;
-t,,[1-9]*)
-	die "Paths with -a does not make sense." ;;
-,t,[1-9]*)
-	die "Paths with --interactive does not make sense." ;;
-,,t,0)
-	die "No paths with -i does not make sense." ;;
-esac
-
-if test ! -z "$templatefile" -a -z "$log_given"
-then
-	if test ! -f "$templatefile"
-	then
-		die "Commit template file does not exist."
-	fi
-fi
-
-################################################################
-# Prepare index to have a tree to be committed
-
-case "$all,$also" in
-t,)
-	if test ! -f "$THIS_INDEX"
-	then
-		die 'nothing to commit (use "git add file1 file2" to include for commit)'
-	fi
-	save_index &&
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git diff-files --name-only -z |
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,t)
-	save_index &&
-	git ls-files --error-unmatch -- "$@" >/dev/null || exit
-
-	git diff-files --name-only -z -- "$@"  |
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,)
-	if test "$interactive" = t; then
-		git add --interactive || exit
-	fi
-	case "$#" in
-	0)
-		;; # commit as-is
-	*)
-		if test -f "$GIT_DIR/MERGE_HEAD"
-		then
-			refuse_partial "Cannot do a partial commit during a merge."
-		fi
-		TMP_INDEX="$GIT_DIR/tmp-index$$"
-		commit_only=`git ls-files --error-unmatch -- "$@"` || exit
-
-		# Build a temporary index and update the real index
-		# the same way.
-		if test -z "$initial_commit"
-		then
-			GIT_INDEX_FILE="$THIS_INDEX" \
-			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
-		else
-			rm -f "$TMP_INDEX"
-		fi || exit
-
-		printf '%s\n' "$commit_only" |
-		GIT_INDEX_FILE="$TMP_INDEX" \
-		git update-index --add --remove --stdin &&
-
-		save_index &&
-		printf '%s\n' "$commit_only" |
-		(
-			GIT_INDEX_FILE="$NEXT_INDEX"
-			export GIT_INDEX_FILE
-			git update-index --remove --stdin
-		) || exit
-		;;
-	esac
-	;;
-esac
-
-################################################################
-# If we do as-is commit, the index file will be THIS_INDEX,
-# otherwise NEXT_INDEX after we make this commit.  We leave
-# the index as is if we abort.
-
-if test -f "$NEXT_INDEX"
-then
-	USE_INDEX="$NEXT_INDEX"
-else
-	USE_INDEX="$THIS_INDEX"
-fi
-
-case "$status_only" in
-t)
-	# This will silently fail in a read-only repository, which is
-	# what we want.
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
-	run_status
-	exit $?
-	;;
-'')
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
-	;;
-esac
-
-################################################################
-# Grab commit message, write out tree and make commit.
-
-if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
-then
-	if test "$TMP_INDEX"
-	then
-		GIT_INDEX_FILE="$TMP_INDEX" "$GIT_DIR"/hooks/pre-commit
-	else
-		GIT_INDEX_FILE="$USE_INDEX" "$GIT_DIR"/hooks/pre-commit
-	fi || exit
-fi
-
-if test "$log_message" != ''
-then
-	printf '%s\n' "$log_message"
-elif test "$logfile" != ""
-then
-	if test "$logfile" = -
-	then
-		test -t 0 &&
-		echo >&2 "(reading log message from standard input)"
-		cat
-	else
-		cat <"$logfile"
-	fi
-elif test "$use_commit" != ""
-then
-	encoding=$(git config i18n.commitencoding || echo UTF-8)
-	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
-	sed -e '1,/^$/d' -e 's/^    //'
-elif test -f "$GIT_DIR/MERGE_MSG"
-then
-	cat "$GIT_DIR/MERGE_MSG"
-elif test -f "$GIT_DIR/SQUASH_MSG"
-then
-	cat "$GIT_DIR/SQUASH_MSG"
-elif test "$templatefile" != ""
-then
-	cat "$templatefile"
-fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
-
-case "$signoff" in
-t)
-	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
-		s/>.*/>/
-		s/^/Signed-off-by: /
-		')
-	blank_before_signoff=
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
-'
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep "$sign"$ >/dev/null ||
-	printf '%s%s\n' "$blank_before_signoff" "$sign" \
-		>>"$GIT_DIR"/COMMIT_EDITMSG
-	;;
-esac
-
-if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
-	echo "#"
-	echo "# It looks like you may be committing a MERGE."
-	echo "# If this is not correct, please remove the file"
-	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
-	echo "# and try again"
-	echo "#"
-fi >>"$GIT_DIR"/COMMIT_EDITMSG
-
-# Author
-if test '' != "$use_commit"
-then
-	eval "$(get_author_ident_from_commit "$use_commit")"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
-fi
-if test '' != "$force_author"
-then
-	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
-	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
-	test '' != "$GIT_AUTHOR_NAME" &&
-	test '' != "$GIT_AUTHOR_EMAIL" ||
-	die "malformed --author parameter"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
-fi
-
-PARENTS="-p HEAD"
-if test -z "$initial_commit"
-then
-	rloga='commit'
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		rloga='commit (merge)'
-		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
-	elif test -n "$amend"; then
-		rloga='commit (amend)'
-		PARENTS=$(git cat-file commit HEAD |
-			sed -n -e '/^$/q' -e 's/^parent /-p /p')
-	fi
-	current="$(git rev-parse --verify HEAD)"
-else
-	if [ -z "$(git ls-files)" ]; then
-		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
-		exit 1
-	fi
-	PARENTS=""
-	rloga='commit (initial)'
-	current=''
-fi
-set_reflog_action "$rloga"
-
-if test -z "$no_edit"
-then
-	{
-		echo ""
-		echo "# Please enter the commit message for your changes."
-		echo "# (Comment lines starting with '#' will not be included)"
-		test -z "$only_include_assumed" || echo "$only_include_assumed"
-		run_status
-	} >>"$GIT_DIR"/COMMIT_EDITMSG
-else
-	# we need to check if there is anything to commit
-	run_status >/dev/null
-fi
-if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" -a -z "$amend" ]
-then
-	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-	run_status
-	exit 1
-fi
-
-case "$no_edit" in
-'')
-	git-var GIT_AUTHOR_IDENT > /dev/null  || die
-	git-var GIT_COMMITTER_IDENT > /dev/null  || die
-	git_editor "$GIT_DIR/COMMIT_EDITMSG"
-	;;
-esac
-
-case "$verify" in
-t)
-	if test -x "$GIT_DIR"/hooks/commit-msg
-	then
-		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
-	fi
-esac
-
-if test -z "$no_edit"
-then
-    sed -e '
-        /^diff --git a\/.*/{
-	    s///
-	    q
-	}
-	/^#/d
-    ' "$GIT_DIR"/COMMIT_EDITMSG
-else
-    cat "$GIT_DIR"/COMMIT_EDITMSG
-fi |
-git stripspace >"$GIT_DIR"/COMMIT_MSG
-
-# Test whether the commit message has any content we didn't supply.
-have_commitmsg=
-grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
-	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
-
-# Is the commit message totally empty?
-if test -s "$GIT_DIR"/COMMIT_BAREMSG
-then
-	if test "$templatefile" != ""
-	then
-		# Test whether this is just the unaltered template.
-		if cnt=`sed -e '/^#/d' < "$templatefile" |
-			git stripspace |
-			diff "$GIT_DIR"/COMMIT_BAREMSG - |
-			wc -l` &&
-		   test 0 -lt $cnt
-		then
-			have_commitmsg=t
-		fi
-	else
-		# No template, so the content in the commit message must
-		# have come from the user.
-		have_commitmsg=t
-	fi
-fi
-
-rm -f "$GIT_DIR"/COMMIT_BAREMSG
-
-if test "$have_commitmsg" = "t"
-then
-	if test -z "$TMP_INDEX"
-	then
-		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
-	else
-		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
-		rm -f "$TMP_INDEX"
-	fi &&
-	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
-	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
-	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
-	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
-	if test -f "$NEXT_INDEX"
-	then
-		mv "$NEXT_INDEX" "$THIS_INDEX"
-	else
-		: ;# happy
-	fi
-else
-	echo >&2 "* no commit message?  aborting commit."
-	false
-fi
-ret="$?"
-rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-
-cd_to_toplevel
-
-git rerere
-
-if test "$ret" = 0
-then
-	if test -x "$GIT_DIR"/hooks/post-commit
-	then
-		"$GIT_DIR"/hooks/post-commit
-	fi
-	if test -z "$quiet"
-	then
-		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
-		       --summary --root HEAD --`
-		echo "Created${initial_commit:+ initial} commit $commit"
-	fi
-fi
-
-exit "$ret"
diff --git a/git.c b/git.c
index cab0e72..62859a2 100644
--- a/git.c
+++ b/git.c
@@ -321,6 +321,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
 		{ "cherry", cmd_cherry, RUN_SETUP },
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
+		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config },
 		{ "count-objects", cmd_count_objects, RUN_SETUP },
@@ -363,10 +364,10 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
 		{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
 		{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
-		{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
 		{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
+		{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 		{ "stripspace", cmd_stripspace },
 		{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 		{ "tag", cmd_tag, RUN_SETUP },
-- 
1.5.2.GIT

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf.
  2007-09-06  0:23   ` [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf Kristian Høgsberg
  2007-09-06  0:23     ` [PATCH 4/9] Introduce entry point for launching add--interactive Kristian Høgsberg
@ 2007-09-06  8:55     ` Junio C Hamano
  2007-09-06  9:43       ` Pierre Habouzit
  1 sibling, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2007-09-06  8:55 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git

As you noted in your follow-up message, this one has overlaps
with the other strbuf series.  I could adjust them if I wanted
to, but I do not have time for it right now.  I might try over
the weekend but no promises.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf.
  2007-09-06  8:55     ` [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf Junio C Hamano
@ 2007-09-06  9:43       ` Pierre Habouzit
  2007-09-06  9:50         ` Pierre Habouzit
  0 siblings, 1 reply; 25+ messages in thread
From: Pierre Habouzit @ 2007-09-06  9:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Kristian Høgsberg, git

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

On Thu, Sep 06, 2007 at 08:55:26AM +0000, Junio C Hamano wrote:
> As you noted in your follow-up message, this one has overlaps
> with the other strbuf series.  I could adjust them if I wanted
> to, but I do not have time for it right now.  I might try over
> the weekend but no promises.

  This one is exactly the same as the one that follows, I corrected a
typo in the comment of the commit, and I forgot to cleanse my tree
before running format-patch again, so you have the "second" patch twice
(name of the patch changed, hence the new one did not replaced the
previous, but created a 0002-foo.patch instead of overwriting the
0002-bar.patch).

  You just must drop the one I followup-ed to.

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

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

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf.
  2007-09-06  9:43       ` Pierre Habouzit
@ 2007-09-06  9:50         ` Pierre Habouzit
  0 siblings, 0 replies; 25+ messages in thread
From: Pierre Habouzit @ 2007-09-06  9:50 UTC (permalink / raw)
  To: Junio C Hamano, Kristian Høgsberg, git

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

On Thu, Sep 06, 2007 at 09:43:23AM +0000, Pierre Habouzit wrote:
> On Thu, Sep 06, 2007 at 08:55:26AM +0000, Junio C Hamano wrote:
> > As you noted in your follow-up message, this one has overlaps
> > with the other strbuf series.  I could adjust them if I wanted
> > to, but I do not have time for it right now.  I might try over
> > the weekend but no promises.
> 
>   This one is exactly the same as the one that follows, I corrected a
> typo in the comment of the commit, and I forgot to cleanse my tree
> before running format-patch again, so you have the "second" patch twice
> (name of the patch changed, hence the new one did not replaced the
> previous, but created a 0002-foo.patch instead of overwriting the
> 0002-bar.patch).
> 
>   You just must drop the one I followup-ed to.

  err sorry, I mixed up with another thread. Did not had coffee yet :/

  Just nvm


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

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

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/9] Enable wt-status output to a given FILE pointer.
  2007-09-06  0:23 [PATCH 1/9] Enable wt-status output to a given FILE pointer Kristian Høgsberg
  2007-09-06  0:23 ` [PATCH 2/9] Enable wt-status to run against non-standard index file Kristian Høgsberg
@ 2007-09-06 16:27 ` Johannes Schindelin
  2007-09-17 23:30   ` Kristian Høgsberg
  1 sibling, 1 reply; 25+ messages in thread
From: Johannes Schindelin @ 2007-09-06 16:27 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 228 bytes --]

Hi,

On Wed, 5 Sep 2007, Kristian Høgsberg wrote:

> Still defaults to stdout, but you can now override wt_status.fp after 
> calling wt_status_prepare().

Would it not be easier to freopen(filename, "a", stdout)?

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/9] Introduce entry point for launching add--interactive.
  2007-09-06  0:23     ` [PATCH 4/9] Introduce entry point for launching add--interactive Kristian Høgsberg
  2007-09-06  0:23       ` [PATCH 5/9] Introduce strbuf_read_fd() Kristian Høgsberg
@ 2007-09-06 16:31       ` Johannes Schindelin
  2007-09-17 23:13         ` Kristian Høgsberg
  1 sibling, 1 reply; 25+ messages in thread
From: Johannes Schindelin @ 2007-09-06 16:31 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1310 bytes --]

Hi,

On Wed, 5 Sep 2007, Kristian Høgsberg wrote:

> diff --git a/builtin-add.c b/builtin-add.c
> index 3dd4ded..e79e8f7 100644
> --- a/builtin-add.c
> +++ b/builtin-add.c
> @@ -153,6 +154,13 @@ static int git_add_config(const char *var, const char *value)
>  	return git_default_config(var, value);
>  }
>  
> +int interactive_add(void)
> +{
> +	const char *argv[2] = { "add--interactive", NULL };
> +
> +	return run_command_v_opt(argv, RUN_GIT_CMD);
> +}

I'd rather have this in builtin-commit.c, since it is quite funny if 
builtin-add.c has code to fork() and exec() itself (eventually, that 
is) ;-)

> diff --git a/commit.h b/commit.h
> index 467872e..64e1d4b 100644
> --- a/commit.h
> +++ b/commit.h
> @@ -122,4 +122,13 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
>  		int depth, int shallow_flag, int not_shallow_flag);
>  
>  int in_merge_bases(struct commit *, struct commit **, int);
> +
> +extern const unsigned char *
> +create_commit(const unsigned char *tree_sha1,
> +	      unsigned char parent_sha1[][20], int parents,
> +	      const char *author_info, const char *committer_info,
> +	      const char *message, int length);
> +
> +extern int interactive_add(void);
> +

Just a guess: you did not want create_commit() to creep in here, right?

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs.
  2007-09-06  0:23         ` [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs Kristian Høgsberg
  2007-09-06  0:23           ` [PATCH 7/9] Add strbuf_read_path() Kristian Høgsberg
@ 2007-09-06 16:38           ` Johannes Schindelin
  2007-09-17 22:59             ` Kristian Høgsberg
  1 sibling, 1 reply; 25+ messages in thread
From: Johannes Schindelin @ 2007-09-06 16:38 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1594 bytes --]

Hi,

On Wed, 5 Sep 2007, Kristian Høgsberg wrote:

> diff --git a/strbuf.c b/strbuf.c
> index fcfc05e..ed2afea 100644
> --- a/strbuf.c
> +++ b/strbuf.c
> @@ -73,43 +74,15 @@ void strbuf_printf(struct strbuf *sb, const char *fmt, ...)
>  {
>  	char buffer[2048];
>  	va_list args;
> -	int len, size = 2 * sizeof buffer;
> +	int len;
>  
>  	va_start(args, fmt);
>  	len = vsnprintf(buffer, sizeof(buffer), fmt, args);
>  	va_end(args);
>  
> -	if (len > sizeof(buffer)) {
> -		/*
> -		 * Didn't fit in the buffer, but this vsnprintf at
> -		 * least gives us the required length back.  Grow the
> -		 * buffer acccordingly and try again.
> -		 */
> -		strbuf_grow(sb, len);
> -		va_start(args, fmt);
> -		len = vsnprintf(sb->buf + sb->len,
> -				sb->alloc - sb->len, fmt, args);
> -		va_end(args);
> -	} else if (len >= 0) {
> -		/*
> -		 * The initial vsnprintf fit in the temp buffer, just
> -		 * copy it to the strbuf.
> -		 */
> -		strbuf_add(sb, buffer, len);
> -	} else {
> -		/*
> -		 * This vnsprintf sucks and just returns -1 when the
> -		 * buffer is too small.  Keep doubling the size until
> -		 * it fits.
> -		 */
> -		while (len < 0) {
> -			strbuf_grow(sb, size);
> -			va_start(args, fmt);
> -			len = vsnprintf(sb->buf + sb->len,
> -					sb->alloc - sb->len, fmt, args);
> -			va_end(args);
> -			size *= 2;
> -		}
> -	}
> +	if (len > sizeof(buffer) || len < 0)
> +		die("out of buffer space\n");
> +
> +	strbuf_add(sb, buffer, len);
>  }

Really?

(If you find the time, it would be really nice to rebase that patch series 
on top of Pierre's strbuf work...)

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 7/9] Add strbuf_read_path().
  2007-09-06  0:23           ` [PATCH 7/9] Add strbuf_read_path() Kristian Høgsberg
  2007-09-06  0:23             ` [PATCH 8/9] Export rerere() and launch_editor() Kristian Høgsberg
@ 2007-09-06 16:40             ` Johannes Schindelin
  1 sibling, 0 replies; 25+ messages in thread
From: Johannes Schindelin @ 2007-09-06 16:40 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 288 bytes --]

Hi,

On Wed, 5 Sep 2007, Kristian Høgsberg wrote:

> +extern int strbuf_read_path(struct strbuf *sb, const char *path);

May I suggest renaming this to "strbuf_read_file()"?  I kind of expected a 
function which reads in the absolute path of a file, judging by the 
name...

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 9/9] Implement git commit as a builtin command.
  2007-09-06  0:23               ` [PATCH 9/9] Implement git commit as a builtin command Kristian Høgsberg
@ 2007-09-06 16:59                 ` Johannes Schindelin
  2007-09-17 22:58                   ` Kristian Høgsberg
  0 siblings, 1 reply; 25+ messages in thread
From: Johannes Schindelin @ 2007-09-06 16:59 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 3976 bytes --]

Hi,

On Wed, 5 Sep 2007, Kristian Høgsberg wrote:

>  contrib/examples/git-commit.sh |  665 +++++++++++++++++++++++++++++++++++
>  git-commit.sh                  |  665 -----------------------------------

You might want to use "git format-patch -M" next time ;-)

> @@ -357,7 +358,6 @@ BUILTIN_OBJS = \
>  	builtin-rev-parse.o \
>  	builtin-revert.o \
>  	builtin-rm.o \
> -	builtin-runstatus.o \

Better keep it; some people's scripts could depend on it.

> +struct option {
> +    enum option_type type;
> +    const char *long_name;
> +    char short_name;
> +    void *value;
> +};
> +
> +static int scan_options(const char ***argv, struct option *options)
> +{

I would not (no longer, anyway) be opposed to replacing the option parsing 
in git with getopt(); I hear that it is small enough to keep a copy in 
compat/getopt.c.

But let's go forward with builtin-commit; getopt() can come later.

> +static char *
> +prepare_index(const char **files, const char *prefix)
> +{
> +	int fd;
> +	struct tree *tree;
> +	struct lock_file *next_index_lock;
> +
> +	fd = hold_locked_index(&lock_file, 1);
> +	if (read_cache() < 0)
> +		die("index file corrupt");
> +
> +	if (all) {
> +		add_files_to_cache(fd, files, NULL);
> +		return lock_file.filename;
> +	} else if (also) {
> +		add_files_to_cache(fd, files, prefix);
> +		return lock_file.filename;
> +	}
> +
> +	if (interactive)
> +		interactive_add();
> +
> +	if (*files == NULL) {
> +		/* Commit index as-is. */
> +		rollback_lock_file(&lock_file);
> +		return get_index_file();
> +	}
> +
> +	/*
> +	 * FIXME: Warn on unknown files.  Shell script does
> +	 *
> +	 *   commit_only=`git-ls-files --error-unmatch -- "$@"`
> +	 */
> +
> +	/*
> +	 * FIXME: shell script does
> +	 *
> +	 *   git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
> +	 *
> +	 * which warns about unmerged files in the index.
> +	 */
> +
> +	/* update the user index file */
> +	add_files_to_cache(fd, files, prefix);

I suspect this, or ...

> +
> +	if (!initial_commit) {
> +		tree = parse_tree_indirect(head_sha1);
> +		if (!tree)
> +			die("failed to unpack HEAD tree object");
> +		if (read_tree(tree, 0, NULL))
> +			die("failed to read HEAD tree object");
> +	}
> +
> +	/* Uh oh, abusing lock_file to create a garbage collected file */
> +	next_index_lock = xmalloc(sizeof(*next_index_lock));
> +	fd = hold_lock_file_for_update(next_index_lock,
> +				       git_path("next-index-%d", getpid()), 1);
> +	add_files_to_cache(fd, files, prefix);

... this, but not both.

> +/* Find out if the message starting at position 'start' in the strbuf
> + * contains only whitespace and Signed-off-by lines. */
> +static int message_is_empty(struct strbuf *sb, int start)
> +{
> +	static const char signed_off_by[] = "Signed-off-by: ";

I think you already defined that globally earlier.

In the function message_is_empty() you write:

> +	/* See if the template is just a prefix of the message. */
> +	strbuf_init(&tmpl);
> +	if (template_file && strbuf_read_path(&tmpl, template_file) > 0) {
> +		stripspace(&tmpl, 1);
> +		if (start + tmpl.len <= sb->len &&
> +		    memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
> +			start += tmpl.len;

Could we not bail out here, if there is no match?  In that case, the 
message is clearly not empty...

> +	/* Check if the rest is just whitespace and Signed-of-by's. */
> +	for (i = start; i < sb->len; i++) {
> +		nl = memchr(sb->buf + i, '\n', sb->len - i);
> +		if (nl)
> +			eol = nl - sb->buf;
> +		else
> +			eol = sb->len;

Why not just "if (isspace(sb->buf[i]) || sb->buf[i] == '\n') continue;"? 
This would also catch the cases where people indent their S-O-Bs.

> +
> +		if (strlen(signed_off_by) <= eol - i &&
> +		    !prefixcmp(sb->buf + i, signed_off_by)) {
> +			i = eol;
> +			continue;
> +		}
> +		while (i < eol)
> +			if (!isspace(sb->buf[i++]))
> +				return 0;
> +	}
> +
> +	return 1;
> +}

I did not review the rest of the code closely yet...

All in all: well done!

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 9/9] Implement git commit as a builtin command.
  2007-09-06 16:59                 ` Johannes Schindelin
@ 2007-09-17 22:58                   ` Kristian Høgsberg
  2007-09-17 23:16                     ` Johannes Schindelin
  2007-09-17 23:56                     ` Jeff King
  0 siblings, 2 replies; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-17 22:58 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

On Thu, 2007-09-06 at 17:59 +0100, Johannes Schindelin wrote:
> Hi,
> 
> On Wed, 5 Sep 2007, Kristian Høgsberg wrote:
> 
> >  contrib/examples/git-commit.sh |  665 +++++++++++++++++++++++++++++++++++
> >  git-commit.sh                  |  665 -----------------------------------
> 
> You might want to use "git format-patch -M" next time ;-)
> 
> > @@ -357,7 +358,6 @@ BUILTIN_OBJS = \
> >  	builtin-rev-parse.o \
> >  	builtin-revert.o \
> >  	builtin-rm.o \
> > -	builtin-runstatus.o \
> 
> Better keep it; some people's scripts could depend on it.

Seriously?  Why don't we remove it and see if somebody yells?  It's more
of an implementation detail than most other git commands; if you need
status output in your script why wouldn't you just run git status?

> > +struct option {
> > +    enum option_type type;
> > +    const char *long_name;
> > +    char short_name;
> > +    void *value;
> > +};
> > +
> > +static int scan_options(const char ***argv, struct option *options)
> > +{
> 
> I would not (no longer, anyway) be opposed to replacing the option parsing 
> in git with getopt(); I hear that it is small enough to keep a copy in 
> compat/getopt.c.
> 
> But let's go forward with builtin-commit; getopt() can come later.

I don't know.  I think it's a situation much like the string library
discussion.  It's a small enough dependency (70 lines!) that there's no
gain in depending on an external implementation, and we can tailor it to
gits needs as we extend the use within git.  And we can call it gitopt!

> > +static char *
> > +prepare_index(const char **files, const char *prefix)
> > +{
> > +	int fd;
> > +	struct tree *tree;
> > +	struct lock_file *next_index_lock;
> > +
> > +	fd = hold_locked_index(&lock_file, 1);
> > +	if (read_cache() < 0)
> > +		die("index file corrupt");
> > +
> > +	if (all) {
> > +		add_files_to_cache(fd, files, NULL);
> > +		return lock_file.filename;
> > +	} else if (also) {
> > +		add_files_to_cache(fd, files, prefix);
> > +		return lock_file.filename;
> > +	}
> > +
> > +	if (interactive)
> > +		interactive_add();
> > +
> > +	if (*files == NULL) {
> > +		/* Commit index as-is. */
> > +		rollback_lock_file(&lock_file);
> > +		return get_index_file();
> > +	}
> > +
> > +	/*
> > +	 * FIXME: Warn on unknown files.  Shell script does
> > +	 *
> > +	 *   commit_only=`git-ls-files --error-unmatch -- "$@"`
> > +	 */
> > +
> > +	/*
> > +	 * FIXME: shell script does
> > +	 *
> > +	 *   git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
> > +	 *
> > +	 * which warns about unmerged files in the index.
> > +	 */
> > +
> > +	/* update the user index file */
> > +	add_files_to_cache(fd, files, prefix);
> 
> I suspect this, or ...
> 
> > +
> > +	if (!initial_commit) {
> > +		tree = parse_tree_indirect(head_sha1);
> > +		if (!tree)
> > +			die("failed to unpack HEAD tree object");
> > +		if (read_tree(tree, 0, NULL))
> > +			die("failed to read HEAD tree object");
> > +	}
> > +
> > +	/* Uh oh, abusing lock_file to create a garbage collected file */
> > +	next_index_lock = xmalloc(sizeof(*next_index_lock));
> > +	fd = hold_lock_file_for_update(next_index_lock,
> > +				       git_path("next-index-%d", getpid()), 1);
> > +	add_files_to_cache(fd, files, prefix);
> 
> ... this, but not both.

No, this needs both.  The first add_files_to_cache() call updates the
user index (.git/index) by adding the given files, then we build a
temporary index from a tree and add the files to that index.

> 
> > +/* Find out if the message starting at position 'start' in the strbuf
> > + * contains only whitespace and Signed-off-by lines. */
> > +static int message_is_empty(struct strbuf *sb, int start)
> > +{
> > +	static const char signed_off_by[] = "Signed-off-by: ";
> 
> I think you already defined that globally earlier.

Ah, yes, fixed.

> In the function message_is_empty() you write:
> 
> > +	/* See if the template is just a prefix of the message. */
> > +	strbuf_init(&tmpl);
> > +	if (template_file && strbuf_read_path(&tmpl, template_file) > 0) {
> > +		stripspace(&tmpl, 1);
> > +		if (start + tmpl.len <= sb->len &&
> > +		    memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
> > +			start += tmpl.len;
> 
> Could we not bail out here, if there is no match?  In that case, the 
> message is clearly not empty...

The contents could be just sign-off-by's.

> > +	/* Check if the rest is just whitespace and Signed-of-by's. */
> > +	for (i = start; i < sb->len; i++) {
> > +		nl = memchr(sb->buf + i, '\n', sb->len - i);
> > +		if (nl)
> > +			eol = nl - sb->buf;
> > +		else
> > +			eol = sb->len;
> 
> Why not just "if (isspace(sb->buf[i]) || sb->buf[i] == '\n') continue;"? 
> This would also catch the cases where people indent their S-O-Bs.
> 
> > +
> > +		if (strlen(signed_off_by) <= eol - i &&
> > +		    !prefixcmp(sb->buf + i, signed_off_by)) {
> > +			i = eol;
> > +			continue;
> > +		}
> > +		while (i < eol)
> > +			if (!isspace(sb->buf[i++]))
> > +				return 0;
> > +	}
> > +
> > +	return 1;
> > +}
> 
> I did not review the rest of the code closely yet...

I'm sending an updated version against Pierre's strbuf changes now.
It's a smaller patch set, so hopefully we can get it in soon.

Kristian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs.
  2007-09-06 16:38           ` [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs Johannes Schindelin
@ 2007-09-17 22:59             ` Kristian Høgsberg
  0 siblings, 0 replies; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-17 22:59 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

On Thu, 2007-09-06 at 17:38 +0100, Johannes Schindelin wrote:
> Hi,
> 
> On Wed, 5 Sep 2007, Kristian Høgsberg wrote:
> 
> > diff --git a/strbuf.c b/strbuf.c
> > index fcfc05e..ed2afea 100644
> > --- a/strbuf.c
> > +++ b/strbuf.c
> > @@ -73,43 +74,15 @@ void strbuf_printf(struct strbuf *sb, const char *fmt, ...)
> >  {
> >  	char buffer[2048];
> >  	va_list args;
> > -	int len, size = 2 * sizeof buffer;
> > +	int len;
> >  
> >  	va_start(args, fmt);
> >  	len = vsnprintf(buffer, sizeof(buffer), fmt, args);
> >  	va_end(args);
> >  
> > -	if (len > sizeof(buffer)) {
> > -		/*
> > -		 * Didn't fit in the buffer, but this vsnprintf at
> > -		 * least gives us the required length back.  Grow the
> > -		 * buffer acccordingly and try again.
> > -		 */
> > -		strbuf_grow(sb, len);
> > -		va_start(args, fmt);
> > -		len = vsnprintf(sb->buf + sb->len,
> > -				sb->alloc - sb->len, fmt, args);
> > -		va_end(args);
> > -	} else if (len >= 0) {
> > -		/*
> > -		 * The initial vsnprintf fit in the temp buffer, just
> > -		 * copy it to the strbuf.
> > -		 */
> > -		strbuf_add(sb, buffer, len);
> > -	} else {
> > -		/*
> > -		 * This vnsprintf sucks and just returns -1 when the
> > -		 * buffer is too small.  Keep doubling the size until
> > -		 * it fits.
> > -		 */
> > -		while (len < 0) {
> > -			strbuf_grow(sb, size);
> > -			va_start(args, fmt);
> > -			len = vsnprintf(sb->buf + sb->len,
> > -					sb->alloc - sb->len, fmt, args);
> > -			va_end(args);
> > -			size *= 2;
> > -		}
> > -	}
> > +	if (len > sizeof(buffer) || len < 0)
> > +		die("out of buffer space\n");
> > +
> > +	strbuf_add(sb, buffer, len);
> >  }
> 
> Really?
> 
> (If you find the time, it would be really nice to rebase that patch series 
> on top of Pierre's strbuf work...)

Argh, this was a screwup when I edited the patch series.  The next
series is based on Pierres changes.

Kristian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/9] Introduce entry point for launching add--interactive.
  2007-09-06 16:31       ` [PATCH 4/9] Introduce entry point for launching add--interactive Johannes Schindelin
@ 2007-09-17 23:13         ` Kristian Høgsberg
  2007-09-17 23:27           ` Johannes Schindelin
  0 siblings, 1 reply; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-17 23:13 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

On Thu, 2007-09-06 at 17:31 +0100, Johannes Schindelin wrote:
> Hi,
> 
> On Wed, 5 Sep 2007, Kristian Høgsberg wrote:
> 
> > diff --git a/builtin-add.c b/builtin-add.c
> > index 3dd4ded..e79e8f7 100644
> > --- a/builtin-add.c
> > +++ b/builtin-add.c
> > @@ -153,6 +154,13 @@ static int git_add_config(const char *var, const char *value)
> >  	return git_default_config(var, value);
> >  }
> >  
> > +int interactive_add(void)
> > +{
> > +	const char *argv[2] = { "add--interactive", NULL };
> > +
> > +	return run_command_v_opt(argv, RUN_GIT_CMD);
> > +}
> 
> I'd rather have this in builtin-commit.c, since it is quite funny if 
> builtin-add.c has code to fork() and exec() itself (eventually, that 
> is) ;-)

Huh... it ends up in the same binary, and interactive_add() sounds like
it should live in builtin-add.c rather than builtin-commit.c.  Either
way, I don't care too much, but can we fix it up later?

> > diff --git a/commit.h b/commit.h
> > index 467872e..64e1d4b 100644
> > --- a/commit.h
> > +++ b/commit.h
> > @@ -122,4 +122,13 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
> >  		int depth, int shallow_flag, int not_shallow_flag);
> >  
> >  int in_merge_bases(struct commit *, struct commit **, int);
> > +
> > +extern const unsigned char *
> > +create_commit(const unsigned char *tree_sha1,
> > +	      unsigned char parent_sha1[][20], int parents,
> > +	      const char *author_info, const char *committer_info,
> > +	      const char *message, int length);
> > +
> > +extern int interactive_add(void);
> > +
> 
> Just a guess: you did not want create_commit() to creep in here, right?

Yeah, that was another oversight, fixed in the next series.

Kristian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 9/9] Implement git commit as a builtin command.
  2007-09-17 22:58                   ` Kristian Høgsberg
@ 2007-09-17 23:16                     ` Johannes Schindelin
  2007-09-17 23:56                     ` Jeff King
  1 sibling, 0 replies; 25+ messages in thread
From: Johannes Schindelin @ 2007-09-17 23:16 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1800 bytes --]

Hi,

On Mon, 17 Sep 2007, Kristian H?gsberg wrote:

> On Thu, 2007-09-06 at 17:59 +0100, Johannes Schindelin wrote:
> > 
> > On Wed, 5 Sep 2007, Kristian Høgsberg wrote:
> > 
> > > -	builtin-runstatus.o \
> > 
> > Better keep it; some people's scripts could depend on it.
> 
> Seriously?  Why don't we remove it and see if somebody yells?  It's more 
> of an implementation detail than most other git commands; if you need 
> status output in your script why wouldn't you just run git status?

git status is deemed porcelain.

Yes, we recently converted a few things to use "git log", which is 
porcelain, too, and I was not happy...

But then, you're right, we could just go and break peoples' scripts, if 
they indeed did not use "git diff" directly.

> > > +struct option {
> > > +    enum option_type type;
> > > +    const char *long_name;
> > > +    char short_name;
> > > +    void *value;
> > > +};
> > > +
> > > +static int scan_options(const char ***argv, struct option *options)
> > > +{
> > 
> > I would not (no longer, anyway) be opposed to replacing the option parsing 
> > in git with getopt(); I hear that it is small enough to keep a copy in 
> > compat/getopt.c.
> > 
> > But let's go forward with builtin-commit; getopt() can come later.
> 
> I don't know.  I think it's a situation much like the string library 
> discussion.  It's a small enough dependency (70 lines!) that there's no 
> gain in depending on an external implementation, and we can tailor it to 
> gits needs as we extend the use within git.  And we can call it gitopt!

Hm.  I liked the semantics of getopt better, but what the heck.

> I'm sending an updated version against Pierre's strbuf changes now. It's 
> a smaller patch set, so hopefully we can get it in soon.

Yes, that would be good.

Thanks,
Dscho

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/9] Introduce entry point for launching add--interactive.
  2007-09-17 23:13         ` Kristian Høgsberg
@ 2007-09-17 23:27           ` Johannes Schindelin
  0 siblings, 0 replies; 25+ messages in thread
From: Johannes Schindelin @ 2007-09-17 23:27 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1120 bytes --]

Hi,

On Mon, 17 Sep 2007, Kristian H?gsberg wrote:

> On Thu, 2007-09-06 at 17:31 +0100, Johannes Schindelin wrote:
> > 
> > On Wed, 5 Sep 2007, Kristian Høgsberg wrote:
> > 
> > > diff --git a/builtin-add.c b/builtin-add.c
> > > index 3dd4ded..e79e8f7 100644
> > > --- a/builtin-add.c
> > > +++ b/builtin-add.c
> > > @@ -153,6 +154,13 @@ static int git_add_config(const char *var, const char *value)
> > >  	return git_default_config(var, value);
> > >  }
> > >  
> > > +int interactive_add(void)
> > > +{
> > > +	const char *argv[2] = { "add--interactive", NULL };
> > > +
> > > +	return run_command_v_opt(argv, RUN_GIT_CMD);
> > > +}
> > 
> > I'd rather have this in builtin-commit.c, since it is quite funny if 
> > builtin-add.c has code to fork() and exec() itself (eventually, that 
> > is) ;-)
> 
> Huh... it ends up in the same binary, and interactive_add() sounds like 
> it should live in builtin-add.c rather than builtin-commit.c.  Either 
> way, I don't care too much, but can we fix it up later?

Well, you are probably right on the former, and therefore we do not have 
to do the latter.

Thanks,
Dscho

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/9] Enable wt-status output to a given FILE pointer.
  2007-09-06 16:27 ` [PATCH 1/9] Enable wt-status output to a given FILE pointer Johannes Schindelin
@ 2007-09-17 23:30   ` Kristian Høgsberg
  0 siblings, 0 replies; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-17 23:30 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

On Thu, 2007-09-06 at 17:27 +0100, Johannes Schindelin wrote:
> Hi,
> 
> On Wed, 5 Sep 2007, Kristian Høgsberg wrote:
> 
> > Still defaults to stdout, but you can now override wt_status.fp after 
> > calling wt_status_prepare().
> 
> Would it not be easier to freopen(filename, "a", stdout)?

It's probably easier, but I think this is cleaner and the patch isn't
that big.  I don't want to worry about the side effects of freopening
stdout...

Kristian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 9/9] Implement git commit as a builtin command.
  2007-09-17 22:58                   ` Kristian Høgsberg
  2007-09-17 23:16                     ` Johannes Schindelin
@ 2007-09-17 23:56                     ` Jeff King
  2007-09-18  0:11                       ` Kristian Høgsberg
  1 sibling, 1 reply; 25+ messages in thread
From: Jeff King @ 2007-09-17 23:56 UTC (permalink / raw)
  To: Kristian Høgsberg; +Cc: Johannes Schindelin, git

On Mon, Sep 17, 2007 at 06:58:01PM -0400, Kristian Høgsberg wrote:

> > > -	builtin-runstatus.o \
> > 
> > Better keep it; some people's scripts could depend on it.
> 
> Seriously?  Why don't we remove it and see if somebody yells?  It's more
> of an implementation detail than most other git commands; if you need
> status output in your script why wouldn't you just run git status?

As the author of builtin-runstatus, I had always intended that it was a
temporary part of the transition to a C git-commit, and would go away
then. But I see in the interim somebody documented it.  It should
perhaps have been called git-status--helper, and the documentation
should have read "DO NOT USE THIS."

So certainly my intent was for it to go away, but whether it has become
something else is perhaps up to others to judge.

-Peff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 9/9] Implement git commit as a builtin command.
  2007-09-17 23:56                     ` Jeff King
@ 2007-09-18  0:11                       ` Kristian Høgsberg
  0 siblings, 0 replies; 25+ messages in thread
From: Kristian Høgsberg @ 2007-09-18  0:11 UTC (permalink / raw)
  To: Jeff King; +Cc: Johannes Schindelin, git


On Mon, 2007-09-17 at 19:56 -0400, Jeff King wrote:
> On Mon, Sep 17, 2007 at 06:58:01PM -0400, Kristian Høgsberg wrote:
> 
> > > > -	builtin-runstatus.o \
> > > 
> > > Better keep it; some people's scripts could depend on it.
> > 
> > Seriously?  Why don't we remove it and see if somebody yells?  It's more
> > of an implementation detail than most other git commands; if you need
> > status output in your script why wouldn't you just run git status?
> 
> As the author of builtin-runstatus, I had always intended that it was a
> temporary part of the transition to a C git-commit, and would go away
> then. But I see in the interim somebody documented it.  It should
> perhaps have been called git-status--helper, and the documentation
> should have read "DO NOT USE THIS."

That's what I suspected, thanks for clearing that up.  It definitely
feels more like a step towards a built-in commit than a useful command
on it's own.  It plugs right into this work, so as such, it's been a
success.

Kristian

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2007-09-18  0:11 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-09-06  0:23 [PATCH 1/9] Enable wt-status output to a given FILE pointer Kristian Høgsberg
2007-09-06  0:23 ` [PATCH 2/9] Enable wt-status to run against non-standard index file Kristian Høgsberg
2007-09-06  0:23   ` [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf Kristian Høgsberg
2007-09-06  0:23     ` [PATCH 4/9] Introduce entry point for launching add--interactive Kristian Høgsberg
2007-09-06  0:23       ` [PATCH 5/9] Introduce strbuf_read_fd() Kristian Høgsberg
2007-09-06  0:23         ` [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs Kristian Høgsberg
2007-09-06  0:23           ` [PATCH 7/9] Add strbuf_read_path() Kristian Høgsberg
2007-09-06  0:23             ` [PATCH 8/9] Export rerere() and launch_editor() Kristian Høgsberg
2007-09-06  0:23               ` [PATCH 9/9] Implement git commit as a builtin command Kristian Høgsberg
2007-09-06 16:59                 ` Johannes Schindelin
2007-09-17 22:58                   ` Kristian Høgsberg
2007-09-17 23:16                     ` Johannes Schindelin
2007-09-17 23:56                     ` Jeff King
2007-09-18  0:11                       ` Kristian Høgsberg
2007-09-06 16:40             ` [PATCH 7/9] Add strbuf_read_path() Johannes Schindelin
2007-09-06 16:38           ` [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs Johannes Schindelin
2007-09-17 22:59             ` Kristian Høgsberg
2007-09-06 16:31       ` [PATCH 4/9] Introduce entry point for launching add--interactive Johannes Schindelin
2007-09-17 23:13         ` Kristian Høgsberg
2007-09-17 23:27           ` Johannes Schindelin
2007-09-06  8:55     ` [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf Junio C Hamano
2007-09-06  9:43       ` Pierre Habouzit
2007-09-06  9:50         ` Pierre Habouzit
2007-09-06 16:27 ` [PATCH 1/9] Enable wt-status output to a given FILE pointer Johannes Schindelin
2007-09-17 23:30   ` Kristian Høgsberg

Code repositories for project(s) associated with this inbox:

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).