X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-log.c;h=82c69d1d0593156c5f7034746fe68f5a1a9f7276;hb=f1efc38bf2856f875b878177c0f0a98d9eb3bb4e;hp=5a8a50b81dabea4ccd9b0ba0fcb5d925a00560d0;hpb=160a59f326d55970f8a038ef635c662b9c648c75;p=git.git diff --git a/builtin-log.c b/builtin-log.c index 5a8a50b81..82c69d1d0 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -10,29 +10,28 @@ #include "revision.h" #include "log-tree.h" #include "builtin.h" +#include +#include /* this is in builtin-diff.c */ void add_head(struct rev_info *revs); -static int cmd_log_wc(int argc, const char **argv, char **envp, +static void cmd_log_init(int argc, const char **argv, const char *prefix, struct rev_info *rev) { - struct commit *commit; - rev->abbrev = DEFAULT_ABBREV; rev->commit_format = CMIT_FMT_DEFAULT; rev->verbose_header = 1; argc = setup_revisions(argc, argv, rev, "HEAD"); - if (rev->always_show_header) { - if (rev->diffopt.pickaxe || rev->diffopt.filter) { - rev->always_show_header = 0; - if (rev->diffopt.output_format == DIFF_FORMAT_RAW) - rev->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT; - } - } - + if (rev->diffopt.pickaxe || rev->diffopt.filter) + rev->always_show_header = 0; if (argc > 1) die("unrecognized argument: %s", argv[1]); +} + +static int cmd_log_walk(struct rev_info *rev) +{ + struct commit *commit; prepare_revision_walk(rev); setup_pager(); @@ -46,22 +45,27 @@ static int cmd_log_wc(int argc, const char **argv, char **envp, return 0; } -int cmd_whatchanged(int argc, const char **argv, char **envp) +int cmd_whatchanged(int argc, const char **argv, const char *prefix) { struct rev_info rev; - init_revisions(&rev); + git_config(git_diff_ui_config); + init_revisions(&rev, prefix); rev.diff = 1; rev.diffopt.recursive = 1; rev.simplify_history = 0; - return cmd_log_wc(argc, argv, envp, &rev); + cmd_log_init(argc, argv, prefix, &rev); + if (!rev.diffopt.output_format) + rev.diffopt.output_format = DIFF_FORMAT_RAW; + return cmd_log_walk(&rev); } -int cmd_show(int argc, const char **argv, char **envp) +int cmd_show(int argc, const char **argv, const char *prefix) { struct rev_info rev; - init_revisions(&rev); + git_config(git_diff_ui_config); + init_revisions(&rev, prefix); rev.diff = 1; rev.diffopt.recursive = 1; rev.combine_merges = 1; @@ -69,17 +73,19 @@ int cmd_show(int argc, const char **argv, char **envp) rev.always_show_header = 1; rev.ignore_merges = 0; rev.no_walk = 1; - return cmd_log_wc(argc, argv, envp, &rev); + cmd_log_init(argc, argv, prefix, &rev); + return cmd_log_walk(&rev); } -int cmd_log(int argc, const char **argv, char **envp) +int cmd_log(int argc, const char **argv, const char *prefix) { struct rev_info rev; - init_revisions(&rev); + git_config(git_diff_ui_config); + init_revisions(&rev, prefix); rev.always_show_header = 1; - rev.diffopt.recursive = 1; - return cmd_log_wc(argc, argv, envp, &rev); + cmd_log_init(argc, argv, prefix, &rev); + return cmd_log_walk(&rev); } static int istitlechar(char c) @@ -101,7 +107,10 @@ static int git_format_config(const char *var, const char *value) strcat(extra_headers, value); return 0; } - return git_default_config(var, value); + if (!strcmp(var, "diff.color")) { + return 0; + } + return git_diff_ui_config(var, value); } @@ -115,7 +124,7 @@ static void reopen_stdout(struct commit *commit, int nr, int keep_subject) int len = 0; if (output_directory) { - safe_strncpy(filename, output_directory, 1010); + strlcpy(filename, output_directory, 1010); len = strlen(filename); if (filename[len - 1] != '/') filename[len++] = '/'; @@ -160,7 +169,78 @@ static void reopen_stdout(struct commit *commit, int nr, int keep_subject) freopen(filename, "w", stdout); } -int cmd_format_patch(int argc, const char **argv, char **envp) +static int get_patch_id(struct commit *commit, struct diff_options *options, + unsigned char *sha1) +{ + diff_tree_sha1(commit->parents->item->object.sha1, commit->object.sha1, + "", options); + diffcore_std(options); + return diff_flush_patch_id(options, sha1); +} + +static void get_patch_ids(struct rev_info *rev, struct diff_options *options, const char *prefix) +{ + struct rev_info check_rev; + struct commit *commit; + struct object *o1, *o2; + unsigned flags1, flags2; + unsigned char sha1[20]; + + if (rev->pending.nr != 2) + die("Need exactly one range."); + + o1 = rev->pending.objects[0].item; + flags1 = o1->flags; + o2 = rev->pending.objects[1].item; + flags2 = o2->flags; + + if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING)) + die("Not a range."); + + diff_setup(options); + options->recursive = 1; + if (diff_setup_done(options) < 0) + die("diff_setup_done failed"); + + /* given a range a..b get all patch ids for b..a */ + init_revisions(&check_rev, prefix); + o1->flags ^= UNINTERESTING; + o2->flags ^= UNINTERESTING; + add_pending_object(&check_rev, o1, "o1"); + add_pending_object(&check_rev, o2, "o2"); + prepare_revision_walk(&check_rev); + + while ((commit = get_revision(&check_rev)) != NULL) { + /* ignore merges */ + if (commit->parents && commit->parents->next) + continue; + + if (!get_patch_id(commit, options, sha1)) + created_object(sha1, xcalloc(1, sizeof(struct object))); + } + + /* reset for next revision walk */ + clear_commit_marks((struct commit *)o1, + SEEN | UNINTERESTING | SHOWN | ADDED); + clear_commit_marks((struct commit *)o2, + SEEN | UNINTERESTING | SHOWN | ADDED); + o1->flags = flags1; + o2->flags = flags2; +} + +static void gen_message_id(char *dest, unsigned int length, char *base) +{ + const char *committer = git_committer_info(1); + const char *email_start = strrchr(committer, '<'); + const char *email_end = strrchr(committer, '>'); + if(!email_start || !email_end || email_start > email_end - 1) + die("Could not extract email from committer identity."); + snprintf(dest, length, "%s.%lu.git.%.*s", base, + (unsigned long) time(NULL), + (int)(email_end - email_start - 1), email_start + 1); +} + +int cmd_format_patch(int argc, const char **argv, const char *prefix) { struct commit *commit; struct commit **list = NULL; @@ -170,19 +250,24 @@ int cmd_format_patch(int argc, const char **argv, char **envp) int numbered = 0; int start_number = -1; int keep_subject = 0; + int ignore_if_in_upstream = 0; + int thread = 0; + const char *in_reply_to = NULL; + struct diff_options patch_id_opts; char *add_signoff = NULL; + char message_id[1024]; + char ref_message_id[1024]; - init_revisions(&rev); + git_config(git_format_config); + init_revisions(&rev, prefix); rev.commit_format = CMIT_FMT_EMAIL; rev.verbose_header = 1; rev.diff = 1; - rev.diffopt.with_raw = 0; - rev.diffopt.with_stat = 1; rev.combine_merges = 0; rev.ignore_merges = 1; - rev.diffopt.output_format = DIFF_FORMAT_PATCH; + rev.diffopt.msg_sep = ""; + rev.diffopt.recursive = 1; - git_config(git_format_config); rev.extra_headers = extra_headers; /* @@ -235,6 +320,18 @@ int cmd_format_patch(int argc, const char **argv, char **envp) rev.mime_boundary = git_version_string; else if (!strncmp(argv[i], "--attach=", 9)) rev.mime_boundary = argv[i] + 9; + else if (!strcmp(argv[i], "--ignore-if-in-upstream")) + ignore_if_in_upstream = 1; + else if (!strcmp(argv[i], "--thread")) + thread = 1; + else if (!strncmp(argv[i], "--in-reply-to=", 14)) + in_reply_to = argv[i] + 14; + else if (!strcmp(argv[i], "--in-reply-to")) { + i++; + if (i == argc) + die("Need a Message-Id for --in-reply-to"); + in_reply_to = argv[i]; + } else argv[j++] = argv[i]; } @@ -249,6 +346,9 @@ int cmd_format_patch(int argc, const char **argv, char **envp) if (argc > 1) die ("unrecognized argument: %s", argv[1]); + if (!rev.diffopt.output_format) + rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH; + if (output_directory) { if (use_stdout) die("standard output, or directory, which one?"); @@ -262,14 +362,25 @@ int cmd_format_patch(int argc, const char **argv, char **envp) add_head(&rev); } + if (ignore_if_in_upstream) + get_patch_ids(&rev, &patch_id_opts, prefix); + if (!use_stdout) realstdout = fdopen(dup(1), "w"); prepare_revision_walk(&rev); while ((commit = get_revision(&rev)) != NULL) { + unsigned char sha1[20]; + /* ignore merges */ if (commit->parents && commit->parents->next) continue; + + if (ignore_if_in_upstream && + !get_patch_id(commit, &patch_id_opts, sha1) && + lookup_object(sha1)) + continue; + nr++; list = realloc(list, nr * sizeof(list[0])); list[nr - 1] = commit; @@ -278,10 +389,23 @@ int cmd_format_patch(int argc, const char **argv, char **envp) if (numbered) rev.total = total + start_number - 1; rev.add_signoff = add_signoff; + rev.ref_message_id = in_reply_to; while (0 <= --nr) { int shown; commit = list[nr]; rev.nr = total - nr + (start_number - 1); + /* Make the second and subsequent mails replies to the first */ + if (thread) { + if (nr == (total - 2)) { + strncpy(ref_message_id, message_id, + sizeof(ref_message_id)); + ref_message_id[sizeof(ref_message_id)-1]='\0'; + rev.ref_message_id = ref_message_id; + } + gen_message_id(message_id, sizeof(message_id), + sha1_to_hex(commit->object.sha1)); + rev.message_id = message_id; + } if (!use_stdout) reopen_stdout(commit, rev.nr, keep_subject); shown = log_tree_commit(&rev, commit);