aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c22
-rw-r--r--builtin/am.c15
-rw-r--r--builtin/apply.c2
-rw-r--r--builtin/backfill.c6
-rw-r--r--builtin/blame.c25
-rw-r--r--builtin/branch.c8
-rw-r--r--builtin/cat-file.c80
-rw-r--r--builtin/check-attr.c2
-rw-r--r--builtin/check-ignore.c3
-rw-r--r--builtin/check-mailmap.c3
-rw-r--r--builtin/checkout--worker.c3
-rw-r--r--builtin/checkout-index.c1
-rw-r--r--builtin/checkout.c43
-rw-r--r--builtin/clean.c77
-rw-r--r--builtin/clone.c40
-rw-r--r--builtin/column.c4
-rw-r--r--builtin/commit-graph.c26
-rw-r--r--builtin/commit-tree.c7
-rw-r--r--builtin/commit.c26
-rw-r--r--builtin/config.c72
-rw-r--r--builtin/count-objects.c11
-rw-r--r--builtin/credential-cache--daemon.c2
-rw-r--r--builtin/credential-store.c2
-rw-r--r--builtin/credential.c3
-rw-r--r--builtin/describe.c94
-rw-r--r--builtin/diff-files.c2
-rw-r--r--builtin/diff-index.c2
-rw-r--r--builtin/diff-tree.c2
-rw-r--r--builtin/diff.c6
-rw-r--r--builtin/difftool.c4
-rw-r--r--builtin/fast-export.c75
-rw-r--r--builtin/fast-import.c178
-rw-r--r--builtin/fetch-pack.c7
-rw-r--r--builtin/fetch.c179
-rw-r--r--builtin/fmt-merge-msg.c2
-rw-r--r--builtin/for-each-ref.c9
-rw-r--r--builtin/fsck.c56
-rw-r--r--builtin/fsmonitor--daemon.c3
-rw-r--r--builtin/gc.c515
-rw-r--r--builtin/grep.c31
-rw-r--r--builtin/hash-object.c7
-rw-r--r--builtin/help.c5
-rw-r--r--builtin/hook.c3
-rw-r--r--builtin/index-pack.c35
-rw-r--r--builtin/interpret-trailers.c3
-rw-r--r--builtin/log.c176
-rw-r--r--builtin/ls-files.c5
-rw-r--r--builtin/ls-remote.c2
-rw-r--r--builtin/ls-tree.c9
-rw-r--r--builtin/merge-base.c3
-rw-r--r--builtin/merge-file.c7
-rw-r--r--builtin/merge-tree.c47
-rw-r--r--builtin/merge.c70
-rw-r--r--builtin/mktag.c12
-rw-r--r--builtin/mktree.c12
-rw-r--r--builtin/multi-pack-index.c11
-rw-r--r--builtin/mv.c2
-rw-r--r--builtin/name-rev.c2
-rw-r--r--builtin/notes.c38
-rw-r--r--builtin/pack-objects.c727
-rw-r--r--builtin/pack-redundant.c12
-rw-r--r--builtin/pack-refs.c1
-rw-r--r--builtin/patch-id.c5
-rw-r--r--builtin/prune.c30
-rw-r--r--builtin/pull.c34
-rw-r--r--builtin/push.c2
-rw-r--r--builtin/range-diff.c2
-rw-r--r--builtin/read-tree.c3
-rw-r--r--builtin/rebase.c47
-rw-r--r--builtin/receive-pack.c115
-rw-r--r--builtin/reflog.c108
-rw-r--r--builtin/refs.c2
-rw-r--r--builtin/remote.c440
-rw-r--r--builtin/repack.c209
-rw-r--r--builtin/replace.c18
-rw-r--r--builtin/replay.c1
-rw-r--r--builtin/rerere.c2
-rw-r--r--builtin/reset.c19
-rw-r--r--builtin/rev-list.c40
-rw-r--r--builtin/rev-parse.c4
-rw-r--r--builtin/revert.c2
-rw-r--r--builtin/rm.c3
-rw-r--r--builtin/send-pack.c10
-rw-r--r--builtin/shortlog.c7
-rw-r--r--builtin/show-branch.c2
-rw-r--r--builtin/show-index.c2
-rw-r--r--builtin/show-ref.c9
-rw-r--r--builtin/sparse-checkout.c2
-rw-r--r--builtin/stash.c544
-rw-r--r--builtin/stripspace.c2
-rw-r--r--builtin/submodule--helper.c235
-rw-r--r--builtin/symbolic-ref.c3
-rw-r--r--builtin/tag.c16
-rw-r--r--builtin/unpack-file.c7
-rw-r--r--builtin/unpack-objects.c29
-rw-r--r--builtin/update-index.c8
-rw-r--r--builtin/update-ref.c28
-rw-r--r--builtin/update-server-info.c1
-rw-r--r--builtin/var.c7
-rw-r--r--builtin/verify-commit.c1
-rw-r--r--builtin/verify-pack.c3
-rw-r--r--builtin/verify-tag.c1
-rw-r--r--builtin/worktree.c10
-rw-r--r--builtin/write-tree.c4
104 files changed, 3252 insertions, 1602 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 7c292ffdc6..0235854f80 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -7,6 +7,7 @@
#include "builtin.h"
#include "advice.h"
#include "config.h"
+#include "environment.h"
#include "lockfile.h"
#include "editor.h"
#include "dir.h"
@@ -29,6 +30,7 @@ static const char * const builtin_add_usage[] = {
NULL
};
static int patch_interactive, add_interactive, edit_interactive;
+static struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
static int take_worktree_changes;
static int add_renormalize;
static int pathspec_file_nul;
@@ -157,7 +159,7 @@ static int refresh(struct repository *repo, int verbose, const struct pathspec *
int interactive_add(struct repository *repo,
const char **argv,
const char *prefix,
- int patch)
+ int patch, struct add_p_opt *add_p_opt)
{
struct pathspec pathspec;
int ret;
@@ -169,9 +171,9 @@ int interactive_add(struct repository *repo,
prefix, argv);
if (patch)
- ret = !!run_add_p(repo, ADD_P_ADD, NULL, &pathspec);
+ ret = !!run_add_p(repo, ADD_P_ADD, add_p_opt, NULL, &pathspec);
else
- ret = !!run_add_i(repo, &pathspec);
+ ret = !!run_add_i(repo, &pathspec, add_p_opt);
clear_pathspec(&pathspec);
return ret;
@@ -253,6 +255,8 @@ static struct option builtin_add_options[] = {
OPT_GROUP(""),
OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0),
OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
@@ -394,6 +398,11 @@ int cmd_add(int argc,
prepare_repo_settings(repo);
repo->settings.command_requires_full_index = 0;
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
if (patch_interactive)
add_interactive = 1;
if (add_interactive) {
@@ -401,7 +410,12 @@ int cmd_add(int argc,
die(_("options '%s' and '%s' cannot be used together"), "--dry-run", "--interactive/--patch");
if (pathspec_from_file)
die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch");
- exit(interactive_add(repo, argv + 1, prefix, patch_interactive));
+ exit(interactive_add(repo, argv + 1, prefix, patch_interactive, &add_p_opt));
+ } else {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--interactive/--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--interactive/--patch");
}
if (edit_interactive) {
diff --git a/builtin/am.c b/builtin/am.c
index e32a3b4c97..6073d64ae9 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -162,18 +162,18 @@ static void am_state_init(struct am_state *state)
state->prec = 4;
- git_config_get_bool("am.threeway", &state->threeway);
+ repo_config_get_bool(the_repository, "am.threeway", &state->threeway);
state->utf8 = 1;
- git_config_get_bool("am.messageid", &state->message_id);
+ repo_config_get_bool(the_repository, "am.messageid", &state->message_id);
state->scissors = SCISSORS_UNSET;
state->quoted_cr = quoted_cr_unset;
strvec_init(&state->git_apply_opts);
- if (!git_config_get_bool("commit.gpgsign", &gpgsign))
+ if (!repo_config_get_bool(the_repository, "commit.gpgsign", &gpgsign))
state->sign_commit = gpgsign ? "" : NULL;
}
@@ -965,7 +965,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
{
if (keep_cr < 0) {
keep_cr = 0;
- git_config_get_bool("am.keepcr", &keep_cr);
+ repo_config_get_bool(the_repository, "am.keepcr", &keep_cr);
}
switch (patch_format) {
@@ -1000,7 +1000,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
if (!patch_format) {
fprintf_ln(stderr, _("Patch format detection failed."));
- exit(128);
+ die(NULL);
}
if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
@@ -1178,7 +1178,7 @@ static void NORETURN die_user_resolve(const struct am_state *state)
strbuf_release(&sb);
}
- exit(128);
+ die(NULL);
}
/**
@@ -2406,6 +2406,7 @@ int cmd_am(int argc,
.type = OPTION_CALLBACK,
.long_name = "show-current-patch",
.value = &resume_mode,
+ .precision = sizeof(resume_mode),
.argh = "(diff|raw)",
.help = N_("show the patch being applied"),
.flags = PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
@@ -2444,7 +2445,7 @@ int cmd_am(int argc,
show_usage_with_options_if_asked(argc, argv, usage, options);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
am_state_init(&state);
diff --git a/builtin/apply.c b/builtin/apply.c
index a1e20c593d..d642a40251 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -29,7 +29,7 @@ int cmd_apply(int argc,
* cf. https://lore.kernel.org/git/xmqqcypfcmn4.fsf@gitster.g/
*/
if (!the_hash_algo)
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+ repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
argc = apply_parse_options(argc, argv,
&state, &force_apply, &options,
diff --git a/builtin/backfill.c b/builtin/backfill.c
index fa82ad2f6f..80056abe47 100644
--- a/builtin/backfill.c
+++ b/builtin/backfill.c
@@ -13,7 +13,7 @@
#include "tree.h"
#include "tree-walk.h"
#include "object.h"
-#include "object-store.h"
+#include "odb.h"
#include "oid-array.h"
#include "oidset.h"
#include "promisor-remote.h"
@@ -67,8 +67,8 @@ static int fill_missing_blobs(const char *path UNUSED,
return 0;
for (size_t i = 0; i < list->nr; i++) {
- if (!has_object(ctx->repo, &list->oid[i],
- OBJECT_INFO_FOR_PREFETCH))
+ if (!odb_has_object(ctx->repo->objects, &list->oid[i],
+ OBJECT_INFO_FOR_PREFETCH))
oid_array_append(&ctx->current_batch, &list->oid[i]);
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 944952e30e..2703820258 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -28,7 +28,7 @@
#include "line-log.h"
#include "progress.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "pager.h"
#include "blame.h"
#include "refs.h"
@@ -197,9 +197,7 @@ static void commit_info_destroy(struct commit_info *ci)
strbuf_release(&ci->summary);
}
-static void get_commit_info(struct commit *commit,
- struct commit_info *ret,
- int detailed)
+static void get_commit_info(struct commit *commit, struct commit_info *ret)
{
int len;
const char *subject, *encoding;
@@ -211,11 +209,6 @@ static void get_commit_info(struct commit *commit,
&ret->author, &ret->author_mail,
&ret->author_time, &ret->author_tz);
- if (!detailed) {
- repo_unuse_commit_buffer(the_repository, commit, message);
- return;
- }
-
get_ac_line(message, "\ncommitter ",
&ret->committer, &ret->committer_mail,
&ret->committer_time, &ret->committer_tz);
@@ -263,7 +256,7 @@ static int emit_one_suspect_detail(struct blame_origin *suspect, int repeat)
return 0;
suspect->commit->object.flags |= METAINFO_SHOWN;
- get_commit_info(suspect->commit, &ci, 1);
+ get_commit_info(suspect->commit, &ci);
printf("author %s\n", ci.author.buf);
printf("author-mail %s\n", ci.author_mail.buf);
printf("author-time %"PRItime"\n", ci.author_time);
@@ -420,7 +413,7 @@ static void parse_color_fields(const char *s)
colorfield_nr = 0;
/* Ideally this would be stripped and split at the same time? */
- string_list_split(&l, s, ',', -1);
+ string_list_split(&l, s, ",", -1);
ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
for_each_string_list_item(item, &l) {
@@ -471,7 +464,7 @@ static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int
int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
const char *default_color = NULL, *color = NULL, *reset = NULL;
- get_commit_info(suspect->commit, &ci, 1);
+ get_commit_info(suspect->commit, &ci);
oid_to_hex_r(hex, &suspect->commit->object.oid);
cp = blame_nth_line(sb, ent->lno);
@@ -665,7 +658,7 @@ static void find_alignment(struct blame_scoreboard *sb, int *option)
if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
struct commit_info ci = COMMIT_INFO_INIT;
suspect->commit->object.flags |= METAINFO_SHOWN;
- get_commit_info(suspect->commit, &ci, 1);
+ get_commit_info(suspect->commit, &ci);
if (*option & OUTPUT_SHOW_EMAIL)
num = utf8_strwidth(ci.author_mail.buf);
else
@@ -837,7 +830,7 @@ static int is_a_rev(const char *name)
if (repo_get_oid(the_repository, name, &oid))
return 0;
- return OBJ_NONE < oid_object_info(the_repository, &oid, NULL);
+ return OBJ_NONE < odb_read_object_info(the_repository->objects, &oid, NULL);
}
static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)
@@ -848,7 +841,7 @@ static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)
oidcpy(&oid, oid_ret);
while (1) {
struct object *obj;
- int kind = oid_object_info(r, &oid, NULL);
+ int kind = odb_read_object_info(r->objects, &oid, NULL);
if (kind == OBJ_COMMIT) {
oidcpy(oid_ret, &oid);
return 0;
@@ -947,7 +940,7 @@ int cmd_blame(int argc,
const char *const *opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage;
setup_default_color_by_age();
- git_config(git_blame_config, &output_option);
+ repo_config(the_repository, git_blame_config, &output_option);
repo_init_revisions(the_repository, &revs, NULL);
revs.date_mode = blame_date_mode;
revs.diffopt.flags.allow_textconv = 1;
diff --git a/builtin/branch.c b/builtin/branch.c
index c150131bd9..fa5ced452e 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -699,7 +699,7 @@ static int edit_branch_description(const char *branch_name)
strbuf_addf(&name, "branch.%s.description", branch_name);
if (buf.len || exists)
- git_config_set(name.buf, buf.len ? buf.buf : NULL);
+ repo_config_set(the_repository, name.buf, buf.len ? buf.buf : NULL);
strbuf_release(&name);
strbuf_release(&buf);
@@ -791,7 +791,7 @@ int cmd_branch(int argc,
* Try to set sort keys from config. If config does not set any,
* fall back on default (refname) sorting.
*/
- git_config(git_branch_config, &sorting_options);
+ repo_config(the_repository, git_branch_config, &sorting_options);
if (!sorting_options.nr)
string_list_append(&sorting_options, "refname");
@@ -987,10 +987,10 @@ int cmd_branch(int argc,
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", branch->name);
- git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+ repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.merge", branch->name);
- git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+ repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_release(&buf);
} else if (!noncreate_actions && argc > 0 && argc <= 2) {
const char *branch_name = argv[0];
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 67a5ff2b9e..fce0b06451 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -24,7 +24,7 @@
#include "pack-bitmap.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "replace-object.h"
#include "promisor-remote.h"
#include "mailmap.h"
@@ -74,7 +74,7 @@ static int filter_object(const char *path, unsigned mode,
{
enum object_type type;
- *buf = repo_read_object_file(the_repository, oid, &type, size);
+ *buf = odb_read_object(the_repository->objects, oid, &type, size);
if (!*buf)
return error(_("cannot read object %s '%s'"),
oid_to_hex(oid), path);
@@ -132,7 +132,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
switch (opt) {
case 't':
oi.typep = &type;
- if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
+ if (odb_read_object_info_extended(the_repository->objects, &oid, &oi, flags) < 0)
die("git cat-file: could not get object info");
printf("%s\n", type_name(type));
ret = 0;
@@ -146,7 +146,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
oi.contentp = (void**)&buf;
}
- if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
+ if (odb_read_object_info_extended(the_repository->objects, &oid, &oi, flags) < 0)
die("git cat-file: could not get object info");
if (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {
@@ -160,8 +160,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
goto cleanup;
case 'e':
- ret = !has_object(the_repository, &oid,
- HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR);
+ ret = !odb_has_object(the_repository->objects, &oid,
+ HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR);
goto cleanup;
case 'w':
@@ -180,7 +180,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
/* else fallthrough */
case 'p':
- type = oid_object_info(the_repository, &oid, NULL);
+ type = odb_read_object_info(the_repository->objects, &oid, NULL);
if (type < 0)
die("Not a valid object name %s", obj_name);
@@ -197,8 +197,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
ret = stream_blob(&oid);
goto cleanup;
}
- buf = repo_read_object_file(the_repository, &oid, &type,
- &size);
+ buf = odb_read_object(the_repository->objects, &oid,
+ &type, &size);
if (!buf)
die("Cannot read object %s", obj_name);
@@ -217,11 +217,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
if (exp_type_id == OBJ_BLOB) {
struct object_id blob_oid;
- if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {
- char *buffer = repo_read_object_file(the_repository,
- &oid,
- &type,
- &size);
+ if (odb_read_object_info(the_repository->objects,
+ &oid, NULL) == OBJ_TAG) {
+ char *buffer = odb_read_object(the_repository->objects,
+ &oid, &type, &size);
const char *target;
if (!buffer)
@@ -235,7 +234,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
} else
oidcpy(&blob_oid, &oid);
- if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB) {
+ if (odb_read_object_info(the_repository->objects,
+ &blob_oid, NULL) == OBJ_BLOB) {
ret = stream_blob(&blob_oid);
goto cleanup;
}
@@ -246,8 +246,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
* fall-back to the usual case.
*/
}
- buf = read_object_with_reference(the_repository, &oid,
- exp_type_id, &size, NULL);
+ buf = odb_read_object_peeled(the_repository->objects, &oid,
+ exp_type_id, &size, NULL);
if (use_mailmap) {
size_t s = size;
@@ -275,6 +275,7 @@ struct expand_data {
struct object_id oid;
enum object_type type;
unsigned long size;
+ unsigned short mode;
off_t disk_size;
const char *rest;
struct object_id delta_base_oid;
@@ -294,7 +295,7 @@ struct expand_data {
/*
* After a mark_query run, this object_info is set up to be
- * passed to oid_object_info_extended. It will point to the data
+ * passed to odb_read_object_info_extended. It will point to the data
* elements above, so you can retrieve the response from there.
*/
struct object_info info;
@@ -306,6 +307,7 @@ struct expand_data {
*/
unsigned skip_object_info : 1;
};
+#define EXPAND_DATA_INIT { .mode = S_IFINVALID }
static int is_atom(const char *atom, const char *s, int slen)
{
@@ -345,6 +347,9 @@ static int expand_atom(struct strbuf *sb, const char *atom, int len,
else
strbuf_addstr(sb,
oid_to_hex(&data->delta_base_oid));
+ } else if (is_atom("objectmode", atom, len)) {
+ if (!data->mark_query && !(S_IFINVALID == data->mode))
+ strbuf_addf(sb, "%06o", data->mode);
} else
return 0;
return 1;
@@ -401,10 +406,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
if (!textconv_object(the_repository,
data->rest, 0100644, oid,
1, &contents, &size))
- contents = repo_read_object_file(the_repository,
- oid,
- &type,
- &size);
+ contents = odb_read_object(the_repository->objects,
+ oid, &type, &size);
if (!contents)
die("could not convert '%s' %s",
oid_to_hex(oid), data->rest);
@@ -421,8 +424,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
unsigned long size;
void *contents;
- contents = repo_read_object_file(the_repository, oid, &type,
- &size);
+ contents = odb_read_object(the_repository->objects, oid,
+ &type, &size);
if (!contents)
die("object %s disappeared", oid_to_hex(oid));
@@ -484,14 +487,17 @@ static void batch_object_write(const char *obj_name,
data->info.sizep = &data->size;
if (pack)
- ret = packed_object_info(the_repository, pack, offset,
- &data->info);
+ ret = packed_object_info(the_repository, pack,
+ offset, &data->info);
else
- ret = oid_object_info_extended(the_repository,
- &data->oid, &data->info,
- OBJECT_INFO_LOOKUP_REPLACE);
+ ret = odb_read_object_info_extended(the_repository->objects,
+ &data->oid, &data->info,
+ OBJECT_INFO_LOOKUP_REPLACE);
if (ret < 0) {
- report_object_status(opt, obj_name, &data->oid, "missing");
+ if (data->mode == S_IFGITLINK)
+ report_object_status(opt, oid_to_hex(&data->oid), &data->oid, "submodule");
+ else
+ report_object_status(opt, obj_name, &data->oid, "missing");
return;
}
@@ -531,8 +537,8 @@ static void batch_object_write(const char *obj_name,
size_t s = data->size;
char *buf = NULL;
- buf = repo_read_object_file(the_repository, &data->oid, &data->type,
- &data->size);
+ buf = odb_read_object(the_repository->objects, &data->oid,
+ &data->type, &data->size);
if (!buf)
die(_("unable to read %s"), oid_to_hex(&data->oid));
buf = replace_idents_using_mailmap(buf, &s);
@@ -613,6 +619,7 @@ static void batch_one_object(const char *obj_name,
goto out;
}
+ data->mode = ctx.mode;
batch_object_write(obj_name, scratch, opt, data, NULL, 0);
out:
@@ -841,7 +848,7 @@ static void batch_each_object(struct batch_options *opt,
};
struct bitmap_index *bitmap = prepare_bitmap_git(the_repository);
- for_each_loose_object(batch_one_object_loose, &payload, 0);
+ for_each_loose_object(the_repository->objects, batch_one_object_loose, &payload, 0);
if (bitmap && !for_each_bitmapped_object(bitmap, &opt->objects_filter,
batch_one_object_bitmapped, &payload)) {
@@ -866,16 +873,15 @@ static int batch_objects(struct batch_options *opt)
{
struct strbuf input = STRBUF_INIT;
struct strbuf output = STRBUF_INIT;
- struct expand_data data;
+ struct expand_data data = EXPAND_DATA_INIT;
int save_warning;
int retval = 0;
/*
* Expand once with our special mark_query flag, which will prime the
- * object_info to be handed to oid_object_info_extended for each
+ * object_info to be handed to odb_read_object_info_extended for each
* object.
*/
- memset(&data, 0, sizeof(data));
data.mark_query = 1;
expand_format(&output,
opt->format ? opt->format : DEFAULT_FORMAT,
@@ -1089,7 +1095,7 @@ int cmd_cat_file(int argc,
OPT_END()
};
- git_config(git_cat_file_config, NULL);
+ repo_config(the_repository, git_cat_file_config, NULL);
batch.buffer_output = -1;
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 7cf275b893..51ed48ce43 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -119,7 +119,7 @@ int cmd_check_attr(int argc,
if (!is_bare_repository())
setup_work_tree();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, check_attr_options,
check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 7b7831d13a..644c9a414f 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -2,6 +2,7 @@
#include "builtin.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
#include "gettext.h"
#include "quote.h"
#include "pathspec.h"
@@ -159,7 +160,7 @@ int cmd_check_ignore(int argc,
int num_ignored;
struct dir_struct dir = DIR_INIT;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, check_ignore_options,
check_ignore_usage, 0);
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index be2cebe121..9cc5c59830 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "ident.h"
#include "mailmap.h"
@@ -56,7 +57,7 @@ int cmd_check_mailmap(int argc,
int i;
struct string_list mailmap = STRING_LIST_INIT_NODUP;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, check_mailmap_options,
check_mailmap_usage, 0);
if (argc == 0 && !use_stdin)
diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c
index da9345a44b..e0772b718b 100644
--- a/builtin/checkout--worker.c
+++ b/builtin/checkout--worker.c
@@ -4,6 +4,7 @@
#include "builtin.h"
#include "config.h"
#include "entry.h"
+#include "environment.h"
#include "gettext.h"
#include "parallel-checkout.h"
#include "parse-options.h"
@@ -132,7 +133,7 @@ int cmd_checkout__worker(int argc,
checkout_worker_usage,
checkout_worker_options);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, checkout_worker_options,
checkout_worker_usage, 0);
if (argc > 0)
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 7f74bc702f..188128aebd 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "lockfile.h"
#include "quote.h"
diff --git a/builtin/checkout.c b/builtin/checkout.c
index d185982f3a..f9453473fe 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -20,7 +20,7 @@
#include "merge-ort-wrappers.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "parse-options.h"
#include "path.h"
#include "preload-index.h"
@@ -61,6 +61,8 @@ static const char * const restore_usage[] = {
struct checkout_opts {
int patch_mode;
+ int patch_context;
+ int patch_interhunk_context;
int quiet;
int merge;
int force;
@@ -104,7 +106,12 @@ struct checkout_opts {
struct tree *source_tree;
};
-#define CHECKOUT_OPTS_INIT { .conflict_style = -1, .merge = -1 }
+#define CHECKOUT_OPTS_INIT { \
+ .conflict_style = -1, \
+ .merge = -1, \
+ .patch_context = -1, \
+ .patch_interhunk_context = -1, \
+}
struct branch_info {
char *name; /* The short name used */
@@ -291,7 +298,7 @@ static int checkout_merged(int pos, const struct checkout *state,
read_mmblob(&ours, &threeway[1]);
read_mmblob(&theirs, &threeway[2]);
- git_config_get_bool("merge.renormalize", &renormalize);
+ repo_config_get_bool(the_repository, "merge.renormalize", &renormalize);
ll_opts.renormalize = renormalize;
ll_opts.conflict_style = conflict_style;
merge_status = ll_merge(&result_buf, path, &ancestor, "base",
@@ -320,7 +327,7 @@ static int checkout_merged(int pos, const struct checkout *state,
* (it also writes the merge result to the object database even
* when it may contain conflicts).
*/
- if (write_object_file(result_buf.ptr, result_buf.size, OBJ_BLOB, &oid))
+ if (odb_write_object(the_repository->objects, result_buf.ptr, result_buf.size, OBJ_BLOB, &oid))
die(_("Unable to add merge result for '%s'"), path);
free(result_buf.ptr);
ce = make_transient_cache_entry(mode, &oid, path, 2, ce_mem_pool);
@@ -539,6 +546,10 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->patch_mode) {
enum add_p_mode patch_mode;
+ struct add_p_opt add_p_opt = {
+ .context = opts->patch_context,
+ .interhunkcontext = opts->patch_interhunk_context,
+ };
const char *rev = new_branch_info->name;
char rev_oid[GIT_MAX_HEXSZ + 1];
@@ -564,8 +575,8 @@ static int checkout_paths(const struct checkout_opts *opts,
else
BUG("either flag must have been set, worktree=%d, index=%d",
opts->checkout_worktree, opts->checkout_index);
- return !!run_add_p(the_repository, patch_mode, rev,
- &opts->pathspec);
+ return !!run_add_p(the_repository, patch_mode, &add_p_opt,
+ rev, &opts->pathspec);
}
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
@@ -838,7 +849,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
init_tree_desc(&trees[0], &tree->object.oid,
tree->buffer, tree->size);
if (parse_tree(new_tree) < 0)
- exit(128);
+ die(NULL);
tree = new_tree;
init_tree_desc(&trees[1], &tree->object.oid,
tree->buffer, tree->size);
@@ -913,7 +924,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
work,
old_tree);
if (ret < 0)
- exit(128);
+ die(NULL);
ret = reset_tree(new_tree,
opts, 0,
writeout_error, new_branch_info);
@@ -1738,6 +1749,8 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,
N_("checkout their version for unmerged files"),
3, PARSE_OPT_NONEG),
OPT_BOOL('p', "patch", &opts->patch_mode, N_("select hunks interactively")),
+ OPT_DIFF_UNIFIED(&opts->patch_context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&opts->patch_interhunk_context),
OPT_BOOL(0, "ignore-skip-worktree-bits", &opts->ignore_skipworktree,
N_("do not limit pathspecs to sparse entries only")),
OPT_PATHSPEC_FROM_FILE(&opts->pathspec_from_file),
@@ -1764,7 +1777,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->prefix = prefix;
opts->show_progress = -1;
- git_config(git_checkout_config, opts);
+ repo_config(the_repository, git_checkout_config, opts);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
@@ -1780,6 +1793,18 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
argc = parse_options(argc, argv, prefix, options,
usagestr, parseopt_flags);
+ if (opts->patch_context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (opts->patch_interhunk_context < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
+ if (!opts->patch_mode) {
+ if (opts->patch_context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--patch");
+ if (opts->patch_interhunk_context != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch");
+ }
+
if (opts->show_progress < 0) {
if (opts->quiet)
opts->show_progress = 0;
diff --git a/builtin/clean.c b/builtin/clean.c
index 053c94fc6b..38b67923a6 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -13,6 +13,7 @@
#include "abspath.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "path.h"
@@ -477,43 +478,39 @@ static int find_unique(const char *choice, struct menu_stuff *menu_stuff)
*/
static int parse_choice(struct menu_stuff *menu_stuff,
int is_single,
- struct strbuf input,
+ char *input,
int **chosen)
{
- struct strbuf **choice_list, **ptr;
+ struct string_list choice = STRING_LIST_INIT_NODUP;
+ struct string_list_item *item;
int nr = 0;
int i;
- if (is_single) {
- choice_list = strbuf_split_max(&input, '\n', 0);
- } else {
- char *p = input.buf;
- do {
- if (*p == ',')
- *p = ' ';
- } while (*p++);
- choice_list = strbuf_split_max(&input, ' ', 0);
- }
+ string_list_split_in_place_f(&choice, input,
+ is_single ? "\n" : ", ", -1,
+ STRING_LIST_SPLIT_TRIM);
- for (ptr = choice_list; *ptr; ptr++) {
- char *p;
- int choose = 1;
+ for_each_string_list_item(item, &choice) {
+ const char *string;
+ int choose;
int bottom = 0, top = 0;
int is_range, is_number;
- strbuf_trim(*ptr);
- if (!(*ptr)->len)
+ string = item->string;
+ if (!*string)
continue;
/* Input that begins with '-'; unchoose */
- if (*(*ptr)->buf == '-') {
+ if (string[0] == '-') {
choose = 0;
- strbuf_remove((*ptr), 0, 1);
+ string++;
+ } else {
+ choose = 1;
}
is_range = 0;
is_number = 1;
- for (p = (*ptr)->buf; *p; p++) {
+ for (const char *p = string; *p; p++) {
if ('-' == *p) {
if (!is_range) {
is_range = 1;
@@ -531,27 +528,27 @@ static int parse_choice(struct menu_stuff *menu_stuff,
}
if (is_number) {
- bottom = atoi((*ptr)->buf);
+ bottom = atoi(string);
top = bottom;
} else if (is_range) {
- bottom = atoi((*ptr)->buf);
+ bottom = atoi(string);
/* a range can be specified like 5-7 or 5- */
- if (!*(strchr((*ptr)->buf, '-') + 1))
+ if (!*(strchr(string, '-') + 1))
top = menu_stuff->nr;
else
- top = atoi(strchr((*ptr)->buf, '-') + 1);
- } else if (!strcmp((*ptr)->buf, "*")) {
+ top = atoi(strchr(string, '-') + 1);
+ } else if (!strcmp(string, "*")) {
bottom = 1;
top = menu_stuff->nr;
} else {
- bottom = find_unique((*ptr)->buf, menu_stuff);
+ bottom = find_unique(string, menu_stuff);
top = bottom;
}
if (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top ||
(is_single && bottom != top)) {
clean_print_color(CLEAN_COLOR_ERROR);
- printf(_("Huh (%s)?\n"), (*ptr)->buf);
+ printf(_("Huh (%s)?\n"), string);
clean_print_color(CLEAN_COLOR_RESET);
continue;
}
@@ -560,7 +557,7 @@ static int parse_choice(struct menu_stuff *menu_stuff,
(*chosen)[i-1] = choose;
}
- strbuf_list_free(choice_list);
+ string_list_clear(&choice, 0);
for (i = 0; i < menu_stuff->nr; i++)
nr += (*chosen)[i];
@@ -630,7 +627,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)
nr = parse_choice(stuff,
opts->flags & MENU_OPTS_SINGLETON,
- choice,
+ choice.buf,
&chosen);
if (opts->flags & MENU_OPTS_SINGLETON) {
@@ -678,12 +675,13 @@ static int filter_by_patterns_cmd(void)
{
struct dir_struct dir = DIR_INIT;
struct strbuf confirm = STRBUF_INIT;
- struct strbuf **ignore_list;
- struct string_list_item *item;
struct pattern_list *pl;
int changed = -1, i;
for (;;) {
+ struct string_list ignore_list = STRING_LIST_INIT_NODUP;
+ struct string_list_item *item;
+
if (!del_list.nr)
break;
@@ -701,14 +699,15 @@ static int filter_by_patterns_cmd(void)
break;
pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
- ignore_list = strbuf_split_max(&confirm, ' ', 0);
- for (i = 0; ignore_list[i]; i++) {
- strbuf_trim(ignore_list[i]);
- if (!ignore_list[i]->len)
- continue;
+ string_list_split_in_place_f(&ignore_list, confirm.buf, " ", -1,
+ STRING_LIST_SPLIT_TRIM);
- add_pattern(ignore_list[i]->buf, "", 0, pl, -(i+1));
+ for (i = 0; i < ignore_list.nr; i++) {
+ item = &ignore_list.items[i];
+ if (!*item->string)
+ continue;
+ add_pattern(item->string, "", 0, pl, -(i+1));
}
changed = 0;
@@ -729,7 +728,7 @@ static int filter_by_patterns_cmd(void)
clean_print_color(CLEAN_COLOR_RESET);
}
- strbuf_list_free(ignore_list);
+ string_list_clear(&ignore_list, 0);
dir_clear(&dir);
}
@@ -949,7 +948,7 @@ int cmd_clean(int argc,
OPT_END()
};
- git_config(git_clean_config, NULL);
+ repo_config(the_repository, git_clean_config, NULL);
argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
0);
diff --git a/builtin/clone.c b/builtin/clone.c
index 91b9cd0d16..c990f398ef 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -25,7 +25,7 @@
#include "refs.h"
#include "refspec.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
@@ -171,7 +171,7 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
} else {
struct strbuf sb = STRBUF_INIT;
strbuf_addf(&sb, "%s/objects", ref_git);
- add_to_alternates_file(sb.buf);
+ odb_add_to_alternates_file(the_repository->objects, sb.buf);
strbuf_release(&sb);
}
@@ -212,12 +212,14 @@ static void copy_alternates(struct strbuf *src, const char *src_repo)
if (!line.len || line.buf[0] == '#')
continue;
if (is_absolute_path(line.buf)) {
- add_to_alternates_file(line.buf);
+ odb_add_to_alternates_file(the_repository->objects,
+ line.buf);
continue;
}
abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf);
if (!normalize_path_copy(abs_path, abs_path))
- add_to_alternates_file(abs_path);
+ odb_add_to_alternates_file(the_repository->objects,
+ abs_path);
else
warning("skipping invalid relative alternate: %s/%s",
src_repo, line.buf);
@@ -352,7 +354,7 @@ static void clone_local(const char *src_repo, const char *dest_repo)
struct strbuf alt = STRBUF_INIT;
get_common_dir(&alt, src_repo);
strbuf_addstr(&alt, "/objects");
- add_to_alternates_file(alt.buf);
+ odb_add_to_alternates_file(the_repository->objects, alt.buf);
strbuf_release(&alt);
} else {
struct strbuf src = STRBUF_INIT;
@@ -504,7 +506,7 @@ static void write_followtags(const struct ref *refs, const char *msg)
continue;
if (ends_with(ref->name, "^{}"))
continue;
- if (!has_object(the_repository, &ref->old_oid, 0))
+ if (!odb_has_object(the_repository->objects, &ref->old_oid, 0))
continue;
refs_update_ref(get_main_ref_store(the_repository), msg,
ref->name, &ref->old_oid, NULL, 0,
@@ -760,16 +762,16 @@ static int write_one_config(const char *key, const char *value,
{
/*
* give git_clone_config a chance to write config values back to the
- * environment, since git_config_set_multivar_gently only deals with
+ * environment, since repo_config_set_multivar_gently only deals with
* config-file writes
*/
int apply_failed = git_clone_config(key, value, ctx, data);
if (apply_failed)
return apply_failed;
- return git_config_set_multivar_gently(key,
- value ? value : "true",
- CONFIG_REGEX_NONE, 0);
+ return repo_config_set_multivar_gently(the_repository, key,
+ value ? value : "true",
+ CONFIG_REGEX_NONE, 0);
}
static void write_config(struct string_list *config)
@@ -820,12 +822,12 @@ static void write_refspec_config(const char *src_ref_prefix,
/* Configure the remote */
if (value.len) {
strbuf_addf(&key, "remote.%s.fetch", remote_name);
- git_config_set_multivar(key.buf, value.buf, "^$", 0);
+ repo_config_set_multivar(the_repository, key.buf, value.buf, "^$", 0);
strbuf_reset(&key);
if (option_mirror) {
strbuf_addf(&key, "remote.%s.mirror", remote_name);
- git_config_set(key.buf, "true");
+ repo_config_set(the_repository, key.buf, "true");
strbuf_reset(&key);
}
}
@@ -999,7 +1001,7 @@ int cmd_clone(int argc,
packet_trace_identity("clone");
- git_config(git_clone_config, NULL);
+ repo_config(the_repository, git_clone_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_clone_options,
builtin_clone_usage, 0);
@@ -1148,7 +1150,7 @@ int cmd_clone(int argc,
strbuf_reset(&sb);
}
- if (!git_config_get_bool("submodule.stickyRecursiveClone", &val) &&
+ if (!repo_config_get_bool(the_repository, "submodule.stickyRecursiveClone", &val) &&
val)
string_list_append(&option_config, "submodule.recurse=true");
@@ -1240,7 +1242,7 @@ int cmd_clone(int argc,
* re-read config after init_db and write_config to pick up any config
* injected by --template and --config, respectively.
*/
- git_config(git_clone_config, NULL);
+ repo_config(the_repository, git_clone_config, NULL);
/*
* If option_reject_shallow is specified from CLI option,
@@ -1292,18 +1294,18 @@ int cmd_clone(int argc,
src_ref_prefix = "refs/";
strbuf_addstr(&branch_top, src_ref_prefix);
- git_config_set("core.bare", "true");
+ repo_config_set(the_repository, "core.bare", "true");
} else if (!option_rev) {
strbuf_addf(&branch_top, "refs/remotes/%s/", remote_name);
}
strbuf_addf(&key, "remote.%s.url", remote_name);
- git_config_set(key.buf, repo);
+ repo_config_set(the_repository, key.buf, repo);
strbuf_reset(&key);
if (!option_tags) {
strbuf_addf(&key, "remote.%s.tagOpt", remote_name);
- git_config_set(key.buf, "--no-tags");
+ repo_config_set(the_repository, key.buf, "--no-tags");
strbuf_reset(&key);
}
@@ -1465,7 +1467,7 @@ int cmd_clone(int argc,
warning(_("failed to fetch objects from bundle URI '%s'"),
bundle_uri);
else if (has_heuristic)
- git_config_set_gently("fetch.bundleuri", bundle_uri);
+ repo_config_set_gently(the_repository, "fetch.bundleuri", bundle_uri);
remote_state_clear(the_repository->remote_state);
free(the_repository->remote_state);
diff --git a/builtin/column.c b/builtin/column.c
index ce6443d5fa..87dce3c6e5 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -42,9 +42,9 @@ int cmd_column(int argc,
/* This one is special and must be the first one */
if (argc > 1 && starts_with(argv[1], "--command=")) {
command = argv[1] + 10;
- git_config(column_config, (void *)command);
+ repo_config(the_repository, column_config, (void *)command);
} else
- git_config(column_config, NULL);
+ repo_config(the_repository, column_config, NULL);
memset(&copts, 0, sizeof(copts));
copts.padding = 1;
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index a783a86e79..4992ac146e 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -2,11 +2,12 @@
#include "builtin.h"
#include "commit.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "parse-options.h"
#include "commit-graph.h"
-#include "object-store.h"
+#include "odb.h"
#include "progress.h"
#include "replace-object.h"
#include "strbuf.h"
@@ -66,7 +67,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
struct commit_graph *graph = NULL;
- struct object_directory *odb = NULL;
+ struct odb_source *source = NULL;
char *graph_name;
char *chain_name;
enum { OPENED_NONE, OPENED_GRAPH, OPENED_CHAIN } opened = OPENED_NONE;
@@ -101,9 +102,9 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
if (opts.progress)
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
- odb = find_odb(the_repository, opts.obj_dir);
- graph_name = get_commit_graph_filename(odb);
- chain_name = get_commit_graph_chain_filename(odb);
+ source = odb_find_source(the_repository->objects, opts.obj_dir);
+ graph_name = get_commit_graph_filename(source);
+ chain_name = get_commit_graph_chain_filename(source);
if (open_commit_graph(graph_name, &fd, &st))
opened = OPENED_GRAPH;
else if (errno != ENOENT)
@@ -120,7 +121,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
if (opened == OPENED_NONE)
return 0;
else if (opened == OPENED_GRAPH)
- graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
+ graph = load_commit_graph_one_fd_st(the_repository, fd, &st, source);
else
graph = load_commit_graph_chain_fd_st(the_repository, fd, &st,
&incomplete_chain);
@@ -221,7 +222,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
struct string_list pack_indexes = STRING_LIST_INIT_DUP;
struct strbuf buf = STRBUF_INIT;
struct oidset commits = OIDSET_INIT;
- struct object_directory *odb = NULL;
+ struct odb_source *source = NULL;
int result = 0;
enum commit_graph_write_flags flags = 0;
struct progress *progress = NULL;
@@ -265,7 +266,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
trace2_cmd_mode("write");
- git_config(git_commit_graph_write_config, &opts);
+ repo_config(the_repository, git_commit_graph_write_config, &opts);
argc = parse_options(argc, argv, prefix,
options,
@@ -289,10 +290,10 @@ static int graph_write(int argc, const char **argv, const char *prefix,
git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))
flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS;
- odb = find_odb(the_repository, opts.obj_dir);
+ source = odb_find_source(the_repository->objects, opts.obj_dir);
if (opts.reachable) {
- if (write_commit_graph_reachable(odb, flags, &write_opts))
+ if (write_commit_graph_reachable(source, flags, &write_opts))
result = 1;
goto cleanup;
}
@@ -311,6 +312,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
while (strbuf_getline(&buf, stdin) != EOF) {
if (read_one_commit(&commits, progress, buf.buf)) {
result = 1;
+ stop_progress(&progress);
goto cleanup;
}
}
@@ -318,7 +320,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
stop_progress(&progress);
}
- if (write_commit_graph(odb,
+ if (write_commit_graph(source,
opts.stdin_packs ? &pack_indexes : NULL,
opts.stdin_commits ? &commits : NULL,
flags,
@@ -346,7 +348,7 @@ int cmd_commit_graph(int argc,
};
struct option *options = parse_options_concat(builtin_commit_graph_options, common_opts);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
disable_replace_refs();
save_commit_buffer = 0;
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index ad6b2c9320..5189e685a7 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -6,10 +6,11 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "commit.h"
#include "parse-options.h"
@@ -48,7 +49,7 @@ static int parse_parent_arg_callback(const struct option *opt,
if (repo_get_oid_commit(the_repository, arg, &oid))
die(_("not a valid object name %s"), arg);
- assert_oid_type(&oid, OBJ_COMMIT);
+ odb_assert_oid_type(the_repository->objects, &oid, OBJ_COMMIT);
new_parent(lookup_commit(the_repository, &oid), parents);
return 0;
}
@@ -125,7 +126,7 @@ int cmd_commit_tree(int argc,
};
int ret;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
show_usage_with_options_if_asked(argc, argv,
commit_tree_usage, options);
diff --git a/builtin/commit.c b/builtin/commit.c
index fba0dded64..b5b9608813 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -19,6 +19,7 @@
#include "environment.h"
#include "diff.h"
#include "commit.h"
+#include "add-interactive.h"
#include "gettext.h"
#include "revision.h"
#include "wt-status.h"
@@ -122,6 +123,7 @@ static const char *edit_message, *use_message;
static char *fixup_message, *fixup_commit, *squash_message;
static const char *fixup_prefix;
static int all, also, interactive, patch_interactive, only, amend, signoff;
+static struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
static int edit_flag = -1; /* unspecified */
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
static int config_commit_verbose = -1; /* unspecified */
@@ -207,9 +209,9 @@ static void status_init_config(struct wt_status *s, config_fn_t fn)
{
wt_status_prepare(the_repository, s);
init_diff_ui_defaults();
- git_config(fn, s);
+ repo_config(the_repository, fn, s);
determine_whence(s);
- s->hints = advice_enabled(ADVICE_STATUS_HINTS); /* must come after git_config() */
+ s->hints = advice_enabled(ADVICE_STATUS_HINTS); /* must come after repo_config() */
}
static void rollback_index_files(void)
@@ -354,6 +356,11 @@ static const char *prepare_index(const char **argv, const char *prefix,
const char *ret;
char *path = NULL;
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
if (is_status)
refresh_flags |= REFRESH_UNMERGED;
parse_pathspec(&pathspec, 0,
@@ -400,7 +407,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
- if (interactive_add(the_repository, argv, prefix, patch_interactive) != 0)
+ if (interactive_add(the_repository, argv, prefix, patch_interactive, &add_p_opt) != 0)
die(_("interactive add failed"));
the_repository->index_file = old_repo_index_file;
@@ -424,6 +431,11 @@ static const char *prepare_index(const char **argv, const char *prefix,
commit_style = COMMIT_NORMAL;
ret = get_lock_file_path(&index_lock);
goto out;
+ } else {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--interactive/--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--interactive/--patch");
}
/*
@@ -688,6 +700,10 @@ static void adjust_comment_line_char(const struct strbuf *sb)
char candidates[] = "#;@!$%^&|:";
char *candidate;
const char *p;
+ size_t cutoff;
+
+ /* Ignore comment chars in trailing comments (e.g., Conflicts:) */
+ cutoff = sb->len - ignored_log_message_bytes(sb->buf, sb->len);
if (!memchr(sb->buf, candidates[0], sb->len)) {
free(comment_line_str_to_free);
@@ -700,7 +716,7 @@ static void adjust_comment_line_char(const struct strbuf *sb)
candidate = strchr(candidates, *p);
if (candidate)
*candidate = ' ';
- for (p = sb->buf; *p; p++) {
+ for (p = sb->buf; p + 1 < sb->buf + cutoff; p++) {
if ((p[0] == '\n' || p[0] == '\r') && p[1]) {
candidate = strchr(candidates, p[1]);
if (candidate)
@@ -1722,6 +1738,8 @@ int cmd_commit(int argc,
OPT_BOOL('i', "include", &also, N_("add specified files to index for commit")),
OPT_BOOL(0, "interactive", &interactive, N_("interactively add files")),
OPT_BOOL('p', "patch", &patch_interactive, N_("interactively add changes")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT_BOOL('o', "only", &only, N_("commit only specified files")),
OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit and commit-msg hooks")),
OPT_BOOL(0, "dry-run", &dry_run, N_("show what would be committed")),
diff --git a/builtin/config.c b/builtin/config.c
index f70d635477..59fb113b07 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -17,9 +17,9 @@
static const char *const builtin_config_usage[] = {
N_("git config list [<file-option>] [<display-option>] [--includes]"),
- N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
- N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
- N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
+ N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<pattern>] [--fixed-value] [--default=<default>] [--url=<url>] <name>"),
+ N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<pattern>] [--fixed-value] <name> <value>"),
+ N_("git config unset [<file-option>] [--all] [--value=<pattern>] [--fixed-value] <name>"),
N_("git config rename-section [<file-option>] <old-name> <new-name>"),
N_("git config remove-section [<file-option>] <name>"),
N_("git config edit [<file-option>]"),
@@ -33,17 +33,17 @@ static const char *const builtin_config_list_usage[] = {
};
static const char *const builtin_config_get_usage[] = {
- N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
+ N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<pattern>] [--fixed-value] [--default=<default>] <name>"),
NULL
};
static const char *const builtin_config_set_usage[] = {
- N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+ N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<pattern>] [--fixed-value] <name> <value>"),
NULL
};
static const char *const builtin_config_unset_usage[] = {
- N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
+ N_("git config unset [<file-option>] [--all] [--value=<pattern>] [--fixed-value] <name>"),
NULL
};
@@ -966,12 +966,12 @@ static int cmd_config_set(int argc, const char **argv, const char *prefix,
value = normalize_value(argv[0], argv[1], type, &default_kvi);
if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) {
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], value, value_pattern,
- comment, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], value, value_pattern,
+ comment, flags);
} else {
- ret = git_config_set_in_file_gently(location_opts.source.file,
- argv[0], comment, value);
+ ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], comment, value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
@@ -1010,12 +1010,12 @@ static int cmd_config_unset(int argc, const char **argv, const char *prefix,
check_write(&location_opts.source);
if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern)
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], NULL, value_pattern,
- NULL, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], NULL, value_pattern,
+ NULL, flags);
else
- ret = git_config_set_in_file_gently(location_opts.source.file, argv[0],
- NULL, NULL);
+ ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file, argv[0],
+ NULL, NULL);
location_options_release(&location_opts);
return ret;
@@ -1091,7 +1091,7 @@ static int show_editor(struct config_location_options *opts)
die(_("editing stdin is not supported"));
if (opts->source.blob)
die(_("editing blobs is not supported"));
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
config_file = opts->source.file ?
xstrdup(opts->source.file) :
repo_git_path(the_repository, "config");
@@ -1296,7 +1296,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
check_write(&location_opts.source);
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
- ret = git_config_set_in_file_gently(location_opts.source.file, argv[0], comment, value);
+ ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file, argv[0], comment, value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
@@ -1305,26 +1305,26 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
check_write(&location_opts.source);
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], value, argv[2],
- comment, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], value, argv[2],
+ comment, flags);
}
else if (actions == ACTION_ADD) {
check_write(&location_opts.source);
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], value,
- CONFIG_REGEX_NONE,
- comment, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], value,
+ CONFIG_REGEX_NONE,
+ comment, flags);
}
else if (actions == ACTION_REPLACE_ALL) {
check_write(&location_opts.source);
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], value, argv[2],
- comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], value, argv[2],
+ comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@@ -1350,19 +1350,19 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
check_write(&location_opts.source);
check_argc(argc, 1, 2);
if (argc == 2)
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], NULL, argv[1],
- NULL, flags);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], NULL, argv[1],
+ NULL, flags);
else
- ret = git_config_set_in_file_gently(location_opts.source.file,
- argv[0], NULL, NULL);
+ ret = repo_config_set_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], NULL, NULL);
}
else if (actions == ACTION_UNSET_ALL) {
check_write(&location_opts.source);
check_argc(argc, 1, 2);
- ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
- argv[0], NULL, argv[1],
- NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
+ ret = repo_config_set_multivar_in_file_gently(the_repository, location_opts.source.file,
+ argv[0], NULL, argv[1],
+ NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
check_write(&location_opts.source);
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index a88c0c9c09..a61d3b46aa 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -7,6 +7,7 @@
#include "builtin.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
#include "gettext.h"
#include "path.h"
#include "parse-options.h"
@@ -80,10 +81,10 @@ static int count_cruft(const char *basename UNUSED, const char *path,
return 0;
}
-static int print_alternate(struct object_directory *odb, void *data UNUSED)
+static int print_alternate(struct odb_source *alternate, void *data UNUSED)
{
printf("alternate: ");
- quote_c_style(odb->path, NULL, stdout, 0);
+ quote_c_style(alternate->path, NULL, stdout, 0);
putchar('\n');
return 0;
}
@@ -106,7 +107,7 @@ int cmd_count_objects(int argc,
OPT_END(),
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, count_objects_usage, 0);
/* we do not take arguments other than flags for now */
@@ -117,7 +118,7 @@ int cmd_count_objects(int argc,
report_linked_checkout_garbage(the_repository);
}
- for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+ for_each_loose_file_in_source(the_repository->objects->sources,
count_loose, count_cruft, NULL, NULL);
if (verbose) {
@@ -159,7 +160,7 @@ int cmd_count_objects(int argc,
printf("prune-packable: %lu\n", packed_loose);
printf("garbage: %lu\n", garbage);
printf("size-garbage: %s\n", garbage_buf.buf);
- foreach_alt_odb(print_alternate, NULL);
+ odb_for_each_alternate(the_repository->objects, print_alternate, NULL);
strbuf_release(&loose_buf);
strbuf_release(&pack_buf);
strbuf_release(&garbage_buf);
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 5065ff4660..65cc619bec 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -307,7 +307,7 @@ int cmd_credential_cache_daemon(int argc,
OPT_END()
};
- git_config_get_bool("credentialcache.ignoresighup", &ignore_sighup);
+ repo_config_get_bool(the_repository, "credentialcache.ignoresighup", &ignore_sighup);
argc = parse_options(argc, argv, prefix, options, usage, 0);
socket_path = argv[0];
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index e669e99dbf..b74e06cc93 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -66,7 +66,7 @@ static void rewrite_credential_file(const char *fn, struct credential *c,
{
int timeout_ms = 1000;
- git_config_get_int("credentialstore.locktimeoutms", &timeout_ms);
+ repo_config_get_int(the_repository, "credentialstore.locktimeoutms", &timeout_ms);
if (hold_lock_file_for_update_timeout(&credential_lock, fn, 0, timeout_ms) < 0)
die_errno(_("unable to get credential storage lock in %d ms"), timeout_ms);
if (extra)
diff --git a/builtin/credential.c b/builtin/credential.c
index 2e11b15dde..a295c80b36 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -3,6 +3,7 @@
#include "git-compat-util.h"
#include "credential.h"
#include "builtin.h"
+#include "environment.h"
#include "config.h"
static const char usage_msg[] =
@@ -16,7 +17,7 @@ int cmd_credential(int argc,
const char *op;
struct credential c = CREDENTIAL_INIT;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
show_usage_if_asked(argc, argv, usage_msg);
if (argc != 2)
diff --git a/builtin/describe.c b/builtin/describe.c
index 2d50883b72..0540976210 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -19,10 +19,11 @@
#include "setup.h"
#include "strvec.h"
#include "run-command.h"
-#include "object-store.h"
+#include "odb.h"
#include "list-objects.h"
#include "commit-slab.h"
#include "wildmatch.h"
+#include "prio-queue.h"
#define MAX_TAGS (FLAG_BITS - 1)
#define DEFAULT_CANDIDATES 10
@@ -249,24 +250,62 @@ static int compare_pt(const void *a_, const void *b_)
return 0;
}
-static unsigned long finish_depth_computation(
- struct commit_list **list,
- struct possible_tag *best)
+struct lazy_queue {
+ struct prio_queue queue;
+ bool get_pending;
+};
+
+#define LAZY_QUEUE_INIT { { compare_commits_by_commit_date }, false }
+
+static void *lazy_queue_get(struct lazy_queue *queue)
+{
+ if (queue->get_pending)
+ prio_queue_get(&queue->queue);
+ else
+ queue->get_pending = true;
+ return prio_queue_peek(&queue->queue);
+}
+
+static void lazy_queue_put(struct lazy_queue *queue, void *thing)
+{
+ if (queue->get_pending)
+ prio_queue_replace(&queue->queue, thing);
+ else
+ prio_queue_put(&queue->queue, thing);
+ queue->get_pending = false;
+}
+
+static bool lazy_queue_empty(const struct lazy_queue *queue)
+{
+ return queue->queue.nr == (queue->get_pending ? 1 : 0);
+}
+
+static void lazy_queue_clear(struct lazy_queue *queue)
+{
+ clear_prio_queue(&queue->queue);
+ queue->get_pending = false;
+}
+
+static bool all_have_flag(const struct lazy_queue *queue, unsigned flag)
+{
+ for (size_t i = queue->get_pending ? 1 : 0; i < queue->queue.nr; i++) {
+ struct commit *commit = queue->queue.array[i].data;
+ if (!(commit->object.flags & flag))
+ return false;
+ }
+ return true;
+}
+
+static unsigned long finish_depth_computation(struct lazy_queue *queue,
+ struct possible_tag *best)
{
unsigned long seen_commits = 0;
- while (*list) {
- struct commit *c = pop_commit(list);
+ while (!lazy_queue_empty(queue)) {
+ struct commit *c = lazy_queue_get(queue);
struct commit_list *parents = c->parents;
seen_commits++;
if (c->object.flags & best->flag_within) {
- struct commit_list *a = *list;
- while (a) {
- struct commit *i = a->item;
- if (!(i->object.flags & best->flag_within))
- break;
- a = a->next;
- }
- if (!a)
+ if (all_have_flag(queue, best->flag_within))
break;
} else
best->depth++;
@@ -274,7 +313,7 @@ static unsigned long finish_depth_computation(
struct commit *p = parents->item;
repo_parse_commit(the_repository, p);
if (!(p->object.flags & SEEN))
- commit_list_insert_by_date(p, list);
+ lazy_queue_put(queue, p);
p->object.flags |= c->object.flags;
parents = parents->next;
}
@@ -316,7 +355,7 @@ static void append_suffix(int depth, const struct object_id *oid, struct strbuf
static void describe_commit(struct object_id *oid, struct strbuf *dst)
{
struct commit *cmit, *gave_up_on = NULL;
- struct commit_list *list;
+ struct lazy_queue queue = LAZY_QUEUE_INIT;
struct commit_name *n;
struct possible_tag all_matches[MAX_TAGS];
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
@@ -359,11 +398,10 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
have_util = 1;
}
- list = NULL;
cmit->object.flags = SEEN;
- commit_list_insert(cmit, &list);
- while (list) {
- struct commit *c = pop_commit(&list);
+ lazy_queue_put(&queue, cmit);
+ while (!lazy_queue_empty(&queue)) {
+ struct commit *c = lazy_queue_get(&queue);
struct commit_list *parents = c->parents;
struct commit_name **slot;
@@ -397,7 +435,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
t->depth++;
}
/* Stop if last remaining path already covered by best candidate(s) */
- if (annotated_cnt && !list) {
+ if (annotated_cnt && lazy_queue_empty(&queue)) {
int best_depth = INT_MAX;
unsigned best_within = 0;
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
@@ -420,7 +458,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
struct commit *p = parents->item;
repo_parse_commit(the_repository, p);
if (!(p->object.flags & SEEN))
- commit_list_insert_by_date(p, &list);
+ lazy_queue_put(&queue, p);
p->object.flags |= c->object.flags;
parents = parents->next;
@@ -435,6 +473,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
strbuf_add_unique_abbrev(dst, cmit_oid, abbrev);
if (suffix)
strbuf_addstr(dst, suffix);
+ lazy_queue_clear(&queue);
return;
}
if (unannotated_cnt)
@@ -450,11 +489,11 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
QSORT(all_matches, match_cnt, compare_pt);
if (gave_up_on) {
- commit_list_insert_by_date(gave_up_on, &list);
+ lazy_queue_put(&queue, gave_up_on);
seen_commits--;
}
- seen_commits += finish_depth_computation(&list, &all_matches[0]);
- free_commit_list(list);
+ seen_commits += finish_depth_computation(&queue, &all_matches[0]);
+ lazy_queue_clear(&queue);
if (debug) {
static int label_width = -1;
@@ -552,7 +591,8 @@ static void describe(const char *arg, int last_one)
if (cmit)
describe_commit(&oid, &sb);
- else if (oid_object_info(the_repository, &oid, NULL) == OBJ_BLOB)
+ else if (odb_read_object_info(the_repository->objects,
+ &oid, NULL) == OBJ_BLOB)
describe_blob(oid, &sb);
else
die(_("%s is neither a commit nor blob"), arg);
@@ -622,7 +662,7 @@ int cmd_describe(int argc,
OPT_END(),
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
if (abbrev < 0)
abbrev = DEFAULT_ABBREV;
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 99b1749723..ea91347ce2 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -31,7 +31,7 @@ int cmd_diff_files(int argc,
show_usage_if_asked(argc, argv, diff_files_usage);
- git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+ repo_config(the_repository, git_diff_basic_config, NULL); /* no "diff" UI options */
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index 81c0bc8ed7..522dacfc4c 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -28,7 +28,7 @@ int cmd_diff_index(int argc,
show_usage_if_asked(argc, argv, diff_cache_usage);
- git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+ repo_config(the_repository, git_diff_basic_config, NULL); /* no "diff" UI options */
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index e31cc797fe..49dd4d00eb 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -124,7 +124,7 @@ int cmd_diff_tree(int argc,
show_usage_if_asked(argc, argv, diff_tree_usage);
- git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+ repo_config(the_repository, git_diff_basic_config, NULL); /* no "diff" UI options */
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/diff.c b/builtin/diff.c
index fa963808c3..9a89e25a98 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -35,7 +35,7 @@ static const char builtin_diff_usage[] =
" or: git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]\n"
" or: git diff [<options>] <commit>...<commit> [--] [<path>...]\n"
" or: git diff [<options>] <blob> <blob>\n"
-" or: git diff [<options>] --no-index [--] <path> <path>"
+" or: git diff [<options>] --no-index [--] <path> <path> [<pathspec>...]"
"\n"
COMMON_DIFF_OPTIONS_HELP;
@@ -483,10 +483,10 @@ int cmd_diff(int argc,
* configurable via a command line option.
*/
if (nongit)
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+ repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
init_diff_ui_defaults();
- git_config(git_diff_ui_config, NULL);
+ repo_config(the_repository, git_diff_ui_config, NULL);
prefix = precompose_argv_prefix(argc, argv, prefix);
repo_init_revisions(the_repository, &rev, prefix);
diff --git a/builtin/difftool.c b/builtin/difftool.c
index a3b64ce694..e4bc1f8316 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -30,7 +30,7 @@
#include "strbuf.h"
#include "lockfile.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
#include "dir.h"
#include "entry.h"
#include "setup.h"
@@ -320,7 +320,7 @@ static char *get_symlink(struct repository *repo,
} else {
enum object_type type;
unsigned long size;
- data = repo_read_object_file(repo, oid, &type, &size);
+ data = odb_read_object(repo->objects, oid, &type, &size);
if (!data)
die(_("could not read object %s for symlink %s"),
oid_to_hex(oid), path);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index fcf6b00d5f..c06ee0b213 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -9,12 +9,13 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "refs.h"
#include "refspec.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
#include "commit.h"
#include "object.h"
#include "tag.h"
@@ -29,6 +30,7 @@
#include "quote.h"
#include "remote.h"
#include "blob.h"
+#include "gpg-interface.h"
static const char *const fast_export_usage[] = {
N_("git fast-export [<rev-list-opts>]"),
@@ -323,7 +325,7 @@ static void export_blob(const struct object_id *oid)
object = (struct object *)lookup_blob(the_repository, oid);
eaten = 0;
} else {
- buf = repo_read_object_file(the_repository, oid, &type, &size);
+ buf = odb_read_object(the_repository->objects, oid, &type, &size);
if (!buf)
die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(the_repository, oid, buf, size,
@@ -652,6 +654,38 @@ static const char *find_commit_multiline_header(const char *msg,
return strbuf_detach(&val, NULL);
}
+static void print_signature(const char *signature, const char *object_hash)
+{
+ if (!signature)
+ return;
+
+ printf("gpgsig %s %s\ndata %u\n%s\n",
+ object_hash,
+ get_signature_format(signature),
+ (unsigned)strlen(signature),
+ signature);
+}
+
+static const char *append_signatures_for_header(struct string_list *signatures,
+ const char *pos,
+ const char *header,
+ const char *object_hash)
+{
+ const char *signature;
+ const char *start = pos;
+ const char *end = pos;
+
+ while ((signature = find_commit_multiline_header(start + 1,
+ header,
+ &end))) {
+ string_list_append(signatures, signature)->util = (void *)object_hash;
+ free((char *)signature);
+ start = end;
+ }
+
+ return end;
+}
+
static void handle_commit(struct commit *commit, struct rev_info *rev,
struct string_list *paths_of_changed_objects)
{
@@ -660,7 +694,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
const char *author, *author_end, *committer, *committer_end;
const char *encoding = NULL;
size_t encoding_len;
- const char *signature_alg = NULL, *signature = NULL;
+ struct string_list signatures = STRING_LIST_INIT_DUP;
const char *message;
char *reencoded = NULL;
struct commit_list *p;
@@ -700,10 +734,11 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
}
if (*commit_buffer_cursor == '\n') {
- if ((signature = find_commit_multiline_header(commit_buffer_cursor + 1, "gpgsig", &commit_buffer_cursor)))
- signature_alg = "sha1";
- else if ((signature = find_commit_multiline_header(commit_buffer_cursor + 1, "gpgsig-sha256", &commit_buffer_cursor)))
- signature_alg = "sha256";
+ const char *after_sha1 = append_signatures_for_header(&signatures, commit_buffer_cursor,
+ "gpgsig", "sha1");
+ const char *after_sha256 = append_signatures_for_header(&signatures, commit_buffer_cursor,
+ "gpgsig-sha256", "sha256");
+ commit_buffer_cursor = (after_sha1 > after_sha256) ? after_sha1 : after_sha256;
}
message = strstr(commit_buffer_cursor, "\n\n");
@@ -769,30 +804,30 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
printf("%.*s\n%.*s\n",
(int)(author_end - author), author,
(int)(committer_end - committer), committer);
- if (signature) {
+ if (signatures.nr) {
switch (signed_commit_mode) {
case SIGN_ABORT:
die("encountered signed commit %s; use "
"--signed-commits=<mode> to handle it",
oid_to_hex(&commit->object.oid));
case SIGN_WARN_VERBATIM:
- warning("exporting signed commit %s",
- oid_to_hex(&commit->object.oid));
+ warning("exporting %"PRIuMAX" signature(s) for commit %s",
+ (uintmax_t)signatures.nr, oid_to_hex(&commit->object.oid));
/* fallthru */
case SIGN_VERBATIM:
- printf("gpgsig %s\ndata %u\n%s",
- signature_alg,
- (unsigned)strlen(signature),
- signature);
+ for (size_t i = 0; i < signatures.nr; i++) {
+ struct string_list_item *item = &signatures.items[i];
+ print_signature(item->string, item->util);
+ }
break;
case SIGN_WARN_STRIP:
- warning("stripping signature from commit %s",
+ warning("stripping signature(s) from commit %s",
oid_to_hex(&commit->object.oid));
/* fallthru */
case SIGN_STRIP:
break;
}
- free((char *)signature);
+ string_list_clear(&signatures, 0);
}
if (!reencoded && encoding)
printf("encoding %.*s\n", (int)encoding_len, encoding);
@@ -869,8 +904,8 @@ static void handle_tag(const char *name, struct tag *tag)
return;
}
- buf = repo_read_object_file(the_repository, &tag->object.oid, &type,
- &size);
+ buf = odb_read_object(the_repository->objects, &tag->object.oid,
+ &type, &size);
if (!buf)
die("could not read tag %s", oid_to_hex(&tag->object.oid));
message = memmem(buf, size, "\n\n", 2);
@@ -1200,7 +1235,7 @@ static void import_marks(char *input_file, int check_exists)
if (last_idnum < mark)
last_idnum = mark;
- type = oid_object_info(the_repository, &oid, NULL);
+ type = odb_read_object_info(the_repository->objects, &oid, NULL);
if (type < 0)
die("object not found: %s", oid_to_hex(&oid));
@@ -1327,7 +1362,7 @@ int cmd_fast_export(int argc,
usage_with_options (fast_export_usage, options);
/* we handle encodings */
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
repo_init_revisions(the_repository, &revs, prefix);
init_revision_sources(&revision_sources);
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index b2839c5f43..2c35f9345d 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -24,11 +24,12 @@
#include "packfile.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "mem-pool.h"
#include "commit-reach.h"
#include "khash.h"
#include "date.h"
+#include "gpg-interface.h"
#define PACK_ID_BITS 16
#define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
@@ -763,7 +764,8 @@ static void start_packfile(void)
struct packed_git *p;
int pack_fd;
- pack_fd = odb_mkstemp(&tmp_file, "pack/tmp_pack_XXXXXX");
+ pack_fd = odb_mkstemp(the_repository->objects, &tmp_file,
+ "pack/tmp_pack_XXXXXX");
FLEX_ALLOC_STR(p, pack_name, tmp_file.buf);
strbuf_release(&tmp_file);
@@ -820,11 +822,11 @@ static char *keep_pack(const char *curr_index_name)
die_errno("failed to write keep file");
odb_pack_name(pack_data->repo, &name, pack_data->hash, "pack");
- if (finalize_object_file(pack_data->pack_name, name.buf))
+ if (finalize_object_file(pack_data->repo, pack_data->pack_name, name.buf))
die("cannot store pack file");
odb_pack_name(pack_data->repo, &name, pack_data->hash, "idx");
- if (finalize_object_file(curr_index_name, name.buf))
+ if (finalize_object_file(pack_data->repo, curr_index_name, name.buf))
die("cannot store index file");
free((void *)curr_index_name);
return strbuf_detach(&name, NULL);
@@ -1264,7 +1266,7 @@ static void load_tree(struct tree_entry *root)
die("Can't load tree %s", oid_to_hex(oid));
} else {
enum object_type type;
- buf = repo_read_object_file(the_repository, oid, &type, &size);
+ buf = odb_read_object(the_repository->objects, oid, &type, &size);
if (!buf || type != OBJ_TREE)
die("Can't load tree %s", oid_to_hex(oid));
}
@@ -1755,8 +1757,8 @@ static void insert_object_entry(struct mark_set **s, struct object_id *oid, uint
struct object_entry *e;
e = find_object(oid);
if (!e) {
- enum object_type type = oid_object_info(the_repository,
- oid, NULL);
+ enum object_type type = odb_read_object_info(the_repository->objects,
+ oid, NULL);
if (type < 0)
die("object not found: %s", oid_to_hex(oid));
e = insert_object(oid);
@@ -2415,8 +2417,8 @@ static void file_change_m(const char *p, struct branch *b)
enum object_type expected = S_ISDIR(mode) ?
OBJ_TREE: OBJ_BLOB;
enum object_type type = oe ? oe->type :
- oid_object_info(the_repository, &oid,
- NULL);
+ odb_read_object_info(the_repository->objects,
+ &oid, NULL);
if (type < 0)
die("%s not found: %s",
S_ISDIR(mode) ? "Tree" : "Blob",
@@ -2534,10 +2536,9 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
oidcpy(&commit_oid, &commit_oe->idx.oid);
} else if (!repo_get_oid(the_repository, p, &commit_oid)) {
unsigned long size;
- char *buf = read_object_with_reference(the_repository,
- &commit_oid,
- OBJ_COMMIT, &size,
- &commit_oid);
+ char *buf = odb_read_object_peeled(the_repository->objects,
+ &commit_oid, OBJ_COMMIT, &size,
+ &commit_oid);
if (!buf || size < the_hash_algo->hexsz + 6)
die("Not a valid commit: %s", p);
free(buf);
@@ -2552,7 +2553,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
die("Not a blob (actually a %s): %s",
type_name(oe->type), command_buf.buf);
} else if (!is_null_oid(&oid)) {
- enum object_type type = oid_object_info(the_repository, &oid,
+ enum object_type type = odb_read_object_info(the_repository->objects, &oid,
NULL);
if (type < 0)
die("Blob not found: %s", command_buf.buf);
@@ -2603,9 +2604,8 @@ static void parse_from_existing(struct branch *b)
unsigned long size;
char *buf;
- buf = read_object_with_reference(the_repository,
- &b->oid, OBJ_COMMIT, &size,
- &b->oid);
+ buf = odb_read_object_peeled(the_repository->objects, &b->oid,
+ OBJ_COMMIT, &size, &b->oid);
parse_from_commit(b, buf, size);
free(buf);
}
@@ -2698,10 +2698,9 @@ static struct hash_list *parse_merge(unsigned int *count)
oidcpy(&n->oid, &oe->idx.oid);
} else if (!repo_get_oid(the_repository, from, &n->oid)) {
unsigned long size;
- char *buf = read_object_with_reference(the_repository,
- &n->oid,
- OBJ_COMMIT,
- &size, &n->oid);
+ char *buf = odb_read_object_peeled(the_repository->objects,
+ &n->oid, OBJ_COMMIT,
+ &size, &n->oid);
if (!buf || size < the_hash_algo->hexsz + 6)
die("Not a valid commit: %s", from);
free(buf);
@@ -2718,15 +2717,82 @@ static struct hash_list *parse_merge(unsigned int *count)
return list;
}
+struct signature_data {
+ char *hash_algo; /* "sha1" or "sha256" */
+ char *sig_format; /* "openpgp", "x509", "ssh", or "unknown" */
+ struct strbuf data; /* The actual signature data */
+};
+
+static void parse_one_signature(struct signature_data *sig, const char *v)
+{
+ char *args = xstrdup(v); /* Will be freed when sig->hash_algo is freed */
+ char *space = strchr(args, ' ');
+
+ if (!space)
+ die("Expected gpgsig format: 'gpgsig <hash-algo> <signature-format>', "
+ "got 'gpgsig %s'", args);
+ *space = '\0';
+
+ sig->hash_algo = args;
+ sig->sig_format = space + 1;
+
+ /* Validate hash algorithm */
+ if (strcmp(sig->hash_algo, "sha1") &&
+ strcmp(sig->hash_algo, "sha256"))
+ die("Unknown git hash algorithm in gpgsig: '%s'", sig->hash_algo);
+
+ /* Validate signature format */
+ if (!valid_signature_format(sig->sig_format))
+ die("Invalid signature format in gpgsig: '%s'", sig->sig_format);
+ if (!strcmp(sig->sig_format, "unknown"))
+ warning("'unknown' signature format in gpgsig");
+
+ /* Read signature data */
+ read_next_command();
+ parse_data(&sig->data, 0, NULL);
+}
+
+static void add_gpgsig_to_commit(struct strbuf *commit_data,
+ const char *header,
+ struct signature_data *sig)
+{
+ struct string_list siglines = STRING_LIST_INIT_NODUP;
+
+ if (!sig->hash_algo)
+ return;
+
+ strbuf_addstr(commit_data, header);
+ string_list_split_in_place(&siglines, sig->data.buf, "\n", -1);
+ strbuf_add_separated_string_list(commit_data, "\n ", &siglines);
+ strbuf_addch(commit_data, '\n');
+ string_list_clear(&siglines, 1);
+ strbuf_release(&sig->data);
+ free(sig->hash_algo);
+}
+
+static void store_signature(struct signature_data *stored_sig,
+ struct signature_data *new_sig,
+ const char *hash_type)
+{
+ if (stored_sig->hash_algo) {
+ warning("multiple %s signatures found, "
+ "ignoring additional signature",
+ hash_type);
+ strbuf_release(&new_sig->data);
+ free(new_sig->hash_algo);
+ } else {
+ *stored_sig = *new_sig;
+ }
+}
+
static void parse_new_commit(const char *arg)
{
- static struct strbuf sig = STRBUF_INIT;
static struct strbuf msg = STRBUF_INIT;
- struct string_list siglines = STRING_LIST_INIT_NODUP;
+ struct signature_data sig_sha1 = { NULL, NULL, STRBUF_INIT };
+ struct signature_data sig_sha256 = { NULL, NULL, STRBUF_INIT };
struct branch *b;
char *author = NULL;
char *committer = NULL;
- char *sig_alg = NULL;
char *encoding = NULL;
struct hash_list *merge_list = NULL;
unsigned int merge_count;
@@ -2750,13 +2816,23 @@ static void parse_new_commit(const char *arg)
}
if (!committer)
die("Expected committer but didn't get one");
- if (skip_prefix(command_buf.buf, "gpgsig ", &v)) {
- sig_alg = xstrdup(v);
- read_next_command();
- parse_data(&sig, 0, NULL);
+
+ /* Process signatures (up to 2: one "sha1" and one "sha256") */
+ while (skip_prefix(command_buf.buf, "gpgsig ", &v)) {
+ struct signature_data sig = { NULL, NULL, STRBUF_INIT };
+
+ parse_one_signature(&sig, v);
+
+ if (!strcmp(sig.hash_algo, "sha1"))
+ store_signature(&sig_sha1, &sig, "SHA-1");
+ else if (!strcmp(sig.hash_algo, "sha256"))
+ store_signature(&sig_sha256, &sig, "SHA-256");
+ else
+ BUG("parse_one_signature() returned unknown hash algo");
+
read_next_command();
- } else
- strbuf_setlen(&sig, 0);
+ }
+
if (skip_prefix(command_buf.buf, "encoding ", &v)) {
encoding = xstrdup(v);
read_next_command();
@@ -2830,23 +2906,14 @@ static void parse_new_commit(const char *arg)
strbuf_addf(&new_data,
"encoding %s\n",
encoding);
- if (sig_alg) {
- if (!strcmp(sig_alg, "sha1"))
- strbuf_addstr(&new_data, "gpgsig ");
- else if (!strcmp(sig_alg, "sha256"))
- strbuf_addstr(&new_data, "gpgsig-sha256 ");
- else
- die("Expected gpgsig algorithm sha1 or sha256, got %s", sig_alg);
- string_list_split_in_place(&siglines, sig.buf, "\n", -1);
- strbuf_add_separated_string_list(&new_data, "\n ", &siglines);
- strbuf_addch(&new_data, '\n');
- }
+
+ add_gpgsig_to_commit(&new_data, "gpgsig ", &sig_sha1);
+ add_gpgsig_to_commit(&new_data, "gpgsig-sha256 ", &sig_sha256);
+
strbuf_addch(&new_data, '\n');
strbuf_addbuf(&new_data, &msg);
- string_list_clear(&siglines, 1);
free(author);
free(committer);
- free(sig_alg);
free(encoding);
if (!store_object(OBJ_COMMIT, &new_data, NULL, &b->oid, next_mark))
@@ -2894,7 +2961,8 @@ static void parse_new_tag(const char *arg)
} else if (!repo_get_oid(the_repository, from, &oid)) {
struct object_entry *oe = find_object(&oid);
if (!oe) {
- type = oid_object_info(the_repository, &oid, NULL);
+ type = odb_read_object_info(the_repository->objects,
+ &oid, NULL);
if (type < 0)
die("Not a valid object: %s", from);
} else
@@ -3000,7 +3068,7 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)
char *buf;
if (!oe || oe->pack_id == MAX_PACK_ID) {
- buf = repo_read_object_file(the_repository, oid, &type, &size);
+ buf = odb_read_object(the_repository->objects, oid, &type, &size);
} else {
type = oe->type;
buf = gfi_unpack_entry(oe, &size);
@@ -3084,8 +3152,8 @@ static struct object_entry *dereference(struct object_entry *oe,
const unsigned hexsz = the_hash_algo->hexsz;
if (!oe) {
- enum object_type type = oid_object_info(the_repository, oid,
- NULL);
+ enum object_type type = odb_read_object_info(the_repository->objects,
+ oid, NULL);
if (type < 0)
die("object not found: %s", oid_to_hex(oid));
/* cache it! */
@@ -3108,8 +3176,8 @@ static struct object_entry *dereference(struct object_entry *oe,
buf = gfi_unpack_entry(oe, &size);
} else {
enum object_type unused;
- buf = repo_read_object_file(the_repository, oid, &unused,
- &size);
+ buf = odb_read_object(the_repository->objects, oid,
+ &unused, &size);
}
if (!buf)
die("Can't load object %s", oid_to_hex(oid));
@@ -3524,25 +3592,25 @@ static void git_pack_config(void)
int limit;
unsigned long packsizelimit_value;
- if (!git_config_get_ulong("pack.depth", &max_depth)) {
+ if (!repo_config_get_ulong(the_repository, "pack.depth", &max_depth)) {
if (max_depth > MAX_DEPTH)
max_depth = MAX_DEPTH;
}
- if (!git_config_get_int("pack.indexversion", &indexversion_value)) {
+ if (!repo_config_get_int(the_repository, "pack.indexversion", &indexversion_value)) {
pack_idx_opts.version = indexversion_value;
if (pack_idx_opts.version > 2)
git_die_config(the_repository, "pack.indexversion",
"bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
}
- if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
+ if (!repo_config_get_ulong(the_repository, "pack.packsizelimit", &packsizelimit_value))
max_packsize = packsizelimit_value;
- if (!git_config_get_int("fastimport.unpacklimit", &limit))
+ if (!repo_config_get_int(the_repository, "fastimport.unpacklimit", &limit))
unpack_limit = limit;
- else if (!git_config_get_int("transfer.unpacklimit", &limit))
+ else if (!repo_config_get_int(the_repository, "transfer.unpacklimit", &limit))
unpack_limit = limit;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
}
static const char fast_import_usage[] =
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index d07eec9e55..d9e42bad58 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -274,8 +274,10 @@ int cmd_fetch_pack(int argc,
}
close(fd[0]);
close(fd[1]);
- if (finish_connect(conn))
- return 1;
+ if (finish_connect(conn)) {
+ ret = 1;
+ goto cleanup;
+ }
ret = !fetched_refs;
@@ -291,6 +293,7 @@ int cmd_fetch_pack(int argc,
printf("%s %s\n",
oid_to_hex(&ref->old_oid), ref->name);
+cleanup:
for (size_t i = 0; i < nr_sought; i++)
free_one_ref(sought_to_free[i]);
free(sought_to_free);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 40a0e8d244..24645c4653 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -14,7 +14,7 @@
#include "refs.h"
#include "refspec.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "oidset.h"
#include "oid-array.h"
#include "commit.h"
@@ -366,9 +366,9 @@ static void find_non_local_tags(const struct ref *refs,
*/
if (ends_with(ref->name, "^{}")) {
if (item &&
- !has_object(the_repository, &ref->old_oid, 0) &&
+ !odb_has_object(the_repository->objects, &ref->old_oid, 0) &&
!oidset_contains(&fetch_oids, &ref->old_oid) &&
- !has_object(the_repository, &item->oid, 0) &&
+ !odb_has_object(the_repository->objects, &item->oid, 0) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
item = NULL;
@@ -382,7 +382,7 @@ static void find_non_local_tags(const struct ref *refs,
* fetch.
*/
if (item &&
- !has_object(the_repository, &item->oid, 0) &&
+ !odb_has_object(the_repository->objects, &item->oid, 0) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
@@ -403,7 +403,7 @@ static void find_non_local_tags(const struct ref *refs,
* checked to see if it needs fetching.
*/
if (item &&
- !has_object(the_repository, &item->oid, 0) &&
+ !odb_has_object(the_repository->objects, &item->oid, 0) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
@@ -640,9 +640,6 @@ static struct ref *get_ref_map(struct remote *remote,
return ref_map;
}
-#define STORE_REF_ERROR_OTHER 1
-#define STORE_REF_ERROR_DF_CONFLICT 2
-
static int s_update_ref(const char *action,
struct ref *ref,
struct ref_transaction *transaction,
@@ -650,7 +647,6 @@ static int s_update_ref(const char *action,
{
char *msg;
char *rla = getenv("GIT_REFLOG_ACTION");
- struct ref_transaction *our_transaction = NULL;
struct strbuf err = STRBUF_INIT;
int ret;
@@ -660,43 +656,10 @@ static int s_update_ref(const char *action,
rla = default_rla.buf;
msg = xstrfmt("%s: %s", rla, action);
- /*
- * If no transaction was passed to us, we manage the transaction
- * ourselves. Otherwise, we trust the caller to handle the transaction
- * lifecycle.
- */
- if (!transaction) {
- transaction = our_transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
- 0, &err);
- if (!transaction) {
- ret = STORE_REF_ERROR_OTHER;
- goto out;
- }
- }
-
ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
check_old ? &ref->old_oid : NULL,
NULL, NULL, 0, msg, &err);
- if (ret) {
- ret = STORE_REF_ERROR_OTHER;
- goto out;
- }
-
- if (our_transaction) {
- switch (ref_transaction_commit(our_transaction, &err)) {
- case 0:
- break;
- case REF_TRANSACTION_ERROR_NAME_CONFLICT:
- ret = STORE_REF_ERROR_DF_CONFLICT;
- goto out;
- default:
- ret = STORE_REF_ERROR_OTHER;
- goto out;
- }
- }
-out:
- ref_transaction_free(our_transaction);
if (ret)
error("%s", err.buf);
strbuf_release(&err);
@@ -910,8 +873,8 @@ static int update_local_ref(struct ref *ref,
struct commit *current = NULL, *updated;
int fast_forward = 0;
- if (!has_object(the_repository, &ref->new_oid,
- HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
+ if (!odb_has_object(the_repository->objects, &ref->new_oid,
+ HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
die(_("object %s not found"), oid_to_hex(&ref->new_oid));
if (oideq(&ref->old_oid, &ref->new_oid)) {
@@ -992,7 +955,7 @@ static int update_local_ref(struct ref *ref,
fast_forward = repo_in_merge_bases(the_repository, current,
updated);
if (fast_forward < 0)
- exit(128);
+ die(NULL);
forced_updates_ms += (getnanotime() - t_before) / 1000000;
} else {
fast_forward = 1;
@@ -1139,7 +1102,6 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
"to avoid this check\n");
static int store_updated_refs(struct display_state *display_state,
- const char *remote_name,
int connectivity_checked,
struct ref_transaction *transaction, struct ref *ref_map,
struct fetch_head *fetch_head,
@@ -1277,11 +1239,6 @@ static int store_updated_refs(struct display_state *display_state,
}
}
- if (rc & STORE_REF_ERROR_DF_CONFLICT)
- error(_("some local refs could not be updated; try running\n"
- " 'git remote prune %s' to remove any old, conflicting "
- "branches"), remote_name);
-
if (advice_enabled(ADVICE_FETCH_SHOW_FORCED_UPDATES)) {
if (!config->show_forced_updates) {
warning(_(warn_show_forced_updates));
@@ -1330,7 +1287,8 @@ static int check_exist_and_connected(struct ref *ref_map)
* we need all direct targets to exist.
*/
for (r = rm; r; r = r->next) {
- if (!has_object(the_repository, &r->old_oid, HAS_OBJECT_RECHECK_PACKED))
+ if (!odb_has_object(the_repository->objects, &r->old_oid,
+ HAS_OBJECT_RECHECK_PACKED))
return -1;
}
@@ -1365,9 +1323,8 @@ static int fetch_and_consume_refs(struct display_state *display_state,
}
trace2_region_enter("fetch", "consume_refs", the_repository);
- ret = store_updated_refs(display_state, transport->remote->name,
- connectivity_checked, transaction, ref_map,
- fetch_head, config);
+ ret = store_updated_refs(display_state, connectivity_checked,
+ transaction, ref_map, fetch_head, config);
trace2_region_leave("fetch", "consume_refs", the_repository);
out:
@@ -1383,9 +1340,10 @@ static int prune_refs(struct display_state *display_state,
int result = 0;
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
struct strbuf err = STRBUF_INIT;
- const char *dangling_msg = dry_run
- ? _(" (%s will become dangling)")
- : _(" (%s has become dangling)");
+ struct string_list refnames = STRING_LIST_INIT_NODUP;
+
+ for (ref = stale_refs; ref; ref = ref->next)
+ string_list_append(&refnames, ref->name);
if (!dry_run) {
if (transaction) {
@@ -1396,15 +1354,9 @@ static int prune_refs(struct display_state *display_state,
goto cleanup;
}
} else {
- struct string_list refnames = STRING_LIST_INIT_NODUP;
-
- for (ref = stale_refs; ref; ref = ref->next)
- string_list_append(&refnames, ref->name);
-
result = refs_delete_refs(get_main_ref_store(the_repository),
"fetch: prune", &refnames,
0);
- string_list_clear(&refnames, 0);
}
}
@@ -1416,12 +1368,14 @@ static int prune_refs(struct display_state *display_state,
_("(none)"), ref->name,
&ref->new_oid, &ref->old_oid,
summary_width);
- refs_warn_dangling_symref(get_main_ref_store(the_repository),
- stderr, dangling_msg, ref->name);
}
+ string_list_sort(&refnames);
+ refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
+ stderr, " ", dry_run, &refnames);
}
cleanup:
+ string_list_clear(&refnames, 0);
strbuf_release(&err);
free_refs(stale_refs);
return result;
@@ -1485,7 +1439,7 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
struct object_id oid;
if (repo_get_oid(the_repository, s, &oid))
die(_("%s is not a valid object"), s);
- if (!has_object(the_repository, &oid, 0))
+ if (!odb_has_object(the_repository->objects, &oid, 0))
die(_("the object %s does not exist"), s);
oid_array_append(oids, &oid);
continue;
@@ -1687,6 +1641,36 @@ cleanup:
return result;
}
+struct ref_rejection_data {
+ int *retcode;
+ int conflict_msg_shown;
+ const char *remote_name;
+};
+
+static void ref_transaction_rejection_handler(const char *refname,
+ const struct object_id *old_oid UNUSED,
+ const struct object_id *new_oid UNUSED,
+ const char *old_target UNUSED,
+ const char *new_target UNUSED,
+ enum ref_transaction_error err,
+ void *cb_data)
+{
+ struct ref_rejection_data *data = cb_data;
+
+ if (err == REF_TRANSACTION_ERROR_NAME_CONFLICT && !data->conflict_msg_shown) {
+ error(_("some local refs could not be updated; try running\n"
+ " 'git remote prune %s' to remove any old, conflicting "
+ "branches"), data->remote_name);
+ data->conflict_msg_shown = 1;
+ } else {
+ const char *reason = ref_transaction_error_msg(err);
+
+ error(_("fetching ref %s failed: %s"), refname, reason);
+ }
+
+ *data->retcode = 1;
+}
+
static int do_fetch(struct transport *transport,
struct refspec *rs,
const struct fetch_config *config)
@@ -1807,6 +1791,24 @@ static int do_fetch(struct transport *transport,
retcode = 1;
}
+ /*
+ * If not atomic, we can still use batched updates, which would be much
+ * more performant. We don't initiate the transaction before pruning,
+ * since pruning must be an independent step, to avoid F/D conflicts.
+ *
+ * TODO: if reference transactions gain logical conflict resolution, we
+ * can delete and create refs (with F/D conflicts) in the same transaction
+ * and this can be moved above the 'prune_refs()' block.
+ */
+ if (!transaction) {
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ REF_TRANSACTION_ALLOW_FAILURE, &err);
+ if (!transaction) {
+ retcode = -1;
+ goto cleanup;
+ }
+ }
+
if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map,
&fetch_head, config)) {
retcode = 1;
@@ -1838,16 +1840,31 @@ static int do_fetch(struct transport *transport,
free_refs(tags_ref_map);
}
- if (transaction) {
- if (retcode)
- goto cleanup;
+ if (retcode)
+ goto cleanup;
- retcode = ref_transaction_commit(transaction, &err);
+ retcode = ref_transaction_commit(transaction, &err);
+ if (retcode) {
+ /*
+ * Explicitly handle transaction cleanup to avoid
+ * aborting an already closed transaction.
+ */
+ ref_transaction_free(transaction);
+ transaction = NULL;
+ goto cleanup;
+ }
+
+ if (!atomic_fetch) {
+ struct ref_rejection_data data = {
+ .retcode = &retcode,
+ .conflict_msg_shown = 0,
+ .remote_name = transport->remote->name,
+ };
+
+ ref_transaction_for_each_rejected_update(transaction,
+ ref_transaction_rejection_handler,
+ &data);
if (retcode) {
- /*
- * Explicitly handle transaction cleanup to avoid
- * aborting an already closed transaction.
- */
ref_transaction_free(transaction);
transaction = NULL;
goto cleanup;
@@ -1978,7 +1995,7 @@ static int add_remote_or_group(const char *name, struct string_list *list)
struct remote_group_data g;
g.name = name; g.list = list;
- git_config(get_remote_group, &g);
+ repo_config(the_repository, get_remote_group, &g);
if (list->nr == prev_nr) {
struct remote *remote = remote_get(name);
if (!remote_is_configured(remote, 0))
@@ -2400,7 +2417,7 @@ int cmd_fetch(int argc,
free(anon);
}
- git_config(git_fetch_config, &config);
+ repo_config(the_repository, git_fetch_config, &config);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
@@ -2491,7 +2508,7 @@ int cmd_fetch(int argc,
if (!max_jobs)
max_jobs = online_cpus();
- if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri) &&
+ if (!repo_config_get_string_tmp(the_repository, "fetch.bundleuri", &bundle_uri) &&
fetch_bundle_uri(the_repository, bundle_uri, NULL))
warning(_("failed to fetch bundles from '%s'"), bundle_uri);
@@ -2653,7 +2670,7 @@ int cmd_fetch(int argc,
commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
trace2_region_enter("fetch", "write-commit-graph", the_repository);
- write_commit_graph_reachable(the_repository->objects->odb,
+ write_commit_graph_reachable(the_repository->objects->sources,
commit_graph_flags,
NULL);
trace2_region_leave("fetch", "write-commit-graph", the_repository);
@@ -2666,12 +2683,12 @@ int cmd_fetch(int argc,
* but respect config settings disabling it.
*/
int opt_val;
- if (git_config_get_int("gc.autopacklimit", &opt_val))
+ if (repo_config_get_int(the_repository, "gc.autopacklimit", &opt_val))
opt_val = -1;
if (opt_val != 0)
git_config_push_parameter("gc.autoPackLimit=1");
- if (git_config_get_int("maintenance.incremental-repack.auto", &opt_val))
+ if (repo_config_get_int(the_repository, "maintenance.incremental-repack.auto", &opt_val))
opt_val = -1;
if (opt_val != 0)
git_config_push_parameter("maintenance.incremental-repack.auto=-1");
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 3b6aac2cf7..edb93c0b3a 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -53,7 +53,7 @@ int cmd_fmt_merge_msg(int argc,
int ret;
struct fmt_merge_msg_opts opts;
- git_config(fmt_merge_msg_config, NULL);
+ repo_config(the_repository, fmt_merge_msg_config, NULL);
argc = parse_options(argc, argv, prefix, options, fmt_merge_msg_usage,
0);
if (argc > 0)
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 3d2207ec77..222637a2c0 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "commit.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "object.h"
#include "parse-options.h"
@@ -13,6 +14,7 @@ static char const * const for_each_ref_usage[] = {
N_("git for-each-ref [--points-at <object>]"),
N_("git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"),
N_("git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"),
+ N_("git for-each-ref [--start-after <marker>]"),
NULL
};
@@ -44,6 +46,7 @@ int cmd_for_each_ref(int argc,
OPT_GROUP(""),
OPT_INTEGER( 0 , "count", &format.array_opts.max_count, N_("show only <n> matched refs")),
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
+ OPT_STRING( 0 , "start-after", &filter.start_after, N_("marker"), N_("start iteration after the provided marker")),
OPT__COLOR(&format.use_color, N_("respect format colors")),
OPT_REF_FILTER_EXCLUDE(&filter),
OPT_REF_SORT(&sorting_options),
@@ -79,6 +82,9 @@ int cmd_for_each_ref(int argc,
if (verify_ref_format(&format))
usage_with_options(for_each_ref_usage, opts);
+ if (filter.start_after && sorting_options.nr > 1)
+ die(_("cannot use --start-after with custom sort options"));
+
sorting = ref_sorting_options(&sorting_options);
ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
filter.ignore_case = icase;
@@ -100,6 +106,9 @@ int cmd_for_each_ref(int argc,
filter.name_patterns = argv;
}
+ if (filter.start_after && filter.name_patterns && filter.name_patterns[0])
+ die(_("cannot use --start-after with patterns"));
+
if (include_root_refs)
flags |= FILTER_REFS_ROOT_REFS | FILTER_REFS_DETACHED_HEAD;
diff --git a/builtin/fsck.c b/builtin/fsck.c
index e7d96a9c8e..d2eb9d4fbe 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -17,7 +17,7 @@
#include "packfile.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "path.h"
#include "read-cache-ll.h"
#include "replace-object.h"
@@ -71,7 +71,8 @@ static const char *printable_type(const struct object_id *oid,
const char *ret;
if (type == OBJ_NONE)
- type = oid_object_info(the_repository, oid, NULL);
+ type = odb_read_object_info(the_repository->objects,
+ oid, NULL);
ret = type_name(type);
if (!ret)
@@ -160,7 +161,7 @@ static int mark_object(struct object *obj, enum object_type type,
return 0;
if (!(obj->flags & HAS_OBJ)) {
- if (parent && !has_object(the_repository, &obj->oid, 1)) {
+ if (parent && !odb_has_object(the_repository->objects, &obj->oid, 1)) {
printf_ln(_("broken link from %7s %s\n"
" to %7s %s"),
printable_type(&parent->oid, parent->type),
@@ -232,8 +233,8 @@ static void mark_unreachable_referents(const struct object_id *oid)
* (and we want to avoid parsing blobs).
*/
if (obj->type == OBJ_NONE) {
- enum object_type type = oid_object_info(the_repository,
- &obj->oid, NULL);
+ enum object_type type = odb_read_object_info(the_repository->objects,
+ &obj->oid, NULL);
if (type > 0)
object_as_type(obj, type, 0);
}
@@ -392,7 +393,8 @@ static void check_connectivity(void)
* and ignore any that weren't present in our earlier
* traversal.
*/
- for_each_loose_object(mark_loose_unreachable_referents, NULL, 0);
+ for_each_loose_object(the_repository->objects,
+ mark_loose_unreachable_referents, NULL, 0);
for_each_packed_object(the_repository,
mark_packed_unreachable_referents,
NULL,
@@ -501,13 +503,12 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
}
}
-static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,
+static int fsck_handle_reflog_ent(const char *refname,
+ struct object_id *ooid, struct object_id *noid,
const char *email UNUSED,
timestamp_t timestamp, int tz UNUSED,
- const char *message UNUSED, void *cb_data)
+ const char *message UNUSED, void *cb_data UNUSED)
{
- const char *refname = cb_data;
-
if (verbose)
fprintf_ln(stderr, _("Checking reflog %s->%s"),
oid_to_hex(ooid), oid_to_hex(noid));
@@ -524,7 +525,7 @@ static int fsck_handle_reflog(const char *logname, void *cb_data)
strbuf_worktree_ref(cb_data, &refname, logname);
refs_for_each_reflog_ent(get_main_ref_store(the_repository),
refname.buf, fsck_handle_reflog_ent,
- refname.buf);
+ NULL);
strbuf_release(&refname);
return 0;
}
@@ -631,7 +632,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,
oi.sizep = &size;
oi.typep = &type;
- if (read_loose_object(path, oid, &real_oid, &contents, &oi) < 0) {
+ if (read_loose_object(the_repository, path, oid, &real_oid, &contents, &oi) < 0) {
if (contents && !oideq(&real_oid, oid))
err = error(_("%s: hash-path mismatch, found at: %s"),
oid_to_hex(&real_oid), path);
@@ -686,7 +687,7 @@ static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)
return 0;
}
-static void fsck_object_dir(const char *path)
+static void fsck_source(struct odb_source *source)
{
struct progress *progress = NULL;
struct for_each_loose_cb cb_data = {
@@ -700,8 +701,8 @@ static void fsck_object_dir(const char *path)
progress = start_progress(the_repository,
_("Checking object directories"), 256);
- for_each_loose_file_in_objdir(path, fsck_loose, fsck_cruft, fsck_subdir,
- &cb_data);
+ for_each_loose_file_in_source(source, fsck_loose,
+ fsck_cruft, fsck_subdir, &cb_data);
display_progress(progress, 256);
stop_progress(&progress);
}
@@ -956,7 +957,7 @@ int cmd_fsck(int argc,
struct repository *repo UNUSED)
{
int i;
- struct object_directory *odb;
+ struct odb_source *source;
/* fsck knows how to handle missing promisor objects */
fetch_if_missing = 0;
@@ -986,20 +987,21 @@ int cmd_fsck(int argc,
if (name_objects)
fsck_enable_object_names(&fsck_walk_options);
- git_config(git_fsck_config, &fsck_obj_options);
+ repo_config(the_repository, git_fsck_config, &fsck_obj_options);
prepare_repo_settings(the_repository);
if (check_references)
fsck_refs(the_repository);
if (connectivity_only) {
- for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
+ for_each_loose_object(the_repository->objects,
+ mark_loose_for_connectivity, NULL, 0);
for_each_packed_object(the_repository,
mark_packed_for_connectivity, NULL, 0);
} else {
- prepare_alt_odb(the_repository);
- for (odb = the_repository->objects->odb; odb; odb = odb->next)
- fsck_object_dir(odb->path);
+ odb_prepare_alternates(the_repository->objects);
+ for (source = the_repository->objects->sources; source; source = source->next)
+ fsck_source(source);
if (check_full) {
struct packed_git *p;
@@ -1108,12 +1110,12 @@ int cmd_fsck(int argc,
if (the_repository->settings.core_commit_graph) {
struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
- prepare_alt_odb(the_repository);
- for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+ odb_prepare_alternates(the_repository->objects);
+ for (source = the_repository->objects->sources; source; source = source->next) {
child_process_init(&commit_graph_verify);
commit_graph_verify.git_cmd = 1;
strvec_pushl(&commit_graph_verify.args, "commit-graph",
- "verify", "--object-dir", odb->path, NULL);
+ "verify", "--object-dir", source->path, NULL);
if (show_progress)
strvec_push(&commit_graph_verify.args, "--progress");
else
@@ -1126,12 +1128,12 @@ int cmd_fsck(int argc,
if (the_repository->settings.core_multi_pack_index) {
struct child_process midx_verify = CHILD_PROCESS_INIT;
- prepare_alt_odb(the_repository);
- for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+ odb_prepare_alternates(the_repository->objects);
+ for (source = the_repository->objects->sources; source; source = source->next) {
child_process_init(&midx_verify);
midx_verify.git_cmd = 1;
strvec_pushl(&midx_verify.args, "multi-pack-index",
- "verify", "--object-dir", odb->path, NULL);
+ "verify", "--object-dir", source->path, NULL);
if (show_progress)
strvec_push(&midx_verify.args, "--progress");
else
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 0820e524f1..242c594646 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -5,6 +5,7 @@
#include "abspath.h"
#include "config.h"
#include "dir.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "fsmonitor-ll.h"
@@ -1547,7 +1548,7 @@ int cmd_fsmonitor__daemon(int argc,
OPT_END()
};
- git_config(fsmonitor_config, NULL);
+ repo_config(the_repository, fsmonitor_config, NULL);
argc = parse_options(argc, argv, prefix, options,
builtin_fsmonitor__daemon_usage, 0);
diff --git a/builtin/gc.c b/builtin/gc.c
index 7dc94f243d..03ae4926b2 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -114,7 +114,7 @@ static int gc_config_is_timestamp_never(const char *var)
const char *value;
timestamp_t expire;
- if (!git_config_get_value(var, &value) && value) {
+ if (!repo_config_get_value(the_repository, var, &value) && value) {
if (parse_expiry_date(value, &expire))
die(_("failed to parse '%s' value '%s'"), var, value);
return expire == 0;
@@ -178,7 +178,7 @@ static void gc_config(struct gc_config *cfg)
char *owned = NULL;
unsigned long ulongval;
- if (!git_config_get_value("gc.packrefs", &value)) {
+ if (!repo_config_get_value(the_repository, "gc.packrefs", &value)) {
if (value && !strcmp(value, "notbare"))
cfg->pack_refs = -1;
else
@@ -189,13 +189,13 @@ static void gc_config(struct gc_config *cfg)
gc_config_is_timestamp_never("gc.reflogexpireunreachable"))
cfg->prune_reflogs = 0;
- git_config_get_int("gc.aggressivewindow", &cfg->aggressive_window);
- git_config_get_int("gc.aggressivedepth", &cfg->aggressive_depth);
- git_config_get_int("gc.auto", &cfg->gc_auto_threshold);
- git_config_get_int("gc.autopacklimit", &cfg->gc_auto_pack_limit);
- git_config_get_bool("gc.autodetach", &cfg->detach_auto);
- git_config_get_bool("gc.cruftpacks", &cfg->cruft_packs);
- git_config_get_ulong("gc.maxcruftsize", &cfg->max_cruft_size);
+ repo_config_get_int(the_repository, "gc.aggressivewindow", &cfg->aggressive_window);
+ repo_config_get_int(the_repository, "gc.aggressivedepth", &cfg->aggressive_depth);
+ repo_config_get_int(the_repository, "gc.auto", &cfg->gc_auto_threshold);
+ repo_config_get_int(the_repository, "gc.autopacklimit", &cfg->gc_auto_pack_limit);
+ repo_config_get_bool(the_repository, "gc.autodetach", &cfg->detach_auto);
+ repo_config_get_bool(the_repository, "gc.cruftpacks", &cfg->cruft_packs);
+ repo_config_get_ulong(the_repository, "gc.maxcruftsize", &cfg->max_cruft_size);
if (!repo_config_get_expiry(the_repository, "gc.pruneexpire", &owned)) {
free(cfg->prune_expire);
@@ -212,23 +212,23 @@ static void gc_config(struct gc_config *cfg)
cfg->gc_log_expire = owned;
}
- git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold);
- git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size);
+ repo_config_get_ulong(the_repository, "gc.bigpackthreshold", &cfg->big_pack_threshold);
+ repo_config_get_ulong(the_repository, "pack.deltacachesize", &cfg->max_delta_cache_size);
- if (!git_config_get_ulong("core.deltabasecachelimit", &ulongval))
+ if (!repo_config_get_ulong(the_repository, "core.deltabasecachelimit", &ulongval))
cfg->delta_base_cache_limit = ulongval;
- if (!git_config_get_string("gc.repackfilter", &owned)) {
+ if (!repo_config_get_string(the_repository, "gc.repackfilter", &owned)) {
free(cfg->repack_filter);
cfg->repack_filter = owned;
}
- if (!git_config_get_string("gc.repackfilterto", &owned)) {
+ if (!repo_config_get_string(the_repository, "gc.repackfilterto", &owned)) {
free(cfg->repack_filter_to);
cfg->repack_filter_to = owned;
}
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
}
enum schedule_priority {
@@ -251,7 +251,24 @@ static enum schedule_priority parse_schedule(const char *value)
return SCHEDULE_NONE;
}
+enum maintenance_task_label {
+ TASK_PREFETCH,
+ TASK_LOOSE_OBJECTS,
+ TASK_INCREMENTAL_REPACK,
+ TASK_GC,
+ TASK_COMMIT_GRAPH,
+ TASK_PACK_REFS,
+ TASK_REFLOG_EXPIRE,
+ TASK_WORKTREE_PRUNE,
+ TASK_RERERE_GC,
+
+ /* Leave as final value */
+ TASK__COUNT
+};
+
struct maintenance_run_opts {
+ enum maintenance_task_label *tasks;
+ size_t tasks_nr, tasks_alloc;
int auto_flag;
int detach;
int quiet;
@@ -261,6 +278,11 @@ struct maintenance_run_opts {
.detach = -1, \
}
+static void maintenance_run_opts_release(struct maintenance_run_opts *opts)
+{
+ free(opts->tasks);
+}
+
static int pack_refs_condition(UNUSED struct gc_config *cfg)
{
/*
@@ -290,7 +312,8 @@ struct count_reflog_entries_data {
size_t limit;
};
-static int count_reflog_entries(struct object_id *old_oid, struct object_id *new_oid,
+static int count_reflog_entries(const char *refname UNUSED,
+ struct object_id *old_oid, struct object_id *new_oid,
const char *committer, timestamp_t timestamp,
int tz, const char *msg, void *cb_data)
{
@@ -310,7 +333,7 @@ static int reflog_expire_condition(struct gc_config *cfg UNUSED)
};
int limit = 100;
- git_config_get_int("maintenance.reflog-expire.auto", &limit);
+ repo_config_get_int(the_repository, "maintenance.reflog-expire.auto", &limit);
if (!limit)
return 0;
if (limit < 0)
@@ -324,6 +347,7 @@ static int reflog_expire_condition(struct gc_config *cfg UNUSED)
count_reflog_entries, &data);
reflog_expiry_cleanup(&data.policy);
+ reflog_clear_expire_config(&data.policy.opts);
return data.count >= data.limit;
}
@@ -356,7 +380,7 @@ static int worktree_prune_condition(struct gc_config *cfg)
struct dirent *d;
DIR *dir = NULL;
- git_config_get_int("maintenance.worktree-prune.auto", &limit);
+ repo_config_get_int(the_repository, "maintenance.worktree-prune.auto", &limit);
if (limit <= 0) {
should_prune = limit < 0;
goto out;
@@ -401,7 +425,7 @@ static int rerere_gc_condition(struct gc_config *cfg UNUSED)
int should_gc = 0, limit = 1;
DIR *dir = NULL;
- git_config_get_int("maintenance.rerere-gc.auto", &limit);
+ repo_config_get_int(the_repository, "maintenance.rerere-gc.auto", &limit);
if (limit <= 0) {
should_gc = limit < 0;
goto out;
@@ -517,7 +541,7 @@ static uint64_t total_ram(void)
return total;
}
#elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM) || defined(HW_PHYSMEM64))
- int64_t physical_memory;
+ uint64_t physical_memory;
int mib[2];
size_t length;
@@ -529,9 +553,16 @@ static uint64_t total_ram(void)
# else
mib[1] = HW_PHYSMEM;
# endif
- length = sizeof(int64_t);
- if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0))
+ length = sizeof(physical_memory);
+ if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0)) {
+ if (length == 4) {
+ uint32_t mem;
+
+ if (!sysctl(mib, 2, &mem, &length, NULL, 0))
+ physical_memory = mem;
+ }
return physical_memory;
+ }
#elif defined(GIT_WINDOWS_NATIVE)
MEMORYSTATUSEX memInfo;
@@ -796,22 +827,14 @@ done:
return ret;
}
-static void gc_before_repack(struct maintenance_run_opts *opts,
- struct gc_config *cfg)
+static int gc_foreground_tasks(struct maintenance_run_opts *opts,
+ struct gc_config *cfg)
{
- /*
- * We may be called twice, as both the pre- and
- * post-daemonized phases will call us, but running these
- * commands more than once is pointless and wasteful.
- */
- static int done = 0;
- if (done++)
- return;
-
if (cfg->pack_refs && maintenance_task_pack_refs(opts, cfg))
- die(FAILED_RUN, "pack-refs");
+ return error(FAILED_RUN, "pack-refs");
if (cfg->prune_reflogs && maintenance_task_reflog_expire(opts, cfg))
- die(FAILED_RUN, "reflog");
+ return error(FAILED_RUN, "reflog");
+ return 0;
}
int cmd_gc(int argc,
@@ -820,12 +843,12 @@ int cmd_gc(int argc,
struct repository *repo UNUSED)
{
int aggressive = 0;
- int quiet = 0;
int force = 0;
const char *name;
pid_t pid;
int daemonized = 0;
int keep_largest_pack = -1;
+ int skip_foreground_tasks = 0;
timestamp_t dummy;
struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
struct gc_config cfg = GC_CONFIG_INIT;
@@ -833,7 +856,7 @@ int cmd_gc(int argc,
const char *prune_expire_arg = prune_expire_sentinel;
int ret;
struct option builtin_gc_options[] = {
- OPT__QUIET(&quiet, N_("suppress progress reporting")),
+ OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
{
.type = OPTION_STRING,
.long_name = "prune",
@@ -858,6 +881,8 @@ int cmd_gc(int argc,
N_("repack all other packs except the largest pack")),
OPT_STRING(0, "expire-to", &cfg.repack_expire_to, N_("dir"),
N_("pack prefix to store a pack containing pruned objects")),
+ OPT_HIDDEN_BOOL(0, "skip-foreground-tasks", &skip_foreground_tasks,
+ N_("skip maintenance tasks typically done in the foreground")),
OPT_END()
};
@@ -893,7 +918,7 @@ int cmd_gc(int argc,
if (cfg.aggressive_window > 0)
strvec_pushf(&repack, "--window=%d", cfg.aggressive_window);
}
- if (quiet)
+ if (opts.quiet)
strvec_push(&repack, "-q");
if (opts.auto_flag) {
@@ -908,7 +933,7 @@ int cmd_gc(int argc,
goto out;
}
- if (!quiet) {
+ if (!opts.quiet) {
if (opts.detach > 0)
fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n"));
else
@@ -941,13 +966,16 @@ int cmd_gc(int argc,
goto out;
}
- if (lock_repo_for_gc(force, &pid)) {
- ret = 0;
- goto out;
- }
+ if (!skip_foreground_tasks) {
+ if (lock_repo_for_gc(force, &pid)) {
+ ret = 0;
+ goto out;
+ }
- gc_before_repack(&opts, &cfg); /* dies on failure */
- delete_tempfile(&pidfile);
+ if (gc_foreground_tasks(&opts, &cfg) < 0)
+ die(NULL);
+ delete_tempfile(&pidfile);
+ }
/*
* failure to daemonize is ok, we'll continue
@@ -976,9 +1004,10 @@ int cmd_gc(int argc,
free(path);
}
- gc_before_repack(&opts, &cfg);
+ if (opts.detach <= 0 && !skip_foreground_tasks)
+ gc_foreground_tasks(&opts, &cfg);
- if (!repository_format_precious_objects) {
+ if (!the_repository->repository_format_precious_objects) {
struct child_process repack_cmd = CHILD_PROCESS_INIT;
repack_cmd.git_cmd = 1;
@@ -993,7 +1022,7 @@ int cmd_gc(int argc,
strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL);
/* run `git prune` even if using cruft packs */
strvec_push(&prune_cmd.args, cfg.prune_expire);
- if (quiet)
+ if (opts.quiet)
strvec_push(&prune_cmd.args, "--no-progress");
if (repo_has_promisor_remote(the_repository))
strvec_push(&prune_cmd.args,
@@ -1020,8 +1049,8 @@ int cmd_gc(int argc,
}
if (the_repository->settings.gc_write_commit_graph == 1)
- write_commit_graph_reachable(the_repository->objects->odb,
- !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
+ write_commit_graph_reachable(the_repository->objects->sources,
+ !opts.quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
NULL);
if (opts.auto_flag && too_many_loose_objects(&cfg))
@@ -1035,6 +1064,7 @@ int cmd_gc(int argc,
}
out:
+ maintenance_run_opts_release(&opts);
gc_config_release(&cfg);
return 0;
}
@@ -1082,7 +1112,7 @@ static int dfs_on_ref(const char *refname UNUSED,
if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled;
- if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
+ if (odb_read_object_info(the_repository->objects, oid, NULL) != OBJ_COMMIT)
return 0;
commit = lookup_commit(the_repository, oid);
@@ -1133,8 +1163,8 @@ static int should_write_commit_graph(struct gc_config *cfg UNUSED)
data.num_not_in_graph = 0;
data.limit = 100;
- git_config_get_int("maintenance.commit-graph.auto",
- &data.limit);
+ repo_config_get_int(the_repository, "maintenance.commit-graph.auto",
+ &data.limit);
if (!data.limit)
return 0;
@@ -1211,8 +1241,14 @@ static int maintenance_task_prefetch(struct maintenance_run_opts *opts,
return 0;
}
-static int maintenance_task_gc(struct maintenance_run_opts *opts,
- struct gc_config *cfg UNUSED)
+static int maintenance_task_gc_foreground(struct maintenance_run_opts *opts,
+ struct gc_config *cfg)
+{
+ return gc_foreground_tasks(opts, cfg);
+}
+
+static int maintenance_task_gc_background(struct maintenance_run_opts *opts,
+ struct gc_config *cfg UNUSED)
{
struct child_process child = CHILD_PROCESS_INIT;
@@ -1226,6 +1262,7 @@ static int maintenance_task_gc(struct maintenance_run_opts *opts,
else
strvec_push(&child.args, "--no-quiet");
strvec_push(&child.args, "--no-detach");
+ strvec_push(&child.args, "--skip-foreground-tasks");
return run_command(&child);
}
@@ -1265,15 +1302,15 @@ static int loose_object_auto_condition(struct gc_config *cfg UNUSED)
{
int count = 0;
- git_config_get_int("maintenance.loose-objects.auto",
- &loose_object_auto_limit);
+ repo_config_get_int(the_repository, "maintenance.loose-objects.auto",
+ &loose_object_auto_limit);
if (!loose_object_auto_limit)
return 0;
if (loose_object_auto_limit < 0)
return 1;
- return for_each_loose_file_in_objdir(the_repository->objects->odb->path,
+ return for_each_loose_file_in_source(the_repository->objects->sources,
loose_object_count,
NULL, NULL, &count);
}
@@ -1308,7 +1345,7 @@ static int pack_loose(struct maintenance_run_opts *opts)
* Do not start pack-objects process
* if there are no loose objects.
*/
- if (!for_each_loose_file_in_objdir(r->objects->odb->path,
+ if (!for_each_loose_file_in_source(r->objects->sources,
bail_on_loose,
NULL, NULL, NULL))
return 0;
@@ -1320,7 +1357,7 @@ static int pack_loose(struct maintenance_run_opts *opts)
strvec_push(&pack_proc.args, "--quiet");
else
strvec_push(&pack_proc.args, "--no-quiet");
- strvec_pushf(&pack_proc.args, "%s/pack/loose", r->objects->odb->path);
+ strvec_pushf(&pack_proc.args, "%s/pack/loose", r->objects->sources->path);
pack_proc.in = -1;
@@ -1348,11 +1385,9 @@ static int pack_loose(struct maintenance_run_opts *opts)
else if (data.batch_size > 0)
data.batch_size--; /* Decrease for equality on limit. */
- for_each_loose_file_in_objdir(r->objects->odb->path,
+ for_each_loose_file_in_source(r->objects->sources,
write_loose_object_to_stdin,
- NULL,
- NULL,
- &data);
+ NULL, NULL, &data);
fclose(data.in);
@@ -1380,8 +1415,8 @@ static int incremental_repack_auto_condition(struct gc_config *cfg UNUSED)
if (!the_repository->settings.core_multi_pack_index)
return 0;
- git_config_get_int("maintenance.incremental-repack.auto",
- &incremental_repack_auto_limit);
+ repo_config_get_int(the_repository, "maintenance.incremental-repack.auto",
+ &incremental_repack_auto_limit);
if (!incremental_repack_auto_limit)
return 0;
@@ -1513,107 +1548,120 @@ static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts
return 0;
}
-typedef int maintenance_task_fn(struct maintenance_run_opts *opts,
- struct gc_config *cfg);
-
-/*
- * An auto condition function returns 1 if the task should run
- * and 0 if the task should NOT run. See needs_to_gc() for an
- * example.
- */
-typedef int maintenance_auto_fn(struct gc_config *cfg);
+typedef int (*maintenance_task_fn)(struct maintenance_run_opts *opts,
+ struct gc_config *cfg);
+typedef int (*maintenance_auto_fn)(struct gc_config *cfg);
struct maintenance_task {
const char *name;
- maintenance_task_fn *fn;
- maintenance_auto_fn *auto_condition;
- unsigned enabled:1;
-
- enum schedule_priority schedule;
- /* -1 if not selected. */
- int selected_order;
-};
+ /*
+ * Work that will be executed before detaching. This should not include
+ * tasks that may run for an extended amount of time as it does cause
+ * auto-maintenance to block until foreground tasks have been run.
+ */
+ maintenance_task_fn foreground;
-enum maintenance_task_label {
- TASK_PREFETCH,
- TASK_LOOSE_OBJECTS,
- TASK_INCREMENTAL_REPACK,
- TASK_GC,
- TASK_COMMIT_GRAPH,
- TASK_PACK_REFS,
- TASK_REFLOG_EXPIRE,
- TASK_WORKTREE_PRUNE,
- TASK_RERERE_GC,
+ /*
+ * Work that will be executed after detaching. When not detaching the
+ * work will be run in the foreground, as well.
+ */
+ maintenance_task_fn background;
- /* Leave as final value */
- TASK__COUNT
+ /*
+ * An auto condition function returns 1 if the task should run and 0 if
+ * the task should NOT run. See needs_to_gc() for an example.
+ */
+ maintenance_auto_fn auto_condition;
};
-static struct maintenance_task tasks[] = {
+static const struct maintenance_task tasks[] = {
[TASK_PREFETCH] = {
- "prefetch",
- maintenance_task_prefetch,
+ .name = "prefetch",
+ .background = maintenance_task_prefetch,
},
[TASK_LOOSE_OBJECTS] = {
- "loose-objects",
- maintenance_task_loose_objects,
- loose_object_auto_condition,
+ .name = "loose-objects",
+ .background = maintenance_task_loose_objects,
+ .auto_condition = loose_object_auto_condition,
},
[TASK_INCREMENTAL_REPACK] = {
- "incremental-repack",
- maintenance_task_incremental_repack,
- incremental_repack_auto_condition,
+ .name = "incremental-repack",
+ .background = maintenance_task_incremental_repack,
+ .auto_condition = incremental_repack_auto_condition,
},
[TASK_GC] = {
- "gc",
- maintenance_task_gc,
- need_to_gc,
- 1,
+ .name = "gc",
+ .foreground = maintenance_task_gc_foreground,
+ .background = maintenance_task_gc_background,
+ .auto_condition = need_to_gc,
},
[TASK_COMMIT_GRAPH] = {
- "commit-graph",
- maintenance_task_commit_graph,
- should_write_commit_graph,
+ .name = "commit-graph",
+ .background = maintenance_task_commit_graph,
+ .auto_condition = should_write_commit_graph,
},
[TASK_PACK_REFS] = {
- "pack-refs",
- maintenance_task_pack_refs,
- pack_refs_condition,
+ .name = "pack-refs",
+ .foreground = maintenance_task_pack_refs,
+ .auto_condition = pack_refs_condition,
},
[TASK_REFLOG_EXPIRE] = {
- "reflog-expire",
- maintenance_task_reflog_expire,
- reflog_expire_condition,
+ .name = "reflog-expire",
+ .foreground = maintenance_task_reflog_expire,
+ .auto_condition = reflog_expire_condition,
},
[TASK_WORKTREE_PRUNE] = {
- "worktree-prune",
- maintenance_task_worktree_prune,
- worktree_prune_condition,
+ .name = "worktree-prune",
+ .background = maintenance_task_worktree_prune,
+ .auto_condition = worktree_prune_condition,
},
[TASK_RERERE_GC] = {
- "rerere-gc",
- maintenance_task_rerere_gc,
- rerere_gc_condition,
+ .name = "rerere-gc",
+ .background = maintenance_task_rerere_gc,
+ .auto_condition = rerere_gc_condition,
},
};
-static int compare_tasks_by_selection(const void *a_, const void *b_)
+enum task_phase {
+ TASK_PHASE_FOREGROUND,
+ TASK_PHASE_BACKGROUND,
+};
+
+static int maybe_run_task(const struct maintenance_task *task,
+ struct repository *repo,
+ struct maintenance_run_opts *opts,
+ struct gc_config *cfg,
+ enum task_phase phase)
{
- const struct maintenance_task *a = a_;
- const struct maintenance_task *b = b_;
+ int foreground = (phase == TASK_PHASE_FOREGROUND);
+ maintenance_task_fn fn = foreground ? task->foreground : task->background;
+ const char *region = foreground ? "maintenance foreground" : "maintenance";
+ int ret = 0;
- return b->selected_order - a->selected_order;
+ if (!fn)
+ return 0;
+ if (opts->auto_flag &&
+ (!task->auto_condition || !task->auto_condition(cfg)))
+ return 0;
+
+ trace2_region_enter(region, task->name, repo);
+ if (fn(opts, cfg)) {
+ error(_("task '%s' failed"), task->name);
+ ret = 1;
+ }
+ trace2_region_leave(region, task->name, repo);
+
+ return ret;
}
static int maintenance_run_tasks(struct maintenance_run_opts *opts,
struct gc_config *cfg)
{
- int i, found_selected = 0;
int result = 0;
struct lock_file lk;
struct repository *r = the_repository;
- char *lock_path = xstrfmt("%s/maintenance", r->objects->odb->path);
+ char *lock_path = xstrfmt("%s/maintenance", r->objects->sources->path);
if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
/*
@@ -1631,6 +1679,11 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
}
free(lock_path);
+ for (size_t i = 0; i < opts->tasks_nr; i++)
+ if (maybe_run_task(&tasks[opts->tasks[i]], r, opts, cfg,
+ TASK_PHASE_FOREGROUND))
+ result = 1;
+
/* Failure to daemonize is ok, we'll continue in foreground. */
if (opts->detach > 0) {
trace2_region_enter("maintenance", "detach", the_repository);
@@ -1638,120 +1691,138 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
trace2_region_leave("maintenance", "detach", the_repository);
}
- for (i = 0; !found_selected && i < TASK__COUNT; i++)
- found_selected = tasks[i].selected_order >= 0;
-
- if (found_selected)
- QSORT(tasks, TASK__COUNT, compare_tasks_by_selection);
-
- for (i = 0; i < TASK__COUNT; i++) {
- if (found_selected && tasks[i].selected_order < 0)
- continue;
-
- if (!found_selected && !tasks[i].enabled)
- continue;
-
- if (opts->auto_flag &&
- (!tasks[i].auto_condition ||
- !tasks[i].auto_condition(cfg)))
- continue;
-
- if (opts->schedule && tasks[i].schedule < opts->schedule)
- continue;
-
- trace2_region_enter("maintenance", tasks[i].name, r);
- if (tasks[i].fn(opts, cfg)) {
- error(_("task '%s' failed"), tasks[i].name);
+ for (size_t i = 0; i < opts->tasks_nr; i++)
+ if (maybe_run_task(&tasks[opts->tasks[i]], r, opts, cfg,
+ TASK_PHASE_BACKGROUND))
result = 1;
- }
- trace2_region_leave("maintenance", tasks[i].name, r);
- }
rollback_lock_file(&lk);
return result;
}
-static void initialize_maintenance_strategy(void)
+struct maintenance_strategy {
+ struct {
+ int enabled;
+ enum schedule_priority schedule;
+ } tasks[TASK__COUNT];
+};
+
+static const struct maintenance_strategy none_strategy = { 0 };
+static const struct maintenance_strategy default_strategy = {
+ .tasks = {
+ [TASK_GC].enabled = 1,
+ },
+};
+static const struct maintenance_strategy incremental_strategy = {
+ .tasks = {
+ [TASK_COMMIT_GRAPH].enabled = 1,
+ [TASK_COMMIT_GRAPH].schedule = SCHEDULE_HOURLY,
+ [TASK_PREFETCH].enabled = 1,
+ [TASK_PREFETCH].schedule = SCHEDULE_HOURLY,
+ [TASK_INCREMENTAL_REPACK].enabled = 1,
+ [TASK_INCREMENTAL_REPACK].schedule = SCHEDULE_DAILY,
+ [TASK_LOOSE_OBJECTS].enabled = 1,
+ [TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY,
+ [TASK_PACK_REFS].enabled = 1,
+ [TASK_PACK_REFS].schedule = SCHEDULE_WEEKLY,
+ },
+};
+
+static void initialize_task_config(struct maintenance_run_opts *opts,
+ const struct string_list *selected_tasks)
{
+ struct strbuf config_name = STRBUF_INIT;
+ struct maintenance_strategy strategy;
const char *config_str;
- if (git_config_get_string_tmp("maintenance.strategy", &config_str))
- return;
+ /*
+ * In case the user has asked us to run tasks explicitly we only use
+ * those specified tasks. Specifically, we do _not_ want to consult the
+ * config or maintenance strategy.
+ */
+ if (selected_tasks->nr) {
+ for (size_t i = 0; i < selected_tasks->nr; i++) {
+ enum maintenance_task_label label = (intptr_t)selected_tasks->items[i].util;;
+ ALLOC_GROW(opts->tasks, opts->tasks_nr + 1, opts->tasks_alloc);
+ opts->tasks[opts->tasks_nr++] = label;
+ }
- if (!strcasecmp(config_str, "incremental")) {
- tasks[TASK_GC].schedule = SCHEDULE_NONE;
- tasks[TASK_COMMIT_GRAPH].enabled = 1;
- tasks[TASK_COMMIT_GRAPH].schedule = SCHEDULE_HOURLY;
- tasks[TASK_PREFETCH].enabled = 1;
- tasks[TASK_PREFETCH].schedule = SCHEDULE_HOURLY;
- tasks[TASK_INCREMENTAL_REPACK].enabled = 1;
- tasks[TASK_INCREMENTAL_REPACK].schedule = SCHEDULE_DAILY;
- tasks[TASK_LOOSE_OBJECTS].enabled = 1;
- tasks[TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY;
- tasks[TASK_PACK_REFS].enabled = 1;
- tasks[TASK_PACK_REFS].schedule = SCHEDULE_WEEKLY;
+ return;
}
-}
-static void initialize_task_config(int schedule)
-{
- int i;
- struct strbuf config_name = STRBUF_INIT;
+ /*
+ * Otherwise, the strategy depends on whether we run as part of a
+ * scheduled job or not:
+ *
+ * - Scheduled maintenance does not perform any housekeeping by
+ * default, but requires the user to pick a maintenance strategy.
+ *
+ * - Unscheduled maintenance uses our default strategy.
+ *
+ * Both of these are affected by the gitconfig though, which may
+ * override specific aspects of our strategy.
+ */
+ if (opts->schedule) {
+ strategy = none_strategy;
- if (schedule)
- initialize_maintenance_strategy();
+ if (!repo_config_get_string_tmp(the_repository, "maintenance.strategy", &config_str)) {
+ if (!strcasecmp(config_str, "incremental"))
+ strategy = incremental_strategy;
+ }
+ } else {
+ strategy = default_strategy;
+ }
- for (i = 0; i < TASK__COUNT; i++) {
+ for (size_t i = 0; i < TASK__COUNT; i++) {
int config_value;
- char *config_str;
strbuf_reset(&config_name);
strbuf_addf(&config_name, "maintenance.%s.enabled",
tasks[i].name);
+ if (!repo_config_get_bool(the_repository, config_name.buf, &config_value))
+ strategy.tasks[i].enabled = config_value;
+ if (!strategy.tasks[i].enabled)
+ continue;
- if (!git_config_get_bool(config_name.buf, &config_value))
- tasks[i].enabled = config_value;
-
- strbuf_reset(&config_name);
- strbuf_addf(&config_name, "maintenance.%s.schedule",
- tasks[i].name);
-
- if (!git_config_get_string(config_name.buf, &config_str)) {
- tasks[i].schedule = parse_schedule(config_str);
- free(config_str);
+ if (opts->schedule) {
+ strbuf_reset(&config_name);
+ strbuf_addf(&config_name, "maintenance.%s.schedule",
+ tasks[i].name);
+ if (!repo_config_get_string_tmp(the_repository, config_name.buf, &config_str))
+ strategy.tasks[i].schedule = parse_schedule(config_str);
+ if (strategy.tasks[i].schedule < opts->schedule)
+ continue;
}
+
+ ALLOC_GROW(opts->tasks, opts->tasks_nr + 1, opts->tasks_alloc);
+ opts->tasks[opts->tasks_nr++] = i;
}
strbuf_release(&config_name);
}
-static int task_option_parse(const struct option *opt UNUSED,
+static int task_option_parse(const struct option *opt,
const char *arg, int unset)
{
- int i, num_selected = 0;
- struct maintenance_task *task = NULL;
+ struct string_list *selected_tasks = opt->value;
+ size_t i;
BUG_ON_OPT_NEG(unset);
- for (i = 0; i < TASK__COUNT; i++) {
- if (tasks[i].selected_order >= 0)
- num_selected++;
- if (!strcasecmp(tasks[i].name, arg)) {
- task = &tasks[i];
- }
- }
-
- if (!task) {
+ for (i = 0; i < TASK__COUNT; i++)
+ if (!strcasecmp(tasks[i].name, arg))
+ break;
+ if (i >= TASK__COUNT) {
error(_("'%s' is not a valid task"), arg);
return 1;
}
- if (task->selected_order >= 0) {
+ if (unsorted_string_list_has_string(selected_tasks, arg)) {
error(_("task '%s' cannot be selected multiple times"), arg);
return 1;
}
- task->selected_order = num_selected + 1;
+ string_list_append(selected_tasks, arg)->util = (void *)(intptr_t)i;
return 0;
}
@@ -1759,8 +1830,8 @@ static int task_option_parse(const struct option *opt UNUSED,
static int maintenance_run(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
- int i;
struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
+ struct string_list selected_tasks = STRING_LIST_INIT_DUP;
struct gc_config cfg = GC_CONFIG_INIT;
struct option builtin_maintenance_run_options[] = {
OPT_BOOL(0, "auto", &opts.auto_flag,
@@ -1772,7 +1843,7 @@ static int maintenance_run(int argc, const char **argv, const char *prefix,
maintenance_opt_schedule),
OPT_BOOL(0, "quiet", &opts.quiet,
N_("do not report progress or other information over stderr")),
- OPT_CALLBACK_F(0, "task", NULL, N_("task"),
+ OPT_CALLBACK_F(0, "task", &selected_tasks, N_("task"),
N_("run a specific task"),
PARSE_OPT_NONEG, task_option_parse),
OPT_END()
@@ -1781,25 +1852,27 @@ static int maintenance_run(int argc, const char **argv, const char *prefix,
opts.quiet = !isatty(2);
- for (i = 0; i < TASK__COUNT; i++)
- tasks[i].selected_order = -1;
-
argc = parse_options(argc, argv, prefix,
builtin_maintenance_run_options,
builtin_maintenance_run_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
- if (opts.auto_flag && opts.schedule)
- die(_("use at most one of --auto and --schedule=<frequency>"));
+ die_for_incompatible_opt2(opts.auto_flag, "--auto",
+ opts.schedule, "--schedule=");
+ die_for_incompatible_opt2(selected_tasks.nr, "--task=",
+ opts.schedule, "--schedule=");
gc_config(&cfg);
- initialize_task_config(opts.schedule);
+ initialize_task_config(&opts, &selected_tasks);
if (argc != 0)
usage_with_options(builtin_maintenance_run_usage,
builtin_maintenance_run_options);
ret = maintenance_run_tasks(&opts, &cfg);
+
+ string_list_clear(&selected_tasks, 0);
+ maintenance_run_opts_release(&opts);
gc_config_release(&cfg);
return ret;
}
@@ -1840,13 +1913,13 @@ static int maintenance_register(int argc, const char **argv, const char *prefix,
options);
/* Disable foreground maintenance */
- git_config_set("maintenance.auto", "false");
+ repo_config_set(the_repository, "maintenance.auto", "false");
/* Set maintenance strategy, if unset */
- if (git_config_get("maintenance.strategy"))
- git_config_set("maintenance.strategy", "incremental");
+ if (repo_config_get(the_repository, "maintenance.strategy"))
+ repo_config_set(the_repository, "maintenance.strategy", "incremental");
- if (!git_config_get_string_multi(key, &list)) {
+ if (!repo_config_get_string_multi(the_repository, key, &list)) {
for_each_string_list_item(item, list) {
if (!strcmp(maintpath, item->string)) {
found = 1;
@@ -1865,7 +1938,7 @@ static int maintenance_register(int argc, const char **argv, const char *prefix,
}
if (!config_file)
die(_("$HOME not set"));
- rc = git_config_set_multivar_in_file_gently(
+ rc = repo_config_set_multivar_in_file_gently(the_repository,
config_file, "maintenance.repo", maintpath,
CONFIG_REGEX_NONE, NULL, 0);
free(global_config_file);
@@ -1915,7 +1988,7 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
}
if (!(config_file
? git_configset_get_string_multi(&cs, key, &list)
- : git_config_get_string_multi(key, &list))) {
+ : repo_config_get_string_multi(the_repository, key, &list))) {
for_each_string_list_item(item, list) {
if (!strcmp(maintpath, item->string)) {
found = 1;
@@ -1934,7 +2007,7 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
}
if (!config_file)
die(_("$HOME not set"));
- rc = git_config_set_multivar_in_file_gently(
+ rc = repo_config_set_multivar_in_file_gently(the_repository,
config_file, key, NULL, maintpath, NULL,
CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
free(global_config_file);
@@ -2271,7 +2344,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
die(_("failed to create directories for '%s'"), filename);
if ((long)lock_file_timeout_ms < 0 &&
- git_config_get_ulong("gc.launchctlplistlocktimeoutms",
+ repo_config_get_ulong(the_repository, "gc.launchctlplistlocktimeoutms",
&lock_file_timeout_ms))
lock_file_timeout_ms = 150;
@@ -3085,7 +3158,7 @@ static int update_background_schedule(const struct maintenance_start_opts *opts,
unsigned int i;
int result = 0;
struct lock_file lk;
- char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path);
+ char *lock_path = xstrfmt("%s/schedule", the_repository->objects->sources->path);
if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
if (errno == EEXIST)
diff --git a/builtin/grep.c b/builtin/grep.c
index 3ce574a605..5df6537333 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "abspath.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "config.h"
@@ -26,7 +27,7 @@
#include "submodule-config.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "packfile.h"
#include "pager.h"
#include "path.h"
@@ -462,7 +463,7 @@ static int grep_submodule(struct grep_opt *opt,
/*
* NEEDSWORK: repo_read_gitmodules() might call
- * add_to_alternates_memory() via config_from_gitmodules(). This
+ * odb_add_to_alternates_memory() via config_from_gitmodules(). This
* operation causes a race condition with concurrent object readings
* performed by the worker threads. That's why we need obj_read_lock()
* here. It should be removed once it's no longer necessary to add the
@@ -505,7 +506,8 @@ static int grep_submodule(struct grep_opt *opt,
* lazily registered as alternates when needed (and except in an
* unexpected code interaction, it won't be needed).
*/
- add_submodule_odb_by_path(subrepo->objects->odb->path);
+ odb_add_submodule_source_by_path(the_repository->objects,
+ subrepo->objects->sources->path);
obj_read_unlock();
memcpy(&subopt, opt, sizeof(subopt));
@@ -519,11 +521,9 @@ static int grep_submodule(struct grep_opt *opt,
struct strbuf base = STRBUF_INIT;
obj_read_lock();
- object_type = oid_object_info(subrepo, oid, NULL);
+ object_type = odb_read_object_info(subrepo->objects, oid, NULL);
obj_read_unlock();
- data = read_object_with_reference(subrepo,
- oid, OBJ_TREE,
- &size, NULL);
+ data = odb_read_object_peeled(subrepo->objects, oid, OBJ_TREE, &size, NULL);
if (!data)
die(_("unable to read tree (%s)"), oid_to_hex(oid));
@@ -572,8 +572,8 @@ static int grep_cache(struct grep_opt *opt,
void *data;
unsigned long size;
- data = repo_read_object_file(the_repository, &ce->oid,
- &type, &size);
+ data = odb_read_object(the_repository->objects, &ce->oid,
+ &type, &size);
if (!data)
die(_("unable to read tree %s"), oid_to_hex(&ce->oid));
init_tree_desc(&tree, &ce->oid, data, size);
@@ -665,8 +665,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
void *data;
unsigned long size;
- data = repo_read_object_file(the_repository,
- &entry.oid, &type, &size);
+ data = odb_read_object(the_repository->objects,
+ &entry.oid, &type, &size);
if (!data)
die(_("unable to read tree (%s)"),
oid_to_hex(&entry.oid));
@@ -704,9 +704,8 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
struct strbuf base;
int hit, len;
- data = read_object_with_reference(opt->repo,
- &obj->oid, OBJ_TREE,
- &size, NULL);
+ data = odb_read_object_peeled(opt->repo->objects, &obj->oid,
+ OBJ_TREE, &size, NULL);
if (!data)
die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
@@ -1037,7 +1036,7 @@ int cmd_grep(int argc,
grep_prefix = prefix;
grep_init(&opt, the_repository);
- git_config(grep_cmd_config, &opt);
+ repo_config(the_repository, grep_cmd_config, &opt);
/*
* If there is no -- then the paths must exist in the working
@@ -1060,7 +1059,7 @@ int cmd_grep(int argc,
if (use_index && !startup_info->have_repository) {
int fallback = 0;
- git_config_get_bool("grep.fallbacktonoindex", &fallback);
+ repo_config_get_bool(the_repository, "grep.fallbacktonoindex", &fallback);
if (fallback)
use_index = 0;
else
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 6a99ec250d..5d900a6b8c 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -8,10 +8,11 @@
#include "builtin.h"
#include "abspath.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
#include "blob.h"
#include "quote.h"
#include "parse-options.h"
@@ -104,14 +105,14 @@ int cmd_hash_object(int argc,
prefix = setup_git_directory_gently(&nongit);
if (nongit && !the_hash_algo)
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+ repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
if (vpath && prefix) {
vpath_free = prefix_filename(prefix, vpath);
vpath = vpath_free;
}
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
if (stdin_paths) {
if (hashstdin)
diff --git a/builtin/help.c b/builtin/help.c
index c257079ceb..c09cbc8912 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -6,6 +6,7 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "exec-cmd.h"
#include "gettext.h"
#include "pager.h"
@@ -210,7 +211,7 @@ static enum help_format parse_help_format(const char *format)
if (!strcmp(format, "web") || !strcmp(format, "html"))
return HELP_FORMAT_WEB;
/*
- * Please update _git_config() in git-completion.bash when you
+ * Please update _repo_config() in git-completion.bash when you
* add new help formats.
*/
die(_("unrecognized help format '%s'"), format);
@@ -706,7 +707,7 @@ int cmd_help(int argc,
}
setup_git_directory_gently(&nongit);
- git_config(git_help_config, NULL);
+ repo_config(the_repository, git_help_config, NULL);
if (parsed_help_format != HELP_FORMAT_NONE)
help_format = parsed_help_format;
diff --git a/builtin/hook.c b/builtin/hook.c
index 672d2e37e8..7afec380d2 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hook.h"
#include "parse-options.h"
@@ -55,7 +56,7 @@ static int run(int argc, const char **argv, const char *prefix,
strvec_push(&opt.args, argv[i]);
/* Need to take into account core.hooksPath */
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
hook_name = argv[0];
if (!ignore_missing)
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index bb7925bd29..f91c301bba 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -21,7 +21,7 @@
#include "packfile.h"
#include "pack-revindex.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
#include "oid-array.h"
#include "oidset.h"
#include "path.h"
@@ -260,7 +260,8 @@ static unsigned check_object(struct object *obj)
if (!(obj->flags & FLAG_CHECKED)) {
unsigned long size;
- int type = oid_object_info(the_repository, &obj->oid, &size);
+ int type = odb_read_object_info(the_repository->objects,
+ &obj->oid, &size);
if (type <= 0)
die(_("did not receive expected object %s"),
oid_to_hex(&obj->oid));
@@ -362,7 +363,7 @@ static const char *open_pack_file(const char *pack_name)
input_fd = 0;
if (!pack_name) {
struct strbuf tmp_file = STRBUF_INIT;
- output_fd = odb_mkstemp(&tmp_file,
+ output_fd = odb_mkstemp(the_repository->objects, &tmp_file,
"pack/tmp_pack_XXXXXX");
pack_name = strbuf_detach(&tmp_file, NULL);
} else {
@@ -892,8 +893,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
if (startup_info->have_repository) {
read_lock();
- collision_test_needed = has_object(the_repository, oid,
- HAS_OBJECT_FETCH_PROMISOR);
+ collision_test_needed = odb_has_object(the_repository->objects, oid,
+ HAS_OBJECT_FETCH_PROMISOR);
read_unlock();
}
@@ -908,13 +909,13 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
enum object_type has_type;
unsigned long has_size;
read_lock();
- has_type = oid_object_info(the_repository, oid, &has_size);
+ has_type = odb_read_object_info(the_repository->objects, oid, &has_size);
if (has_type < 0)
die(_("cannot read existing object info %s"), oid_to_hex(oid));
if (has_type != type || has_size != size)
die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
- has_data = repo_read_object_file(the_repository, oid,
- &has_type, &has_size);
+ has_data = odb_read_object(the_repository->objects, oid,
+ &has_type, &has_size);
read_unlock();
if (!data)
data = new_data = get_data_from_pack(obj_entry);
@@ -1501,9 +1502,9 @@ static void fix_unresolved_deltas(struct hashfile *f)
struct oid_array to_fetch = OID_ARRAY_INIT;
for (i = 0; i < nr_ref_deltas; i++) {
struct ref_delta_entry *d = sorted_by_pos[i];
- if (!oid_object_info_extended(the_repository, &d->oid,
- NULL,
- OBJECT_INFO_FOR_PREFETCH))
+ if (!odb_read_object_info_extended(the_repository->objects,
+ &d->oid, NULL,
+ OBJECT_INFO_FOR_PREFETCH))
continue;
oid_array_append(&to_fetch, &d->oid);
}
@@ -1520,8 +1521,8 @@ static void fix_unresolved_deltas(struct hashfile *f)
if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
continue;
- data = repo_read_object_file(the_repository, &d->oid, &type,
- &size);
+ data = odb_read_object(the_repository->objects, &d->oid,
+ &type, &size);
if (!data)
continue;
@@ -1597,7 +1598,7 @@ static void rename_tmp_packfile(const char **final_name,
if (!*final_name || strcmp(*final_name, curr_name)) {
if (!*final_name)
*final_name = odb_pack_name(the_repository, name, hash, ext);
- if (finalize_object_file(curr_name, *final_name))
+ if (finalize_object_file(the_repository, curr_name, *final_name))
die(_("unable to rename temporary '*.%s' file to '%s'"),
ext, *final_name);
} else if (make_read_only_if_same) {
@@ -1829,7 +1830,7 @@ static void repack_local_links(void)
oidset_iter_init(&outgoing_links, &iter);
while ((oid = oidset_iter_next(&iter))) {
struct object_info info = OBJECT_INFO_INIT;
- if (oid_object_info_extended(the_repository, oid, &info, 0))
+ if (odb_read_object_info_extended(the_repository->objects, oid, &info, 0))
/* Missing; assume it is a promisor object */
continue;
if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
@@ -1916,7 +1917,7 @@ int cmd_index_pack(int argc,
reset_pack_idx_option(&opts);
opts.flags |= WRITE_REV;
- git_config(git_index_pack_config, &opts);
+ repo_config(the_repository, git_index_pack_config, &opts);
if (prefix && chdir(prefix))
die(_("Cannot come back to cwd"));
@@ -2034,7 +2035,7 @@ int cmd_index_pack(int argc,
* choice but to guess the object hash.
*/
if (!the_repository->hash_algo)
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+ repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY);
if (rev_index) {
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 44d8ccddc9..41b0750e5a 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -6,6 +6,7 @@
*/
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "string-list.h"
@@ -220,7 +221,7 @@ int cmd_interpret_trailers(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options,
git_interpret_trailers_usage, 0);
diff --git a/builtin/log.c b/builtin/log.c
index b450cd3bde..c2f8bbf863 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -15,7 +15,7 @@
#include "hex.h"
#include "refs.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "pager.h"
#include "color.h"
#include "commit.h"
@@ -113,6 +113,15 @@ struct log_config {
int fmt_patch_name_max;
char *fmt_pretty;
char *default_date_mode;
+
+#ifndef WITH_BREAKING_CHANGES
+ /*
+ * Note: git_log_config() does not touch this member and that
+ * is very deliberate. This member is only to be used to
+ * resurrect whatchanged that is deprecated.
+ */
+ int i_still_use_this;
+#endif
};
static void log_config_init(struct log_config *cfg)
@@ -212,7 +221,7 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
struct string_list *include = decoration_filter->include_ref_pattern;
const struct string_list *config_exclude;
- if (!git_config_get_string_multi("log.excludeDecoration",
+ if (!repo_config_get_string_multi(the_repository, "log.excludeDecoration",
&config_exclude)) {
struct string_list_item *item;
for_each_string_list_item(item, config_exclude)
@@ -226,7 +235,7 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
* since the command-line takes precedent.
*/
if (use_default_decoration_filter &&
- !git_config_get_string("log.initialdecorationset", &value) &&
+ !repo_config_get_string(the_repository, "log.initialdecorationset", &value) &&
!strcmp("all", value))
use_default_decoration_filter = 0;
free(value);
@@ -267,6 +276,10 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
OPT__QUIET(&quiet, N_("suppress diff output")),
OPT_BOOL(0, "source", &source, N_("show source")),
OPT_BOOL(0, "use-mailmap", &mailmap, N_("use mail map file")),
+#ifndef WITH_BREAKING_CHANGES
+ OPT_HIDDEN_BOOL(0, "i-still-use-this", &cfg->i_still_use_this,
+ "<use this deprecated command>"),
+#endif
OPT_ALIAS(0, "mailmap", "use-mailmap"),
OPT_CALLBACK_F(0, "clear-decorations", NULL, NULL,
N_("clear all previously-defined decoration filters"),
@@ -378,129 +391,6 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
cmd_log_init_finish(argc, argv, prefix, rev, opt, cfg);
}
-/*
- * This gives a rough estimate for how many commits we
- * will print out in the list.
- */
-static int estimate_commit_count(struct commit_list *list)
-{
- int n = 0;
-
- while (list) {
- struct commit *commit = list->item;
- unsigned int flags = commit->object.flags;
- list = list->next;
- if (!(flags & (TREESAME | UNINTERESTING)))
- n++;
- }
- return n;
-}
-
-static void show_early_header(struct rev_info *rev, const char *stage, int nr)
-{
- if (rev->shown_one) {
- rev->shown_one = 0;
- if (rev->commit_format != CMIT_FMT_ONELINE)
- putchar(rev->diffopt.line_termination);
- }
- fprintf(rev->diffopt.file, _("Final output: %d %s\n"), nr, stage);
-}
-
-static struct itimerval early_output_timer;
-
-static void log_show_early(struct rev_info *revs, struct commit_list *list)
-{
- int i = revs->early_output;
- int show_header = 1;
- int no_free = revs->diffopt.no_free;
-
- revs->diffopt.no_free = 0;
- sort_in_topological_order(&list, revs->sort_order);
- while (list && i) {
- struct commit *commit = list->item;
- switch (simplify_commit(revs, commit)) {
- case commit_show:
- if (show_header) {
- int n = estimate_commit_count(list);
- show_early_header(revs, "incomplete", n);
- show_header = 0;
- }
- log_tree_commit(revs, commit);
- i--;
- break;
- case commit_ignore:
- break;
- case commit_error:
- revs->diffopt.no_free = no_free;
- diff_free(&revs->diffopt);
- return;
- }
- list = list->next;
- }
-
- /* Did we already get enough commits for the early output? */
- if (!i) {
- revs->diffopt.no_free = 0;
- diff_free(&revs->diffopt);
- return;
- }
-
- /*
- * ..if no, then repeat it twice a second until we
- * do.
- *
- * NOTE! We don't use "it_interval", because if the
- * reader isn't listening, we want our output to be
- * throttled by the writing, and not have the timer
- * trigger every second even if we're blocked on a
- * reader!
- */
- early_output_timer.it_value.tv_sec = 0;
- early_output_timer.it_value.tv_usec = 500000;
- setitimer(ITIMER_REAL, &early_output_timer, NULL);
-}
-
-static void early_output(int signal UNUSED)
-{
- show_early_output = log_show_early;
-}
-
-static void setup_early_output(void)
-{
- struct sigaction sa;
-
- /*
- * Set up the signal handler, minimally intrusively:
- * we only set a single volatile integer word (not
- * using sigatomic_t - trying to avoid unnecessary
- * system dependencies and headers), and using
- * SA_RESTART.
- */
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = early_output;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- sigaction(SIGALRM, &sa, NULL);
-
- /*
- * If we can get the whole output in less than a
- * tenth of a second, don't even bother doing the
- * early-output thing..
- *
- * This is a one-time-only trigger.
- */
- early_output_timer.it_value.tv_sec = 0;
- early_output_timer.it_value.tv_usec = 100000;
- setitimer(ITIMER_REAL, &early_output_timer, NULL);
-}
-
-static void finish_early_output(struct rev_info *rev)
-{
- int n = estimate_commit_count(rev->commits);
- signal(SIGALRM, SIG_IGN);
- show_early_header(rev, "done", n);
-}
-
static int cmd_log_walk_no_free(struct rev_info *rev)
{
struct commit *commit;
@@ -508,15 +398,9 @@ static int cmd_log_walk_no_free(struct rev_info *rev)
int saved_dcctc = 0;
int result;
- if (rev->early_output)
- setup_early_output();
-
if (prepare_revision_walk(rev))
die(_("revision walk setup failed"));
- if (rev->early_output)
- finish_early_output(rev);
-
/*
* For --check and --exit-code, the exit code is based on CHECK_FAILED
* and HAS_CHANGES being accumulated in rev->diffopt, so be careful to
@@ -633,6 +517,7 @@ static int git_log_config(const char *var, const char *value,
return git_diff_ui_config(var, value, ctx, cb);
}
+#ifndef WITH_BREAKING_CHANGES
int cmd_whatchanged(int argc,
const char **argv,
const char *prefix,
@@ -645,10 +530,10 @@ int cmd_whatchanged(int argc,
log_config_init(&cfg);
init_diff_ui_defaults();
- git_config(git_log_config, &cfg);
+ repo_config(the_repository, git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.diff = 1;
rev.simplify_history = 0;
@@ -656,6 +541,10 @@ int cmd_whatchanged(int argc,
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
+
+ if (!cfg.i_still_use_this)
+ you_still_use_that("git whatchanged");
+
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
@@ -665,6 +554,7 @@ int cmd_whatchanged(int argc,
log_config_release(&cfg);
return ret;
}
+#endif
static void show_tagger(const char *buf, struct rev_info *rev)
{
@@ -714,7 +604,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
{
unsigned long size;
enum object_type type;
- char *buf = repo_read_object_file(the_repository, oid, &type, &size);
+ char *buf = odb_read_object(the_repository->objects, oid, &type, &size);
unsigned long offset = 0;
if (!buf)
@@ -771,7 +661,7 @@ int cmd_show(int argc,
log_config_init(&cfg);
init_diff_ui_defaults();
- git_config(git_log_config, &cfg);
+ repo_config(the_repository, git_log_config, &cfg);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
@@ -780,7 +670,7 @@ int cmd_show(int argc,
memset(&match_all, 0, sizeof(match_all));
repo_init_revisions(the_repository, &rev, prefix);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.diff = 1;
rev.always_show_header = 1;
@@ -888,11 +778,11 @@ int cmd_log_reflog(int argc,
log_config_init(&cfg);
init_diff_ui_defaults();
- git_config(git_log_config, &cfg);
+ repo_config(the_repository, git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
init_reflog_walk(&rev.reflog_info);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.verbose_header = 1;
memset(&opt, 0, sizeof(opt));
@@ -933,10 +823,10 @@ int cmd_log(int argc,
log_config_init(&cfg);
init_diff_ui_defaults();
- git_config(git_log_config, &cfg);
+ repo_config(the_repository, git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.always_show_header = 1;
memset(&opt, 0, sizeof(opt));
@@ -2139,9 +2029,9 @@ int cmd_format_patch(int argc,
format_config_init(&cfg);
init_diff_ui_defaults();
init_display_notes(&cfg.notes_opt);
- git_config(git_format_config, &cfg);
+ repo_config(the_repository, git_format_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
- git_config(grep_config, &rev.grep_filter);
+ repo_config(the_repository, grep_config, &rev.grep_filter);
rev.show_notes = cfg.show_notes;
memcpy(&rev.notes_opt, &cfg.notes_opt, sizeof(cfg.notes_opt));
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index be74f0a03b..c06a6f33e4 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -11,6 +11,7 @@
#include "builtin.h"
#include "config.h"
#include "convert.h"
+#include "environment.h"
#include "quote.h"
#include "dir.h"
#include "gettext.h"
@@ -25,7 +26,7 @@
#include "setup.h"
#include "sparse-index.h"
#include "submodule.h"
-#include "object-store.h"
+#include "odb.h"
#include "hex.h"
@@ -251,7 +252,7 @@ static void expand_objectsize(struct repository *repo, struct strbuf *line,
{
if (type == OBJ_BLOB) {
unsigned long size;
- if (oid_object_info(repo, oid, &size) < 0)
+ if (odb_read_object_info(repo->objects, oid, &size) < 0)
die(_("could not get object info about '%s'"),
oid_to_hex(oid));
if (padded)
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 01a4d4daa1..df09000b30 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -112,7 +112,7 @@ int cmd_ls_remote(int argc,
* depending on what object hash the remote uses.
*/
if (!the_repository->hash_algo)
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+ repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
packet_trace_identity("ls-remote");
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 8aafc30ca4..5d55731ca3 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -7,10 +7,11 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "tree.h"
#include "path.h"
#include "quote.h"
@@ -27,7 +28,7 @@ static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
{
if (type == OBJ_BLOB) {
unsigned long size;
- if (oid_object_info(the_repository, oid, &size) < 0)
+ if (odb_read_object_info(the_repository->objects, oid, &size) < 0)
die(_("could not get object info about '%s'"),
oid_to_hex(oid));
if (padded)
@@ -217,7 +218,7 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
if (type == OBJ_BLOB) {
unsigned long size;
- if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
+ if (odb_read_object_info(the_repository->objects, oid, &size) == OBJ_BAD)
xsnprintf(size_text, sizeof(size_text), "BAD");
else
xsnprintf(size_text, sizeof(size_text),
@@ -375,7 +376,7 @@ int cmd_ls_tree(int argc,
struct object_context obj_context = {0};
int ret;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, ls_tree_options,
ls_tree_usage, 0);
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 123c81515e..3f82781245 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -2,6 +2,7 @@
#include "builtin.h"
#include "config.h"
#include "commit.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "object-name.h"
@@ -167,7 +168,7 @@ int cmd_merge_base(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
if (cmdmode == 'a') {
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 2b16b10d2c..46775d0c79 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -7,7 +7,7 @@
#include "hex.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "config.h"
#include "gettext.h"
#include "setup.h"
@@ -97,7 +97,7 @@ int cmd_merge_file(int argc,
if (startup_info->have_repository) {
/* Read the configuration file */
- git_config(git_xmerge_config, NULL);
+ repo_config(the_repository, git_xmerge_config, NULL);
if (0 <= git_xmerge_style)
xmp.style = git_xmerge_style;
}
@@ -155,7 +155,8 @@ int cmd_merge_file(int argc,
if (object_id && !to_stdout) {
struct object_id oid;
if (result.size) {
- if (write_object_file(result.ptr, result.size, OBJ_BLOB, &oid) < 0)
+ if (odb_write_object(the_repository->objects, result.ptr,
+ result.size, OBJ_BLOB, &oid) < 0)
ret = error(_("Could not write object file"));
} else {
oidcpy(&oid, the_hash_algo->empty_blob);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 7f41665dfd..1c063d9a41 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+#include "environment.h"
#include "tree-walk.h"
#include "xdiff-interface.h"
#include "help.h"
@@ -10,7 +11,7 @@
#include "commit-reach.h"
#include "merge-ort.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "parse-options.h"
#include "blob.h"
#include "merge-blobs.h"
@@ -75,9 +76,9 @@ static void *result(struct merge_list *entry, unsigned long *size)
const char *path = entry->path;
if (!entry->stage)
- return repo_read_object_file(the_repository,
- &entry->blob->object.oid, &type,
- size);
+ return odb_read_object(the_repository->objects,
+ &entry->blob->object.oid, &type,
+ size);
base = NULL;
if (entry->stage == 1) {
base = entry->blob;
@@ -100,9 +101,9 @@ static void *origin(struct merge_list *entry, unsigned long *size)
enum object_type type;
while (entry) {
if (entry->stage == 2)
- return repo_read_object_file(the_repository,
- &entry->blob->object.oid,
- &type, size);
+ return odb_read_object(the_repository->objects,
+ &entry->blob->object.oid,
+ &type, size);
entry = entry->link;
}
return NULL;
@@ -618,32 +619,34 @@ int cmd_merge_tree(int argc,
"--merge-base", "--stdin");
line_termination = '\0';
while (strbuf_getline_lf(&buf, stdin) != EOF) {
- struct strbuf **split;
+ struct string_list split = STRING_LIST_INIT_NODUP;
const char *input_merge_base = NULL;
- split = strbuf_split(&buf, ' ');
- if (!split[0] || !split[1])
+ string_list_split_in_place_f(&split, buf.buf, " ", -1,
+ STRING_LIST_SPLIT_TRIM);
+
+ if (split.nr < 2)
die(_("malformed input line: '%s'."), buf.buf);
- strbuf_rtrim(split[0]);
- strbuf_rtrim(split[1]);
/* parse the merge-base */
- if (!strcmp(split[1]->buf, "--")) {
- input_merge_base = split[0]->buf;
+ if (!strcmp(split.items[1].string, "--")) {
+ input_merge_base = split.items[0].string;
}
- if (input_merge_base && split[2] && split[3] && !split[4]) {
- strbuf_rtrim(split[2]);
- strbuf_rtrim(split[3]);
- real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);
- } else if (!input_merge_base && !split[2]) {
- real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
+ if (input_merge_base && split.nr == 4) {
+ real_merge(&o, input_merge_base,
+ split.items[2].string, split.items[3].string,
+ prefix);
+ } else if (!input_merge_base && split.nr == 2) {
+ real_merge(&o, NULL,
+ split.items[0].string, split.items[1].string,
+ prefix);
} else {
die(_("malformed input line: '%s'."), buf.buf);
}
maybe_flush_or_die(stdout, "stdout");
- strbuf_list_free(split);
+ string_list_clear(&split, 0);
}
strbuf_release(&buf);
@@ -683,7 +686,7 @@ int cmd_merge_tree(int argc,
if (argc != expected_remaining_argc)
usage_with_options(merge_tree_usage, mt_options);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
/* Do the relevant type of merge */
if (o.mode == MODE_REAL)
diff --git a/builtin/merge.c b/builtin/merge.c
index ce90e52fe4..c3810c9cb2 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -69,7 +69,10 @@ static const char * const builtin_merge_usage[] = {
NULL
};
-static int show_diffstat = 1, shortlog_len = -1, squash;
+#define MERGE_SHOW_DIFFSTAT 1
+#define MERGE_SHOW_COMPACTSUMMARY 2
+
+static int show_diffstat = MERGE_SHOW_DIFFSTAT, shortlog_len = -1, squash;
static int option_commit = -1;
static int option_edit = -1;
static int allow_trivial = 1, have_message, verify_signatures;
@@ -243,12 +246,28 @@ static int option_parse_strategy(const struct option *opt UNUSED,
return 0;
}
+static int option_parse_compact_summary(const struct option *opt,
+ const char *name UNUSED, int unset)
+{
+ int *setting = opt->value;
+
+ if (unset)
+ *setting = 0;
+ else
+ *setting = MERGE_SHOW_COMPACTSUMMARY;
+ return 0;
+}
+
static struct option builtin_merge_options[] = {
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)")),
+ OPT_CALLBACK_F(0, "compact-summary", &show_diffstat, NULL,
+ N_("show a compact-summary at the end of the merge"),
+ PARSE_OPT_NOARG,
+ option_parse_compact_summary),
{
.type = OPTION_INTEGER,
.long_name = "log",
@@ -494,8 +513,19 @@ static void finish(struct commit *head_commit,
struct diff_options opts;
repo_diff_setup(the_repository, &opts);
init_diffstat_widths(&opts);
- opts.output_format |=
- DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+
+ switch (show_diffstat) {
+ case MERGE_SHOW_DIFFSTAT: /* 1 */
+ opts.output_format |=
+ DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+ break;
+ case MERGE_SHOW_COMPACTSUMMARY: /* 2 */
+ opts.output_format |= DIFF_FORMAT_DIFFSTAT;
+ opts.flags.stat_with_summary = 1;
+ break;
+ default:
+ break;
+ }
opts.detect_rename = DIFF_DETECT_RENAME;
diff_setup_done(&opts);
diff_tree_oid(head, new_head, "", &opts);
@@ -643,7 +673,35 @@ static int git_merge_config(const char *k, const char *v,
}
if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat")) {
- show_diffstat = git_config_bool(k, v);
+ int val = git_parse_maybe_bool_text(v);
+ switch (val) {
+ case 0:
+ show_diffstat = 0;
+ break;
+ case 1:
+ show_diffstat = MERGE_SHOW_DIFFSTAT;
+ break;
+ default:
+ if (!strcmp(v, "compact"))
+ show_diffstat = MERGE_SHOW_COMPACTSUMMARY;
+ /*
+ * We do not need to have an explicit
+ *
+ * else if (!strcmp(v, "diffstat"))
+ * show_diffstat = MERGE_SHOW_DIFFSTAT;
+ *
+ * here, because the catch-all uses the
+ * diffstat style anyway.
+ */
+ else
+ /*
+ * A setting from a future? It is not an
+ * error grave enough to fail the command.
+ * proceed using the default one.
+ */
+ show_diffstat = MERGE_SHOW_DIFFSTAT;
+ break;
+ }
} else if (!strcmp(k, "merge.verifysignatures")) {
verify_signatures = git_config_bool(k, v);
} else if (!strcmp(k, "pull.twohead")) {
@@ -817,7 +875,7 @@ static void add_strategies(const char *string, unsigned attr)
if (string) {
struct string_list list = STRING_LIST_INIT_DUP;
struct string_list_item *item;
- string_list_split(&list, string, ' ', -1);
+ string_list_split(&list, string, " ", -1);
for_each_string_list_item(item, &list)
append_strategy(get_strategy(item->string));
string_list_clear(&list, 0);
@@ -1334,7 +1392,7 @@ int cmd_merge(int argc,
skip_prefix(branch, "refs/heads/", &branch);
init_diff_ui_defaults();
- git_config(git_merge_config, NULL);
+ repo_config(the_repository, git_merge_config, NULL);
if (!branch || is_null_oid(&head_oid))
head_commit = NULL;
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 7ac11c46d5..7cf6e1230a 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -6,7 +6,7 @@
#include "strbuf.h"
#include "replace-object.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
#include "fsck.h"
#include "config.h"
@@ -41,7 +41,7 @@ static int mktag_fsck_error_func(struct fsck_options *o UNUSED,
fprintf_ln(stderr, _("error: tag input does not pass fsck: %s"), message);
return 1;
default:
- BUG(_("%d (FSCK_IGNORE?) should never trigger this callback"),
+ BUG("%d (FSCK_IGNORE?) should never trigger this callback",
msg_type);
}
}
@@ -54,8 +54,8 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
void *buffer;
const struct object_id *repl;
- buffer = repo_read_object_file(the_repository, tagged_oid, &type,
- &size);
+ buffer = odb_read_object(the_repository->objects, tagged_oid,
+ &type, &size);
if (!buffer)
die(_("could not read tagged object '%s'"),
oid_to_hex(tagged_oid));
@@ -98,7 +98,7 @@ int cmd_mktag(int argc,
fsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY,
FSCK_WARN);
/* config might set fsck.extraHeaderEntry=* again */
- git_config(git_fsck_config, &fsck_options);
+ repo_config(the_repository, git_fsck_config, &fsck_options);
if (fsck_tag_standalone(NULL, buf.buf, buf.len, &fsck_options,
&tagged_oid, &tagged_type))
die(_("tag on stdin did not pass our strict fsck check"));
@@ -106,7 +106,7 @@ int cmd_mktag(int argc,
if (verify_object_in_tag(&tagged_oid, &tagged_type) < 0)
die(_("tag on stdin did not refer to a valid object"));
- if (write_object_file(buf.buf, buf.len, OBJ_TAG, &result) < 0)
+ if (odb_write_object(the_repository->objects, buf.buf, buf.len, OBJ_TAG, &result) < 0)
die(_("unable to write tag file"));
strbuf_release(&buf);
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 4b47803467..12772303f5 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -12,7 +12,7 @@
#include "tree.h"
#include "parse-options.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
static struct treeent {
unsigned mode;
@@ -63,7 +63,7 @@ static void write_tree(struct object_id *oid)
strbuf_add(&buf, ent->oid.hash, the_hash_algo->rawsz);
}
- write_object_file(buf.buf, buf.len, OBJ_TREE, oid);
+ odb_write_object(the_repository->objects, buf.buf, buf.len, OBJ_TREE, oid);
strbuf_release(&buf);
}
@@ -124,10 +124,10 @@ static void mktree_line(char *buf, int nul_term_line, int allow_missing)
/* Check the type of object identified by oid without fetching objects */
oi.typep = &obj_type;
- if (oid_object_info_extended(the_repository, &oid, &oi,
- OBJECT_INFO_LOOKUP_REPLACE |
- OBJECT_INFO_QUICK |
- OBJECT_INFO_SKIP_FETCH_OBJECT) < 0)
+ if (odb_read_object_info_extended(the_repository->objects, &oid, &oi,
+ OBJECT_INFO_LOOKUP_REPLACE |
+ OBJECT_INFO_QUICK |
+ OBJECT_INFO_SKIP_FETCH_OBJECT) < 0)
obj_type = -1;
if (obj_type < 0) {
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 69a9750732..d3b9e98be3 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -2,12 +2,13 @@
#include "builtin.h"
#include "abspath.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "midx.h"
#include "strbuf.h"
#include "trace2.h"
-#include "object-store.h"
+#include "odb.h"
#include "replace-object.h"
#include "repository.h"
@@ -143,7 +144,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE;
- git_config(git_multi_pack_index_write_config, NULL);
+ repo_config(the_repository, git_multi_pack_index_write_config, NULL);
options = add_common_options(builtin_multi_pack_index_write_options);
@@ -290,12 +291,12 @@ int cmd_multi_pack_index(int argc,
disable_replace_refs();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
if (the_repository &&
the_repository->objects &&
- the_repository->objects->odb)
- opts.object_dir = xstrdup(the_repository->objects->odb->path);
+ the_repository->objects->sources)
+ opts.object_dir = xstrdup(the_repository->objects->sources->path);
argc = parse_options(argc, argv, prefix, options,
builtin_multi_pack_index_usage, 0);
diff --git a/builtin/mv.c b/builtin/mv.c
index 07548fe96a..d43925097b 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -239,7 +239,7 @@ int cmd_mv(int argc,
struct strbuf pathbuf = STRBUF_INIT;
int ret;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_mv_options,
builtin_mv_usage, 0);
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index ff199638de..74512e54a3 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -600,7 +600,7 @@ int cmd_name_rev(int argc,
mem_pool_init(&string_pool, 0);
init_commit_rev_name(&rev_names);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
#ifndef WITH_BREAKING_CHANGES
diff --git a/builtin/notes.c b/builtin/notes.c
index a3f433ca4c..9af602bdd7 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -16,7 +16,7 @@
#include "notes.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "path.h"
#include "pretty.h"
@@ -152,7 +152,7 @@ static void copy_obj_to_fd(int fd, const struct object_id *oid)
{
unsigned long size;
enum object_type type;
- char *buf = repo_read_object_file(the_repository, oid, &type, &size);
+ char *buf = odb_read_object(the_repository->objects, oid, &type, &size);
if (buf) {
if (size)
write_or_die(fd, buf, size);
@@ -229,7 +229,8 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
static void write_note_data(struct note_data *d, struct object_id *oid)
{
- if (write_object_file(d->buf.buf, d->buf.len, OBJ_BLOB, oid)) {
+ if (odb_write_object(the_repository->objects, d->buf.buf,
+ d->buf.len, OBJ_BLOB, oid)) {
int status = die_message(_("unable to write note object"));
if (d->edit_path)
@@ -319,7 +320,7 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
strbuf_init(&msg->buf, 0);
if (repo_get_oid(the_repository, arg, &object))
die(_("failed to resolve '%s' as a valid ref."), arg);
- if (!(value = repo_read_object_file(the_repository, &object, &type, &len)))
+ if (!(value = odb_read_object(the_repository->objects, &object, &type, &len)))
die(_("failed to read object '%s'."), arg);
if (type != OBJ_BLOB) {
strbuf_release(&msg->buf);
@@ -375,18 +376,19 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
while (strbuf_getline_lf(&buf, stdin) != EOF) {
struct object_id from_obj, to_obj;
- struct strbuf **split;
+ struct string_list split = STRING_LIST_INIT_NODUP;
int err;
- split = strbuf_split(&buf, ' ');
- if (!split[0] || !split[1])
+ string_list_split_in_place_f(&split, buf.buf, " ", -1,
+ STRING_LIST_SPLIT_TRIM);
+ if (split.nr < 2)
die(_("malformed input line: '%s'."), buf.buf);
- strbuf_rtrim(split[0]);
- strbuf_rtrim(split[1]);
- if (repo_get_oid(the_repository, split[0]->buf, &from_obj))
- die(_("failed to resolve '%s' as a valid ref."), split[0]->buf);
- if (repo_get_oid(the_repository, split[1]->buf, &to_obj))
- die(_("failed to resolve '%s' as a valid ref."), split[1]->buf);
+ if (repo_get_oid(the_repository, split.items[0].string, &from_obj))
+ die(_("failed to resolve '%s' as a valid ref."),
+ split.items[0].string);
+ if (repo_get_oid(the_repository, split.items[1].string, &to_obj))
+ die(_("failed to resolve '%s' as a valid ref."),
+ split.items[1].string);
if (rewrite_cmd)
err = copy_note_for_rewrite(c, &from_obj, &to_obj);
@@ -396,11 +398,11 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
if (err) {
error(_("failed to copy notes from '%s' to '%s'"),
- split[0]->buf, split[1]->buf);
+ split.items[0].string, split.items[1].string);
ret = 1;
}
- strbuf_list_free(split);
+ string_list_clear(&split, 0);
}
if (!rewrite_cmd) {
@@ -722,7 +724,7 @@ static int append_edit(int argc, const char **argv, const char *prefix,
unsigned long size;
enum object_type type;
struct strbuf buf = STRBUF_INIT;
- char *prev_buf = repo_read_object_file(the_repository, note, &type, &size);
+ char *prev_buf = odb_read_object(the_repository->objects, note, &type, &size);
if (!prev_buf)
die(_("unable to read %s"), oid_to_hex(note));
@@ -873,7 +875,7 @@ static int git_config_get_notes_strategy(const char *key,
{
char *value;
- if (git_config_get_string(key, &value))
+ if (repo_config_get_string(the_repository, key, &value))
return 1;
if (parse_notes_merge_strategy(value, strategy))
git_die_config(the_repository, key, _("unknown notes merge strategy %s"), value);
@@ -1145,7 +1147,7 @@ int cmd_notes(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_notes_usage,
PARSE_OPT_SUBCOMMAND_OPTIONAL);
if (!fn) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 8b33edc2ff..53a2256250 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -32,7 +32,7 @@
#include "list.h"
#include "packfile.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
#include "replace-object.h"
#include "dir.h"
#include "midx.h"
@@ -41,6 +41,10 @@
#include "promisor-remote.h"
#include "pack-mtimes.h"
#include "parse-options.h"
+#include "blob.h"
+#include "tree.h"
+#include "path-walk.h"
+#include "trace2.h"
/*
* Objects we are going to pack are collected in the `to_pack` structure.
@@ -184,8 +188,14 @@ static inline void oe_set_delta_size(struct packing_data *pack,
#define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val)
static const char *const pack_usage[] = {
- N_("git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"),
- N_("git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]"),
+ N_("git pack-objects [-q | --progress | --all-progress] [--all-progress-implied]\n"
+ " [--no-reuse-delta] [--delta-base-offset] [--non-empty]\n"
+ " [--local] [--incremental] [--window=<n>] [--depth=<n>]\n"
+ " [--revs [--unpacked | --all]] [--keep-pack=<pack-name>]\n"
+ " [--cruft] [--cruft-expiration=<time>]\n"
+ " [--stdout [--filter=<filter-spec>] | <base-name>]\n"
+ " [--shallow] [--keep-true-parents] [--[no-]sparse]\n"
+ " [--name-hash-version=<n>] [--path-walk] < <object-list>"),
NULL
};
@@ -200,6 +210,7 @@ static int keep_unreachable, unpack_unreachable, include_tag;
static timestamp_t unpack_unreachable_expiration;
static int pack_loose_unreachable;
static int cruft;
+static int shallow = 0;
static timestamp_t cruft_expiration;
static int local;
static int have_non_local_packs;
@@ -218,6 +229,7 @@ static int delta_search_threads;
static int pack_to_stdout;
static int sparse;
static int thin;
+static int path_walk = -1;
static int num_preferred_base;
static struct progress *progress_state;
@@ -272,6 +284,12 @@ static struct oidmap configured_exclusions;
static struct oidset excluded_by_config;
static int name_hash_version = -1;
+enum stdin_packs_mode {
+ STDIN_PACKS_MODE_NONE,
+ STDIN_PACKS_MODE_STANDARD,
+ STDIN_PACKS_MODE_FOLLOW,
+};
+
/**
* Check whether the name_hash_version chosen by user input is appropriate,
* and also validate whether it is compatible with other features.
@@ -337,13 +355,13 @@ static void *get_delta(struct object_entry *entry)
void *buf, *base_buf, *delta_buf;
enum object_type type;
- buf = repo_read_object_file(the_repository, &entry->idx.oid, &type,
- &size);
+ buf = odb_read_object(the_repository->objects, &entry->idx.oid,
+ &type, &size);
if (!buf)
die(_("unable to read %s"), oid_to_hex(&entry->idx.oid));
- base_buf = repo_read_object_file(the_repository,
- &DELTA(entry)->idx.oid, &type,
- &base_size);
+ base_buf = odb_read_object(the_repository->objects,
+ &DELTA(entry)->idx.oid, &type,
+ &base_size);
if (!base_buf)
die("unable to read %s",
oid_to_hex(&DELTA(entry)->idx.oid));
@@ -506,9 +524,9 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
&size, NULL)) != NULL)
buf = NULL;
else {
- buf = repo_read_object_file(the_repository,
- &entry->idx.oid, &type,
- &size);
+ buf = odb_read_object(the_repository->objects,
+ &entry->idx.oid, &type,
+ &size);
if (!buf)
die(_("unable to read %s"),
oid_to_hex(&entry->idx.oid));
@@ -1437,7 +1455,7 @@ static void write_pack_file(void)
strbuf_setlen(&tmpname, tmpname_len);
}
- rename_tmp_packfile_idx(&tmpname, &idx_tmp_name);
+ rename_tmp_packfile_idx(the_repository, &tmpname, &idx_tmp_name);
free(idx_tmp_name);
strbuf_release(&tmpname);
@@ -1688,11 +1706,19 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
uint32_t found_mtime)
{
int want;
+ struct odb_source *source;
struct list_head *pos;
- struct multi_pack_index *m;
- if (!exclude && local && has_loose_object_nonlocal(oid))
- return 0;
+ if (!exclude && local) {
+ /*
+ * Note that we start iterating at `sources->next` so that we
+ * skip the local object source.
+ */
+ struct odb_source *source = the_repository->objects->sources->next;
+ for (; source; source = source->next)
+ if (has_loose_object(source, oid))
+ return 0;
+ }
/*
* If we already know the pack object lives in, start checks from that
@@ -1709,9 +1735,13 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
*found_offset = 0;
}
- for (m = get_multi_pack_index(the_repository); m; m = m->next) {
+ odb_prepare_alternates(the_repository->objects);
+
+ for (source = the_repository->objects->sources; source; source = source->next) {
+ struct multi_pack_index *m = get_multi_pack_index(source);
struct pack_entry e;
- if (fill_midx_entry(the_repository, oid, &e, m)) {
+
+ if (m && fill_midx_entry(the_repository, oid, &e, m)) {
want = want_object_in_pack_one(e.p, oid, exclude, found_pack, found_offset, found_mtime);
if (want != -1)
return want;
@@ -1895,7 +1925,7 @@ static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
/* Did not find one. Either we got a bogus request or
* we need to read and perhaps cache.
*/
- data = repo_read_object_file(the_repository, oid, &type, &size);
+ data = odb_read_object(the_repository->objects, oid, &type, &size);
if (!data)
return NULL;
if (type != OBJ_TREE) {
@@ -2055,8 +2085,8 @@ static void add_preferred_base(struct object_id *oid)
if (window <= num_preferred_base++)
return;
- data = read_object_with_reference(the_repository, oid,
- OBJ_TREE, &size, &tree_oid);
+ data = odb_read_object_peeled(the_repository->objects, oid,
+ OBJ_TREE, &size, &tree_oid);
if (!data)
return;
@@ -2154,10 +2184,10 @@ static void prefetch_to_pack(uint32_t object_index_start) {
for (i = object_index_start; i < to_pack.nr_objects; i++) {
struct object_entry *entry = to_pack.objects + i;
- if (!oid_object_info_extended(the_repository,
- &entry->idx.oid,
- NULL,
- OBJECT_INFO_FOR_PREFETCH))
+ if (!odb_read_object_info_extended(the_repository->objects,
+ &entry->idx.oid,
+ NULL,
+ OBJECT_INFO_FOR_PREFETCH))
continue;
oid_array_append(&to_fetch, &entry->idx.oid);
}
@@ -2298,19 +2328,19 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
/*
* No choice but to fall back to the recursive delta walk
- * with oid_object_info() to find about the object type
+ * with odb_read_object_info() to find about the object type
* at this point...
*/
give_up:
unuse_pack(&w_curs);
}
- if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
- OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0) {
+ if (odb_read_object_info_extended(the_repository->objects, &entry->idx.oid, &oi,
+ OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0) {
if (repo_has_promisor_remote(the_repository)) {
prefetch_to_pack(object_index);
- if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
- OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0)
+ if (odb_read_object_info_extended(the_repository->objects, &entry->idx.oid, &oi,
+ OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0)
type = -1;
} else {
type = -1;
@@ -2384,12 +2414,13 @@ static void drop_reused_delta(struct object_entry *entry)
if (packed_object_info(the_repository, IN_PACK(entry), entry->in_pack_offset, &oi) < 0) {
/*
* We failed to get the info from this pack for some reason;
- * fall back to oid_object_info, which may find another copy.
+ * fall back to odb_read_object_info, which may find another copy.
* And if that fails, the error will be recorded in oe_type(entry)
* and dealt with in prepare_pack().
*/
oe_set_type(entry,
- oid_object_info(the_repository, &entry->idx.oid, &size));
+ odb_read_object_info(the_repository->objects,
+ &entry->idx.oid, &size));
} else {
oe_set_type(entry, type);
}
@@ -2677,7 +2708,8 @@ unsigned long oe_get_size_slow(struct packing_data *pack,
if (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {
packing_data_lock(&to_pack);
- if (oid_object_info(the_repository, &e->idx.oid, &size) < 0)
+ if (odb_read_object_info(the_repository->objects,
+ &e->idx.oid, &size) < 0)
die(_("unable to get size of %s"),
oid_to_hex(&e->idx.oid));
packing_data_unlock(&to_pack);
@@ -2760,9 +2792,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
/* Load data if not already done */
if (!trg->data) {
packing_data_lock(&to_pack);
- trg->data = repo_read_object_file(the_repository,
- &trg_entry->idx.oid, &type,
- &sz);
+ trg->data = odb_read_object(the_repository->objects,
+ &trg_entry->idx.oid, &type,
+ &sz);
packing_data_unlock(&to_pack);
if (!trg->data)
die(_("object %s cannot be read"),
@@ -2775,9 +2807,9 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
}
if (!src->data) {
packing_data_lock(&to_pack);
- src->data = repo_read_object_file(the_repository,
- &src_entry->idx.oid, &type,
- &sz);
+ src->data = odb_read_object(the_repository->objects,
+ &src_entry->idx.oid, &type,
+ &sz);
packing_data_unlock(&to_pack);
if (!src->data) {
if (src_entry->preferred_base) {
@@ -3041,6 +3073,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
struct thread_params {
pthread_t thread;
struct object_entry **list;
+ struct packing_region *regions;
unsigned list_size;
unsigned remaining;
int window;
@@ -3283,6 +3316,242 @@ static int add_ref_tag(const char *tag UNUSED, const char *referent UNUSED, cons
return 0;
}
+static int should_attempt_deltas(struct object_entry *entry)
+{
+ if (DELTA(entry))
+ /* This happens if we decided to reuse existing
+ * delta from a pack. "reuse_delta &&" is implied.
+ */
+ return 0;
+
+ if (!entry->type_valid ||
+ oe_size_less_than(&to_pack, entry, 50))
+ return 0;
+
+ if (entry->no_try_delta)
+ return 0;
+
+ if (!entry->preferred_base) {
+ if (oe_type(entry) < 0)
+ die(_("unable to get type of object %s"),
+ oid_to_hex(&entry->idx.oid));
+ } else if (oe_type(entry) < 0) {
+ /*
+ * This object is not found, but we
+ * don't have to include it anyway.
+ */
+ return 0;
+ }
+
+ return 1;
+}
+
+static void find_deltas_for_region(struct object_entry *list,
+ struct packing_region *region,
+ unsigned int *processed)
+{
+ struct object_entry **delta_list;
+ unsigned int delta_list_nr = 0;
+
+ ALLOC_ARRAY(delta_list, region->nr);
+ for (size_t i = 0; i < region->nr; i++) {
+ struct object_entry *entry = list + region->start + i;
+ if (should_attempt_deltas(entry))
+ delta_list[delta_list_nr++] = entry;
+ }
+
+ QSORT(delta_list, delta_list_nr, type_size_sort);
+ find_deltas(delta_list, &delta_list_nr, window, depth, processed);
+ free(delta_list);
+}
+
+static void find_deltas_by_region(struct object_entry *list,
+ struct packing_region *regions,
+ size_t start, size_t nr)
+{
+ unsigned int processed = 0;
+ size_t progress_nr;
+
+ if (!nr)
+ return;
+
+ progress_nr = regions[nr - 1].start + regions[nr - 1].nr;
+
+ if (progress)
+ progress_state = start_progress(the_repository,
+ _("Compressing objects by path"),
+ progress_nr);
+
+ while (nr--)
+ find_deltas_for_region(list,
+ &regions[start++],
+ &processed);
+
+ display_progress(progress_state, progress_nr);
+ stop_progress(&progress_state);
+}
+
+static void *threaded_find_deltas_by_path(void *arg)
+{
+ struct thread_params *me = arg;
+
+ progress_lock();
+ while (me->remaining) {
+ while (me->remaining) {
+ progress_unlock();
+ find_deltas_for_region(to_pack.objects,
+ me->regions,
+ me->processed);
+ progress_lock();
+ me->remaining--;
+ me->regions++;
+ }
+
+ me->working = 0;
+ pthread_cond_signal(&progress_cond);
+ progress_unlock();
+
+ /*
+ * We must not set ->data_ready before we wait on the
+ * condition because the main thread may have set it to 1
+ * before we get here. In order to be sure that new
+ * work is available if we see 1 in ->data_ready, it
+ * was initialized to 0 before this thread was spawned
+ * and we reset it to 0 right away.
+ */
+ pthread_mutex_lock(&me->mutex);
+ while (!me->data_ready)
+ pthread_cond_wait(&me->cond, &me->mutex);
+ me->data_ready = 0;
+ pthread_mutex_unlock(&me->mutex);
+
+ progress_lock();
+ }
+ progress_unlock();
+ /* leave ->working 1 so that this doesn't get more work assigned */
+ return NULL;
+}
+
+static void ll_find_deltas_by_region(struct object_entry *list,
+ struct packing_region *regions,
+ uint32_t start, uint32_t nr)
+{
+ struct thread_params *p;
+ int i, ret, active_threads = 0;
+ unsigned int processed = 0;
+ uint32_t progress_nr;
+ init_threaded_search();
+
+ if (!nr)
+ return;
+
+ progress_nr = regions[nr - 1].start + regions[nr - 1].nr;
+ if (delta_search_threads <= 1) {
+ find_deltas_by_region(list, regions, start, nr);
+ cleanup_threaded_search();
+ return;
+ }
+
+ if (progress > pack_to_stdout)
+ fprintf_ln(stderr,
+ Q_("Path-based delta compression using up to %d thread",
+ "Path-based delta compression using up to %d threads",
+ delta_search_threads),
+ delta_search_threads);
+ CALLOC_ARRAY(p, delta_search_threads);
+
+ if (progress)
+ progress_state = start_progress(the_repository,
+ _("Compressing objects by path"),
+ progress_nr);
+ /* Partition the work amongst work threads. */
+ for (i = 0; i < delta_search_threads; i++) {
+ unsigned sub_size = nr / (delta_search_threads - i);
+
+ p[i].window = window;
+ p[i].depth = depth;
+ p[i].processed = &processed;
+ p[i].working = 1;
+ p[i].data_ready = 0;
+
+ p[i].regions = regions;
+ p[i].list_size = sub_size;
+ p[i].remaining = sub_size;
+
+ regions += sub_size;
+ nr -= sub_size;
+ }
+
+ /* Start work threads. */
+ for (i = 0; i < delta_search_threads; i++) {
+ if (!p[i].list_size)
+ continue;
+ pthread_mutex_init(&p[i].mutex, NULL);
+ pthread_cond_init(&p[i].cond, NULL);
+ ret = pthread_create(&p[i].thread, NULL,
+ threaded_find_deltas_by_path, &p[i]);
+ if (ret)
+ die(_("unable to create thread: %s"), strerror(ret));
+ active_threads++;
+ }
+
+ /*
+ * Now let's wait for work completion. Each time a thread is done
+ * with its work, we steal half of the remaining work from the
+ * thread with the largest number of unprocessed objects and give
+ * it to that newly idle thread. This ensure good load balancing
+ * until the remaining object list segments are simply too short
+ * to be worth splitting anymore.
+ */
+ while (active_threads) {
+ struct thread_params *target = NULL;
+ struct thread_params *victim = NULL;
+ unsigned sub_size = 0;
+
+ progress_lock();
+ for (;;) {
+ for (i = 0; !target && i < delta_search_threads; i++)
+ if (!p[i].working)
+ target = &p[i];
+ if (target)
+ break;
+ pthread_cond_wait(&progress_cond, &progress_mutex);
+ }
+
+ for (i = 0; i < delta_search_threads; i++)
+ if (p[i].remaining > 2*window &&
+ (!victim || victim->remaining < p[i].remaining))
+ victim = &p[i];
+ if (victim) {
+ sub_size = victim->remaining / 2;
+ target->regions = victim->regions + victim->remaining - sub_size;
+ victim->list_size -= sub_size;
+ victim->remaining -= sub_size;
+ }
+ target->list_size = sub_size;
+ target->remaining = sub_size;
+ target->working = 1;
+ progress_unlock();
+
+ pthread_mutex_lock(&target->mutex);
+ target->data_ready = 1;
+ pthread_cond_signal(&target->cond);
+ pthread_mutex_unlock(&target->mutex);
+
+ if (!sub_size) {
+ pthread_join(target->thread, NULL);
+ pthread_cond_destroy(&target->cond);
+ pthread_mutex_destroy(&target->mutex);
+ active_threads--;
+ }
+ }
+ cleanup_threaded_search();
+ free(p);
+
+ display_progress(progress_state, progress_nr);
+ stop_progress(&progress_state);
+}
+
static void prepare_pack(int window, int depth)
{
struct object_entry **delta_list;
@@ -3307,39 +3576,21 @@ static void prepare_pack(int window, int depth)
if (!to_pack.nr_objects || !window || !depth)
return;
+ if (path_walk)
+ ll_find_deltas_by_region(to_pack.objects, to_pack.regions,
+ 0, to_pack.nr_regions);
+
ALLOC_ARRAY(delta_list, to_pack.nr_objects);
nr_deltas = n = 0;
for (i = 0; i < to_pack.nr_objects; i++) {
struct object_entry *entry = to_pack.objects + i;
- if (DELTA(entry))
- /* This happens if we decided to reuse existing
- * delta from a pack. "reuse_delta &&" is implied.
- */
- continue;
-
- if (!entry->type_valid ||
- oe_size_less_than(&to_pack, entry, 50))
+ if (!should_attempt_deltas(entry))
continue;
- if (entry->no_try_delta)
- continue;
-
- if (!entry->preferred_base) {
+ if (!entry->preferred_base)
nr_deltas++;
- if (oe_type(entry) < 0)
- die(_("unable to get type of object %s"),
- oid_to_hex(&entry->idx.oid));
- } else {
- if (oe_type(entry) < 0) {
- /*
- * This object is not found, but we
- * don't have to include it anyway.
- */
- continue;
- }
- }
delta_list[n++] = entry;
}
@@ -3494,7 +3745,6 @@ static int add_object_entry_from_pack(const struct object_id *oid,
return 0;
if (p) {
- struct rev_info *revs = _data;
struct object_info oi = OBJECT_INFO_INIT;
oi.typep = &type;
@@ -3502,6 +3752,7 @@ static int add_object_entry_from_pack(const struct object_id *oid,
die(_("could not get type of object %s in pack %s"),
oid_to_hex(oid), p->pack_name);
} else if (type == OBJ_COMMIT) {
+ struct rev_info *revs = _data;
/*
* commits in included packs are used as starting points for the
* subsequent revision walk
@@ -3517,32 +3768,48 @@ static int add_object_entry_from_pack(const struct object_id *oid,
return 0;
}
-static void show_commit_pack_hint(struct commit *commit UNUSED,
- void *data UNUSED)
+static void show_object_pack_hint(struct object *object, const char *name,
+ void *data)
{
- /* nothing to do; commits don't have a namehash */
+ enum stdin_packs_mode mode = *(enum stdin_packs_mode *)data;
+ if (mode == STDIN_PACKS_MODE_FOLLOW) {
+ if (object->type == OBJ_BLOB &&
+ !has_object(the_repository, &object->oid, 0))
+ return;
+ add_object_entry(&object->oid, object->type, name, 0);
+ } else {
+ struct object_entry *oe = packlist_find(&to_pack, &object->oid);
+ if (!oe)
+ return;
+
+ /*
+ * Our 'to_pack' list was constructed by iterating all
+ * objects packed in included packs, and so doesn't have
+ * a non-zero hash field that you would typically pick
+ * up during a reachability traversal.
+ *
+ * Make a best-effort attempt to fill in the ->hash and
+ * ->no_try_delta fields here in order to perhaps
+ * improve the delta selection process.
+ */
+ oe->hash = pack_name_hash_fn(name);
+ oe->no_try_delta = name && no_try_delta(name);
+
+ stdin_packs_hints_nr++;
+ }
}
-static void show_object_pack_hint(struct object *object, const char *name,
- void *data UNUSED)
+static void show_commit_pack_hint(struct commit *commit, void *data)
{
- struct object_entry *oe = packlist_find(&to_pack, &object->oid);
- if (!oe)
+ enum stdin_packs_mode mode = *(enum stdin_packs_mode *)data;
+
+ if (mode == STDIN_PACKS_MODE_FOLLOW) {
+ show_object_pack_hint((struct object *)commit, "", data);
return;
+ }
- /*
- * Our 'to_pack' list was constructed by iterating all objects packed in
- * included packs, and so doesn't have a non-zero hash field that you
- * would typically pick up during a reachability traversal.
- *
- * Make a best-effort attempt to fill in the ->hash and ->no_try_delta
- * here using a now in order to perhaps improve the delta selection
- * process.
- */
- oe->hash = pack_name_hash_fn(name);
- oe->no_try_delta = name && no_try_delta(name);
+ /* nothing to do; commits don't have a namehash */
- stdin_packs_hints_nr++;
}
static int pack_mtime_cmp(const void *_a, const void *_b)
@@ -3562,7 +3829,7 @@ static int pack_mtime_cmp(const void *_a, const void *_b)
return 0;
}
-static void read_packs_list_from_stdin(void)
+static void read_packs_list_from_stdin(struct rev_info *revs)
{
struct strbuf buf = STRBUF_INIT;
struct string_list include_packs = STRING_LIST_INIT_DUP;
@@ -3570,24 +3837,6 @@ static void read_packs_list_from_stdin(void)
struct string_list_item *item = NULL;
struct packed_git *p;
- struct rev_info revs;
-
- repo_init_revisions(the_repository, &revs, NULL);
- /*
- * Use a revision walk to fill in the namehash of objects in the include
- * packs. To save time, we'll avoid traversing through objects that are
- * in excluded packs.
- *
- * That may cause us to avoid populating all of the namehash fields of
- * all included objects, but our goal is best-effort, since this is only
- * an optimization during delta selection.
- */
- revs.no_kept_objects = 1;
- revs.keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
- revs.blob_objects = 1;
- revs.tree_objects = 1;
- revs.tag_objects = 1;
- revs.ignore_missing_links = 1;
while (strbuf_getline(&buf, stdin) != EOF) {
if (!buf.len)
@@ -3657,25 +3906,55 @@ static void read_packs_list_from_stdin(void)
struct packed_git *p = item->util;
for_each_object_in_pack(p,
add_object_entry_from_pack,
- &revs,
+ revs,
FOR_EACH_OBJECT_PACK_ORDER);
}
+ strbuf_release(&buf);
+ string_list_clear(&include_packs, 0);
+ string_list_clear(&exclude_packs, 0);
+}
+
+static void add_unreachable_loose_objects(struct rev_info *revs);
+
+static void read_stdin_packs(enum stdin_packs_mode mode, int rev_list_unpacked)
+{
+ struct rev_info revs;
+
+ repo_init_revisions(the_repository, &revs, NULL);
+ /*
+ * Use a revision walk to fill in the namehash of objects in the include
+ * packs. To save time, we'll avoid traversing through objects that are
+ * in excluded packs.
+ *
+ * That may cause us to avoid populating all of the namehash fields of
+ * all included objects, but our goal is best-effort, since this is only
+ * an optimization during delta selection.
+ */
+ revs.no_kept_objects = 1;
+ revs.keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
+ revs.blob_objects = 1;
+ revs.tree_objects = 1;
+ revs.tag_objects = 1;
+ revs.ignore_missing_links = 1;
+
+ /* avoids adding objects in excluded packs */
+ ignore_packed_keep_in_core = 1;
+ read_packs_list_from_stdin(&revs);
+ if (rev_list_unpacked)
+ add_unreachable_loose_objects(&revs);
+
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));
traverse_commit_list(&revs,
show_commit_pack_hint,
show_object_pack_hint,
- NULL);
+ &mode);
trace2_data_intmax("pack-objects", the_repository, "stdin_packs_found",
stdin_packs_found_nr);
trace2_data_intmax("pack-objects", the_repository, "stdin_packs_hints",
stdin_packs_hints_nr);
-
- strbuf_release(&buf);
- string_list_clear(&include_packs, 0);
- string_list_clear(&exclude_packs, 0);
}
static void add_cruft_object_entry(const struct object_id *oid, enum object_type type,
@@ -3695,7 +3974,14 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
} else {
if (!want_object_in_pack_mtime(oid, 0, &pack, &offset, mtime))
return;
- if (!pack && type == OBJ_BLOB && !has_loose_object(oid)) {
+ if (!pack && type == OBJ_BLOB) {
+ struct odb_source *source = the_repository->objects->sources;
+ int found = 0;
+
+ for (; !found && source; source = source->next)
+ if (has_loose_object(source, oid))
+ found = 1;
+
/*
* If a traversed tree has a missing blob then we want
* to avoid adding that missing object to our pack.
@@ -3709,7 +3995,8 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
* limited to "ensure non-tip blobs which don't exist in
* packs do exist via loose objects". Confused?
*/
- return;
+ if (!found)
+ return;
}
entry = create_object_entry(oid, type, pack_name_hash_fn(name),
@@ -3773,7 +4060,6 @@ static void mark_pack_kept_in_core(struct string_list *packs, unsigned keep)
}
}
-static void add_unreachable_loose_objects(void);
static void add_objects_in_unpacked_packs(void);
static void enumerate_cruft_objects(void)
@@ -3783,7 +4069,7 @@ static void enumerate_cruft_objects(void)
_("Enumerating cruft objects"), 0);
add_objects_in_unpacked_packs();
- add_unreachable_loose_objects();
+ add_unreachable_loose_objects(NULL);
stop_progress(&progress_state);
}
@@ -3966,7 +4252,7 @@ static void show_object__ma_allow_any(struct object *obj, const char *name, void
* Quietly ignore ALL missing objects. This avoids problems with
* staging them now and getting an odd error later.
*/
- if (!has_object(the_repository, &obj->oid, 0))
+ if (!odb_has_object(the_repository->objects, &obj->oid, 0))
return;
show_object(obj, name, data);
@@ -3980,7 +4266,7 @@ static void show_object__ma_allow_promisor(struct object *obj, const char *name,
* Quietly ignore EXPECTED missing objects. This avoids problems with
* staging them now and getting an odd error later.
*/
- if (!has_object(the_repository, &obj->oid, 0) &&
+ if (!odb_has_object(the_repository->objects, &obj->oid, 0) &&
is_promisor_object(to_pack.repo, &obj->oid))
return;
@@ -4061,9 +4347,10 @@ static void add_objects_in_unpacked_packs(void)
}
static int add_loose_object(const struct object_id *oid, const char *path,
- void *data UNUSED)
+ void *data)
{
- enum object_type type = oid_object_info(the_repository, oid, NULL);
+ struct rev_info *revs = data;
+ enum object_type type = odb_read_object_info(the_repository->objects, oid, NULL);
if (type < 0) {
warning(_("loose object at %s could not be examined"), path);
@@ -4083,6 +4370,10 @@ static int add_loose_object(const struct object_id *oid, const char *path,
} else {
add_object_entry(oid, type, "", 0);
}
+
+ if (revs && type == OBJ_COMMIT)
+ add_pending_oid(revs, NULL, oid, 0);
+
return 0;
}
@@ -4091,11 +4382,10 @@ static int add_loose_object(const struct object_id *oid, const char *path,
* add_object_entry will weed out duplicates, so we just add every
* loose object we find.
*/
-static void add_unreachable_loose_objects(void)
+static void add_unreachable_loose_objects(struct rev_info *revs)
{
- for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
- add_loose_object,
- NULL, NULL, NULL);
+ for_each_loose_file_in_source(the_repository->objects->sources,
+ add_loose_object, NULL, NULL, revs);
}
static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
@@ -4163,7 +4453,8 @@ static void loosen_unused_packed_objects(void)
if (!packlist_find(&to_pack, &oid) &&
!has_sha1_pack_kept_or_nonlocal(&oid) &&
!loosened_object_can_be_discarded(&oid, p->mtime)) {
- if (force_object_loose(&oid, p->mtime))
+ if (force_object_loose(the_repository->objects->sources,
+ &oid, p->mtime))
die(_("unable to force loose object"));
loosened_objects_nr++;
}
@@ -4272,6 +4563,93 @@ static void mark_bitmap_preferred_tips(void)
}
}
+static inline int is_oid_uninteresting(struct repository *repo,
+ struct object_id *oid)
+{
+ struct object *o = lookup_object(repo, oid);
+ return !o || (o->flags & UNINTERESTING);
+}
+
+static int add_objects_by_path(const char *path,
+ struct oid_array *oids,
+ enum object_type type,
+ void *data)
+{
+ size_t oe_start = to_pack.nr_objects;
+ size_t oe_end;
+ unsigned int *processed = data;
+
+ /*
+ * First, add all objects to the packing data, including the ones
+ * marked UNINTERESTING (translated to 'exclude') as they can be
+ * used as delta bases.
+ */
+ for (size_t i = 0; i < oids->nr; i++) {
+ int exclude;
+ struct object_info oi = OBJECT_INFO_INIT;
+ struct object_id *oid = &oids->oid[i];
+
+ /* Skip objects that do not exist locally. */
+ if ((exclude_promisor_objects || arg_missing_action != MA_ERROR) &&
+ oid_object_info_extended(the_repository, oid, &oi,
+ OBJECT_INFO_FOR_PREFETCH) < 0)
+ continue;
+
+ exclude = is_oid_uninteresting(the_repository, oid);
+
+ if (exclude && !thin)
+ continue;
+
+ add_object_entry(oid, type, path, exclude);
+ }
+
+ oe_end = to_pack.nr_objects;
+
+ /* We can skip delta calculations if it is a no-op. */
+ if (oe_end == oe_start || !window)
+ return 0;
+
+ ALLOC_GROW(to_pack.regions,
+ to_pack.nr_regions + 1,
+ to_pack.nr_regions_alloc);
+
+ to_pack.regions[to_pack.nr_regions].start = oe_start;
+ to_pack.regions[to_pack.nr_regions].nr = oe_end - oe_start;
+ to_pack.nr_regions++;
+
+ *processed += oids->nr;
+ display_progress(progress_state, *processed);
+
+ return 0;
+}
+
+static void get_object_list_path_walk(struct rev_info *revs)
+{
+ struct path_walk_info info = PATH_WALK_INFO_INIT;
+ unsigned int processed = 0;
+ int result;
+
+ info.revs = revs;
+ info.path_fn = add_objects_by_path;
+ info.path_fn_data = &processed;
+
+ /*
+ * Allow the --[no-]sparse option to be interesting here, if only
+ * for testing purposes. Paths with no interesting objects will not
+ * contribute to the resulting pack, but only create noisy preferred
+ * base objects.
+ */
+ info.prune_all_uninteresting = sparse;
+ info.edge_aggressive = shallow;
+
+ trace2_region_enter("pack-objects", "path-walk", revs->repo);
+ result = walk_objects_by_path(&info);
+ trace2_region_leave("pack-objects", "path-walk", revs->repo);
+
+ if (result)
+ die(_("failed to pack objects via path-walk"));
+}
+
static void get_object_list(struct rev_info *revs, int ac, const char **av)
{
struct setup_revision_opt s_r_opt = {
@@ -4327,15 +4705,19 @@ static void get_object_list(struct rev_info *revs, int ac, const char **av)
if (write_bitmap_index)
mark_bitmap_preferred_tips();
- if (prepare_revision_walk(revs))
- die(_("revision walk setup failed"));
- mark_edges_uninteresting(revs, show_edge, sparse);
-
if (!fn_show_object)
fn_show_object = show_object;
- traverse_commit_list(revs,
- show_commit, fn_show_object,
- NULL);
+
+ if (path_walk) {
+ get_object_list_path_walk(revs);
+ } else {
+ if (prepare_revision_walk(revs))
+ die(_("revision walk setup failed"));
+ mark_edges_uninteresting(revs, show_edge, sparse);
+ traverse_commit_list(revs,
+ show_commit, fn_show_object,
+ NULL);
+ }
if (unpack_unreachable_expiration) {
revs->ignore_missing_links = 1;
@@ -4351,7 +4733,7 @@ static void get_object_list(struct rev_info *revs, int ac, const char **av)
if (keep_unreachable)
add_objects_in_unpacked_packs();
if (pack_loose_unreachable)
- add_unreachable_loose_objects();
+ add_unreachable_loose_objects(NULL);
if (unpack_unreachable)
loosen_unused_packed_objects();
@@ -4449,7 +4831,7 @@ static int option_parse_cruft_expiration(const struct option *opt UNUSED,
static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
{
struct object_info info = OBJECT_INFO_INIT;
- if (oid_object_info_extended(the_repository, &obj->oid, &info, 0))
+ if (odb_read_object_info_extended(the_repository->objects, &obj->oid, &info, 0))
BUG("should_include_obj should only be called on existing objects");
return info.whence != OI_PACKED || !info.u.packed.pack->pack_promisor;
}
@@ -4458,18 +4840,34 @@ static int is_not_in_promisor_pack(struct commit *commit, void *data) {
return is_not_in_promisor_pack_obj((struct object *) commit, data);
}
+static int parse_stdin_packs_mode(const struct option *opt, const char *arg,
+ int unset)
+{
+ enum stdin_packs_mode *mode = opt->value;
+
+ if (unset)
+ *mode = STDIN_PACKS_MODE_NONE;
+ else if (!arg || !*arg)
+ *mode = STDIN_PACKS_MODE_STANDARD;
+ else if (!strcmp(arg, "follow"))
+ *mode = STDIN_PACKS_MODE_FOLLOW;
+ else
+ die(_("invalid value for '%s': '%s'"), opt->long_name, arg);
+
+ return 0;
+}
+
int cmd_pack_objects(int argc,
const char **argv,
const char *prefix,
struct repository *repo UNUSED)
{
int use_internal_rev_list = 0;
- int shallow = 0;
int all_progress_implied = 0;
struct strvec rp = STRVEC_INIT;
int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
int rev_list_index = 0;
- int stdin_packs = 0;
+ enum stdin_packs_mode stdin_packs = STDIN_PACKS_MODE_NONE;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
struct list_objects_filter_options filter_options =
LIST_OBJECTS_FILTER_INIT;
@@ -4524,6 +4922,9 @@ int cmd_pack_objects(int argc,
OPT_SET_INT_F(0, "indexed-objects", &rev_list_index,
N_("include objects referred to by the index"),
1, PARSE_OPT_NONEG),
+ OPT_CALLBACK_F(0, "stdin-packs", &stdin_packs, N_("mode"),
+ N_("read packs from stdin"),
+ PARSE_OPT_OPTARG, parse_stdin_packs_mode),
OPT_BOOL(0, "stdin-packs", &stdin_packs,
N_("read packs from stdin")),
OPT_BOOL(0, "stdout", &pack_to_stdout,
@@ -4545,6 +4946,8 @@ int cmd_pack_objects(int argc,
N_("use the sparse reachability algorithm")),
OPT_BOOL(0, "thin", &thin,
N_("create thin packs")),
+ OPT_BOOL(0, "path-walk", &path_walk,
+ N_("use the path-walk API to walk objects when possible")),
OPT_BOOL(0, "shallow", &shallow,
N_("create packs suitable for shallow fetches")),
OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep_on_disk,
@@ -4599,7 +5002,7 @@ int cmd_pack_objects(int argc,
reset_pack_idx_option(&pack_idx_opts);
pack_idx_opts.flags |= WRITE_REV;
- git_config(git_pack_config, NULL);
+ repo_config(the_repository, git_pack_config, NULL);
if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
pack_idx_opts.flags &= ~WRITE_REV;
@@ -4614,6 +5017,17 @@ int cmd_pack_objects(int argc,
if (pack_to_stdout != !base_name || argc)
usage_with_options(pack_usage, pack_objects_options);
+ if (path_walk < 0) {
+ if (use_bitmap_index > 0 ||
+ !use_internal_rev_list)
+ path_walk = 0;
+ else if (the_repository->gitdir &&
+ the_repository->settings.pack_use_path_walk)
+ path_walk = 1;
+ else
+ path_walk = git_env_bool("GIT_TEST_PACK_PATH_WALK", 0);
+ }
+
if (depth < 0)
depth = 0;
if (depth >= (1 << OE_DEPTH_BITS)) {
@@ -4630,7 +5044,28 @@ int cmd_pack_objects(int argc,
window = 0;
strvec_push(&rp, "pack-objects");
- if (thin) {
+
+ if (path_walk) {
+ const char *option = NULL;
+ if (filter_options.choice)
+ option = "--filter";
+ else if (use_delta_islands)
+ option = "--delta-islands";
+
+ if (option) {
+ warning(_("cannot use %s with %s"),
+ option, "--path-walk");
+ path_walk = 0;
+ }
+ }
+ if (path_walk) {
+ strvec_push(&rp, "--boundary");
+ /*
+ * We must disable the bitmaps because we are removing
+ * the --objects / --objects-edge[-aggressive] options.
+ */
+ use_bitmap_index = 0;
+ } else if (thin) {
use_internal_rev_list = 1;
strvec_push(&rp, shallow
? "--objects-edge-aggressive"
@@ -4655,9 +5090,10 @@ int cmd_pack_objects(int argc,
strvec_push(&rp, "--unpacked");
}
- if (exclude_promisor_objects && exclude_promisor_objects_best_effort)
- die(_("options '%s' and '%s' cannot be used together"),
- "--exclude-promisor-objects", "--exclude-promisor-objects-best-effort");
+ die_for_incompatible_opt2(exclude_promisor_objects,
+ "--exclude-promisor-objects",
+ exclude_promisor_objects_best_effort,
+ "--exclude-promisor-objects-best-effort");
if (exclude_promisor_objects) {
use_internal_rev_list = 1;
fetch_if_missing = 0;
@@ -4695,13 +5131,14 @@ int cmd_pack_objects(int argc,
if (!pack_to_stdout && thin)
die(_("--thin cannot be used to build an indexable pack"));
- if (keep_unreachable && unpack_unreachable)
- die(_("options '%s' and '%s' cannot be used together"), "--keep-unreachable", "--unpack-unreachable");
+ die_for_incompatible_opt2(keep_unreachable, "--keep-unreachable",
+ unpack_unreachable, "--unpack-unreachable");
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
unpack_unreachable_expiration = 0;
- if (stdin_packs && filter_options.choice)
- die(_("cannot use --filter with --stdin-packs"));
+ die_for_incompatible_opt2(stdin_packs, "--stdin-packs",
+ filter_options.choice, "--filter");
+
if (stdin_packs && use_internal_rev_list)
die(_("cannot use internal rev list with --stdin-packs"));
@@ -4709,8 +5146,8 @@ int cmd_pack_objects(int argc,
if (cruft) {
if (use_internal_rev_list)
die(_("cannot use internal rev list with --cruft"));
- if (stdin_packs)
- die(_("cannot use --stdin-packs with --cruft"));
+ die_for_incompatible_opt2(stdin_packs, "--stdin-packs",
+ cruft, "--cruft");
}
/*
@@ -4778,11 +5215,7 @@ int cmd_pack_objects(int argc,
progress_state = start_progress(the_repository,
_("Enumerating objects"), 0);
if (stdin_packs) {
- /* avoids adding objects in excluded packs */
- ignore_packed_keep_in_core = 1;
- read_packs_list_from_stdin();
- if (rev_list_unpacked)
- add_unreachable_loose_objects();
+ read_stdin_packs(stdin_packs, rev_list_unpacked);
} else if (cruft) {
read_cruft_objects();
} else if (!use_internal_rev_list) {
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 5d1fc78176..fe81c293e3 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -13,7 +13,7 @@
#include "hex.h"
#include "packfile.h"
-#include "object-store.h"
+#include "odb.h"
#include "strbuf.h"
#define BLKSIZE 512
@@ -625,14 +625,8 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, s
break;
}
- if (!i_still_use_this) {
- fputs(_("'git pack-redundant' is nominated for removal.\n"
- "If you still use this command, please add an extra\n"
- "option, '--i-still-use-this', on the command line\n"
- "and let us know you still use it by sending an e-mail\n"
- "to <git@vger.kernel.org>. Thanks.\n"), stderr);
- die(_("refusing to run without --i-still-use-this"));
- }
+ if (!i_still_use_this)
+ you_still_use_that("git pack-redundant");
if (load_all_packs)
load_all();
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index e47bae1c80..5e28d0f9e8 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "refs.h"
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index cdef2ec10a..d26e9d0c1e 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -3,6 +3,7 @@
#include "builtin.h"
#include "config.h"
#include "diff.h"
+#include "environment.h"
#include "gettext.h"
#include "hash.h"
#include "hex.h"
@@ -235,7 +236,7 @@ int cmd_patch_id(int argc,
OPT_END()
};
- git_config(git_patch_id_config, &config);
+ repo_config(the_repository, git_patch_id_config, &config);
/* verbatim implies stable */
if (config.verbatim)
@@ -254,7 +255,7 @@ int cmd_patch_id(int argc,
* the code that computes patch IDs to always use SHA1.
*/
if (!the_hash_algo)
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+ repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
generate_id_list(opts ? opts > 1 : config.stable,
opts ? opts == 3 : config.verbatim);
diff --git a/builtin/prune.c b/builtin/prune.c
index e930caa0c0..55635a891f 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
#define DISABLE_SIGN_COMPARE_WARNINGS
#include "builtin.h"
@@ -17,7 +16,7 @@
#include "replace-object.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "shallow.h"
static const char * const prune_usage[] = {
@@ -64,7 +63,7 @@ static void perform_reachability_traversal(struct rev_info *revs)
return;
if (show_progress)
- progress = start_delayed_progress(the_repository,
+ progress = start_delayed_progress(revs->repo,
_("Checking connectivity"), 0);
mark_reachable_objects(revs, 1, expire, progress);
stop_progress(&progress);
@@ -78,7 +77,7 @@ static int is_object_reachable(const struct object_id *oid,
perform_reachability_traversal(revs);
- obj = lookup_object(the_repository, oid);
+ obj = lookup_object(revs->repo, oid);
return obj && (obj->flags & SEEN);
}
@@ -99,8 +98,8 @@ static int prune_object(const struct object_id *oid, const char *fullpath,
if (st.st_mtime > expire)
return 0;
if (show_only || verbose) {
- enum object_type type = oid_object_info(the_repository, oid,
- NULL);
+ enum object_type type =
+ odb_read_object_info(revs->repo->objects, oid, NULL);
printf("%s %s\n", oid_to_hex(oid),
(type > 0) ? type_name(type) : "unknown");
}
@@ -154,7 +153,7 @@ static void remove_temporary_files(const char *path)
int cmd_prune(int argc,
const char **argv,
const char *prefix,
- struct repository *repo UNUSED)
+ struct repository *repo)
{
struct rev_info revs;
int exclude_promisor_objects = 0;
@@ -173,20 +172,19 @@ int cmd_prune(int argc,
expire = TIME_MAX;
save_commit_buffer = 0;
disable_replace_refs();
- repo_init_revisions(the_repository, &revs, prefix);
argc = parse_options(argc, argv, prefix, options, prune_usage, 0);
- if (repository_format_precious_objects)
+ repo_init_revisions(repo, &revs, prefix);
+ if (repo->repository_format_precious_objects)
die(_("cannot prune in a precious-objects repo"));
while (argc--) {
struct object_id oid;
const char *name = *argv++;
- if (!repo_get_oid(the_repository, name, &oid)) {
- struct object *object = parse_object_or_die(the_repository, &oid,
- name);
+ if (!repo_get_oid(repo, name, &oid)) {
+ struct object *object = parse_object_or_die(repo, &oid, name);
add_pending_object(&revs, object, "");
}
else
@@ -200,16 +198,16 @@ int cmd_prune(int argc,
revs.exclude_promisor_objects = 1;
}
- for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+ for_each_loose_file_in_source(repo->objects->sources,
prune_object, prune_cruft, prune_subdir, &revs);
prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0);
- remove_temporary_files(repo_get_object_directory(the_repository));
- s = mkpathdup("%s/pack", repo_get_object_directory(the_repository));
+ remove_temporary_files(repo_get_object_directory(repo));
+ s = mkpathdup("%s/pack", repo_get_object_directory(repo));
remove_temporary_files(s);
free(s);
- if (is_repository_shallow(the_repository)) {
+ if (is_repository_shallow(repo)) {
perform_reachability_traversal(&revs);
prune_shallow(show_only ? PRUNE_SHOW_ONLY : 0);
}
diff --git a/builtin/pull.c b/builtin/pull.c
index a1ebc6ad33..5ebd529620 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -11,6 +11,7 @@
#include "builtin.h"
#include "advice.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "merge.h"
@@ -90,7 +91,8 @@ static char *opt_ff;
static const char *opt_verify_signatures;
static const char *opt_verify;
static int opt_autostash = -1;
-static int config_autostash;
+static int config_rebase_autostash;
+static int config_pull_autostash = -1;
static int check_trust_level = 1;
static struct strvec opt_strategies = STRVEC_INIT;
static struct strvec opt_strategy_opts = STRVEC_INIT;
@@ -143,6 +145,9 @@ static struct option pull_options[] = {
OPT_PASSTHRU(0, "summary", &opt_diffstat, NULL,
N_("(synonym to --stat)"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
+ OPT_PASSTHRU(0, "compact-summary", &opt_diffstat, NULL,
+ N_("show a compact-summary at the end of the merge"),
+ PARSE_OPT_NOARG),
OPT_PASSTHRU(0, "log", &opt_log, N_("n"),
N_("add (at most <n>) entries from shortlog to merge commit message"),
PARSE_OPT_OPTARG),
@@ -309,7 +314,7 @@ static const char *config_get_ff(void)
{
const char *value;
- if (git_config_get_value("pull.ff", &value))
+ if (repo_config_get_value(the_repository, "pull.ff", &value))
return NULL;
switch (git_parse_maybe_bool(value)) {
@@ -340,7 +345,7 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified)
if (curr_branch) {
char *key = xstrfmt("branch.%s.rebase", curr_branch->name);
- if (!git_config_get_value(key, &value)) {
+ if (!repo_config_get_value(the_repository, key, &value)) {
enum rebase_type ret = parse_config_rebase(key, value, 1);
free(key);
return ret;
@@ -349,7 +354,7 @@ static enum rebase_type config_get_rebase(int *rebase_unspecified)
free(key);
}
- if (!git_config_get_value("pull.rebase", &value))
+ if (!repo_config_get_value(the_repository, "pull.rebase", &value))
return parse_config_rebase("pull.rebase", value, 1);
*rebase_unspecified = 1;
@@ -364,7 +369,18 @@ static int git_pull_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
if (!strcmp(var, "rebase.autostash")) {
- config_autostash = git_config_bool(var, value);
+ /*
+ * run_rebase() also reads this option. The reason we handle it here is
+ * that when pull.rebase is true, a fast-forward may occur without
+ * invoking run_rebase(). We need to ensure that autostash is set even
+ * in the fast-forward case.
+ *
+ * run_merge() handles merge.autostash, so we don't handle it here.
+ */
+ config_rebase_autostash = git_config_bool(var, value);
+ return 0;
+ } else if (!strcmp(var, "pull.autostash")) {
+ config_pull_autostash = git_config_bool(var, value);
return 0;
} else if (!strcmp(var, "submodule.recurse")) {
recurse_submodules = git_config_bool(var, value) ?
@@ -487,7 +503,7 @@ static void NORETURN die_no_merge_candidates(const char *repo, const char **refs
} else
fprintf_ln(stderr, _("Your configuration specifies to merge with the ref '%s'\n"
"from the remote, but no such ref was fetched."),
- *curr_branch->merge_name);
+ curr_branch->merge[0]->src);
exit(1);
}
@@ -996,13 +1012,15 @@ int cmd_pull(int argc,
if (!getenv("GIT_REFLOG_ACTION"))
set_reflog_message(argc, argv);
- git_config(git_pull_config, NULL);
+ repo_config(the_repository, git_pull_config, NULL);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
}
argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
+ if (opt_autostash == -1)
+ opt_autostash = config_pull_autostash;
if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
recurse_submodules = recurse_submodules_cli;
@@ -1049,7 +1067,7 @@ int cmd_pull(int argc,
if (opt_rebase) {
if (opt_autostash == -1)
- opt_autostash = config_autostash;
+ opt_autostash = config_rebase_autostash;
if (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index))
die(_("Updating an unborn branch with changes added to the index."));
diff --git a/builtin/push.c b/builtin/push.c
index 92d530e5c4..d0794b7b30 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -598,7 +598,7 @@ int cmd_push(int argc,
};
packet_trace_identity("push");
- git_config(git_push_config, &flags);
+ repo_config(the_repository, git_push_config, &flags);
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
push_options = (push_options_cmdline.nr
? &push_options_cmdline
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index 32ddb6613f..a563abff5f 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -54,7 +54,7 @@ int cmd_range_diff(int argc,
struct object_id oid;
const char *three_dots = NULL;
- git_config(git_diff_ui_config, NULL);
+ repo_config(the_repository, git_diff_ui_config, NULL);
repo_diff_setup(the_repository, &diffopt);
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index a8f352f7cd..34f7a59f38 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -6,6 +6,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
@@ -168,7 +169,7 @@ int cmd_read_tree(int argc,
opts.src_index = the_repository->index;
opts.dst_index = the_repository->index;
- git_config(git_read_tree_config, NULL);
+ repo_config(the_repository, git_read_tree_config, NULL);
argc = parse_options(argc, argv, cmd_prefix, read_tree_options,
read_tree_usage, 0);
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 2e8c4ee678..3c85768d29 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -293,15 +293,6 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
&revisions, &shortrevisions))
goto cleanup;
- if (init_basic_state(&replay,
- opts->head_name ? opts->head_name : "detached HEAD",
- opts->onto, &opts->orig_head->object.oid))
- goto cleanup;
-
- if (!opts->upstream && opts->squash_onto)
- write_file(path_squash_onto(), "%s\n",
- oid_to_hex(opts->squash_onto));
-
strvec_pushl(&make_script_args, "", revisions, NULL);
if (opts->restrict_revision)
strvec_pushf(&make_script_args, "^%s",
@@ -310,21 +301,30 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
ret = sequencer_make_script(the_repository, &todo_list.buf,
make_script_args.nr, make_script_args.v,
flags);
-
- if (ret)
+ if (ret) {
error(_("could not generate todo list"));
- else {
- discard_index(the_repository->index);
- if (todo_list_parse_insn_buffer(the_repository, &replay,
- todo_list.buf.buf, &todo_list))
- BUG("unusable todo list");
-
- ret = complete_action(the_repository, &replay, flags,
- shortrevisions, opts->onto_name, opts->onto,
- &opts->orig_head->object.oid, &opts->exec,
- opts->autosquash, opts->update_refs, &todo_list);
+ goto cleanup;
}
+ if (init_basic_state(&replay,
+ opts->head_name ? opts->head_name : "detached HEAD",
+ opts->onto, &opts->orig_head->object.oid))
+ goto cleanup;
+
+ if (!opts->upstream && opts->squash_onto)
+ write_file(path_squash_onto(), "%s\n",
+ oid_to_hex(opts->squash_onto));
+
+ discard_index(the_repository->index);
+ if (todo_list_parse_insn_buffer(the_repository, &replay,
+ todo_list.buf.buf, &todo_list))
+ BUG("unusable todo list");
+
+ ret = complete_action(the_repository, &replay, flags,
+ shortrevisions, opts->onto_name, opts->onto,
+ &opts->orig_head->object.oid, &opts->exec,
+ opts->autosquash, opts->update_refs, &todo_list);
+
cleanup:
replay_opts_release(&replay);
free(revisions);
@@ -340,7 +340,7 @@ static int run_sequencer_rebase(struct rebase_options *opts)
unsigned flags = 0;
int abbreviate_commands = 0, ret = 0;
- git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
+ repo_config_get_bool(the_repository, "rebase.abbreviatecommands", &abbreviate_commands);
flags |= opts->keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
@@ -1128,6 +1128,7 @@ int cmd_rebase(int argc,
.short_name = 'n',
.long_name = "no-stat",
.value = &options.flags,
+ .precision = sizeof(options.flags),
.help = N_("do not show diffstat of what changed upstream"),
.flags = PARSE_OPT_NOARG,
.defval = REBASE_DIFFSTAT,
@@ -1244,7 +1245,7 @@ int cmd_rebase(int argc,
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- git_config(rebase_config, &options);
+ repo_config(the_repository, rebase_config, &options);
/* options.gpg_sign_opt will be either "-S" or NULL */
gpg_sign = options.gpg_sign_opt ? "" : NULL;
FREE_AND_NULL(options.gpg_sign_opt);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index a317d6c278..1113137a6f 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -33,7 +33,7 @@
#include "packfile.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "path.h"
#include "protocol.h"
#include "commit-reach.h"
@@ -359,7 +359,8 @@ static void write_head_info(void)
refs_for_each_fullref_in(get_main_ref_store(the_repository), "",
exclude_patterns, show_ref_cb, &seen);
- for_each_alternate_ref(show_one_alternate_ref, &seen);
+ odb_for_each_alternate_ref(the_repository->objects,
+ show_one_alternate_ref, &seen);
oidset_clear(&seen);
strvec_clear(&excludes_vector);
@@ -759,8 +760,8 @@ static void prepare_push_cert_sha1(struct child_process *proc)
int bogs /* beginning_of_gpg_sig */;
already_done = 1;
- if (write_object_file(push_cert.buf, push_cert.len, OBJ_BLOB,
- &push_cert_oid))
+ if (odb_write_object(the_repository->objects, push_cert.buf,
+ push_cert.len, OBJ_BLOB, &push_cert_oid))
oidclr(&push_cert_oid, the_repository->hash_algo);
memset(&sigcheck, '\0', sizeof(sigcheck));
@@ -1508,8 +1509,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
if (!is_null_oid(new_oid) &&
- !has_object(the_repository, new_oid,
- HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR)) {
+ !odb_has_object(the_repository->objects, new_oid,
+ HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR)) {
error("unpack should have generated %s, "
"but I can't find it!", oid_to_hex(new_oid));
ret = "bad pack";
@@ -1846,36 +1847,102 @@ static void BUG_if_skipped_connectivity_check(struct command *commands,
BUG_if_bug("connectivity check skipped???");
}
+static void ref_transaction_rejection_handler(const char *refname,
+ const struct object_id *old_oid UNUSED,
+ const struct object_id *new_oid UNUSED,
+ const char *old_target UNUSED,
+ const char *new_target UNUSED,
+ enum ref_transaction_error err,
+ void *cb_data)
+{
+ struct strmap *failed_refs = cb_data;
+
+ strmap_put(failed_refs, refname, (char *)ref_transaction_error_msg(err));
+}
+
static void execute_commands_non_atomic(struct command *commands,
struct shallow_info *si)
{
struct command *cmd;
struct strbuf err = STRBUF_INIT;
+ const char *reported_error = NULL;
+ struct strmap failed_refs = STRMAP_INIT;
- for (cmd = commands; cmd; cmd = cmd->next) {
- if (!should_process_cmd(cmd) || cmd->run_proc_receive)
- continue;
+ /*
+ * Reference updates, where D/F conflicts shouldn't arise due to
+ * one reference being deleted, while the other being created
+ * are treated as conflicts in batched updates. This is because
+ * we don't do conflict resolution inside a transaction. To
+ * mitigate this, delete references in a separate batch.
+ *
+ * NEEDSWORK: Add conflict resolution between deletion and creation
+ * of reference updates within a transaction. With that, we can
+ * combine the two phases.
+ */
+ enum processing_phase {
+ PHASE_DELETIONS,
+ PHASE_OTHERS
+ };
- transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
- 0, &err);
- if (!transaction) {
- rp_error("%s", err.buf);
- strbuf_reset(&err);
- cmd->error_string = "transaction failed to start";
- continue;
+ for (enum processing_phase phase = PHASE_DELETIONS; phase <= PHASE_OTHERS; phase++) {
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (!should_process_cmd(cmd) || cmd->run_proc_receive)
+ continue;
+
+ if (phase == PHASE_DELETIONS && !is_null_oid(&cmd->new_oid))
+ continue;
+ else if (phase == PHASE_OTHERS && is_null_oid(&cmd->new_oid))
+ continue;
+
+ /*
+ * Lazily create a transaction only when we know there are
+ * updates to be added.
+ */
+ if (!transaction) {
+ transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ REF_TRANSACTION_ALLOW_FAILURE, &err);
+ if (!transaction) {
+ rp_error("%s", err.buf);
+ strbuf_reset(&err);
+ reported_error = "transaction failed to start";
+ goto failure;
+ }
+ }
+
+ cmd->error_string = update(cmd, si);
}
- cmd->error_string = update(cmd, si);
+ /* No transaction, so nothing to commit */
+ if (!transaction)
+ goto cleanup;
- if (!cmd->error_string
- && ref_transaction_commit(transaction, &err)) {
+ if (ref_transaction_commit(transaction, &err)) {
rp_error("%s", err.buf);
- strbuf_reset(&err);
- cmd->error_string = "failed to update ref";
+ reported_error = "failed to update refs";
+ goto failure;
}
+
+ ref_transaction_for_each_rejected_update(transaction,
+ ref_transaction_rejection_handler,
+ &failed_refs);
+
+ if (strmap_empty(&failed_refs))
+ goto cleanup;
+
+ failure:
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (reported_error)
+ cmd->error_string = reported_error;
+ else if (strmap_contains(&failed_refs, cmd->ref_name))
+ cmd->error_string = strmap_get(&failed_refs, cmd->ref_name);
+ }
+
+ cleanup:
ref_transaction_free(transaction);
+ transaction = NULL;
+ strmap_clear(&failed_refs, 0);
+ strbuf_release(&err);
}
- strbuf_release(&err);
}
static void execute_commands_atomic(struct command *commands,
@@ -2136,7 +2203,7 @@ static struct command *read_head_info(struct packet_reader *reader,
use_push_options = 1;
hash = parse_feature_value(feature_list, "object-format", &len, NULL);
if (!hash) {
- hash = hash_algos[GIT_HASH_SHA1].name;
+ hash = hash_algos[GIT_HASH_SHA1_LEGACY].name;
len = strlen(hash);
}
if (xstrncmpz(the_hash_algo->name, hash, len))
@@ -2546,7 +2613,7 @@ int cmd_receive_pack(int argc,
if (!enter_repo(service_dir, 0))
die("'%s' does not appear to be a git repository", service_dir);
- git_config(receive_pack_config, NULL);
+ repo_config(the_repository, receive_pack_config, NULL);
if (cert_nonce_seed)
push_cert_nonce = prepare_push_cert_nonce(service_dir, time(NULL));
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 3acaf3e32c..c8f6b93d60 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -3,6 +3,8 @@
#include "builtin.h"
#include "config.h"
#include "gettext.h"
+#include "hex.h"
+#include "odb.h"
#include "revision.h"
#include "reachable.h"
#include "wildmatch.h"
@@ -17,21 +19,24 @@
#define BUILTIN_REFLOG_LIST_USAGE \
N_("git reflog list")
-#define BUILTIN_REFLOG_EXPIRE_USAGE \
- N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
- " [--rewrite] [--updateref] [--stale-fix]\n" \
- " [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
+#define BUILTIN_REFLOG_EXISTS_USAGE \
+ N_("git reflog exists <ref>")
+
+#define BUILTIN_REFLOG_WRITE_USAGE \
+ N_("git reflog write <ref> <old-oid> <new-oid> <message>")
#define BUILTIN_REFLOG_DELETE_USAGE \
N_("git reflog delete [--rewrite] [--updateref]\n" \
" [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
-#define BUILTIN_REFLOG_EXISTS_USAGE \
- N_("git reflog exists <ref>")
-
#define BUILTIN_REFLOG_DROP_USAGE \
N_("git reflog drop [--all [--single-worktree] | <refs>...]")
+#define BUILTIN_REFLOG_EXPIRE_USAGE \
+ N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
+ " [--rewrite] [--updateref] [--stale-fix]\n" \
+ " [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
+
static const char *const reflog_show_usage[] = {
BUILTIN_REFLOG_SHOW_USAGE,
NULL,
@@ -42,9 +47,14 @@ static const char *const reflog_list_usage[] = {
NULL,
};
-static const char *const reflog_expire_usage[] = {
- BUILTIN_REFLOG_EXPIRE_USAGE,
- NULL
+static const char *const reflog_exists_usage[] = {
+ BUILTIN_REFLOG_EXISTS_USAGE,
+ NULL,
+};
+
+static const char *const reflog_write_usage[] = {
+ BUILTIN_REFLOG_WRITE_USAGE,
+ NULL,
};
static const char *const reflog_delete_usage[] = {
@@ -52,23 +62,24 @@ static const char *const reflog_delete_usage[] = {
NULL
};
-static const char *const reflog_exists_usage[] = {
- BUILTIN_REFLOG_EXISTS_USAGE,
- NULL,
-};
-
static const char *const reflog_drop_usage[] = {
BUILTIN_REFLOG_DROP_USAGE,
NULL,
};
+static const char *const reflog_expire_usage[] = {
+ BUILTIN_REFLOG_EXPIRE_USAGE,
+ NULL
+};
+
static const char *const reflog_usage[] = {
BUILTIN_REFLOG_SHOW_USAGE,
BUILTIN_REFLOG_LIST_USAGE,
- BUILTIN_REFLOG_EXPIRE_USAGE,
+ BUILTIN_REFLOG_EXISTS_USAGE,
+ BUILTIN_REFLOG_WRITE_USAGE,
BUILTIN_REFLOG_DELETE_USAGE,
BUILTIN_REFLOG_DROP_USAGE,
- BUILTIN_REFLOG_EXISTS_USAGE,
+ BUILTIN_REFLOG_EXPIRE_USAGE,
NULL
};
@@ -202,7 +213,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix,
OPT_END()
};
- git_config(reflog_expire_config, &opts);
+ repo_config(the_repository, reflog_expire_config, &opts);
save_commit_buffer = 0;
do_all = status = 0;
@@ -283,6 +294,9 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix,
&cb);
free(ref);
}
+
+ reflog_clear_expire_config(&opts);
+
return status;
}
@@ -392,6 +406,59 @@ static int cmd_reflog_drop(int argc, const char **argv, const char *prefix,
return ret;
}
+static int cmd_reflog_write(int argc, const char **argv, const char *prefix,
+ struct repository *repo)
+{
+ const struct option options[] = {
+ OPT_END()
+ };
+ struct object_id old_oid, new_oid;
+ struct strbuf err = STRBUF_INIT;
+ struct ref_transaction *tx;
+ const char *ref, *message;
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, options, reflog_write_usage, 0);
+ if (argc != 4)
+ usage_with_options(reflog_write_usage, options);
+
+ ref = argv[0];
+ if (!is_root_ref(ref) && check_refname_format(ref, 0))
+ die(_("invalid reference name: %s"), ref);
+
+ ret = get_oid_hex_algop(argv[1], &old_oid, repo->hash_algo);
+ if (ret)
+ die(_("invalid old object ID: '%s'"), argv[1]);
+ if (!is_null_oid(&old_oid) && !odb_has_object(repo->objects, &old_oid, 0))
+ die(_("old object '%s' does not exist"), argv[1]);
+
+ ret = get_oid_hex_algop(argv[2], &new_oid, repo->hash_algo);
+ if (ret)
+ die(_("invalid new object ID: '%s'"), argv[2]);
+ if (!is_null_oid(&new_oid) && !odb_has_object(repo->objects, &new_oid, 0))
+ die(_("new object '%s' does not exist"), argv[2]);
+
+ message = argv[3];
+
+ tx = ref_store_transaction_begin(get_main_ref_store(repo), 0, &err);
+ if (!tx)
+ die(_("cannot start transaction: %s"), err.buf);
+
+ ret = ref_transaction_update_reflog(tx, ref, &new_oid, &old_oid,
+ git_committer_info(0),
+ message, 0, &err);
+ if (ret)
+ die(_("cannot queue reflog update: %s"), err.buf);
+
+ ret = ref_transaction_commit(tx, &err);
+ if (ret)
+ die(_("cannot commit reflog update: %s"), err.buf);
+
+ ref_transaction_free(tx);
+ strbuf_release(&err);
+ return 0;
+}
+
/*
* main "reflog"
*/
@@ -404,10 +471,11 @@ int cmd_reflog(int argc,
struct option options[] = {
OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
OPT_SUBCOMMAND("list", &fn, cmd_reflog_list),
- OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
- OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
+ OPT_SUBCOMMAND("write", &fn, cmd_reflog_write),
+ OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
OPT_SUBCOMMAND("drop", &fn, cmd_reflog_drop),
+ OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
OPT_END()
};
diff --git a/builtin/refs.c b/builtin/refs.c
index 998d2a2c1c..c7ad0a2963 100644
--- a/builtin/refs.c
+++ b/builtin/refs.c
@@ -88,7 +88,7 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
if (argc)
usage(_("'git refs verify' takes no arguments"));
- git_config(git_fsck_config, &fsck_refs_options);
+ repo_config(the_repository, git_fsck_config, &fsck_refs_options);
prepare_repo_settings(the_repository);
worktrees = get_worktrees_without_reading_head();
diff --git a/builtin/remote.c b/builtin/remote.c
index 0d6755bcb7..8a7ed4299a 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1,9 +1,11 @@
#define USE_THE_REPOSITORY_VARIABLE
-#define DISABLE_SIGN_COMPARE_WARNINGS
#include "builtin.h"
+#include "advice.h"
#include "config.h"
+#include "date.h"
#include "gettext.h"
+#include "ident.h"
#include "parse-options.h"
#include "path.h"
#include "transport.h"
@@ -14,7 +16,7 @@
#include "rebase.h"
#include "refs.h"
#include "refspec.h"
-#include "object-store.h"
+#include "odb.h"
#include "strvec.h"
#include "commit-reach.h"
#include "progress.h"
@@ -132,7 +134,7 @@ static void add_branch(const char *key, const char *branchname,
else
strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
branchname, remotename, branchname);
- git_config_set_multivar(key, tmp->buf, "^$", 0);
+ repo_config_set_multivar(the_repository, key, tmp->buf, "^$", 0);
}
static const char mirror_advice[] =
@@ -157,6 +159,21 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
return 0;
}
+static int check_remote_collision(struct remote *remote, void *data)
+{
+ const char *name = data;
+ const char *p;
+
+ if (skip_prefix(name, remote->name, &p) && *p == '/')
+ die(_("remote name '%s' is a subset of existing remote '%s'"),
+ name, remote->name);
+ if (skip_prefix(remote->name, name, &p) && *p == '/')
+ die(_("remote name '%s' is a superset of existing remote '%s'"),
+ name, remote->name);
+
+ return 0;
+}
+
static int add(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
@@ -167,7 +184,6 @@ static int add(int argc, const char **argv, const char *prefix,
struct remote *remote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
const char *name, *url;
- int i;
int result = 0;
struct option options[] = {
@@ -208,15 +224,17 @@ static int add(int argc, const char **argv, const char *prefix,
if (!valid_remote_name(name))
die(_("'%s' is not a valid remote name"), name);
+ for_each_remote(check_remote_collision, (void *)name);
+
strbuf_addf(&buf, "remote.%s.url", name);
- git_config_set(buf.buf, url);
+ repo_config_set(the_repository, buf.buf, url);
if (!mirror || mirror & MIRROR_FETCH) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", name);
if (track.nr == 0)
string_list_append(&track, "*");
- for (i = 0; i < track.nr; i++) {
+ for (size_t i = 0; i < track.nr; i++) {
add_branch(buf.buf, track.items[i].string,
name, mirror, &buf2);
}
@@ -225,14 +243,14 @@ static int add(int argc, const char **argv, const char *prefix,
if (mirror & MIRROR_PUSH) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.mirror", name);
- git_config_set(buf.buf, "true");
+ repo_config_set(the_repository, buf.buf, "true");
}
if (fetch_tags != TAGS_DEFAULT) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.tagOpt", name);
- git_config_set(buf.buf,
- fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
+ repo_config_set(the_repository, buf.buf,
+ fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
}
if (fetch && fetch_remote(name)) {
@@ -353,7 +371,7 @@ static void read_branches(void)
{
if (branch_list.nr)
return;
- git_config(config_read_branches, NULL);
+ repo_config(the_repository, config_read_branches, NULL);
}
struct ref_states {
@@ -454,8 +472,8 @@ static int get_push_ref_states(const struct ref *remote_refs,
info->status = PUSH_STATUS_UPTODATE;
else if (is_null_oid(&ref->old_oid))
info->status = PUSH_STATUS_CREATE;
- else if (has_object(the_repository, &ref->old_oid,
- HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR) &&
+ else if (odb_has_object(the_repository->objects, &ref->old_oid,
+ HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR) &&
ref_newer(&ref->new_oid, &ref->old_oid))
info->status = PUSH_STATUS_FASTFORWARD;
else
@@ -595,54 +613,170 @@ static int add_branch_for_removal(const char *refname,
struct rename_info {
const char *old_name;
const char *new_name;
- struct string_list *remote_branches;
- uint32_t symrefs_nr;
+ struct ref_transaction *transaction;
+ struct progress *progress;
+ struct strbuf *err;
+ uint32_t progress_nr;
+ uint64_t index;
};
-static int read_remote_branches(const char *refname, const char *referent UNUSED,
- const struct object_id *oid UNUSED,
- int flags UNUSED, void *cb_data)
+static void compute_renamed_ref(struct rename_info *rename,
+ const char *refname,
+ struct strbuf *out)
+{
+ strbuf_reset(out);
+ strbuf_addstr(out, refname);
+ strbuf_splice(out, strlen("refs/remotes/"), strlen(rename->old_name),
+ rename->new_name, strlen(rename->new_name));
+}
+
+static int rename_one_reflog_entry(const char *old_refname,
+ struct object_id *old_oid,
+ struct object_id *new_oid,
+ const char *committer,
+ timestamp_t timestamp, int tz,
+ const char *msg, void *cb_data)
{
struct rename_info *rename = cb_data;
- struct strbuf buf = STRBUF_INIT;
- struct string_list_item *item;
- int flag;
- const char *symref;
-
- strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name);
- if (starts_with(refname, buf.buf)) {
- item = string_list_append(rename->remote_branches, refname);
- symref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
- refname, RESOLVE_REF_READING,
- NULL, &flag);
- if (symref && (flag & REF_ISSYMREF)) {
- item->util = xstrdup(symref);
- rename->symrefs_nr++;
- } else {
- item->util = NULL;
- }
+ struct strbuf new_refname = STRBUF_INIT;
+ struct strbuf identity = STRBUF_INIT;
+ struct strbuf name = STRBUF_INIT;
+ struct strbuf mail = STRBUF_INIT;
+ struct ident_split ident;
+ const char *date;
+ int error;
+
+ compute_renamed_ref(rename, old_refname, &new_refname);
+
+ if (split_ident_line(&ident, committer, strlen(committer)) < 0) {
+ error = -1;
+ goto out;
}
- strbuf_release(&buf);
- return 0;
+ strbuf_add(&name, ident.name_begin, ident.name_end - ident.name_begin);
+ strbuf_add(&mail, ident.mail_begin, ident.mail_end - ident.mail_begin);
+
+ date = show_date(timestamp, tz, DATE_MODE(NORMAL));
+ strbuf_addstr(&identity, fmt_ident(name.buf, mail.buf,
+ WANT_BLANK_IDENT, date, 0));
+
+ error = ref_transaction_update_reflog(rename->transaction, new_refname.buf,
+ new_oid, old_oid, identity.buf, msg,
+ rename->index++, rename->err);
+
+out:
+ strbuf_release(&new_refname);
+ strbuf_release(&identity);
+ strbuf_release(&name);
+ strbuf_release(&mail);
+ return error;
+}
+
+static int rename_one_reflog(const char *old_refname,
+ const struct object_id *old_oid,
+ struct rename_info *rename)
+{
+ struct strbuf new_refname = STRBUF_INIT;
+ struct strbuf message = STRBUF_INIT;
+ int error;
+
+ if (!refs_reflog_exists(get_main_ref_store(the_repository), old_refname))
+ return 0;
+
+ error = refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+ old_refname, rename_one_reflog_entry, rename);
+ if (error < 0)
+ goto out;
+
+ compute_renamed_ref(rename, old_refname, &new_refname);
+
+ /*
+ * Manually write the reflog entry for the now-renamed ref. We cannot
+ * rely on `rename_one_ref()` to do this for us as that would screw
+ * over order in which reflog entries are being written.
+ *
+ * Furthermore, we only append the entry in case the reference
+ * resolves. Missing references shouldn't have reflogs anyway.
+ */
+ strbuf_addf(&message, "remote: renamed %s to %s", old_refname,
+ new_refname.buf);
+
+ error = ref_transaction_update_reflog(rename->transaction, new_refname.buf,
+ old_oid, old_oid, git_committer_info(0),
+ message.buf, rename->index++, rename->err);
+ if (error < 0)
+ return error;
+
+out:
+ strbuf_release(&new_refname);
+ strbuf_release(&message);
+ return error;
+}
+
+static int rename_one_ref(const char *old_refname, const char *referent,
+ const struct object_id *oid,
+ int flags, void *cb_data)
+{
+ struct strbuf new_referent = STRBUF_INIT;
+ struct strbuf new_refname = STRBUF_INIT;
+ struct rename_info *rename = cb_data;
+ int error;
+
+ compute_renamed_ref(rename, old_refname, &new_refname);
+
+ if (flags & REF_ISSYMREF) {
+ /*
+ * Stupidly enough `referent` is not pointing to the immediate
+ * target of a symref, but it's the recursively resolved value.
+ * So symrefs pointing to symrefs would be misresolved, and
+ * unborn symrefs don't have any value for the `referent` at all.
+ */
+ referent = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ old_refname, RESOLVE_REF_NO_RECURSE,
+ NULL, NULL);
+ compute_renamed_ref(rename, referent, &new_referent);
+ oid = NULL;
+ }
+
+ error = ref_transaction_delete(rename->transaction, old_refname,
+ oid, referent, REF_NO_DEREF, NULL, rename->err);
+ if (error < 0)
+ goto out;
+
+ error = ref_transaction_update(rename->transaction, new_refname.buf, oid, null_oid(the_hash_algo),
+ (flags & REF_ISSYMREF) ? new_referent.buf : NULL, NULL,
+ REF_SKIP_CREATE_REFLOG | REF_NO_DEREF | REF_SKIP_OID_VERIFICATION,
+ NULL, rename->err);
+ if (error < 0)
+ goto out;
+
+ error = rename_one_reflog(old_refname, oid, rename);
+ if (error < 0)
+ goto out;
+
+ display_progress(rename->progress, ++rename->progress_nr);
+
+out:
+ strbuf_release(&new_referent);
+ strbuf_release(&new_refname);
+ return error;
}
static int migrate_file(struct remote *remote)
{
struct strbuf buf = STRBUF_INIT;
- int i;
strbuf_addf(&buf, "remote.%s.url", remote->name);
- for (i = 0; i < remote->url.nr; i++)
- git_config_set_multivar(buf.buf, remote->url.v[i], "^$", 0);
+ for (size_t i = 0; i < remote->url.nr; i++)
+ repo_config_set_multivar(the_repository, buf.buf, remote->url.v[i], "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.push", remote->name);
- for (i = 0; i < remote->push.nr; i++)
- git_config_set_multivar(buf.buf, remote->push.items[i].raw, "^$", 0);
+ for (int i = 0; i < remote->push.nr; i++)
+ repo_config_set_multivar(the_repository, buf.buf, remote->push.items[i].raw, "^$", 0);
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", remote->name);
- for (i = 0; i < remote->fetch.nr; i++)
- git_config_set_multivar(buf.buf, remote->fetch.items[i].raw, "^$", 0);
+ for (int i = 0; i < remote->fetch.nr; i++)
+ repo_config_set_multivar(the_repository, buf.buf, remote->fetch.items[i].raw, "^$", 0);
#ifndef WITH_BREAKING_CHANGES
if (remote->origin == REMOTE_REMOTES)
unlink_or_warn(repo_git_path_replace(the_repository, &buf,
@@ -690,12 +824,12 @@ static void handle_push_default(const char* old_name, const char* new_name)
.origin = STRBUF_INIT,
.linenr = -1,
};
- git_config(config_read_push_default, &push_default);
+ repo_config(the_repository, config_read_push_default, &push_default);
if (push_default.scope >= CONFIG_SCOPE_COMMAND)
; /* pass */
else if (push_default.scope >= CONFIG_SCOPE_LOCAL) {
- int result = git_config_set_gently("remote.pushDefault",
- new_name);
+ int result = repo_config_set_gently(the_repository, "remote.pushDefault",
+ new_name);
if (new_name && result && result != CONFIG_NOTHING_SET)
die(_("could not set '%s'"), "remote.pushDefault");
else if (!new_name && result && result != CONFIG_NOTHING_SET)
@@ -713,6 +847,14 @@ static void handle_push_default(const char* old_name, const char* new_name)
strbuf_release(&push_default.origin);
}
+static const char conflicting_remote_refs_advice[] = N_(
+ "The remote you are trying to rename has conflicting references in the\n"
+ "new target refspec. This is most likely caused by you trying to nest\n"
+ "a remote into itself, e.g. by renaming 'parent' into 'parent/child'\n"
+ "or by unnesting a remote, e.g. the other way round.\n"
+ "\n"
+ "If that is the case, you can address this by first renaming the\n"
+ "remote to a different name.\n");
static int mv(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
@@ -724,11 +866,11 @@ static int mv(int argc, const char **argv, const char *prefix,
};
struct remote *oldremote, *newremote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT,
- old_remote_context = STRBUF_INIT;
- struct string_list remote_branches = STRING_LIST_INIT_DUP;
- struct rename_info rename;
- int i, refs_renamed_nr = 0, refspec_updated = 0;
- struct progress *progress = NULL;
+ old_remote_context = STRBUF_INIT, err = STRBUF_INIT;
+ struct rename_info rename = {
+ .err = &err,
+ };
+ int refspecs_need_update = 0;
int result = 0;
argc = parse_options(argc, argv, prefix, options,
@@ -739,8 +881,6 @@ static int mv(int argc, const char **argv, const char *prefix,
rename.old_name = argv[0];
rename.new_name = argv[1];
- rename.remote_branches = &remote_branches;
- rename.symrefs_nr = 0;
oldremote = remote_get(rename.old_name);
if (!remote_is_configured(oldremote, 1)) {
@@ -768,19 +908,50 @@ static int mv(int argc, const char **argv, const char *prefix,
goto out;
}
+ strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
+
+ for (int i = 0; i < oldremote->fetch.nr && !refspecs_need_update; i++)
+ refspecs_need_update = !!strstr(oldremote->fetch.items[i].raw,
+ old_remote_context.buf);
+
+ if (refspecs_need_update) {
+ rename.transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+ 0, &err);
+ if (!rename.transaction)
+ goto out;
+
+ if (show_progress)
+ rename.progress = start_delayed_progress(the_repository,
+ _("Renaming remote references"), 0);
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "refs/remotes/%s/", rename.old_name);
+
+ result = refs_for_each_rawref_in(get_main_ref_store(the_repository), buf.buf,
+ rename_one_ref, &rename);
+ if (result < 0)
+ die(_("queueing remote ref renames failed: %s"), rename.err->buf);
+
+ result = ref_transaction_prepare(rename.transaction, &err);
+ if (result < 0) {
+ error("renaming remote references failed: %s", err.buf);
+ if (result == REF_TRANSACTION_ERROR_NAME_CONFLICT)
+ advise(conflicting_remote_refs_advice);
+ die(NULL);
+ }
+ }
+
if (oldremote->fetch.nr) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
- git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
- strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
- for (i = 0; i < oldremote->fetch.nr; i++) {
+ repo_config_set_multivar(the_repository, buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+ for (int i = 0; i < oldremote->fetch.nr; i++) {
char *ptr;
strbuf_reset(&buf2);
strbuf_addstr(&buf2, oldremote->fetch.items[i].raw);
ptr = strstr(buf2.buf, old_remote_context.buf);
if (ptr) {
- refspec_updated = 1;
strbuf_splice(&buf2,
ptr-buf2.buf + strlen(":refs/remotes/"),
strlen(rename.old_name), rename.new_name,
@@ -791,103 +962,43 @@ static int mv(int argc, const char **argv, const char *prefix,
"\tPlease update the configuration manually if necessary."),
buf2.buf);
- git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
+ repo_config_set_multivar(the_repository, buf.buf, buf2.buf, "^$", 0);
}
}
read_branches();
- for (i = 0; i < branch_list.nr; i++) {
+ for (size_t i = 0; i < branch_list.nr; i++) {
struct string_list_item *item = branch_list.items + i;
struct branch_info *info = item->util;
if (info->remote_name && !strcmp(info->remote_name, rename.old_name)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", item->string);
- git_config_set(buf.buf, rename.new_name);
+ repo_config_set(the_repository, buf.buf, rename.new_name);
}
if (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.pushRemote", item->string);
- git_config_set(buf.buf, rename.new_name);
+ repo_config_set(the_repository, buf.buf, rename.new_name);
}
}
- if (!refspec_updated)
- goto out;
-
- /*
- * First remove symrefs, then rename the rest, finally create
- * the new symrefs.
- */
- refs_for_each_ref(get_main_ref_store(the_repository),
- read_remote_branches, &rename);
- if (show_progress) {
- /*
- * Count symrefs twice, since "renaming" them is done by
- * deleting and recreating them in two separate passes.
- */
- progress = start_progress(the_repository,
- _("Renaming remote references"),
- rename.remote_branches->nr + rename.symrefs_nr);
- }
- for (i = 0; i < remote_branches.nr; i++) {
- struct string_list_item *item = remote_branches.items + i;
- struct strbuf referent = STRBUF_INIT;
-
- if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
- &referent))
- continue;
- if (refs_delete_ref(get_main_ref_store(the_repository), NULL, item->string, NULL, REF_NO_DEREF))
- die(_("deleting '%s' failed"), item->string);
-
- strbuf_release(&referent);
- display_progress(progress, ++refs_renamed_nr);
- }
- for (i = 0; i < remote_branches.nr; i++) {
- struct string_list_item *item = remote_branches.items + i;
+ if (refspecs_need_update) {
+ result = ref_transaction_commit(rename.transaction, &err);
+ if (result < 0)
+ die(_("renaming remote refs failed: %s"), rename.err->buf);
- if (item->util)
- continue;
- strbuf_reset(&buf);
- strbuf_addstr(&buf, item->string);
- strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
- rename.new_name, strlen(rename.new_name));
- strbuf_reset(&buf2);
- strbuf_addf(&buf2, "remote: renamed %s to %s",
- item->string, buf.buf);
- if (refs_rename_ref(get_main_ref_store(the_repository), item->string, buf.buf, buf2.buf))
- die(_("renaming '%s' failed"), item->string);
- display_progress(progress, ++refs_renamed_nr);
- }
- for (i = 0; i < remote_branches.nr; i++) {
- struct string_list_item *item = remote_branches.items + i;
+ stop_progress(&rename.progress);
- if (!item->util)
- continue;
- strbuf_reset(&buf);
- strbuf_addstr(&buf, item->string);
- strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
- rename.new_name, strlen(rename.new_name));
- strbuf_reset(&buf2);
- strbuf_addstr(&buf2, item->util);
- strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old_name),
- rename.new_name, strlen(rename.new_name));
- strbuf_reset(&buf3);
- strbuf_addf(&buf3, "remote: renamed %s to %s",
- item->string, buf.buf);
- if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf))
- die(_("creating '%s' failed"), buf.buf);
- display_progress(progress, ++refs_renamed_nr);
+ handle_push_default(rename.old_name, rename.new_name);
}
- stop_progress(&progress);
-
- handle_push_default(rename.old_name, rename.new_name);
out:
- string_list_clear(&remote_branches, 1);
+ ref_transaction_free(rename.transaction);
strbuf_release(&old_remote_context);
strbuf_release(&buf);
strbuf_release(&buf2);
strbuf_release(&buf3);
+ strbuf_release(&err);
return result;
}
@@ -903,7 +1014,7 @@ static int rm(int argc, const char **argv, const char *prefix,
struct string_list branches = STRING_LIST_INIT_DUP;
struct string_list skipped = STRING_LIST_INIT_DUP;
struct branches_for_remote cb_data;
- int i, result;
+ int result;
memset(&cb_data, 0, sizeof(cb_data));
cb_data.branches = &branches;
@@ -925,7 +1036,7 @@ static int rm(int argc, const char **argv, const char *prefix,
for_each_remote(add_known_remote, &known_remotes);
read_branches();
- for (i = 0; i < branch_list.nr; i++) {
+ for (size_t i = 0; i < branch_list.nr; i++) {
struct string_list_item *item = branch_list.items + i;
struct branch_info *info = item->util;
if (info->remote_name && !strcmp(info->remote_name, remote->name)) {
@@ -934,7 +1045,7 @@ static int rm(int argc, const char **argv, const char *prefix,
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.%s",
item->string, *k);
- result = git_config_set_gently(buf.buf, NULL);
+ result = repo_config_set_gently(the_repository, buf.buf, NULL);
if (result && result != CONFIG_NOTHING_SET)
die(_("could not unset '%s'"), buf.buf);
}
@@ -942,7 +1053,7 @@ static int rm(int argc, const char **argv, const char *prefix,
if (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) {
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.pushremote", item->string);
- result = git_config_set_gently(buf.buf, NULL);
+ result = repo_config_set_gently(the_repository, buf.buf, NULL);
if (result && result != CONFIG_NOTHING_SET)
die(_("could not unset '%s'"), buf.buf);
}
@@ -971,7 +1082,7 @@ static int rm(int argc, const char **argv, const char *prefix,
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
"to delete them, use:",
skipped.nr));
- for (i = 0; i < skipped.nr; i++)
+ for (size_t i = 0; i < skipped.nr; i++)
fprintf(stderr, " git branch -d %s\n",
skipped.items[i].string);
}
@@ -1149,7 +1260,6 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
struct branch_info *branch_info = item->util;
struct string_list *merge = &branch_info->merge;
int width = show_info->width + 4;
- int i;
if (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) {
error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"),
@@ -1175,7 +1285,7 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
} else {
printf_ln(_("merges with remote %s"), merge->items[0].string);
}
- for (i = 1; i < merge->nr; i++)
+ for (size_t i = 1; i < merge->nr; i++)
printf(_("%-*s and with remote %s\n"), width, "",
merge->items[i].string);
@@ -1260,7 +1370,6 @@ static int get_one_entry(struct remote *remote, void *priv)
struct string_list *list = priv;
struct strbuf remote_info_buf = STRBUF_INIT;
struct strvec *url;
- int i;
if (remote->url.nr > 0) {
struct strbuf promisor_config = STRBUF_INIT;
@@ -1268,7 +1377,7 @@ static int get_one_entry(struct remote *remote, void *priv)
strbuf_addf(&promisor_config, "remote.%s.partialclonefilter", remote->name);
strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url.v[0]);
- if (!git_config_get_string_tmp(promisor_config.buf, &partial_clone_filter))
+ if (!repo_config_get_string_tmp(the_repository, promisor_config.buf, &partial_clone_filter))
strbuf_addf(&remote_info_buf, " [%s]", partial_clone_filter);
strbuf_release(&promisor_config);
@@ -1277,8 +1386,7 @@ static int get_one_entry(struct remote *remote, void *priv)
} else
string_list_append(list, remote->name)->util = NULL;
url = push_url_of_remote(remote);
- for (i = 0; i < url->nr; i++)
- {
+ for (size_t i = 0; i < url->nr; i++) {
strbuf_addf(&remote_info_buf, "%s (push)", url->v[i]);
string_list_append(list, remote->name)->util =
strbuf_detach(&remote_info_buf, NULL);
@@ -1295,10 +1403,8 @@ static int show_all(void)
result = for_each_remote(get_one_entry, &list);
if (!result) {
- int i;
-
string_list_sort(&list);
- for (i = 0; i < list.nr; i++) {
+ for (size_t i = 0; i < list.nr; i++) {
struct string_list_item *item = list.items + i;
if (verbose)
printf("%s\t%s\n", item->string,
@@ -1335,7 +1441,7 @@ static int show(int argc, const char **argv, const char *prefix,
query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES);
for (; argc; argc--, argv++) {
- int i;
+ size_t i;
struct strvec *url;
get_remote_ref_states(*argv, &info.states, query_flag);
@@ -1441,7 +1547,7 @@ static void report_set_head_auto(const char *remote, const char *head_name,
static int set_head(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
- int i, opt_a = 0, opt_d = 0, result = 0, was_detached;
+ int opt_a = 0, opt_d = 0, result = 0, was_detached;
struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
b_local_head = STRBUF_INIT;
char *head_name = NULL;
@@ -1457,10 +1563,13 @@ static int set_head(int argc, const char **argv, const char *prefix,
};
argc = parse_options(argc, argv, prefix, options,
builtin_remote_sethead_usage, 0);
- if (argc) {
- strbuf_addf(&b_head, "refs/remotes/%s/HEAD", argv[0]);
- remote = remote_get(argv[0]);
- }
+
+ /* All modes require at least a remote name. */
+ if (!argc)
+ usage_with_options(builtin_remote_sethead_usage, options);
+
+ strbuf_addf(&b_head, "refs/remotes/%s/HEAD", argv[0]);
+ remote = remote_get(argv[0]);
if (!opt_a && !opt_d && argc == 2) {
head_name = xstrdup(argv[1]);
@@ -1472,7 +1581,7 @@ static int set_head(int argc, const char **argv, const char *prefix,
else if (states.heads.nr > 1) {
result |= error(_("Multiple remote HEAD branches. "
"Please choose one explicitly with:"));
- for (i = 0; i < states.heads.nr; i++)
+ for (size_t i = 0; i < states.heads.nr; i++)
fprintf(stderr, " git remote set-head %s %s\n",
argv[0], states.heads.items[i].string);
} else
@@ -1503,7 +1612,7 @@ static int set_head(int argc, const char **argv, const char *prefix,
struct strbuf config_name = STRBUF_INIT;
strbuf_addf(&config_name,
"remote.%s.followremotehead", remote->name);
- git_config_set(config_name.buf, "warn");
+ repo_config_set(the_repository, config_name.buf, "warn");
strbuf_release(&config_name);
}
@@ -1521,9 +1630,6 @@ static int prune_remote(const char *remote, int dry_run)
struct ref_states states = REF_STATES_INIT;
struct string_list refs_to_prune = STRING_LIST_INIT_NODUP;
struct string_list_item *item;
- const char *dangling_msg = dry_run
- ? _(" %s will become dangling!")
- : _(" %s has become dangling!");
get_remote_ref_states(remote, &states, GET_REF_STATES);
@@ -1555,7 +1661,7 @@ static int prune_remote(const char *remote, int dry_run)
}
refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
- stdout, dangling_msg, &refs_to_prune);
+ stdout, " ", dry_run, &refs_to_prune);
string_list_clear(&refs_to_prune, 0);
free_remote_ref_states(&states);
@@ -1623,7 +1729,7 @@ static int update(int argc, const char **argv, const char *prefix,
strvec_push(&cmd.args, argv[i]);
if (strcmp(cmd.args.v[cmd.args.nr-1], "default") == 0) {
- git_config(get_remote_default, &default_defined);
+ repo_config(the_repository, get_remote_default, &default_defined);
if (!default_defined) {
strvec_pop(&cmd.args);
strvec_push(&cmd.args, "--all");
@@ -1636,8 +1742,8 @@ static int update(int argc, const char **argv, const char *prefix,
static int remove_all_fetch_refspecs(const char *key)
{
- return git_config_set_multivar_gently(key, NULL, NULL,
- CONFIG_FLAGS_MULTI_REPLACE);
+ return repo_config_set_multivar_gently(the_repository, key, NULL, NULL,
+ CONFIG_FLAGS_MULTI_REPLACE);
}
static void add_branches(struct remote *remote, const char **branches,
@@ -1700,7 +1806,7 @@ static int set_branches(int argc, const char **argv, const char *prefix,
static int get_url(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
- int i, push_mode = 0, all_mode = 0;
+ int push_mode = 0, all_mode = 0;
const char *remotename = NULL;
struct remote *remote;
struct strvec *url;
@@ -1728,7 +1834,7 @@ static int get_url(int argc, const char **argv, const char *prefix,
url = push_mode ? push_url_of_remote(remote) : &remote->url;
if (all_mode) {
- for (i = 0; i < url->nr; i++)
+ for (size_t i = 0; i < url->nr; i++)
printf_ln("%s", url->v[i]);
} else {
printf_ln("%s", url->v[0]);
@@ -1740,7 +1846,7 @@ static int get_url(int argc, const char **argv, const char *prefix,
static int set_url(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
- int i, push_mode = 0, add_mode = 0, delete_mode = 0;
+ int push_mode = 0, add_mode = 0, delete_mode = 0;
int matches = 0, negative_matches = 0;
const char *remotename = NULL;
const char *newurl = NULL;
@@ -1793,10 +1899,10 @@ static int set_url(int argc, const char **argv, const char *prefix,
/* Special cases that add new entry. */
if ((!oldurl && !delete_mode) || add_mode) {
if (add_mode)
- git_config_set_multivar(name_buf.buf, newurl,
+ repo_config_set_multivar(the_repository, name_buf.buf, newurl,
"^$", 0);
else
- git_config_set(name_buf.buf, newurl);
+ repo_config_set(the_repository, name_buf.buf, newurl);
goto out;
}
@@ -1804,7 +1910,7 @@ static int set_url(int argc, const char **argv, const char *prefix,
if (regcomp(&old_regex, oldurl, REG_EXTENDED))
die(_("Invalid old URL pattern: %s"), oldurl);
- for (i = 0; i < urlset->nr; i++)
+ for (size_t i = 0; i < urlset->nr; i++)
if (!regexec(&old_regex, urlset->v[i], 0, NULL, 0))
matches++;
else
@@ -1817,10 +1923,10 @@ static int set_url(int argc, const char **argv, const char *prefix,
regfree(&old_regex);
if (!delete_mode)
- git_config_set_multivar(name_buf.buf, newurl, oldurl, 0);
+ repo_config_set_multivar(the_repository, name_buf.buf, newurl, oldurl, 0);
else
- git_config_set_multivar(name_buf.buf, NULL, oldurl,
- CONFIG_FLAGS_MULTI_REPLACE);
+ repo_config_set_multivar(the_repository, name_buf.buf, NULL, oldurl,
+ CONFIG_FLAGS_MULTI_REPLACE);
out:
strbuf_release(&name_buf);
return 0;
diff --git a/builtin/repack.c b/builtin/repack.c
index 59214dbdfd..a4def39197 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -17,7 +17,7 @@
#include "midx.h"
#include "packfile.h"
#include "prune-packed.h"
-#include "object-store.h"
+#include "odb.h"
#include "promisor-remote.h"
#include "shallow.h"
#include "pack.h"
@@ -39,11 +39,12 @@ static int write_bitmaps = -1;
static int use_delta_islands;
static int run_update_server_info = 1;
static char *packdir, *packtmp_name, *packtmp;
+static int midx_must_contain_cruft = 1;
static const char *const git_repack_usage[] = {
N_("git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
- "[--write-midx] [--name-hash-version=<n>]"),
+ "[--write-midx] [--name-hash-version=<n>] [--path-walk]"),
NULL
};
@@ -63,6 +64,7 @@ struct pack_objects_args {
int quiet;
int local;
int name_hash_version;
+ int path_walk;
struct list_objects_filter_options filter_options;
};
@@ -107,6 +109,10 @@ static int repack_config(const char *var, const char *value,
free(cruft_po_args->threads);
return git_config_string(&cruft_po_args->threads, var, value);
}
+ if (!strcmp(var, "repack.midxmustcontaincruft")) {
+ midx_must_contain_cruft = git_config_bool(var, value);
+ return 0;
+ }
return git_default_config(var, value, ctx, cb);
}
@@ -217,9 +223,9 @@ static void mark_packs_for_deletion(struct existing_packs *existing,
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);
+ struct multi_pack_index *m = get_multi_pack_index(the_repository->objects->sources);
strbuf_addf(&buf, "%s.pack", base_name);
- if (m && midx_contains_pack(m, buf.buf))
+ if (m && m->local && midx_contains_pack(m, buf.buf))
clear_midx_file(the_repository);
strbuf_insertf(&buf, 0, "%s/", dir_name);
unlink_pack_path(buf.buf, 1);
@@ -313,6 +319,8 @@ static void prepare_pack_objects(struct child_process *cmd,
strvec_pushf(&cmd->args, "--no-reuse-object");
if (args->name_hash_version)
strvec_pushf(&cmd->args, "--name-hash-version=%d", args->name_hash_version);
+ if (args->path_walk)
+ strvec_pushf(&cmd->args, "--path-walk");
if (args->local)
strvec_push(&cmd->args, "--local");
if (args->quiet)
@@ -687,6 +695,77 @@ static void free_pack_geometry(struct pack_geometry *geometry)
free(geometry->pack);
}
+static int midx_has_unknown_packs(char **midx_pack_names,
+ size_t midx_pack_names_nr,
+ struct string_list *include,
+ struct pack_geometry *geometry,
+ struct existing_packs *existing)
+{
+ size_t i;
+
+ string_list_sort(include);
+
+ for (i = 0; i < midx_pack_names_nr; i++) {
+ const char *pack_name = midx_pack_names[i];
+
+ /*
+ * Determine whether or not each MIDX'd pack from the existing
+ * MIDX (if any) is represented in the new MIDX. For each pack
+ * in the MIDX, it must either be:
+ *
+ * - In the "include" list of packs to be included in the new
+ * MIDX. Note this function is called before the include
+ * list is populated with any cruft pack(s).
+ *
+ * - Below the geometric split line (if using pack geometry),
+ * indicating that the pack won't be included in the new
+ * MIDX, but its contents were rolled up as part of the
+ * geometric repack.
+ *
+ * - In the existing non-kept packs list (if not using pack
+ * geometry), and marked as non-deleted.
+ */
+ if (string_list_has_string(include, pack_name)) {
+ continue;
+ } else if (geometry) {
+ struct strbuf buf = STRBUF_INIT;
+ uint32_t j;
+
+ for (j = 0; j < geometry->split; j++) {
+ strbuf_reset(&buf);
+ strbuf_addstr(&buf, pack_basename(geometry->pack[j]));
+ strbuf_strip_suffix(&buf, ".pack");
+ strbuf_addstr(&buf, ".idx");
+
+ if (!strcmp(pack_name, buf.buf)) {
+ strbuf_release(&buf);
+ break;
+ }
+ }
+
+ strbuf_release(&buf);
+
+ if (j < geometry->split)
+ continue;
+ } else {
+ struct string_list_item *item;
+
+ item = string_list_lookup(&existing->non_kept_packs,
+ pack_name);
+ if (item && !pack_is_marked_for_deletion(item))
+ continue;
+ }
+
+ /*
+ * If we got to this point, the MIDX includes some pack that we
+ * don't know about.
+ */
+ return 1;
+ }
+
+ return 0;
+}
+
struct midx_snapshot_ref_data {
struct tempfile *f;
struct oidset seen;
@@ -707,7 +786,7 @@ static int midx_snapshot_ref_one(const char *refname UNUSED,
if (oidset_insert(&data->seen, oid))
return 0; /* already seen */
- if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
+ if (odb_read_object_info(the_repository->objects, oid, NULL) != OBJ_COMMIT)
return 0;
fprintf(data->f->fp, "%s%s\n", data->preferred ? "+" : "",
@@ -755,6 +834,8 @@ static void midx_snapshot_refs(struct tempfile *f)
static void midx_included_packs(struct string_list *include,
struct existing_packs *existing,
+ char **midx_pack_names,
+ size_t midx_pack_names_nr,
struct string_list *names,
struct pack_geometry *geometry)
{
@@ -808,26 +889,56 @@ static void midx_included_packs(struct string_list *include,
}
}
- for_each_string_list_item(item, &existing->cruft_packs) {
+ if (midx_must_contain_cruft ||
+ midx_has_unknown_packs(midx_pack_names, midx_pack_names_nr,
+ include, geometry, existing)) {
/*
- * 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.
+ * If there are one or more unknown pack(s) present (see
+ * midx_has_unknown_packs() for what makes a pack
+ * "unknown") in the MIDX before the repack, keep them
+ * as they may be required to form a reachability
+ * closure if the MIDX is bitmapped.
*
- * 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).
+ * For example, a cruft pack can be required to form a
+ * reachability closure if the MIDX is bitmapped and one
+ * or more of the bitmap's selected commits reaches a
+ * once-cruft object that was later made reachable.
*/
- if (pack_is_marked_for_deletion(item))
- continue;
+ 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;
- strbuf_reset(&buf);
- strbuf_addf(&buf, "%s.idx", item->string);
- string_list_insert(include, buf.buf);
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s.idx", item->string);
+ string_list_insert(include, buf.buf);
+ }
+ } else {
+ /*
+ * Modern versions of Git (with the appropriate
+ * configuration setting) will write new copies of
+ * once-cruft objects when doing a --geometric repack.
+ *
+ * If the MIDX has no cruft pack, new packs written
+ * during a --geometric repack will not rely on the
+ * cruft pack to form a reachability closure, so we can
+ * avoid including them in the MIDX in that case.
+ */
+ ;
}
strbuf_release(&buf);
@@ -1142,6 +1253,8 @@ int cmd_repack(int argc,
struct tempfile *refs_snapshot = NULL;
int i, ext, ret;
int show_progress;
+ char **midx_pack_names = NULL;
+ size_t midx_pack_names_nr = 0;
/* variables to be filled by option parsing */
int delete_redundant = 0;
@@ -1184,6 +1297,8 @@ int cmd_repack(int argc,
N_("pass --no-reuse-object to git-pack-objects")),
OPT_INTEGER(0, "name-hash-version", &po_args.name_hash_version,
N_("specify the name hash version to use for grouping similar objects by path")),
+ OPT_BOOL(0, "path-walk", &po_args.path_walk,
+ N_("pass --path-walk to git-pack-objects")),
OPT_NEGBIT('n', NULL, &run_update_server_info,
N_("do not run git-update-server-info"), 1),
OPT__QUIET(&po_args.quiet, N_("be quiet")),
@@ -1225,7 +1340,7 @@ int cmd_repack(int argc,
list_objects_filter_init(&po_args.filter_options);
- git_config(repack_config, &cruft_po_args);
+ repo_config(the_repository, repack_config, &cruft_po_args);
argc = parse_options(argc, argv, prefix, builtin_repack_options,
git_repack_usage, 0);
@@ -1235,7 +1350,7 @@ int cmd_repack(int argc,
po_args.depth = xstrdup_or_null(opt_depth);
po_args.threads = xstrdup_or_null(opt_threads);
- if (delete_redundant && repository_format_precious_objects)
+ if (delete_redundant && the_repository->repository_format_precious_objects)
die(_("cannot delete packs in a precious-objects repo"));
die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A",
@@ -1256,7 +1371,8 @@ int cmd_repack(int argc,
if (write_bitmaps && !(pack_everything & ALL_INTO_ONE) && !write_midx)
die(_(incremental_bitmap_conflict_error));
- if (write_bitmaps && po_args.local && has_alt_odb(the_repository)) {
+ if (write_bitmaps && po_args.local &&
+ odb_has_alternates(the_repository->objects)) {
/*
* When asked to do a local repack, but we have
* packfiles that are inherited from an alternate, then
@@ -1356,7 +1472,10 @@ int cmd_repack(int argc,
!(pack_everything & PACK_CRUFT))
strvec_push(&cmd.args, "--pack-loose-unreachable");
} else if (geometry.split_factor) {
- strvec_push(&cmd.args, "--stdin-packs");
+ if (midx_must_contain_cruft)
+ strvec_push(&cmd.args, "--stdin-packs");
+ else
+ strvec_push(&cmd.args, "--stdin-packs=follow");
strvec_push(&cmd.args, "--unpacked");
} else {
strvec_push(&cmd.args, "--unpacked");
@@ -1396,8 +1515,25 @@ int cmd_repack(int argc,
if (ret)
goto cleanup;
- if (!names.nr && !po_args.quiet)
- printf_ln(_("Nothing new to pack."));
+ if (!names.nr) {
+ if (!po_args.quiet)
+ printf_ln(_("Nothing new to pack."));
+ /*
+ * If we didn't write any new packs, the non-cruft packs
+ * may refer to once-unreachable objects in the cruft
+ * pack(s).
+ *
+ * If there isn't already a MIDX, the one we write
+ * must include the cruft pack(s), in case the
+ * non-cruft pack(s) refer to once-cruft objects.
+ *
+ * If there is already a MIDX, we can punt here, since
+ * midx_has_unknown_packs() will make the decision for
+ * us.
+ */
+ if (!get_multi_pack_index(the_repository->objects->sources))
+ midx_must_contain_cruft = 1;
+ }
if (pack_everything & PACK_CRUFT) {
const char *pack_prefix = find_pack_prefix(packdir, packtmp);
@@ -1478,6 +1614,19 @@ int cmd_repack(int argc,
string_list_sort(&names);
+ if (get_multi_pack_index(the_repository->objects->sources)) {
+ struct multi_pack_index *m =
+ get_multi_pack_index(the_repository->objects->sources);
+
+ ALLOC_ARRAY(midx_pack_names,
+ m->num_packs + m->num_packs_in_base);
+
+ for (; m; m = m->base_midx)
+ for (uint32_t i = 0; i < m->num_packs; i++)
+ midx_pack_names[midx_pack_names_nr++] =
+ xstrdup(m->pack_names[i]);
+ }
+
close_object_store(the_repository->objects);
/*
@@ -1519,7 +1668,8 @@ int cmd_repack(int argc,
if (write_midx) {
struct string_list include = STRING_LIST_INIT_DUP;
- midx_included_packs(&include, &existing, &names, &geometry);
+ midx_included_packs(&include, &existing, midx_pack_names,
+ midx_pack_names_nr, &names, &geometry);
ret = write_midx_included_packs(&include, &geometry, &names,
refs_snapshot ? get_tempfile_path(refs_snapshot) : NULL,
@@ -1570,6 +1720,9 @@ cleanup:
string_list_clear(&names, 1);
existing_packs_release(&existing);
free_pack_geometry(&geometry);
+ for (size_t i = 0; i < midx_pack_names_nr; i++)
+ free(midx_pack_names[i]);
+ free(midx_pack_names);
pack_objects_args_release(&po_args);
pack_objects_args_release(&cruft_po_args);
diff --git a/builtin/replace.c b/builtin/replace.c
index 48c7c6a2d5..900b560a77 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -11,6 +11,7 @@
#include "builtin.h"
#include "config.h"
#include "editor.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "refs.h"
@@ -19,7 +20,7 @@
#include "run-command.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "replace-object.h"
#include "tag.h"
#include "wildmatch.h"
@@ -65,8 +66,8 @@ static int show_reference(const char *refname,
if (repo_get_oid(data->repo, refname, &object))
return error(_("failed to resolve '%s' as a valid ref"), refname);
- obj_type = oid_object_info(data->repo, &object, NULL);
- repl_type = oid_object_info(data->repo, oid, NULL);
+ obj_type = odb_read_object_info(data->repo->objects, &object, NULL);
+ repl_type = odb_read_object_info(data->repo->objects, oid, NULL);
printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
oid_to_hex(oid), type_name(repl_type));
@@ -185,8 +186,8 @@ static int replace_object_oid(const char *object_ref,
struct strbuf err = STRBUF_INIT;
int res = 0;
- obj_type = oid_object_info(the_repository, object, NULL);
- repl_type = oid_object_info(the_repository, repl, NULL);
+ obj_type = odb_read_object_info(the_repository->objects, object, NULL);
+ repl_type = odb_read_object_info(the_repository->objects, repl, NULL);
if (!force && obj_type != repl_type)
return error(_("Objects must be of the same type.\n"
"'%s' points to a replaced object of type '%s'\n"
@@ -334,7 +335,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
if (repo_get_oid(the_repository, object_ref, &old_oid) < 0)
return error(_("not a valid object name: '%s'"), object_ref);
- type = oid_object_info(the_repository, &old_oid, NULL);
+ type = odb_read_object_info(the_repository->objects, &old_oid, NULL);
if (type < 0)
return error(_("unable to get object type for %s"),
oid_to_hex(&old_oid));
@@ -488,7 +489,8 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
return -1;
}
- if (write_object_file(buf.buf, buf.len, OBJ_COMMIT, &new_oid)) {
+ if (odb_write_object(the_repository->objects, buf.buf,
+ buf.len, OBJ_COMMIT, &new_oid)) {
strbuf_release(&buf);
return error(_("could not write replacement commit for: '%s'"),
old_ref);
@@ -574,7 +576,7 @@ int cmd_replace(int argc,
};
disable_replace_refs();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
diff --git a/builtin/replay.c b/builtin/replay.c
index 225cef0880..6172c8aacc 100644
--- a/builtin/replay.c
+++ b/builtin/replay.c
@@ -84,6 +84,7 @@ static struct commit *create_commit(struct repository *repo,
obj = parse_object(repo, &ret);
out:
+ repo_unuse_commit_buffer(the_repository, based_on, message);
free_commit_extra_headers(extra);
free_commit_list(parents);
strbuf_release(&msg);
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 1312e79d89..a056cb791b 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -66,7 +66,7 @@ int cmd_rerere(int argc,
argc = parse_options(argc, argv, prefix, options, rerere_usage, 0);
- git_config(git_xmerge_config, NULL);
+ repo_config(the_repository, git_xmerge_config, NULL);
if (autoupdate == 1)
flags = RERERE_AUTOUPDATE;
diff --git a/builtin/reset.c b/builtin/reset.c
index dc50ffc1ac..ed35802af1 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -346,6 +346,7 @@ int cmd_reset(int argc,
struct object_id oid;
struct pathspec pathspec;
int intent_to_add = 0;
+ struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
const struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_BOOL(0, "no-refresh", &no_refresh,
@@ -370,6 +371,8 @@ int cmd_reset(int argc,
PARSE_OPT_OPTARG,
option_parse_recurse_submodules_worktree_updater),
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT_BOOL('N', "intent-to-add", &intent_to_add,
N_("record only the fact that removed paths will be added later")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
@@ -377,7 +380,7 @@ int cmd_reset(int argc,
OPT_END()
};
- git_config(git_reset_config, NULL);
+ repo_config(the_repository, git_reset_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
@@ -420,6 +423,11 @@ int cmd_reset(int argc,
oidcpy(&oid, &tree->object.oid);
}
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
@@ -427,9 +435,14 @@ int cmd_reset(int argc,
if (reset_type != NONE)
die(_("options '%s' and '%s' cannot be used together"), "--patch", "--{hard,mixed,soft}");
trace2_cmd_mode("patch-interactive");
- update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, rev,
- &pathspec);
+ update_ref_status = !!run_add_p(the_repository, ADD_P_RESET,
+ &add_p_opt, rev, &pathspec);
goto cleanup;
+ } else {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch");
}
/* git reset tree [--] paths... can be used to
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 0984b607bf..99f876ba85 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -14,7 +14,7 @@
#include "object.h"
#include "object-name.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
#include "pack-bitmap.h"
#include "parse-options.h"
#include "log-tree.h"
@@ -28,6 +28,14 @@
#include "quote.h"
#include "strbuf.h"
+struct rev_list_info {
+ struct rev_info *revs;
+ int flags;
+ int show_timestamp;
+ int hdr_termination;
+ const char *header_prefix;
+};
+
static const char rev_list_usage[] =
"git rev-list [<options>] <commit>... [--] [<path>...]\n"
"\n"
@@ -110,7 +118,8 @@ static off_t get_object_disk_usage(struct object *obj)
off_t size;
struct object_info oi = OBJECT_INFO_INIT;
oi.disk_sizep = &size;
- if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0)
+ if (odb_read_object_info_extended(the_repository->objects,
+ &obj->oid, &oi, 0) < 0)
die(_("unable to get disk usage of %s"), oid_to_hex(&obj->oid));
return size;
}
@@ -346,7 +355,8 @@ static void show_commit(struct commit *commit, void *data)
static int finish_object(struct object *obj, const char *name, void *cb_data)
{
struct rev_list_info *info = cb_data;
- if (oid_object_info_extended(the_repository, &obj->oid, NULL, 0) < 0) {
+ if (odb_read_object_info_extended(the_repository->objects,
+ &obj->oid, NULL, 0) < 0) {
finish_object__ma(obj, name);
return 1;
}
@@ -634,7 +644,7 @@ int cmd_rev_list(int argc,
show_usage_if_asked(argc, argv, rev_list_usage);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
repo_init_revisions(the_repository, &revs, prefix);
revs.abbrev = DEFAULT_ABBREV;
revs.commit_format = CMIT_FMT_UNSPECIFIED;
@@ -650,17 +660,21 @@ int cmd_rev_list(int argc,
*
* Let "--missing" to conditionally set fetch_if_missing.
*/
+
/*
- * NEEDSWORK: These loops that attempt to find presence of
- * options without understanding that the options they are
- * skipping are broken (e.g., it would not know "--grep
+ * NEEDSWORK: The next loop is utterly broken. It tries to
+ * notice an option is used, but without understanding if each
+ * option takes an argument, which fundamentally would not
+ * work. It would not know "--grep
* --exclude-promisor-objects" is not triggering
- * "--exclude-promisor-objects" option). We really need
- * setup_revisions() to have a mechanism to allow and disallow
- * some sets of options for different commands (like rev-list,
- * replay, etc). Such a mechanism should do an early parsing
- * of options and be able to manage the `--missing=...` and
- * `--exclude-promisor-objects` options below.
+ * "--exclude-promisor-objects" option, for example.
+ *
+ * We really need setup_revisions() to have a mechanism to
+ * allow and disallow some sets of options for different
+ * commands (like rev-list, replay, etc). Such a mechanism
+ * should do an early parsing of options and be able to manage
+ * the `--missing=...` and `--exclude-promisor-objects`
+ * options below.
*/
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 490da33bec..44ff1b8342 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -734,7 +734,7 @@ int cmd_rev_parse(int argc,
/* No options; just report on whether we're in a git repo or not. */
if (argc == 1) {
setup_git_directory();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
return 0;
}
@@ -769,7 +769,7 @@ int cmd_rev_parse(int argc,
/* The rest of the options require a git repository. */
if (!did_repo_setup) {
prefix = setup_git_directory();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
did_repo_setup = 1;
prepare_repo_settings(the_repository);
diff --git a/builtin/revert.c b/builtin/revert.c
index e07c2217fe..c3f92b585d 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -111,7 +111,7 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
const char *cleanup_arg = NULL;
- const char sentinel_value;
+ const char sentinel_value = 0; /* value not important */
const char *strategy = &sentinel_value;
const char *gpg_sign = &sentinel_value;
enum empty_action empty_opt = EMPTY_COMMIT_UNSPECIFIED;
diff --git a/builtin/rm.c b/builtin/rm.c
index a6565a69cf..05d89e98c3 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "advice.h"
#include "config.h"
+#include "environment.h"
#include "lockfile.h"
#include "dir.h"
#include "gettext.h"
@@ -271,7 +272,7 @@ int cmd_rm(int argc,
struct pathspec pathspec;
char *seen;
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_rm_options,
builtin_rm_usage, 0);
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index c6e0e9d051..8b81c8a848 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "hex.h"
#include "pkt-line.h"
#include "run-command.h"
@@ -304,9 +305,10 @@ int cmd_send_pack(int argc,
flags |= MATCH_REFS_MIRROR;
/* match them up */
- if (match_push_refs(local_refs, &remote_refs, &rs, flags))
- return -1;
-
+ if (match_push_refs(local_refs, &remote_refs, &rs, flags)) {
+ ret = -1;
+ goto cleanup;
+ }
if (!is_empty_cas(&cas))
apply_push_cas(&cas, remote, remote_refs);
@@ -339,10 +341,12 @@ int cmd_send_pack(int argc,
/* stable plumbing output; do not modify or localize */
fprintf(stderr, "Everything up-to-date\n");
+cleanup:
string_list_clear(&push_options, 0);
free_refs(remote_refs);
free_refs(local_refs);
refspec_clear(&rs);
+ oid_array_clear(&extra_have);
oid_array_clear(&shallow);
clear_cas_option(&cas);
return ret;
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 30075b67be..b91acf45c8 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -187,7 +187,7 @@ static void insert_records_from_trailers(struct shortlog *log,
ctx->output_encoding);
body = strstr(commit_buffer, "\n\n");
if (!body)
- return;
+ goto out;
trailer_iterator_init(&iter, body);
while (trailer_iterator_advance(&iter)) {
@@ -206,6 +206,7 @@ static void insert_records_from_trailers(struct shortlog *log,
}
trailer_iterator_release(&iter);
+out:
strbuf_release(&ident);
repo_unuse_commit_buffer(the_repository, commit, commit_buffer);
}
@@ -418,9 +419,9 @@ int cmd_shortlog(int argc,
* git/nongit so that we do not have to do this.
*/
if (nongit && !the_hash_algo)
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+ repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
shortlog_init(&log);
repo_init_revisions(the_repository, &rev, prefix);
parse_options_start(&ctx, argc, argv, prefix, options,
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 525b231d87..1ab7db9d2c 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -710,7 +710,7 @@ int cmd_show_branch(int ac,
init_commit_name_slab(&name_slab);
- git_config(git_show_branch_config, NULL);
+ repo_config(the_repository, git_show_branch_config, NULL);
/* If nothing is specified, try the default first */
if (ac == 1 && default_args.nr) {
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 9d4ecf5e7b..2c3e2940ce 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c
@@ -47,7 +47,7 @@ int cmd_show_index(int argc,
* the index file passed in and use that instead.
*/
if (!the_hash_algo)
- repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+ repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);
hashsz = the_hash_algo->rawsz;
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 623a52a45f..0b6f9edf86 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -1,11 +1,12 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "refs/refs-internal.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "object.h"
#include "string-list.h"
#include "parse-options.h"
@@ -35,8 +36,8 @@ static void show_one(const struct show_one_options *opts,
const char *hex;
struct object_id peeled;
- if (!has_object(the_repository, oid,
- HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
+ if (!odb_has_object(the_repository->objects, oid,
+ HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
die("git show-ref: bad ref %s (%s)", refname,
oid_to_hex(oid));
@@ -324,7 +325,7 @@ struct repository *repo UNUSED)
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, show_ref_options,
show_ref_usage, 0);
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 1bf01591b2..8c333b3e2e 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -1082,7 +1082,7 @@ int cmd_sparse_checkout(int argc,
builtin_sparse_checkout_options,
builtin_sparse_checkout_usage, 0);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/stash.c b/builtin/stash.c
index cfbd92852a..f5ddee5c7f 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -28,7 +28,10 @@
#include "log-tree.h"
#include "diffcore.h"
#include "reflog.h"
+#include "reflog-walk.h"
#include "add-interactive.h"
+#include "oid-array.h"
+#include "commit.h"
#define INCLUDE_ALL_FILES 2
@@ -56,6 +59,10 @@
" [-u | --include-untracked] [-a | --all] [<message>]")
#define BUILTIN_STASH_CREATE_USAGE \
N_("git stash create [<message>]")
+#define BUILTIN_STASH_EXPORT_USAGE \
+ N_("git stash export (--print | --to-ref <ref>) [<stash>...]")
+#define BUILTIN_STASH_IMPORT_USAGE \
+ N_("git stash import <commit>")
#define BUILTIN_STASH_CLEAR_USAGE \
"git stash clear"
@@ -71,6 +78,8 @@ static const char * const git_stash_usage[] = {
BUILTIN_STASH_CLEAR_USAGE,
BUILTIN_STASH_CREATE_USAGE,
BUILTIN_STASH_STORE_USAGE,
+ BUILTIN_STASH_EXPORT_USAGE,
+ BUILTIN_STASH_IMPORT_USAGE,
NULL
};
@@ -124,6 +133,16 @@ static const char * const git_stash_save_usage[] = {
NULL
};
+static const char * const git_stash_export_usage[] = {
+ BUILTIN_STASH_EXPORT_USAGE,
+ NULL
+};
+
+static const char * const git_stash_import_usage[] = {
+ BUILTIN_STASH_IMPORT_USAGE,
+ NULL
+};
+
static const char ref_stash[] = "refs/stash";
static struct strbuf stash_index_path = STRBUF_INIT;
@@ -132,6 +151,7 @@ static struct strbuf stash_index_path = STRBUF_INIT;
* b_commit is set to the base commit
* i_commit is set to the commit containing the index tree
* u_commit is set to the commit containing the untracked files tree
+ * c_commit is set to the first parent (chain commit) when importing and is otherwise unset
* w_tree is set to the working tree
* b_tree is set to the base tree
* i_tree is set to the index tree
@@ -142,6 +162,7 @@ struct stash_info {
struct object_id b_commit;
struct object_id i_commit;
struct object_id u_commit;
+ struct object_id c_commit;
struct object_id w_tree;
struct object_id b_tree;
struct object_id i_tree;
@@ -160,6 +181,33 @@ static void free_stash_info(struct stash_info *info)
strbuf_release(&info->revision);
}
+static int check_stash_topology(struct repository *r, struct commit *stash)
+{
+ struct commit *p1, *p2, *p3 = NULL;
+
+ /* stash must have two or three parents */
+ if (!stash->parents || !stash->parents->next ||
+ (stash->parents->next->next && stash->parents->next->next->next))
+ return -1;
+ p1 = stash->parents->item;
+ p2 = stash->parents->next->item;
+ if (stash->parents->next->next)
+ p3 = stash->parents->next->next->item;
+ if (repo_parse_commit(r, p1) || repo_parse_commit(r, p2) ||
+ (p3 && repo_parse_commit(r, p3)))
+ return -1;
+ /* p2 must have a single parent, p3 must have no parents */
+ if (!p2->parents || p2->parents->next || (p3 && p3->parents))
+ return -1;
+ if (repo_parse_commit(r, p2->parents->item))
+ return -1;
+ /* p2^1 must equal p1 */
+ if (!oideq(&p1->object.oid, &p2->parents->item->object.oid))
+ return -1;
+
+ return 0;
+}
+
static void assert_stash_like(struct stash_info *info, const char *revision)
{
if (get_oidf(&info->b_commit, "%s^1", revision) ||
@@ -169,6 +217,25 @@ static void assert_stash_like(struct stash_info *info, const char *revision)
die(_("'%s' is not a stash-like commit"), revision);
}
+static int parse_stash_revision(struct strbuf *revision, const char *commit, int quiet)
+{
+ strbuf_reset(revision);
+ if (!commit) {
+ if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash)) {
+ if (!quiet)
+ fprintf_ln(stderr, _("No stash entries found."));
+ return -1;
+ }
+
+ strbuf_addf(revision, "%s@{0}", ref_stash);
+ } else if (strspn(commit, "0123456789") == strlen(commit)) {
+ strbuf_addf(revision, "%s@{%s}", ref_stash, commit);
+ } else {
+ strbuf_addstr(revision, commit);
+ }
+ return 0;
+}
+
static int get_stash_info(struct stash_info *info, int argc, const char **argv)
{
int ret;
@@ -196,17 +263,9 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
if (argc == 1)
commit = argv[0];
- if (!commit) {
- if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash)) {
- fprintf_ln(stderr, _("No stash entries found."));
- return -1;
- }
-
- strbuf_addf(&info->revision, "%s@{0}", ref_stash);
- } else if (strspn(commit, "0123456789") == strlen(commit)) {
- strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit);
- } else {
- strbuf_addstr(&info->revision, commit);
+ strbuf_init(&info->revision, 0);
+ if (parse_stash_revision(&info->revision, commit, 0)) {
+ return -1;
}
revision = info->revision.buf;
@@ -679,7 +738,8 @@ cleanup:
return ret;
}
-static int reject_reflog_ent(struct object_id *ooid UNUSED,
+static int reject_reflog_ent(const char *refname UNUSED,
+ struct object_id *ooid UNUSED,
struct object_id *noid UNUSED,
const char *email UNUSED,
timestamp_t timestamp UNUSED,
@@ -920,7 +980,7 @@ static int show_stash(int argc, const char **argv, const char *prefix,
int do_usage = 0;
init_diff_ui_defaults();
- git_config(git_diff_ui_config, NULL);
+ repo_config(the_repository, git_diff_ui_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
argc = parse_options(argc, argv, prefix, options, git_stash_show_usage,
@@ -1242,7 +1302,8 @@ done:
}
static int stash_patch(struct stash_info *info, const struct pathspec *ps,
- struct strbuf *out_patch, int quiet)
+ struct strbuf *out_patch, int quiet,
+ struct add_p_opt *add_p_opt)
{
int ret = 0;
struct child_process cp_read_tree = CHILD_PROCESS_INIT;
@@ -1267,7 +1328,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
- ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps);
+ ret = !!run_add_p(the_repository, ADD_P_STASH, add_p_opt, NULL, ps);
the_repository->index_file = old_repo_index_file;
if (old_index_env && *old_index_env)
@@ -1362,8 +1423,8 @@ done:
}
static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_buf,
- int include_untracked, int patch_mode, int only_staged,
- struct stash_info *info, struct strbuf *patch,
+ int include_untracked, int patch_mode, struct add_p_opt *add_p_opt,
+ int only_staged, struct stash_info *info, struct strbuf *patch,
int quiet)
{
int ret = 0;
@@ -1372,6 +1433,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
const char *head_short_sha1 = NULL;
const char *branch_ref = NULL;
const char *branch_name = "(no branch)";
+ char *branch_name_buf = NULL;
struct commit *head_commit = NULL;
struct commit_list *parents = NULL;
struct strbuf msg = STRBUF_INIT;
@@ -1404,8 +1466,12 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
branch_ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
"HEAD", 0, NULL, &flags);
- if (flags & REF_ISSYMREF)
- skip_prefix(branch_ref, "refs/heads/", &branch_name);
+
+ if (flags & REF_ISSYMREF) {
+ if (skip_prefix(branch_ref, "refs/heads/", &branch_name))
+ branch_name = branch_name_buf = xstrdup(branch_name);
+ }
+
head_short_sha1 = repo_find_unique_abbrev(the_repository,
&head_commit->object.oid,
DEFAULT_ABBREV);
@@ -1439,7 +1505,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
untracked_commit_option = 1;
}
if (patch_mode) {
- ret = stash_patch(info, ps, patch, quiet);
+ ret = stash_patch(info, ps, patch, quiet, add_p_opt);
if (ret < 0) {
if (!quiet)
fprintf_ln(stderr, _("Cannot save the current "
@@ -1495,6 +1561,7 @@ done:
strbuf_release(&msg);
strbuf_release(&untracked_files);
free_commit_list(parents);
+ free(branch_name_buf);
return ret;
}
@@ -1513,7 +1580,7 @@ static int create_stash(int argc, const char **argv, const char *prefix UNUSED,
if (!check_changes_tracked_files(&ps))
return 0;
- ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, 0, &info,
+ ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, NULL, 0, &info,
NULL, 0);
if (!ret)
printf_ln("%s", oid_to_hex(&info.w_commit));
@@ -1524,7 +1591,8 @@ static int create_stash(int argc, const char **argv, const char *prefix UNUSED,
}
static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int quiet,
- int keep_index, int patch_mode, int include_untracked, int only_staged)
+ int keep_index, int patch_mode, struct add_p_opt *add_p_opt,
+ int include_untracked, int only_staged)
{
int ret = 0;
struct stash_info info = STASH_INFO_INIT;
@@ -1594,8 +1662,8 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
if (stash_msg)
strbuf_addstr(&stash_msg_buf, stash_msg);
- if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, only_staged,
- &info, &patch, quiet)) {
+ if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode,
+ add_p_opt, only_staged, &info, &patch, quiet)) {
ret = -1;
goto done;
}
@@ -1768,6 +1836,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
const char *stash_msg = NULL;
char *pathspec_from_file = NULL;
struct pathspec ps;
+ struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
N_("keep index")),
@@ -1775,6 +1844,8 @@ static int push_stash(int argc, const char **argv, const char *prefix,
N_("stash staged changes only")),
OPT_BOOL('p', "patch", &patch_mode,
N_("stash in patch mode")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT__QUIET(&quiet, N_("quiet mode")),
OPT_BOOL('u', "include-untracked", &include_untracked,
N_("include untracked files in stash")),
@@ -1789,11 +1860,15 @@ static int push_stash(int argc, const char **argv, const char *prefix,
int ret;
if (argc) {
- force_assume = !strcmp(argv[0], "-p");
+ int flags = PARSE_OPT_KEEP_DASHDASH;
+
+ if (push_assumed)
+ flags |= PARSE_OPT_STOP_AT_NON_OPTION;
+
argc = parse_options(argc, argv, prefix, options,
push_assumed ? git_stash_usage :
- git_stash_push_usage,
- PARSE_OPT_KEEP_DASHDASH);
+ git_stash_push_usage, flags);
+ force_assume |= patch_mode;
}
if (argc) {
@@ -1826,8 +1901,20 @@ static int push_stash(int argc, const char **argv, const char *prefix,
die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
}
+ if (!patch_mode) {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch");
+ }
+
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
- include_untracked, only_staged);
+ &add_p_opt, include_untracked, only_staged);
clear_pathspec(&ps);
free(pathspec_from_file);
@@ -1852,6 +1939,7 @@ static int save_stash(int argc, const char **argv, const char *prefix,
const char *stash_msg = NULL;
struct pathspec ps;
struct strbuf stash_msg_buf = STRBUF_INIT;
+ struct add_p_opt add_p_opt = ADD_P_OPT_INIT;
struct option options[] = {
OPT_BOOL('k', "keep-index", &keep_index,
N_("keep index")),
@@ -1859,6 +1947,8 @@ static int save_stash(int argc, const char **argv, const char *prefix,
N_("stash staged changes only")),
OPT_BOOL('p', "patch", &patch_mode,
N_("stash in patch mode")),
+ OPT_DIFF_UNIFIED(&add_p_opt.context),
+ OPT_DIFF_INTERHUNK_CONTEXT(&add_p_opt.interhunkcontext),
OPT__QUIET(&quiet, N_("quiet mode")),
OPT_BOOL('u', "include-untracked", &include_untracked,
N_("include untracked files in stash")),
@@ -1877,13 +1967,405 @@ static int save_stash(int argc, const char **argv, const char *prefix,
stash_msg = strbuf_join_argv(&stash_msg_buf, argc, argv, ' ');
memset(&ps, 0, sizeof(ps));
+
+ if (add_p_opt.context < -1)
+ die(_("'%s' cannot be negative"), "--unified");
+ if (add_p_opt.interhunkcontext < -1)
+ die(_("'%s' cannot be negative"), "--inter-hunk-context");
+
+ if (!patch_mode) {
+ if (add_p_opt.context != -1)
+ die(_("the option '%s' requires '%s'"), "--unified", "--patch");
+ if (add_p_opt.interhunkcontext != -1)
+ die(_("the option '%s' requires '%s'"), "--inter-hunk-context", "--patch");
+ }
+
ret = do_push_stash(&ps, stash_msg, quiet, keep_index,
- patch_mode, include_untracked, only_staged);
+ patch_mode, &add_p_opt, include_untracked,
+ only_staged);
strbuf_release(&stash_msg_buf);
return ret;
}
+static int write_commit_with_parents(struct repository *r,
+ struct object_id *out,
+ const struct object_id *oid,
+ struct commit_list *parents)
+{
+ size_t author_len, committer_len;
+ struct commit *this;
+ const char *orig_author, *orig_committer;
+ char *author = NULL, *committer = NULL;
+ const char *buffer;
+ unsigned long bufsize;
+ const char *p;
+ struct strbuf msg = STRBUF_INIT;
+ int ret = 0;
+ struct ident_split id;
+
+ this = lookup_commit_reference(r, oid);
+ buffer = repo_get_commit_buffer(r, this, &bufsize);
+ orig_author = find_commit_header(buffer, "author", &author_len);
+ orig_committer = find_commit_header(buffer, "committer", &committer_len);
+
+ if (!orig_author || !orig_committer) {
+ ret = error(_("cannot parse commit %s"), oid_to_hex(oid));
+ goto out;
+ }
+
+ if (split_ident_line(&id, orig_author, author_len) < 0 ||
+ split_ident_line(&id, orig_committer, committer_len) < 0) {
+ ret = error(_("invalid author or committer for %s"), oid_to_hex(oid));
+ goto out;
+ }
+
+ p = strstr(buffer, "\n\n");
+ strbuf_addstr(&msg, "git stash: ");
+
+ if (p)
+ strbuf_add(&msg, p + 2, bufsize - (p + 2 - buffer));
+ strbuf_complete_line(&msg);
+
+ author = xmemdupz(orig_author, author_len);
+ committer = xmemdupz(orig_committer, committer_len);
+
+ if (commit_tree_extended(msg.buf, msg.len,
+ r->hash_algo->empty_tree, parents,
+ out, author, committer,
+ NULL, NULL)) {
+ ret = error(_("could not write commit"));
+ goto out;
+ }
+out:
+ strbuf_release(&msg);
+ repo_unuse_commit_buffer(r, this, buffer);
+ free(author);
+ free(committer);
+ return ret;
+}
+
+static int do_import_stash(struct repository *r, const char *rev)
+{
+ struct object_id chain;
+ int res = 0;
+ const char *buffer = NULL;
+ unsigned long bufsize;
+ struct commit *this = NULL;
+ struct commit_list *items = NULL, *cur;
+ char *msg = NULL;
+
+ if (repo_get_oid(r, rev, &chain))
+ return error(_("not a valid revision: %s"), rev);
+
+ this = lookup_commit_reference(r, &chain);
+ if (!this)
+ return error(_("not a commit: %s"), rev);
+
+ /*
+ * Walk the commit history, finding each stash entry, and load data into
+ * the array.
+ */
+ for (;;) {
+ const char *author, *committer;
+ size_t author_len, committer_len;
+ const char *p;
+ const char *expected = "git stash <git@stash> 1000684800 +0000";
+ const char *prefix = "git stash: ";
+ struct commit *stash;
+ struct tree *tree = repo_get_commit_tree(r, this);
+
+ if (!tree ||
+ !oideq(&tree->object.oid, r->hash_algo->empty_tree) ||
+ (this->parents &&
+ (!this->parents->next || this->parents->next->next))) {
+ res = error(_("%s is not a valid exported stash commit"),
+ oid_to_hex(&this->object.oid));
+ goto out;
+ }
+
+ buffer = repo_get_commit_buffer(r, this, &bufsize);
+
+ if (!this->parents) {
+ /*
+ * We don't have any parents. Make sure this is our
+ * root commit.
+ */
+ author = find_commit_header(buffer, "author", &author_len);
+ committer = find_commit_header(buffer, "committer", &committer_len);
+
+ if (!author || !committer) {
+ error(_("cannot parse commit %s"), oid_to_hex(&this->object.oid));
+ goto out;
+ }
+
+ if (author_len != strlen(expected) ||
+ committer_len != strlen(expected) ||
+ memcmp(author, expected, author_len) ||
+ memcmp(committer, expected, committer_len)) {
+ res = error(_("found root commit %s with invalid data"), oid_to_hex(&this->object.oid));
+ goto out;
+ }
+ break;
+ }
+
+ p = strstr(buffer, "\n\n");
+ if (!p) {
+ res = error(_("cannot parse commit %s"), oid_to_hex(&this->object.oid));
+ goto out;
+ }
+
+ p += 2;
+ if (((size_t)(bufsize - (p - buffer)) < strlen(prefix)) ||
+ memcmp(prefix, p, strlen(prefix))) {
+ res = error(_("found stash commit %s without expected prefix"), oid_to_hex(&this->object.oid));
+ goto out;
+ }
+
+ stash = this->parents->next->item;
+
+ if (repo_parse_commit(r, this->parents->item) ||
+ repo_parse_commit(r, stash)) {
+ res = error(_("cannot parse parents of commit: %s"),
+ oid_to_hex(&this->object.oid));
+ goto out;
+ }
+
+ if (check_stash_topology(r, stash)) {
+ res = error(_("%s does not look like a stash commit"),
+ oid_to_hex(&stash->object.oid));
+ goto out;
+ }
+
+ repo_unuse_commit_buffer(r, this, buffer);
+ buffer = NULL;
+ items = commit_list_insert(stash, &items);
+ this = this->parents->item;
+ }
+
+ /*
+ * Now, walk each entry, adding it to the stash as a normal stash
+ * commit.
+ */
+ for (cur = items; cur; cur = cur->next) {
+ const char *p;
+ struct object_id *oid;
+
+ this = cur->item;
+ oid = &this->object.oid;
+ buffer = repo_get_commit_buffer(r, this, &bufsize);
+ if (!buffer) {
+ res = error(_("cannot read commit buffer for %s"), oid_to_hex(oid));
+ goto out;
+ }
+
+ p = strstr(buffer, "\n\n");
+ if (!p) {
+ res = error(_("cannot parse commit %s"), oid_to_hex(oid));
+ goto out;
+ }
+
+ p += 2;
+ msg = xmemdupz(p, bufsize - (p - buffer));
+ repo_unuse_commit_buffer(r, this, buffer);
+ buffer = NULL;
+
+ if (do_store_stash(oid, msg, 1)) {
+ res = error(_("cannot save the stash for %s"), oid_to_hex(oid));
+ goto out;
+ }
+ FREE_AND_NULL(msg);
+ }
+out:
+ if (this && buffer)
+ repo_unuse_commit_buffer(r, this, buffer);
+ free_commit_list(items);
+ free(msg);
+
+ return res;
+}
+
+static int import_stash(int argc, const char **argv, const char *prefix,
+ struct repository *repo)
+{
+ struct option options[] = {
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, options,
+ git_stash_import_usage,
+ PARSE_OPT_KEEP_DASHDASH);
+
+ if (argc != 1)
+ usage_msg_opt("a revision is required", git_stash_import_usage, options);
+
+ return do_import_stash(repo, argv[0]);
+}
+
+struct stash_entry_data {
+ struct repository *r;
+ struct commit_list **items;
+ size_t count;
+};
+
+static int collect_stash_entries(const char *refname UNUSED,
+ struct object_id *old_oid UNUSED,
+ struct object_id *new_oid,
+ const char *committer UNUSED,
+ timestamp_t timestamp UNUSED,
+ int tz UNUSED, const char *msg UNUSED,
+ void *cb_data)
+{
+ struct stash_entry_data *data = cb_data;
+ struct commit *stash;
+
+ data->count++;
+ stash = lookup_commit_reference(data->r, new_oid);
+ if (!stash || check_stash_topology(data->r, stash)) {
+ return error(_("%s does not look like a stash commit"),
+ oid_to_hex(new_oid));
+ }
+ data->items = commit_list_append(stash, data->items);
+ return 0;
+}
+
+static int do_export_stash(struct repository *r,
+ const char *ref,
+ int argc,
+ const char **argv)
+{
+ struct object_id base;
+ struct object_context unused;
+ struct commit *prev;
+ struct commit_list *items = NULL, **iter = &items, *cur;
+ int res = 0;
+ int i;
+ struct strbuf revision = STRBUF_INIT;
+ const char *author, *committer;
+
+ /*
+ * This is an arbitrary, fixed date, specifically the one used by git
+ * format-patch. The goal is merely to produce reproducible output.
+ */
+ prepare_fallback_ident("git stash", "git@stash");
+ author = fmt_ident("git stash", "git@stash", WANT_BLANK_IDENT,
+ "2001-09-17T00:00:00Z", 0);
+ committer = fmt_ident("git stash", "git@stash", WANT_BLANK_IDENT,
+ "2001-09-17T00:00:00Z", 0);
+
+ /* First, we create a single empty commit. */
+ if (commit_tree_extended("", 0, r->hash_algo->empty_tree, NULL,
+ &base, author, committer, NULL, NULL))
+ return error(_("unable to write base commit"));
+
+ prev = lookup_commit_reference(r, &base);
+
+ if (argc) {
+ /*
+ * Find each specified stash, and load data into the array.
+ */
+ for (i = 0; i < argc; i++) {
+ struct object_id oid;
+ struct commit *stash;
+
+ if (parse_stash_revision(&revision, argv[i], 1) ||
+ get_oid_with_context(r, revision.buf,
+ GET_OID_QUIETLY | GET_OID_GENTLY,
+ &oid, &unused)) {
+ res = error(_("unable to find stash entry %s"), argv[i]);
+ goto out;
+ }
+
+ stash = lookup_commit_reference(r, &oid);
+ if (!stash || check_stash_topology(r, stash)) {
+ res = error(_("%s does not look like a stash commit"),
+ revision.buf);
+ goto out;
+ }
+ iter = commit_list_append(stash, iter);
+ }
+ } else {
+ /*
+ * Walk the reflog, finding each stash entry, and load data into the
+ * array.
+ */
+ struct stash_entry_data cb_data = {
+ .r = r, .items = iter,
+ };
+ if (refs_for_each_reflog_ent_reverse(get_main_ref_store(r),
+ "refs/stash",
+ collect_stash_entries,
+ &cb_data) && cb_data.count)
+ goto out;
+ }
+
+ /*
+ * Now, create a set of commits identical to the regular stash commits,
+ * but where their first parents form a chain to our original empty
+ * base commit.
+ */
+ items = reverse_commit_list(items);
+ for (cur = items; cur; cur = cur->next) {
+ struct commit_list *parents = NULL;
+ struct commit_list **next = &parents;
+ struct object_id out;
+ struct commit *stash = cur->item;
+
+ next = commit_list_append(prev, next);
+ next = commit_list_append(stash, next);
+ res = write_commit_with_parents(r, &out, &stash->object.oid, parents);
+ free_commit_list(parents);
+ if (res)
+ goto out;
+ prev = lookup_commit_reference(r, &out);
+ }
+ if (ref)
+ refs_update_ref(get_main_ref_store(r), NULL, ref,
+ &prev->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ else
+ puts(oid_to_hex(&prev->object.oid));
+out:
+ strbuf_release(&revision);
+ free_commit_list(items);
+
+ return res;
+}
+
+enum export_action {
+ ACTION_NONE,
+ ACTION_PRINT,
+ ACTION_TO_REF,
+};
+
+static int export_stash(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo)
+{
+ const char *ref = NULL;
+ enum export_action action = ACTION_NONE;
+ struct option options[] = {
+ OPT_CMDMODE(0, "print", &action,
+ N_("print the object ID instead of writing it to a ref"),
+ ACTION_PRINT),
+ OPT_STRING(0, "to-ref", &ref, "ref",
+ N_("save the data to the given ref")),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, options,
+ git_stash_export_usage,
+ PARSE_OPT_KEEP_DASHDASH);
+
+ if (ref && action == ACTION_NONE)
+ action = ACTION_TO_REF;
+
+ if (action == ACTION_NONE || (ref && action == ACTION_PRINT))
+ return error(_("exactly one of --print and --to-ref is required"));
+
+ return do_export_stash(repo, ref, argc, argv);
+}
+
int cmd_stash(int argc,
const char **argv,
const char *prefix,
@@ -1904,13 +2386,15 @@ int cmd_stash(int argc,
OPT_SUBCOMMAND("store", &fn, store_stash),
OPT_SUBCOMMAND("create", &fn, create_stash),
OPT_SUBCOMMAND("push", &fn, push_stash_unassumed),
+ OPT_SUBCOMMAND("export", &fn, export_stash),
+ OPT_SUBCOMMAND("import", &fn, import_stash),
OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE),
OPT_END()
};
const char **args_copy;
int ret;
- git_config(git_stash_config, NULL);
+ repo_config(the_repository, git_stash_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_stash_usage,
PARSE_OPT_SUBCOMMAND_OPTIONAL |
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index e147f3ff92..4a566cbc5d 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -55,7 +55,7 @@ int cmd_stripspace(int argc,
if (mode == STRIP_COMMENTS || mode == COMMENT_LINES) {
setup_git_directory_gently(&nongit);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
}
if (strbuf_read(&buf, 0, 1024) < 0)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 53da2116dd..07a1935cbe 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -28,10 +28,12 @@
#include "diff.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "advice.h"
#include "branch.h"
#include "list-objects-filter-options.h"
+#include "wildmatch.h"
+#include "strbuf.h"
#define OPT_QUIET (1 << 0)
#define OPT_CACHED (1 << 1)
@@ -41,61 +43,9 @@
typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
void *cb_data);
-static int repo_get_default_remote(struct repository *repo, char **default_remote)
-{
- char *dest = NULL;
- struct strbuf sb = STRBUF_INIT;
- struct ref_store *store = get_main_ref_store(repo);
- const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
- NULL);
-
- if (!refname)
- return die_message(_("No such ref: %s"), "HEAD");
-
- /* detached HEAD */
- if (!strcmp(refname, "HEAD")) {
- *default_remote = xstrdup("origin");
- return 0;
- }
-
- if (!skip_prefix(refname, "refs/heads/", &refname))
- return die_message(_("Expecting a full ref name, got %s"),
- refname);
-
- strbuf_addf(&sb, "branch.%s.remote", refname);
- if (repo_config_get_string(repo, sb.buf, &dest))
- *default_remote = xstrdup("origin");
- else
- *default_remote = dest;
-
- strbuf_release(&sb);
- return 0;
-}
-
-static int get_default_remote_submodule(const char *module_path, char **default_remote)
-{
- struct repository subrepo;
- int ret;
-
- if (repo_submodule_init(&subrepo, the_repository, module_path,
- null_oid(the_hash_algo)) < 0)
- return die_message(_("could not get a repository handle for submodule '%s'"),
- module_path);
- ret = repo_get_default_remote(&subrepo, default_remote);
- repo_clear(&subrepo);
-
- return ret;
-}
-
static char *get_default_remote(void)
{
- char *default_remote;
- int code = repo_get_default_remote(the_repository, &default_remote);
-
- if (code)
- exit(code);
-
- return default_remote;
+ return xstrdup(repo_default_remote(the_repository));
}
static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
@@ -105,7 +55,7 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
struct strbuf remotesb = STRBUF_INIT;
strbuf_addf(&remotesb, "remote.%s.url", remote);
- if (git_config_get_string(remotesb.buf, &remoteurl)) {
+ if (repo_config_get_string(the_repository, remotesb.buf, &remoteurl)) {
if (!quiet)
warning(_("could not look up configuration '%s'. "
"Assuming this repository is its own "
@@ -122,6 +72,46 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
return resolved_url;
}
+static int get_default_remote_submodule(const char *module_path, char **default_remote)
+{
+ const struct submodule *sub;
+ struct repository subrepo;
+ const char *remote_name = NULL;
+ char *url = NULL;
+
+ sub = submodule_from_path(the_repository, null_oid(the_hash_algo), module_path);
+ if (sub && sub->url) {
+ url = xstrdup(sub->url);
+
+ /* Possibly a url relative to parent */
+ if (starts_with_dot_dot_slash(url) ||
+ starts_with_dot_slash(url)) {
+ char *oldurl = url;
+
+ url = resolve_relative_url(oldurl, NULL, 1);
+ free(oldurl);
+ }
+ }
+
+ if (repo_submodule_init(&subrepo, the_repository, module_path,
+ null_oid(the_hash_algo)) < 0)
+ return die_message(_("could not get a repository handle for submodule '%s'"),
+ module_path);
+
+ /* Look up by URL first */
+ if (url)
+ remote_name = repo_remote_from_url(&subrepo, url);
+ if (!remote_name)
+ remote_name = repo_default_remote(&subrepo);
+
+ *default_remote = xstrdup(remote_name);
+
+ repo_clear(&subrepo);
+ free(url);
+
+ return 0;
+}
+
/* the result should be freed by the caller. */
static char *get_submodule_displaypath(const char *path, const char *prefix,
const char *super_prefix)
@@ -303,7 +293,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
char *displaypath;
if (validate_submodule_path(path) < 0)
- exit(128);
+ die(NULL);
displaypath = get_submodule_displaypath(path, info->prefix,
info->super_prefix);
@@ -438,18 +428,6 @@ cleanup:
return ret;
}
-static int starts_with_dot_slash(const char *const path)
-{
- return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
- PATH_MATCH_XPLATFORM);
-}
-
-static int starts_with_dot_dot_slash(const char *const path)
-{
- return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
- PATH_MATCH_XPLATFORM);
-}
-
struct init_cb {
const char *prefix;
const char *super_prefix;
@@ -482,7 +460,7 @@ static void init_submodule(const char *path, const char *prefix,
*/
if (!is_submodule_active(the_repository, path)) {
strbuf_addf(&sb, "submodule.%s.active", sub->name);
- git_config_set_gently(sb.buf, "true");
+ repo_config_set_gently(the_repository, sb.buf, "true");
strbuf_reset(&sb);
}
@@ -492,7 +470,7 @@ static void init_submodule(const char *path, const char *prefix,
* .gitmodules, so look it up directly.
*/
strbuf_addf(&sb, "submodule.%s.url", sub->name);
- if (git_config_get_string(sb.buf, &url)) {
+ if (repo_config_get_string(the_repository, sb.buf, &url)) {
if (!sub->url)
die(_("No url found for submodule path '%s' in .gitmodules"),
displaypath);
@@ -508,7 +486,7 @@ static void init_submodule(const char *path, const char *prefix,
free(oldurl);
}
- if (git_config_set_gently(sb.buf, url))
+ if (repo_config_set_gently(the_repository, sb.buf, url))
die(_("Failed to register url for submodule path '%s'"),
displaypath);
if (!(flags & OPT_QUIET))
@@ -520,7 +498,7 @@ static void init_submodule(const char *path, const char *prefix,
/* Copy "update" setting when it is not set yet */
strbuf_addf(&sb, "submodule.%s.update", sub->name);
- if (git_config_get_string_tmp(sb.buf, &upd) &&
+ if (repo_config_get_string_tmp(the_repository, sb.buf, &upd) &&
sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
if (sub->update_strategy.type == SM_UPDATE_COMMAND) {
fprintf(stderr, _("warning: command update mode suggested for submodule '%s'\n"),
@@ -530,7 +508,7 @@ static void init_submodule(const char *path, const char *prefix,
upd = submodule_update_type_to_string(sub->update_strategy.type);
}
- if (git_config_set_gently(sb.buf, upd))
+ if (repo_config_set_gently(the_repository, sb.buf, upd))
die(_("Failed to register update mode for submodule path '%s'"), displaypath);
}
strbuf_release(&sb);
@@ -573,7 +551,7 @@ static int module_init(int argc, const char **argv, const char *prefix,
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
- if (!argc && !git_config_get("submodule.active"))
+ if (!argc && !repo_config_get(the_repository, "submodule.active"))
module_list_active(&list);
info.prefix = prefix;
@@ -643,7 +621,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
};
if (validate_submodule_path(path) < 0)
- exit(128);
+ die(NULL);
if (!submodule_from_path(the_repository, null_oid(the_hash_algo), path))
die(_("no submodule mapping found in .gitmodules for path '%s'"),
@@ -673,7 +651,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
"--ignore-submodules=dirty", "--quiet", "--",
path, NULL);
- git_config(git_diff_basic_config, NULL);
+ repo_config(the_repository, git_diff_basic_config, NULL);
repo_init_revisions(the_repository, &rev, NULL);
rev.abbrev = 0;
@@ -1058,7 +1036,7 @@ static void prepare_submodule_summary(struct summary_cb *info,
config_key = xstrfmt("submodule.%s.ignore",
sub->name);
- if (!git_config_get_string_tmp(config_key, &value))
+ if (!repo_config_get_string_tmp(the_repository, config_key, &value))
ignore_all = !strcmp(value, "all");
else if (sub->ignore)
ignore_all = !strcmp(sub->ignore, "all");
@@ -1132,7 +1110,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
if (info->argc)
strvec_pushv(&diff_args, info->argv);
- git_config(git_diff_basic_config, NULL);
+ repo_config(the_repository, git_diff_basic_config, NULL);
repo_init_revisions(the_repository, &rev, info->prefix);
rev.abbrev = 0;
precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
@@ -1257,7 +1235,7 @@ static void sync_submodule(const char *path, const char *prefix,
return;
if (validate_submodule_path(path) < 0)
- exit(128);
+ die(NULL);
sub = submodule_from_path(the_repository, null_oid(the_hash_algo), path);
@@ -1286,7 +1264,7 @@ static void sync_submodule(const char *path, const char *prefix,
strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.url", sub->name);
- if (git_config_set_gently(sb.buf, super_config_url))
+ if (repo_config_set_gently(the_repository, sb.buf, super_config_url))
die(_("failed to register url for submodule path '%s'"),
displaypath);
@@ -1304,7 +1282,7 @@ static void sync_submodule(const char *path, const char *prefix,
submodule_to_gitdir(the_repository, &sb, path);
strbuf_addstr(&sb, "/config");
- if (git_config_set_in_file_gently(sb.buf, remote_key, NULL, sub_origin_url))
+ if (repo_config_set_in_file_gently(the_repository, sb.buf, remote_key, NULL, sub_origin_url))
die(_("failed to update remote for submodule '%s'"),
path);
@@ -1402,7 +1380,7 @@ static void deinit_submodule(const char *path, const char *prefix,
char *sub_git_dir = xstrfmt("%s/.git", path);
if (validate_submodule_path(path) < 0)
- exit(128);
+ die(NULL);
sub = submodule_from_path(the_repository, null_oid(the_hash_algo), path);
@@ -1582,7 +1560,7 @@ static const char alternate_error_advice[] = N_(
);
static int add_possible_reference_from_superproject(
- struct object_directory *odb, void *sas_cb)
+ struct odb_source *alt_odb, void *sas_cb)
{
struct submodule_alternate_setup *sas = sas_cb;
size_t len;
@@ -1591,12 +1569,12 @@ static int add_possible_reference_from_superproject(
* If the alternate object store is another repository, try the
* standard layout with .git/(modules/<name>)+/objects
*/
- if (strip_suffix(odb->path, "/objects", &len)) {
+ if (strip_suffix(alt_odb->path, "/objects", &len)) {
struct repository alternate;
char *sm_alternate;
struct strbuf sb = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
- strbuf_add(&sb, odb->path, len);
+ strbuf_add(&sb, alt_odb->path, len);
if (repo_init(&alternate, sb.buf, NULL) < 0)
die(_("could not get a repository handle for gitdir '%s'"),
@@ -1647,11 +1625,11 @@ static void prepare_possible_alternates(const char *sm_name,
char *sm_alternate = NULL, *error_strategy = NULL;
struct submodule_alternate_setup sas = SUBMODULE_ALTERNATE_SETUP_INIT;
- git_config_get_string("submodule.alternateLocation", &sm_alternate);
+ repo_config_get_string(the_repository, "submodule.alternateLocation", &sm_alternate);
if (!sm_alternate)
return;
- git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
+ repo_config_get_string(the_repository, "submodule.alternateErrorStrategy", &error_strategy);
if (!error_strategy)
error_strategy = xstrdup("die");
@@ -1668,7 +1646,8 @@ static void prepare_possible_alternates(const char *sm_name,
die(_("Value '%s' for submodule.alternateErrorStrategy is not recognized"), error_strategy);
if (!strcmp(sm_alternate, "superproject"))
- foreach_alt_odb(add_possible_reference_from_superproject, &sas);
+ odb_for_each_alternate(the_repository->objects,
+ add_possible_reference_from_superproject, &sas);
else if (!strcmp(sm_alternate, "no"))
; /* do nothing */
else
@@ -1724,7 +1703,7 @@ static int clone_submodule(const struct module_clone_data *clone_data,
char *to_free = NULL;
if (validate_submodule_path(clone_data_path) < 0)
- exit(128);
+ die(NULL);
if (!is_absolute_path(clone_data->path))
clone_data_path = to_free = xstrfmt("%s/%s", repo_get_work_tree(the_repository),
@@ -1831,14 +1810,14 @@ static int clone_submodule(const struct module_clone_data *clone_data,
die(_("could not get submodule directory for '%s'"), clone_data_path);
/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
- git_config_get_string("submodule.alternateLocation", &sm_alternate);
+ repo_config_get_string(the_repository, "submodule.alternateLocation", &sm_alternate);
if (sm_alternate)
- git_config_set_in_file(p, "submodule.alternateLocation",
- sm_alternate);
- git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
+ repo_config_set_in_file(the_repository, p, "submodule.alternateLocation",
+ sm_alternate);
+ repo_config_get_string(the_repository, "submodule.alternateErrorStrategy", &error_strategy);
if (error_strategy)
- git_config_set_in_file(p, "submodule.alternateErrorStrategy",
- error_strategy);
+ repo_config_set_in_file(the_repository, p, "submodule.alternateErrorStrategy",
+ error_strategy);
free(sm_alternate);
free(error_strategy);
@@ -2545,7 +2524,7 @@ static int ensure_core_worktree(const char *path)
abs_path = absolute_pathdup(path);
rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
- git_config_set_in_file(cfg_file, "core.worktree", rel_path);
+ repo_config_set_in_file(the_repository, cfg_file, "core.worktree", rel_path);
free(cfg_file);
free(abs_path);
@@ -2660,8 +2639,10 @@ static int update_submodule(struct update_data *update_data)
if (code)
return code;
code = remote_submodule_branch(update_data->sm_path, &branch);
- if (code)
+ if (code) {
+ free(remote_name);
return code;
+ }
remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
free(remote_name);
@@ -2851,7 +2832,7 @@ static int module_update(int argc, const char **argv, const char *prefix,
};
update_clone_config_from_gitmodules(&opt.max_jobs);
- git_config(git_update_clone_config, &opt.max_jobs);
+ repo_config(the_repository, git_update_clone_config, &opt.max_jobs);
argc = parse_options(argc, argv, prefix, module_update_options,
git_submodule_helper_usage, 0);
@@ -2899,7 +2880,7 @@ static int module_update(int argc, const char **argv, const char *prefix,
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
- if (!argc && !git_config_get("submodule.active"))
+ if (!argc && !repo_config_get(the_repository, "submodule.active"))
module_list_active(&list);
info.prefix = opt.prefix;
@@ -3149,7 +3130,7 @@ static int module_create_branch(int argc, const char **argv, const char *prefix,
NULL
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
track = git_branch_track;
argc = parse_options(argc, argv, prefix, options, usage, 0);
@@ -3328,9 +3309,11 @@ static void configure_added_submodule(struct add_data *add_data)
char *key;
struct child_process add_submod = CHILD_PROCESS_INIT;
struct child_process add_gitmodules = CHILD_PROCESS_INIT;
+ const struct string_list *values;
+ int matched = 0;
key = xstrfmt("submodule.%s.url", add_data->sm_name);
- git_config_set_gently(key, add_data->realrepo);
+ repo_config_set_gently(the_repository, key, add_data->realrepo);
free(key);
add_submod.git_cmd = 1;
@@ -3370,20 +3353,28 @@ static void configure_added_submodule(struct add_data *add_data)
* is_submodule_active(), since that function needs to find
* out the value of "submodule.active" again anyway.
*/
- if (!git_config_get("submodule.active")) {
+ if (repo_config_get(the_repository, "submodule.active") || /* key absent */
+ repo_config_get_string_multi(the_repository, "submodule.active", &values)) {
/*
* If the submodule being added isn't already covered by the
* current configured pathspec, set the submodule's active flag
*/
- if (!is_submodule_active(the_repository, add_data->sm_path)) {
+ key = xstrfmt("submodule.%s.active", add_data->sm_name);
+ repo_config_set_gently(the_repository, key, "true");
+ free(key);
+ } else {
+ for (size_t i = 0; i < values->nr; i++) {
+ const char *pat = values->items[i].string;
+ if (!wildmatch(pat, add_data->sm_path, 0)) { /* match found */
+ matched = 1;
+ break;
+ }
+ }
+ if (!matched) { /* no pattern matched -> force-enable */
key = xstrfmt("submodule.%s.active", add_data->sm_name);
- git_config_set_gently(key, "true");
+ repo_config_set_gently(the_repository, key, "true");
free(key);
}
- } else {
- key = xstrfmt("submodule.%s.active", add_data->sm_name);
- git_config_set_gently(key, "true");
- free(key);
}
}
@@ -3444,6 +3435,9 @@ static int module_add(int argc, const char **argv, const char *prefix,
struct add_data add_data = ADD_DATA_INIT;
const char *ref_storage_format = NULL;
char *to_free = NULL;
+ const struct submodule *existing;
+ struct strbuf buf = STRBUF_INIT;
+ char *sm_name_to_free = NULL;
struct option options[] = {
OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
N_("branch of repository to add as submodule")),
@@ -3524,7 +3518,7 @@ static int module_add(int argc, const char **argv, const char *prefix,
strip_dir_trailing_slashes(add_data.sm_path);
if (validate_submodule_path(add_data.sm_path) < 0)
- exit(128);
+ die(NULL);
die_on_index_match(add_data.sm_path, force);
die_on_repo_without_commits(add_data.sm_path);
@@ -3546,6 +3540,28 @@ static int module_add(int argc, const char **argv, const char *prefix,
if(!add_data.sm_name)
add_data.sm_name = add_data.sm_path;
+ existing = submodule_from_name(the_repository,
+ null_oid(the_hash_algo),
+ add_data.sm_name);
+
+ if (existing && strcmp(existing->path, add_data.sm_path)) {
+ if (!force) {
+ die(_("submodule name '%s' already used for path '%s'"),
+ add_data.sm_name, existing->path);
+ }
+ /* --force: build <name><n> until unique */
+ for (int i = 1; ; i++) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s%d", add_data.sm_name, i);
+ if (!submodule_from_name(the_repository,
+ null_oid(the_hash_algo),
+ buf.buf)) {
+ break;
+ }
+ }
+ add_data.sm_name = sm_name_to_free = strbuf_detach(&buf, NULL);
+ }
+
if (check_submodule_name(add_data.sm_name))
die(_("'%s' is not a valid submodule name"), add_data.sm_name);
@@ -3561,6 +3577,7 @@ static int module_add(int argc, const char **argv, const char *prefix,
ret = 0;
cleanup:
+ free(sm_name_to_free);
free(add_data.sm_path);
free(to_free);
strbuf_release(&sb);
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 299d23d76a..231e41e715 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "refs.h"
#include "parse-options.h"
@@ -59,7 +60,7 @@ int cmd_symbolic_ref(int argc,
OPT_END(),
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options,
git_symbolic_ref_usage, 0);
if (msg && !*msg)
diff --git a/builtin/tag.c b/builtin/tag.c
index 4742b27d16..f0665af3ac 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -19,7 +19,7 @@
#include "refs.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
#include "path.h"
#include "tag.h"
#include "parse-options.h"
@@ -244,7 +244,7 @@ static void write_tag_body(int fd, const struct object_id *oid)
struct strbuf payload = STRBUF_INIT;
struct strbuf signature = STRBUF_INIT;
- orig = buf = repo_read_object_file(the_repository, oid, &type, &size);
+ orig = buf = odb_read_object(the_repository->objects, oid, &type, &size);
if (!buf)
return;
if (parse_signature(buf, size, &payload, &signature)) {
@@ -271,8 +271,8 @@ static int build_tag_object(struct strbuf *buf, int sign, struct object_id *resu
struct object_id *compat_oid = NULL, compat_oid_buf;
if (sign && do_sign(buf, &compat_oid, &compat_oid_buf) < 0)
return error(_("unable to sign the tag"));
- if (write_object_file_flags(buf->buf, buf->len, OBJ_TAG, result,
- compat_oid, 0) < 0)
+ if (odb_write_object_ext(the_repository->objects, buf->buf,
+ buf->len, OBJ_TAG, result, compat_oid, 0) < 0)
return error(_("unable to write tag file"));
return 0;
}
@@ -304,7 +304,7 @@ static void create_tag(const struct object_id *object, const char *object_ref,
struct strbuf header = STRBUF_INIT;
int should_edit;
- type = oid_object_info(the_repository, object, NULL);
+ type = odb_read_object_info(the_repository->objects, object, NULL);
if (type <= OBJ_NONE)
die(_("bad object type."));
@@ -401,13 +401,13 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
}
strbuf_addstr(sb, " (");
- type = oid_object_info(the_repository, oid, NULL);
+ type = odb_read_object_info(the_repository->objects, oid, NULL);
switch (type) {
default:
strbuf_addstr(sb, "object of unknown type");
break;
case OBJ_COMMIT:
- if ((buf = repo_read_object_file(the_repository, oid, &type, &size))) {
+ if ((buf = odb_read_object(the_repository->objects, oid, &type, &size))) {
subject_len = find_commit_subject(buf, &subject_start);
strbuf_insert(sb, sb->len, subject_start, subject_len);
} else {
@@ -546,7 +546,7 @@ int cmd_tag(int argc,
* Try to set sort keys from config. If config does not set any,
* fall back on default (refname) sorting.
*/
- git_config(git_tag_config, &sorting_options);
+ repo_config(the_repository, git_tag_config, &sorting_options);
if (!sorting_options.nr)
string_list_append(&sorting_options, "refname");
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index e33acfc4ee..87877a9fab 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,10 +1,11 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "hex.h"
#include "object-file.h"
#include "object-name.h"
-#include "object-store.h"
+#include "odb.h"
static char *create_temp_file(struct object_id *oid)
{
@@ -14,7 +15,7 @@ static char *create_temp_file(struct object_id *oid)
unsigned long size;
int fd;
- buf = repo_read_object_file(the_repository, oid, &type, &size);
+ buf = odb_read_object(the_repository->objects, oid, &type, &size);
if (!buf || type != OBJ_BLOB)
die("unable to read blob object %s", oid_to_hex(oid));
@@ -43,7 +44,7 @@ int cmd_unpack_file(int argc,
if (repo_get_oid(the_repository, argv[1], &oid))
die("Not a valid object name %s", argv[1]);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
puts(create_temp_file(&oid));
return 0;
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index e905d5f4e1..7ae7c82b6c 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -9,7 +9,7 @@
#include "git-zlib.h"
#include "hex.h"
#include "object-file.h"
-#include "object-store.h"
+#include "odb.h"
#include "object.h"
#include "delta.h"
#include "pack.h"
@@ -204,8 +204,8 @@ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
{
struct object_id oid;
- if (write_object_file(obj_buf->buffer, obj_buf->size,
- obj->type, &oid) < 0)
+ if (odb_write_object(the_repository->objects, obj_buf->buffer, obj_buf->size,
+ obj->type, &oid) < 0)
die("failed to write object %s", oid_to_hex(&obj->oid));
obj->flags |= FLAG_WRITTEN;
}
@@ -232,7 +232,7 @@ static int check_object(struct object *obj, enum object_type type,
if (!(obj->flags & FLAG_OPEN)) {
unsigned long size;
- int type = oid_object_info(the_repository, &obj->oid, &size);
+ int type = odb_read_object_info(the_repository->objects, &obj->oid, &size);
if (type != obj->type || type <= 0)
die("object of unexpected type");
obj->flags |= FLAG_WRITTEN;
@@ -272,16 +272,16 @@ static void write_object(unsigned nr, enum object_type type,
void *buf, unsigned long size)
{
if (!strict) {
- if (write_object_file(buf, size, type,
- &obj_list[nr].oid) < 0)
+ if (odb_write_object(the_repository->objects, buf, size, type,
+ &obj_list[nr].oid) < 0)
die("failed to write object");
added_object(nr, type, buf, size);
free(buf);
obj_list[nr].obj = NULL;
} else if (type == OBJ_BLOB) {
struct blob *blob;
- if (write_object_file(buf, size, type,
- &obj_list[nr].oid) < 0)
+ if (odb_write_object(the_repository->objects, buf, size, type,
+ &obj_list[nr].oid) < 0)
die("failed to write object");
added_object(nr, type, buf, size);
free(buf);
@@ -403,7 +403,8 @@ static void stream_blob(unsigned long size, unsigned nr)
data.zstream = &zstream;
git_inflate_init(&zstream);
- if (stream_loose_object(&in_stream, size, &info->oid))
+ if (stream_loose_object(the_repository->objects->sources,
+ &in_stream, size, &info->oid))
die(_("failed to write object in stream"));
if (data.status != Z_STREAM_END)
@@ -449,8 +450,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
delta_data = get_data(delta_size);
if (!delta_data)
return;
- if (has_object(the_repository, &base_oid,
- HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
+ if (odb_has_object(the_repository->objects, &base_oid,
+ HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
; /* Ok we have this one */
else if (resolve_against_held(nr, &base_oid,
delta_data, delta_size))
@@ -516,8 +517,8 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
if (resolve_against_held(nr, &base_oid, delta_data, delta_size))
return;
- base = repo_read_object_file(the_repository, &base_oid, &type,
- &base_size);
+ base = odb_read_object(the_repository->objects, &base_oid,
+ &type, &base_size);
if (!base) {
error("failed to read delta-pack base object %s",
oid_to_hex(&base_oid));
@@ -621,7 +622,7 @@ int cmd_unpack_objects(int argc,
disable_replace_refs();
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
quiet = !isatty(2);
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 538b619ba4..2380f3ccd6 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -981,6 +981,7 @@ int cmd_update_index(int argc,
.type = OPTION_SET_INT,
.long_name = "assume-unchanged",
.value = &mark_valid_only,
+ .precision = sizeof(mark_valid_only),
.help = N_("mark files as \"not changing\""),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = MARK_FLAG,
@@ -989,6 +990,7 @@ int cmd_update_index(int argc,
.type = OPTION_SET_INT,
.long_name = "no-assume-unchanged",
.value = &mark_valid_only,
+ .precision = sizeof(mark_valid_only),
.help = N_("clear assumed-unchanged bit"),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = UNMARK_FLAG,
@@ -997,6 +999,7 @@ int cmd_update_index(int argc,
.type = OPTION_SET_INT,
.long_name = "skip-worktree",
.value = &mark_skip_worktree_only,
+ .precision = sizeof(mark_skip_worktree_only),
.help = N_("mark files as \"index-only\""),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = MARK_FLAG,
@@ -1005,6 +1008,7 @@ int cmd_update_index(int argc,
.type = OPTION_SET_INT,
.long_name = "no-skip-worktree",
.value = &mark_skip_worktree_only,
+ .precision = sizeof(mark_skip_worktree_only),
.help = N_("clear skip-worktree bit"),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = UNMARK_FLAG,
@@ -1079,6 +1083,7 @@ int cmd_update_index(int argc,
.type = OPTION_SET_INT,
.long_name = "fsmonitor-valid",
.value = &mark_fsmonitor_only,
+ .precision = sizeof(mark_fsmonitor_only),
.help = N_("mark files as fsmonitor valid"),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = MARK_FLAG,
@@ -1087,6 +1092,7 @@ int cmd_update_index(int argc,
.type = OPTION_SET_INT,
.long_name = "no-fsmonitor-valid",
.value = &mark_fsmonitor_only,
+ .precision = sizeof(mark_fsmonitor_only),
.help = N_("clear fsmonitor valid bit"),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = UNMARK_FLAG,
@@ -1097,7 +1103,7 @@ int cmd_update_index(int argc,
show_usage_with_options_if_asked(argc, argv,
update_index_usage, options);
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
prepare_repo_settings(r);
the_repository->settings.command_requires_full_index = 0;
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 2b1e336ba1..195437e7c6 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -3,6 +3,7 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hash.h"
#include "hex.h"
@@ -575,30 +576,7 @@ static void print_rejected_refs(const char *refname,
void *cb_data UNUSED)
{
struct strbuf sb = STRBUF_INIT;
- const char *reason = "";
-
- switch (err) {
- case REF_TRANSACTION_ERROR_NAME_CONFLICT:
- reason = "refname conflict";
- break;
- case REF_TRANSACTION_ERROR_CREATE_EXISTS:
- reason = "reference already exists";
- break;
- case REF_TRANSACTION_ERROR_NONEXISTENT_REF:
- reason = "reference does not exist";
- break;
- case REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE:
- reason = "incorrect old value provided";
- break;
- case REF_TRANSACTION_ERROR_INVALID_NEW_VALUE:
- reason = "invalid new value provided";
- break;
- case REF_TRANSACTION_ERROR_EXPECTED_SYMREF:
- reason = "expected symref but found regular ref";
- break;
- default:
- reason = "unkown failure";
- }
+ const char *reason = ref_transaction_error_msg(err);
strbuf_addf(&sb, "rejected %s %s %s %s\n", refname,
new_oid ? oid_to_hex(new_oid) : new_target,
@@ -792,7 +770,7 @@ int cmd_update_ref(int argc,
OPT_END(),
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_update_ref_usage,
0);
if (msg && !*msg)
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index ba702d30ef..4c12968a83 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "parse-options.h"
#include "server-info.h"
diff --git a/builtin/var.c b/builtin/var.c
index ada642a9fe..cc3a43cde2 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -11,6 +11,7 @@
#include "attr.h"
#include "config.h"
#include "editor.h"
+#include "environment.h"
#include "ident.h"
#include "pager.h"
#include "refs.h"
@@ -181,7 +182,7 @@ static void list_vars(void)
if (ptr->multivalued && *val) {
struct string_list list = STRING_LIST_INIT_DUP;
- string_list_split(&list, val, '\n', -1);
+ string_list_split(&list, val, "\n", -1);
for (size_t i = 0; i < list.nr; i++)
printf("%s=%s\n", ptr->name, list.items[i].string);
string_list_clear(&list, 0);
@@ -226,11 +227,11 @@ int cmd_var(int argc,
usage(var_usage);
if (strcmp(argv[1], "-l") == 0) {
- git_config(show_config, NULL);
+ repo_config(the_repository, show_config, NULL);
list_vars();
return 0;
}
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
git_var = get_git_var(argv[1]);
if (!git_var)
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index 5f749a30da..62398acd72 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -7,6 +7,7 @@
*/
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "object-name.h"
#include "commit.h"
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 34e4ed715f..65fd6629a0 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "run-command.h"
#include "parse-options.h"
@@ -81,7 +82,7 @@ int cmd_verify_pack(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, verify_pack_options,
verify_pack_usage, 0);
if (argc < 1)
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index ed1c40338f..cd6bc11095 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -7,6 +7,7 @@
*/
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "tag.h"
#include "object-name.h"
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 88a36ea9f8..812774a5ca 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -379,13 +379,13 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
bare &&
- git_config_set_multivar_in_file_gently(
+ repo_config_set_multivar_in_file_gently(the_repository,
to_file, "core.bare", NULL, "true", NULL, 0))
error(_("failed to unset '%s' in '%s'"),
"core.bare", to_file);
if (!git_configset_get(&cs, "core.worktree") &&
- git_config_set_in_file_gently(to_file,
- "core.worktree", NULL, NULL))
+ repo_config_set_in_file_gently(the_repository, to_file,
+ "core.worktree", NULL, NULL))
error(_("failed to unset '%s' in '%s'"),
"core.worktree", to_file);
@@ -621,7 +621,7 @@ static void print_preparing_worktree_line(int detach,
else {
struct commit *commit = lookup_commit_reference_by_name(branch);
if (!commit)
- BUG(_("unreachable: invalid reference: %s"), branch);
+ BUG("unreachable: invalid reference: %s", branch);
fprintf_ln(stderr, _("Preparing worktree (detached HEAD %s)"),
repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
}
@@ -1448,7 +1448,7 @@ int cmd_worktree(int ac,
OPT_END()
};
- git_config(git_worktree_config, NULL);
+ repo_config(the_repository, git_worktree_config, NULL);
if (!prefix)
prefix = "";
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index 5a8dc377ec..e3bd1a40db 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -6,6 +6,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
+#include "environment.h"
#include "gettext.h"
#include "hex.h"
#include "tree.h"
@@ -35,6 +36,7 @@ int cmd_write_tree(int argc,
.type = OPTION_BIT,
.long_name = "ignore-cache-tree",
.value = &flags,
+ .precision = sizeof(flags),
.help = N_("only useful for debugging"),
.flags = PARSE_OPT_HIDDEN | PARSE_OPT_NOARG,
.defval = WRITE_TREE_IGNORE_CACHE_TREE,
@@ -42,7 +44,7 @@ int cmd_write_tree(int argc,
OPT_END()
};
- git_config(git_default_config, NULL);
+ repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, cmd_prefix, write_tree_options,
write_tree_usage, 0);