| Johannes Schindelin | bd321bc | 2005-10-26 13:10:20 | [diff] [blame] | 1 | #include <stdlib.h> |
| 2 | #include "cache.h" |
| 3 | #include "commit.h" |
| 4 | #include "tag.h" |
| 5 | #include "refs.h" |
| 6 | |
| 7 | static const char name_rev_usage[] = |
| 8 | "git-name-rev [--tags] ( --all | --stdin | commitish [commitish...] )\n"; |
| 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 | { |
| 22 | struct rev_name *name = (struct rev_name *)commit->object.util; |
| 23 | struct commit_list *parents; |
| Junio C Hamano | f2e6f1c | 2005-11-29 04:51:44 | [diff] [blame] | 24 | int parent_number = 1; |
| Johannes Schindelin | bd321bc | 2005-10-26 13:10:20 | [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)); |
| 44 | commit->object.util = name; |
| 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-29 04:51:44 | [diff] [blame] | 59 | if (parent_number > 1) { |
| Johannes Schindelin | bd321bc | 2005-10-26 13:10:20 | [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 | |
| 77 | static int tags_only = 0; |
| 78 | |
| 79 | static int name_ref(const char *path, const unsigned char *sha1) |
| 80 | { |
| 81 | struct object *o = parse_object(sha1); |
| 82 | int deref = 0; |
| 83 | |
| 84 | if (tags_only && strncmp(path, "refs/tags/", 10)) |
| 85 | return 0; |
| 86 | |
| 87 | while (o && o->type == tag_type) { |
| 88 | struct tag *t = (struct tag *) o; |
| 89 | if (!t->tagged) |
| 90 | break; /* broken repository */ |
| 91 | o = parse_object(t->tagged->sha1); |
| 92 | deref = 1; |
| 93 | } |
| 94 | if (o && o->type == commit_type) { |
| 95 | struct commit *commit = (struct commit *)o; |
| Johannes Schindelin | bd321bc | 2005-10-26 13:10:20 | [diff] [blame] | 96 | |
| Junio C Hamano | 2c817df | 2006-01-11 22:20:09 | [diff] [blame] | 97 | if (!strncmp(path, "refs/heads/", 11)) |
| 98 | path = path + 11; |
| 99 | else if (!strncmp(path, "refs/", 5)) |
| 100 | path = path + 5; |
| Johannes Schindelin | bd321bc | 2005-10-26 13:10:20 | [diff] [blame] | 101 | |
| 102 | name_rev(commit, strdup(path), 0, 0, deref); |
| 103 | } |
| 104 | return 0; |
| 105 | } |
| 106 | |
| 107 | /* returns a static buffer */ |
| 108 | static const char* get_rev_name(struct object *o) |
| 109 | { |
| 110 | static char buffer[1024]; |
| 111 | struct rev_name *n = (struct rev_name *)o->util; |
| 112 | if (!n) |
| 113 | return "undefined"; |
| 114 | |
| 115 | if (!n->generation) |
| 116 | return n->tip_name; |
| 117 | |
| 118 | snprintf(buffer, sizeof(buffer), "%s~%d", n->tip_name, n->generation); |
| 119 | |
| 120 | return buffer; |
| 121 | } |
| 122 | |
| 123 | int main(int argc, char **argv) |
| 124 | { |
| 125 | struct object_list *revs = NULL; |
| 126 | struct object_list **walker = &revs; |
| 127 | int as_is = 0, all = 0, transform_stdin = 0; |
| 128 | |
| 129 | setup_git_directory(); |
| 130 | |
| 131 | if (argc < 2) |
| 132 | usage(name_rev_usage); |
| 133 | |
| 134 | for (--argc, ++argv; argc; --argc, ++argv) { |
| 135 | unsigned char sha1[20]; |
| 136 | struct object *o; |
| 137 | struct commit *commit; |
| 138 | |
| 139 | if (!as_is && (*argv)[0] == '-') { |
| 140 | if (!strcmp(*argv, "--")) { |
| 141 | as_is = 1; |
| 142 | continue; |
| 143 | } else if (!strcmp(*argv, "--tags")) { |
| 144 | tags_only = 1; |
| 145 | continue; |
| 146 | } else if (!strcmp(*argv, "--all")) { |
| 147 | if (argc > 1) |
| 148 | die("Specify either a list, or --all, not both!"); |
| 149 | all = 1; |
| 150 | cutoff = 0; |
| 151 | continue; |
| 152 | } else if (!strcmp(*argv, "--stdin")) { |
| 153 | if (argc > 1) |
| 154 | die("Specify either a list, or --stdin, not both!"); |
| 155 | transform_stdin = 1; |
| 156 | cutoff = 0; |
| 157 | continue; |
| 158 | } |
| 159 | usage(name_rev_usage); |
| 160 | } |
| 161 | |
| 162 | if (get_sha1(*argv, sha1)) { |
| 163 | fprintf(stderr, "Could not get sha1 for %s. Skipping.\n", |
| 164 | *argv); |
| 165 | continue; |
| 166 | } |
| 167 | |
| Junio C Hamano | 9534f40 | 2005-11-02 23:19:13 | [diff] [blame] | 168 | o = deref_tag(parse_object(sha1), *argv, 0); |
| Johannes Schindelin | bd321bc | 2005-10-26 13:10:20 | [diff] [blame] | 169 | if (!o || o->type != commit_type) { |
| 170 | fprintf(stderr, "Could not get commit for %s. Skipping.\n", |
| 171 | *argv); |
| 172 | continue; |
| 173 | } |
| 174 | |
| 175 | commit = (struct commit *)o; |
| 176 | |
| 177 | if (cutoff > commit->date) |
| 178 | cutoff = commit->date; |
| 179 | |
| 180 | object_list_append((struct object *)commit, walker); |
| 181 | (*walker)->name = *argv; |
| 182 | walker = &((*walker)->next); |
| 183 | } |
| 184 | |
| 185 | for_each_ref(name_ref); |
| 186 | |
| 187 | if (transform_stdin) { |
| 188 | char buffer[2048]; |
| 189 | char *p, *p_start; |
| 190 | |
| 191 | while (!feof(stdin)) { |
| 192 | int forty = 0; |
| 193 | p = fgets(buffer, sizeof(buffer), stdin); |
| 194 | if (!p) |
| 195 | break; |
| 196 | |
| 197 | for (p_start = p; *p; p++) { |
| 198 | #define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f')) |
| 199 | if (!ishex(*p)) |
| 200 | forty = 0; |
| 201 | else if (++forty == 40 && |
| 202 | !ishex(*(p+1))) { |
| 203 | unsigned char sha1[40]; |
| 204 | const char *name = "undefined"; |
| 205 | char c = *(p+1); |
| 206 | |
| 207 | forty = 0; |
| 208 | |
| 209 | *(p+1) = 0; |
| 210 | if (!get_sha1(p - 39, sha1)) { |
| 211 | struct object *o = |
| 212 | lookup_object(sha1); |
| 213 | if (o) |
| 214 | name = get_rev_name(o); |
| 215 | } |
| 216 | *(p+1) = c; |
| 217 | |
| 218 | if (!strcmp(name, "undefined")) |
| 219 | continue; |
| 220 | |
| Junio C Hamano | 2d76d0d | 2005-11-26 07:36:58 | [diff] [blame] | 221 | fwrite(p_start, p - p_start + 1, 1, |
| 222 | stdout); |
| 223 | printf(" (%s)", name); |
| Johannes Schindelin | bd321bc | 2005-10-26 13:10:20 | [diff] [blame] | 224 | p_start = p + 1; |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | /* flush */ |
| 229 | if (p_start != p) |
| 230 | fwrite(p_start, p - p_start, 1, stdout); |
| 231 | } |
| 232 | } else if (all) { |
| Johannes Schindelin | bd321bc | 2005-10-26 13:10:20 | [diff] [blame] | 233 | int i; |
| 234 | |
| 235 | for (i = 0; i < nr_objs; i++) |
| 236 | printf("%s %s\n", sha1_to_hex(objs[i]->sha1), |
| 237 | get_rev_name(objs[i])); |
| 238 | } else |
| 239 | for ( ; revs; revs = revs->next) |
| 240 | printf("%s %s\n", revs->name, get_rev_name(revs->item)); |
| 241 | |
| 242 | return 0; |
| 243 | } |
| 244 | |