static void handle_commit(struct commit *commit, struct rev_info *rev) { int saved_output_format = rev->diffopt.output_format; const char *author, *author_end, *committer, *committer_end; const char *encoding, *message; char *reencoded = NULL; struct commit_list *p; int i; rev->diffopt.output_format = DIFF_FORMAT_CALLBACK; parse_commit_or_die(commit); author = strstr(commit->buffer, "\nauthor "); if (!author) die ("Could not find author in commit %s", sha1_to_hex(commit->object.sha1)); author++; author_end = strchrnul(author, '\n'); committer = strstr(author_end, "\ncommitter "); if (!committer) die ("Could not find committer in commit %s", sha1_to_hex(commit->object.sha1)); committer++; committer_end = strchrnul(committer, '\n'); message = strstr(committer_end, "\n\n"); encoding = find_encoding(committer_end, message); if (message) message += 2; if (commit->parents && get_object_mark(&commit->parents->item->object) != 0 && !full_tree) { parse_commit_or_die(commit->parents->item); diff_tree_sha1(commit->parents->item->tree->object.sha1, commit->tree->object.sha1, "", &rev->diffopt); } else diff_root_tree_sha1(commit->tree->object.sha1, "", &rev->diffopt); /* Export the referenced blobs, and remember the marks. */ for (i = 0; i < diff_queued_diff.nr; i++) if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode)) export_blob(diff_queued_diff.queue[i]->two->sha1); mark_next_object(&commit->object); if (!is_encoding_utf8(encoding)) reencoded = reencode_string(message, "UTF-8", encoding); if (!commit->parents) printf("reset %s\n", (const char*)commit->util); printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s", (const char *)commit->util, last_idnum, (int)(author_end - author), author, (int)(committer_end - committer), committer, (unsigned)(reencoded ? strlen(reencoded) : message ? strlen(message) : 0), reencoded ? reencoded : message ? message : ""); free(reencoded); for (i = 0, p = commit->parents; p; p = p->next) { int mark = get_object_mark(&p->item->object); if (!mark) continue; if (i == 0) printf("from :%d\n", mark); else printf("merge :%d\n", mark); i++; } if (full_tree) printf("deleteall\n"); log_tree_diff_flush(rev); rev->diffopt.output_format = saved_output_format; printf("\n"); show_progress(); }
/* * Show the diff of a commit. * * Return true if we printed any log info messages */ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log_info *log) { int showed_log; struct commit_list *parents; struct object_id *oid; if (!opt->diff && !DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)) return 0; parse_commit_or_die(commit); oid = &commit->tree->object.oid; /* Root commit? */ parents = get_saved_parents(opt, commit); if (!parents) { if (opt->show_root_diff) { diff_root_tree_sha1(oid->hash, "", &opt->diffopt); log_tree_diff_flush(opt); } return !opt->loginfo; } /* More than one parent? */ if (parents && parents->next) { if (opt->ignore_merges) return 0; else if (opt->combine_merges) return do_diff_combined(opt, commit); else if (opt->first_parent_only) { /* * Generate merge log entry only for the first * parent, showing summary diff of the others * we merged _in_. */ parse_commit_or_die(parents->item); diff_tree_sha1(parents->item->tree->object.oid.hash, oid->hash, "", &opt->diffopt); log_tree_diff_flush(opt); return !opt->loginfo; } /* If we show individual diffs, show the parent info */ log->parent = parents->item; } showed_log = 0; for (;;) { struct commit *parent = parents->item; parse_commit_or_die(parent); diff_tree_sha1(parent->tree->object.oid.hash, oid->hash, "", &opt->diffopt); log_tree_diff_flush(opt); showed_log |= !opt->loginfo; /* Set up the log info for the next parent, if any.. */ parents = parents->next; if (!parents) break; log->parent = parents->item; opt->loginfo = log; } return showed_log; }
void diff_tree_combined(const unsigned char *sha1, const unsigned char parent[][20], int num_parent, int dense, struct rev_info *rev) { struct diff_options *opt = &rev->diffopt; struct diff_options diffopts; struct combine_diff_path *p, *paths = NULL; int i, num_paths, needsep, show_log_first; diffopts = *opt; diffopts.output_format = DIFF_FORMAT_NO_OUTPUT; DIFF_OPT_SET(&diffopts, RECURSIVE); DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL); show_log_first = !!rev->loginfo && !rev->no_commit_id; needsep = 0; /* find set of paths that everybody touches */ for (i = 0; i < num_parent; i++) { /* show stat against the first parent even * when doing combined diff. */ int stat_opt = (opt->output_format & (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT)); if (i == 0 && stat_opt) diffopts.output_format = stat_opt; else diffopts.output_format = DIFF_FORMAT_NO_OUTPUT; diff_tree_sha1(parent[i], sha1, "", &diffopts); diffcore_std(&diffopts); paths = intersect_paths(paths, i, num_parent); if (show_log_first && i == 0) { show_log(rev); if (rev->verbose_header && opt->output_format) putchar(opt->line_termination); } diff_flush(&diffopts); } /* find out surviving paths */ for (num_paths = 0, p = paths; p; p = p->next) { if (p->len) num_paths++; } if (num_paths) { if (opt->output_format & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME | DIFF_FORMAT_NAME_STATUS)) { for (p = paths; p; p = p->next) { if (p->len) show_raw_diff(p, num_parent, rev); } needsep = 1; } else if (opt->output_format & (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT)) needsep = 1; if (opt->output_format & DIFF_FORMAT_PATCH) { if (needsep) putchar(opt->line_termination); for (p = paths; p; p = p->next) { if (p->len) show_patch_diff(p, num_parent, dense, rev); } } } /* Clean things up */ while (paths) { struct combine_diff_path *tmp = paths; paths = paths->next; free(tmp); } }