Matthias Kestenholz | d6b64ed | 2006-08-03 17:24:35 +0200 | [diff] [blame] | 1 | #include "builtin.h" |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 2 | #include "cache.h" |
| 3 | #include "commit.h" |
| 4 | #include "tag.h" |
| 5 | #include "refs.h" |
| 6 | |
Junio C Hamano | c075aea | 2007-05-24 12:20:42 -0700 | [diff] [blame] | 7 | #define CUTOFF_DATE_SLOP 86400 /* one day */ |
| 8 | |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 9 | static const char name_rev_usage[] = |
Johannes Schindelin | 2afc29a | 2007-02-17 19:22:35 +0100 | [diff] [blame] | 10 | "git-name-rev [--tags | --refs=<pattern>] ( --all | --stdin | committish [committish...] )\n"; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 11 | |
| 12 | typedef struct rev_name { |
| 13 | const char *tip_name; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 14 | int generation; |
Johannes Schindelin | ac076c2 | 2007-08-27 12:37:33 +0100 | [diff] [blame] | 15 | int distance; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 16 | } rev_name; |
| 17 | |
| 18 | static long cutoff = LONG_MAX; |
| 19 | |
Johannes Schindelin | ac076c2 | 2007-08-27 12:37:33 +0100 | [diff] [blame] | 20 | /* How many generations are maximally preferred over _one_ merge traversal? */ |
| 21 | #define MERGE_TRAVERSAL_WEIGHT 65535 |
| 22 | |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 23 | static void name_rev(struct commit *commit, |
Johannes Schindelin | ac076c2 | 2007-08-27 12:37:33 +0100 | [diff] [blame] | 24 | const char *tip_name, int generation, int distance, |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 25 | int deref) |
| 26 | { |
Linus Torvalds | d3ff6f5 | 2006-06-17 18:26:18 -0700 | [diff] [blame] | 27 | struct rev_name *name = (struct rev_name *)commit->util; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 28 | struct commit_list *parents; |
Junio C Hamano | f2e6f1c | 2005-11-28 20:51:44 -0800 | [diff] [blame] | 29 | int parent_number = 1; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 30 | |
| 31 | if (!commit->object.parsed) |
| 32 | parse_commit(commit); |
| 33 | |
| 34 | if (commit->date < cutoff) |
| 35 | return; |
| 36 | |
| 37 | if (deref) { |
| 38 | char *new_name = xmalloc(strlen(tip_name)+3); |
| 39 | strcpy(new_name, tip_name); |
| 40 | strcat(new_name, "^0"); |
| 41 | tip_name = new_name; |
| 42 | |
| 43 | if (generation) |
| 44 | die("generation: %d, but deref?", generation); |
| 45 | } |
| 46 | |
| 47 | if (name == NULL) { |
| 48 | name = xmalloc(sizeof(rev_name)); |
Linus Torvalds | d3ff6f5 | 2006-06-17 18:26:18 -0700 | [diff] [blame] | 49 | commit->util = name; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 50 | goto copy_data; |
Johannes Schindelin | ac076c2 | 2007-08-27 12:37:33 +0100 | [diff] [blame] | 51 | } else if (name->distance > distance) { |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 52 | copy_data: |
| 53 | name->tip_name = tip_name; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 54 | name->generation = generation; |
Johannes Schindelin | ac076c2 | 2007-08-27 12:37:33 +0100 | [diff] [blame] | 55 | name->distance = distance; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 56 | } else |
| 57 | return; |
| 58 | |
| 59 | for (parents = commit->parents; |
| 60 | parents; |
| 61 | parents = parents->next, parent_number++) { |
Junio C Hamano | f2e6f1c | 2005-11-28 20:51:44 -0800 | [diff] [blame] | 62 | if (parent_number > 1) { |
Johannes Schindelin | 59d3f54 | 2007-02-20 01:08:48 +0100 | [diff] [blame] | 63 | int len = strlen(tip_name); |
Andy Whitcroft | cf606e3 | 2007-05-15 17:33:25 +0100 | [diff] [blame] | 64 | char *new_name = xmalloc(len + |
| 65 | 1 + decimal_length(generation) + /* ~<n> */ |
| 66 | 1 + 2 + /* ^NN */ |
| 67 | 1); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 68 | |
Johannes Schindelin | 59d3f54 | 2007-02-20 01:08:48 +0100 | [diff] [blame] | 69 | if (len > 2 && !strcmp(tip_name + len - 2, "^0")) |
| 70 | len -= 2; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 71 | if (generation > 0) |
Johannes Schindelin | 59d3f54 | 2007-02-20 01:08:48 +0100 | [diff] [blame] | 72 | sprintf(new_name, "%.*s~%d^%d", len, tip_name, |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 73 | generation, parent_number); |
| 74 | else |
Johannes Schindelin | 59d3f54 | 2007-02-20 01:08:48 +0100 | [diff] [blame] | 75 | sprintf(new_name, "%.*s^%d", len, tip_name, |
| 76 | parent_number); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 77 | |
Johannes Schindelin | ac076c2 | 2007-08-27 12:37:33 +0100 | [diff] [blame] | 78 | name_rev(parents->item, new_name, 0, |
| 79 | distance + MERGE_TRAVERSAL_WEIGHT, 0); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 80 | } else { |
Johannes Schindelin | ac076c2 | 2007-08-27 12:37:33 +0100 | [diff] [blame] | 81 | name_rev(parents->item, tip_name, generation + 1, |
| 82 | distance + 1, 0); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 83 | } |
| 84 | } |
| 85 | } |
| 86 | |
Johannes Schindelin | 2afc29a | 2007-02-17 19:22:35 +0100 | [diff] [blame] | 87 | struct name_ref_data { |
| 88 | int tags_only; |
Shawn O. Pearce | 2361570 | 2007-05-21 03:20:25 -0400 | [diff] [blame] | 89 | int name_only; |
Johannes Schindelin | 2afc29a | 2007-02-17 19:22:35 +0100 | [diff] [blame] | 90 | const char *ref_filter; |
| 91 | }; |
| 92 | |
Junio C Hamano | 8da1977 | 2006-09-20 22:02:01 -0700 | [diff] [blame] | 93 | static int name_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data) |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 94 | { |
| 95 | struct object *o = parse_object(sha1); |
Johannes Schindelin | 2afc29a | 2007-02-17 19:22:35 +0100 | [diff] [blame] | 96 | struct name_ref_data *data = cb_data; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 97 | int deref = 0; |
| 98 | |
Junio C Hamano | cc44c76 | 2007-02-20 01:53:29 -0800 | [diff] [blame] | 99 | if (data->tags_only && prefixcmp(path, "refs/tags/")) |
Johannes Schindelin | 2afc29a | 2007-02-17 19:22:35 +0100 | [diff] [blame] | 100 | return 0; |
| 101 | |
| 102 | if (data->ref_filter && fnmatch(data->ref_filter, path, 0)) |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 103 | return 0; |
| 104 | |
Linus Torvalds | 1974632 | 2006-07-11 20:45:31 -0700 | [diff] [blame] | 105 | while (o && o->type == OBJ_TAG) { |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 106 | struct tag *t = (struct tag *) o; |
| 107 | if (!t->tagged) |
| 108 | break; /* broken repository */ |
| 109 | o = parse_object(t->tagged->sha1); |
| 110 | deref = 1; |
| 111 | } |
Linus Torvalds | 1974632 | 2006-07-11 20:45:31 -0700 | [diff] [blame] | 112 | if (o && o->type == OBJ_COMMIT) { |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 113 | struct commit *commit = (struct commit *)o; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 114 | |
Junio C Hamano | cc44c76 | 2007-02-20 01:53:29 -0800 | [diff] [blame] | 115 | if (!prefixcmp(path, "refs/heads/")) |
Junio C Hamano | 2c817df | 2006-01-11 14:20:09 -0800 | [diff] [blame] | 116 | path = path + 11; |
Shawn O. Pearce | 2361570 | 2007-05-21 03:20:25 -0400 | [diff] [blame] | 117 | else if (data->tags_only |
| 118 | && data->name_only |
| 119 | && !prefixcmp(path, "refs/tags/")) |
| 120 | path = path + 10; |
Junio C Hamano | cc44c76 | 2007-02-20 01:53:29 -0800 | [diff] [blame] | 121 | else if (!prefixcmp(path, "refs/")) |
Junio C Hamano | 2c817df | 2006-01-11 14:20:09 -0800 | [diff] [blame] | 122 | path = path + 5; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 123 | |
Shawn Pearce | 9befac4 | 2006-09-02 00:16:31 -0400 | [diff] [blame] | 124 | name_rev(commit, xstrdup(path), 0, 0, deref); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 125 | } |
| 126 | return 0; |
| 127 | } |
| 128 | |
| 129 | /* returns a static buffer */ |
| 130 | static const char* get_rev_name(struct object *o) |
| 131 | { |
| 132 | static char buffer[1024]; |
Linus Torvalds | d3ff6f5 | 2006-06-17 18:26:18 -0700 | [diff] [blame] | 133 | struct rev_name *n; |
| 134 | struct commit *c; |
| 135 | |
Linus Torvalds | 1974632 | 2006-07-11 20:45:31 -0700 | [diff] [blame] | 136 | if (o->type != OBJ_COMMIT) |
Linus Torvalds | d3ff6f5 | 2006-06-17 18:26:18 -0700 | [diff] [blame] | 137 | return "undefined"; |
| 138 | c = (struct commit *) o; |
| 139 | n = c->util; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 140 | if (!n) |
| 141 | return "undefined"; |
| 142 | |
| 143 | if (!n->generation) |
| 144 | return n->tip_name; |
Johannes Schindelin | 59d3f54 | 2007-02-20 01:08:48 +0100 | [diff] [blame] | 145 | else { |
| 146 | int len = strlen(n->tip_name); |
| 147 | if (len > 2 && !strcmp(n->tip_name + len - 2, "^0")) |
| 148 | len -= 2; |
| 149 | snprintf(buffer, sizeof(buffer), "%.*s~%d", len, n->tip_name, |
| 150 | n->generation); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 151 | |
Johannes Schindelin | 59d3f54 | 2007-02-20 01:08:48 +0100 | [diff] [blame] | 152 | return buffer; |
| 153 | } |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 154 | } |
Linus Torvalds | 1f1e895 | 2006-06-19 17:42:35 -0700 | [diff] [blame] | 155 | |
Matthias Kestenholz | d6b64ed | 2006-08-03 17:24:35 +0200 | [diff] [blame] | 156 | int cmd_name_rev(int argc, const char **argv, const char *prefix) |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 157 | { |
Linus Torvalds | 1f1e895 | 2006-06-19 17:42:35 -0700 | [diff] [blame] | 158 | struct object_array revs = { 0, 0, NULL }; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 159 | int as_is = 0, all = 0, transform_stdin = 0; |
Shawn O. Pearce | 2361570 | 2007-05-21 03:20:25 -0400 | [diff] [blame] | 160 | struct name_ref_data data = { 0, 0, NULL }; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 161 | |
Junio C Hamano | 84a9b58 | 2006-03-23 23:41:18 -0800 | [diff] [blame] | 162 | git_config(git_default_config); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 163 | |
| 164 | if (argc < 2) |
| 165 | usage(name_rev_usage); |
| 166 | |
| 167 | for (--argc, ++argv; argc; --argc, ++argv) { |
| 168 | unsigned char sha1[20]; |
| 169 | struct object *o; |
| 170 | struct commit *commit; |
| 171 | |
| 172 | if (!as_is && (*argv)[0] == '-') { |
| 173 | if (!strcmp(*argv, "--")) { |
| 174 | as_is = 1; |
| 175 | continue; |
Shawn O. Pearce | 2361570 | 2007-05-21 03:20:25 -0400 | [diff] [blame] | 176 | } else if (!strcmp(*argv, "--name-only")) { |
| 177 | data.name_only = 1; |
| 178 | continue; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 179 | } else if (!strcmp(*argv, "--tags")) { |
Johannes Schindelin | 2afc29a | 2007-02-17 19:22:35 +0100 | [diff] [blame] | 180 | data.tags_only = 1; |
| 181 | continue; |
Junio C Hamano | cc44c76 | 2007-02-20 01:53:29 -0800 | [diff] [blame] | 182 | } else if (!prefixcmp(*argv, "--refs=")) { |
Johannes Schindelin | 2afc29a | 2007-02-17 19:22:35 +0100 | [diff] [blame] | 183 | data.ref_filter = *argv + 7; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 184 | continue; |
| 185 | } else if (!strcmp(*argv, "--all")) { |
| 186 | if (argc > 1) |
| 187 | die("Specify either a list, or --all, not both!"); |
| 188 | all = 1; |
| 189 | cutoff = 0; |
| 190 | continue; |
| 191 | } else if (!strcmp(*argv, "--stdin")) { |
| 192 | if (argc > 1) |
| 193 | die("Specify either a list, or --stdin, not both!"); |
| 194 | transform_stdin = 1; |
| 195 | cutoff = 0; |
| 196 | continue; |
| 197 | } |
| 198 | usage(name_rev_usage); |
| 199 | } |
| 200 | |
| 201 | if (get_sha1(*argv, sha1)) { |
| 202 | fprintf(stderr, "Could not get sha1 for %s. Skipping.\n", |
| 203 | *argv); |
| 204 | continue; |
| 205 | } |
| 206 | |
Junio C Hamano | 9534f40 | 2005-11-02 15:19:13 -0800 | [diff] [blame] | 207 | o = deref_tag(parse_object(sha1), *argv, 0); |
Linus Torvalds | 1974632 | 2006-07-11 20:45:31 -0700 | [diff] [blame] | 208 | if (!o || o->type != OBJ_COMMIT) { |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 209 | fprintf(stderr, "Could not get commit for %s. Skipping.\n", |
| 210 | *argv); |
| 211 | continue; |
| 212 | } |
| 213 | |
| 214 | commit = (struct commit *)o; |
| 215 | |
| 216 | if (cutoff > commit->date) |
| 217 | cutoff = commit->date; |
| 218 | |
Linus Torvalds | 1f1e895 | 2006-06-19 17:42:35 -0700 | [diff] [blame] | 219 | add_object_array((struct object *)commit, *argv, &revs); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 220 | } |
| 221 | |
Junio C Hamano | c075aea | 2007-05-24 12:20:42 -0700 | [diff] [blame] | 222 | if (cutoff) |
| 223 | cutoff = cutoff - CUTOFF_DATE_SLOP; |
Johannes Schindelin | 2afc29a | 2007-02-17 19:22:35 +0100 | [diff] [blame] | 224 | for_each_ref(name_ref, &data); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 225 | |
| 226 | if (transform_stdin) { |
| 227 | char buffer[2048]; |
| 228 | char *p, *p_start; |
| 229 | |
| 230 | while (!feof(stdin)) { |
| 231 | int forty = 0; |
| 232 | p = fgets(buffer, sizeof(buffer), stdin); |
| 233 | if (!p) |
| 234 | break; |
| 235 | |
| 236 | for (p_start = p; *p; p++) { |
| 237 | #define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f')) |
| 238 | if (!ishex(*p)) |
| 239 | forty = 0; |
| 240 | else if (++forty == 40 && |
| 241 | !ishex(*(p+1))) { |
| 242 | unsigned char sha1[40]; |
| 243 | const char *name = "undefined"; |
| 244 | char c = *(p+1); |
| 245 | |
| 246 | forty = 0; |
| 247 | |
| 248 | *(p+1) = 0; |
| 249 | if (!get_sha1(p - 39, sha1)) { |
| 250 | struct object *o = |
| 251 | lookup_object(sha1); |
| 252 | if (o) |
| 253 | name = get_rev_name(o); |
| 254 | } |
| 255 | *(p+1) = c; |
| 256 | |
| 257 | if (!strcmp(name, "undefined")) |
| 258 | continue; |
| 259 | |
Junio C Hamano | 2d76d0d | 2005-11-25 23:36:58 -0800 | [diff] [blame] | 260 | fwrite(p_start, p - p_start + 1, 1, |
| 261 | stdout); |
| 262 | printf(" (%s)", name); |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 263 | p_start = p + 1; |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | /* flush */ |
| 268 | if (p_start != p) |
| 269 | fwrite(p_start, p - p_start, 1, stdout); |
| 270 | } |
| 271 | } else if (all) { |
Linus Torvalds | fc046a7 | 2006-06-29 21:38:55 -0700 | [diff] [blame] | 272 | int i, max; |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 273 | |
Linus Torvalds | fc046a7 | 2006-06-29 21:38:55 -0700 | [diff] [blame] | 274 | max = get_max_object_index(); |
| 275 | for (i = 0; i < max; i++) { |
| 276 | struct object * obj = get_indexed_object(i); |
| 277 | if (!obj) |
| 278 | continue; |
Shawn O. Pearce | 2361570 | 2007-05-21 03:20:25 -0400 | [diff] [blame] | 279 | if (!data.name_only) |
| 280 | printf("%s ", sha1_to_hex(obj->sha1)); |
| 281 | printf("%s\n", get_rev_name(obj)); |
Linus Torvalds | fc046a7 | 2006-06-29 21:38:55 -0700 | [diff] [blame] | 282 | } |
Linus Torvalds | 1f1e895 | 2006-06-19 17:42:35 -0700 | [diff] [blame] | 283 | } else { |
| 284 | int i; |
Shawn O. Pearce | 2361570 | 2007-05-21 03:20:25 -0400 | [diff] [blame] | 285 | for (i = 0; i < revs.nr; i++) { |
| 286 | if (!data.name_only) |
| 287 | printf("%s ", revs.objects[i].name); |
| 288 | printf("%s\n", get_rev_name(revs.objects[i].item)); |
| 289 | } |
Linus Torvalds | 1f1e895 | 2006-06-19 17:42:35 -0700 | [diff] [blame] | 290 | } |
Johannes Schindelin | bd321bc | 2005-10-26 15:10:20 +0200 | [diff] [blame] | 291 | |
| 292 | return 0; |
| 293 | } |