aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c5
-rw-r--r--builtin/am.c7
-rw-r--r--builtin/branch.c2
-rw-r--r--builtin/cat-file.c4
-rw-r--r--builtin/check-attr.c3
-rw-r--r--builtin/checkout-index.c17
-rw-r--r--builtin/checkout.c15
-rw-r--r--builtin/commit-graph.c32
-rw-r--r--builtin/describe.c12
-rw-r--r--builtin/diff-files.c12
-rw-r--r--builtin/diff-index.c4
-rw-r--r--builtin/diff-tree.c2
-rw-r--r--builtin/diff.c82
-rw-r--r--builtin/fast-export.c36
-rw-r--r--builtin/fast-import.c1
-rw-r--r--builtin/fetch.c6
-rw-r--r--builtin/fsmonitor--daemon.c10
-rw-r--r--builtin/gc.c318
-rw-r--r--builtin/grep.c7
-rw-r--r--builtin/index-pack.c5
-rw-r--r--builtin/interpret-trailers.c31
-rw-r--r--builtin/log.c93
-rw-r--r--builtin/ls-tree.c3
-rw-r--r--builtin/merge-tree.c20
-rw-r--r--builtin/merge.c51
-rw-r--r--builtin/mv.c2
-rw-r--r--builtin/name-rev.c8
-rw-r--r--builtin/pack-objects.c40
-rw-r--r--builtin/read-tree.c2
-rw-r--r--builtin/rebase.c3
-rw-r--r--builtin/receive-pack.c6
-rw-r--r--builtin/repack.c680
-rw-r--r--builtin/stash.c24
-rw-r--r--builtin/submodule--helper.c37
-rw-r--r--builtin/unpack-objects.c5
-rw-r--r--builtin/update-index.c121
-rw-r--r--builtin/update-ref.c14
-rw-r--r--builtin/var.c2
-rw-r--r--builtin/worktree.c10
39 files changed, 1081 insertions, 651 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 4b0dd798df..c27254a5cd 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -194,8 +194,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
out = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
rev.diffopt.file = xfdopen(out, "w");
rev.diffopt.close_file = 1;
- if (run_diff_files(&rev, 0))
- die(_("Could not write patch"));
+ run_diff_files(&rev, 0);
if (launch_editor(file, NULL, NULL))
die(_("editing patch failed"));
@@ -232,6 +231,8 @@ static char *chmod_arg;
static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
{
+ BUG_ON_OPT_ARG(arg);
+
/* if we are told to ignore, we are not adding removals */
*(int *)opt->value = !unset ? 0 : 1;
return 0;
diff --git a/builtin/am.c b/builtin/am.c
index 8bde034fae..6655059a57 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1430,7 +1430,7 @@ static void write_index_patch(const struct am_state *state)
rev_info.diffopt.close_file = 1;
add_pending_object(&rev_info, &tree->object, "");
diff_setup_done(&rev_info.diffopt);
- run_diff_index(&rev_info, 1);
+ run_diff_index(&rev_info, DIFF_INDEX_CACHED);
release_revisions(&rev_info);
}
@@ -1593,7 +1593,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
rev_info.diffopt.filter |= diff_filter_bit('M');
add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
diff_setup_done(&rev_info.diffopt);
- run_diff_index(&rev_info, 1);
+ run_diff_index(&rev_info, DIFF_INDEX_CACHED);
release_revisions(&rev_info);
}
@@ -2303,7 +2303,8 @@ static int parse_opt_show_current_patch(const struct option *opt, const char *ar
if (resume->mode == RESUME_SHOW_PATCH && new_value != resume->sub_mode)
return error(_("options '%s=%s' and '%s=%s' "
"cannot be used together"),
- "--show-current-patch", "--show-current-patch", arg, valid_modes[resume->sub_mode]);
+ "--show-current-patch", arg,
+ "--show-current-patch", valid_modes[resume->sub_mode]);
resume->mode = RESUME_SHOW_PATCH;
resume->sub_mode = new_value;
diff --git a/builtin/branch.c b/builtin/branch.c
index 08da650516..2ec190b14a 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -261,7 +261,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
const char *path;
if ((path = branch_checked_out(name))) {
error(_("Cannot delete branch '%s' "
- "checked out at '%s'"),
+ "used by worktree at '%s'"),
bname.buf, path);
ret = 1;
continue;
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 694c8538df..ea8ad601ec 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -922,11 +922,11 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
N_("git cat-file <type> <object>"),
N_("git cat-file (-e | -p) <object>"),
N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
+ N_("git cat-file (--textconv | --filters)\n"
+ " [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
" [--textconv | --filters] [-Z]"),
- N_("git cat-file (--textconv | --filters)\n"
- " [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
NULL
};
const struct option options[] = {
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index b22ff748c3..c1da1d184e 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -122,6 +122,9 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, check_attr_options,
check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
if (repo_read_index(the_repository) < 0) {
die("invalid cache");
}
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index f62f13f2b5..3b68b47615 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -24,7 +24,7 @@
static int nul_term_line;
static int checkout_stage; /* default to checkout stage0 */
static int ignore_skip_worktree; /* default to 0 */
-static int to_tempfile;
+static int to_tempfile = -1;
static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
static struct checkout state = CHECKOUT_INIT;
@@ -193,15 +193,16 @@ static const char * const builtin_checkout_index_usage[] = {
static int option_parse_stage(const struct option *opt,
const char *arg, int unset)
{
+ int *stage = opt->value;
+
BUG_ON_OPT_NEG(unset);
if (!strcmp(arg, "all")) {
- to_tempfile = 1;
- checkout_stage = CHECKOUT_ALL;
+ *stage = CHECKOUT_ALL;
} else {
int ch = arg[0];
if ('1' <= ch && ch <= '3')
- checkout_stage = arg[0] - '0';
+ *stage = arg[0] - '0';
else
die(_("stage should be between 1 and 3 or all"));
}
@@ -239,7 +240,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
N_("write the content to temporary files")),
OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
N_("when creating files, prepend <string>")),
- OPT_CALLBACK_F(0, "stage", NULL, "(1|2|3|all)",
+ OPT_CALLBACK_F(0, "stage", &checkout_stage, "(1|2|3|all)",
N_("copy out the files from named stage"),
PARSE_OPT_NONEG, option_parse_stage),
OPT_END()
@@ -269,6 +270,12 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
state.base_dir = "";
state.base_dir_len = strlen(state.base_dir);
+ if (to_tempfile < 0)
+ to_tempfile = (checkout_stage == CHECKOUT_ALL);
+ if (!to_tempfile && checkout_stage == CHECKOUT_ALL)
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--stage=all", "--no-temp");
+
/*
* when --prefix is specified we do not want to update cache.
*/
diff --git a/builtin/checkout.c b/builtin/checkout.c
index f53612f468..f02434bc15 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -523,6 +523,15 @@ static int checkout_paths(const struct checkout_opts *opts,
"--merge", "--conflict", "--staged");
}
+ /*
+ * recreating unmerged index entries and writing out data from
+ * unmerged index entries would make no sense when checking out
+ * of a tree-ish.
+ */
+ if ((opts->merge || opts->writeout_stage) && opts->source_tree)
+ die(_("'%s', '%s', or '%s' cannot be used when checking out of a tree"),
+ "--merge", "--ours", "--theirs");
+
if (opts->patch_mode) {
enum add_p_mode patch_mode;
const char *rev = new_branch_info->name;
@@ -560,6 +569,8 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->source_tree)
read_tree_some(opts->source_tree, &opts->pathspec);
+ if (opts->merge)
+ unmerge_index(&the_index, &opts->pathspec, CE_MATCHED);
ps_matched = xcalloc(opts->pathspec.nr, 1);
@@ -583,10 +594,6 @@ static int checkout_paths(const struct checkout_opts *opts,
}
free(ps_matched);
- /* "checkout -m path" to recreate conflicted state */
- if (opts->merge)
- unmerge_marked_index(&the_index);
-
/* Any unmerged paths? */
for (pos = 0; pos < the_index.cache_nr; pos++) {
const struct cache_entry *ce = the_index.cache[pos];
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index c88389df24..45d035af60 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -69,10 +69,12 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
struct commit_graph *graph = NULL;
struct object_directory *odb = NULL;
char *graph_name;
- int open_ok;
+ char *chain_name;
+ enum { OPENED_NONE, OPENED_GRAPH, OPENED_CHAIN } opened = OPENED_NONE;
int fd;
struct stat st;
int flags = 0;
+ int incomplete_chain = 0;
int ret;
static struct option builtin_commit_graph_verify_options[] = {
@@ -102,24 +104,39 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
odb = find_odb(the_repository, opts.obj_dir);
graph_name = get_commit_graph_filename(odb);
- open_ok = open_commit_graph(graph_name, &fd, &st);
- if (!open_ok && errno != ENOENT)
+ chain_name = get_commit_graph_chain_filename(odb);
+ if (open_commit_graph(graph_name, &fd, &st))
+ opened = OPENED_GRAPH;
+ else if (errno != ENOENT)
die_errno(_("Could not open commit-graph '%s'"), graph_name);
+ else if (open_commit_graph_chain(chain_name, &fd, &st))
+ opened = OPENED_CHAIN;
+ else if (errno != ENOENT)
+ die_errno(_("could not open commit-graph chain '%s'"), chain_name);
FREE_AND_NULL(graph_name);
+ FREE_AND_NULL(chain_name);
FREE_AND_NULL(options);
- if (open_ok)
+ if (opened == OPENED_NONE)
+ return 0;
+ else if (opened == OPENED_GRAPH)
graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
else
- graph = read_commit_graph_one(the_repository, odb);
+ graph = load_commit_graph_chain_fd_st(the_repository, fd, &st,
+ &incomplete_chain);
- /* Return failure if open_ok predicted success */
if (!graph)
- return !!open_ok;
+ return 1;
ret = verify_commit_graph(the_repository, graph, flags);
free_commit_graph(graph);
+
+ if (incomplete_chain) {
+ error("one or more commit-graph chain files could not be loaded");
+ ret |= 1;
+ }
+
return ret;
}
@@ -311,6 +328,7 @@ cleanup:
FREE_AND_NULL(options);
string_list_clear(&pack_indexes, 0);
strbuf_release(&buf);
+ oidset_clear(&commits);
return result;
}
diff --git a/builtin/describe.c b/builtin/describe.c
index b28a4a1f82..fb6b0508f3 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -561,9 +561,11 @@ static void describe(const char *arg, int last_one)
static int option_parse_exact_match(const struct option *opt, const char *arg,
int unset)
{
+ int *val = opt->value;
+
BUG_ON_OPT_ARG(arg);
- max_candidates = unset ? DEFAULT_CANDIDATES : 0;
+ *val = unset ? DEFAULT_CANDIDATES : 0;
return 0;
}
@@ -578,7 +580,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "long", &longformat, N_("always use long format")),
OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
OPT__ABBREV(&abbrev),
- OPT_CALLBACK_F(0, "exact-match", NULL, NULL,
+ OPT_CALLBACK_F(0, "exact-match", &max_candidates, NULL,
N_("only output exact matches"),
PARSE_OPT_NOARG, option_parse_exact_match),
OPT_INTEGER(0, "candidates", &max_candidates,
@@ -668,7 +670,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
struct lock_file index_lock = LOCK_INIT;
struct rev_info revs;
struct strvec args = STRVEC_INIT;
- int fd, result;
+ int fd;
setup_work_tree();
prepare_repo_settings(the_repository);
@@ -685,9 +687,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
strvec_pushv(&args, diff_index_args);
if (setup_revisions(args.nr, args.v, &revs, NULL) != 1)
BUG("malformed internal diff-index command line");
- result = run_diff_index(&revs, 0);
+ run_diff_index(&revs, 0);
- if (!diff_result_code(&revs.diffopt, result))
+ if (!diff_result_code(&revs.diffopt))
suffix = NULL;
else
suffix = dirty;
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 50330b8dd2..f38912cd40 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -80,14 +80,10 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
(rev.diffopt.output_format & DIFF_FORMAT_PATCH))
diff_merges_set_dense_combined_if_unset(&rev);
- if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
- perror("repo_read_index_preload");
- result = -1;
- goto cleanup;
- }
- result = run_diff_files(&rev, options);
- result = diff_result_code(&rev.diffopt, result);
-cleanup:
+ if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0)
+ die_errno("repo_read_index_preload");
+ run_diff_files(&rev, options);
+ result = diff_result_code(&rev.diffopt);
release_revisions(&rev);
return result;
}
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 9db7139b83..220f341ffa 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -72,8 +72,8 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
perror("repo_read_index");
return -1;
}
- result = run_diff_index(&rev, option);
- result = diff_result_code(&rev.diffopt, result);
+ run_diff_index(&rev, option);
+ result = diff_result_code(&rev.diffopt);
release_revisions(&rev);
return result;
}
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index c9ba35f143..86be634286 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -232,5 +232,5 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
diff_free(&opt->diffopt);
}
- return diff_result_code(&opt->diffopt, 0);
+ return diff_result_code(&opt->diffopt);
}
diff --git a/builtin/diff.c b/builtin/diff.c
index b19530c996..55e7d21755 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -77,9 +77,9 @@ static void stuff_change(struct diff_options *opt,
diff_queue(&diff_queued_diff, one, two);
}
-static int builtin_diff_b_f(struct rev_info *revs,
- int argc, const char **argv UNUSED,
- struct object_array_entry **blob)
+static void builtin_diff_b_f(struct rev_info *revs,
+ int argc, const char **argv UNUSED,
+ struct object_array_entry **blob)
{
/* Blob vs file in the working tree*/
struct stat st;
@@ -109,12 +109,11 @@ static int builtin_diff_b_f(struct rev_info *revs,
path);
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
- return 0;
}
-static int builtin_diff_blobs(struct rev_info *revs,
- int argc, const char **argv UNUSED,
- struct object_array_entry **blob)
+static void builtin_diff_blobs(struct rev_info *revs,
+ int argc, const char **argv UNUSED,
+ struct object_array_entry **blob)
{
const unsigned mode = canon_mode(S_IFREG | 0644);
@@ -134,11 +133,10 @@ static int builtin_diff_blobs(struct rev_info *revs,
blob_path(blob[0]), blob_path(blob[1]));
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
- return 0;
}
-static int builtin_diff_index(struct rev_info *revs,
- int argc, const char **argv)
+static void builtin_diff_index(struct rev_info *revs,
+ int argc, const char **argv)
{
unsigned int option = 0;
while (1 < argc) {
@@ -163,20 +161,18 @@ static int builtin_diff_index(struct rev_info *revs,
setup_work_tree();
if (repo_read_index_preload(the_repository,
&revs->diffopt.pathspec, 0) < 0) {
- perror("repo_read_index_preload");
- return -1;
+ die_errno("repo_read_index_preload");
}
} else if (repo_read_index(the_repository) < 0) {
- perror("repo_read_cache");
- return -1;
+ die_errno("repo_read_cache");
}
- return run_diff_index(revs, option);
+ run_diff_index(revs, option);
}
-static int builtin_diff_tree(struct rev_info *revs,
- int argc, const char **argv,
- struct object_array_entry *ent0,
- struct object_array_entry *ent1)
+static void builtin_diff_tree(struct rev_info *revs,
+ int argc, const char **argv,
+ struct object_array_entry *ent0,
+ struct object_array_entry *ent1)
{
const struct object_id *(oid[2]);
struct object_id mb_oid;
@@ -209,13 +205,12 @@ static int builtin_diff_tree(struct rev_info *revs,
}
diff_tree_oid(oid[0], oid[1], "", &revs->diffopt);
log_tree_diff_flush(revs);
- return 0;
}
-static int builtin_diff_combined(struct rev_info *revs,
- int argc, const char **argv UNUSED,
- struct object_array_entry *ent,
- int ents, int first_non_parent)
+static void builtin_diff_combined(struct rev_info *revs,
+ int argc, const char **argv UNUSED,
+ struct object_array_entry *ent,
+ int ents, int first_non_parent)
{
struct oid_array parents = OID_ARRAY_INIT;
int i;
@@ -236,7 +231,6 @@ static int builtin_diff_combined(struct rev_info *revs,
}
diff_tree_combined(&ent[first_non_parent].item->oid, &parents, revs);
oid_array_clear(&parents);
- return 0;
}
static void refresh_index_quietly(void)
@@ -254,7 +248,7 @@ static void refresh_index_quietly(void)
repo_update_index_if_able(the_repository, &lock_file);
}
-static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
+static void builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
{
unsigned int options = 0;
@@ -269,8 +263,10 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
options |= DIFF_SILENT_ON_REMOVED;
else if (!strcmp(argv[1], "-h"))
usage(builtin_diff_usage);
- else
- return error(_("invalid option: %s"), argv[1]);
+ else {
+ error(_("invalid option: %s"), argv[1]);
+ usage(builtin_diff_usage);
+ }
argv++; argc--;
}
@@ -287,10 +283,9 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
setup_work_tree();
if (repo_read_index_preload(the_repository, &revs->diffopt.pathspec,
0) < 0) {
- perror("repo_read_index_preload");
- return -1;
+ die_errno("repo_read_index_preload");
}
- return run_diff_files(revs, options);
+ run_diff_files(revs, options);
}
struct symdiff {
@@ -404,7 +399,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
int blobs = 0, paths = 0;
struct object_array_entry *blob[2];
int nongit = 0, no_index = 0;
- int result = 0;
+ int result;
struct symdiff sdiff;
/*
@@ -479,8 +474,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
repo_init_revisions(the_repository, &rev, prefix);
/* Set up defaults that will apply to both no-index and regular diffs. */
- rev.diffopt.stat_width = -1;
- rev.diffopt.stat_graph_width = -1;
+ init_diffstat_widths(&rev.diffopt);
rev.diffopt.flags.allow_external = 1;
rev.diffopt.flags.allow_textconv = 1;
@@ -583,17 +577,17 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (!ent.nr) {
switch (blobs) {
case 0:
- result = builtin_diff_files(&rev, argc, argv);
+ builtin_diff_files(&rev, argc, argv);
break;
case 1:
if (paths != 1)
usage(builtin_diff_usage);
- result = builtin_diff_b_f(&rev, argc, argv, blob);
+ builtin_diff_b_f(&rev, argc, argv, blob);
break;
case 2:
if (paths)
usage(builtin_diff_usage);
- result = builtin_diff_blobs(&rev, argc, argv, blob);
+ builtin_diff_blobs(&rev, argc, argv, blob);
break;
default:
usage(builtin_diff_usage);
@@ -602,18 +596,18 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
else if (blobs)
usage(builtin_diff_usage);
else if (ent.nr == 1)
- result = builtin_diff_index(&rev, argc, argv);
+ builtin_diff_index(&rev, argc, argv);
else if (ent.nr == 2) {
if (sdiff.warn)
warning(_("%s...%s: multiple merge bases, using %s"),
sdiff.left, sdiff.right, sdiff.base);
- result = builtin_diff_tree(&rev, argc, argv,
- &ent.objects[0], &ent.objects[1]);
+ builtin_diff_tree(&rev, argc, argv,
+ &ent.objects[0], &ent.objects[1]);
} else
- result = builtin_diff_combined(&rev, argc, argv,
- ent.objects, ent.nr,
- first_non_parent);
- result = diff_result_code(&rev.diffopt, result);
+ builtin_diff_combined(&rev, argc, argv,
+ ent.objects, ent.nr,
+ first_non_parent);
+ result = diff_result_code(&rev.diffopt);
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
release_revisions(&rev);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 56dc69fac1..70aff515ac 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -33,9 +33,9 @@ static const char *fast_export_usage[] = {
};
static int progress;
-static enum { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
-static enum { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
-static enum { REENCODE_ABORT, REENCODE_YES, REENCODE_NO } reencode_mode = REENCODE_ABORT;
+static enum signed_tag_mode { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
+static enum tag_of_filtered_mode { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
+static enum reencode_mode { REENCODE_ABORT, REENCODE_YES, REENCODE_NO } reencode_mode = REENCODE_ABORT;
static int fake_missing_tagger;
static int use_done_feature;
static int no_data;
@@ -53,16 +53,18 @@ static struct revision_sources revision_sources;
static int parse_opt_signed_tag_mode(const struct option *opt,
const char *arg, int unset)
{
+ enum signed_tag_mode *val = opt->value;
+
if (unset || !strcmp(arg, "abort"))
- signed_tag_mode = SIGNED_TAG_ABORT;
+ *val = SIGNED_TAG_ABORT;
else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
- signed_tag_mode = VERBATIM;
+ *val = VERBATIM;
else if (!strcmp(arg, "warn"))
- signed_tag_mode = WARN;
+ *val = WARN;
else if (!strcmp(arg, "warn-strip"))
- signed_tag_mode = WARN_STRIP;
+ *val = WARN_STRIP;
else if (!strcmp(arg, "strip"))
- signed_tag_mode = STRIP;
+ *val = STRIP;
else
return error("Unknown signed-tags mode: %s", arg);
return 0;
@@ -71,12 +73,14 @@ static int parse_opt_signed_tag_mode(const struct option *opt,
static int parse_opt_tag_of_filtered_mode(const struct option *opt,
const char *arg, int unset)
{
+ enum tag_of_filtered_mode *val = opt->value;
+
if (unset || !strcmp(arg, "abort"))
- tag_of_filtered_mode = TAG_FILTERING_ABORT;
+ *val = TAG_FILTERING_ABORT;
else if (!strcmp(arg, "drop"))
- tag_of_filtered_mode = DROP;
+ *val = DROP;
else if (!strcmp(arg, "rewrite"))
- tag_of_filtered_mode = REWRITE;
+ *val = REWRITE;
else
return error("Unknown tag-of-filtered mode: %s", arg);
return 0;
@@ -85,21 +89,23 @@ static int parse_opt_tag_of_filtered_mode(const struct option *opt,
static int parse_opt_reencode_mode(const struct option *opt,
const char *arg, int unset)
{
+ enum reencode_mode *val = opt->value;
+
if (unset) {
- reencode_mode = REENCODE_ABORT;
+ *val = REENCODE_ABORT;
return 0;
}
switch (git_parse_maybe_bool(arg)) {
case 0:
- reencode_mode = REENCODE_NO;
+ *val = REENCODE_NO;
break;
case 1:
- reencode_mode = REENCODE_YES;
+ *val = REENCODE_YES;
break;
default:
if (!strcasecmp(arg, "abort"))
- reencode_mode = REENCODE_ABORT;
+ *val = REENCODE_ABORT;
else
return error("Unknown reencoding mode: %s", arg);
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 4dbb10aff3..444f41cf8c 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -1102,6 +1102,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
|| (pack_size + PACK_SIZE_THRESHOLD + len) < pack_size)
cycle_packfile();
+ the_hash_algo->init_fn(&checkpoint.ctx);
hashfile_checkpoint(pack_file, &checkpoint);
offset = checkpoint.offset;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index eed4a7cdb6..fd134ba74d 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -176,7 +176,7 @@ static int parse_refmap_arg(const struct option *opt, const char *arg, int unset
* "git fetch --refmap='' origin foo"
* can be used to tell the command not to store anywhere
*/
- refspec_append(&refmap, arg);
+ refspec_append(opt->value, arg);
return 0;
}
@@ -308,7 +308,7 @@ static void clear_item(struct refname_hash_entry *item)
static void add_already_queued_tags(const char *refname,
- const struct object_id *old_oid,
+ const struct object_id *old_oid UNUSED,
const struct object_id *new_oid,
void *cb_data)
{
@@ -2204,7 +2204,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
OPT_BOOL(0, "update-shallow", &update_shallow,
N_("accept refs that update .git/shallow")),
- OPT_CALLBACK_F(0, "refmap", NULL, N_("refmap"),
+ OPT_CALLBACK_F(0, "refmap", &refmap, N_("refmap"),
N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
OPT_IPVERSION(&family),
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 7e99c4d61b..5d01db5c02 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -129,8 +129,9 @@ struct fsmonitor_cookie_item {
enum fsmonitor_cookie_item_result result;
};
-static int cookies_cmp(const void *data, const struct hashmap_entry *he1,
- const struct hashmap_entry *he2, const void *keydata)
+static int cookies_cmp(const void *data UNUSED,
+ const struct hashmap_entry *he1,
+ const struct hashmap_entry *he2, const void *keydata)
{
const struct fsmonitor_cookie_item *a =
container_of(he1, const struct fsmonitor_cookie_item, entry);
@@ -1412,7 +1413,7 @@ done:
return err;
}
-static int try_to_run_foreground_daemon(int detach_console)
+static int try_to_run_foreground_daemon(int detach_console MAYBE_UNUSED)
{
/*
* Technically, we don't need to probe for an existing daemon
@@ -1442,7 +1443,8 @@ static int try_to_run_foreground_daemon(int detach_console)
static start_bg_wait_cb bg_wait_cb;
-static int bg_wait_cb(const struct child_process *cp, void *cb_data)
+static int bg_wait_cb(const struct child_process *cp UNUSED,
+ void *cb_data UNUSED)
{
enum ipc_active_state s = fsmonitor_ipc__get_state();
diff --git a/builtin/gc.c b/builtin/gc.c
index 5c4315f0d8..7c11d5ebef 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -52,6 +52,7 @@ static const char * const builtin_gc_usage[] = {
static int pack_refs = 1;
static int prune_reflogs = 1;
static int cruft_packs = 1;
+static unsigned long max_cruft_size;
static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
@@ -61,6 +62,8 @@ static timestamp_t gc_log_expire_time;
static const char *gc_log_expire = "1.day.ago";
static const char *prune_expire = "2.weeks.ago";
static const char *prune_worktrees_expire = "3.months.ago";
+static char *repack_filter;
+static char *repack_filter_to;
static unsigned long big_pack_threshold;
static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
@@ -163,6 +166,7 @@ static void gc_config(void)
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
git_config_get_bool("gc.autodetach", &detach_auto);
git_config_get_bool("gc.cruftpacks", &cruft_packs);
+ git_config_get_ulong("gc.maxcruftsize", &max_cruft_size);
git_config_get_expiry("gc.pruneexpire", &prune_expire);
git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
git_config_get_expiry("gc.logexpiry", &gc_log_expire);
@@ -170,6 +174,9 @@ static void gc_config(void)
git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
+ git_config_get_string("gc.repackfilter", &repack_filter);
+ git_config_get_string("gc.repackfilterto", &repack_filter_to);
+
git_config(git_default_config, NULL);
}
@@ -347,6 +354,9 @@ static void add_repack_all_option(struct string_list *keep_pack)
strvec_push(&repack, "--cruft");
if (prune_expire)
strvec_pushf(&repack, "--cruft-expiration=%s", prune_expire);
+ if (max_cruft_size)
+ strvec_pushf(&repack, "--max-cruft-size=%lu",
+ max_cruft_size);
} else {
strvec_push(&repack, "-A");
if (prune_expire)
@@ -355,6 +365,11 @@ static void add_repack_all_option(struct string_list *keep_pack)
if (keep_pack)
for_each_string_list(keep_pack, keep_one_pack, NULL);
+
+ if (repack_filter && *repack_filter)
+ strvec_pushf(&repack, "--filter=%s", repack_filter);
+ if (repack_filter_to && *repack_filter_to)
+ strvec_pushf(&repack, "--filter-to=%s", repack_filter_to);
}
static void add_repack_incremental_option(void)
@@ -575,6 +590,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
N_("prune unreferenced objects"),
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
OPT_BOOL(0, "cruft", &cruft_packs, N_("pack unreferenced objects separately")),
+ OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
+ N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
PARSE_OPT_NOCOMPLETE),
@@ -1403,7 +1420,7 @@ static void initialize_task_config(int schedule)
strbuf_release(&config_name);
}
-static int task_option_parse(const struct option *opt,
+static int task_option_parse(const struct option *opt UNUSED,
const char *arg, int unset)
{
int i, num_selected = 0;
@@ -1708,6 +1725,15 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
return 1;
}
+static int get_random_minute(void)
+{
+ /* Use a static value when under tests. */
+ if (getenv("GIT_TEST_MAINT_SCHEDULER"))
+ return 13;
+
+ return git_rand() % 60;
+}
+
static int is_launchctl_available(void)
{
const char *cmd = "launchctl";
@@ -1820,6 +1846,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT;
struct stat st;
const char *cmd = "launchctl";
+ int minute = get_random_minute();
get_schedule_cmd(&cmd, NULL);
preamble = "<?xml version=\"1.0\"?>\n"
@@ -1845,29 +1872,30 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
case SCHEDULE_HOURLY:
repeat = "<dict>\n"
"<key>Hour</key><integer>%d</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>%d</integer>\n"
"</dict>\n";
for (i = 1; i <= 23; i++)
- strbuf_addf(&plist, repeat, i);
+ strbuf_addf(&plist, repeat, i, minute);
break;
case SCHEDULE_DAILY:
repeat = "<dict>\n"
"<key>Day</key><integer>%d</integer>\n"
"<key>Hour</key><integer>0</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>%d</integer>\n"
"</dict>\n";
for (i = 1; i <= 6; i++)
- strbuf_addf(&plist, repeat, i);
+ strbuf_addf(&plist, repeat, i, minute);
break;
case SCHEDULE_WEEKLY:
- strbuf_addstr(&plist,
- "<dict>\n"
- "<key>Day</key><integer>0</integer>\n"
- "<key>Hour</key><integer>0</integer>\n"
- "<key>Minute</key><integer>0</integer>\n"
- "</dict>\n");
+ strbuf_addf(&plist,
+ "<dict>\n"
+ "<key>Day</key><integer>0</integer>\n"
+ "<key>Hour</key><integer>0</integer>\n"
+ "<key>Minute</key><integer>%d</integer>\n"
+ "</dict>\n",
+ minute);
break;
default:
@@ -1923,7 +1951,7 @@ static int launchctl_add_plists(void)
launchctl_schedule_plist(exec_path, SCHEDULE_WEEKLY);
}
-static int launchctl_update_schedule(int run_maintenance, int fd)
+static int launchctl_update_schedule(int run_maintenance, int fd UNUSED)
{
if (run_maintenance)
return launchctl_add_plists();
@@ -1984,6 +2012,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
const char *frequency = get_frequency(schedule);
char *name = schtasks_task_name(frequency);
struct strbuf tfilename = STRBUF_INIT;
+ int minute = get_random_minute();
get_schedule_cmd(&cmd, NULL);
@@ -2004,7 +2033,7 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
switch (schedule) {
case SCHEDULE_HOURLY:
fprintf(tfile->fp,
- "<StartBoundary>2020-01-01T01:00:00</StartBoundary>\n"
+ "<StartBoundary>2020-01-01T01:%02d:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByDay>\n"
"<DaysInterval>1</DaysInterval>\n"
@@ -2013,12 +2042,13 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
"<Interval>PT1H</Interval>\n"
"<Duration>PT23H</Duration>\n"
"<StopAtDurationEnd>false</StopAtDurationEnd>\n"
- "</Repetition>\n");
+ "</Repetition>\n",
+ minute);
break;
case SCHEDULE_DAILY:
fprintf(tfile->fp,
- "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+ "<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByWeek>\n"
"<DaysOfWeek>\n"
@@ -2030,19 +2060,21 @@ static int schtasks_schedule_task(const char *exec_path, enum schedule_priority
"<Saturday />\n"
"</DaysOfWeek>\n"
"<WeeksInterval>1</WeeksInterval>\n"
- "</ScheduleByWeek>\n");
+ "</ScheduleByWeek>\n",
+ minute);
break;
case SCHEDULE_WEEKLY:
fprintf(tfile->fp,
- "<StartBoundary>2020-01-01T00:00:00</StartBoundary>\n"
+ "<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
"<Enabled>true</Enabled>\n"
"<ScheduleByWeek>\n"
"<DaysOfWeek>\n"
"<Sunday />\n"
"</DaysOfWeek>\n"
"<WeeksInterval>1</WeeksInterval>\n"
- "</ScheduleByWeek>\n");
+ "</ScheduleByWeek>\n",
+ minute);
break;
default:
@@ -2100,7 +2132,7 @@ static int schtasks_schedule_tasks(void)
schtasks_schedule_task(exec_path, SCHEDULE_WEEKLY);
}
-static int schtasks_update_schedule(int run_maintenance, int fd)
+static int schtasks_update_schedule(int run_maintenance, int fd UNUSED)
{
if (run_maintenance)
return schtasks_schedule_tasks();
@@ -2159,6 +2191,7 @@ static int crontab_update_schedule(int run_maintenance, int fd)
FILE *cron_list, *cron_in;
struct strbuf line = STRBUF_INIT;
struct tempfile *tmpedit = NULL;
+ int minute = get_random_minute();
get_schedule_cmd(&cmd, NULL);
strvec_split(&crontab_list.args, cmd);
@@ -2213,11 +2246,11 @@ static int crontab_update_schedule(int run_maintenance, int fd)
"# replaced in the future by a Git command.\n\n");
strbuf_addf(&line_format,
- "%%s %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n",
+ "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n",
exec_path, exec_path);
- fprintf(cron_in, line_format.buf, "0", "1-23", "*", "hourly");
- fprintf(cron_in, line_format.buf, "0", "0", "1-6", "daily");
- fprintf(cron_in, line_format.buf, "0", "0", "0", "weekly");
+ fprintf(cron_in, line_format.buf, minute, "1-23", "*", "hourly");
+ fprintf(cron_in, line_format.buf, minute, "0", "1-6", "daily");
+ fprintf(cron_in, line_format.buf, minute, "0", "0", "weekly");
strbuf_release(&line_format);
fprintf(cron_in, "\n%s\n", END_LINE);
@@ -2276,77 +2309,54 @@ static char *xdg_config_home_systemd(const char *filename)
return xdg_config_home_for("systemd/user", filename);
}
-static int systemd_timer_enable_unit(int enable,
- enum schedule_priority schedule)
-{
- const char *cmd = "systemctl";
- struct child_process child = CHILD_PROCESS_INIT;
- const char *frequency = get_frequency(schedule);
+#define SYSTEMD_UNIT_FORMAT "git-maintenance@%s.%s"
- /*
- * Disabling the systemd unit while it is already disabled makes
- * systemctl print an error.
- * Let's ignore it since it means we already are in the expected state:
- * the unit is disabled.
- *
- * On the other hand, enabling a systemd unit which is already enabled
- * produces no error.
- */
- if (!enable)
- child.no_stderr = 1;
-
- get_schedule_cmd(&cmd, NULL);
- strvec_split(&child.args, cmd);
- strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
- "--now", NULL);
- strvec_pushf(&child.args, "git-maintenance@%s.timer", frequency);
-
- if (start_command(&child))
- return error(_("failed to start systemctl"));
- if (finish_command(&child))
- /*
- * Disabling an already disabled systemd unit makes
- * systemctl fail.
- * Let's ignore this failure.
- *
- * Enabling an enabled systemd unit doesn't fail.
- */
- if (enable)
- return error(_("failed to run systemctl"));
- return 0;
-}
-
-static int systemd_timer_delete_unit_templates(void)
+static int systemd_timer_delete_timer_file(enum schedule_priority priority)
{
int ret = 0;
- char *filename = xdg_config_home_systemd("git-maintenance@.timer");
- if (unlink(filename) && !is_missing_file_error(errno))
- ret = error_errno(_("failed to delete '%s'"), filename);
- FREE_AND_NULL(filename);
+ const char *frequency = get_frequency(priority);
+ char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+ char *filename = xdg_config_home_systemd(local_timer_name);
- filename = xdg_config_home_systemd("git-maintenance@.service");
if (unlink(filename) && !is_missing_file_error(errno))
ret = error_errno(_("failed to delete '%s'"), filename);
free(filename);
+ free(local_timer_name);
return ret;
}
-static int systemd_timer_delete_units(void)
+static int systemd_timer_delete_service_template(void)
{
- return systemd_timer_enable_unit(0, SCHEDULE_HOURLY) ||
- systemd_timer_enable_unit(0, SCHEDULE_DAILY) ||
- systemd_timer_enable_unit(0, SCHEDULE_WEEKLY) ||
- systemd_timer_delete_unit_templates();
+ int ret = 0;
+ char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+ char *filename = xdg_config_home_systemd(local_service_name);
+ if (unlink(filename) && !is_missing_file_error(errno))
+ ret = error_errno(_("failed to delete '%s'"), filename);
+
+ free(filename);
+ free(local_service_name);
+ return ret;
}
-static int systemd_timer_write_unit_templates(const char *exec_path)
+/*
+ * Write the schedule information into a git-maintenance@<schedule>.timer
+ * file using a custom minute. This timer file cannot use the templating
+ * system, so we generate a specific file for each.
+ */
+static int systemd_timer_write_timer_file(enum schedule_priority schedule,
+ int minute)
{
+ int res = -1;
char *filename;
FILE *file;
const char *unit;
+ char *schedule_pattern = NULL;
+ const char *frequency = get_frequency(schedule);
+ char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+ filename = xdg_config_home_systemd(local_timer_name);
- filename = xdg_config_home_systemd("git-maintenance@.timer");
if (safe_create_leading_directories(filename)) {
error(_("failed to create directories for '%s'"), filename);
goto error;
@@ -2355,6 +2365,23 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
if (!file)
goto error;
+ switch (schedule) {
+ case SCHEDULE_HOURLY:
+ schedule_pattern = xstrfmt("*-*-* 1..23:%02d:00", minute);
+ break;
+
+ case SCHEDULE_DAILY:
+ schedule_pattern = xstrfmt("Tue..Sun *-*-* 0:%02d:00", minute);
+ break;
+
+ case SCHEDULE_WEEKLY:
+ schedule_pattern = xstrfmt("Mon 0:%02d:00", minute);
+ break;
+
+ default:
+ BUG("Unhandled schedule_priority");
+ }
+
unit = "# This file was created and is maintained by Git.\n"
"# Any edits made in this file might be replaced in the future\n"
"# by a Git command.\n"
@@ -2363,12 +2390,12 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
"Description=Optimize Git repositories data\n"
"\n"
"[Timer]\n"
- "OnCalendar=%i\n"
+ "OnCalendar=%s\n"
"Persistent=true\n"
"\n"
"[Install]\n"
"WantedBy=timers.target\n";
- if (fputs(unit, file) == EOF) {
+ if (fprintf(file, unit, schedule_pattern) < 0) {
error(_("failed to write to '%s'"), filename);
fclose(file);
goto error;
@@ -2377,9 +2404,36 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
error_errno(_("failed to flush '%s'"), filename);
goto error;
}
+
+ res = 0;
+
+error:
+ free(schedule_pattern);
+ free(local_timer_name);
free(filename);
+ return res;
+}
- filename = xdg_config_home_systemd("git-maintenance@.service");
+/*
+ * No matter the schedule, we use the same service and can make use of the
+ * templating system. When installing git-maintenance@<schedule>.timer,
+ * systemd will notice that git-maintenance@.service exists as a template
+ * and will use this file and insert the <schedule> into the template at
+ * the position of "%i".
+ */
+static int systemd_timer_write_service_template(const char *exec_path)
+{
+ int res = -1;
+ char *filename;
+ FILE *file;
+ const char *unit;
+ char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+
+ filename = xdg_config_home_systemd(local_service_name);
+ if (safe_create_leading_directories(filename)) {
+ error(_("failed to create directories for '%s'"), filename);
+ goto error;
+ }
file = fopen_or_warn(filename, "w");
if (!file)
goto error;
@@ -2397,7 +2451,7 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
"LockPersonality=yes\n"
"MemoryDenyWriteExecute=yes\n"
"NoNewPrivileges=yes\n"
- "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6\n"
+ "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_VSOCK\n"
"RestrictNamespaces=yes\n"
"RestrictRealtime=yes\n"
"RestrictSUIDSGID=yes\n"
@@ -2412,29 +2466,114 @@ static int systemd_timer_write_unit_templates(const char *exec_path)
error_errno(_("failed to flush '%s'"), filename);
goto error;
}
+
+ res = 0;
+
+error:
+ free(local_service_name);
free(filename);
+ return res;
+}
+
+static int systemd_timer_enable_unit(int enable,
+ enum schedule_priority schedule,
+ int minute)
+{
+ const char *cmd = "systemctl";
+ struct child_process child = CHILD_PROCESS_INIT;
+ const char *frequency = get_frequency(schedule);
+
+ /*
+ * Disabling the systemd unit while it is already disabled makes
+ * systemctl print an error.
+ * Let's ignore it since it means we already are in the expected state:
+ * the unit is disabled.
+ *
+ * On the other hand, enabling a systemd unit which is already enabled
+ * produces no error.
+ */
+ if (!enable)
+ child.no_stderr = 1;
+ else if (systemd_timer_write_timer_file(schedule, minute))
+ return -1;
+
+ get_schedule_cmd(&cmd, NULL);
+ strvec_split(&child.args, cmd);
+ strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
+ "--now", NULL);
+ strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+ if (start_command(&child))
+ return error(_("failed to start systemctl"));
+ if (finish_command(&child))
+ /*
+ * Disabling an already disabled systemd unit makes
+ * systemctl fail.
+ * Let's ignore this failure.
+ *
+ * Enabling an enabled systemd unit doesn't fail.
+ */
+ if (enable)
+ return error(_("failed to run systemctl"));
return 0;
+}
+
+/*
+ * A previous version of Git wrote the timer units as template files.
+ * Clean these up, if they exist.
+ */
+static void systemd_timer_delete_stale_timer_templates(void)
+{
+ char *timer_template_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "timer");
+ char *filename = xdg_config_home_systemd(timer_template_name);
+
+ if (unlink(filename) && !is_missing_file_error(errno))
+ warning(_("failed to delete '%s'"), filename);
-error:
free(filename);
- systemd_timer_delete_unit_templates();
- return -1;
+ free(timer_template_name);
+}
+
+static int systemd_timer_delete_unit_files(void)
+{
+ systemd_timer_delete_stale_timer_templates();
+
+ /* Purposefully not short-circuited to make sure all are called. */
+ return systemd_timer_delete_timer_file(SCHEDULE_HOURLY) |
+ systemd_timer_delete_timer_file(SCHEDULE_DAILY) |
+ systemd_timer_delete_timer_file(SCHEDULE_WEEKLY) |
+ systemd_timer_delete_service_template();
+}
+
+static int systemd_timer_delete_units(void)
+{
+ int minute = get_random_minute();
+ /* Purposefully not short-circuited to make sure all are called. */
+ return systemd_timer_enable_unit(0, SCHEDULE_HOURLY, minute) |
+ systemd_timer_enable_unit(0, SCHEDULE_DAILY, minute) |
+ systemd_timer_enable_unit(0, SCHEDULE_WEEKLY, minute) |
+ systemd_timer_delete_unit_files();
}
static int systemd_timer_setup_units(void)
{
+ int minute = get_random_minute();
const char *exec_path = git_exec_path();
- int ret = systemd_timer_write_unit_templates(exec_path) ||
- systemd_timer_enable_unit(1, SCHEDULE_HOURLY) ||
- systemd_timer_enable_unit(1, SCHEDULE_DAILY) ||
- systemd_timer_enable_unit(1, SCHEDULE_WEEKLY);
+ int ret = systemd_timer_write_service_template(exec_path) ||
+ systemd_timer_enable_unit(1, SCHEDULE_HOURLY, minute) ||
+ systemd_timer_enable_unit(1, SCHEDULE_DAILY, minute) ||
+ systemd_timer_enable_unit(1, SCHEDULE_WEEKLY, minute);
+
if (ret)
systemd_timer_delete_units();
+ else
+ systemd_timer_delete_stale_timer_templates();
+
return ret;
}
-static int systemd_timer_update_schedule(int run_maintenance, int fd)
+static int systemd_timer_update_schedule(int run_maintenance, int fd UNUSED)
{
if (run_maintenance)
return systemd_timer_setup_units();
@@ -2606,9 +2745,12 @@ static int maintenance_start(int argc, const char **argv, const char *prefix)
opts.scheduler = resolve_scheduler(opts.scheduler);
validate_scheduler(opts.scheduler);
+ if (update_background_schedule(&opts, 1))
+ die(_("failed to set up maintenance schedule"));
+
if (maintenance_register(ARRAY_SIZE(register_args)-1, register_args, NULL))
warning(_("failed to add repo to global config"));
- return update_background_schedule(&opts, 1);
+ return 0;
}
static const char *const builtin_maintenance_stop_usage[] = {
diff --git a/builtin/grep.c b/builtin/grep.c
index 50e712a184..b71222330a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -924,9 +924,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
N_("process binary files with textconv filters")),
OPT_SET_INT('r', "recursive", &opt.max_depth,
N_("search in subdirectories (default)"), -1),
- { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
- N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
- NULL, 1 },
+ OPT_INTEGER_F(0, "max-depth", &opt.max_depth,
+ N_("descend at most <n> levels"), PARSE_OPT_NONEG),
OPT_GROUP(""),
OPT_SET_INT('E', "extended-regexp", &opt.pattern_type_option,
N_("use extended POSIX regular expressions"),
@@ -990,7 +989,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F(0, "and", &opt, NULL,
N_("combine patterns specified with -e"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback),
- OPT_BOOL(0, "or", &dummy, ""),
+ OPT_BOOL_F(0, "or", &dummy, "", PARSE_OPT_NONEG),
OPT_CALLBACK_F(0, "not", &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback),
OPT_CALLBACK_F('(', NULL, &opt, NULL, "",
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 006ffdc9c5..dda94a9f46 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1166,6 +1166,7 @@ static void parse_pack_objects(unsigned char *hash)
struct ofs_delta_entry *ofs_delta = ofs_deltas;
struct object_id ref_delta_oid;
struct stat st;
+ git_hash_ctx tmp_ctx;
if (verbose)
progress = start_progress(
@@ -1202,7 +1203,9 @@ static void parse_pack_objects(unsigned char *hash)
/* Check pack integrity */
flush();
- the_hash_algo->final_fn(hash, &input_ctx);
+ the_hash_algo->init_fn(&tmp_ctx);
+ the_hash_algo->clone_fn(&tmp_ctx, &input_ctx);
+ the_hash_algo->final_fn(hash, &tmp_ctx);
if (!hasheq(fill(the_hash_algo->rawsz), hash))
die(_("pack is corrupted (SHA1 mismatch)"));
use(the_hash_algo->rawsz);
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index c5e8345265..033bd1556c 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -14,7 +14,7 @@
static const char * const git_interpret_trailers_usage[] = {
N_("git interpret-trailers [--in-place] [--trim-empty]\n"
- " [(--trailer <token>[(=|:)<value>])...]\n"
+ " [(--trailer (<key>|<keyAlias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"),
NULL
};
@@ -24,21 +24,24 @@ static enum trailer_if_exists if_exists;
static enum trailer_if_missing if_missing;
static int option_parse_where(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset UNUSED)
{
- return trailer_set_where(&where, arg);
+ /* unset implies NULL arg, which is handled in our helper */
+ return trailer_set_where(opt->value, arg);
}
static int option_parse_if_exists(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset UNUSED)
{
- return trailer_set_if_exists(&if_exists, arg);
+ /* unset implies NULL arg, which is handled in our helper */
+ return trailer_set_if_exists(opt->value, arg);
}
static int option_parse_if_missing(const struct option *opt,
- const char *arg, int unset)
+ const char *arg, int unset UNUSED)
{
- return trailer_set_if_missing(&if_missing, arg);
+ /* unset implies NULL arg, which is handled in our helper */
+ return trailer_set_if_missing(opt->value, arg);
}
static void new_trailers_clear(struct list_head *trailers)
@@ -97,19 +100,19 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")),
OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),
- OPT_CALLBACK(0, "where", NULL, N_("action"),
+ OPT_CALLBACK(0, "where", &where, N_("placement"),
N_("where to place the new trailer"), option_parse_where),
- OPT_CALLBACK(0, "if-exists", NULL, N_("action"),
+ OPT_CALLBACK(0, "if-exists", &if_exists, N_("action"),
N_("action if trailer already exists"), option_parse_if_exists),
- OPT_CALLBACK(0, "if-missing", NULL, N_("action"),
+ OPT_CALLBACK(0, "if-missing", &if_missing, N_("action"),
N_("action if trailer is missing"), option_parse_if_missing),
OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")),
- OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")),
- OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")),
- OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("set parsing options"),
+ OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply trailer.* configuration variables")),
+ OPT_BOOL(0, "unfold", &opts.unfold, N_("reformat multiline trailer values as single-line values")),
+ OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("alias for --only-trailers --only-input --unfold"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse),
- OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat --- specially")),
+ OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat \"---\" as the end of input")),
OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
N_("trailer(s) to add"), option_parse_trailer),
OPT_END()
diff --git a/builtin/log.c b/builtin/log.c
index db3a88bfe9..ba775d7b5c 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -118,16 +118,19 @@ static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
-static int clear_decorations_callback(const struct option *opt,
- const char *arg, int unset)
+static int clear_decorations_callback(const struct option *opt UNUSED,
+ const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
string_list_clear(&decorate_refs_include, 0);
string_list_clear(&decorate_refs_exclude, 0);
use_default_decoration_filter = 0;
return 0;
}
-static int decorate_callback(const struct option *opt, const char *arg, int unset)
+static int decorate_callback(const struct option *opt UNUSED, const char *arg,
+ int unset)
{
if (unset)
decoration_style = 0;
@@ -173,16 +176,15 @@ static void cmd_log_init_defaults(struct rev_info *rev)
if (default_follow)
rev->diffopt.flags.default_follow_renames = 1;
rev->verbose_header = 1;
+ init_diffstat_widths(&rev->diffopt);
rev->diffopt.flags.recursive = 1;
- rev->diffopt.stat_width = -1; /* use full terminal width */
- rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
+ rev->diffopt.flags.allow_textconv = 1;
rev->abbrev_commit = default_abbrev_commit;
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
rev->patch_name_max = fmt_patch_name_max;
rev->show_signature = default_show_signature;
rev->encode_email_headers = default_encode_email_headers;
- rev->diffopt.flags.allow_textconv = 1;
if (default_date_mode)
parse_date_format(default_date_mode, &rev->date_mode);
@@ -549,7 +551,7 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
rev->diffopt.flags.check_failed) {
return 02;
}
- return diff_result_code(&rev->diffopt, 0);
+ return diff_result_code(&rev->diffopt);
}
static int cmd_log_walk(struct rev_info *rev)
@@ -1253,7 +1255,15 @@ static void show_diffstat(struct rev_info *rev,
fprintf(rev->diffopt.file, "\n");
}
+static void read_desc_file(struct strbuf *buf, const char *desc_file)
+{
+ if (strbuf_read_file(buf, desc_file, 0) < 0)
+ die_errno(_("unable to read branch description file '%s'"),
+ desc_file);
+}
+
static void prepare_cover_text(struct pretty_print_context *pp,
+ const char *description_file,
const char *branch_name,
struct strbuf *sb,
const char *encoding,
@@ -1267,7 +1277,9 @@ static void prepare_cover_text(struct pretty_print_context *pp,
if (cover_from_description_mode == COVER_FROM_NONE)
goto do_pp;
- if (branch_name && *branch_name)
+ if (description_file && *description_file)
+ read_desc_file(&description_sb, description_file);
+ else if (branch_name && *branch_name)
read_branch_desc(&description_sb, branch_name);
if (!description_sb.len)
goto do_pp;
@@ -1313,6 +1325,7 @@ static void get_notes_args(struct strvec *arg, struct rev_info *rev)
static void make_cover_letter(struct rev_info *rev, int use_separate_file,
struct commit *origin,
int nr, struct commit **list,
+ const char *description_file,
const char *branch_name,
int quiet)
{
@@ -1352,7 +1365,8 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
pp.rev = rev;
pp.print_email_subject = 1;
pp_user_info(&pp, NULL, &sb, committer, encoding);
- prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
+ prepare_cover_text(&pp, description_file, branch_name, &sb,
+ encoding, need_8bit_cte);
fprintf(rev->diffopt.file, "%s\n", sb.buf);
strbuf_release(&sb);
@@ -1468,19 +1482,16 @@ static int subject_prefix = 0;
static int subject_prefix_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct strbuf *sprefix;
+
BUG_ON_OPT_NEG(unset);
+ sprefix = opt->value;
subject_prefix = 1;
- ((struct rev_info *)opt->value)->subject_prefix = arg;
+ strbuf_reset(sprefix);
+ strbuf_addstr(sprefix, arg);
return 0;
}
-static int rfc_callback(const struct option *opt, const char *arg, int unset)
-{
- BUG_ON_OPT_NEG(unset);
- BUG_ON_OPT_ARG(arg);
- return subject_prefix_callback(opt, "RFC PATCH", unset);
-}
-
static int numbered_cmdline_opt = 0;
static int numbered_callback(const struct option *opt, const char *arg,
@@ -1555,7 +1566,8 @@ static int inline_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
-static int header_callback(const struct option *opt, const char *arg, int unset)
+static int header_callback(const struct option *opt UNUSED, const char *arg,
+ int unset)
{
if (unset) {
string_list_clear(&extra_hdr, 0);
@@ -1567,24 +1579,6 @@ static int header_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
-static int to_callback(const struct option *opt, const char *arg, int unset)
-{
- if (unset)
- string_list_clear(&extra_to, 0);
- else
- string_list_append(&extra_to, arg);
- return 0;
-}
-
-static int cc_callback(const struct option *opt, const char *arg, int unset)
-{
- if (unset)
- string_list_clear(&extra_cc, 0);
- else
- string_list_append(&extra_cc, arg);
- return 0;
-}
-
static int from_callback(const struct option *opt, const char *arg, int unset)
{
char **from = opt->value;
@@ -1893,6 +1887,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int quiet = 0;
const char *reroll_count = NULL;
char *cover_from_description_arg = NULL;
+ char *description_file = NULL;
char *branch_name = NULL;
char *base_commit = NULL;
struct base_tree_info bases;
@@ -1907,6 +1902,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct strbuf rdiff_title = STRBUF_INIT;
struct strbuf sprefix = STRBUF_INIT;
int creation_factor = -1;
+ int rfc = 0;
const struct option builtin_format_patch_options[] = {
OPT_CALLBACK_F('n', "numbered", &numbered, NULL,
@@ -1930,13 +1926,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("mark the series as Nth re-roll")),
OPT_INTEGER(0, "filename-max-length", &fmt_patch_name_max,
N_("max length of output filename")),
- OPT_CALLBACK_F(0, "rfc", &rev, NULL,
- N_("use [RFC PATCH] instead of [PATCH]"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback),
+ OPT_BOOL(0, "rfc", &rfc, N_("use [RFC PATCH] instead of [PATCH]")),
OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
N_("cover-from-description-mode"),
N_("generate parts of a cover letter based on a branch's description")),
- OPT_CALLBACK_F(0, "subject-prefix", &rev, N_("prefix"),
+ OPT_FILENAME(0, "description-file", &description_file,
+ N_("use branch description from file")),
+ OPT_CALLBACK_F(0, "subject-prefix", &sprefix, N_("prefix"),
N_("use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback),
OPT_CALLBACK_F('o', "output-directory", &output_directory,
@@ -1957,8 +1953,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
OPT_GROUP(N_("Messaging")),
OPT_CALLBACK(0, "add-header", NULL, N_("header"),
N_("add email header"), header_callback),
- OPT_CALLBACK(0, "to", NULL, N_("email"), N_("add To: header"), to_callback),
- OPT_CALLBACK(0, "cc", NULL, N_("email"), N_("add Cc: header"), cc_callback),
+ OPT_STRING_LIST(0, "to", &extra_to, N_("email"), N_("add To: header")),
+ OPT_STRING_LIST(0, "cc", &extra_cc, N_("email"), N_("add Cc: header")),
OPT_CALLBACK_F(0, "from", &from, N_("ident"),
N_("set From address to <ident> (or committer ident if absent)"),
PARSE_OPT_OPTARG, from_callback),
@@ -2016,11 +2012,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.max_parents = 1;
rev.diffopt.flags.recursive = 1;
rev.diffopt.no_free = 1;
- rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
+ strbuf_addstr(&sprefix, fmt_patch_subject_prefix);
if (format_no_prefix)
diff_set_noprefix(&rev.diffopt);
@@ -2048,13 +2044,16 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (cover_from_description_arg)
cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
+ if (rfc)
+ strbuf_insertstr(&sprefix, 0, "RFC ");
+
if (reroll_count) {
- strbuf_addf(&sprefix, "%s v%s",
- rev.subject_prefix, reroll_count);
+ strbuf_addf(&sprefix, " v%s", reroll_count);
rev.reroll_count = reroll_count;
- rev.subject_prefix = sprefix.buf;
}
+ rev.subject_prefix = sprefix.buf;
+
for (i = 0; i < extra_hdr.nr; i++) {
strbuf_addstr(&buf, extra_hdr.items[i].string);
strbuf_addch(&buf, '\n');
@@ -2321,7 +2320,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (thread)
gen_message_id(&rev, "cover");
make_cover_letter(&rev, !!output_directory,
- origin, nr, list, branch_name, quiet);
+ origin, nr, list, description_file, branch_name, quiet);
print_bases(&bases, rev.diffopt.file);
print_signature(rev.diffopt.file);
total++;
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index f558db5f3b..209d2dc0d5 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -241,7 +241,8 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
return recurse;
}
-static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
+static int show_tree_name_only(const struct object_id *oid UNUSED,
+ struct strbuf *base,
const char *pathname, unsigned mode,
void *context)
{
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 0de42aecf4..a35e0452d6 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -18,6 +18,7 @@
#include "quote.h"
#include "tree.h"
#include "config.h"
+#include "strvec.h"
static int line_termination = '\n';
@@ -414,6 +415,7 @@ struct merge_tree_options {
int show_messages;
int name_only;
int use_stdin;
+ struct merge_options merge_options;
};
static int real_merge(struct merge_tree_options *o,
@@ -423,10 +425,11 @@ static int real_merge(struct merge_tree_options *o,
{
struct commit *parent1, *parent2;
struct commit_list *merge_bases = NULL;
- struct merge_options opt;
struct merge_result result = { 0 };
int show_messages = o->show_messages;
+ struct merge_options opt;
+ copy_merge_options(&opt, &o->merge_options);
parent1 = get_merge_parent(branch1);
if (!parent1)
help_unknown_ref(branch1, "merge-tree",
@@ -437,8 +440,6 @@ static int real_merge(struct merge_tree_options *o,
help_unknown_ref(branch2, "merge-tree",
_("not something we can merge"));
- init_merge_options(&opt, the_repository);
-
opt.show_rename_progress = 0;
opt.branch1 = branch1;
@@ -507,12 +508,14 @@ static int real_merge(struct merge_tree_options *o,
if (o->use_stdin)
putchar(line_termination);
merge_finalize(&opt, &result);
+ clear_merge_options(&opt);
return !result.clean; /* result.clean < 0 handled above */
}
int cmd_merge_tree(int argc, const char **argv, const char *prefix)
{
struct merge_tree_options o = { .show_messages = -1 };
+ struct strvec xopts = STRVEC_INIT;
int expected_remaining_argc;
int original_argc;
const char *merge_base = NULL;
@@ -548,14 +551,25 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
&merge_base,
N_("commit"),
N_("specify a merge-base for the merge")),
+ OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+ N_("option for selected merge strategy")),
OPT_END()
};
+ /* Init merge options */
+ init_merge_options(&o.merge_options, the_repository);
+
/* Parse arguments */
original_argc = argc - 1; /* ignoring argv[0] */
argc = parse_options(argc, argv, prefix, mt_options,
merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+ if (xopts.nr && o.mode == MODE_TRIVIAL)
+ die(_("--trivial-merge is incompatible with all other options"));
+ for (int x = 0; x < xopts.nr; x++)
+ if (parse_merge_opt(&o.merge_options, xopts.v[x]))
+ die(_("unknown strategy option: -X%s"), xopts.v[x]);
+
/* Handle --stdin */
if (o.use_stdin) {
struct strbuf buf = STRBUF_INIT;
diff --git a/builtin/merge.c b/builtin/merge.c
index de68910177..d748d46e13 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -79,8 +79,7 @@ static int overwrite_ignore = 1;
static struct strbuf merge_msg = STRBUF_INIT;
static struct strategy **use_strategies;
static size_t use_strategies_nr, use_strategies_alloc;
-static const char **xopts;
-static size_t xopts_nr, xopts_alloc;
+static struct strvec xopts = STRVEC_INIT;
static const char *branch;
static char *branch_mergeoptions;
static int verbosity;
@@ -232,7 +231,7 @@ static void append_strategy(struct strategy *s)
use_strategies[use_strategies_nr++] = s;
}
-static int option_parse_strategy(const struct option *opt,
+static int option_parse_strategy(const struct option *opt UNUSED,
const char *name, int unset)
{
if (unset)
@@ -242,29 +241,9 @@ static int option_parse_strategy(const struct option *opt,
return 0;
}
-static int option_parse_x(const struct option *opt,
- const char *arg, int unset)
-{
- if (unset)
- return 0;
-
- ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);
- xopts[xopts_nr++] = xstrdup(arg);
- return 0;
-}
-
-static int option_parse_n(const struct option *opt,
- const char *arg, int unset)
-{
- BUG_ON_OPT_ARG(arg);
- show_diffstat = unset;
- return 0;
-}
-
static struct option builtin_merge_options[] = {
- OPT_CALLBACK_F('n', NULL, NULL, NULL,
- N_("do not show a diffstat at the end of the merge"),
- PARSE_OPT_NOARG, option_parse_n),
+ OPT_SET_INT('n', NULL, &show_diffstat,
+ N_("do not show a diffstat at the end of the merge"), 0),
OPT_BOOL(0, "stat", &show_diffstat,
N_("show a diffstat at the end of the merge")),
OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
@@ -285,10 +264,10 @@ static struct option builtin_merge_options[] = {
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
OPT_BOOL(0, "verify-signatures", &verify_signatures,
N_("verify that the named commit has a valid GPG signature")),
- OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
+ OPT_CALLBACK('s', "strategy", NULL, N_("strategy"),
N_("merge strategy to use"), option_parse_strategy),
- OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
- N_("option for selected merge strategy"), option_parse_x),
+ OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+ N_("option for selected merge strategy")),
OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
@@ -487,8 +466,7 @@ static void finish(struct commit *head_commit,
if (new_head && show_diffstat) {
struct diff_options opts;
repo_diff_setup(the_repository, &opts);
- opts.stat_width = -1; /* use full terminal width */
- opts.stat_graph_width = -1; /* respect statGraphWidth config */
+ init_diffstat_widths(&opts);
opts.output_format |=
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
opts.detect_rename = DIFF_DETECT_RENAME;
@@ -749,9 +727,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
o.show_rename_progress =
show_progress == -1 ? isatty(2) : show_progress;
- for (x = 0; x < xopts_nr; x++)
- if (parse_merge_opt(&o, xopts[x]))
- die(_("unknown strategy option: -X%s"), xopts[x]);
+ for (x = 0; x < xopts.nr; x++)
+ if (parse_merge_opt(&o, xopts.v[x]))
+ die(_("unknown strategy option: -X%s"), xopts.v[x]);
o.branch1 = head_arg;
o.branch2 = merge_remote_util(remoteheads->item)->name;
@@ -777,7 +755,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
return clean ? 0 : 1;
} else {
return try_merge_command(the_repository,
- strategy, xopts_nr, xopts,
+ strategy, xopts.nr, xopts.v,
common, head_arg, remoteheads);
}
}
@@ -1654,6 +1632,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
for (j = remoteheads; j; j = j->next) {
struct commit_list *common_one;
+ struct commit *common_item;
/*
* Here we *have* to calculate the individual
@@ -1663,7 +1642,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
common_one = repo_get_merge_bases(the_repository,
head_commit,
j->item);
- if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
+ common_item = common_one->item;
+ free_commit_list(common_one);
+ if (!oideq(&common_item->object.oid, &j->item->object.oid)) {
up_to_date = 0;
break;
}
diff --git a/builtin/mv.c b/builtin/mv.c
index 05e7156034..c596515ad0 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -305,7 +305,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
}
if (S_ISDIR(st.st_mode)
&& lstat(dst, &dest_st) == 0) {
- bad = _("cannot move directory over file");
+ bad = _("destination already exists");
goto act_on_entry;
}
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index c706fa3720..2dd1807c4e 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -582,12 +582,8 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
OPT_BOOL(0, "always", &always,
N_("show abbreviated commit object as fallback")),
- {
- /* A Hidden OPT_BOOL */
- OPTION_SET_INT, 0, "peel-tag", &peel_tag, NULL,
- N_("dereference tags in the input (internal use)"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1,
- },
+ OPT_HIDDEN_BOOL(0, "peel-tag", &peel_tag,
+ N_("dereference tags in the input (internal use)")),
OPT_END(),
};
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index d2a162d528..89a8b5a976 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -3603,7 +3603,6 @@ static void read_cruft_objects(void)
string_list_append(&discard_packs, buf.buf + 1);
else
string_list_append(&fresh_packs, buf.buf);
- strbuf_reset(&buf);
}
string_list_sort(&discard_packs);
@@ -3739,7 +3738,7 @@ static void show_object__ma_allow_promisor(struct object *obj, const char *name,
show_object(obj, name, data);
}
-static int option_parse_missing_action(const struct option *opt,
+static int option_parse_missing_action(const struct option *opt UNUSED,
const char *arg, int unset)
{
assert(arg);
@@ -4120,34 +4119,37 @@ static void add_extra_kept_packs(const struct string_list *names)
static int option_parse_quiet(const struct option *opt, const char *arg,
int unset)
{
+ int *val = opt->value;
+
BUG_ON_OPT_ARG(arg);
if (!unset)
- progress = 0;
- else if (!progress)
- progress = 1;
+ *val = 0;
+ else if (!*val)
+ *val = 1;
return 0;
}
static int option_parse_index_version(const struct option *opt,
const char *arg, int unset)
{
+ struct pack_idx_option *popts = opt->value;
char *c;
const char *val = arg;
BUG_ON_OPT_NEG(unset);
- pack_idx_opts.version = strtoul(val, &c, 10);
- if (pack_idx_opts.version > 2)
+ popts->version = strtoul(val, &c, 10);
+ if (popts->version > 2)
die(_("unsupported index version %s"), val);
if (*c == ',' && c[1])
- pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);
- if (*c || pack_idx_opts.off32_limit & 0x80000000)
+ popts->off32_limit = strtoul(c+1, &c, 0);
+ if (*c || popts->off32_limit & 0x80000000)
die(_("bad index version '%s'"), val);
return 0;
}
-static int option_parse_unpack_unreachable(const struct option *opt,
+static int option_parse_unpack_unreachable(const struct option *opt UNUSED,
const char *arg, int unset)
{
if (unset) {
@@ -4162,7 +4164,7 @@ static int option_parse_unpack_unreachable(const struct option *opt,
return 0;
}
-static int option_parse_cruft_expiration(const struct option *opt,
+static int option_parse_cruft_expiration(const struct option *opt UNUSED,
const char *arg, int unset)
{
if (unset) {
@@ -4190,7 +4192,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
LIST_OBJECTS_FILTER_INIT;
struct option pack_objects_options[] = {
- OPT_CALLBACK_F('q', "quiet", NULL, NULL,
+ OPT_CALLBACK_F('q', "quiet", &progress, NULL,
N_("do not show progress meter"),
PARSE_OPT_NOARG, option_parse_quiet),
OPT_SET_INT(0, "progress", &progress,
@@ -4200,7 +4202,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "all-progress-implied",
&all_progress_implied,
N_("similar to --all-progress when progress meter is shown")),
- OPT_CALLBACK_F(0, "index-version", NULL, N_("<version>[,<offset>]"),
+ OPT_CALLBACK_F(0, "index-version", &pack_idx_opts, N_("<version>[,<offset>]"),
N_("write the pack index file in the specified idx format version"),
PARSE_OPT_NONEG, option_parse_index_version),
OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
@@ -4383,7 +4385,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!HAVE_THREADS && delta_search_threads != 1)
warning(_("no threads support, ignoring --threads"));
- if (!pack_to_stdout && !pack_size_limit && !cruft)
+ if (!pack_to_stdout && !pack_size_limit)
pack_size_limit = pack_size_limit_cfg;
if (pack_to_stdout && pack_size_limit)
die(_("--max-pack-size cannot be used to build a pack for transfer"));
@@ -4400,12 +4402,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
unpack_unreachable_expiration = 0;
- if (filter_options.choice) {
- if (!pack_to_stdout)
- die(_("cannot use --filter without --stdout"));
- if (stdin_packs)
- die(_("cannot use --filter with --stdin-packs"));
- }
+ if (stdin_packs && filter_options.choice)
+ die(_("cannot use --filter with --stdin-packs"));
if (stdin_packs && use_internal_rev_list)
die(_("cannot use internal rev list with --stdin-packs"));
@@ -4415,8 +4413,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
die(_("cannot use internal rev list with --cruft"));
if (stdin_packs)
die(_("cannot use --stdin-packs with --cruft"));
- if (pack_size_limit)
- die(_("cannot use --max-pack-size with --cruft"));
}
/*
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 1fec702a04..8196ca9dd8 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -49,7 +49,7 @@ static const char * const read_tree_usage[] = {
NULL
};
-static int index_output_cb(const struct option *opt, const char *arg,
+static int index_output_cb(const struct option *opt UNUSED, const char *arg,
int unset)
{
BUG_ON_OPT_NEG(unset);
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 50cb85751f..f990811614 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1803,8 +1803,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/* We want color (if set), but no pager */
repo_diff_setup(the_repository, &opts);
- opts.stat_width = -1; /* use full terminal width */
- opts.stat_graph_width = -1; /* respect statGraphWidth config */
+ init_diffstat_widths(&opts);
opts.output_format |=
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
opts.detect_rename = DIFF_DETECT_RENAME;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index fb8e1549d1..8c4f0cb90a 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -2527,10 +2527,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (cert_nonce_seed)
push_cert_nonce = prepare_push_cert_nonce(service_dir, time(NULL));
- if (0 <= transfer_unpack_limit)
- unpack_limit = transfer_unpack_limit;
- else if (0 <= receive_unpack_limit)
+ if (0 <= receive_unpack_limit)
unpack_limit = receive_unpack_limit;
+ else if (0 <= transfer_unpack_limit)
+ unpack_limit = transfer_unpack_limit;
switch (determine_protocol_version_server()) {
case protocol_v2:
diff --git a/builtin/repack.c b/builtin/repack.c
index 97051479e4..edaee4dbec 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -21,13 +21,14 @@
#include "pack.h"
#include "pack-bitmap.h"
#include "refs.h"
+#include "list-objects-filter-options.h"
#define ALL_INTO_ONE 1
#define LOOSEN_UNREACHABLE 2
#define PACK_CRUFT 4
#define DELETE_PACK 1
-#define CRUFT_PACK 2
+#define RETAIN_PACK 2
static int pack_everything;
static int delta_base_offset = 1;
@@ -52,11 +53,12 @@ struct pack_objects_args {
const char *window_memory;
const char *depth;
const char *threads;
- const char *max_pack_size;
+ unsigned long max_pack_size;
int no_reuse_delta;
int no_reuse_object;
int quiet;
int local;
+ struct list_objects_filter_options filter_options;
};
static int repack_config(const char *var, const char *value,
@@ -95,14 +97,143 @@ static int repack_config(const char *var, const char *value,
return git_default_config(var, value, ctx, cb);
}
+struct existing_packs {
+ struct string_list kept_packs;
+ struct string_list non_kept_packs;
+ struct string_list cruft_packs;
+};
+
+#define EXISTING_PACKS_INIT { \
+ .kept_packs = STRING_LIST_INIT_DUP, \
+ .non_kept_packs = STRING_LIST_INIT_DUP, \
+ .cruft_packs = STRING_LIST_INIT_DUP, \
+}
+
+static int has_existing_non_kept_packs(const struct existing_packs *existing)
+{
+ return existing->non_kept_packs.nr || existing->cruft_packs.nr;
+}
+
+static void pack_mark_for_deletion(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util | DELETE_PACK);
+}
+
+static void pack_unmark_for_deletion(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util & ~DELETE_PACK);
+}
+
+static int pack_is_marked_for_deletion(struct string_list_item *item)
+{
+ return (uintptr_t)item->util & DELETE_PACK;
+}
+
+static void pack_mark_retained(struct string_list_item *item)
+{
+ item->util = (void*)((uintptr_t)item->util | RETAIN_PACK);
+}
+
+static int pack_is_retained(struct string_list_item *item)
+{
+ return (uintptr_t)item->util & RETAIN_PACK;
+}
+
+static void mark_packs_for_deletion_1(struct string_list *names,
+ struct string_list *list)
+{
+ struct string_list_item *item;
+ const int hexsz = the_hash_algo->hexsz;
+
+ for_each_string_list_item(item, list) {
+ char *sha1;
+ size_t len = strlen(item->string);
+ if (len < hexsz)
+ continue;
+ sha1 = item->string + len - hexsz;
+
+ if (pack_is_retained(item)) {
+ pack_unmark_for_deletion(item);
+ } else if (!string_list_has_string(names, sha1)) {
+ /*
+ * Mark this pack for deletion, which ensures
+ * that this pack won't be included in a MIDX
+ * (if `--write-midx` was given) and that we
+ * will actually delete this pack (if `-d` was
+ * given).
+ */
+ pack_mark_for_deletion(item);
+ }
+ }
+}
+
+static void retain_cruft_pack(struct existing_packs *existing,
+ struct packed_git *cruft)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct string_list_item *item;
+
+ strbuf_addstr(&buf, pack_basename(cruft));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ item = string_list_lookup(&existing->cruft_packs, buf.buf);
+ if (!item)
+ BUG("could not find cruft pack '%s'", pack_basename(cruft));
+
+ pack_mark_retained(item);
+ strbuf_release(&buf);
+}
+
+static void mark_packs_for_deletion(struct existing_packs *existing,
+ struct string_list *names)
+
+{
+ mark_packs_for_deletion_1(names, &existing->non_kept_packs);
+ mark_packs_for_deletion_1(names, &existing->cruft_packs);
+}
+
+static void remove_redundant_pack(const char *dir_name, const char *base_name)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
+ strbuf_addf(&buf, "%s.pack", base_name);
+ if (m && midx_contains_pack(m, buf.buf))
+ clear_midx_file(the_repository);
+ strbuf_insertf(&buf, 0, "%s/", dir_name);
+ unlink_pack_path(buf.buf, 1);
+ strbuf_release(&buf);
+}
+
+static void remove_redundant_packs_1(struct string_list *packs)
+{
+ struct string_list_item *item;
+ for_each_string_list_item(item, packs) {
+ if (!pack_is_marked_for_deletion(item))
+ continue;
+ remove_redundant_pack(packdir, item->string);
+ }
+}
+
+static void remove_redundant_existing_packs(struct existing_packs *existing)
+{
+ remove_redundant_packs_1(&existing->non_kept_packs);
+ remove_redundant_packs_1(&existing->cruft_packs);
+}
+
+static void existing_packs_release(struct existing_packs *existing)
+{
+ string_list_clear(&existing->kept_packs, 0);
+ string_list_clear(&existing->non_kept_packs, 0);
+ string_list_clear(&existing->cruft_packs, 0);
+}
+
/*
- * Adds all packs hex strings (pack-$HASH) to either fname_nonkept_list
- * or fname_kept_list based on whether each pack has a corresponding
+ * Adds all packs hex strings (pack-$HASH) to either packs->non_kept
+ * or packs->kept based on whether each pack has a corresponding
* .keep file or not. Packs without a .keep file are not to be kept
* if we are going to pack everything into one file.
*/
-static void collect_pack_filenames(struct string_list *fname_nonkept_list,
- struct string_list *fname_kept_list,
+static void collect_pack_filenames(struct existing_packs *existing,
const struct string_list *extra_keep)
{
struct packed_git *p;
@@ -126,28 +257,16 @@ static void collect_pack_filenames(struct string_list *fname_nonkept_list,
strbuf_strip_suffix(&buf, ".pack");
if ((extra_keep->nr > 0 && i < extra_keep->nr) || p->pack_keep)
- string_list_append(fname_kept_list, buf.buf);
- else {
- struct string_list_item *item;
- item = string_list_append(fname_nonkept_list, buf.buf);
- if (p->is_cruft)
- item->util = (void*)(uintptr_t)CRUFT_PACK;
- }
+ string_list_append(&existing->kept_packs, buf.buf);
+ else if (p->is_cruft)
+ string_list_append(&existing->cruft_packs, buf.buf);
+ else
+ string_list_append(&existing->non_kept_packs, buf.buf);
}
- string_list_sort(fname_kept_list);
- strbuf_release(&buf);
-}
-
-static void remove_redundant_pack(const char *dir_name, const char *base_name)
-{
- struct strbuf buf = STRBUF_INIT;
- struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
- strbuf_addf(&buf, "%s.pack", base_name);
- if (m && midx_contains_pack(m, buf.buf))
- clear_midx_file(the_repository);
- strbuf_insertf(&buf, 0, "%s/", dir_name);
- unlink_pack_path(buf.buf, 1);
+ string_list_sort(&existing->kept_packs);
+ string_list_sort(&existing->non_kept_packs);
+ string_list_sort(&existing->cruft_packs);
strbuf_release(&buf);
}
@@ -165,7 +284,7 @@ static void prepare_pack_objects(struct child_process *cmd,
if (args->threads)
strvec_pushf(&cmd->args, "--threads=%s", args->threads);
if (args->max_pack_size)
- strvec_pushf(&cmd->args, "--max-pack-size=%s", args->max_pack_size);
+ strvec_pushf(&cmd->args, "--max-pack-size=%lu", args->max_pack_size);
if (args->no_reuse_delta)
strvec_pushf(&cmd->args, "--no-reuse-delta");
if (args->no_reuse_object)
@@ -238,6 +357,18 @@ static struct generated_pack_data *populate_pack_exts(const char *name)
return data;
}
+static int has_pack_ext(const struct generated_pack_data *data,
+ const char *ext)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(exts); i++) {
+ if (strcmp(exts[i].name, ext))
+ continue;
+ return !!data->tempfiles[i];
+ }
+ BUG("unknown pack extension: '%s'", ext);
+}
+
static void repack_promisor_objects(const struct pack_objects_args *args,
struct string_list *names)
{
@@ -303,6 +434,8 @@ struct pack_geometry {
struct packed_git **pack;
uint32_t pack_nr, pack_alloc;
uint32_t split;
+
+ int split_factor;
};
static uint32_t geometry_pack_weight(struct packed_git *p)
@@ -324,17 +457,13 @@ static int geometry_cmp(const void *va, const void *vb)
return 0;
}
-static void init_pack_geometry(struct pack_geometry **geometry_p,
- struct string_list *existing_kept_packs,
+static void init_pack_geometry(struct pack_geometry *geometry,
+ struct existing_packs *existing,
const struct pack_objects_args *args)
{
struct packed_git *p;
- struct pack_geometry *geometry;
struct strbuf buf = STRBUF_INIT;
- *geometry_p = xcalloc(1, sizeof(struct pack_geometry));
- geometry = *geometry_p;
-
for (p = get_all_packs(the_repository); p; p = p->next) {
if (args->local && !p->pack_local)
/*
@@ -346,23 +475,24 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
if (!pack_kept_objects) {
/*
- * Any pack that has its pack_keep bit set will appear
- * in existing_kept_packs below, but this saves us from
- * doing a more expensive check.
+ * Any pack that has its pack_keep bit set will
+ * appear in existing->kept_packs below, but
+ * this saves us from doing a more expensive
+ * check.
*/
if (p->pack_keep)
continue;
/*
- * The pack may be kept via the --keep-pack option;
- * check 'existing_kept_packs' to determine whether to
- * ignore it.
+ * The pack may be kept via the --keep-pack
+ * option; check 'existing->kept_packs' to
+ * determine whether to ignore it.
*/
strbuf_reset(&buf);
strbuf_addstr(&buf, pack_basename(p));
strbuf_strip_suffix(&buf, ".pack");
- if (string_list_has_string(existing_kept_packs, buf.buf))
+ if (string_list_has_string(&existing->kept_packs, buf.buf))
continue;
}
if (p->is_cruft)
@@ -380,7 +510,7 @@ static void init_pack_geometry(struct pack_geometry **geometry_p,
strbuf_release(&buf);
}
-static void split_pack_geometry(struct pack_geometry *geometry, int factor)
+static void split_pack_geometry(struct pack_geometry *geometry)
{
uint32_t i;
uint32_t split;
@@ -399,12 +529,14 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
struct packed_git *ours = geometry->pack[i];
struct packed_git *prev = geometry->pack[i - 1];
- if (unsigned_mult_overflows(factor, geometry_pack_weight(prev)))
+ if (unsigned_mult_overflows(geometry->split_factor,
+ geometry_pack_weight(prev)))
die(_("pack %s too large to consider in geometric "
"progression"),
prev->pack_name);
- if (geometry_pack_weight(ours) < factor * geometry_pack_weight(prev))
+ if (geometry_pack_weight(ours) <
+ geometry->split_factor * geometry_pack_weight(prev))
break;
}
@@ -439,10 +571,12 @@ static void split_pack_geometry(struct pack_geometry *geometry, int factor)
for (i = split; i < geometry->pack_nr; i++) {
struct packed_git *ours = geometry->pack[i];
- if (unsigned_mult_overflows(factor, total_size))
+ if (unsigned_mult_overflows(geometry->split_factor,
+ total_size))
die(_("pack %s too large to roll up"), ours->pack_name);
- if (geometry_pack_weight(ours) < factor * total_size) {
+ if (geometry_pack_weight(ours) <
+ geometry->split_factor * total_size) {
if (unsigned_add_overflows(total_size,
geometry_pack_weight(ours)))
die(_("pack %s too large to roll up"),
@@ -492,13 +626,38 @@ static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
return NULL;
}
+static void geometry_remove_redundant_packs(struct pack_geometry *geometry,
+ struct string_list *names,
+ struct existing_packs *existing)
+{
+ struct strbuf buf = STRBUF_INIT;
+ uint32_t i;
+
+ for (i = 0; i < geometry->split; i++) {
+ struct packed_git *p = geometry->pack[i];
+ if (string_list_has_string(names, hash_to_hex(p->hash)))
+ continue;
+
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, pack_basename(p));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ if ((p->pack_keep) ||
+ (string_list_has_string(&existing->kept_packs, buf.buf)))
+ continue;
+
+ remove_redundant_pack(packdir, buf.buf);
+ }
+
+ strbuf_release(&buf);
+}
+
static void free_pack_geometry(struct pack_geometry *geometry)
{
if (!geometry)
return;
free(geometry->pack);
- free(geometry);
}
struct midx_snapshot_ref_data {
@@ -564,18 +723,17 @@ static void midx_snapshot_refs(struct tempfile *f)
}
static void midx_included_packs(struct string_list *include,
- struct string_list *existing_nonkept_packs,
- struct string_list *existing_kept_packs,
+ struct existing_packs *existing,
struct string_list *names,
struct pack_geometry *geometry)
{
struct string_list_item *item;
- for_each_string_list_item(item, existing_kept_packs)
+ for_each_string_list_item(item, &existing->kept_packs)
string_list_insert(include, xstrfmt("%s.idx", item->string));
for_each_string_list_item(item, names)
string_list_insert(include, xstrfmt("pack-%s.idx", item->string));
- if (geometry) {
+ if (geometry->split_factor) {
struct strbuf buf = STRBUF_INIT;
uint32_t i;
for (i = geometry->split; i < geometry->pack_nr; i++) {
@@ -598,28 +756,37 @@ static void midx_included_packs(struct string_list *include,
string_list_insert(include, strbuf_detach(&buf, NULL));
}
-
- for_each_string_list_item(item, existing_nonkept_packs) {
- if (!((uintptr_t)item->util & CRUFT_PACK)) {
- /*
- * no need to check DELETE_PACK, since we're not
- * doing an ALL_INTO_ONE repack
- */
- continue;
- }
- string_list_insert(include, xstrfmt("%s.idx", item->string));
- }
} else {
- for_each_string_list_item(item, existing_nonkept_packs) {
- if ((uintptr_t)item->util & DELETE_PACK)
+ for_each_string_list_item(item, &existing->non_kept_packs) {
+ if (pack_is_marked_for_deletion(item))
continue;
string_list_insert(include, xstrfmt("%s.idx", item->string));
}
}
+
+ for_each_string_list_item(item, &existing->cruft_packs) {
+ /*
+ * When doing a --geometric repack, there is no need to check
+ * for deleted packs, since we're by definition not doing an
+ * ALL_INTO_ONE repack (hence no packs will be deleted).
+ * Otherwise we must check for and exclude any packs which are
+ * enqueued for deletion.
+ *
+ * So we could omit the conditional below in the --geometric
+ * case, but doing so is unnecessary since no packs are marked
+ * as pending deletion (since we only call
+ * `mark_packs_for_deletion()` when doing an all-into-one
+ * repack).
+ */
+ if (pack_is_marked_for_deletion(item))
+ continue;
+ string_list_insert(include, xstrfmt("%s.idx", item->string));
+ }
}
static int write_midx_included_packs(struct string_list *include,
struct pack_geometry *geometry,
+ struct string_list *names,
const char *refs_snapshot,
int show_progress, int write_bitmaps)
{
@@ -649,6 +816,38 @@ static int write_midx_included_packs(struct string_list *include,
if (preferred)
strvec_pushf(&cmd.args, "--preferred-pack=%s",
pack_basename(preferred));
+ else if (names->nr) {
+ /* The largest pack was repacked, meaning that either
+ * one or two packs exist depending on whether the
+ * repository has a cruft pack or not.
+ *
+ * Select the non-cruft one as preferred to encourage
+ * pack-reuse among packs containing reachable objects
+ * over unreachable ones.
+ *
+ * (Note we could write multiple packs here if
+ * `--max-pack-size` was given, but any one of them
+ * will suffice, so pick the first one.)
+ */
+ for_each_string_list_item(item, names) {
+ struct generated_pack_data *data = item->util;
+ if (has_pack_ext(data, ".mtimes"))
+ continue;
+
+ strvec_pushf(&cmd.args, "--preferred-pack=pack-%s.pack",
+ item->string);
+ break;
+ }
+ } else {
+ /*
+ * No packs were kept, and no packs were written. The
+ * only thing remaining are .keep packs (unless
+ * --pack-kept-objects was given).
+ *
+ * Set the `--preferred-pack` arbitrarily here.
+ */
+ ;
+ }
if (refs_snapshot)
strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot);
@@ -694,18 +893,163 @@ static void remove_redundant_bitmaps(struct string_list *include,
strbuf_release(&path);
}
+static int finish_pack_objects_cmd(struct child_process *cmd,
+ struct string_list *names,
+ int local)
+{
+ FILE *out;
+ struct strbuf line = STRBUF_INIT;
+
+ out = xfdopen(cmd->out, "r");
+ while (strbuf_getline_lf(&line, out) != EOF) {
+ struct string_list_item *item;
+
+ if (line.len != the_hash_algo->hexsz)
+ die(_("repack: Expecting full hex object ID lines only "
+ "from pack-objects."));
+ /*
+ * Avoid putting packs written outside of the repository in the
+ * list of names.
+ */
+ if (local) {
+ item = string_list_append(names, line.buf);
+ item->util = populate_pack_exts(line.buf);
+ }
+ }
+ fclose(out);
+
+ strbuf_release(&line);
+
+ return finish_command(cmd);
+}
+
+static int write_filtered_pack(const struct pack_objects_args *args,
+ const char *destination,
+ const char *pack_prefix,
+ struct existing_packs *existing,
+ struct string_list *names)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ struct string_list_item *item;
+ FILE *in;
+ int ret;
+ const char *caret;
+ const char *scratch;
+ int local = skip_prefix(destination, packdir, &scratch);
+
+ prepare_pack_objects(&cmd, args, destination);
+
+ strvec_push(&cmd.args, "--stdin-packs");
+
+ if (!pack_kept_objects)
+ strvec_push(&cmd.args, "--honor-pack-keep");
+ for_each_string_list_item(item, &existing->kept_packs)
+ strvec_pushf(&cmd.args, "--keep-pack=%s", item->string);
+
+ cmd.in = -1;
+
+ ret = start_command(&cmd);
+ if (ret)
+ return ret;
+
+ /*
+ * Here 'names' contains only the pack(s) that were just
+ * written, which is exactly the packs we want to keep. Also
+ * 'existing_kept_packs' already contains the packs in
+ * 'keep_pack_list'.
+ */
+ in = xfdopen(cmd.in, "w");
+ for_each_string_list_item(item, names)
+ fprintf(in, "^%s-%s.pack\n", pack_prefix, item->string);
+ for_each_string_list_item(item, &existing->non_kept_packs)
+ fprintf(in, "%s.pack\n", item->string);
+ for_each_string_list_item(item, &existing->cruft_packs)
+ fprintf(in, "%s.pack\n", item->string);
+ caret = pack_kept_objects ? "" : "^";
+ for_each_string_list_item(item, &existing->kept_packs)
+ fprintf(in, "%s%s.pack\n", caret, item->string);
+ fclose(in);
+
+ return finish_pack_objects_cmd(&cmd, names, local);
+}
+
+static int existing_cruft_pack_cmp(const void *va, const void *vb)
+{
+ struct packed_git *a = *(struct packed_git **)va;
+ struct packed_git *b = *(struct packed_git **)vb;
+
+ if (a->pack_size < b->pack_size)
+ return -1;
+ if (a->pack_size > b->pack_size)
+ return 1;
+ return 0;
+}
+
+static void collapse_small_cruft_packs(FILE *in, size_t max_size,
+ struct existing_packs *existing)
+{
+ struct packed_git **existing_cruft, *p;
+ struct strbuf buf = STRBUF_INIT;
+ size_t total_size = 0;
+ size_t existing_cruft_nr = 0;
+ size_t i;
+
+ ALLOC_ARRAY(existing_cruft, existing->cruft_packs.nr);
+
+ for (p = get_all_packs(the_repository); p; p = p->next) {
+ if (!(p->is_cruft && p->pack_local))
+ continue;
+
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, pack_basename(p));
+ strbuf_strip_suffix(&buf, ".pack");
+
+ if (!string_list_has_string(&existing->cruft_packs, buf.buf))
+ continue;
+
+ if (existing_cruft_nr >= existing->cruft_packs.nr)
+ BUG("too many cruft packs (found %"PRIuMAX", but knew "
+ "of %"PRIuMAX")",
+ (uintmax_t)existing_cruft_nr + 1,
+ (uintmax_t)existing->cruft_packs.nr);
+ existing_cruft[existing_cruft_nr++] = p;
+ }
+
+ QSORT(existing_cruft, existing_cruft_nr, existing_cruft_pack_cmp);
+
+ for (i = 0; i < existing_cruft_nr; i++) {
+ size_t proposed;
+
+ p = existing_cruft[i];
+ proposed = st_add(total_size, p->pack_size);
+
+ if (proposed <= max_size) {
+ total_size = proposed;
+ fprintf(in, "-%s\n", pack_basename(p));
+ } else {
+ retain_cruft_pack(existing, p);
+ fprintf(in, "%s\n", pack_basename(p));
+ }
+ }
+
+ for (i = 0; i < existing->non_kept_packs.nr; i++)
+ fprintf(in, "-%s.pack\n",
+ existing->non_kept_packs.items[i].string);
+
+ strbuf_release(&buf);
+ free(existing_cruft);
+}
+
static int write_cruft_pack(const struct pack_objects_args *args,
const char *destination,
const char *pack_prefix,
const char *cruft_expiration,
struct string_list *names,
- struct string_list *existing_packs,
- struct string_list *existing_kept_packs)
+ struct existing_packs *existing)
{
struct child_process cmd = CHILD_PROCESS_INIT;
- struct strbuf line = STRBUF_INIT;
struct string_list_item *item;
- FILE *in, *out;
+ FILE *in;
int ret;
const char *scratch;
int local = skip_prefix(destination, packdir, &scratch);
@@ -719,7 +1063,6 @@ static int write_cruft_pack(const struct pack_objects_args *args,
strvec_push(&cmd.args, "--honor-pack-keep");
strvec_push(&cmd.args, "--non-empty");
- strvec_push(&cmd.args, "--max-pack-size=0");
cmd.in = -1;
@@ -743,33 +1086,30 @@ static int write_cruft_pack(const struct pack_objects_args *args,
in = xfdopen(cmd.in, "w");
for_each_string_list_item(item, names)
fprintf(in, "%s-%s.pack\n", pack_prefix, item->string);
- for_each_string_list_item(item, existing_packs)
- fprintf(in, "-%s.pack\n", item->string);
- for_each_string_list_item(item, existing_kept_packs)
+ if (args->max_pack_size && !cruft_expiration) {
+ collapse_small_cruft_packs(in, args->max_pack_size, existing);
+ } else {
+ for_each_string_list_item(item, &existing->non_kept_packs)
+ fprintf(in, "-%s.pack\n", item->string);
+ for_each_string_list_item(item, &existing->cruft_packs)
+ fprintf(in, "-%s.pack\n", item->string);
+ }
+ for_each_string_list_item(item, &existing->kept_packs)
fprintf(in, "%s.pack\n", item->string);
fclose(in);
- out = xfdopen(cmd.out, "r");
- while (strbuf_getline_lf(&line, out) != EOF) {
- struct string_list_item *item;
-
- if (line.len != the_hash_algo->hexsz)
- die(_("repack: Expecting full hex object ID lines only "
- "from pack-objects."));
- /*
- * avoid putting packs written outside of the repository in the
- * list of names
- */
- if (local) {
- item = string_list_append(names, line.buf);
- item->util = populate_pack_exts(line.buf);
- }
- }
- fclose(out);
-
- strbuf_release(&line);
+ return finish_pack_objects_cmd(&cmd, names, local);
+}
- return finish_command(&cmd);
+static const char *find_pack_prefix(const char *packdir, const char *packtmp)
+{
+ const char *pack_prefix;
+ if (!skip_prefix(packtmp, packdir, &pack_prefix))
+ die(_("pack prefix %s does not begin with objdir %s"),
+ packtmp, packdir);
+ if (*pack_prefix == '/')
+ pack_prefix++;
+ return pack_prefix;
}
int cmd_repack(int argc, const char **argv, const char *prefix)
@@ -777,13 +1117,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
struct child_process cmd = CHILD_PROCESS_INIT;
struct string_list_item *item;
struct string_list names = STRING_LIST_INIT_DUP;
- struct string_list existing_nonkept_packs = STRING_LIST_INIT_DUP;
- struct string_list existing_kept_packs = STRING_LIST_INIT_DUP;
- struct pack_geometry *geometry = NULL;
- struct strbuf line = STRBUF_INIT;
+ struct existing_packs existing = EXISTING_PACKS_INIT;
+ struct pack_geometry geometry = { 0 };
struct tempfile *refs_snapshot = NULL;
int i, ext, ret;
- FILE *out;
int show_progress;
/* variables to be filled by option parsing */
@@ -793,10 +1130,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
struct pack_objects_args po_args = {NULL};
struct pack_objects_args cruft_po_args = {NULL};
- int geometric_factor = 0;
int write_midx = 0;
const char *cruft_expiration = NULL;
const char *expire_to = NULL;
+ const char *filter_to = NULL;
struct option builtin_repack_options[] = {
OPT_BIT('a', NULL, &pack_everything,
@@ -809,6 +1146,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
PACK_CRUFT),
OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
N_("with --cruft, expire objects older than this")),
+ OPT_MAGNITUDE(0, "max-cruft-size", &cruft_po_args.max_pack_size,
+ N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL('d', NULL, &delete_redundant,
N_("remove redundant packs, and run git-prune-packed")),
OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
@@ -836,21 +1175,26 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("limits the maximum delta depth")),
OPT_STRING(0, "threads", &po_args.threads, N_("n"),
N_("limits the maximum number of threads")),
- OPT_STRING(0, "max-pack-size", &po_args.max_pack_size, N_("bytes"),
+ OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size,
N_("maximum size of each packfile")),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&po_args.filter_options),
OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
N_("repack objects in packs marked with .keep")),
OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
N_("do not repack this pack")),
- OPT_INTEGER('g', "geometric", &geometric_factor,
+ OPT_INTEGER('g', "geometric", &geometry.split_factor,
N_("find a geometric progression with factor <N>")),
OPT_BOOL('m', "write-midx", &write_midx,
N_("write a multi-pack index of the resulting packs")),
OPT_STRING(0, "expire-to", &expire_to, N_("dir"),
N_("pack prefix to store a pack containing pruned objects")),
+ OPT_STRING(0, "filter-to", &filter_to, N_("dir"),
+ N_("pack prefix to store a pack containing filtered out objects")),
OPT_END()
};
+ list_objects_filter_init(&po_args.filter_options);
+
git_config(repack_config, &cruft_po_args);
argc = parse_options(argc, argv, prefix, builtin_repack_options,
@@ -915,14 +1259,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
- collect_pack_filenames(&existing_nonkept_packs, &existing_kept_packs,
- &keep_pack_list);
+ collect_pack_filenames(&existing, &keep_pack_list);
- if (geometric_factor) {
+ if (geometry.split_factor) {
if (pack_everything)
die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
- init_pack_geometry(&geometry, &existing_kept_packs, &po_args);
- split_pack_geometry(geometry, geometric_factor);
+ init_pack_geometry(&geometry, &existing, &po_args);
+ split_pack_geometry(&geometry);
}
prepare_pack_objects(&cmd, &po_args, packtmp);
@@ -936,7 +1279,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_pushf(&cmd.args, "--keep-pack=%s",
keep_pack_list.items[i].string);
strvec_push(&cmd.args, "--non-empty");
- if (!geometry) {
+ if (!geometry.split_factor) {
/*
* We need to grab all reachable objects, including those that
* are reachable from reflogs and the index.
@@ -965,7 +1308,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (pack_everything & ALL_INTO_ONE) {
repack_promisor_objects(&po_args, &names);
- if (existing_nonkept_packs.nr && delete_redundant &&
+ if (has_existing_non_kept_packs(&existing) &&
+ delete_redundant &&
!(pack_everything & PACK_CRUFT)) {
for_each_string_list_item(item, &names) {
strvec_pushf(&cmd.args, "--keep-pack=%s-%s.pack",
@@ -983,7 +1327,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_push(&cmd.args, "--pack-loose-unreachable");
}
}
- } else if (geometry) {
+ } else if (geometry.split_factor) {
strvec_push(&cmd.args, "--stdin-packs");
strvec_push(&cmd.args, "--unpacked");
} else {
@@ -991,7 +1335,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
strvec_push(&cmd.args, "--incremental");
}
- if (geometry)
+ if (po_args.filter_options.choice)
+ strvec_pushf(&cmd.args, "--filter=%s",
+ expand_list_objects_filter_spec(&po_args.filter_options));
+ else if (filter_to)
+ die(_("option '%s' can only be used along with '%s'"), "--filter-to", "--filter");
+
+ if (geometry.split_factor)
cmd.in = -1;
else
cmd.no_stdin = 1;
@@ -1000,32 +1350,21 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (ret)
goto cleanup;
- if (geometry) {
+ if (geometry.split_factor) {
FILE *in = xfdopen(cmd.in, "w");
/*
* The resulting pack should contain all objects in packs that
* are going to be rolled up, but exclude objects in packs which
* are being left alone.
*/
- for (i = 0; i < geometry->split; i++)
- fprintf(in, "%s\n", pack_basename(geometry->pack[i]));
- for (i = geometry->split; i < geometry->pack_nr; i++)
- fprintf(in, "^%s\n", pack_basename(geometry->pack[i]));
+ for (i = 0; i < geometry.split; i++)
+ fprintf(in, "%s\n", pack_basename(geometry.pack[i]));
+ for (i = geometry.split; i < geometry.pack_nr; i++)
+ fprintf(in, "^%s\n", pack_basename(geometry.pack[i]));
fclose(in);
}
- out = xfdopen(cmd.out, "r");
- while (strbuf_getline_lf(&line, out) != EOF) {
- struct string_list_item *item;
-
- if (line.len != the_hash_algo->hexsz)
- die(_("repack: Expecting full hex object ID lines only from pack-objects."));
- item = string_list_append(&names, line.buf);
- item->util = populate_pack_exts(item->string);
- }
- strbuf_release(&line);
- fclose(out);
- ret = finish_command(&cmd);
+ ret = finish_pack_objects_cmd(&cmd, &names, 1);
if (ret)
goto cleanup;
@@ -1033,12 +1372,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
printf_ln(_("Nothing new to pack."));
if (pack_everything & PACK_CRUFT) {
- const char *pack_prefix;
- if (!skip_prefix(packtmp, packdir, &pack_prefix))
- die(_("pack prefix %s does not begin with objdir %s"),
- packtmp, packdir);
- if (*pack_prefix == '/')
- pack_prefix++;
+ const char *pack_prefix = find_pack_prefix(packdir, packtmp);
if (!cruft_po_args.window)
cruft_po_args.window = po_args.window;
@@ -1048,14 +1382,15 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
cruft_po_args.depth = po_args.depth;
if (!cruft_po_args.threads)
cruft_po_args.threads = po_args.threads;
+ if (!cruft_po_args.max_pack_size)
+ cruft_po_args.max_pack_size = po_args.max_pack_size;
cruft_po_args.local = po_args.local;
cruft_po_args.quiet = po_args.quiet;
ret = write_cruft_pack(&cruft_po_args, packtmp, pack_prefix,
cruft_expiration, &names,
- &existing_nonkept_packs,
- &existing_kept_packs);
+ &existing);
if (ret)
goto cleanup;
@@ -1086,13 +1421,25 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
pack_prefix,
NULL,
&names,
- &existing_nonkept_packs,
- &existing_kept_packs);
+ &existing);
if (ret)
goto cleanup;
}
}
+ if (po_args.filter_options.choice) {
+ if (!filter_to)
+ filter_to = packtmp;
+
+ ret = write_filtered_pack(&po_args,
+ filter_to,
+ find_pack_prefix(packdir, packtmp),
+ &existing,
+ &names);
+ if (ret)
+ goto cleanup;
+ }
+
string_list_sort(&names);
close_object_store(the_repository->objects);
@@ -1131,31 +1478,14 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
}
/* End of pack replacement. */
- if (delete_redundant && pack_everything & ALL_INTO_ONE) {
- const int hexsz = the_hash_algo->hexsz;
- for_each_string_list_item(item, &existing_nonkept_packs) {
- char *sha1;
- size_t len = strlen(item->string);
- if (len < hexsz)
- continue;
- sha1 = item->string + len - hexsz;
- /*
- * Mark this pack for deletion, which ensures that this
- * pack won't be included in a MIDX (if `--write-midx`
- * was given) and that we will actually delete this pack
- * (if `-d` was given).
- */
- if (!string_list_has_string(&names, sha1))
- item->util = (void*)(uintptr_t)((size_t)item->util | DELETE_PACK);
- }
- }
+ if (delete_redundant && pack_everything & ALL_INTO_ONE)
+ mark_packs_for_deletion(&existing, &names);
if (write_midx) {
struct string_list include = STRING_LIST_INIT_NODUP;
- midx_included_packs(&include, &existing_nonkept_packs,
- &existing_kept_packs, &names, geometry);
+ midx_included_packs(&include, &existing, &names, &geometry);
- ret = write_midx_included_packs(&include, geometry,
+ ret = write_midx_included_packs(&include, &geometry, &names,
refs_snapshot ? get_tempfile_path(refs_snapshot) : NULL,
show_progress, write_bitmaps > 0);
@@ -1172,35 +1502,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (delete_redundant) {
int opts = 0;
- for_each_string_list_item(item, &existing_nonkept_packs) {
- if (!((uintptr_t)item->util & DELETE_PACK))
- continue;
- remove_redundant_pack(packdir, item->string);
- }
-
- if (geometry) {
- struct strbuf buf = STRBUF_INIT;
-
- uint32_t i;
- for (i = 0; i < geometry->split; i++) {
- struct packed_git *p = geometry->pack[i];
- if (string_list_has_string(&names,
- hash_to_hex(p->hash)))
- continue;
+ remove_redundant_existing_packs(&existing);
- strbuf_reset(&buf);
- strbuf_addstr(&buf, pack_basename(p));
- strbuf_strip_suffix(&buf, ".pack");
-
- if ((p->pack_keep) ||
- (string_list_has_string(&existing_kept_packs,
- buf.buf)))
- continue;
-
- remove_redundant_pack(packdir, buf.buf);
- }
- strbuf_release(&buf);
- }
+ if (geometry.split_factor)
+ geometry_remove_redundant_packs(&geometry, &names,
+ &existing);
if (show_progress)
opts |= PRUNE_PACKED_VERBOSE;
prune_packed_objects(opts);
@@ -1224,9 +1530,9 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
cleanup:
string_list_clear(&names, 1);
- string_list_clear(&existing_nonkept_packs, 0);
- string_list_clear(&existing_kept_packs, 0);
- free_pack_geometry(geometry);
+ existing_packs_release(&existing);
+ free_pack_geometry(&geometry);
+ list_objects_filter_release(&po_args.filter_options);
return ret;
}
diff --git a/builtin/stash.c b/builtin/stash.c
index fe64cde9ce..4a6771c9f4 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -362,7 +362,7 @@ static int is_path_a_directory(const char *path)
}
static void add_diff_to_buf(struct diff_queue_struct *q,
- struct diff_options *options,
+ struct diff_options *options UNUSED,
void *data)
{
int i;
@@ -973,7 +973,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
}
log_tree_diff_flush(&rev);
- ret = diff_result_code(&rev.diffopt, 0);
+ ret = diff_result_code(&rev.diffopt);
cleanup:
strvec_clear(&stash_args);
free_stash_info(&info);
@@ -989,6 +989,12 @@ usage:
static int do_store_stash(const struct object_id *w_commit, const char *stash_msg,
int quiet)
{
+ struct stash_info info;
+ char revision[GIT_MAX_HEXSZ];
+
+ oid_to_hex_r(revision, w_commit);
+ assert_stash_like(&info, revision);
+
if (!stash_msg)
stash_msg = "Created via \"git stash store\".";
@@ -1089,7 +1095,6 @@ static int get_untracked_files(const struct pathspec *ps, int include_untracked,
*/
static int check_changes_tracked_files(const struct pathspec *ps)
{
- int result;
struct rev_info rev;
struct object_id dummy;
int ret = 0;
@@ -1111,14 +1116,14 @@ static int check_changes_tracked_files(const struct pathspec *ps)
add_head_to_pending(&rev);
diff_setup_done(&rev.diffopt);
- result = run_diff_index(&rev, 1);
- if (diff_result_code(&rev.diffopt, result)) {
+ run_diff_index(&rev, DIFF_INDEX_CACHED);
+ if (diff_result_code(&rev.diffopt)) {
ret = 1;
goto done;
}
- result = run_diff_files(&rev, 0);
- if (diff_result_code(&rev.diffopt, result)) {
+ run_diff_files(&rev, 0);
+ if (diff_result_code(&rev.diffopt)) {
ret = 1;
goto done;
}
@@ -1309,10 +1314,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
add_pending_object(&rev, parse_object(the_repository, &info->b_commit),
"");
- if (run_diff_index(&rev, 0)) {
- ret = -1;
- goto done;
- }
+ run_diff_index(&rev, 0);
cp_upd_index.git_cmd = 1;
strvec_pushl(&cp_upd_index.args, "update-index",
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f6871efd95..cce46450ab 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -629,7 +629,6 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
char *displaypath;
struct strvec diff_files_args = STRVEC_INIT;
struct rev_info rev = REV_INFO_INIT;
- int diff_files_result;
struct strbuf buf = STRBUF_INIT;
const char *git_dir;
struct setup_revision_opt opt = {
@@ -669,9 +668,9 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
repo_init_revisions(the_repository, &rev, NULL);
rev.abbrev = 0;
setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt);
- diff_files_result = run_diff_files(&rev, 0);
+ run_diff_files(&rev, 0);
- if (!diff_result_code(&rev.diffopt, diff_files_result)) {
+ if (!diff_result_code(&rev.diffopt)) {
print_status(flags, ' ', path, ce_oid,
displaypath);
} else if (!(flags & OPT_CACHED)) {
@@ -1141,7 +1140,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
}
if (diff_cmd == DIFF_INDEX)
- run_diff_index(&rev, info->cached);
+ run_diff_index(&rev, info->cached ? DIFF_INDEX_CACHED : 0);
else
run_diff_files(&rev, 0);
prepare_submodule_summary(info, &list);
@@ -2890,7 +2889,7 @@ cleanup:
static int module_set_url(int argc, const char **argv, const char *prefix)
{
- int quiet = 0;
+ int quiet = 0, ret;
const char *newurl;
const char *path;
char *config_name;
@@ -2902,20 +2901,29 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
N_("git submodule set-url [--quiet] <path> <newurl>"),
NULL
};
+ const struct submodule *sub;
argc = parse_options(argc, argv, prefix, options, usage, 0);
if (argc != 2 || !(path = argv[0]) || !(newurl = argv[1]))
usage_with_options(usage, options);
- config_name = xstrfmt("submodule.%s.url", path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
- config_set_in_gitmodules_file_gently(config_name, newurl);
- sync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);
+ if (!sub)
+ die(_("no submodule mapping found in .gitmodules for path '%s'"),
+ path);
- free(config_name);
+ config_name = xstrfmt("submodule.%s.url", sub->name);
+ ret = config_set_in_gitmodules_file_gently(config_name, newurl);
- return 0;
+ if (!ret) {
+ repo_read_gitmodules(the_repository, 0);
+ sync_submodule(sub->path, prefix, NULL, quiet ? OPT_QUIET : 0);
+ }
+
+ free(config_name);
+ return !!ret;
}
static int module_set_branch(int argc, const char **argv, const char *prefix)
@@ -2942,6 +2950,7 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
N_("git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"),
NULL
};
+ const struct submodule *sub;
argc = parse_options(argc, argv, prefix, options, usage, 0);
@@ -2954,7 +2963,13 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
if (argc != 1 || !(path = argv[0]))
usage_with_options(usage, options);
- config_name = xstrfmt("submodule.%s.branch", path);
+ sub = submodule_from_path(the_repository, null_oid(), path);
+
+ if (!sub)
+ die(_("no submodule mapping found in .gitmodules for path '%s'"),
+ path);
+
+ config_name = xstrfmt("submodule.%s.branch", sub->name);
ret = config_set_in_gitmodules_file_gently(config_name, opt_branch);
free(config_name);
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 32505255a0..fef7423448 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -609,6 +609,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
{
int i;
struct object_id oid;
+ git_hash_ctx tmp_ctx;
disable_replace_refs();
@@ -669,7 +670,9 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix UNUSED)
the_hash_algo->init_fn(&ctx);
unpack_all();
the_hash_algo->update_fn(&ctx, buffer, offset);
- the_hash_algo->final_oid_fn(&oid, &ctx);
+ the_hash_algo->init_fn(&tmp_ctx);
+ the_hash_algo->clone_fn(&tmp_ctx, &ctx);
+ the_hash_algo->final_oid_fn(&oid, &tmp_ctx);
if (strict) {
write_rest();
if (fsck_finish(&fsck_options))
diff --git a/builtin/update-index.c b/builtin/update-index.c
index aee3cb8cbd..7bcaa1476c 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -609,9 +609,6 @@ static const char * const update_index_usage[] = {
NULL
};
-static struct object_id head_oid;
-static struct object_id merge_head_oid;
-
static struct cache_entry *read_one_ent(const char *which,
struct object_id *ent, const char *path,
int namelen, int stage)
@@ -642,84 +639,17 @@ static struct cache_entry *read_one_ent(const char *which,
static int unresolve_one(const char *path)
{
- int namelen = strlen(path);
- int pos;
- int ret = 0;
- struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
-
- /* See if there is such entry in the index. */
- pos = index_name_pos(&the_index, path, namelen);
- if (0 <= pos) {
- /* already merged */
- pos = unmerge_index_entry_at(&the_index, pos);
- if (pos < the_index.cache_nr) {
- const struct cache_entry *ce = the_index.cache[pos];
- if (ce_stage(ce) &&
- ce_namelen(ce) == namelen &&
- !memcmp(ce->name, path, namelen))
- return 0;
- }
- /* no resolve-undo information; fall back */
- } else {
- /* If there isn't, either it is unmerged, or
- * resolved as "removed" by mistake. We do not
- * want to do anything in the former case.
- */
- pos = -pos-1;
- if (pos < the_index.cache_nr) {
- const struct cache_entry *ce = the_index.cache[pos];
- if (ce_namelen(ce) == namelen &&
- !memcmp(ce->name, path, namelen)) {
- fprintf(stderr,
- "%s: skipping still unmerged path.\n",
- path);
- goto free_return;
- }
- }
- }
-
- /* Grab blobs from given path from HEAD and MERGE_HEAD,
- * stuff HEAD version in stage #2,
- * stuff MERGE_HEAD version in stage #3.
- */
- ce_2 = read_one_ent("our", &head_oid, path, namelen, 2);
- ce_3 = read_one_ent("their", &merge_head_oid, path, namelen, 3);
-
- if (!ce_2 || !ce_3) {
- ret = -1;
- goto free_return;
- }
- if (oideq(&ce_2->oid, &ce_3->oid) &&
- ce_2->ce_mode == ce_3->ce_mode) {
- fprintf(stderr, "%s: identical in both, skipping.\n",
- path);
- goto free_return;
- }
-
- remove_file_from_index(&the_index, path);
- if (add_index_entry(&the_index, ce_2, ADD_CACHE_OK_TO_ADD)) {
- error("%s: cannot add our version to the index.", path);
- ret = -1;
- goto free_return;
- }
- if (!add_index_entry(&the_index, ce_3, ADD_CACHE_OK_TO_ADD))
- return 0;
- error("%s: cannot add their version to the index.", path);
- ret = -1;
- free_return:
- discard_cache_entry(ce_2);
- discard_cache_entry(ce_3);
- return ret;
-}
-
-static void read_head_pointers(void)
-{
- if (read_ref("HEAD", &head_oid))
- die("No HEAD -- no initial commit yet?");
- if (read_ref("MERGE_HEAD", &merge_head_oid)) {
- fprintf(stderr, "Not in the middle of a merge.\n");
- exit(0);
- }
+ struct string_list_item *item;
+ int res = 0;
+
+ if (!the_index.resolve_undo)
+ return res;
+ item = string_list_lookup(the_index.resolve_undo, path);
+ if (!item)
+ return res; /* no resolve-undo record for the path */
+ res = unmerge_index_entry(&the_index, path, item->util, 0);
+ FREE_AND_NULL(item->util);
+ return res;
}
static int do_unresolve(int ac, const char **av,
@@ -728,11 +658,6 @@ static int do_unresolve(int ac, const char **av,
int i;
int err = 0;
- /* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
- * are not doing a merge, so exit with success status.
- */
- read_head_pointers();
-
for (i = 1; i < ac; i++) {
const char *arg = av[i];
char *p = prefix_path(prefix, prefix_length, arg);
@@ -751,6 +676,7 @@ static int do_reupdate(const char **paths,
int pos;
int has_head = 1;
struct pathspec pathspec;
+ struct object_id head_oid;
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
@@ -856,7 +782,7 @@ static int chmod_callback(const struct option *opt,
return 0;
}
-static int resolve_undo_clear_callback(const struct option *opt,
+static int resolve_undo_clear_callback(const struct option *opt UNUSED,
const char *arg, int unset)
{
BUG_ON_OPT_NEG(unset);
@@ -890,7 +816,7 @@ static int parse_new_style_cacheinfo(const char *arg,
}
static enum parse_opt_result cacheinfo_callback(
- struct parse_opt_ctx_t *ctx, const struct option *opt,
+ struct parse_opt_ctx_t *ctx, const struct option *opt UNUSED,
const char *arg, int unset)
{
struct object_id oid;
@@ -1090,6 +1016,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
resolve_undo_clear_callback),
OPT_INTEGER(0, "index-version", &preferred_index_format,
N_("write index in this format")),
+ OPT_SET_INT(0, "show-index-version", &preferred_index_format,
+ N_("report on-disk index format version"), -1),
OPT_BOOL(0, "split-index", &split_index,
N_("enable or disable split index")),
OPT_BOOL(0, "untracked-cache", &untracked_cache,
@@ -1182,15 +1110,20 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
if (preferred_index_format) {
- if (preferred_index_format < INDEX_FORMAT_LB ||
- INDEX_FORMAT_UB < preferred_index_format)
+ if (preferred_index_format < 0) {
+ printf(_("%d\n"), the_index.version);
+ } else if (preferred_index_format < INDEX_FORMAT_LB ||
+ INDEX_FORMAT_UB < preferred_index_format) {
die("index-version %d not in range: %d..%d",
preferred_index_format,
INDEX_FORMAT_LB, INDEX_FORMAT_UB);
-
- if (the_index.version != preferred_index_format)
- the_index.cache_changed |= SOMETHING_CHANGED;
- the_index.version = preferred_index_format;
+ } else {
+ if (the_index.version != preferred_index_format)
+ the_index.cache_changed |= SOMETHING_CHANGED;
+ report(_("index-version: was %d, set to %d"),
+ the_index.version, preferred_index_format);
+ the_index.version = preferred_index_format;
+ }
}
if (read_from_stdin) {
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 242102273e..c0c4e65e6f 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -311,8 +311,8 @@ static void report_ok(const char *command)
fflush(stdout);
}
-static void parse_cmd_option(struct ref_transaction *transaction,
- const char *next, const char *end)
+static void parse_cmd_option(struct ref_transaction *transaction UNUSED,
+ const char *next, const char *end UNUSED)
{
const char *rest;
if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination)
@@ -321,8 +321,8 @@ static void parse_cmd_option(struct ref_transaction *transaction,
die("option unknown: %s", next);
}
-static void parse_cmd_start(struct ref_transaction *transaction,
- const char *next, const char *end)
+static void parse_cmd_start(struct ref_transaction *transaction UNUSED,
+ const char *next, const char *end UNUSED)
{
if (*next != line_termination)
die("start: extra input: %s", next);
@@ -330,7 +330,7 @@ static void parse_cmd_start(struct ref_transaction *transaction,
}
static void parse_cmd_prepare(struct ref_transaction *transaction,
- const char *next, const char *end)
+ const char *next, const char *end UNUSED)
{
struct strbuf error = STRBUF_INIT;
if (*next != line_termination)
@@ -341,7 +341,7 @@ static void parse_cmd_prepare(struct ref_transaction *transaction,
}
static void parse_cmd_abort(struct ref_transaction *transaction,
- const char *next, const char *end)
+ const char *next, const char *end UNUSED)
{
struct strbuf error = STRBUF_INIT;
if (*next != line_termination)
@@ -352,7 +352,7 @@ static void parse_cmd_abort(struct ref_transaction *transaction,
}
static void parse_cmd_commit(struct ref_transaction *transaction,
- const char *next, const char *end)
+ const char *next, const char *end UNUSED)
{
struct strbuf error = STRBUF_INIT;
if (*next != line_termination)
diff --git a/builtin/var.c b/builtin/var.c
index 74161bdf1c..8cf7dd9e2e 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -66,7 +66,7 @@ static char *git_attr_val_system(int ident_flag UNUSED)
static char *git_attr_val_global(int ident_flag UNUSED)
{
- char *file = xstrdup(git_attr_global_file());
+ char *file = xstrdup_or_null(git_attr_global_file());
if (file) {
normalize_path_copy(file, file);
return file;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 4cd01842de..62b7e26f4b 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -628,10 +628,10 @@ static void print_preparing_worktree_line(int detach,
*
* Returns 0 on failure and non-zero on success.
*/
-static int first_valid_ref(const char *refname,
- const struct object_id *oid,
- int flags,
- void *cb_data)
+static int first_valid_ref(const char *refname UNUSED,
+ const struct object_id *oid UNUSED,
+ int flags UNUSED,
+ void *cb_data UNUSED)
{
return 1;
}
@@ -696,7 +696,7 @@ static int can_use_remote_refs(const struct add_opts *opts)
return 1;
} else if (!opts->force && remote_get(NULL)) {
die(_("No local or remote refs exist despite at least one remote\n"
- "present, stopping; use 'add -f' to overide or fetch a remote first"));
+ "present, stopping; use 'add -f' to override or fetch a remote first"));
}
return 0;
}