int git_root_diff(GIT_DIFF diff, const GIT_HASH hash, GIT_FILE* file, int* count, int isstat) { int ret; struct object_id oid; struct rev_info *p_Rev; struct diff_queue_struct *q = &diff_queued_diff; p_Rev = (struct rev_info *)diff; hashcpy(oid.hash, hash); ret = diff_root_tree_oid(&oid, "", &p_Rev->diffopt); if(ret) return ret; if(isstat) { diffcore_std(&p_Rev->diffopt); memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t)); for (int i = 0; i < q->nr; ++i) { struct diff_filepair *p = q->queue[i]; //if (check_pair_status(p)) diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat); } } if (file) *file = q; if (count) *count = q->nr; return 0; }
void cgit_diff_tree(const unsigned char *old_sha1, const unsigned char *new_sha1, filepair_fn fn, const char *prefix) { struct diff_options opt; int ret; int prefixlen; diff_setup(&opt); opt.output_format = DIFF_FORMAT_CALLBACK; opt.detect_rename = 1; opt.rename_limit = ctx.cfg.renamelimit; DIFF_OPT_SET(&opt, RECURSIVE); opt.format_callback = cgit_diff_tree_cb; opt.format_callback_data = fn; if (prefix) { opt.nr_paths = 1; opt.paths = &prefix; prefixlen = strlen(prefix); opt.pathlens = &prefixlen; } diff_setup_done(&opt); if (old_sha1 && !is_null_sha1(old_sha1)) ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); else ret = diff_root_tree_sha1(new_sha1, "", &opt); diffcore_std(&opt); diff_flush(&opt); }
int log_tree_diff_flush(struct rev_info *opt) { diffcore_std(&opt->diffopt); if (diff_queue_is_empty()) { int saved_fmt = opt->diffopt.output_format; opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT; diff_flush(&opt->diffopt); opt->diffopt.output_format = saved_fmt; return 0; } if (opt->loginfo && !opt->no_commit_id) { /* When showing a verbose header (i.e. log message), * and not in --pretty=oneline format, we would want * an extra newline between the end of log and the * output for readability. */ show_log(opt); if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) && opt->verbose_header && opt->commit_format != CMIT_FMT_ONELINE) { int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH; if ((pch & opt->diffopt.output_format) == pch) printf("---"); putchar('\n'); } } diff_flush(&opt->diffopt); return 1; }
void check_for_new_submodule_commits(unsigned char new_sha1[20]) { struct rev_info rev; struct commit *commit; const char *argv[] = {NULL, NULL, "--not", "--all", NULL}; int argc = ARRAY_SIZE(argv) - 1; init_revisions(&rev, NULL); argv[1] = xstrdup(sha1_to_hex(new_sha1)); setup_revisions(argc, argv, &rev, NULL); if (prepare_revision_walk(&rev)) die("revision walk setup failed"); /* * Collect all submodules (whether checked out or not) for which new * commits have been recorded upstream in "changed_submodule_paths". */ while ((commit = get_revision(&rev))) { struct commit_list *parent = commit->parents; while (parent) { struct diff_options diff_opts; diff_setup(&diff_opts); diff_opts.output_format |= DIFF_FORMAT_CALLBACK; diff_opts.format_callback = submodule_collect_changed_cb; if (diff_setup_done(&diff_opts) < 0) die("diff_setup_done failed"); diff_tree_sha1(parent->item->object.sha1, commit->object.sha1, "", &diff_opts); diffcore_std(&diff_opts); diff_flush(&diff_opts); parent = parent->next; } } free((char *)argv[1]); }
void cgit_diff_tree(const unsigned char *old_sha1, const unsigned char *new_sha1, filepair_fn fn, const char *prefix, int ignorews) { struct diff_options opt; struct pathspec_item item; diff_setup(&opt); opt.output_format = DIFF_FORMAT_CALLBACK; opt.detect_rename = 1; opt.rename_limit = ctx.cfg.renamelimit; DIFF_OPT_SET(&opt, RECURSIVE); if (ignorews) DIFF_XDL_SET(&opt, IGNORE_WHITESPACE); opt.format_callback = cgit_diff_tree_cb; opt.format_callback_data = fn; if (prefix) { item.match = prefix; item.len = strlen(prefix); opt.pathspec.nr = 1; opt.pathspec.items = &item; } diff_setup_done(&opt); if (old_sha1 && !is_null_sha1(old_sha1)) diff_tree_sha1(old_sha1, new_sha1, "", &opt); else diff_root_tree_sha1(new_sha1, "", &opt); diffcore_std(&opt); diff_flush(&opt); }
static int builtin_diff_b_f(struct rev_info *revs, int argc, const char **argv, struct blobinfo *blob, const char *path) { /* Blob vs file in the working tree*/ struct stat st; if (argc > 1) usage(builtin_diff_usage); if (lstat(path, &st)) die_errno("failed to stat '%s'", path); if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) die("'%s': not a regular file or symlink", path); diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/"); if (blob[0].mode == S_IFINVALID) blob[0].mode = canon_mode(st.st_mode); stuff_change(&revs->diffopt, blob[0].mode, canon_mode(st.st_mode), blob[0].sha1, null_sha1, path, path); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; }
int git_do_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count,int isstat) { struct rev_info *p_Rev; int ret; int i; struct diff_queue_struct *q = &diff_queued_diff; p_Rev = (struct rev_info *)diff; ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt); if( ret ) { free_all_pack(); return ret; } if(isstat) { diffcore_std(&p_Rev->diffopt); memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t)); for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; //if (check_pair_status(p)) diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat); } } free_all_pack(); if(file) *file = q; if(count) *count = q->nr; return 0; }
static int read_from_tree(const char *prefix, const char **argv, unsigned char *tree_sha1, int refresh_flags) { struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); int index_fd, index_was_discarded = 0; struct diff_options opt; memset(&opt, 0, sizeof(opt)); diff_tree_setup_paths(get_pathspec(prefix, (const char **)argv), &opt); opt.output_format = DIFF_FORMAT_CALLBACK; opt.format_callback = update_index_from_diff; opt.format_callback_data = &index_was_discarded; index_fd = hold_locked_index(lock, 1); index_was_discarded = 0; read_cache(); if (do_diff_cache(tree_sha1, &opt)) return 1; diffcore_std(&opt); diff_flush(&opt); diff_tree_release_paths(&opt); if (!index_was_discarded) /* The index is still clobbered from do_diff_cache() */ discard_cache(); return update_index_refresh(index_fd, lock, refresh_flags); }
static int builtin_diff_b_f(struct rev_info *revs, int argc, const char **argv, struct blobinfo *blob) { /* Blob vs file in the working tree*/ struct stat st; const char *path; if (argc > 1) usage(builtin_diff_usage); GUARD_PATHSPEC(&revs->prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL); path = revs->prune_data.items[0].match; if (lstat(path, &st)) die_errno(_("failed to stat '%s'"), path); if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) die(_("'%s': not a regular file or symlink"), path); diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/"); if (blob[0].mode == S_IFINVALID) blob[0].mode = canon_mode(st.st_mode); stuff_change(&revs->diffopt, blob[0].mode, canon_mode(st.st_mode), blob[0].sha1, null_sha1, 1, 0, path, path); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; }
void diff_no_index(struct rev_info *revs, int argc, const char **argv, const char *prefix) { int i, prefixlen; const char *paths[2]; diff_setup(&revs->diffopt); for (i = 1; i < argc - 2; ) { int j; if (!strcmp(argv[i], "--no-index")) i++; else if (!strcmp(argv[i], "--")) i++; else { j = diff_opt_parse(&revs->diffopt, argv + i, argc - i); if (j <= 0) die("invalid diff option/value: %s", argv[i]); i += j; } } prefixlen = prefix ? strlen(prefix) : 0; for (i = 0; i < 2; i++) { const char *p = argv[argc - 2 + i]; if (!strcmp(p, "-")) /* * stdin should be spelled as "-"; if you have * path that is "-", spell it as "./-". */ p = file_from_standard_input; else if (prefixlen) p = xstrdup(prefix_filename(prefix, prefixlen, p)); paths[i] = p; } revs->diffopt.skip_stat_unmatch = 1; if (!revs->diffopt.output_format) revs->diffopt.output_format = DIFF_FORMAT_PATCH; DIFF_OPT_SET(&revs->diffopt, NO_INDEX); revs->max_count = -2; diff_setup_done(&revs->diffopt); setup_diff_pager(&revs->diffopt); DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); if (queue_diff(&revs->diffopt, paths[0], paths[1])) exit(1); diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/"); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); /* * The return code for --no-index imitates diff(1): * 0 = no changes, 1 = changes, else error */ exit(diff_result_code(&revs->diffopt, 0)); }
static void patch_diff(const char *a, const char *b, struct diff_options *diffopt) { diff_queue(&diff_queued_diff, get_filespec("a", a), get_filespec("b", b)); diffcore_std(diffopt); diff_flush(diffopt); }
/* * Get information of all renames which occurred between 'o_tree' and * 'tree'. We need the three trees in the merge ('o_tree', 'a_tree' and * 'b_tree') to be able to associate the correct cache entries with * the rename information. 'tree' is always equal to either a_tree or b_tree. */ static struct string_list *get_renames(struct merge_options *o, struct tree *tree, struct tree *o_tree, struct tree *a_tree, struct tree *b_tree, struct string_list *entries) { int i; struct string_list *renames; struct diff_options opts; renames = xcalloc(1, sizeof(struct string_list)); diff_setup(&opts); DIFF_OPT_SET(&opts, RECURSIVE); opts.detect_rename = DIFF_DETECT_RENAME; opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit : o->diff_rename_limit >= 0 ? o->diff_rename_limit : 500; opts.warn_on_too_large_rename = 1; opts.output_format = DIFF_FORMAT_NO_OUTPUT; if (diff_setup_done(&opts) < 0) die("diff setup failed"); diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts); diffcore_std(&opts); for (i = 0; i < diff_queued_diff.nr; ++i) { struct string_list_item *item; struct rename *re; struct diff_filepair *pair = diff_queued_diff.queue[i]; if (pair->status != 'R') { diff_free_filepair(pair); continue; } re = xmalloc(sizeof(*re)); re->processed = 0; re->pair = pair; item = string_list_lookup(re->pair->one->path, entries); if (!item) re->src_entry = insert_stage_data(re->pair->one->path, o_tree, a_tree, b_tree, entries); else re->src_entry = item->util; item = string_list_lookup(re->pair->two->path, entries); if (!item) re->dst_entry = insert_stage_data(re->pair->two->path, o_tree, a_tree, b_tree, entries); else re->dst_entry = item->util; item = string_list_insert(pair->one->path, renames); item->util = re; } opts.output_format = DIFF_FORMAT_NO_OUTPUT; diff_queued_diff.nr = 0; diff_flush(&opts); return renames; }
int log_tree_diff_flush(struct rev_info *opt) { opt->shown_dashes = 0; diffcore_std(&opt->diffopt); if (diff_queue_is_empty()) { int saved_fmt = opt->diffopt.output_format; opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT; diff_flush(&opt->diffopt); opt->diffopt.output_format = saved_fmt; return 0; } if (opt->loginfo && !opt->no_commit_id) { show_log(opt); if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) && opt->verbose_header && opt->commit_format != CMIT_FMT_ONELINE && !commit_format_is_empty(opt->commit_format)) { /* * When showing a verbose header (i.e. log message), * and not in --pretty=oneline format, we would want * an extra newline between the end of log and the * diff/diffstat output for readability. */ int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH; if (opt->diffopt.output_prefix) { struct strbuf *msg = NULL; msg = opt->diffopt.output_prefix(&opt->diffopt, opt->diffopt.output_prefix_data); fwrite(msg->buf, msg->len, 1, stdout); } /* * We may have shown three-dashes line early * between notes and the log message, in which * case we only want a blank line after the * notes without (an extra) three-dashes line. * Otherwise, we show the three-dashes line if * we are showing the patch with diffstat, but * in that case, there is no extra blank line * after the three-dashes line. */ if (!opt->shown_dashes && (pch & opt->diffopt.output_format) == pch) printf("---"); putchar('\n'); } } diff_flush(&opt->diffopt); return 1; }
static void finish(struct commit *head_commit, struct commit_list *remoteheads, const unsigned char *new_head, const char *msg) { struct strbuf reflog_message = STRBUF_INIT; const unsigned char *head = head_commit->object.oid.hash; if (!msg) strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION")); else { if (verbosity >= 0) printf("%s\n", msg); strbuf_addf(&reflog_message, "%s: %s", getenv("GIT_REFLOG_ACTION"), msg); } if (squash) { squash_message(head_commit, remoteheads); } else { if (verbosity >= 0 && !merge_msg.len) printf(_("No merge message -- not updating HEAD\n")); else { const char *argv_gc_auto[] = { "gc", "--auto", NULL }; update_ref(reflog_message.buf, "HEAD", new_head, head, 0, UPDATE_REFS_DIE_ON_ERR); /* * We ignore errors in 'gc --auto', since the * user should see them. */ close_all_packs(); run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); } } if (new_head && show_diffstat) { struct diff_options opts; diff_setup(&opts); opts.stat_width = -1; /* use full terminal width */ opts.stat_graph_width = -1; /* respect statGraphWidth config */ opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; diff_setup_done(&opts); diff_tree_sha1(head, new_head, "", &opts); diffcore_std(&opts); diff_flush(&opts); } /* Run a post-merge hook */ run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL); strbuf_release(&reflog_message); }
int commit_patch_id(struct commit *commit, struct diff_options *options, unsigned char *sha1, int diff_header_only) { if (!patch_id_defined(commit)) return -1; if (commit->parents) diff_tree_sha1(commit->parents->item->object.oid.hash, commit->object.oid.hash, "", options); else diff_root_tree_sha1(commit->object.oid.hash, "", options); diffcore_std(options); return diff_flush_patch_id(options, sha1, diff_header_only); }
int commit_patch_id(struct commit *commit, struct diff_options *options, struct object_id *oid, int diff_header_only) { if (!patch_id_defined(commit)) return -1; if (commit->parents) diff_tree_oid(&commit->parents->item->object.oid, &commit->object.oid, "", options); else diff_root_tree_oid(&commit->object.oid, "", options); diffcore_std(options); return diff_flush_patch_id(options, oid, diff_header_only); }
static void finish(const unsigned char *new_head, const char *msg) { struct strbuf reflog_message = STRBUF_INIT; if (!msg) strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION")); else { if (verbosity >= 0) printf("%s\n", msg); strbuf_addf(&reflog_message, "%s: %s", getenv("GIT_REFLOG_ACTION"), msg); } if (squash) { squash_message(); } else { if (verbosity >= 0 && !merge_msg.len) printf(_("No merge message -- not updating HEAD\n")); else { const char *argv_gc_auto[] = { "gc", "--auto", NULL }; update_ref(reflog_message.buf, "HEAD", new_head, head, 0, DIE_ON_ERR); /* * We ignore errors in 'gc --auto', since the * user should see them. */ run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); } } if (new_head && show_diffstat) { struct diff_options opts; diff_setup(&opts); opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; if (diff_use_color_default > 0) DIFF_OPT_SET(&opts, COLOR_DIFF); if (diff_setup_done(&opts) < 0) die(_("diff_setup_done failed")); diff_tree_sha1(head, new_head, "", &opts); diffcore_std(&opts); diff_flush(&opts); } /* Run a post-merge hook */ run_hook(NULL, "post-merge", squash ? "1" : "0", NULL); strbuf_release(&reflog_message); }
int main(int ac, const char **av) { int stage1, stage2; setup_git_directory(); git_config(git_diff_config); read_cache(); diff_setup(&diff_options); while (1 < ac && av[1][0] == '-') { const char *arg = av[1]; if (!strcmp(arg, "-r")) ; /* as usual */ else { int diff_opt_cnt; diff_opt_cnt = diff_opt_parse(&diff_options, av+1, ac-1); if (diff_opt_cnt < 0) usage(diff_stages_usage); else if (diff_opt_cnt) { av += diff_opt_cnt; ac -= diff_opt_cnt; continue; } else usage(diff_stages_usage); } ac--; av++; } if (ac < 3 || sscanf(av[1], "%d", &stage1) != 1 || ! (0 <= stage1 && stage1 <= 3) || sscanf(av[2], "%d", &stage2) != 1 || ! (0 <= stage2 && stage2 <= 3)) usage(diff_stages_usage); av += 3; /* The rest from av[0] are for paths restriction. */ diff_options.paths = av; if (diff_setup_done(&diff_options) < 0) usage(diff_stages_usage); diff_stages(stage1, stage2); diffcore_std(&diff_options); diff_flush(&diff_options); return 0; }
static void calculate_changed_submodule_paths(void) { struct rev_info rev; struct commit *commit; struct argv_array argv = ARGV_ARRAY_INIT; /* No need to check if there are no submodules configured */ if (!config_name_for_path.nr) return; init_revisions(&rev, NULL); argv_array_push(&argv, "--"); /* argv[0] program name */ sha1_array_for_each_unique(&ref_tips_after_fetch, add_sha1_to_argv, &argv); argv_array_push(&argv, "--not"); sha1_array_for_each_unique(&ref_tips_before_fetch, add_sha1_to_argv, &argv); setup_revisions(argv.argc, argv.argv, &rev, NULL); if (prepare_revision_walk(&rev)) die("revision walk setup failed"); /* * Collect all submodules (whether checked out or not) for which new * commits have been recorded upstream in "changed_submodule_paths". */ while ((commit = get_revision(&rev))) { struct commit_list *parent = commit->parents; while (parent) { struct diff_options diff_opts; diff_setup(&diff_opts); DIFF_OPT_SET(&diff_opts, RECURSIVE); diff_opts.output_format |= DIFF_FORMAT_CALLBACK; diff_opts.format_callback = submodule_collect_changed_cb; if (diff_setup_done(&diff_opts) < 0) die("diff_setup_done failed"); diff_tree_sha1(parent->item->object.sha1, commit->object.sha1, "", &diff_opts); diffcore_std(&diff_opts); diff_flush(&diff_opts); parent = parent->next; } } argv_array_clear(&argv); sha1_array_clear(&ref_tips_before_fetch); sha1_array_clear(&ref_tips_after_fetch); initialized_fetch_ref_tips = 0; }
static int read_from_tree(const char **pathspec, unsigned char *tree_sha1) { struct diff_options opt; memset(&opt, 0, sizeof(opt)); diff_tree_setup_paths(pathspec, &opt); opt.output_format = DIFF_FORMAT_CALLBACK; opt.format_callback = update_index_from_diff; read_cache(); if (do_diff_cache(tree_sha1, &opt)) return 1; diffcore_std(&opt); diff_flush(&opt); diff_tree_release_paths(&opt); return 0; }
int run_diff_index(struct rev_info *revs, int cached) { struct object_array_entry *ent; if (revs->pending.nr != 1) BUG("run_diff_index must be passed exactly one tree"); trace_performance_enter(); ent = revs->pending.objects; if (diff_cache(revs, &ent->item->oid, ent->name, cached)) exit(128); diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/"); diffcore_fix_diff_index(&revs->diffopt); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); trace_performance_leave("diff-index"); return 0; }
static int read_from_tree(const struct pathspec *pathspec, unsigned char *tree_sha1, int intent_to_add) { struct diff_options opt; memset(&opt, 0, sizeof(opt)); copy_pathspec(&opt.pathspec, pathspec); opt.output_format = DIFF_FORMAT_CALLBACK; opt.format_callback = update_index_from_diff; opt.format_callback_data = &intent_to_add; if (do_diff_cache(tree_sha1, &opt)) return 1; diffcore_std(&opt); diff_flush(&opt); free_pathspec(&opt.pathspec); return 0; }
static int read_from_tree(const struct pathspec *pathspec, struct object_id *tree_oid, int intent_to_add) { struct diff_options opt; memset(&opt, 0, sizeof(opt)); copy_pathspec(&opt.pathspec, pathspec); opt.output_format = DIFF_FORMAT_CALLBACK; opt.format_callback = update_index_from_diff; opt.format_callback_data = &intent_to_add; opt.flags.override_submodule_config = 1; if (do_diff_cache(tree_oid, &opt)) return 1; diffcore_std(&opt); diff_flush(&opt); clear_pathspec(&opt.pathspec); return 0; }
static int builtin_diff_blobs(struct rev_info *revs, int argc, const char **argv, struct blobinfo *blob) { unsigned mode = canon_mode(S_IFREG | 0644); if (argc > 1) usage(builtin_diff_usage); if (blob[0].mode == S_IFINVALID) blob[0].mode = mode; if (blob[1].mode == S_IFINVALID) blob[1].mode = mode; stuff_change(&revs->diffopt, blob[0].mode, blob[1].mode, blob[0].sha1, blob[1].sha1, blob[0].name, blob[1].name); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; }
static int builtin_diff_blobs(struct rev_info *revs, int argc, const char **argv, struct object_array_entry **blob) { unsigned mode = canon_mode(S_IFREG | 0644); if (argc > 1) usage(builtin_diff_usage); if (blob[0]->mode == S_IFINVALID) blob[0]->mode = mode; if (blob[1]->mode == S_IFINVALID) blob[1]->mode = mode; stuff_change(&revs->diffopt, blob[0]->mode, blob[1]->mode, &blob[0]->item->oid, &blob[1]->item->oid, 1, 1, blob_path(blob[0]), blob_path(blob[1])); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; }
/* * We have an origin -- find the path that corresponds to it in its * parent and return an origin structure to represent it. */ static struct blame_origin *find_rename(struct commit *parent, struct blame_origin *origin) { struct blame_origin *porigin = NULL; struct diff_options diff_opts; int i; diff_setup(&diff_opts); DIFF_OPT_SET(&diff_opts, RECURSIVE); diff_opts.detect_rename = DIFF_DETECT_RENAME; diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; diff_opts.single_follow = origin->path; diff_setup_done(&diff_opts); if (is_null_oid(&origin->commit->object.oid)) do_diff_cache(&parent->tree->object.oid, &diff_opts); else diff_tree_oid(&parent->tree->object.oid, &origin->commit->tree->object.oid, "", &diff_opts); diffcore_std(&diff_opts); for (i = 0; i < diff_queued_diff.nr; i++) { struct diff_filepair *p = diff_queued_diff.queue[i]; if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, origin->path)) { porigin = get_origin(parent, p->one->path); oidcpy(&porigin->blob_oid, &p->one->oid); porigin->mode = p->one->mode; break; } } diff_flush(&diff_opts); clear_pathspec(&diff_opts.pathspec); return porigin; }
static void make_cover_letter(struct rev_info *rev, int use_stdout, int numbered, int numbered_files, struct commit *origin, int nr, struct commit **list, struct commit *head) { const char *committer; const char *subject_start = NULL; const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n"; const char *msg; const char *extra_headers = rev->extra_headers; struct shortlog log; struct strbuf sb = STRBUF_INIT; int i; const char *encoding = "UTF-8"; struct diff_options opts; int need_8bit_cte = 0; struct commit *commit = NULL; if (rev->commit_format != CMIT_FMT_EMAIL) die("Cover letter needs email format"); committer = git_committer_info(0); if (!numbered_files) { /* * We fake a commit for the cover letter so we get the filename * desired. */ commit = xcalloc(1, sizeof(*commit)); commit->buffer = xmalloc(400); snprintf(commit->buffer, 400, "tree 0000000000000000000000000000000000000000\n" "parent %s\n" "author %s\n" "committer %s\n\n" "cover letter\n", sha1_to_hex(head->object.sha1), committer, committer); } if (!use_stdout && reopen_stdout(commit, rev)) return; if (commit) { free(commit->buffer); free(commit); } log_write_email_headers(rev, head, &subject_start, &extra_headers, &need_8bit_cte); for (i = 0; !need_8bit_cte && i < nr; i++) if (has_non_ascii(list[i]->buffer)) need_8bit_cte = 1; msg = body; pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822, encoding); pp_title_line(CMIT_FMT_EMAIL, &msg, &sb, subject_start, extra_headers, encoding, need_8bit_cte); pp_remainder(CMIT_FMT_EMAIL, &msg, &sb, 0); printf("%s\n", sb.buf); strbuf_release(&sb); shortlog_init(&log); log.wrap_lines = 1; log.wrap = 72; log.in1 = 2; log.in2 = 4; for (i = 0; i < nr; i++) shortlog_add_commit(&log, list[i]); shortlog_output(&log); /* * We can only do diffstat with a unique reference point */ if (!origin) return; memcpy(&opts, &rev->diffopt, sizeof(opts)); opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; diff_setup_done(&opts); diff_tree_sha1(origin->tree->object.sha1, head->tree->object.sha1, "", &opts); diffcore_std(&opts); diff_flush(&opts); printf("\n"); }
static void make_cover_letter(struct rev_info *rev, int use_stdout, int numbered, int numbered_files, struct commit *origin, int nr, struct commit **list, struct commit *head, const char *branch_name, int quiet) { const char *committer; const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n"; const char *msg; struct shortlog log; struct strbuf sb = STRBUF_INIT; int i; const char *encoding = "UTF-8"; struct diff_options opts; int need_8bit_cte = 0; struct pretty_print_context pp = {0}; if (rev->commit_format != CMIT_FMT_EMAIL) die(_("Cover letter needs email format")); committer = git_committer_info(0); if (!use_stdout && reopen_stdout(NULL, numbered_files ? NULL : "cover-letter", rev, quiet)) return; log_write_email_headers(rev, head, &pp.subject, &pp.after_subject, &need_8bit_cte); for (i = 0; !need_8bit_cte && i < nr; i++) if (has_non_ascii(list[i]->buffer)) need_8bit_cte = 1; msg = body; pp.fmt = CMIT_FMT_EMAIL; pp.date_mode = DATE_RFC2822; pp_user_info(&pp, NULL, &sb, committer, encoding); pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte); pp_remainder(&pp, &msg, &sb, 0); add_branch_description(&sb, branch_name); printf("%s\n", sb.buf); strbuf_release(&sb); shortlog_init(&log); log.wrap_lines = 1; log.wrap = 72; log.in1 = 2; log.in2 = 4; for (i = 0; i < nr; i++) shortlog_add_commit(&log, list[i]); shortlog_output(&log); /* * We can only do diffstat with a unique reference point */ if (!origin) return; memcpy(&opts, &rev->diffopt, sizeof(opts)); opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; diff_setup_done(&opts); diff_tree_sha1(origin->tree->object.sha1, head->tree->object.sha1, "", &opts); diffcore_std(&opts); diff_flush(&opts); printf("\n"); print_signature(); }
static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) { struct diff_options diff_opts; struct diff_queue_struct *q = &diff_queued_diff; struct diff_filepair *choice; const char *paths[1]; int i; /* Remove the file creation entry from the diff queue, and remember it */ choice = q->queue[0]; q->nr = 0; diff_setup(&diff_opts); DIFF_OPT_SET(&diff_opts, RECURSIVE); diff_opts.detect_rename = DIFF_DETECT_RENAME; diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; diff_opts.single_follow = opt->paths[0]; diff_opts.break_opt = opt->break_opt; paths[0] = NULL; diff_tree_setup_paths(paths, &diff_opts); if (diff_setup_done(&diff_opts) < 0) die("unable to set up diff options to follow renames"); diff_tree(t1, t2, base, &diff_opts); diffcore_std(&diff_opts); diff_tree_release_paths(&diff_opts); /* Go through the new set of filepairing, and see if we find a more interesting one */ for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; /* * Found a source? Not only do we use that for the new * diff_queued_diff, we will also use that as the path in * the future! */ if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) { /* Switch the file-pairs around */ q->queue[i] = choice; choice = p; /* Update the path we use from now on.. */ diff_tree_release_paths(opt); opt->paths[0] = xstrdup(p->one->path); diff_tree_setup_paths(opt->paths, opt); break; } } /* * Then, discard all the non-relevane file pairs... */ for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; diff_free_filepair(p); } /* * .. and re-instate the one we want (which might be either the * original one, or the rename/copy we found) */ q->queue[0] = choice; q->nr = 1; }
void diff_no_index(struct rev_info *revs, int argc, const char **argv, int nongit, const char *prefix) { int i; int no_index = 0; unsigned options = 0; /* Were we asked to do --no-index explicitly? */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--")) return; if (!strcmp(argv[i], "--no-index")) no_index = 1; if (argv[i][0] != '-') break; } if (!no_index && !nongit) { /* * Inside a git repository, without --no-index. Only * when a path outside the repository is given, * e.g. "git diff /var/tmp/[12]", or "git diff * Makefile /var/tmp/Makefile", allow it to be used as * a colourful "diff" replacement. */ if ((argc != i + 2) || (!path_outside_repo(argv[i]) && !path_outside_repo(argv[i+1]))) return; } if (argc != i + 2) die("git diff %s takes two paths", no_index ? "--no-index" : "[--no-index]"); /* * If the user asked for our exit code then don't start a * pager or we would end up reporting its exit code instead. */ if (!DIFF_OPT_TST(&revs->diffopt, EXIT_WITH_STATUS)) setup_pager(); diff_setup(&revs->diffopt); if (!revs->diffopt.output_format) revs->diffopt.output_format = DIFF_FORMAT_PATCH; for (i = 1; i < argc - 2; ) { int j; if (!strcmp(argv[i], "--no-index")) i++; else if (!strcmp(argv[1], "-q")) options |= DIFF_SILENT_ON_REMOVED; else { j = diff_opt_parse(&revs->diffopt, argv + i, argc - i); if (!j) die("invalid diff option/value: %s", argv[i]); i += j; } } if (prefix) { int len = strlen(prefix); revs->diffopt.paths = xcalloc(2, sizeof(char*)); for (i = 0; i < 2; i++) { const char *p = argv[argc - 2 + i]; /* * stdin should be spelled as '-'; if you have * path that is '-', spell it as ./-. */ p = (strcmp(p, "-") ? xstrdup(prefix_filename(prefix, len, p)) : p); revs->diffopt.paths[i] = p; } } else revs->diffopt.paths = argv + argc - 2; revs->diffopt.nr_paths = 2; DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); DIFF_OPT_SET(&revs->diffopt, NO_INDEX); revs->max_count = -2; if (diff_setup_done(&revs->diffopt) < 0) die("diff_setup_done failed"); if (queue_diff(&revs->diffopt, revs->diffopt.paths[0], revs->diffopt.paths[1])) exit(1); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); /* * The return code for --no-index imitates diff(1): * 0 = no changes, 1 = changes, else error */ exit(revs->diffopt.found_changes); }