Add "--all" flag to rev-parse that shows all refs
[git.git] / rev-parse.c
1 /*
2  * rev-parse.c
3  *
4  * Copyright (C) Linus Torvalds, 2005
5  */
6 #include "cache.h"
7 #include "commit.h"
8 #include "refs.h"
9
10 static char *def = NULL;
11 static int no_revs = 0;
12 static int single_rev = 0;
13 static int revs_only = 0;
14 static int do_rev_argument = 1;
15 static int output_revs = 0;
16
17 #define NORMAL 0
18 #define REVERSED 1
19 static int show_type = NORMAL;
20
21 static int get_extended_sha1(char *name, unsigned char *sha1);
22
23 /*
24  * Some arguments are relevant "revision" arguments,
25  * others are about output format or other details.
26  * This sorts it all out.
27  */
28 static int is_rev_argument(const char *arg)
29 {
30         static const char *rev_args[] = {
31                 "--max-count=",
32                 "--max-age=",
33                 "--min-age=",
34                 "--merge-order",
35                 NULL
36         };
37         const char **p = rev_args;
38
39         for (;;) {
40                 const char *str = *p++;
41                 int len;
42                 if (!str)
43                         return 0;
44                 len = strlen(str);
45                 if (!strncmp(arg, str, len))
46                         return 1;
47         }
48 }
49
50 static void show_rev(int type, const unsigned char *sha1)
51 {
52         if (no_revs)
53                 return;
54         output_revs++;
55         printf("%s%s\n", type == show_type ? "" : "^", sha1_to_hex(sha1));
56 }
57
58 static void show_rev_arg(char *rev)
59 {
60         if (no_revs)
61                 return;
62         puts(rev);
63 }
64
65 static void show_norev(char *norev)
66 {
67         if (revs_only)
68                 return;
69         puts(norev);
70 }
71
72 static void show_arg(char *arg)
73 {
74         if (do_rev_argument && is_rev_argument(arg))
75                 show_rev_arg(arg);
76         else
77                 show_norev(arg);
78 }
79
80 static int get_parent(char *name, unsigned char *result, int idx)
81 {
82         unsigned char sha1[20];
83         int ret = get_extended_sha1(name, sha1);
84         struct commit *commit;
85         struct commit_list *p;
86
87         if (ret)
88                 return ret;
89         commit = lookup_commit_reference(sha1);
90         if (!commit)
91                 return -1;
92         if (parse_commit(commit))
93                 return -1;
94         p = commit->parents;
95         while (p) {
96                 if (!--idx) {
97                         memcpy(result, p->item->object.sha1, 20);
98                         return 0;
99                 }
100                 p = p->next;
101         }
102         return -1;
103 }
104
105 /*
106  * This is like "get_sha1()", except it allows "sha1 expressions",
107  * notably "xyz^" for "parent of xyz"
108  */
109 static int get_extended_sha1(char *name, unsigned char *sha1)
110 {
111         int parent;
112         int len = strlen(name);
113
114         parent = 1;
115         if (len > 2 && name[len-1] >= '1' && name[len-1] <= '9') {
116                 parent = name[len-1] - '0';
117                 len--;
118         }
119         if (len > 1 && name[len-1] == '^') {
120                 int ret;
121                 name[len-1] = 0;
122                 ret = get_parent(name, sha1, parent);
123                 name[len-1] = '^';
124                 if (!ret)
125                         return 0;
126         }
127         return get_sha1(name, sha1);
128 }
129
130 static void show_default(void)
131 {
132         char *s = def;
133
134         if (s) {
135                 unsigned char sha1[20];
136
137                 def = NULL;
138                 if (!get_extended_sha1(s, sha1)) {
139                         show_rev(NORMAL, sha1);
140                         return;
141                 }
142                 show_arg(s);
143         }
144 }
145
146 static int show_reference(const char *refname, const unsigned char *sha1)
147 {
148         show_rev(NORMAL, sha1);
149         return 0;
150 }
151
152 int main(int argc, char **argv)
153 {
154         int i, as_is = 0;
155         unsigned char sha1[20];
156
157         for (i = 1; i < argc; i++) {
158                 char *arg = argv[i];
159                 char *dotdot;
160         
161                 if (as_is) {
162                         show_norev(arg);
163                         continue;
164                 }
165                 if (*arg == '-') {
166                         if (!strcmp(arg, "--")) {
167                                 show_default();
168                                 if (revs_only)
169                                         break;
170                                 as_is = 1;
171                         }
172                         if (!strcmp(arg, "--default")) {
173                                 def = argv[i+1];
174                                 i++;
175                                 continue;
176                         }
177                         if (!strcmp(arg, "--revs-only")) {
178                                 revs_only = 1;
179                                 continue;
180                         }
181                         if (!strcmp(arg, "--no-revs")) {
182                                 no_revs = 1;
183                                 continue;
184                         }
185                         if (!strcmp(arg, "--verify")) {
186                                 revs_only = 1;
187                                 do_rev_argument = 0;
188                                 single_rev = 1;
189                                 continue;
190                         }
191                         if (!strcmp(arg, "--not")) {
192                                 show_type ^= REVERSED;
193                                 continue;
194                         }
195                         if (!strcmp(arg, "--all")) {
196                                 for_each_ref(show_reference);
197                                 continue;
198                         }
199                         show_arg(arg);
200                         continue;
201                 }
202                 dotdot = strstr(arg, "..");
203                 if (dotdot) {
204                         unsigned char end[20];
205                         char *n = dotdot+2;
206                         *dotdot = 0;
207                         if (!get_extended_sha1(arg, sha1)) {
208                                 if (!*n)
209                                         n = "HEAD";
210                                 if (!get_extended_sha1(n, end)) {
211                                         if (no_revs)
212                                                 continue;
213                                         def = NULL;
214                                         show_rev(NORMAL, end);
215                                         show_rev(REVERSED, sha1);
216                                         continue;
217                                 }
218                         }
219                         *dotdot = '.';
220                 }
221                 if (!get_extended_sha1(arg, sha1)) {
222                         if (no_revs)
223                                 continue;
224                         def = NULL;
225                         show_rev(NORMAL, sha1);
226                         continue;
227                 }
228                 if (*arg == '^' && !get_extended_sha1(arg+1, sha1)) {
229                         if (no_revs)
230                                 continue;
231                         def = NULL;
232                         show_rev(REVERSED, sha1);
233                         continue;
234                 }
235                 show_default();
236                 show_norev(arg);
237         }
238         show_default();
239         if (single_rev && output_revs != 1) {
240                 fprintf(stderr, "Needed a single revision\n");
241                 exit(1);
242         }
243         return 0;
244 }