]> git.ipfire.org Git - thirdparty/git.git/blame - rev-parse.c
Add "--flags" and "--no-flags" arguments to git-rev-parse
[thirdparty/git.git] / rev-parse.c
CommitLineData
178cb243
LT
1/*
2 * rev-parse.c
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
6#include "cache.h"
a8be83fe 7#include "commit.h"
960bba0d 8#include "refs.h"
a8be83fe 9
023d66ed
LT
10static 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;
f79b65aa
LT
16static int flags_only = 0;
17static int no_flags = 0;
023d66ed 18
042a4ed7
LT
19#define NORMAL 0
20#define REVERSED 1
21static int show_type = NORMAL;
22
a8be83fe 23static int get_extended_sha1(char *name, unsigned char *sha1);
178cb243 24
921d865e
LT
25/*
26 * Some arguments are relevant "revision" arguments,
27 * others are about output format or other details.
28 * This sorts it all out.
29 */
30static int is_rev_argument(const char *arg)
31{
32 static const char *rev_args[] = {
33 "--max-count=",
34 "--max-age=",
35 "--min-age=",
36 "--merge-order",
37 NULL
38 };
39 const char **p = rev_args;
40
41 for (;;) {
42 const char *str = *p++;
43 int len;
44 if (!str)
45 return 0;
46 len = strlen(str);
47 if (!strncmp(arg, str, len))
48 return 1;
49 }
50}
51
960bba0d 52static void show_rev(int type, const unsigned char *sha1)
023d66ed
LT
53{
54 if (no_revs)
55 return;
56 output_revs++;
042a4ed7 57 printf("%s%s\n", type == show_type ? "" : "^", sha1_to_hex(sha1));
023d66ed
LT
58}
59
60static void show_rev_arg(char *rev)
61{
62 if (no_revs)
63 return;
64 puts(rev);
65}
66
67static void show_norev(char *norev)
68{
f79b65aa
LT
69 if (flags_only)
70 return;
023d66ed
LT
71 if (revs_only)
72 return;
73 puts(norev);
74}
75
76static void show_arg(char *arg)
77{
f79b65aa
LT
78 if (no_flags)
79 return;
023d66ed
LT
80 if (do_rev_argument && is_rev_argument(arg))
81 show_rev_arg(arg);
82 else
83 show_norev(arg);
84}
85
a8be83fe
LT
86static int get_parent(char *name, unsigned char *result, int idx)
87{
88 unsigned char sha1[20];
89 int ret = get_extended_sha1(name, sha1);
90 struct commit *commit;
91 struct commit_list *p;
92
93 if (ret)
94 return ret;
95 commit = lookup_commit_reference(sha1);
96 if (!commit)
97 return -1;
98 if (parse_commit(commit))
99 return -1;
100 p = commit->parents;
101 while (p) {
102 if (!--idx) {
103 memcpy(result, p->item->object.sha1, 20);
104 return 0;
105 }
106 p = p->next;
107 }
108 return -1;
109}
110
5736bef1
LT
111static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
112{
113 static char dirname[PATH_MAX];
114 char hex[40];
115 DIR *dir;
116 int found;
117
118 snprintf(dirname, sizeof(dirname), "%s/%.2s", get_object_directory(), name);
119 dir = opendir(dirname);
120 sprintf(hex, "%.2s", name);
121 found = 0;
122 if (dir) {
123 struct dirent *de;
124 while ((de = readdir(dir)) != NULL) {
125 if (strlen(de->d_name) != 38)
126 continue;
127 if (memcmp(de->d_name, name + 2, len-2))
128 continue;
129 memcpy(hex + 2, de->d_name, 38);
130 if (++found > 1)
131 break;
132 }
133 closedir(dir);
134 }
135 if (found == 1)
136 return get_sha1_hex(hex, sha1) == 0;
137 return 0;
138}
139
671fe4bb
LT
140static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)
141{
142 do {
143 if (*a != *b)
144 return 0;
145 a++;
146 b++;
147 len -= 2;
148 } while (len > 1);
149 if (len)
150 if ((*a ^ *b) & 0xf0)
151 return 0;
152 return 1;
153}
154
5736bef1
LT
155static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)
156{
671fe4bb
LT
157 struct packed_git *p;
158
159 prepare_packed_git();
160 for (p = packed_git; p; p = p->next) {
161 unsigned num = num_packed_objects(p);
162 unsigned first = 0, last = num;
163 while (first < last) {
164 unsigned mid = (first + last) / 2;
165 unsigned char now[20];
166 int cmp;
167
168 nth_packed_object_sha1(p, mid, now);
169 cmp = memcmp(match, now, 20);
170 if (!cmp) {
171 first = mid;
172 break;
173 }
174 if (cmp > 0) {
175 first = mid+1;
176 continue;
177 }
178 last = mid;
179 }
180 if (first < num) {
181 unsigned char now[20], next[20];
182 nth_packed_object_sha1(p, first, now);
183 if (match_sha(len, match, now)) {
184 if (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) {
185 memcpy(sha1, now, 20);
186 return 1;
187 }
188 }
189 }
190 }
5736bef1
LT
191 return 0;
192}
193
194static int get_short_sha1(char *name, unsigned char *sha1)
195{
196 int i;
197 char canonical[40];
198 unsigned char res[20];
199
200 memset(res, 0, 20);
201 memset(canonical, 'x', 40);
202 for (i = 0;;i++) {
203 unsigned char c = name[i];
204 unsigned char val;
205 if (!c || i > 40)
206 break;
207 if (c >= '0' && c <= '9')
208 val = c - '0';
209 else if (c >= 'a' && c <= 'f')
210 val = c - 'a' + 10;
211 else if (c >= 'A' && c <='F') {
212 val = c - 'A' + 10;
213 c -= 'A' - 'a';
214 }
215 else
216 return -1;
217 canonical[i] = c;
218 if (!(i & 1))
219 val <<= 4;
220 res[i >> 1] |= val;
221 }
222 if (i < 4)
223 return -1;
224 if (find_short_object_filename(i, canonical, sha1))
225 return 0;
226 if (find_short_packed_object(i, res, sha1))
227 return 0;
228 return -1;
229}
230
a8be83fe
LT
231/*
232 * This is like "get_sha1()", except it allows "sha1 expressions",
218e441d 233 * notably "xyz^" for "parent of xyz"
a8be83fe
LT
234 */
235static int get_extended_sha1(char *name, unsigned char *sha1)
236{
5736bef1 237 int parent, ret;
a8be83fe
LT
238 int len = strlen(name);
239
240 parent = 1;
218e441d 241 if (len > 2 && name[len-1] >= '1' && name[len-1] <= '9') {
a8be83fe
LT
242 parent = name[len-1] - '0';
243 len--;
244 }
218e441d 245 if (len > 1 && name[len-1] == '^') {
218e441d 246 name[len-1] = 0;
a8be83fe 247 ret = get_parent(name, sha1, parent);
218e441d 248 name[len-1] = '^';
a8be83fe
LT
249 if (!ret)
250 return 0;
251 }
5736bef1
LT
252 ret = get_sha1(name, sha1);
253 if (!ret)
254 return 0;
255 return get_short_sha1(name, sha1);
a8be83fe
LT
256}
257
023d66ed
LT
258static void show_default(void)
259{
260 char *s = def;
261
262 if (s) {
263 unsigned char sha1[20];
264
265 def = NULL;
266 if (!get_extended_sha1(s, sha1)) {
042a4ed7 267 show_rev(NORMAL, sha1);
023d66ed
LT
268 return;
269 }
270 show_arg(s);
271 }
272}
273
960bba0d
LT
274static int show_reference(const char *refname, const unsigned char *sha1)
275{
276 show_rev(NORMAL, sha1);
277 return 0;
278}
279
178cb243
LT
280int main(int argc, char **argv)
281{
023d66ed 282 int i, as_is = 0;
178cb243
LT
283 unsigned char sha1[20];
284
285 for (i = 1; i < argc; i++) {
286 char *arg = argv[i];
287 char *dotdot;
288
289 if (as_is) {
023d66ed 290 show_norev(arg);
178cb243
LT
291 continue;
292 }
293 if (*arg == '-') {
294 if (!strcmp(arg, "--")) {
023d66ed 295 show_default();
8ebb0184
LT
296 if (revs_only)
297 break;
178cb243
LT
298 as_is = 1;
299 }
300 if (!strcmp(arg, "--default")) {
178cb243
LT
301 def = argv[i+1];
302 i++;
303 continue;
304 }
8ebb0184
LT
305 if (!strcmp(arg, "--revs-only")) {
306 revs_only = 1;
307 continue;
308 }
309 if (!strcmp(arg, "--no-revs")) {
310 no_revs = 1;
311 continue;
312 }
f79b65aa
LT
313 if (!strcmp(arg, "--flags")) {
314 flags_only = 1;
315 continue;
316 }
317 if (!strcmp(arg, "--no-flags")) {
318 no_flags = 1;
319 continue;
320 }
023d66ed
LT
321 if (!strcmp(arg, "--verify")) {
322 revs_only = 1;
323 do_rev_argument = 0;
324 single_rev = 1;
325 continue;
921d865e 326 }
042a4ed7
LT
327 if (!strcmp(arg, "--not")) {
328 show_type ^= REVERSED;
329 continue;
330 }
960bba0d
LT
331 if (!strcmp(arg, "--all")) {
332 for_each_ref(show_reference);
333 continue;
334 }
023d66ed 335 show_arg(arg);
178cb243
LT
336 continue;
337 }
178cb243
LT
338 dotdot = strstr(arg, "..");
339 if (dotdot) {
340 unsigned char end[20];
341 char *n = dotdot+2;
342 *dotdot = 0;
a8be83fe 343 if (!get_extended_sha1(arg, sha1)) {
178cb243
LT
344 if (!*n)
345 n = "HEAD";
a8be83fe 346 if (!get_extended_sha1(n, end)) {
8ebb0184
LT
347 if (no_revs)
348 continue;
349 def = NULL;
042a4ed7
LT
350 show_rev(NORMAL, end);
351 show_rev(REVERSED, sha1);
178cb243
LT
352 continue;
353 }
354 }
355 *dotdot = '.';
356 }
a8be83fe 357 if (!get_extended_sha1(arg, sha1)) {
800644c5
LT
358 if (no_revs)
359 continue;
360 def = NULL;
042a4ed7 361 show_rev(NORMAL, sha1);
800644c5
LT
362 continue;
363 }
a8be83fe 364 if (*arg == '^' && !get_extended_sha1(arg+1, sha1)) {
800644c5
LT
365 if (no_revs)
366 continue;
367 def = NULL;
042a4ed7 368 show_rev(REVERSED, sha1);
800644c5
LT
369 continue;
370 }
023d66ed
LT
371 show_default();
372 show_norev(arg);
373 }
374 show_default();
375 if (single_rev && output_revs != 1) {
376 fprintf(stderr, "Needed a single revision\n");
377 exit(1);
178cb243 378 }
178cb243
LT
379 return 0;
380}