All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Aguilar <davvid@gmail.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: Nanako Shiraishi <nanako3@lavabit.com>,
	Jon Seymour <jon.seymour@gmail.com>,
	Jakub Narebski <jnareb@gmail.com>,
	Git Mailing List <git@vger.kernel.org>
Subject: Re: git-ls-files --added?
Date: Fri, 29 May 2009 23:02:34 -0700	[thread overview]
Message-ID: <20090530060233.GA10033@gmail.com> (raw)
In-Reply-To: <7v4ov38q5x.fsf@alter.siamese.dyndns.org>

On Fri, May 29, 2009 at 04:06:50PM -0700, Junio C Hamano wrote:
> Nanako Shiraishi <nanako3@lavabit.com> writes:
> 
> > ..., but I think the patch in the thread quoted by Junio (http://thread.gmane.org/gmane.comp.version-control.git/97830/focus=99134) does exactly that.
> 
> I do not know if it matches what David wants, but I can tell you that that
> patch is certainly ancient.
> 
> Here is a minimal update to make it apply cleanly on top of today's
> 'master'.

Thanks Nanako + Junio!

There's good stuff to build upon here so I'll take a deeper look
into it.  Getting this as plumbing will help a lot of future git
scripters.

>         XsssY PATH1 -> PATH2
> 
>     format, where X is the diff status between HEAD and the index, sss is the
>     rename/copy score of the change (if X is rename or copy --- otherwise
>     it is blank), Y is the diff status between the index and the worktree.  
>     PATH1 is the path in the HEAD, and " -> PATH2" part is shown only when
>     PATH1 corresponds to a different path in the index/worktree.

Can/should shortstatus handle comparing against arbitrary revs,
so we can parse the same info against HEAD~ to see a fake
status as if we're amending a commit?  That'd be pretty useful.


> If you apply this patch with "git apply" (no --index) and then
> 
>         $ git mv COPYING RENAMING
> 
> then you would see:
> 
>         $ ./git-shortstatus
>         M     Makefile
>         R100  COPYING -> RENAMING
>             M builtin-commit.c
>             M builtin-revert.c
>             M builtin.h
>             M git.c
>             M wt-status.c
>             M wt-status.h        

Very nice.

I'll look into your suggestions below when I have some more
time and welcome others to help out as well.


> It is very much welcomed if somebody wants to build on top of this.  A few
> obvious things, aside from bikeshedding to drop the score value (which I
> just did as a sanity check measure and for nothing else --- I won't feel
> hurt if we lost that field from the output) and such are:
> 
>  * We can also rewrite wt_status_print_untracked() using the collected
>    data by making the collector pay attention to untracked files quite
>    easily;
> 
>  * I did not bouther touching wt_status_print_initial() but I think it
>    should be straightforward to produce its output from the collected
>    data, as the collector already knows how to handle the initial commit.
> 
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
> 
>  Makefile         |    1 +
>  builtin-commit.c |   45 +++++++++++-
>  builtin-revert.c |    1 +
>  builtin.h        |    1 +
>  git.c            |    1 +
>  wt-status.c      |  214 ++++++++++++++++++++++++++++++++++++++++++-----------
>  wt-status.h      |    9 ++
>  7 files changed, 226 insertions(+), 46 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index eaae45d..fd497d4 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -359,6 +359,7 @@ BUILT_INS += git-init$X
>  BUILT_INS += git-merge-subtree$X
>  BUILT_INS += git-peek-remote$X
>  BUILT_INS += git-repo-config$X
> +BUILT_INS += git-shortstatus$X
>  BUILT_INS += git-show$X
>  BUILT_INS += git-stage$X
>  BUILT_INS += git-status$X
> diff --git a/builtin-commit.c b/builtin-commit.c
> index baaa75c..463356b 100644
> --- a/builtin-commit.c
> +++ b/builtin-commit.c
> @@ -14,6 +14,7 @@
>  #include "diffcore.h"
>  #include "commit.h"
>  #include "revision.h"
> +#include "string-list.h"
>  #include "wt-status.h"
>  #include "run-command.h"
>  #include "refs.h"
> @@ -21,7 +22,6 @@
>  #include "strbuf.h"
>  #include "utf8.h"
>  #include "parse-options.h"
> -#include "string-list.h"
>  #include "rerere.h"
>  #include "unpack-trees.h"
>  
> @@ -817,6 +817,49 @@ static int parse_and_validate_options(int argc, const char *argv[],
>  	return argc;
>  }
>  
> +int cmd_shortstatus(int argc, const char **argv, const char *prefix)
> +{
> +	struct wt_status s;
> +	int i;
> +
> +	read_cache();
> +	refresh_cache(REFRESH_QUIET);
> +	wt_status_prepare(&s);
> +	wt_status_collect_changes(&s);
> +	for (i = 0; i < s.change.nr; i++) {
> +		struct wt_status_change_data *d;
> +		struct string_list_item *it;
> +		char pfx[1 + 3 + 1 + 1];
> +
> +		it = &(s.change.items[i]);
> +		d = it->util;
> +		switch (d->index_status) {
> +		case DIFF_STATUS_COPIED:
> +		case DIFF_STATUS_RENAMED:
> +			sprintf(pfx, "%c%3d",
> +				d->index_status,
> +				(int)(d->index_score * 100 / MAX_SCORE));
> +			break;
> +		case 0:
> +			memcpy(pfx, "    ", 4);
> +			break;
> +		default:
> +			sprintf(pfx, "%c   ", d->index_status);
> +			break;
> +		}
> +		if (!d->worktree_status)
> +			pfx[4] = ' ';
> +		else
> +			pfx[4] = d->worktree_status;
> +		pfx[5] = '\0';
> +		printf("%s ", pfx);
> +		if (d->head_path)
> +			printf("%s -> ", d->head_path);
> +		printf("%s\n", it->string);
> +	}
> +	return 0;
> +}
> +
>  int cmd_status(int argc, const char **argv, const char *prefix)
>  {
>  	const char *index_file;
> diff --git a/builtin-revert.c b/builtin-revert.c
> index 3f2614e..10f1655 100644
> --- a/builtin-revert.c
> +++ b/builtin-revert.c
> @@ -3,6 +3,7 @@
>  #include "object.h"
>  #include "commit.h"
>  #include "tag.h"
> +#include "string-list.h"
>  #include "wt-status.h"
>  #include "run-command.h"
>  #include "exec_cmd.h"
> diff --git a/builtin.h b/builtin.h
> index 425ff8e..23e9eb6 100644
> --- a/builtin.h
> +++ b/builtin.h
> @@ -95,6 +95,7 @@ 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_shortstatus(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/git.c b/git.c
> index 5a00726..68c223e 100644
> --- a/git.c
> +++ b/git.c
> @@ -348,6 +348,7 @@ static void handle_internal_command(int argc, const char **argv)
>  		{ "rm", cmd_rm, RUN_SETUP },
>  		{ "send-pack", cmd_send_pack, RUN_SETUP },
>  		{ "shortlog", cmd_shortlog, USE_PAGER },
> +		{ "shortstatus", cmd_shortstatus, RUN_SETUP | NEED_WORK_TREE },
>  		{ "show-branch", cmd_show_branch, RUN_SETUP },
>  		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
>  		{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
> diff --git a/wt-status.c b/wt-status.c
> index 1b6df45..89be28e 100644
> --- a/wt-status.c
> +++ b/wt-status.c
> @@ -1,4 +1,5 @@
>  #include "cache.h"
> +#include "string-list.h"
>  #include "wt-status.h"
>  #include "color.h"
>  #include "object.h"
> @@ -56,6 +57,7 @@ void wt_status_prepare(struct wt_status *s)
>  	s->reference = "HEAD";
>  	s->fp = stdout;
>  	s->index_file = get_index_file();
> +	s->change.strdup_strings = 1;
>  }
>  
>  static void wt_status_print_cached_header(struct wt_status *s)
> @@ -98,18 +100,22 @@ static void wt_status_print_trailer(struct wt_status *s)
>  
>  #define quote_path quote_path_relative
>  
> -static void wt_status_print_filepair(struct wt_status *s,
> -				     int t, struct diff_filepair *p)
> +static void wt_status_print_change_data(struct wt_status *s,
> +					int t,
> +					int status,
> +					char *one_name,
> +					char *two_name,
> +					int score)
>  {
>  	const char *c = color(t);
>  	const char *one, *two;
>  	struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
>  
> -	one = quote_path(p->one->path, -1, &onebuf, s->prefix);
> -	two = quote_path(p->two->path, -1, &twobuf, s->prefix);
> +	one = quote_path(one_name, -1, &onebuf, s->prefix);
> +	two = quote_path(two_name, -1, &twobuf, s->prefix);
>  
>  	color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
> -	switch (p->status) {
> +	switch (status) {
>  	case DIFF_STATUS_ADDED:
>  		color_fprintf(s->fp, c, "new file:   %s", one);
>  		break;
> @@ -135,64 +141,88 @@ static void wt_status_print_filepair(struct wt_status *s,
>  		color_fprintf(s->fp, c, "unmerged:   %s", one);
>  		break;
>  	default:
> -		die("bug: unhandled diff status %c", p->status);
> +		die("bug: unhandled diff status %c", status);
>  	}
>  	fprintf(s->fp, "\n");
>  	strbuf_release(&onebuf);
>  	strbuf_release(&twobuf);
>  }
>  
> -static void wt_status_print_updated_cb(struct diff_queue_struct *q,
> -		struct diff_options *options,
> -		void *data)
> +static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
> +					 struct diff_options *options,
> +					 void *data)
>  {
>  	struct wt_status *s = data;
> -	int shown_header = 0;
>  	int i;
> +
> +	if (!q->nr)
> +		return;
> +	s->workdir_dirty = 1;
>  	for (i = 0; i < q->nr; i++) {
> -		if (q->queue[i]->status == 'U')
> -			continue;
> -		if (!shown_header) {
> -			wt_status_print_cached_header(s);
> -			s->commitable = 1;
> -			shown_header = 1;
> -		}
> -		wt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);
> +		struct diff_filepair *p;
> +		struct string_list_item *it;
> +		struct wt_status_change_data *d;
> +
> +		p = q->queue[i];
> +
> +		d = xcalloc(1, sizeof(*d));
> +		d->worktree_status = p->status;
> +		it = string_list_insert(p->one->path, &s->change);
> +		it->util = d;
>  	}
> -	if (shown_header)
> -		wt_status_print_trailer(s);
>  }
>  
> -static void wt_status_print_changed_cb(struct diff_queue_struct *q,
> -                        struct diff_options *options,
> -                        void *data)
> +static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
> +					 struct diff_options *options,
> +					 void *data)
>  {
>  	struct wt_status *s = data;
>  	int i;
> -	if (q->nr) {
> -		int has_deleted = 0;
> -		s->workdir_dirty = 1;
> -		for (i = 0; i < q->nr; i++)
> -			if (q->queue[i]->status == DIFF_STATUS_DELETED) {
> -				has_deleted = 1;
> -				break;
> -			}
> -		wt_status_print_dirty_header(s, has_deleted);
> +
> +	for (i = 0; i < q->nr; i++) {
> +		struct diff_filepair *p;
> +		struct string_list_item *it;
> +		struct wt_status_change_data *d;
> +
> +		p = q->queue[i];
> +		it = string_list_insert(p->two->path, &s->change);
> +		d = it->util;
> +		if (!d) {
> +			d = xcalloc(1, sizeof(*d));
> +			it->util = d;
> +		}
> +		d->index_status = p->status;
> +		switch (p->status) {
> +		case DIFF_STATUS_COPIED:
> +		case DIFF_STATUS_RENAMED:
> +			d->head_path = xstrdup(p->one->path);
> +			d->index_score = p->score;
> +			break;
> +		}
>  	}
> -	for (i = 0; i < q->nr; i++)
> -		wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);
> -	if (q->nr)
> -		wt_status_print_trailer(s);
>  }
>  
> -static void wt_status_print_updated(struct wt_status *s)
> +static void wt_status_collect_changes_worktree(struct wt_status *s)
> +{
> +	struct rev_info rev;
> +
> +	init_revisions(&rev, NULL);
> +	setup_revisions(0, NULL, &rev, NULL);
> +	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
> +	rev.diffopt.format_callback = wt_status_collect_changed_cb;
> +	rev.diffopt.format_callback_data = s;
> +	run_diff_files(&rev, 0);
> +}
> +
> +static void wt_status_collect_changes_index(struct wt_status *s)
>  {
>  	struct rev_info rev;
> +
>  	init_revisions(&rev, NULL);
>  	setup_revisions(0, NULL, &rev,
>  		s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);
>  	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
> -	rev.diffopt.format_callback = wt_status_print_updated_cb;
> +	rev.diffopt.format_callback = wt_status_collect_updated_cb;
>  	rev.diffopt.format_callback_data = s;
>  	rev.diffopt.detect_rename = 1;
>  	rev.diffopt.rename_limit = 200;
> @@ -200,15 +230,107 @@ static void wt_status_print_updated(struct wt_status *s)
>  	run_diff_index(&rev, 1);
>  }
>  
> +static void wt_status_collect_changes_initial(struct wt_status *s)
> +{
> +	int i;
> +
> +	for (i = 0; i < active_nr; i++) {
> +		struct string_list_item *it;
> +		struct wt_status_change_data *d;
> +
> +		it = string_list_insert(active_cache[i]->name, &s->change);
> +		d = it->util;
> +		if (!d) {
> +			d = xcalloc(1, sizeof(*d));
> +			it->util = d;
> +		}
> +		d->index_status = DIFF_STATUS_ADDED;
> +	}
> +}
> +
> +void wt_status_collect_changes(struct wt_status *s)
> +{
> +	wt_status_collect_changes_worktree(s);
> +
> +	if (s->is_initial)
> +		wt_status_collect_changes_initial(s);
> +	else
> +		wt_status_collect_changes_index(s);
> +}
> +
> +static void wt_status_print_updated(struct wt_status *s)
> +{
> +	int shown_header = 0;
> +	int i;
> +
> +	for (i = 0; i < s->change.nr; i++) {
> +		struct wt_status_change_data *d;
> +		struct string_list_item *it;
> +		it = &(s->change.items[i]);
> +		d = it->util;
> +		if (!d->index_status)
> +			continue;
> +		if (!shown_header) {
> +			wt_status_print_cached_header(s);
> +			s->commitable = 1;
> +			shown_header = 1;
> +		}
> +		wt_status_print_change_data(s, WT_STATUS_UPDATED,
> +					    d->index_status,
> +					    d->head_path ? d->head_path : it->string,
> +					    it->string,
> +					    d->index_score);
> +	}
> +	if (shown_header)
> +		wt_status_print_trailer(s);
> +}
> +
> +/*
> + * -1 : has delete
> + *  0 : no change
> + *  1 : some change but no delete
> + */
> +static int wt_status_check_worktree_changes(struct wt_status *s)
> +{
> +	int i;
> +	int changes = 0;
> +
> +	for (i = 0; i < s->change.nr; i++) {
> +		struct wt_status_change_data *d;
> +		d = s->change.items[i].util;
> +		if (!d->worktree_status)
> +			continue;
> +		changes = 1;
> +		if (d->worktree_status == DIFF_STATUS_DELETED)
> +			return -1;
> +	}
> +	return changes;
> +}
> +
>  static void wt_status_print_changed(struct wt_status *s)
>  {
> -	struct rev_info rev;
> -	init_revisions(&rev, "");
> -	setup_revisions(0, NULL, &rev, NULL);
> -	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
> -	rev.diffopt.format_callback = wt_status_print_changed_cb;
> -	rev.diffopt.format_callback_data = s;
> -	run_diff_files(&rev, 0);
> +	int i;
> +	int worktree_changes = wt_status_check_worktree_changes(s);
> +
> +	if (!worktree_changes)
> +		return;
> +
> +	wt_status_print_dirty_header(s, worktree_changes < 0);
> +
> +	for (i = 0; i < s->change.nr; i++) {
> +		struct wt_status_change_data *d;
> +		struct string_list_item *it;
> +		it = &(s->change.items[i]);
> +		d = it->util;
> +		if (!d->worktree_status)
> +			continue;
> +		wt_status_print_change_data(s, WT_STATUS_CHANGED,
> +					    d->worktree_status,
> +					    it->string,
> +					    it->string,
> +					    0);
> +	}
> +	wt_status_print_trailer(s);
>  }
>  
>  static void wt_status_print_submodule_summary(struct wt_status *s)
> @@ -337,6 +459,8 @@ void wt_status_print(struct wt_status *s)
>  			wt_status_print_tracking(s);
>  	}
>  
> +	wt_status_collect_changes(s);
> +
>  	if (s->is_initial) {
>  		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
>  		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit");
> diff --git a/wt-status.h b/wt-status.h
> index 78add09..00508c3 100644
> --- a/wt-status.h
> +++ b/wt-status.h
> @@ -18,6 +18,13 @@ enum untracked_status_type {
>  };
>  extern enum untracked_status_type show_untracked_files;
>  
> +struct wt_status_change_data {
> +	int worktree_status;
> +	int index_status;
> +	int index_score;
> +	char *head_path;
> +};
> +
>  struct wt_status {
>  	int is_initial;
>  	char *branch;
> @@ -33,6 +40,7 @@ struct wt_status {
>  	const char *index_file;
>  	FILE *fp;
>  	const char *prefix;
> +	struct string_list change;
>  };
>  
>  int git_status_config(const char *var, const char *value, void *cb);
> @@ -40,5 +48,6 @@ extern int wt_status_use_color;
>  extern int wt_status_relative_paths;
>  void wt_status_prepare(struct wt_status *s);
>  void wt_status_print(struct wt_status *s);
> +void wt_status_collect_changes(struct wt_status *s);
>  
>  #endif /* STATUS_H */

-- 
		David

  reply	other threads:[~2009-05-30  6:02 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-24  7:54 git-ls-files --added? Jon Seymour
2009-05-24  8:37 ` Jakub Narebski
2009-05-24  9:12   ` Jon Seymour
2009-05-24 18:17     ` Junio C Hamano
2009-05-25  6:33       ` Junio C Hamano
2009-05-25  7:31         ` Constantine Plotnikov
2009-05-25  7:46           ` Björn Steinbrink
2009-05-26  0:56         ` Jon Seymour
2009-05-29 21:26           ` David Aguilar
2009-05-29 22:01             ` Nanako Shiraishi
2009-05-29 23:06               ` Junio C Hamano
2009-05-30  6:02                 ` David Aguilar [this message]
2009-05-31 16:19                   ` Tony Finch

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090530060233.GA10033@gmail.com \
    --to=davvid@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=jnareb@gmail.com \
    --cc=jon.seymour@gmail.com \
    --cc=nanako3@lavabit.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.