This patch adds a unique identifier for each file shown by "git status".
Subsequent operation (add/rm/checkout/commit/reset) may use these ids to simplify specifying the files, provided that they are taught about the --id option as well.
Example:
$ git status --id
# On branch local
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: builtin-add.c (m1)
# modified: builtin-checkout.c (m2)
# modified: builtin-commit.c (m3)
# modified: builtin-reset.c (m4)
# modified: builtin-rm.c (m5)
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# makefile.debug (x1)
# nazri.sh (x2)
no changes added to commit (use "git add" and/or "git commit -a")
$ git add --id m1
# Short for "git add builtin-add.c
$ git add --id m3,m5
# Short for "git add builtin-commit.c builtin-rm.c"
# Even shorter: -d is equivalent to --id
$ git add -d m3,m5
Signed-off-by: Nazri Ramliy <ayiehere@gmail.com>
---
cache.h | 1 +
path.c | 44 ++++++++++++++++++
wt-status.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
wt-status.h | 1 +
4 files changed, 181 insertions(+), 11 deletions(-)
Show changes to 4 files +181 −11
cache.h, path.c, wt-status.c, wt-status.h
diff --git a/cache.h b/cache.h
index e6c7f33..05817e3 100644
--- a/cache.h
+++ b/cache.h
@@ -649,6 +649,7 @@ const char *make_relative_path(const char *abs, const char *base);
int normalize_path_copy(char *dst, const char *src);
int longest_ancestor_length(const char *path, const char *prefix_list);
char *strip_path_suffix(const char *path, const char *suffix);
+char ** expand_file_ids(const char *file_id, int *argc, char **argv);
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
extern int sha1_object_info(const unsigned char *, unsigned long *);
diff --git a/path.c b/path.c
index 047fdb0..7824c4a 100644
--- a/path.c
+++ b/path.c
@@ -564,3 +564,47 @@ char *strip_path_suffix(const char *path, const char *suffix)
return NULL;
return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
}
+
+char ** expand_file_ids(const char *file_id, int *argc, char **argv)
+{
+ FILE *fp;
+ const char *filename = git_path("FILE_IDS");
+ struct strbuf sb = STRBUF_INIT;
+ int i;
+
+ char **new_argv;
+
+ new_argv = (char **) xmalloc(*argc * sizeof(char *));
+ for (i = 0; i < *argc; i++) {
+ new_argv[i] = (char *) argv[i];
+ }
+
+ fp = fopen(filename, "r");
+ if (!fp)
+ die("cannot open %s: %s\n", filename, strerror(errno));
+
+ while (strbuf_getline(&sb, fp, '\n') == 0) {
+ char *b, *e;
+ if (sb.len == 0)
+ continue;
+ b = e = sb.buf;
+ while(*e && *e != ' ')
+ e++;
+ *e = '\0';
+ if(strstr(file_id, b)) {
+ (*argc)++;
+ new_argv = xrealloc(new_argv, (*argc) * sizeof(char *));
+ new_argv[*argc - 1] = xstrdup(e+1);
+ }
+ }
+ strbuf_release(&sb);
+
+ /*
+ * parse_options adds a NULL terminator at end of argv. Do the same for
+ * new_argv.
+ */
+ new_argv = xrealloc(new_argv, *argc + 1 * sizeof(char *));
+ new_argv[*argc] = NULL;
+
+ return new_argv;
+}
diff --git a/wt-status.c b/wt-status.c
index 47735d8..6013fbd 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -96,6 +96,106 @@ static void wt_status_print_trailer(struct wt_status *s)
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
}
+struct id_list {
+ struct id_list *next;
+ char status;
+ int nr;
+ char *name;
+};
+
+static struct id_list *wt_files = NULL;
+static struct id_list *wt_files_last = NULL;
+static int n_id_list = 0;
+
+static int get_id_list_id(char status)
+{
+ static int added = 0;
+ static int copied = 0;
+ static int deleted = 0;
+ static int modified = 0;
+ static int renamed = 0;
+ static int type_changed = 0;
+ static int unknown = 0;
+ static int unmerged = 0;
+
+ switch(status) {
+ case DIFF_STATUS_ADDED:
+ return ++added;
+ case DIFF_STATUS_COPIED:
+ return ++copied;
+ case DIFF_STATUS_DELETED:
+ return ++deleted;
+ case DIFF_STATUS_MODIFIED:
+ return ++modified;
+ case DIFF_STATUS_RENAMED:
+ return ++renamed;
+ case DIFF_STATUS_TYPE_CHANGED:
+ return ++type_changed;
+ case DIFF_STATUS_UNKNOWN:
+ return ++unknown;
+ case DIFF_STATUS_UNMERGED:
+ return ++unmerged;
+ }
+ die("bug: unhandled diff status %c", status);
+}
+
+static int add_to_id_list(char status, const char *name)
+{
+ struct id_list *new_entry;
+ if(wt_files_last == NULL) {
+ wt_files = xcalloc(1, sizeof(*wt_files));
+ wt_files_last = wt_files;
+ new_entry = wt_files_last;
+ } else {
+ wt_files_last->next = xcalloc(1, sizeof(*wt_files));
+ new_entry = wt_files_last->next;
+ wt_files_last = wt_files_last->next;
+ }
+ new_entry->name = xstrdup(name);
+ new_entry->nr = get_id_list_id(status);
+ new_entry->status = status;
+ new_entry->next = NULL;
+
+ n_id_list++;
+
+ return new_entry->nr;
+}
+
+static void store_id_list()
+{
+ FILE *fp;
+ struct id_list *p = wt_files;
+ const char *filename = git_path("FILE_IDS");
+
+ fp = fopen(filename, "w");
+ if (!fp)
+ die("cannot open %s: %s\n", filename, strerror(errno));
+
+ while (p) {
+ fprintf(fp, "%c%d %s\n",tolower(p->status), p->nr, p->name);
+ p = p->next;
+ }
+ fclose(fp);
+}
+
+static void free_id_list()
+{
+ struct id_list *p = wt_files;
+ struct id_list *next = p;
+ while (p) {
+ next = p->next;
+ free(p->name);
+ free(p);
+ p = next;
+ }
+ wt_files = NULL;
+}
+
+static void format_id(char *buf, char status, int nr)
+{
+ sprintf(buf, " (%c%d)", tolower(status), nr);
+}
+
#define quote_path quote_path_relative
static void wt_status_print_filepair(struct wt_status *s,
@@ -104,35 +204,48 @@ static void wt_status_print_filepair(struct wt_status *s,
const char *c = color(t);
const char *one, *two;
struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
+ char id[64] = ""; /* arbitrary limit, 64 should be enough for everybody ... */
+ int nr;
one = quote_path(p->one->path, -1, &onebuf, s->prefix);
two = quote_path(p->two->path, -1, &twobuf, s->prefix);
+ if (s->show_file_id) {
+ if ( p->status == DIFF_STATUS_RENAMED
+ || p->status == DIFF_STATUS_COPIED)
+ nr = add_to_id_list(p->status, two);
+ else
+ nr = add_to_id_list(p->status, one);
+ format_id(id, p->status, nr);
+ }
+
+
color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
switch (p->status) {
case DIFF_STATUS_ADDED:
- color_fprintf(s->fp, c, "new file: %s", one);
+ color_fprintf(s->fp, c, "new file: %s%s", one, id);
break;
case DIFF_STATUS_COPIED:
- color_fprintf(s->fp, c, "copied: %s -> %s", one, two);
+ color_fprintf(s->fp, c, "copied: %s -> %s%s", one, two, id);
break;
case DIFF_STATUS_DELETED:
- color_fprintf(s->fp, c, "deleted: %s", one);
+ color_fprintf(s->fp, c, "deleted: %s%s", one, id);
break;
case DIFF_STATUS_MODIFIED:
- color_fprintf(s->fp, c, "modified: %s", one);
+ color_fprintf(s->fp, c, "modified: %s%s", one, id);
+
break;
case DIFF_STATUS_RENAMED:
- color_fprintf(s->fp, c, "renamed: %s -> %s", one, two);
+ color_fprintf(s->fp, c, "renamed: %s -> %s%s", one, two, id);
break;
case DIFF_STATUS_TYPE_CHANGED:
- color_fprintf(s->fp, c, "typechange: %s", one);
+ color_fprintf(s->fp, c, "typechange: %s%s", one, id);
break;
case DIFF_STATUS_UNKNOWN:
- color_fprintf(s->fp, c, "unknown: %s", one);
+ color_fprintf(s->fp, c, "unknown: %s%s", one, id);
break;
case DIFF_STATUS_UNMERGED:
- color_fprintf(s->fp, c, "unmerged: %s", one);
+ color_fprintf(s->fp, c, "unmerged: %s%s", one, id);
break;
default:
die("bug: unhandled diff status %c", p->status);
@@ -247,6 +360,9 @@ static void wt_status_print_untracked(struct wt_status *s)
int i;
int shown_header = 0;
struct strbuf buf = STRBUF_INIT;
+ char id[64] = ""; /* arbitrary limit, 64 should be enough for everybody ... */
+ char *quoted;
+ int nr;
memset(&dir, 0, sizeof(dir));
@@ -266,9 +382,13 @@ static void wt_status_print_untracked(struct wt_status *s)
shown_header = 1;
}
color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
- color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%s",
- quote_path(ent->name, ent->len,
- &buf, s->prefix));
+ quoted = quote_path(ent->name, ent->len, &buf, s->prefix);
+ if (s->show_file_id) {
+ nr = add_to_id_list(DIFF_STATUS_UNKNOWN, quoted);
+ format_id(id, DIFF_STATUS_UNKNOWN, nr);
+ }
+ color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%s%s",
+ quoted, id);
}
strbuf_release(&buf);
}
@@ -370,6 +490,10 @@ void wt_status_print(struct wt_status *s)
else
printf("nothing to commit (working directory clean)\n");
}
+ if (s->show_file_id) {
+ store_id_list();
+ free_id_list();
+ }
}
int git_status_config(const char *k, const char *v, void *cb)
diff --git a/wt-status.h b/wt-status.h
index 78add09..efcb566 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -23,6 +23,7 @@ struct wt_status {
char *branch;
const char *reference;
int verbose;
+ int show_file_id;
int amend;
int untracked;
int nowarn;