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