🌐 AI搜索 & 代理 主页
blob: 4bd58ebb67358b5640a7c89a24477c80c84ae7f4 [file] [log] [blame]
Linus Torvalds178cb242005-06-13 17:06:501/*
2 * rev-parse.c
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
6#include "cache.h"
Linus Torvaldsa8be83f2005-06-21 03:28:097#include "commit.h"
Linus Torvalds960bba02005-07-03 20:07:528#include "refs.h"
Linus Torvaldsa8be83f2005-06-21 03:28:099
Linus Torvalds023d66e2005-06-24 17:12:5510static char *def = NULL;
11static int no_revs = 0;
12static int single_rev = 0;
13static int revs_only = 0;
14static int do_rev_argument = 1;
15static int output_revs = 0;
Linus Torvaldsf79b65a2005-07-06 17:08:0816static int flags_only = 0;
17static int no_flags = 0;
Junio C Hamano5bb2c652005-07-23 02:08:3218static int output_sq = 0;
Linus Torvalds023d66e2005-06-24 17:12:5519
Linus Torvalds042a4ed2005-06-26 18:34:3020#define NORMAL 0
21#define REVERSED 1
22static int show_type = NORMAL;
23
Linus Torvaldsa8be83f2005-06-21 03:28:0924static int get_extended_sha1(char *name, unsigned char *sha1);
Linus Torvalds178cb242005-06-13 17:06:5025
Linus Torvalds921d8652005-06-13 18:14:2026/*
27 * Some arguments are relevant "revision" arguments,
28 * others are about output format or other details.
29 * This sorts it all out.
30 */
31static int is_rev_argument(const char *arg)
32{
33 static const char *rev_args[] = {
34 "--max-count=",
35 "--max-age=",
36 "--min-age=",
37 "--merge-order",
38 NULL
39 };
40 const char **p = rev_args;
41
42 for (;;) {
43 const char *str = *p++;
44 int len;
45 if (!str)
46 return 0;
47 len = strlen(str);
48 if (!strncmp(arg, str, len))
49 return 1;
50 }
51}
52
Junio C Hamano5bb2c652005-07-23 02:08:3253static void show(const char *arg)
54{
55 if (output_sq) {
56 int sq = '\'', ch;
57
58 putchar(sq);
59 while ((ch = *arg++)) {
60 if (ch == sq)
61 fputs("'\\'", stdout);
62 putchar(ch);
63 }
64 putchar(sq);
65 putchar(' ');
66 }
67 else
68 puts(arg);
69}
70
Linus Torvalds960bba02005-07-03 20:07:5271static void show_rev(int type, const unsigned char *sha1)
Linus Torvalds023d66e2005-06-24 17:12:5572{
73 if (no_revs)
74 return;
75 output_revs++;
Junio C Hamano5bb2c652005-07-23 02:08:3276
77 /* Hexadecimal string plus possibly a carret;
78 * this does not have to be quoted even under output_sq.
79 */
80 printf("%s%s%c", type == show_type ? "" : "^", sha1_to_hex(sha1),
81 output_sq ? ' ' : '\n');
Linus Torvalds023d66e2005-06-24 17:12:5582}
83
84static void show_rev_arg(char *rev)
85{
86 if (no_revs)
87 return;
Junio C Hamano5bb2c652005-07-23 02:08:3288 show(rev);
Linus Torvalds023d66e2005-06-24 17:12:5589}
90
91static void show_norev(char *norev)
92{
Linus Torvaldsf79b65a2005-07-06 17:08:0893 if (flags_only)
94 return;
Linus Torvalds023d66e2005-06-24 17:12:5595 if (revs_only)
96 return;
Junio C Hamano5bb2c652005-07-23 02:08:3297 show(norev);
Linus Torvalds023d66e2005-06-24 17:12:5598}
99
100static void show_arg(char *arg)
101{
Linus Torvaldsf79b65a2005-07-06 17:08:08102 if (no_flags)
103 return;
Linus Torvalds023d66e2005-06-24 17:12:55104 if (do_rev_argument && is_rev_argument(arg))
105 show_rev_arg(arg);
106 else
107 show_norev(arg);
108}
109
Linus Torvaldsa8be83f2005-06-21 03:28:09110static int get_parent(char *name, unsigned char *result, int idx)
111{
112 unsigned char sha1[20];
113 int ret = get_extended_sha1(name, sha1);
114 struct commit *commit;
115 struct commit_list *p;
116
117 if (ret)
118 return ret;
119 commit = lookup_commit_reference(sha1);
120 if (!commit)
121 return -1;
122 if (parse_commit(commit))
123 return -1;
Linus Torvalds79162bb2005-07-12 01:27:25124 if (!idx) {
125 memcpy(result, commit->object.sha1, 20);
126 return 0;
127 }
Linus Torvaldsa8be83f2005-06-21 03:28:09128 p = commit->parents;
129 while (p) {
130 if (!--idx) {
131 memcpy(result, p->item->object.sha1, 20);
132 return 0;
133 }
134 p = p->next;
135 }
136 return -1;
137}
138
Linus Torvalds5736bef2005-07-04 03:27:06139static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
140{
141 static char dirname[PATH_MAX];
142 char hex[40];
143 DIR *dir;
144 int found;
145
146 snprintf(dirname, sizeof(dirname), "%s/%.2s", get_object_directory(), name);
147 dir = opendir(dirname);
148 sprintf(hex, "%.2s", name);
149 found = 0;
150 if (dir) {
151 struct dirent *de;
152 while ((de = readdir(dir)) != NULL) {
153 if (strlen(de->d_name) != 38)
154 continue;
155 if (memcmp(de->d_name, name + 2, len-2))
156 continue;
157 memcpy(hex + 2, de->d_name, 38);
158 if (++found > 1)
159 break;
160 }
161 closedir(dir);
162 }
163 if (found == 1)
164 return get_sha1_hex(hex, sha1) == 0;
165 return 0;
166}
167
Linus Torvalds671fe4b2005-07-04 04:01:11168static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)
169{
170 do {
171 if (*a != *b)
172 return 0;
173 a++;
174 b++;
175 len -= 2;
176 } while (len > 1);
177 if (len)
178 if ((*a ^ *b) & 0xf0)
179 return 0;
180 return 1;
181}
182
Linus Torvalds5736bef2005-07-04 03:27:06183static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)
184{
Linus Torvalds671fe4b2005-07-04 04:01:11185 struct packed_git *p;
186
187 prepare_packed_git();
188 for (p = packed_git; p; p = p->next) {
189 unsigned num = num_packed_objects(p);
190 unsigned first = 0, last = num;
191 while (first < last) {
192 unsigned mid = (first + last) / 2;
193 unsigned char now[20];
194 int cmp;
195
196 nth_packed_object_sha1(p, mid, now);
197 cmp = memcmp(match, now, 20);
198 if (!cmp) {
199 first = mid;
200 break;
201 }
202 if (cmp > 0) {
203 first = mid+1;
204 continue;
205 }
206 last = mid;
207 }
208 if (first < num) {
209 unsigned char now[20], next[20];
210 nth_packed_object_sha1(p, first, now);
211 if (match_sha(len, match, now)) {
212 if (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) {
213 memcpy(sha1, now, 20);
214 return 1;
215 }
216 }
217 }
218 }
Linus Torvalds5736bef2005-07-04 03:27:06219 return 0;
220}
221
222static int get_short_sha1(char *name, unsigned char *sha1)
223{
224 int i;
225 char canonical[40];
226 unsigned char res[20];
227
228 memset(res, 0, 20);
229 memset(canonical, 'x', 40);
230 for (i = 0;;i++) {
231 unsigned char c = name[i];
232 unsigned char val;
233 if (!c || i > 40)
234 break;
235 if (c >= '0' && c <= '9')
236 val = c - '0';
237 else if (c >= 'a' && c <= 'f')
238 val = c - 'a' + 10;
239 else if (c >= 'A' && c <='F') {
240 val = c - 'A' + 10;
241 c -= 'A' - 'a';
242 }
243 else
244 return -1;
245 canonical[i] = c;
246 if (!(i & 1))
247 val <<= 4;
248 res[i >> 1] |= val;
249 }
250 if (i < 4)
251 return -1;
252 if (find_short_object_filename(i, canonical, sha1))
253 return 0;
254 if (find_short_packed_object(i, res, sha1))
255 return 0;
256 return -1;
257}
258
Linus Torvaldsa8be83f2005-06-21 03:28:09259/*
260 * This is like "get_sha1()", except it allows "sha1 expressions",
Linus Torvalds218e4412005-06-21 04:06:47261 * notably "xyz^" for "parent of xyz"
Linus Torvaldsa8be83f2005-06-21 03:28:09262 */
263static int get_extended_sha1(char *name, unsigned char *sha1)
264{
Linus Torvalds5736bef2005-07-04 03:27:06265 int parent, ret;
Linus Torvaldsa8be83f2005-06-21 03:28:09266 int len = strlen(name);
267
268 parent = 1;
Linus Torvalds79162bb2005-07-12 01:27:25269 if (len > 2 && name[len-1] >= '0' && name[len-1] <= '9') {
Linus Torvaldsa8be83f2005-06-21 03:28:09270 parent = name[len-1] - '0';
271 len--;
272 }
Linus Torvalds218e4412005-06-21 04:06:47273 if (len > 1 && name[len-1] == '^') {
Linus Torvalds218e4412005-06-21 04:06:47274 name[len-1] = 0;
Linus Torvaldsa8be83f2005-06-21 03:28:09275 ret = get_parent(name, sha1, parent);
Linus Torvalds218e4412005-06-21 04:06:47276 name[len-1] = '^';
Linus Torvaldsa8be83f2005-06-21 03:28:09277 if (!ret)
278 return 0;
279 }
Linus Torvalds5736bef2005-07-04 03:27:06280 ret = get_sha1(name, sha1);
281 if (!ret)
282 return 0;
283 return get_short_sha1(name, sha1);
Linus Torvaldsa8be83f2005-06-21 03:28:09284}
285
Linus Torvalds023d66e2005-06-24 17:12:55286static void show_default(void)
287{
288 char *s = def;
289
290 if (s) {
291 unsigned char sha1[20];
292
293 def = NULL;
294 if (!get_extended_sha1(s, sha1)) {
Linus Torvalds042a4ed2005-06-26 18:34:30295 show_rev(NORMAL, sha1);
Linus Torvalds023d66e2005-06-24 17:12:55296 return;
297 }
298 show_arg(s);
299 }
300}
301
Linus Torvalds960bba02005-07-03 20:07:52302static int show_reference(const char *refname, const unsigned char *sha1)
303{
304 show_rev(NORMAL, sha1);
305 return 0;
306}
307
Linus Torvalds178cb242005-06-13 17:06:50308int main(int argc, char **argv)
309{
Linus Torvalds023d66e2005-06-24 17:12:55310 int i, as_is = 0;
Linus Torvalds178cb242005-06-13 17:06:50311 unsigned char sha1[20];
312
313 for (i = 1; i < argc; i++) {
314 char *arg = argv[i];
315 char *dotdot;
316
317 if (as_is) {
Linus Torvalds023d66e2005-06-24 17:12:55318 show_norev(arg);
Linus Torvalds178cb242005-06-13 17:06:50319 continue;
320 }
321 if (*arg == '-') {
322 if (!strcmp(arg, "--")) {
Linus Torvalds023d66e2005-06-24 17:12:55323 show_default();
Linus Torvalds8ebb0182005-06-13 17:21:11324 if (revs_only)
325 break;
Linus Torvalds178cb242005-06-13 17:06:50326 as_is = 1;
327 }
328 if (!strcmp(arg, "--default")) {
Linus Torvalds178cb242005-06-13 17:06:50329 def = argv[i+1];
330 i++;
331 continue;
332 }
Linus Torvalds8ebb0182005-06-13 17:21:11333 if (!strcmp(arg, "--revs-only")) {
334 revs_only = 1;
335 continue;
336 }
337 if (!strcmp(arg, "--no-revs")) {
338 no_revs = 1;
339 continue;
340 }
Linus Torvaldsf79b65a2005-07-06 17:08:08341 if (!strcmp(arg, "--flags")) {
342 flags_only = 1;
343 continue;
344 }
345 if (!strcmp(arg, "--no-flags")) {
346 no_flags = 1;
347 continue;
348 }
Linus Torvalds023d66e2005-06-24 17:12:55349 if (!strcmp(arg, "--verify")) {
350 revs_only = 1;
351 do_rev_argument = 0;
352 single_rev = 1;
353 continue;
Linus Torvalds921d8652005-06-13 18:14:20354 }
Junio C Hamano5bb2c652005-07-23 02:08:32355 if (!strcmp(arg, "--sq")) {
356 output_sq = 1;
357 continue;
358 }
Linus Torvalds042a4ed2005-06-26 18:34:30359 if (!strcmp(arg, "--not")) {
360 show_type ^= REVERSED;
361 continue;
362 }
Linus Torvalds960bba02005-07-03 20:07:52363 if (!strcmp(arg, "--all")) {
364 for_each_ref(show_reference);
365 continue;
366 }
Linus Torvalds023d66e2005-06-24 17:12:55367 show_arg(arg);
Linus Torvalds178cb242005-06-13 17:06:50368 continue;
369 }
Linus Torvalds178cb242005-06-13 17:06:50370 dotdot = strstr(arg, "..");
371 if (dotdot) {
372 unsigned char end[20];
373 char *n = dotdot+2;
374 *dotdot = 0;
Linus Torvaldsa8be83f2005-06-21 03:28:09375 if (!get_extended_sha1(arg, sha1)) {
Linus Torvalds178cb242005-06-13 17:06:50376 if (!*n)
377 n = "HEAD";
Linus Torvaldsa8be83f2005-06-21 03:28:09378 if (!get_extended_sha1(n, end)) {
Linus Torvalds8ebb0182005-06-13 17:21:11379 if (no_revs)
380 continue;
381 def = NULL;
Linus Torvalds042a4ed2005-06-26 18:34:30382 show_rev(NORMAL, end);
383 show_rev(REVERSED, sha1);
Linus Torvalds178cb242005-06-13 17:06:50384 continue;
385 }
386 }
387 *dotdot = '.';
388 }
Linus Torvaldsa8be83f2005-06-21 03:28:09389 if (!get_extended_sha1(arg, sha1)) {
Linus Torvalds800644c2005-06-20 15:29:13390 if (no_revs)
391 continue;
392 def = NULL;
Linus Torvalds042a4ed2005-06-26 18:34:30393 show_rev(NORMAL, sha1);
Linus Torvalds800644c2005-06-20 15:29:13394 continue;
395 }
Linus Torvaldsa8be83f2005-06-21 03:28:09396 if (*arg == '^' && !get_extended_sha1(arg+1, sha1)) {
Linus Torvalds800644c2005-06-20 15:29:13397 if (no_revs)
398 continue;
399 def = NULL;
Linus Torvalds042a4ed2005-06-26 18:34:30400 show_rev(REVERSED, sha1);
Linus Torvalds800644c2005-06-20 15:29:13401 continue;
402 }
Linus Torvalds023d66e2005-06-24 17:12:55403 show_default();
404 show_norev(arg);
Linus Torvalds178cb242005-06-13 17:06:50405 }
Linus Torvalds023d66e2005-06-24 17:12:55406 show_default();
407 if (single_rev && output_revs != 1) {
408 fprintf(stderr, "Needed a single revision\n");
409 exit(1);
410 }
Linus Torvalds178cb242005-06-13 17:06:50411 return 0;
412}