~ubuntu-branches/ubuntu/intrepid/git-core/intrepid-updates

« back to all changes in this revision

Viewing changes to builtin-log.c

  • Committer: Package Import Robot
  • Author(s): Gerrit Pape
  • Date: 2007-04-22 13:31:05 UTC
  • mfrom: (1.1.14)
  • Revision ID: package-import@ubuntu.com-20070422133105-tkmhz328g2p0epz1
Tags: 1:1.5.1.2-1
* new upstream point release.
* debian/changelog.upstream: upstream changes taken from mailing list
  announcement.

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
#include "revision.h"
11
11
#include "log-tree.h"
12
12
#include "builtin.h"
13
 
#include <time.h>
14
 
#include <sys/time.h>
 
13
#include "tag.h"
 
14
#include "reflog-walk.h"
 
15
 
 
16
static int default_show_root = 1;
15
17
 
16
18
/* this is in builtin-diff.c */
17
19
void add_head(struct rev_info *revs);
19
21
static void cmd_log_init(int argc, const char **argv, const char *prefix,
20
22
                      struct rev_info *rev)
21
23
{
 
24
        int i;
 
25
 
22
26
        rev->abbrev = DEFAULT_ABBREV;
23
27
        rev->commit_format = CMIT_FMT_DEFAULT;
24
28
        rev->verbose_header = 1;
 
29
        rev->show_root_diff = default_show_root;
25
30
        argc = setup_revisions(argc, argv, rev, "HEAD");
26
31
        if (rev->diffopt.pickaxe || rev->diffopt.filter)
27
32
                rev->always_show_header = 0;
28
 
        if (argc > 1)
29
 
                die("unrecognized argument: %s", argv[1]);
 
33
        for (i = 1; i < argc; i++) {
 
34
                const char *arg = argv[i];
 
35
                if (!prefixcmp(arg, "--encoding=")) {
 
36
                        arg += 11;
 
37
                        if (strcmp(arg, "none"))
 
38
                                git_log_output_encoding = xstrdup(arg);
 
39
                        else
 
40
                                git_log_output_encoding = "";
 
41
                }
 
42
                else
 
43
                        die("unrecognized argument: %s", arg);
 
44
        }
30
45
}
31
46
 
32
47
static int cmd_log_walk(struct rev_info *rev)
36
51
        prepare_revision_walk(rev);
37
52
        while ((commit = get_revision(rev)) != NULL) {
38
53
                log_tree_commit(rev, commit);
39
 
                free(commit->buffer);
40
 
                commit->buffer = NULL;
 
54
                if (!rev->reflog_info) {
 
55
                        /* we allow cycles in reflog ancestry */
 
56
                        free(commit->buffer);
 
57
                        commit->buffer = NULL;
 
58
                }
41
59
                free_commit_list(commit->parents);
42
60
                commit->parents = NULL;
43
61
        }
44
62
        return 0;
45
63
}
46
64
 
 
65
static int git_log_config(const char *var, const char *value)
 
66
{
 
67
        if (!strcmp(var, "log.showroot")) {
 
68
                default_show_root = git_config_bool(var, value);
 
69
                return 0;
 
70
        }
 
71
        return git_diff_ui_config(var, value);
 
72
}
 
73
 
47
74
int cmd_whatchanged(int argc, const char **argv, const char *prefix)
48
75
{
49
76
        struct rev_info rev;
50
77
 
51
 
        git_config(git_diff_ui_config);
 
78
        git_config(git_log_config);
52
79
        init_revisions(&rev, prefix);
53
80
        rev.diff = 1;
54
81
        rev.diffopt.recursive = 1;
59
86
        return cmd_log_walk(&rev);
60
87
}
61
88
 
 
89
static int show_object(const unsigned char *sha1, int suppress_header)
 
90
{
 
91
        unsigned long size;
 
92
        enum object_type type;
 
93
        char *buf = read_sha1_file(sha1, &type, &size);
 
94
        int offset = 0;
 
95
 
 
96
        if (!buf)
 
97
                return error("Could not read object %s", sha1_to_hex(sha1));
 
98
 
 
99
        if (suppress_header)
 
100
                while (offset < size && buf[offset++] != '\n') {
 
101
                        int new_offset = offset;
 
102
                        while (new_offset < size && buf[new_offset++] != '\n')
 
103
                                ; /* do nothing */
 
104
                        offset = new_offset;
 
105
                }
 
106
 
 
107
        if (offset < size)
 
108
                fwrite(buf + offset, size - offset, 1, stdout);
 
109
        free(buf);
 
110
        return 0;
 
111
}
 
112
 
 
113
static int show_tree_object(const unsigned char *sha1,
 
114
                const char *base, int baselen,
 
115
                const char *pathname, unsigned mode, int stage)
 
116
{
 
117
        printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
 
118
        return 0;
 
119
}
 
120
 
62
121
int cmd_show(int argc, const char **argv, const char *prefix)
63
122
{
64
123
        struct rev_info rev;
 
124
        struct object_array_entry *objects;
 
125
        int i, count, ret = 0;
65
126
 
66
 
        git_config(git_diff_ui_config);
 
127
        git_config(git_log_config);
67
128
        init_revisions(&rev, prefix);
68
129
        rev.diff = 1;
69
130
        rev.diffopt.recursive = 1;
73
134
        rev.ignore_merges = 0;
74
135
        rev.no_walk = 1;
75
136
        cmd_log_init(argc, argv, prefix, &rev);
 
137
 
 
138
        count = rev.pending.nr;
 
139
        objects = rev.pending.objects;
 
140
        for (i = 0; i < count && !ret; i++) {
 
141
                struct object *o = objects[i].item;
 
142
                const char *name = objects[i].name;
 
143
                switch (o->type) {
 
144
                case OBJ_BLOB:
 
145
                        ret = show_object(o->sha1, 0);
 
146
                        break;
 
147
                case OBJ_TAG: {
 
148
                        struct tag *t = (struct tag *)o;
 
149
 
 
150
                        printf("%stag %s%s\n\n",
 
151
                                        diff_get_color(rev.diffopt.color_diff,
 
152
                                                DIFF_COMMIT),
 
153
                                        t->tag,
 
154
                                        diff_get_color(rev.diffopt.color_diff,
 
155
                                                DIFF_RESET));
 
156
                        ret = show_object(o->sha1, 1);
 
157
                        objects[i].item = (struct object *)t->tagged;
 
158
                        i--;
 
159
                        break;
 
160
                }
 
161
                case OBJ_TREE:
 
162
                        printf("%stree %s%s\n\n",
 
163
                                        diff_get_color(rev.diffopt.color_diff,
 
164
                                                DIFF_COMMIT),
 
165
                                        name,
 
166
                                        diff_get_color(rev.diffopt.color_diff,
 
167
                                                DIFF_RESET));
 
168
                        read_tree_recursive((struct tree *)o, "", 0, 0, NULL,
 
169
                                        show_tree_object);
 
170
                        break;
 
171
                case OBJ_COMMIT:
 
172
                        rev.pending.nr = rev.pending.alloc = 0;
 
173
                        rev.pending.objects = NULL;
 
174
                        add_object_array(o, name, &rev.pending);
 
175
                        ret = cmd_log_walk(&rev);
 
176
                        break;
 
177
                default:
 
178
                        ret = error("Unknown type: %d", o->type);
 
179
                }
 
180
        }
 
181
        free(objects);
 
182
        return ret;
 
183
}
 
184
 
 
185
/*
 
186
 * This is equivalent to "git log -g --abbrev-commit --pretty=oneline"
 
187
 */
 
188
int cmd_log_reflog(int argc, const char **argv, const char *prefix)
 
189
{
 
190
        struct rev_info rev;
 
191
 
 
192
        git_config(git_log_config);
 
193
        init_revisions(&rev, prefix);
 
194
        init_reflog_walk(&rev.reflog_info);
 
195
        rev.abbrev_commit = 1;
 
196
        rev.verbose_header = 1;
 
197
        cmd_log_init(argc, argv, prefix, &rev);
 
198
 
 
199
        /*
 
200
         * This means that we override whatever commit format the user gave
 
201
         * on the cmd line.  Sad, but cmd_log_init() currently doesn't
 
202
         * allow us to set a different default.
 
203
         */
 
204
        rev.commit_format = CMIT_FMT_ONELINE;
 
205
        rev.always_show_header = 1;
 
206
 
 
207
        /*
 
208
         * We get called through "git reflog", so unlike the other log
 
209
         * routines, we need to set up our pager manually..
 
210
         */
 
211
        setup_pager();
 
212
 
76
213
        return cmd_log_walk(&rev);
77
214
}
78
215
 
80
217
{
81
218
        struct rev_info rev;
82
219
 
83
 
        git_config(git_diff_ui_config);
 
220
        git_config(git_log_config);
84
221
        init_revisions(&rev, prefix);
85
222
        rev.always_show_header = 1;
86
223
        cmd_log_init(argc, argv, prefix, &rev);
87
224
        return cmd_log_walk(&rev);
88
225
}
89
226
 
 
227
/* format-patch */
 
228
#define FORMAT_PATCH_NAME_MAX 64
 
229
 
90
230
static int istitlechar(char c)
91
231
{
92
232
        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
95
235
 
96
236
static char *extra_headers = NULL;
97
237
static int extra_headers_size = 0;
 
238
static const char *fmt_patch_suffix = ".patch";
98
239
 
99
240
static int git_format_config(const char *var, const char *value)
100
241
{
101
242
        if (!strcmp(var, "format.headers")) {
102
 
                int len = strlen(value);
 
243
                int len;
 
244
 
 
245
                if (!value)
 
246
                        die("format.headers without value");
 
247
                len = strlen(value);
103
248
                extra_headers_size += len + 1;
104
249
                extra_headers = xrealloc(extra_headers, extra_headers_size);
105
250
                extra_headers[extra_headers_size - len - 1] = 0;
106
251
                strcat(extra_headers, value);
107
252
                return 0;
108
253
        }
109
 
        if (!strcmp(var, "diff.color")) {
110
 
                return 0;
111
 
        }
112
 
        return git_diff_ui_config(var, value);
 
254
        if (!strcmp(var, "format.suffix")) {
 
255
                if (!value)
 
256
                        die("format.suffix without value");
 
257
                fmt_patch_suffix = xstrdup(value);
 
258
                return 0;
 
259
        }
 
260
        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
 
261
                return 0;
 
262
        }
 
263
        return git_log_config(var, value);
113
264
}
114
265
 
115
266
 
116
267
static FILE *realstdout = NULL;
117
268
static const char *output_directory = NULL;
118
269
 
119
 
static void reopen_stdout(struct commit *commit, int nr, int keep_subject)
 
270
static int reopen_stdout(struct commit *commit, int nr, int keep_subject)
120
271
{
121
 
        char filename[1024];
 
272
        char filename[PATH_MAX];
122
273
        char *sol;
123
274
        int len = 0;
 
275
        int suffix_len = strlen(fmt_patch_suffix) + 1;
124
276
 
125
277
        if (output_directory) {
126
 
                strlcpy(filename, output_directory, 1010);
 
278
                if (strlen(output_directory) >=
 
279
                    sizeof(filename) - FORMAT_PATCH_NAME_MAX - suffix_len)
 
280
                        return error("name of output directory is too long");
 
281
                strlcpy(filename, output_directory, sizeof(filename) - suffix_len);
127
282
                len = strlen(filename);
128
283
                if (filename[len - 1] != '/')
129
284
                        filename[len++] = '/';
138
293
 
139
294
                sol += 2;
140
295
                /* strip [PATCH] or [PATCH blabla] */
141
 
                if (!keep_subject && !strncmp(sol, "[PATCH", 6)) {
 
296
                if (!keep_subject && !prefixcmp(sol, "[PATCH")) {
142
297
                        char *eos = strchr(sol + 6, ']');
143
298
                        if (eos) {
144
299
                                while (isspace(*eos))
147
302
                        }
148
303
                }
149
304
 
150
 
                for (j = 0; len < 1024 - 6 && sol[j] && sol[j] != '\n'; j++) {
 
305
                for (j = 0;
 
306
                     j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 &&
 
307
                             len < sizeof(filename) - suffix_len &&
 
308
                             sol[j] && sol[j] != '\n';
 
309
                     j++) {
151
310
                        if (istitlechar(sol[j])) {
152
311
                                if (space) {
153
312
                                        filename[len++] = '-';
162
321
                }
163
322
                while (filename[len - 1] == '.' || filename[len - 1] == '-')
164
323
                        len--;
 
324
                filename[len] = 0;
165
325
        }
166
 
        strcpy(filename + len, ".txt");
 
326
        if (len + suffix_len >= sizeof(filename))
 
327
                return error("Patch pathname too long");
 
328
        strcpy(filename + len, fmt_patch_suffix);
167
329
        fprintf(realstdout, "%s\n", filename);
168
 
        freopen(filename, "w", stdout);
 
330
        if (freopen(filename, "w", stdout) == NULL)
 
331
                return error("Cannot open patch file %s",filename);
 
332
        return 0;
 
333
 
169
334
}
170
335
 
171
336
static int get_patch_id(struct commit *commit, struct diff_options *options,
232
397
 
233
398
static void gen_message_id(char *dest, unsigned int length, char *base)
234
399
{
235
 
        const char *committer = git_committer_info(1);
 
400
        const char *committer = git_committer_info(-1);
236
401
        const char *email_start = strrchr(committer, '<');
237
402
        const char *email_end = strrchr(committer, '>');
238
403
        if(!email_start || !email_end || email_start > email_end - 1)
260
425
        char message_id[1024];
261
426
        char ref_message_id[1024];
262
427
 
263
 
        setup_ident();
264
428
        git_config(git_format_config);
265
429
        init_revisions(&rev, prefix);
266
430
        rev.commit_format = CMIT_FMT_EMAIL;
284
448
                else if (!strcmp(argv[i], "-n") ||
285
449
                                !strcmp(argv[i], "--numbered"))
286
450
                        numbered = 1;
287
 
                else if (!strncmp(argv[i], "--start-number=", 15))
 
451
                else if (!prefixcmp(argv[i], "--start-number="))
288
452
                        start_number = strtol(argv[i] + 15, NULL, 10);
289
453
                else if (!strcmp(argv[i], "--start-number")) {
290
454
                        i++;
318
482
                        memcpy(add_signoff, committer, endpos - committer + 1);
319
483
                        add_signoff[endpos - committer + 1] = 0;
320
484
                }
321
 
                else if (!strcmp(argv[i], "--attach"))
322
 
                        rev.mime_boundary = git_version_string;
323
 
                else if (!strncmp(argv[i], "--attach=", 9))
324
 
                        rev.mime_boundary = argv[i] + 9;
 
485
                else if (!strcmp(argv[i], "--attach")) {
 
486
                        rev.mime_boundary = git_version_string;
 
487
                        rev.no_inline = 1;
 
488
                }
 
489
                else if (!prefixcmp(argv[i], "--attach=")) {
 
490
                        rev.mime_boundary = argv[i] + 9;
 
491
                        rev.no_inline = 1;
 
492
                }
 
493
                else if (!strcmp(argv[i], "--inline")) {
 
494
                        rev.mime_boundary = git_version_string;
 
495
                        rev.no_inline = 0;
 
496
                }
 
497
                else if (!prefixcmp(argv[i], "--inline=")) {
 
498
                        rev.mime_boundary = argv[i] + 9;
 
499
                        rev.no_inline = 0;
 
500
                }
325
501
                else if (!strcmp(argv[i], "--ignore-if-in-upstream"))
326
502
                        ignore_if_in_upstream = 1;
327
503
                else if (!strcmp(argv[i], "--thread"))
328
504
                        thread = 1;
329
 
                else if (!strncmp(argv[i], "--in-reply-to=", 14))
 
505
                else if (!prefixcmp(argv[i], "--in-reply-to="))
330
506
                        in_reply_to = argv[i] + 14;
331
507
                else if (!strcmp(argv[i], "--in-reply-to")) {
332
508
                        i++;
334
510
                                die("Need a Message-Id for --in-reply-to");
335
511
                        in_reply_to = argv[i];
336
512
                }
 
513
                else if (!prefixcmp(argv[i], "--suffix="))
 
514
                        fmt_patch_suffix = argv[i] + 9;
337
515
                else
338
516
                        argv[j++] = argv[i];
339
517
        }
349
527
                die ("unrecognized argument: %s", argv[1]);
350
528
 
351
529
        if (!rev.diffopt.output_format)
352
 
                rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
353
 
 
354
 
        if (!output_directory)
 
530
                rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY | DIFF_FORMAT_PATCH;
 
531
 
 
532
        if (!rev.diffopt.text)
 
533
                rev.diffopt.binary = 1;
 
534
 
 
535
        if (!output_directory && !use_stdout)
355
536
                output_directory = prefix;
356
537
 
357
538
        if (output_directory) {
363
544
        }
364
545
 
365
546
        if (rev.pending.nr == 1) {
366
 
                rev.pending.objects[0].item->flags |= UNINTERESTING;
367
 
                add_head(&rev);
 
547
                if (rev.max_count < 0) {
 
548
                        rev.pending.objects[0].item->flags |= UNINTERESTING;
 
549
                        add_head(&rev);
 
550
                }
 
551
                /* Otherwise, it is "format-patch -22 HEAD", and
 
552
                 * get_revision() would return only the specified count.
 
553
                 */
368
554
        }
369
555
 
370
556
        if (ignore_if_in_upstream)
412
598
                        rev.message_id = message_id;
413
599
                }
414
600
                if (!use_stdout)
415
 
                        reopen_stdout(commit, rev.nr, keep_subject);
 
601
                        if (reopen_stdout(commit, rev.nr, keep_subject))
 
602
                                die("Failed to create output files");
416
603
                shown = log_tree_commit(&rev, commit);
417
604
                free(commit->buffer);
418
605
                commit->buffer = NULL;