summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/am.c2
-rw-r--r--builtin/blame.c2
-rw-r--r--builtin/branch.c25
-rw-r--r--builtin/checkout.c134
-rw-r--r--builtin/commit.c3
-rw-r--r--builtin/diff-tree.c6
-rw-r--r--builtin/merge.c9
-rw-r--r--builtin/pack-objects.c16
-rw-r--r--builtin/pack-redundant.c232
-rw-r--r--builtin/prune-packed.c5
-rw-r--r--builtin/prune.c44
-rw-r--r--builtin/rebase.c17
-rw-r--r--builtin/receive-pack.c4
-rw-r--r--builtin/reset.c6
-rw-r--r--builtin/submodule--helper.c9
-rw-r--r--builtin/update-index.c41
-rw-r--r--builtin/worktree.c1
17 files changed, 340 insertions, 216 deletions
diff --git a/builtin/am.c b/builtin/am.c
index 58a2aef28b..86e33495b0 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -453,6 +453,7 @@ static int run_post_rewrite_hook(const struct am_state *state)
cp.in = xopen(am_path(state, "rewritten"), O_RDONLY);
cp.stdout_to_stderr = 1;
+ cp.trace2_hook_name = "post-rewrite";
ret = run_command(&cp);
@@ -1579,6 +1580,7 @@ static void do_commit(const struct am_state *state)
}
author = fmt_ident(state->author_name, state->author_email,
+ WANT_AUTHOR_IDENT,
state->ignore_date ? NULL : state->author_date,
IDENT_STRICT);
diff --git a/builtin/blame.c b/builtin/blame.c
index 581de0d832..177c1022a0 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -814,7 +814,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
* and are only included here to get included in the "-h"
* output:
*/
- { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb },
+ { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, NULL, 0, parse_opt_unknown_cb },
OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
diff --git a/builtin/branch.c b/builtin/branch.c
index 1be727209b..4c83055730 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -443,6 +443,21 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
free(to_free);
}
+static void print_current_branch_name(void)
+{
+ int flags;
+ const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
+ const char *shortname;
+ if (!refname)
+ die(_("could not resolve HEAD"));
+ else if (!(flags & REF_ISSYMREF))
+ return;
+ else if (skip_prefix(refname, "refs/heads/", &shortname))
+ puts(shortname);
+ else
+ die(_("HEAD (%s) points outside of refs/heads/"), refname);
+}
+
static void reject_rebase_or_bisect_branch(const char *target)
{
struct worktree **worktrees = get_worktrees(0);
@@ -581,6 +596,7 @@ static int edit_branch_description(const char *branch_name)
int cmd_branch(int argc, const char **argv, const char *prefix)
{
int delete = 0, rename = 0, copy = 0, force = 0, list = 0;
+ int show_current = 0;
int reflog = 0, edit_description = 0;
int quiet = 0, unset_upstream = 0;
const char *new_upstream = NULL;
@@ -620,6 +636,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_BIT('c', "copy", &copy, N_("copy a branch and its reflog"), 1),
OPT_BIT('C', NULL, &copy, N_("copy a branch, even if target exists"), 2),
OPT_BOOL('l', "list", &list, N_("list branch names")),
+ OPT_BOOL(0, "show-current", &show_current, N_("show current branch name")),
OPT_BOOL(0, "create-reflog", &reflog, N_("create the branch's reflog")),
OPT_BOOL(0, "edit-description", &edit_description,
N_("edit the description for the branch")),
@@ -662,14 +679,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
0);
- if (!delete && !rename && !copy && !edit_description && !new_upstream && !unset_upstream && argc == 0)
+ if (!delete && !rename && !copy && !edit_description && !new_upstream &&
+ !show_current && !unset_upstream && argc == 0)
list = 1;
if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr ||
filter.no_commit)
list = 1;
- if (!!delete + !!rename + !!copy + !!new_upstream +
+ if (!!delete + !!rename + !!copy + !!new_upstream + !!show_current +
list + unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
@@ -697,6 +715,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!argc)
die(_("branch name required"));
return delete_branches(argc, argv, delete > 1, filter.kind, quiet);
+ } else if (show_current) {
+ print_current_branch_name();
+ return 0;
} else if (list) {
/* git branch --local also shows HEAD when it is detached */
if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 24b8593b93..0e6037b296 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -46,6 +46,7 @@ struct checkout_opts {
int ignore_other_worktrees;
int show_progress;
int count_checkout_paths;
+ int overlay_mode;
/*
* If new checkout options are added, skip_merge_working_tree
* should be updated accordingly.
@@ -135,7 +136,8 @@ static int skip_same_name(const struct cache_entry *ce, int pos)
return pos;
}
-static int check_stage(int stage, const struct cache_entry *ce, int pos)
+static int check_stage(int stage, const struct cache_entry *ce, int pos,
+ int overlay_mode)
{
while (pos < active_nr &&
!strcmp(active_cache[pos]->name, ce->name)) {
@@ -143,6 +145,8 @@ static int check_stage(int stage, const struct cache_entry *ce, int pos)
return 0;
pos++;
}
+ if (!overlay_mode)
+ return 0;
if (stage == 2)
return error(_("path '%s' does not have our version"), ce->name);
else
@@ -168,7 +172,8 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)
}
static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
- const struct checkout *state, int *nr_checkouts)
+ const struct checkout *state, int *nr_checkouts,
+ int overlay_mode)
{
while (pos < active_nr &&
!strcmp(active_cache[pos]->name, ce->name)) {
@@ -177,6 +182,10 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
NULL, nr_checkouts);
pos++;
}
+ if (!overlay_mode) {
+ unlink_entry(ce);
+ return 0;
+ }
if (stage == 2)
return error(_("path '%s' does not have our version"), ce->name);
else
@@ -251,6 +260,59 @@ static int checkout_merged(int pos, const struct checkout *state, int *nr_checko
return status;
}
+static void mark_ce_for_checkout_overlay(struct cache_entry *ce,
+ char *ps_matched,
+ const struct checkout_opts *opts)
+{
+ ce->ce_flags &= ~CE_MATCHED;
+ if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
+ return;
+ if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
+ /*
+ * "git checkout tree-ish -- path", but this entry
+ * is in the original index but is not in tree-ish
+ * or does not match the pathspec; it will not be
+ * checked out to the working tree. We will not do
+ * anything to this entry at all.
+ */
+ return;
+ /*
+ * Either this entry came from the tree-ish we are
+ * checking the paths out of, or we are checking out
+ * of the index.
+ *
+ * If it comes from the tree-ish, we already know it
+ * matches the pathspec and could just stamp
+ * CE_MATCHED to it from update_some(). But we still
+ * need ps_matched and read_tree_recursive (and
+ * eventually tree_entry_interesting) cannot fill
+ * ps_matched yet. Once it can, we can avoid calling
+ * match_pathspec() for _all_ entries when
+ * opts->source_tree != NULL.
+ */
+ if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))
+ ce->ce_flags |= CE_MATCHED;
+}
+
+static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce,
+ char *ps_matched,
+ const struct checkout_opts *opts)
+{
+ ce->ce_flags &= ~CE_MATCHED;
+ if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
+ return;
+ if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {
+ ce->ce_flags |= CE_MATCHED;
+ if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
+ /*
+ * In overlay mode, but the path is not in
+ * tree-ish, which means we should remove it
+ * from the index and the working tree.
+ */
+ ce->ce_flags |= CE_REMOVE | CE_WT_REMOVE;
+ }
+}
+
static int checkout_paths(const struct checkout_opts *opts,
const char *revision)
{
@@ -263,6 +325,8 @@ static int checkout_paths(const struct checkout_opts *opts,
struct lock_file lock_file = LOCK_INIT;
int nr_checkouts = 0, nr_unmerged = 0;
+ trace2_cmd_mode(opts->patch_mode ? "patch" : "path");
+
if (opts->track != BRANCH_TRACK_UNSPECIFIED)
die(_("'%s' cannot be used with updating paths"), "--track");
@@ -302,37 +366,15 @@ static int checkout_paths(const struct checkout_opts *opts,
* Make sure all pathspecs participated in locating the paths
* to be checked out.
*/
- for (pos = 0; pos < active_nr; pos++) {
- struct cache_entry *ce = active_cache[pos];
- ce->ce_flags &= ~CE_MATCHED;
- if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
- continue;
- if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
- /*
- * "git checkout tree-ish -- path", but this entry
- * is in the original index; it will not be checked
- * out to the working tree and it does not matter
- * if pathspec matched this entry. We will not do
- * anything to this entry at all.
- */
- continue;
- /*
- * Either this entry came from the tree-ish we are
- * checking the paths out of, or we are checking out
- * of the index.
- *
- * If it comes from the tree-ish, we already know it
- * matches the pathspec and could just stamp
- * CE_MATCHED to it from update_some(). But we still
- * need ps_matched and read_tree_recursive (and
- * eventually tree_entry_interesting) cannot fill
- * ps_matched yet. Once it can, we can avoid calling
- * match_pathspec() for _all_ entries when
- * opts->source_tree != NULL.
- */
- if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))
- ce->ce_flags |= CE_MATCHED;
- }
+ for (pos = 0; pos < active_nr; pos++)
+ if (opts->overlay_mode)
+ mark_ce_for_checkout_overlay(active_cache[pos],
+ ps_matched,
+ opts);
+ else
+ mark_ce_for_checkout_no_overlay(active_cache[pos],
+ ps_matched,
+ opts);
if (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {
free(ps_matched);
@@ -353,7 +395,7 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->force) {
warning(_("path '%s' is unmerged"), ce->name);
} else if (opts->writeout_stage) {
- errs |= check_stage(opts->writeout_stage, ce, pos);
+ errs |= check_stage(opts->writeout_stage, ce, pos, opts->overlay_mode);
} else if (opts->merge) {
errs |= check_stages((1<<2) | (1<<3), ce, pos);
} else {
@@ -383,13 +425,16 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->writeout_stage)
errs |= checkout_stage(opts->writeout_stage,
ce, pos,
- &state, &nr_checkouts);
+ &state,
+ &nr_checkouts, opts->overlay_mode);
else if (opts->merge)
errs |= checkout_merged(pos, &state,
&nr_unmerged);
pos = skip_same_name(ce, pos) - 1;
}
}
+ remove_marked_cache_entries(&the_index, 1);
+ remove_scheduled_dirs();
errs |= finish_delayed_checkout(&state, &nr_checkouts);
if (opts->count_checkout_paths) {
@@ -572,6 +617,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,
*/
/*
+ * opts->overlay_mode cannot be used with switching branches so is
+ * not tested here
+ */
+
+ /*
* If we aren't creating a new branch any changes or updates will
* happen in the existing branch. Since that could only be updating
* the index and working directory, we don't want to skip those steps
@@ -966,6 +1016,9 @@ static int switch_branches(const struct checkout_opts *opts,
void *path_to_free;
struct object_id rev;
int flag, writeout_error = 0;
+
+ trace2_cmd_mode("branch");
+
memset(&old_branch_info, 0, sizeof(old_branch_info));
old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
if (old_branch_info.path)
@@ -1203,6 +1256,8 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
int status;
struct strbuf branch_ref = STRBUF_INIT;
+ trace2_cmd_mode("unborn");
+
if (!opts->new_branch)
die(_("You are on a branch yet to be born"));
strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
@@ -1224,6 +1279,10 @@ static int checkout_branch(struct checkout_opts *opts,
die(_("'%s' cannot be used with switching branches"),
"--patch");
+ if (!opts->overlay_mode)
+ die(_("'%s' cannot be used with switching branches"),
+ "--no-overlay");
+
if (opts->writeout_stage)
die(_("'%s' cannot be used with switching branches"),
"--ours/--theirs");
@@ -1312,6 +1371,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
"checkout", "control recursive updating of submodules",
PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")),
+ OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode (default)")),
OPT_END(),
};
@@ -1320,6 +1380,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.overwrite_ignore = 1;
opts.prefix = prefix;
opts.show_progress = -1;
+ opts.overlay_mode = -1;
git_config(git_checkout_config, &opts);
@@ -1344,6 +1405,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
die(_("-b, -B and --orphan are mutually exclusive"));
+ if (opts.overlay_mode == 1 && opts.patch_mode)
+ die(_("-p and --overlay are mutually exclusive"));
+
/*
* From here on, new_branch will contain the branch to be checked out,
* and new_branch_force and new_orphan_branch will tell us which one of
diff --git a/builtin/commit.c b/builtin/commit.c
index 2986553d5f..8d7a613fda 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -609,7 +609,8 @@ static void determine_author_info(struct strbuf *author_ident)
set_ident_var(&date, strbuf_detach(&date_buf, NULL));
}
- strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
+ strbuf_addstr(author_ident, fmt_ident(name, email, WANT_AUTHOR_IDENT, date,
+ IDENT_STRICT));
assert_split_ident(&author, author_ident);
export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index a90681bcba..cb9ea79367 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -83,9 +83,13 @@ static int diff_tree_stdin(char *line)
}
static const char diff_tree_usage[] =
-"git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
+"git diff-tree [--stdin] [-m] [-c | --cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
"[<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n"
" -r diff recursively\n"
+" -c show combined diff for merge commits\n"
+" --cc show combined diff for merge commits removing uninteresting hunks\n"
+" --combined-all-paths\n"
+" show name of file in all parents for combined diffs\n"
" --root include the initial commit as diff against /dev/null\n"
COMMON_DIFF_OPTIONS_HELP;
diff --git a/builtin/merge.c b/builtin/merge.c
index e47d77baee..5ce8946d39 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -113,12 +113,15 @@ static int option_parse_message(const struct option *opt,
return 0;
}
-static int option_read_message(struct parse_opt_ctx_t *ctx,
- const struct option *opt, int unset)
+static enum parse_opt_result option_read_message(struct parse_opt_ctx_t *ctx,
+ const struct option *opt,
+ const char *arg_not_used,
+ int unset)
{
struct strbuf *buf = opt->value;
const char *arg;
+ BUG_ON_OPT_ARG(arg_not_used);
if (unset)
BUG("-F cannot be negated");
@@ -262,7 +265,7 @@ static struct option builtin_merge_options[] = {
option_parse_message),
{ OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
N_("read message from file"), PARSE_OPT_NONEG,
- (parse_opt_cb *) option_read_message },
+ NULL, 0, option_read_message },
OPT__VERBOSITY(&verbosity),
OPT_BOOL(0, "abort", &abort_current_merge,
N_("abort the current in-progress merge")),
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index a9fac7c128..a154fc29f6 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -33,6 +33,7 @@
#include "object-store.h"
#include "dir.h"
#include "midx.h"
+#include "trace2.h"
#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
#define SIZE(obj) oe_size(&to_pack, obj)
@@ -3473,6 +3474,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
}
}
+ trace2_region_enter("pack-objects", "enumerate-objects",
+ the_repository);
prepare_packing_data(the_repository, &to_pack);
if (progress)
@@ -3487,12 +3490,23 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (include_tag && nr_result)
for_each_ref(add_ref_tag, NULL);
stop_progress(&progress_state);
+ trace2_region_leave("pack-objects", "enumerate-objects",
+ the_repository);
if (non_empty && !nr_result)
return 0;
- if (nr_result)
+ if (nr_result) {
+ trace2_region_enter("pack-objects", "prepare-pack",
+ the_repository);
prepare_pack(window, depth);
+ trace2_region_leave("pack-objects", "prepare-pack",
+ the_repository);
+ }
+
+ trace2_region_enter("pack-objects", "write-pack-file", the_repository);
write_pack_file();
+ trace2_region_leave("pack-objects", "write-pack-file", the_repository);
+
if (progress)
fprintf_ln(stderr,
_("Total %"PRIu32" (delta %"PRIu32"),"
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 11bc514566..68c1e547c2 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -32,14 +32,10 @@ static struct pack_list {
struct pack_list *next;
struct packed_git *pack;
struct llist *unique_objects;
- struct llist *all_objects;
+ struct llist *remaining_objects;
+ size_t all_objects_size;
} *local_packs = NULL, *altodb_packs = NULL;
-struct pll {
- struct pll *next;
- struct pack_list *pl;
-};
-
static struct llist_item *free_nodes;
static inline void llist_item_put(struct llist_item *item)
@@ -63,15 +59,6 @@ static inline struct llist_item *llist_item_get(void)
return new_item;
}
-static void llist_free(struct llist *list)
-{
- while ((list->back = list->front)) {
- list->front = list->front->next;
- llist_item_put(list->back);
- }
- free(list);
-}
-
static inline void llist_init(struct llist **list)
{
*list = xmalloc(sizeof(struct llist));
@@ -254,6 +241,11 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
struct llist_item *p1_hint = NULL, *p2_hint = NULL;
const unsigned int hashsz = the_hash_algo->rawsz;
+ if (!p1->unique_objects)
+ p1->unique_objects = llist_copy(p1->remaining_objects);
+ if (!p2->unique_objects)
+ p2->unique_objects = llist_copy(p2->remaining_objects);
+
p1_base = p1->pack->index_data;
p2_base = p2->pack->index_data;
p1_base += 256 * 4 + ((p1->pack->index_version < 2) ? 4 : 8);
@@ -285,78 +277,6 @@ static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
}
}
-static void pll_free(struct pll *l)
-{
- struct pll *old;
- struct pack_list *opl;
-
- while (l) {
- old = l;
- while (l->pl) {
- opl = l->pl;
- l->pl = opl->next;
- free(opl);
- }
- l = l->next;
- free(old);
- }
-}
-
-/* all the permutations have to be free()d at the same time,
- * since they refer to each other
- */
-static struct pll * get_permutations(struct pack_list *list, int n)
-{
- struct pll *subset, *ret = NULL, *new_pll = NULL;
-
- if (list == NULL || pack_list_size(list) < n || n == 0)
- return NULL;
-
- if (n == 1) {
- while (list) {
- new_pll = xmalloc(sizeof(*new_pll));
- new_pll->pl = NULL;
- pack_list_insert(&new_pll->pl, list);
- new_pll->next = ret;
- ret = new_pll;
- list = list->next;
- }
- return ret;
- }
-
- while (list->next) {
- subset = get_permutations(list->next, n - 1);
- while (subset) {
- new_pll = xmalloc(sizeof(*new_pll));
- new_pll->pl = subset->pl;
- pack_list_insert(&new_pll->pl, list);
- new_pll->next = ret;
- ret = new_pll;
- subset = subset->next;
- }
- list = list->next;
- }
- return ret;
-}
-
-static int is_superset(struct pack_list *pl, struct llist *list)
-{
- struct llist *diff;
-
- diff = llist_copy(list);
-
- while (pl) {
- llist_sorted_difference_inplace(diff, pl->all_objects);
- if (diff->size == 0) { /* we're done */
- llist_free(diff);
- return 1;
- }
- pl = pl->next;
- }
- llist_free(diff);
- return 0;
-}
-
static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
{
size_t ret = 0;
@@ -421,14 +341,58 @@ static inline off_t pack_set_bytecount(struct pack_list *pl)
return ret;
}
+static int cmp_remaining_objects(const void *a, const void *b)
+{
+ struct pack_list *pl_a = *((struct pack_list **)a);
+ struct pack_list *pl_b = *((struct pack_list **)b);
+
+ if (pl_a->remaining_objects->size == pl_b->remaining_objects->size) {
+ /* have the same remaining_objects, big pack first */
+ if (pl_a->all_objects_size == pl_b->all_objects_size)
+ return 0;
+ else if (pl_a->all_objects_size < pl_b->all_objects_size)
+ return 1;
+ else
+ return -1;
+ } else if (pl_a->remaining_objects->size < pl_b->remaining_objects->size) {
+ /* sort by remaining objects, more objects first */
+ return 1;
+ } else {
+ return -1;
+ }
+}
+
+/* Sort pack_list, greater size of remaining_objects first */
+static void sort_pack_list(struct pack_list **pl)
+{
+ struct pack_list **ary, *p;
+ int i;
+ size_t n = pack_list_size(*pl);
+
+ if (n < 2)
+ return;
+
+ /* prepare an array of packed_list for easier sorting */
+ ary = xcalloc(n, sizeof(struct pack_list *));
+ for (n = 0, p = *pl; p; p = p->next)
+ ary[n++] = p;
+
+ QSORT(ary, n, cmp_remaining_objects);
+
+ /* link them back again */
+ for (i = 0; i < n - 1; i++)
+ ary[i]->next = ary[i + 1];
+ ary[n - 1]->next = NULL;
+ *pl = ary[0];
+
+ free(ary);
+}
+
+
static void minimize(struct pack_list **min)
{
- struct pack_list *pl, *unique = NULL,
- *non_unique = NULL, *min_perm = NULL;
- struct pll *perm, *perm_all, *perm_ok = NULL, *new_perm;
- struct llist *missing;
- off_t min_perm_size = 0, perm_size;
- int n;
+ struct pack_list *pl, *unique = NULL, *non_unique = NULL;
+ struct llist *missing, *unique_pack_objects;
pl = local_packs;
while (pl) {
@@ -442,53 +406,41 @@ static void minimize(struct pack_list **min)
missing = llist_copy(all_objects);
pl = unique;
while (pl) {
- llist_sorted_difference_inplace(missing, pl->all_objects);
+ llist_sorted_difference_inplace(missing, pl->remaining_objects);
pl = pl->next;
}
+ *min = unique;
+
/* return if there are no objects missing from the unique set */
if (missing->size == 0) {
- *min = unique;
free(missing);
return;
}
- /* find the permutations which contain all missing objects */
- for (n = 1; n <= pack_list_size(non_unique) && !perm_ok; n++) {
- perm_all = perm = get_permutations(non_unique, n);
- while (perm) {
- if (is_superset(perm->pl, missing)) {
- new_perm = xmalloc(sizeof(struct pll));
- memcpy(new_perm, perm, sizeof(struct pll));
- new_perm->next = perm_ok;
- perm_ok = new_perm;
- }
- perm = perm->next;
- }
- if (perm_ok)
- break;
- pll_free(perm_all);
- }
- if (perm_ok == NULL)
- die("Internal error: No complete sets found!");
-
- /* find the permutation with the smallest size */
- perm = perm_ok;
- while (perm) {
- perm_size = pack_set_bytecount(perm->pl);
- if (!min_perm_size || min_perm_size > perm_size) {
- min_perm_size = perm_size;
- min_perm = perm->pl;
- }
- perm = perm->next;
- }
- *min = min_perm;
- /* add the unique packs to the list */
- pl = unique;
+ unique_pack_objects = llist_copy(all_objects);
+ llist_sorted_difference_inplace(unique_pack_objects, missing);
+
+ /* remove unique pack objects from the non_unique packs */
+ pl = non_unique;
while (pl) {
- pack_list_insert(min, pl);
+ llist_sorted_difference_inplace(pl->remaining_objects, unique_pack_objects);
pl = pl->next;
}
+
+ while (non_unique) {
+ /* sort the non_unique packs, greater size of remaining_objects first */
+ sort_pack_list(&non_unique);
+ if (non_unique->remaining_objects->size == 0)
+ break;
+
+ pack_list_insert(min, non_unique);
+
+ for (pl = non_unique->next; pl && pl->remaining_objects->size > 0; pl = pl->next)
+ llist_sorted_difference_inplace(pl->remaining_objects, non_unique->remaining_objects);
+
+ non_unique = non_unique->next;
+ }
}
static void load_all_objects(void)
@@ -500,7 +452,7 @@ static void load_all_objects(void)
while (pl) {
hint = NULL;
- l = pl->all_objects->front;
+ l = pl->remaining_objects->front;
while (l) {
hint = llist_insert_sorted_unique(all_objects,
l->oid, hint);
@@ -511,7 +463,7 @@ static void load_all_objects(void)
/* remove objects present in remote packs */
pl = altodb_packs;
while (pl) {
- llist_sorted_difference_inplace(all_objects, pl->all_objects);
+ llist_sorted_difference_inplace(all_objects, pl->remaining_objects);
pl = pl->next;
}
}
@@ -536,11 +488,10 @@ static void scan_alt_odb_packs(void)
while (alt) {
local = local_packs;
while (local) {
- llist_sorted_difference_inplace(local->unique_objects,
- alt->all_objects);
+ llist_sorted_difference_inplace(local->remaining_objects,
+ alt->remaining_objects);
local = local->next;
}
- llist_sorted_difference_inplace(all_objects, alt->all_objects);
alt = alt->next;
}
}
@@ -555,7 +506,7 @@ static struct pack_list * add_pack(struct packed_git *p)
return NULL;
l.pack = p;
- llist_init(&l.all_objects);
+ llist_init(&l.remaining_objects);
if (open_pack_index(p))
return NULL;
@@ -564,11 +515,11 @@ static struct pack_list * add_pack(struct packed_git *p)
base += 256 * 4 + ((p->index_version < 2) ? 4 : 8);
step = the_hash_algo->rawsz + ((p->index_version < 2) ? 4 : 0);
while (off < p->num_objects * step) {
- llist_insert_back(l.all_objects, (const struct object_id *)(base + off));
+ llist_insert_back(l.remaining_objects, (const struct object_id *)(base + off));
off += step;
}
- /* this list will be pruned in cmp_two_packs later */
- l.unique_objects = llist_copy(l.all_objects);
+ l.all_objects_size = l.remaining_objects->size;
+ l.unique_objects = NULL;
if (p->pack_local)
return pack_list_insert(&local_packs, &l);
else
@@ -603,7 +554,7 @@ static void load_all(void)
int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
{
int i;
- struct pack_list *min, *red, *pl;
+ struct pack_list *min = NULL, *red, *pl;
struct llist *ignore;
struct object_id *oid;
char buf[GIT_MAX_HEXSZ + 2]; /* hex hash + \n + \0 */
@@ -646,7 +597,6 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
load_all_objects();
- cmp_local_packs();
if (alt_odb)
scan_alt_odb_packs();
@@ -663,10 +613,12 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
llist_sorted_difference_inplace(all_objects, ignore);
pl = local_packs;
while (pl) {
- llist_sorted_difference_inplace(pl->unique_objects, ignore);
+ llist_sorted_difference_inplace(pl->remaining_objects, ignore);
pl = pl->next;
}
+ cmp_local_packs();
+
minimize(&min);
if (verbose) {
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index a9e7b552b9..48c5e78e33 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -63,6 +63,11 @@ int cmd_prune_packed(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, prune_packed_options,
prune_packed_usage, 0);
+ if (argc > 0)
+ usage_msg_opt(_("too many arguments"),
+ prune_packed_usage,
+ prune_packed_options);
+
prune_packed_objects(opts);
return 0;
}
diff --git a/builtin/prune.c b/builtin/prune.c
index 1ec9ddd751..97613eccb5 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -31,16 +31,39 @@ static int prune_tmp_file(const char *fullpath)
return 0;
}
+static void perform_reachability_traversal(struct rev_info *revs)
+{
+ static int initialized;
+ struct progress *progress = NULL;
+
+ if (initialized)
+ return;
+
+ if (show_progress)
+ progress = start_delayed_progress(_("Checking connectivity"), 0);
+ mark_reachable_objects(revs, 1, expire, progress);
+ stop_progress(&progress);
+ initialized = 1;
+}
+
+static int is_object_reachable(const struct object_id *oid,
+ struct rev_info *revs)
+{
+ struct object *obj;
+
+ perform_reachability_traversal(revs);
+
+ obj = lookup_object(the_repository, oid->hash);
+ return obj && (obj->flags & SEEN);
+}
+
static int prune_object(const struct object_id *oid, const char *fullpath,
void *data)
{
+ struct rev_info *revs = data;
struct stat st;
- /*
- * Do we know about this object?
- * It must have been reachable
- */
- if (lookup_object(the_repository, oid->hash))
+ if (is_object_reachable(oid, revs))
return 0;
if (lstat(fullpath, &st)) {
@@ -102,7 +125,6 @@ static void remove_temporary_files(const char *path)
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")),
@@ -142,17 +164,13 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
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_cruft, prune_subdir, &revs);
prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0);
remove_temporary_files(get_object_directory());
@@ -160,8 +178,10 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
remove_temporary_files(s);
free(s);
- if (is_repository_shallow(the_repository))
+ if (is_repository_shallow(the_repository)) {
+ perform_reachability_traversal(&revs);
prune_shallow(show_only ? PRUNE_SHOW_ONLY : 0);
+ }
return 0;
}
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 7c7bc13e91..52114cbf0d 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1027,6 +1027,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
ACTION_EDIT_TODO,
ACTION_SHOW_CURRENT_PATCH,
} action = NO_ACTION;
+ static const char *action_names[] = { N_("undefined"),
+ N_("continue"),
+ N_("skip"),
+ N_("abort"),
+ N_("quit"),
+ N_("edit_todo"),
+ N_("show_current_patch"),
+ NULL };
const char *gpg_sign = NULL;
struct string_list exec = STRING_LIST_INIT_NODUP;
const char *rebase_merges = NULL;
@@ -1212,6 +1220,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("The --edit-todo action can only be used during "
"interactive rebase."));
+ if (trace2_is_enabled()) {
+ if (is_interactive(&options))
+ trace2_cmd_mode("interactive");
+ else if (exec.nr)
+ trace2_cmd_mode("interactive-exec");
+ else
+ trace2_cmd_mode(action_names[action]);
+ }
+
switch (action) {
case ACTION_CONTINUE: {
struct object_id head;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d58b7750b6..8bc714a5fc 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -694,6 +694,8 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
proc.argv = argv;
proc.in = -1;
proc.stdout_to_stderr = 1;
+ proc.trace2_hook_name = hook_name;
+
if (feed_state->push_options) {
int i;
for (i = 0; i < feed_state->push_options->nr; i++)
@@ -807,6 +809,7 @@ static int run_update_hook(struct command *cmd)
proc.stdout_to_stderr = 1;
proc.err = use_sideband ? -1 : 0;
proc.argv = argv;
+ proc.trace2_hook_name = "update";
code = start_command(&proc);
if (code)
@@ -1190,6 +1193,7 @@ static void run_update_post_hook(struct command *commands)
proc.no_stdin = 1;
proc.stdout_to_stderr = 1;
proc.err = use_sideband ? -1 : 0;
+ proc.trace2_hook_name = "post-update";
if (!start_command(&proc)) {
if (use_sideband)
diff --git a/builtin/reset.c b/builtin/reset.c
index 4d18a461fa..7882829a95 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -341,6 +341,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (patch_mode) {
if (reset_type != NONE)
die(_("--patch is incompatible with --{hard,mixed,soft}"));
+ trace2_cmd_mode("patch-interactive");
return run_add_interactive(rev, "--patch=reset", &pathspec);
}
@@ -357,6 +358,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (reset_type == NONE)
reset_type = MIXED; /* by default */
+ if (pathspec.nr)
+ trace2_cmd_mode("path");
+ else
+ trace2_cmd_mode(reset_type_names[reset_type]);
+
if (reset_type != SOFT && (reset_type != MIXED || get_git_work_tree()))
setup_work_tree();
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index b80fc4ba3d..6bcc4f1bd7 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1816,11 +1816,10 @@ static int update_submodules(struct submodule_update_clone *suc)
{
int i;
- run_processes_parallel(suc->max_jobs,
- update_clone_get_next_task,
- update_clone_start_failure,
- update_clone_task_finished,
- suc);
+ run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
+ update_clone_start_failure,
+ update_clone_task_finished, suc, "submodule",
+ "parallel/update");
/*
* We saved the output and put it out all at once now.
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 02ace602b9..1b6c42f748 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -848,14 +848,16 @@ static int parse_new_style_cacheinfo(const char *arg,
return 0;
}
-static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,
- const struct option *opt, int unset)
+static enum parse_opt_result cacheinfo_callback(
+ struct parse_opt_ctx_t *ctx, const struct option *opt,
+ const char *arg, int unset)
{
struct object_id oid;
unsigned int mode;
const char *path;
BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
if (!parse_new_style_cacheinfo(ctx->argv[1], &mode, &oid, &path)) {
if (add_cacheinfo(mode, &oid, path, 0))
@@ -874,12 +876,14 @@ static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,
return 0;
}
-static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx,
- const struct option *opt, int unset)
+static enum parse_opt_result stdin_cacheinfo_callback(
+ struct parse_opt_ctx_t *ctx, const struct option *opt,
+ const char *arg, int unset)
{
int *nul_term_line = opt->value;
BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
if (ctx->argc != 1)
return error("option '%s' must be the last argument", opt->long_name);
@@ -888,12 +892,14 @@ static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx,
return 0;
}
-static int stdin_callback(struct parse_opt_ctx_t *ctx,
- const struct option *opt, int unset)
+static enum parse_opt_result stdin_callback(
+ struct parse_opt_ctx_t *ctx, const struct option *opt,
+ const char *arg, int unset)
{
int *read_from_stdin = opt->value;
BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
if (ctx->argc != 1)
return error("option '%s' must be the last argument", opt->long_name);
@@ -901,13 +907,15 @@ static int stdin_callback(struct parse_opt_ctx_t *ctx,
return 0;
}
-static int unresolve_callback(struct parse_opt_ctx_t *ctx,
- const struct option *opt, int unset)
+static enum parse_opt_result unresolve_callback(
+ struct parse_opt_ctx_t *ctx, const struct option *opt,
+ const char *arg, int unset)
{
int *has_errors = opt->value;
const char *prefix = startup_info->prefix;
BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
/* consume remaining arguments. */
*has_errors = do_unresolve(ctx->argc, ctx->argv,
@@ -920,13 +928,15 @@ static int unresolve_callback(struct parse_opt_ctx_t *ctx,
return 0;
}
-static int reupdate_callback(struct parse_opt_ctx_t *ctx,
- const struct option *opt, int unset)
+static enum parse_opt_result reupdate_callback(
+ struct parse_opt_ctx_t *ctx, const struct option *opt,
+ const char *arg, int unset)
{
int *has_errors = opt->value;
const char *prefix = startup_info->prefix;
BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
/* consume remaining arguments. */
setup_work_tree();
@@ -986,7 +996,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
N_("add the specified entry to the index"),
PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
- (parse_opt_cb *) cacheinfo_callback},
+ NULL, 0,
+ cacheinfo_callback},
{OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+|-)x",
N_("override the executable bit of the listed files"),
PARSE_OPT_NONEG,
@@ -1012,19 +1023,19 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
{OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL,
N_("read list of paths to be updated from standard input"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
- (parse_opt_cb *) stdin_callback},
+ NULL, 0, stdin_callback},
{OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL,
N_("add entries from standard input to the index"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
- (parse_opt_cb *) stdin_cacheinfo_callback},
+ NULL, 0, stdin_cacheinfo_callback},
{OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL,
N_("repopulate stages #2 and #3 for the listed paths"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
- (parse_opt_cb *) unresolve_callback},
+ NULL, 0, unresolve_callback},
{OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL,
N_("only update entries that differ from HEAD"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
- (parse_opt_cb *) reupdate_callback},
+ NULL, 0, reupdate_callback},
OPT_BIT(0, "ignore-missing", &refresh_args.flags,
N_("ignore files missing from worktree"),
REFRESH_IGNORE_MISSING),
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 3f9907fcc9..6cc094a453 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -402,6 +402,7 @@ done:
cp.dir = path;
cp.env = env;
cp.argv = NULL;
+ cp.trace2_hook_name = "post-checkout";
argv_array_pushl(&cp.args, absolute_path(hook),
oid_to_hex(&null_oid),
oid_to_hex(&commit->object.oid),