9 static const char shortlog_usage
[] =
10 "git-shortlog [-n] [-s] [<commit-id>... ]\n";
12 static int compare_by_number(const void *a1
, const void *a2
)
14 const struct path_list_item
*i1
= a1
, *i2
= a2
;
15 const struct path_list
*l1
= i1
->util
, *l2
= i2
->util
;
19 else if (l1
->nr
== l2
->nr
)
25 static struct path_list_item mailmap_list
[] = {
26 { "R.Marek@sh.cvut.cz", (void*)"Rudolf Marek" },
27 { "Ralf.Wildenhues@gmx.de", (void*)"Ralf Wildenhues" },
28 { "aherrman@de.ibm.com", (void*)"Andreas Herrmann" },
29 { "akpm@osdl.org", (void*)"Andrew Morton" },
30 { "andrew.vasquez@qlogic.com", (void*)"Andrew Vasquez" },
31 { "aquynh@gmail.com", (void*)"Nguyen Anh Quynh" },
32 { "axboe@suse.de", (void*)"Jens Axboe" },
33 { "blaisorblade@yahoo.it", (void*)"Paolo 'Blaisorblade' Giarrusso" },
34 { "bunk@stusta.de", (void*)"Adrian Bunk" },
35 { "domen@coderock.org", (void*)"Domen Puncer" },
36 { "dougg@torque.net", (void*)"Douglas Gilbert" },
37 { "dwmw2@shinybook.infradead.org", (void*)"David Woodhouse" },
38 { "ecashin@coraid.com", (void*)"Ed L Cashin" },
39 { "felix@derklecks.de", (void*)"Felix Moeller" },
40 { "fzago@systemfabricworks.com", (void*)"Frank Zago" },
41 { "gregkh@suse.de", (void*)"Greg Kroah-Hartman" },
42 { "hch@lst.de", (void*)"Christoph Hellwig" },
43 { "htejun@gmail.com", (void*)"Tejun Heo" },
44 { "jejb@mulgrave.(none)", (void*)"James Bottomley" },
45 { "jejb@titanic.il.steeleye.com", (void*)"James Bottomley" },
46 { "jgarzik@pretzel.yyz.us", (void*)"Jeff Garzik" },
47 { "johnpol@2ka.mipt.ru", (void*)"Evgeniy Polyakov" },
48 { "kay.sievers@vrfy.org", (void*)"Kay Sievers" },
49 { "minyard@acm.org", (void*)"Corey Minyard" },
50 { "mshah@teja.com", (void*)"Mitesh shah" },
51 { "pj@ludd.ltu.se", (void*)"Peter A Jonsson" },
52 { "rmps@joel.ist.utl.pt", (void*)"Rui Saraiva" },
53 { "santtu.hyrkko@gmail.com", (void*)"Santtu Hyrkk\e,Av\e(B" },
54 { "simon@thekelleys.org.uk", (void*)"Simon Kelley" },
55 { "ssant@in.ibm.com", (void*)"Sachin P Sant" },
56 { "terra@gnome.org", (void*)"Morten Welinder" },
57 { "tony.luck@intel.com", (void*)"Tony Luck" },
58 { "welinder@anemone.rentec.com", (void*)"Morten Welinder" },
59 { "welinder@darter.rentec.com", (void*)"Morten Welinder" },
60 { "welinder@troll.com", (void*)"Morten Welinder" }
63 static struct path_list mailmap
= {
65 sizeof(mailmap_list
) / sizeof(struct path_list_item
), 0, 0
68 static int map_email(char *email
, char *name
, int maxlen
)
71 struct path_list_item
*item
;
73 /* autocomplete common developers */
74 p
= strchr(email
, '>');
79 item
= path_list_lookup(email
, &mailmap
);
81 const char *realname
= (const char *)item
->util
;
82 strncpy(name
, realname
, maxlen
);
88 static void insert_author_oneline(struct path_list
*list
,
89 const char *author
, int authorlen
,
90 const char *oneline
, int onelinelen
)
92 const char *dot3
= "/pub/scm/linux/kernel/git/";
94 struct path_list_item
*item
;
95 struct path_list
*onelines
;
97 while (authorlen
> 0 && isspace(author
[authorlen
- 1]))
100 buffer
= xmalloc(authorlen
+ 1);
101 memcpy(buffer
, author
, authorlen
);
102 buffer
[authorlen
] = '\0';
104 item
= path_list_insert(buffer
, list
);
105 if (item
->util
== NULL
)
106 item
->util
= xcalloc(1, sizeof(struct path_list
));
110 if (!strncmp(oneline
, "[PATCH", 6)) {
111 char *eob
= strchr(oneline
, ']');
114 while (isspace(eob
[1]) && eob
[1] != '\n')
116 if (eob
- oneline
< onelinelen
) {
117 onelinelen
-= eob
- oneline
;
123 while (onelinelen
> 0 && isspace(oneline
[0])) {
128 while (onelinelen
> 0 && isspace(oneline
[onelinelen
- 1]))
131 buffer
= xmalloc(onelinelen
+ 1);
132 memcpy(buffer
, oneline
, onelinelen
);
133 buffer
[onelinelen
] = '\0';
135 while ((p
= strstr(buffer
, dot3
)) != NULL
) {
137 strcpy(p
+ 2, p
+ sizeof(dot3
) - 1);
141 onelines
= item
->util
;
142 if (onelines
->nr
>= onelines
->alloc
) {
143 onelines
->alloc
= alloc_nr(onelines
->nr
);
144 onelines
->items
= xrealloc(onelines
->items
,
146 * sizeof(struct path_list_item
));
149 onelines
->items
[onelines
->nr
].util
= NULL
;
150 onelines
->items
[onelines
->nr
++].path
= buffer
;
153 static void read_from_stdin(struct path_list
*list
)
157 while (fgets(buffer
, sizeof(buffer
), stdin
) != NULL
) {
159 if ((buffer
[0] == 'A' || buffer
[0] == 'a') &&
160 !strncmp(buffer
+ 1, "uthor: ", 7) &&
161 (bob
= strchr(buffer
+ 7, '<')) != NULL
) {
162 char buffer2
[1024], offset
= 0;
164 if (map_email(bob
+ 1, buffer
, sizeof(buffer
)))
165 bob
= buffer
+ strlen(buffer
);
168 while (isspace(bob
[-1]))
172 while (fgets(buffer2
, sizeof(buffer2
), stdin
) &&
175 if (fgets(buffer2
, sizeof(buffer2
), stdin
))
176 insert_author_oneline(list
,
178 bob
- buffer
- offset
,
179 buffer2
, strlen(buffer2
));
184 static void get_from_rev(struct rev_info
*rev
, struct path_list
*list
)
187 struct commit
*commit
;
189 prepare_revision_walk(rev
);
190 while ((commit
= get_revision(rev
)) != NULL
) {
191 char *author
= NULL
, *oneline
, *buffer
;
192 int authorlen
= authorlen
, onelinelen
;
194 /* get author and oneline */
195 for (buffer
= commit
->buffer
; buffer
&& *buffer
!= '\0' &&
197 char *eol
= strchr(buffer
, '\n');
200 eol
= buffer
+ strlen(buffer
);
204 if (!strncmp(buffer
, "author ", 7)) {
205 char *bracket
= strchr(buffer
, '<');
207 if (bracket
== NULL
|| bracket
> eol
)
208 die("Invalid commit buffer: %s",
209 sha1_to_hex(commit
->object
.sha1
));
211 if (map_email(bracket
+ 1, scratch
,
214 authorlen
= strlen(scratch
);
216 while (bracket
[-1] == ' ')
220 authorlen
= bracket
- buffer
- 7;
227 die ("Missing author: %s",
228 sha1_to_hex(commit
->object
.sha1
));
230 if (buffer
== NULL
|| *buffer
== '\0') {
232 onelinelen
= sizeof(oneline
) + 1;
236 oneline
= buffer
+ 1;
237 eol
= strchr(oneline
, '\n');
239 onelinelen
= strlen(oneline
);
241 onelinelen
= eol
- oneline
;
244 insert_author_oneline(list
,
245 author
, authorlen
, oneline
, onelinelen
);
250 int cmd_shortlog(int argc
, const char **argv
, const char *prefix
)
253 struct path_list list
= { NULL
, 0, 0, 1 };
254 int i
, j
, sort_by_number
= 0, summary
= 0;
256 init_revisions(&rev
, prefix
);
257 argc
= setup_revisions(argc
, argv
, &rev
, NULL
);
259 if (!strcmp(argv
[1], "-n") || !strcmp(argv
[1], "--numbered"))
261 else if (!strcmp(argv
[1], "-s") ||
262 !strcmp(argv
[1], "--summary"))
264 else if (!strcmp(argv
[1], "-h") || !strcmp(argv
[1], "--help"))
265 usage(shortlog_usage
);
267 die ("unrecognized argument: %s", argv
[1]);
272 if (rev
.pending
.nr
== 1)
273 die ("Need a range!");
274 else if (rev
.pending
.nr
== 0)
275 read_from_stdin(&list
);
277 get_from_rev(&rev
, &list
);
280 qsort(list
.items
, sizeof(struct path_list_item
), list
.nr
,
283 for (i
= 0; i
< list
.nr
; i
++) {
284 struct path_list
*onelines
= list
.items
[i
].util
;
286 printf("%s (%d):\n", list
.items
[i
].path
, onelines
->nr
);
288 for (j
= onelines
->nr
- 1; j
>= 0; j
--)
289 printf(" %s\n", onelines
->items
[j
].path
);
293 onelines
->strdup_paths
= 1;
294 path_list_clear(onelines
, 1);
296 list
.items
[i
].util
= NULL
;
299 list
.strdup_paths
= 1;
300 path_list_clear(&list
, 1);