int cmd_diff_files(int argc, const char **argv, const char *prefix) { struct rev_info rev; int result; unsigned options = 0; if (argc == 2 && !strcmp(argv[1], "-h")) usage(diff_files_usage); git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ repo_init_revisions(the_repository, &rev, prefix); rev.abbrev = 0; precompose_argv(argc, argv); argc = setup_revisions(argc, argv, &rev, NULL); while (1 < argc && argv[1][0] == '-') { if (!strcmp(argv[1], "--base")) rev.max_count = 1; else if (!strcmp(argv[1], "--ours")) rev.max_count = 2; else if (!strcmp(argv[1], "--theirs")) rev.max_count = 3; else if (!strcmp(argv[1], "-q")) options |= DIFF_SILENT_ON_REMOVED; else usage(diff_files_usage); argv++; argc--; } if (!rev.diffopt.output_format) rev.diffopt.output_format = DIFF_FORMAT_RAW; /* * Make sure there are NO revision (i.e. pending object) parameter, * rev.max_count is reasonable (0 <= n <= 3), and * there is no other revision filtering parameters. */ if (rev.pending.nr || rev.min_age != -1 || rev.max_age != -1 || 3 < rev.max_count) usage(diff_files_usage); /* * "diff-files --base -p" should not combine merges because it * was not asked to. "diff-files -c -p" should not densify * (the user should ask with "diff-files --cc" explicitly). */ if (rev.max_count == -1 && !rev.combine_merges && (rev.diffopt.output_format & DIFF_FORMAT_PATCH)) rev.combine_merges = rev.dense_combined_merges = 1; if (read_cache_preload(&rev.diffopt.pathspec) < 0) { perror("read_cache_preload"); return -1; } result = run_diff_files(&rev, options); return diff_result_code(&rev.diffopt, result); }
static void show_local_changes(struct object *head, const struct diff_options *opts) { struct rev_info rev; /* I think we want full paths, even if we're in a subdirectory. */ repo_init_revisions(the_repository, &rev, NULL); rev.diffopt.flags = opts->flags; rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS; diff_setup_done(&rev.diffopt); add_pending_object(&rev, head, NULL); run_diff_index(&rev, 0); }
int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt) { struct rev_info revs; repo_init_revisions(the_repository, &revs, NULL); copy_pathspec(&revs.prune_data, &opt->pathspec); revs.diffopt = *opt; if (diff_cache(&revs, tree_oid, NULL, 1)) exit(128); return 0; }
static int edit_patch(int argc, const char **argv, const char *prefix) { char *file = git_pathdup("ADD_EDIT.patch"); const char *apply_argv[] = { "apply", "--recount", "--cached", NULL, NULL }; struct child_process child = CHILD_PROCESS_INIT; struct rev_info rev; int out; struct stat st; apply_argv[3] = file; git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ if (read_cache() < 0) die(_("Could not read the index")); repo_init_revisions(the_repository, &rev, prefix); rev.diffopt.context = 7; argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; rev.diffopt.use_color = 0; rev.diffopt.flags.ignore_dirty_submodules = 1; out = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (out < 0) die(_("Could not open '%s' for writing."), file); rev.diffopt.file = xfdopen(out, "w"); rev.diffopt.close_file = 1; if (run_diff_files(&rev, 0)) die(_("Could not write patch")); if (launch_editor(file, NULL, NULL)) die(_("editing patch failed")); if (stat(file, &st)) die_errno(_("Could not stat '%s'"), file); if (!st.st_size) die(_("Empty patch. Aborted.")); child.git_cmd = 1; child.argv = apply_argv; if (run_command(&child)) die(_("Could not apply '%s'"), file); unlink(file); free(file); return 0; }
int index_differs_from(const char *def, const struct diff_flags *flags, int ita_invisible_in_index) { struct rev_info rev; struct setup_revision_opt opt; repo_init_revisions(the_repository, &rev, NULL); memset(&opt, 0, sizeof(opt)); opt.def = def; setup_revisions(0, NULL, &rev, &opt); rev.diffopt.flags.quick = 1; rev.diffopt.flags.exit_with_status = 1; if (flags) diff_flags_or(&rev.diffopt.flags, flags); rev.diffopt.ita_invisible_in_index = ita_invisible_in_index; run_diff_index(&rev, 1); object_array_clear(&rev.pending); return (rev.diffopt.flags.has_changes != 0); }
int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags) { struct update_callback_data data; struct rev_info rev; memset(&data, 0, sizeof(data)); data.flags = flags; repo_init_revisions(the_repository, &rev, prefix); setup_revisions(0, NULL, &rev, NULL); if (pathspec) copy_pathspec(&rev.prune_data, pathspec); rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = update_callback; rev.diffopt.format_callback_data = &data; rev.diffopt.flags.override_submodule_config = 1; rev.max_count = 0; /* do not compare unmerged paths with stage #2 */ run_diff_files(&rev, DIFF_RACY_IS_MODIFIED); clear_pathspec(&rev.prune_data); return !!data.add_errors; }
/* * We are about to leave commit that was at the tip of a detached * HEAD. If it is not reachable from any ref, this is the last chance * for the user to do so without resorting to reflog. */ static void orphaned_commit_warning(struct commit *old_commit, struct commit *new_commit) { struct rev_info revs; struct object *object = &old_commit->object; repo_init_revisions(the_repository, &revs, NULL); setup_revisions(0, NULL, &revs, NULL); object->flags &= ~UNINTERESTING; add_pending_object(&revs, object, oid_to_hex(&object->oid)); for_each_ref(add_pending_uninteresting_ref, &revs); add_pending_oid(&revs, "HEAD", &new_commit->object.oid, UNINTERESTING); if (prepare_revision_walk(&revs)) die(_("internal error in revision walk")); if (!(old_commit->object.flags & UNINTERESTING)) suggest_reattach(old_commit, &revs); else describe_detached_head(_("Previous HEAD position was"), old_commit); /* Clean up objects used, as they will be reused. */ clear_commit_marks_all(ALL_REV_FLAGS); }
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) { struct expire_reflog_policy_cb cb; timestamp_t now = time(NULL); int i, status, do_all, all_worktrees = 1; int explicit_expiry = 0; unsigned int flags = 0; default_reflog_expire_unreachable = now - 30 * 24 * 3600; default_reflog_expire = now - 90 * 24 * 3600; git_config(reflog_expire_config, NULL); save_commit_buffer = 0; do_all = status = 0; memset(&cb, 0, sizeof(cb)); cb.cmd.expire_total = default_reflog_expire; cb.cmd.expire_unreachable = default_reflog_expire_unreachable; for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n")) flags |= EXPIRE_REFLOGS_DRY_RUN; else if (starts_with(arg, "--expire=")) { if (parse_expiry_date(arg + 9, &cb.cmd.expire_total)) die(_("'%s' is not a valid timestamp"), arg); explicit_expiry |= EXPIRE_TOTAL; } else if (starts_with(arg, "--expire-unreachable=")) { if (parse_expiry_date(arg + 21, &cb.cmd.expire_unreachable)) die(_("'%s' is not a valid timestamp"), arg); explicit_expiry |= EXPIRE_UNREACH; } else if (!strcmp(arg, "--stale-fix")) cb.cmd.stalefix = 1; else if (!strcmp(arg, "--rewrite")) flags |= EXPIRE_REFLOGS_REWRITE; else if (!strcmp(arg, "--updateref")) flags |= EXPIRE_REFLOGS_UPDATE_REF; else if (!strcmp(arg, "--all")) do_all = 1; else if (!strcmp(arg, "--single-worktree")) all_worktrees = 0; else if (!strcmp(arg, "--verbose")) flags |= EXPIRE_REFLOGS_VERBOSE; else if (!strcmp(arg, "--")) { i++; break; } else if (arg[0] == '-') usage(_(reflog_expire_usage)); else break; } /* * We can trust the commits and objects reachable from refs * even in older repository. We cannot trust what's reachable * from reflog if the repository was pruned with older git. */ if (cb.cmd.stalefix) { repo_init_revisions(the_repository, &cb.cmd.revs, prefix); if (flags & EXPIRE_REFLOGS_VERBOSE) printf(_("Marking reachable objects...")); mark_reachable_objects(&cb.cmd.revs, 0, 0, NULL); if (flags & EXPIRE_REFLOGS_VERBOSE) putchar('\n'); } if (do_all) { struct collect_reflog_cb collected; struct worktree **worktrees, **p; int i; memset(&collected, 0, sizeof(collected)); worktrees = get_worktrees(0); for (p = worktrees; *p; p++) { if (!all_worktrees && !(*p)->is_current) continue; collected.wt = *p; refs_for_each_reflog(get_worktree_ref_store(*p), collect_reflog, &collected); } free_worktrees(worktrees); for (i = 0; i < collected.nr; i++) { struct collected_reflog *e = collected.e[i]; set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog); status |= reflog_expire(e->reflog, &e->oid, flags, reflog_expiry_prepare, should_expire_reflog_ent, reflog_expiry_cleanup, &cb); free(e); } free(collected.e); } for (; i < argc; i++) { char *ref; struct object_id oid; if (!dwim_log(argv[i], strlen(argv[i]), &oid, &ref)) { status |= error(_("%s points nowhere!"), argv[i]); continue; } set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref); status |= reflog_expire(ref, &oid, flags, reflog_expiry_prepare, should_expire_reflog_ent, reflog_expiry_cleanup, &cb); } return status; }
int cmd_prune(int argc, const char **argv, const char *prefix) { struct rev_info revs; struct progress *progress = NULL; int exclude_promisor_objects = 0; const struct option options[] = { OPT__DRY_RUN(&show_only, N_("do not remove, show only")), OPT__VERBOSE(&verbose, N_("report pruned objects")), OPT_BOOL(0, "progress", &show_progress, N_("show progress")), OPT_EXPIRY_DATE(0, "expire", &expire, N_("expire objects older than <time>")), OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects, N_("limit traversal to objects outside promisor packfiles")), OPT_END() }; char *s; git_config(git_default_config, NULL); expire = TIME_MAX; save_commit_buffer = 0; read_replace_refs = 0; ref_paranoia = 1; repo_init_revisions(the_repository, &revs, prefix); argc = parse_options(argc, argv, prefix, options, prune_usage, 0); if (repository_format_precious_objects) die(_("cannot prune in a precious-objects repo")); while (argc--) { struct object_id oid; const char *name = *argv++; if (!get_oid(name, &oid)) { struct object *object = parse_object_or_die(&oid, name); add_pending_object(&revs, object, ""); } else die("unrecognized argument: %s", name); } if (show_progress == -1) show_progress = isatty(2); if (show_progress) progress = start_delayed_progress(_("Checking connectivity"), 0); if (exclude_promisor_objects) { fetch_if_missing = 0; revs.exclude_promisor_objects = 1; } mark_reachable_objects(&revs, 1, expire, progress); stop_progress(&progress); for_each_loose_file_in_objdir(get_object_directory(), prune_object, prune_cruft, prune_subdir, NULL); prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0); remove_temporary_files(get_object_directory()); s = mkpathdup("%s/pack", get_object_directory()); remove_temporary_files(s); free(s); if (is_repository_shallow(the_repository)) prune_shallow(show_only ? PRUNE_SHOW_ONLY : 0); return 0; }
void bitmap_writer_build(struct packing_data *to_pack) { static const double REUSE_BITMAP_THRESHOLD = 0.2; int i, reuse_after, need_reset; struct bitmap *base = bitmap_new(); struct rev_info revs; writer.bitmaps = kh_init_sha1(); writer.to_pack = to_pack; if (writer.show_progress) writer.progress = start_progress("Building bitmaps", writer.selected_nr); repo_init_revisions(to_pack->repo, &revs, NULL); revs.tag_objects = 1; revs.tree_objects = 1; revs.blob_objects = 1; revs.no_walk = 0; revs.include_check = should_include; reset_revision_walk(); reuse_after = writer.selected_nr * REUSE_BITMAP_THRESHOLD; need_reset = 0; for (i = writer.selected_nr - 1; i >= 0; --i) { struct bitmapped_commit *stored; struct object *object; khiter_t hash_pos; int hash_ret; stored = &writer.selected[i]; object = (struct object *)stored->commit; if (stored->bitmap == NULL) { if (i < writer.selected_nr - 1 && (need_reset || !in_merge_bases(writer.selected[i + 1].commit, stored->commit))) { bitmap_reset(base); reset_all_seen(); } add_pending_object(&revs, object, ""); revs.include_check_data = base; if (prepare_revision_walk(&revs)) die("revision walk setup failed"); traverse_commit_list(&revs, show_commit, show_object, base); object_array_clear(&revs.pending); stored->bitmap = bitmap_to_ewah(base); need_reset = 0; } else need_reset = 1; if (i >= reuse_after) stored->flags |= BITMAP_FLAG_REUSE; hash_pos = kh_put_sha1(writer.bitmaps, object->oid.hash, &hash_ret); if (hash_ret == 0) die("Duplicate entry when writing index: %s", oid_to_hex(&object->oid)); kh_value(writer.bitmaps, hash_pos) = stored; display_progress(writer.progress, writer.selected_nr - i); } bitmap_free(base); stop_progress(&writer.progress); compute_xor_offsets(); }