aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c26
-rw-r--r--builtin/blame.c17
-rw-r--r--builtin/cat-file.c2
-rw-r--r--builtin/checkout.c33
-rw-r--r--builtin/clean.c74
-rw-r--r--builtin/commit-graph.c13
-rw-r--r--builtin/commit.c18
-rw-r--r--builtin/count-objects.c2
-rw-r--r--builtin/describe.c142
-rw-r--r--builtin/diff.c15
-rw-r--r--builtin/fast-import.c4
-rw-r--r--builtin/fmt-merge-msg.c6
-rw-r--r--builtin/for-each-ref.c42
-rw-r--r--builtin/fsck.c25
-rw-r--r--builtin/gc.c14
-rw-r--r--builtin/index-pack.c2
-rw-r--r--builtin/last-modified.c326
-rw-r--r--builtin/log.c129
-rw-r--r--builtin/ls-files.c13
-rw-r--r--builtin/merge-file.c3
-rw-r--r--builtin/merge-recursive.c3
-rw-r--r--builtin/merge-tree.c30
-rw-r--r--builtin/merge.c9
-rw-r--r--builtin/mktag.c2
-rw-r--r--builtin/mktree.c2
-rw-r--r--builtin/multi-pack-index.c31
-rw-r--r--builtin/notes.c26
-rw-r--r--builtin/pack-objects.c41
-rw-r--r--builtin/prune.c2
-rw-r--r--builtin/pull.c20
-rw-r--r--builtin/rebase.c42
-rw-r--r--builtin/receive-pack.c4
-rw-r--r--builtin/reflog.c106
-rw-r--r--builtin/refs.c62
-rw-r--r--builtin/remote.c356
-rw-r--r--builtin/repack.c13
-rw-r--r--builtin/replace.c3
-rw-r--r--builtin/repo.c171
-rw-r--r--builtin/reset.c17
-rw-r--r--builtin/rev-list.c30
-rw-r--r--builtin/revert.c2
-rw-r--r--builtin/stash.c62
-rw-r--r--builtin/submodule--helper.c50
-rw-r--r--builtin/tag.c4
-rw-r--r--builtin/unpack-objects.c20
-rw-r--r--builtin/update-index.c7
-rw-r--r--builtin/var.c2
47 files changed, 1456 insertions, 567 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 88d1d330fa..740c7c4581 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -30,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;
@@ -158,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;
@@ -170,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;
@@ -254,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")),
@@ -386,6 +389,7 @@ int cmd_add(int argc,
char *seen = NULL;
char *ps_matched = NULL;
struct lock_file lock_file = LOCK_INIT;
+ struct odb_transaction *transaction;
repo_config(repo, add_config, NULL);
@@ -395,6 +399,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) {
@@ -402,7 +411,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) {
@@ -561,7 +575,7 @@ int cmd_add(int argc,
string_list_clear(&only_match_skip_worktree, 0);
}
- begin_odb_transaction();
+ transaction = begin_odb_transaction(repo->objects);
ps_matched = xcalloc(pathspec.nr, 1);
if (add_renormalize)
@@ -580,7 +594,7 @@ int cmd_add(int argc,
if (chmod_arg && pathspec.nr)
exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only);
- end_odb_transaction();
+ end_odb_transaction(transaction);
finish:
if (write_locked_index(repo->index, &lock_file,
diff --git a/builtin/blame.c b/builtin/blame.c
index 71efeb7c7e..2703820258 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -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
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index b9eb2bb3b9..fce0b06451 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -848,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)) {
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 37efde5989..f9453473fe 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -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 */
@@ -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);
@@ -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),
@@ -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 a1977b92dc..38b67923a6 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -478,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;
@@ -532,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;
}
@@ -561,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];
@@ -631,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) {
@@ -679,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;
@@ -702,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;
@@ -730,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);
}
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 4992ac146e..fe3ebaadad 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -102,14 +102,15 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
if (opts.progress)
flags |= COMMIT_GRAPH_WRITE_PROGRESS;
- source = odb_find_source(the_repository->objects, opts.obj_dir);
+ source = odb_find_source_or_die(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)
die_errno(_("Could not open commit-graph '%s'"), graph_name);
- else if (open_commit_graph_chain(chain_name, &fd, &st))
+ else if (open_commit_graph_chain(chain_name, &fd, &st,
+ the_repository->hash_algo))
opened = OPENED_CHAIN;
else if (errno != ENOENT)
die_errno(_("could not open commit-graph chain '%s'"), chain_name);
@@ -121,15 +122,15 @@ 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, source);
+ graph = load_commit_graph_one_fd_st(source, fd, &st);
else
- graph = load_commit_graph_chain_fd_st(the_repository, fd, &st,
+ graph = load_commit_graph_chain_fd_st(the_repository->objects, fd, &st,
&incomplete_chain);
if (!graph)
return 1;
- ret = verify_commit_graph(the_repository, graph, flags);
+ ret = verify_commit_graph(graph, flags);
free_commit_graph(graph);
if (incomplete_chain) {
@@ -290,7 +291,7 @@ 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;
- source = odb_find_source(the_repository->objects, opts.obj_dir);
+ source = odb_find_source_or_die(the_repository->objects, opts.obj_dir);
if (opts.reachable) {
if (write_commit_graph_reachable(source, flags, &write_opts))
diff --git a/builtin/commit.c b/builtin/commit.c
index f821fdcfcc..384d0b4e93 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 */
@@ -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");
}
/*
@@ -1730,6 +1742,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")),
@@ -1940,7 +1954,7 @@ int cmd_commit(int argc,
"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."));
- git_test_write_commit_graph_or_die();
+ git_test_write_commit_graph_or_die(the_repository->objects->sources);
repo_rerere(the_repository, 0);
run_auto_maintenance(quiet);
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index b1148a68fa..a61d3b46aa 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -118,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) {
diff --git a/builtin/describe.c b/builtin/describe.c
index d7dd8139de..9f4e26d7ff 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -23,6 +23,8 @@
#include "list-objects.h"
#include "commit-slab.h"
#include "wildmatch.h"
+#include "prio-queue.h"
+#include "oidset.h"
#define MAX_TAGS (FLAG_BITS - 1)
#define DEFAULT_CANDIDATES 10
@@ -249,36 +251,83 @@ 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 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);
+ struct oidset unflagged = OIDSET_INIT;
+
+ 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 & best->flag_within))
+ oidset_insert(&unflagged, &commit->object.oid);
+ }
+
+ 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 (!oidset_size(&unflagged))
break;
- } else
+ } else {
+ oidset_remove(&unflagged, &c->object.oid);
best->depth++;
+ }
while (parents) {
+ unsigned seen, flag_before, flag_after;
struct commit *p = parents->item;
repo_parse_commit(the_repository, p);
- if (!(p->object.flags & SEEN))
- commit_list_insert_by_date(p, list);
+ seen = p->object.flags & SEEN;
+ if (!seen)
+ lazy_queue_put(queue, p);
+ flag_before = p->object.flags & best->flag_within;
p->object.flags |= c->object.flags;
+ flag_after = p->object.flags & best->flag_within;
+ if (!seen && !flag_after)
+ oidset_insert(&unflagged, &p->object.oid);
+ if (seen && !flag_before && flag_after)
+ oidset_remove(&unflagged, &p->object.oid);
parents = parents->next;
}
}
+ oidset_clear(&unflagged);
return seen_commits;
}
@@ -313,18 +362,16 @@ static void append_suffix(int depth, const struct object_id *oid, struct strbuf
repo_find_unique_abbrev(the_repository, oid, abbrev));
}
-static void describe_commit(struct object_id *oid, struct strbuf *dst)
+static void describe_commit(struct commit *cmit, struct strbuf *dst)
{
- struct commit *cmit, *gave_up_on = NULL;
- struct commit_list *list;
+ struct commit *gave_up_on = NULL;
+ 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;
unsigned long seen_commits = 0;
unsigned int unannotated_cnt = 0;
- cmit = lookup_commit_reference(the_repository, oid);
-
n = find_commit_name(&cmit->object.oid);
if (n && (tags || all || n->prio == 2)) {
/*
@@ -332,7 +379,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
*/
append_name(n, dst);
if (n->misnamed || longformat)
- append_suffix(0, n->tag ? get_tagged_oid(n->tag) : oid, dst);
+ append_suffix(0, n->tag ? get_tagged_oid(n->tag) : &cmit->object.oid, dst);
if (suffix)
strbuf_addstr(dst, suffix);
return;
@@ -359,11 +406,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 +443,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 +466,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 +481,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 +497,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;
@@ -489,8 +536,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
}
struct process_commit_data {
- struct object_id current_commit;
- struct object_id looking_for;
+ struct commit *current_commit;
+ const struct object_id *looking_for;
struct strbuf *dst;
struct rev_info *revs;
};
@@ -498,30 +545,38 @@ struct process_commit_data {
static void process_commit(struct commit *commit, void *data)
{
struct process_commit_data *pcd = data;
- pcd->current_commit = commit->object.oid;
+ pcd->current_commit = commit;
}
static void process_object(struct object *obj, const char *path, void *data)
{
struct process_commit_data *pcd = data;
- if (oideq(&pcd->looking_for, &obj->oid) && !pcd->dst->len) {
+ if (oideq(pcd->looking_for, &obj->oid) && !pcd->dst->len) {
reset_revision_walk();
- describe_commit(&pcd->current_commit, pcd->dst);
- strbuf_addf(pcd->dst, ":%s", path);
+ if (pcd->current_commit) {
+ describe_commit(pcd->current_commit, pcd->dst);
+ strbuf_addf(pcd->dst, ":%s", path);
+ }
free_commit_list(pcd->revs->commits);
pcd->revs->commits = NULL;
}
}
-static void describe_blob(struct object_id oid, struct strbuf *dst)
+static void describe_blob(const struct object_id *oid, struct strbuf *dst)
{
struct rev_info revs;
struct strvec args = STRVEC_INIT;
- struct process_commit_data pcd = { *null_oid(the_hash_algo), oid, dst, &revs};
+ struct object_id head_oid;
+ struct process_commit_data pcd = { NULL, oid, dst, &revs};
+
+ if (repo_get_oid(the_repository, "HEAD", &head_oid))
+ die(_("cannot search for blob '%s' on an unborn branch"),
+ oid_to_hex(oid));
strvec_pushl(&args, "internal: The first arg is not parsed",
- "--objects", "--in-commit-order", "--reverse", "HEAD",
+ "--objects", "--in-commit-order", "--reverse",
+ oid_to_hex(&head_oid),
NULL);
repo_init_revisions(the_repository, &revs, NULL);
@@ -535,6 +590,9 @@ static void describe_blob(struct object_id oid, struct strbuf *dst)
reset_revision_walk();
release_revisions(&revs);
strvec_clear(&args);
+
+ if (!dst->len)
+ die(_("blob '%s' not reachable from HEAD"), oid_to_hex(oid));
}
static void describe(const char *arg, int last_one)
@@ -551,10 +609,10 @@ static void describe(const char *arg, int last_one)
cmit = lookup_commit_reference_gently(the_repository, &oid, 1);
if (cmit)
- describe_commit(&oid, &sb);
+ describe_commit(cmit, &sb);
else if (odb_read_object_info(the_repository->objects,
&oid, NULL) == OBJ_BLOB)
- describe_blob(oid, &sb);
+ describe_blob(&oid, &sb);
else
die(_("%s is neither a commit nor blob"), arg);
diff --git a/builtin/diff.c b/builtin/diff.c
index 9a89e25a98..0b23c41456 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -487,6 +487,21 @@ int cmd_diff(int argc,
init_diff_ui_defaults();
repo_config(the_repository, git_diff_ui_config, NULL);
+
+ /*
+ * If we are ignoring the fact that our current directory may
+ * be part of a working tree controlled by a Git repository to
+ * pretend to be a "better GNU diff", we should undo the
+ * effect of the setup code that did a chdir() to the top of
+ * the working tree. Where we came from is recorded in the
+ * prefix.
+ */
+ if (no_index && prefix) {
+ if (chdir(prefix))
+ die(_("cannot come back to cwd"));
+ prefix = NULL;
+ }
+
prefix = precompose_argv_prefix(argc, argv, prefix);
repo_init_revisions(the_repository, &rev, prefix);
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index adf3994be1..2c35f9345d 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -822,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);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index edb93c0b3a..cf4273a52c 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "config.h"
#include "fmt-merge-msg.h"
@@ -13,12 +12,13 @@ static const char * const fmt_merge_msg_usage[] = {
int cmd_fmt_merge_msg(int argc,
const char **argv,
const char *prefix,
- struct repository *repo UNUSED)
+ struct repository *repo)
{
char *inpath = NULL;
const char *message = NULL;
char *into_name = NULL;
int shortlog_len = -1;
+ int merge_log_config = -1;
struct option options[] = {
{
.type = OPTION_INTEGER,
@@ -53,7 +53,7 @@ int cmd_fmt_merge_msg(int argc,
int ret;
struct fmt_merge_msg_opts opts;
- repo_config(the_repository, fmt_merge_msg_config, NULL);
+ repo_config(repo, fmt_merge_msg_config, &merge_log_config);
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 a8f7f8c762..4a2fc421db 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -2,6 +2,7 @@
#include "commit.h"
#include "config.h"
#include "environment.h"
+#include "for-each-ref.h"
#include "gettext.h"
#include "object.h"
#include "parse-options.h"
@@ -9,18 +10,7 @@
#include "strbuf.h"
#include "strvec.h"
-static char const * const for_each_ref_usage[] = {
- N_("git for-each-ref [<options>] [<pattern>]"),
- 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>]]"),
- NULL
-};
-
-int cmd_for_each_ref(int argc,
- const char **argv,
- const char *prefix,
- struct repository *repo)
+int for_each_ref_core(int argc, const char **argv, const char *prefix, struct repository *repo, const char *const *usage)
{
struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
@@ -45,6 +35,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),
@@ -68,17 +59,20 @@ int cmd_for_each_ref(int argc,
/* Set default (refname) sorting */
string_list_append(&sorting_options, "refname");
- parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
+ parse_options(argc, argv, prefix, opts, usage, 0);
if (format.array_opts.max_count < 0) {
error("invalid --count argument: `%d'", format.array_opts.max_count);
- usage_with_options(for_each_ref_usage, opts);
+ usage_with_options(usage, opts);
}
if (HAS_MULTI_BITS(format.quote_style)) {
error("more than one quoting style?");
- usage_with_options(for_each_ref_usage, opts);
+ usage_with_options(usage, opts);
}
if (verify_ref_format(&format))
- usage_with_options(for_each_ref_usage, opts);
+ usage_with_options(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);
@@ -101,6 +95,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;
@@ -112,3 +109,16 @@ int cmd_for_each_ref(int argc,
strvec_clear(&vec);
return 0;
}
+
+int cmd_for_each_ref(int argc,
+ const char **argv,
+ const char *prefix,
+ struct repository *repo)
+{
+ static char const * const for_each_ref_usage[] = {
+ N_("git for-each-ref " COMMON_USAGE_FOR_EACH_REF),
+ NULL
+ };
+
+ return for_each_ref_core(argc, argv, prefix, repo, for_each_ref_usage);
+}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 0ec6ca06e3..d2eb9d4fbe 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -393,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,
@@ -502,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));
@@ -525,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;
}
@@ -632,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);
@@ -687,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 = {
@@ -701,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);
}
@@ -994,13 +994,14 @@ int cmd_fsck(int argc,
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 {
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next)
- fsck_object_dir(source->path);
+ fsck_source(source);
if (check_full) {
struct packed_git *p;
diff --git a/builtin/gc.c b/builtin/gc.c
index 183798f0dc..03ae4926b2 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -312,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)
{
@@ -346,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;
}
@@ -1308,7 +1310,7 @@ static int loose_object_auto_condition(struct gc_config *cfg UNUSED)
if (loose_object_auto_limit < 0)
return 1;
- return for_each_loose_file_in_objdir(the_repository->objects->sources->path,
+ return for_each_loose_file_in_source(the_repository->objects->sources,
loose_object_count,
NULL, NULL, &count);
}
@@ -1343,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->sources->path,
+ if (!for_each_loose_file_in_source(r->objects->sources,
bail_on_loose,
NULL, NULL, NULL))
return 0;
@@ -1383,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->sources->path,
+ for_each_loose_file_in_source(r->objects->sources,
write_loose_object_to_stdin,
- NULL,
- NULL,
- &data);
+ NULL, NULL, &data);
fclose(data.in);
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 53f1a7cd71..f91c301bba 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1598,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) {
diff --git a/builtin/last-modified.c b/builtin/last-modified.c
new file mode 100644
index 0000000000..886ba12cb5
--- /dev/null
+++ b/builtin/last-modified.c
@@ -0,0 +1,326 @@
+#include "git-compat-util.h"
+#include "bloom.h"
+#include "builtin.h"
+#include "commit-graph.h"
+#include "commit.h"
+#include "config.h"
+#include "environment.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "environment.h"
+#include "hashmap.h"
+#include "hex.h"
+#include "log-tree.h"
+#include "object-name.h"
+#include "object.h"
+#include "parse-options.h"
+#include "quote.h"
+#include "repository.h"
+#include "revision.h"
+
+struct last_modified_entry {
+ struct hashmap_entry hashent;
+ struct object_id oid;
+ struct bloom_key key;
+ const char path[FLEX_ARRAY];
+};
+
+static int last_modified_entry_hashcmp(const void *unused UNUSED,
+ const struct hashmap_entry *hent1,
+ const struct hashmap_entry *hent2,
+ const void *path)
+{
+ const struct last_modified_entry *ent1 =
+ container_of(hent1, const struct last_modified_entry, hashent);
+ const struct last_modified_entry *ent2 =
+ container_of(hent2, const struct last_modified_entry, hashent);
+ return strcmp(ent1->path, path ? path : ent2->path);
+}
+
+struct last_modified {
+ struct hashmap paths;
+ struct rev_info rev;
+ bool recursive;
+ bool show_trees;
+};
+
+static void last_modified_release(struct last_modified *lm)
+{
+ struct hashmap_iter iter;
+ struct last_modified_entry *ent;
+
+ hashmap_for_each_entry(&lm->paths, &iter, ent, hashent)
+ bloom_key_clear(&ent->key);
+
+ hashmap_clear_and_free(&lm->paths, struct last_modified_entry, hashent);
+ release_revisions(&lm->rev);
+}
+
+struct last_modified_callback_data {
+ struct last_modified *lm;
+ struct commit *commit;
+};
+
+static void add_path_from_diff(struct diff_queue_struct *q,
+ struct diff_options *opt UNUSED, void *data)
+{
+ struct last_modified *lm = data;
+
+ for (int i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ struct last_modified_entry *ent;
+ const char *path = p->two->path;
+
+ FLEX_ALLOC_STR(ent, path, path);
+ oidcpy(&ent->oid, &p->two->oid);
+ if (lm->rev.bloom_filter_settings)
+ bloom_key_fill(&ent->key, path, strlen(path),
+ lm->rev.bloom_filter_settings);
+ hashmap_entry_init(&ent->hashent, strhash(ent->path));
+ hashmap_add(&lm->paths, &ent->hashent);
+ }
+}
+
+static int populate_paths_from_revs(struct last_modified *lm)
+{
+ int num_interesting = 0;
+ struct diff_options diffopt;
+
+ /*
+ * Create a copy of `struct diff_options`. In this copy a callback is
+ * set that when called adds entries to `paths` in `struct last_modified`.
+ * This copy is used to diff the tree of the target revision against an
+ * empty tree. This results in all paths in the target revision being
+ * listed. After `paths` is populated, we don't need this copy no more.
+ */
+ memcpy(&diffopt, &lm->rev.diffopt, sizeof(diffopt));
+ copy_pathspec(&diffopt.pathspec, &lm->rev.diffopt.pathspec);
+ diffopt.output_format = DIFF_FORMAT_CALLBACK;
+ diffopt.format_callback = add_path_from_diff;
+ diffopt.format_callback_data = lm;
+
+ for (size_t i = 0; i < lm->rev.pending.nr; i++) {
+ struct object_array_entry *obj = lm->rev.pending.objects + i;
+
+ if (obj->item->flags & UNINTERESTING)
+ continue;
+
+ if (num_interesting++)
+ return error(_("last-modified can only operate on one tree at a time"));
+
+ diff_tree_oid(lm->rev.repo->hash_algo->empty_tree,
+ &obj->item->oid, "", &diffopt);
+ diff_flush(&diffopt);
+ }
+ clear_pathspec(&diffopt.pathspec);
+
+ return 0;
+}
+
+static void last_modified_emit(struct last_modified *lm,
+ const char *path, const struct commit *commit)
+
+{
+ if (commit->object.flags & BOUNDARY)
+ putchar('^');
+ printf("%s\t", oid_to_hex(&commit->object.oid));
+
+ if (lm->rev.diffopt.line_termination)
+ write_name_quoted(path, stdout, '\n');
+ else
+ printf("%s%c", path, '\0');
+}
+
+static void mark_path(const char *path, const struct object_id *oid,
+ struct last_modified_callback_data *data)
+{
+ struct last_modified_entry *ent;
+
+ /* Is it even a path that we are interested in? */
+ ent = hashmap_get_entry_from_hash(&data->lm->paths, strhash(path), path,
+ struct last_modified_entry, hashent);
+ if (!ent)
+ return;
+
+ /*
+ * Is it arriving at a version of interest, or is it from a side branch
+ * which did not contribute to the final state?
+ */
+ if (!oideq(oid, &ent->oid))
+ return;
+
+ last_modified_emit(data->lm, path, data->commit);
+
+ hashmap_remove(&data->lm->paths, &ent->hashent, path);
+ bloom_key_clear(&ent->key);
+ free(ent);
+}
+
+static void last_modified_diff(struct diff_queue_struct *q,
+ struct diff_options *opt UNUSED, void *cbdata)
+{
+ struct last_modified_callback_data *data = cbdata;
+
+ for (int i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ switch (p->status) {
+ case DIFF_STATUS_DELETED:
+ /*
+ * There's no point in feeding a deletion, as it could
+ * not have resulted in our current state, which
+ * actually has the file.
+ */
+ break;
+
+ default:
+ /*
+ * Otherwise, we care only that we somehow arrived at
+ * a final oid state. Note that this covers some
+ * potentially controversial areas, including:
+ *
+ * 1. A rename or copy will be found, as it is the
+ * first time the content has arrived at the given
+ * path.
+ *
+ * 2. Even a non-content modification like a mode or
+ * type change will trigger it.
+ *
+ * We take the inclusive approach for now, and find
+ * anything which impacts the path. Options to tweak
+ * the behavior (e.g., to "--follow" the content across
+ * renames) can come later.
+ */
+ mark_path(p->two->path, &p->two->oid, data);
+ break;
+ }
+ }
+}
+
+static bool maybe_changed_path(struct last_modified *lm, struct commit *origin)
+{
+ struct bloom_filter *filter;
+ struct last_modified_entry *ent;
+ struct hashmap_iter iter;
+
+ if (!lm->rev.bloom_filter_settings)
+ return true;
+
+ if (commit_graph_generation(origin) == GENERATION_NUMBER_INFINITY)
+ return true;
+
+ filter = get_bloom_filter(lm->rev.repo, origin);
+ if (!filter)
+ return true;
+
+ hashmap_for_each_entry(&lm->paths, &iter, ent, hashent) {
+ if (bloom_filter_contains(filter, &ent->key,
+ lm->rev.bloom_filter_settings))
+ return true;
+ }
+ return false;
+}
+
+static int last_modified_run(struct last_modified *lm)
+{
+ struct last_modified_callback_data data = { .lm = lm };
+
+ lm->rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+ lm->rev.diffopt.format_callback = last_modified_diff;
+ lm->rev.diffopt.format_callback_data = &data;
+
+ prepare_revision_walk(&lm->rev);
+
+ while (hashmap_get_size(&lm->paths)) {
+ data.commit = get_revision(&lm->rev);
+ if (!data.commit)
+ BUG("paths remaining beyond boundary in last-modified");
+
+ if (data.commit->object.flags & BOUNDARY) {
+ diff_tree_oid(lm->rev.repo->hash_algo->empty_tree,
+ &data.commit->object.oid, "",
+ &lm->rev.diffopt);
+ diff_flush(&lm->rev.diffopt);
+
+ break;
+ }
+
+ if (!maybe_changed_path(lm, data.commit))
+ continue;
+
+ log_tree_commit(&lm->rev, data.commit);
+ }
+
+ return 0;
+}
+
+static int last_modified_init(struct last_modified *lm, struct repository *r,
+ const char *prefix, int argc, const char **argv)
+{
+ hashmap_init(&lm->paths, last_modified_entry_hashcmp, NULL, 0);
+
+ repo_init_revisions(r, &lm->rev, prefix);
+ lm->rev.def = "HEAD";
+ lm->rev.combine_merges = 1;
+ lm->rev.show_root_diff = 1;
+ lm->rev.boundary = 1;
+ lm->rev.no_commit_id = 1;
+ lm->rev.diff = 1;
+ lm->rev.diffopt.flags.recursive = lm->recursive;
+ lm->rev.diffopt.flags.tree_in_recursive = lm->show_trees;
+
+ argc = setup_revisions(argc, argv, &lm->rev, NULL);
+ if (argc > 1) {
+ error(_("unknown last-modified argument: %s"), argv[1]);
+ return argc;
+ }
+
+ lm->rev.bloom_filter_settings = get_bloom_filter_settings(lm->rev.repo);
+
+ if (populate_paths_from_revs(lm) < 0)
+ return error(_("unable to setup last-modified"));
+
+ return 0;
+}
+
+int cmd_last_modified(int argc, const char **argv, const char *prefix,
+ struct repository *repo)
+{
+ int ret;
+ struct last_modified lm = { 0 };
+
+ const char * const last_modified_usage[] = {
+ N_("git last-modified [--recursive] [--show-trees] "
+ "[<revision-range>] [[--] <path>...]"),
+ NULL
+ };
+
+ struct option last_modified_options[] = {
+ OPT_BOOL('r', "recursive", &lm.recursive,
+ N_("recurse into subtrees")),
+ OPT_BOOL('t', "show-trees", &lm.show_trees,
+ N_("show tree entries when recursing into subtrees")),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, last_modified_options,
+ last_modified_usage,
+ PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+ repo_config(repo, git_default_config, NULL);
+
+ ret = last_modified_init(&lm, repo, prefix, argc, argv);
+ if (ret > 0)
+ usage_with_options(last_modified_usage,
+ last_modified_options);
+ if (ret)
+ goto out;
+
+ ret = last_modified_run(&lm);
+ if (ret)
+ goto out;
+
+out:
+ last_modified_release(&lm);
+
+ return ret;
+}
diff --git a/builtin/log.c b/builtin/log.c
index a9969ad00a..c2f8bbf863 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -391,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;
@@ -521,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
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index c06a6f33e4..b148607f7a 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -414,14 +414,21 @@ static void show_files(struct repository *repo, struct dir_struct *dir)
if (!(show_cached || show_stage || show_deleted || show_modified))
return;
- if (!show_sparse_dirs)
- ensure_full_index(repo->index);
-
for (i = 0; i < repo->index->cache_nr; i++) {
const struct cache_entry *ce = repo->index->cache[i];
struct stat st;
int stat_err;
+ if (S_ISSPARSEDIR(ce->ce_mode) && !show_sparse_dirs) {
+ /*
+ * This is the first time we've hit a sparse dir,
+ * so expansion will leave the first 'i' entries
+ * alone.
+ */
+ ensure_full_index(repo->index);
+ ce = repo->index->cache[i];
+ }
+
construct_fullname(&fullname, repo, ce);
if ((dir->flags & DIR_SHOW_IGNORED) &&
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 3da4ca2c8c..46775d0c79 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -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-recursive.c b/builtin/merge-recursive.c
index 03b5100cfa..17aa4db37a 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -38,7 +38,8 @@ int cmd_merge_recursive(int argc,
if (argv[0] && ends_with(argv[0], "-subtree"))
o.subtree_shift = "";
- if (argc == 2 && !strcmp(argv[1], "-h")) {
+ if (argc == 2 && (!strcmp(argv[1], "-h") ||
+ !strcmp(argv[1], "--help-all"))) {
struct strbuf msg = STRBUF_INIT;
strbuf_addf(&msg, builtin_merge_recursive_usage, argv[0]);
show_usage_if_asked(argc, argv, msg.buf);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 203f0e6456..1c063d9a41 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -619,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);
diff --git a/builtin/merge.c b/builtin/merge.c
index 794cb7bb26..c421a11b0b 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -264,7 +264,7 @@ static struct option builtin_merge_options[] = {
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, N_("compact-summary"),
+ 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),
@@ -875,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);
@@ -1374,6 +1374,7 @@ int cmd_merge(int argc,
struct commit_list *remoteheads = NULL, *p;
void *branch_to_free;
int orig_argc = argc;
+ int merge_log_config = -1;
show_usage_with_options_if_asked(argc, argv,
builtin_merge_usage, builtin_merge_options);
@@ -1395,7 +1396,7 @@ int cmd_merge(int argc,
skip_prefix(branch, "refs/heads/", &branch);
init_diff_ui_defaults();
- repo_config(the_repository, git_merge_config, NULL);
+ repo_config(the_repository, git_merge_config, &merge_log_config);
if (!branch || is_null_oid(&head_oid))
head_commit = NULL;
@@ -1865,7 +1866,7 @@ int cmd_merge(int argc,
if (squash) {
finish(head_commit, remoteheads, NULL, NULL);
- git_test_write_commit_graph_or_die();
+ git_test_write_commit_graph_or_die(the_repository->objects->sources);
} else
write_merge_state(remoteheads);
diff --git a/builtin/mktag.c b/builtin/mktag.c
index e078c97d03..7cf6e1230a 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -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 81df7f6099..12772303f5 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -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);
}
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index d3b9e98be3..5f364aa816 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -65,12 +65,20 @@ static int parse_object_dir(const struct option *opt, const char *arg,
char **value = opt->value;
free(*value);
if (unset)
- *value = xstrdup(repo_get_object_directory(the_repository));
+ *value = xstrdup(the_repository->objects->sources->path);
else
*value = real_pathdup(arg, 1);
return 0;
}
+static struct odb_source *handle_object_dir_option(struct repository *repo)
+{
+ struct odb_source *source = odb_find_source(repo->objects, opts.object_dir);
+ if (!source)
+ source = odb_add_to_alternates_memory(repo->objects, opts.object_dir);
+ return source;
+}
+
static struct option common_opts[] = {
OPT_CALLBACK(0, "object-dir", &opts.object_dir,
N_("directory"),
@@ -140,6 +148,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
N_("refs snapshot for selecting bitmap commits")),
OPT_END(),
};
+ struct odb_source *source;
int ret;
opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE;
@@ -158,6 +167,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
if (argc)
usage_with_options(builtin_multi_pack_index_write_usage,
options);
+ source = handle_object_dir_option(repo);
FREE_AND_NULL(options);
@@ -166,7 +176,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
read_packs_from_stdin(&packs);
- ret = write_midx_file_only(repo, opts.object_dir, &packs,
+ ret = write_midx_file_only(source, &packs,
opts.preferred_pack,
opts.refs_snapshot, opts.flags);
@@ -177,7 +187,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
}
- ret = write_midx_file(repo, opts.object_dir, opts.preferred_pack,
+ ret = write_midx_file(source, opts.preferred_pack,
opts.refs_snapshot, opts.flags);
free(opts.refs_snapshot);
@@ -194,6 +204,8 @@ static int cmd_multi_pack_index_verify(int argc, const char **argv,
N_("force progress reporting"), MIDX_PROGRESS),
OPT_END(),
};
+ struct odb_source *source;
+
options = add_common_options(builtin_multi_pack_index_verify_options);
trace2_cmd_mode(argv[0]);
@@ -206,10 +218,11 @@ static int cmd_multi_pack_index_verify(int argc, const char **argv,
if (argc)
usage_with_options(builtin_multi_pack_index_verify_usage,
options);
+ source = handle_object_dir_option(the_repository);
FREE_AND_NULL(options);
- return verify_midx_file(the_repository, opts.object_dir, opts.flags);
+ return verify_midx_file(source, opts.flags);
}
static int cmd_multi_pack_index_expire(int argc, const char **argv,
@@ -222,6 +235,8 @@ static int cmd_multi_pack_index_expire(int argc, const char **argv,
N_("force progress reporting"), MIDX_PROGRESS),
OPT_END(),
};
+ struct odb_source *source;
+
options = add_common_options(builtin_multi_pack_index_expire_options);
trace2_cmd_mode(argv[0]);
@@ -234,10 +249,11 @@ static int cmd_multi_pack_index_expire(int argc, const char **argv,
if (argc)
usage_with_options(builtin_multi_pack_index_expire_usage,
options);
+ source = handle_object_dir_option(the_repository);
FREE_AND_NULL(options);
- return expire_midx_packs(the_repository, opts.object_dir, opts.flags);
+ return expire_midx_packs(source, opts.flags);
}
static int cmd_multi_pack_index_repack(int argc, const char **argv,
@@ -252,6 +268,7 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv,
N_("force progress reporting"), MIDX_PROGRESS),
OPT_END(),
};
+ struct odb_source *source;
options = add_common_options(builtin_multi_pack_index_repack_options);
@@ -266,11 +283,11 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv,
if (argc)
usage_with_options(builtin_multi_pack_index_repack_usage,
options);
+ source = handle_object_dir_option(the_repository);
FREE_AND_NULL(options);
- return midx_repack(the_repository, opts.object_dir,
- (size_t)opts.batch_size, opts.flags);
+ return midx_repack(source, (size_t)opts.batch_size, opts.flags);
}
int cmd_multi_pack_index(int argc,
diff --git a/builtin/notes.c b/builtin/notes.c
index d2252cf534..9af602bdd7 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -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)
@@ -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) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 949baf1520..1494afcf3d 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1455,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);
@@ -1706,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
@@ -1727,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(m, oid, &e)) {
want = want_object_in_pack_one(e.p, oid, exclude, found_pack, found_offset, found_mtime);
if (want != -1)
return want;
@@ -3962,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.
@@ -3976,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),
@@ -4364,7 +4384,7 @@ static int add_loose_object(const struct object_id *oid, const char *path,
*/
static void add_unreachable_loose_objects(struct rev_info *revs)
{
- for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+ for_each_loose_file_in_source(the_repository->objects->sources,
add_loose_object, NULL, NULL, revs);
}
@@ -4433,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++;
}
diff --git a/builtin/prune.c b/builtin/prune.c
index d1c0ee1419..55635a891f 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -198,7 +198,7 @@ int cmd_prune(int argc,
revs.exclude_promisor_objects = 1;
}
- for_each_loose_file_in_objdir(repo_get_object_directory(repo),
+ 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);
diff --git a/builtin/pull.c b/builtin/pull.c
index e6d3535c3b..5ebd529620 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -91,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;
@@ -368,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) ?
@@ -1007,6 +1019,8 @@ int cmd_pull(int argc,
}
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;
@@ -1053,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/rebase.c b/builtin/rebase.c
index 962917ec48..67c0352bf8 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);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 82d516a42c..1113137a6f 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -760,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));
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 4312f3d34c..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
};
@@ -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 c7ad0a2963..91548783b7 100644
--- a/builtin/refs.c
+++ b/builtin/refs.c
@@ -6,6 +6,8 @@
#include "refs.h"
#include "strbuf.h"
#include "worktree.h"
+#include "for-each-ref.h"
+#include "refs/refs-internal.h"
#define REFS_MIGRATE_USAGE \
N_("git refs migrate --ref-format=<format> [--no-reflog] [--dry-run]")
@@ -13,6 +15,9 @@
#define REFS_VERIFY_USAGE \
N_("git refs verify [--strict] [--verbose]")
+#define REFS_EXISTS_USAGE \
+ N_("git refs exists <ref>")
+
static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
@@ -101,6 +106,59 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
return ret;
}
+static int cmd_refs_list(int argc, const char **argv, const char *prefix,
+ struct repository *repo)
+{
+ static char const * const refs_list_usage[] = {
+ N_("git refs list " COMMON_USAGE_FOR_EACH_REF),
+ NULL
+ };
+
+ return for_each_ref_core(argc, argv, prefix, repo, refs_list_usage);
+}
+
+static int cmd_refs_exists(int argc, const char **argv, const char *prefix,
+ struct repository *repo UNUSED)
+{
+ struct strbuf unused_referent = STRBUF_INIT;
+ struct object_id unused_oid;
+ unsigned int unused_type;
+ int failure_errno = 0;
+ const char *ref;
+ int ret = 0;
+ const char * const exists_usage[] = {
+ REFS_EXISTS_USAGE,
+ NULL,
+ };
+ struct option options[] = {
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, prefix, options, exists_usage, 0);
+ if (argc != 1)
+ die(_("'git refs exists' requires a reference"));
+
+ ref = *argv++;
+ if (refs_read_raw_ref(get_main_ref_store(the_repository), ref,
+ &unused_oid, &unused_referent, &unused_type,
+ &failure_errno)) {
+ if (failure_errno == ENOENT || failure_errno == EISDIR) {
+ error(_("reference does not exist"));
+ ret = 2;
+ } else {
+ errno = failure_errno;
+ error_errno(_("failed to look up reference"));
+ ret = 1;
+ }
+
+ goto out;
+ }
+
+out:
+ strbuf_release(&unused_referent);
+ return ret;
+}
+
int cmd_refs(int argc,
const char **argv,
const char *prefix,
@@ -109,12 +167,16 @@ int cmd_refs(int argc,
const char * const refs_usage[] = {
REFS_MIGRATE_USAGE,
REFS_VERIFY_USAGE,
+ "git refs list " COMMON_USAGE_FOR_EACH_REF,
+ REFS_EXISTS_USAGE,
NULL,
};
parse_opt_subcommand_fn *fn = NULL;
struct option opts[] = {
OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate),
OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify),
+ OPT_SUBCOMMAND("list", &fn, cmd_refs_list),
+ OPT_SUBCOMMAND("exists", &fn, cmd_refs_exists),
OPT_END(),
};
diff --git a/builtin/remote.c b/builtin/remote.c
index 43a122740a..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"
@@ -182,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[] = {
@@ -233,7 +234,7 @@ static int add(int argc, const char **argv, const char *prefix,
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);
}
@@ -612,53 +613,169 @@ 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++)
+ 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++)
+ 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++)
+ 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)
@@ -730,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)
@@ -741,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,
@@ -756,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)) {
@@ -785,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);
repo_config_set_multivar(the_repository, 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++) {
+ 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,
@@ -813,7 +967,7 @@ static int mv(int argc, const char **argv, const char *prefix,
}
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)) {
@@ -828,83 +982,23 @@ static int mv(int argc, const char **argv, const char *prefix,
}
}
- if (!refspec_updated)
- goto out;
+ if (refspecs_need_update) {
+ result = ref_transaction_commit(rename.transaction, &err);
+ if (result < 0)
+ die(_("renaming remote refs failed: %s"), rename.err->buf);
- /*
- * 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);
+ stop_progress(&rename.progress);
- strbuf_release(&referent);
- display_progress(progress, ++refs_renamed_nr);
+ handle_push_default(rename.old_name, rename.new_name);
}
- for (i = 0; i < remote_branches.nr; i++) {
- struct string_list_item *item = remote_branches.items + i;
-
- 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;
-
- 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);
- }
- 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;
}
@@ -920,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;
@@ -942,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)) {
@@ -988,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);
}
@@ -1166,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"),
@@ -1192,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);
@@ -1277,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;
@@ -1294,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);
@@ -1312,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,
@@ -1352,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);
@@ -1458,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;
@@ -1474,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]);
@@ -1489,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
@@ -1714,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;
@@ -1742,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]);
@@ -1754,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;
@@ -1818,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
diff --git a/builtin/repack.c b/builtin/repack.c
index ec5bc83e54..c490a51e91 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -223,9 +223,10 @@ 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 odb_source *source = the_repository->objects->sources;
+ struct multi_pack_index *m = get_multi_pack_index(source);
strbuf_addf(&buf, "%s.pack", base_name);
- if (m && midx_contains_pack(m, buf.buf))
+ if (m && source->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);
@@ -1531,7 +1532,7 @@ int cmd_repack(int argc,
* midx_has_unknown_packs() will make the decision for
* us.
*/
- if (!get_local_multi_pack_index(the_repository))
+ if (!get_multi_pack_index(the_repository->objects->sources))
midx_must_contain_cruft = 1;
}
@@ -1614,9 +1615,9 @@ int cmd_repack(int argc,
string_list_sort(&names);
- if (get_local_multi_pack_index(the_repository)) {
+ if (get_multi_pack_index(the_repository->objects->sources)) {
struct multi_pack_index *m =
- get_local_multi_pack_index(the_repository);
+ get_multi_pack_index(the_repository->objects->sources);
ALLOC_ARRAY(midx_pack_names,
m->num_packs + m->num_packs_in_base);
@@ -1711,7 +1712,7 @@ int cmd_repack(int argc,
unsigned flags = 0;
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0))
flags |= MIDX_WRITE_INCREMENTAL;
- write_midx_file(the_repository, repo_get_object_directory(the_repository),
+ write_midx_file(the_repository->objects->sources,
NULL, NULL, flags);
}
diff --git a/builtin/replace.c b/builtin/replace.c
index 19897ef927..900b560a77 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -489,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);
diff --git a/builtin/repo.c b/builtin/repo.c
new file mode 100644
index 0000000000..bbb0966f2d
--- /dev/null
+++ b/builtin/repo.c
@@ -0,0 +1,171 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "environment.h"
+#include "parse-options.h"
+#include "quote.h"
+#include "refs.h"
+#include "strbuf.h"
+#include "shallow.h"
+
+static const char *const repo_usage[] = {
+ "git repo info [--format=(keyvalue|nul)] [-z] [<key>...]",
+ NULL
+};
+
+typedef int get_value_fn(struct repository *repo, struct strbuf *buf);
+
+enum output_format {
+ FORMAT_KEYVALUE,
+ FORMAT_NUL_TERMINATED,
+};
+
+struct field {
+ const char *key;
+ get_value_fn *get_value;
+};
+
+static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
+{
+ strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
+ return 0;
+}
+
+static int get_layout_shallow(struct repository *repo, struct strbuf *buf)
+{
+ strbuf_addstr(buf,
+ is_repository_shallow(repo) ? "true" : "false");
+ return 0;
+}
+
+static int get_object_format(struct repository *repo, struct strbuf *buf)
+{
+ strbuf_addstr(buf, repo->hash_algo->name);
+ return 0;
+}
+
+static int get_references_format(struct repository *repo, struct strbuf *buf)
+{
+ strbuf_addstr(buf,
+ ref_storage_format_to_name(repo->ref_storage_format));
+ return 0;
+}
+
+/* repo_info_fields keys must be in lexicographical order */
+static const struct field repo_info_fields[] = {
+ { "layout.bare", get_layout_bare },
+ { "layout.shallow", get_layout_shallow },
+ { "object.format", get_object_format },
+ { "references.format", get_references_format },
+};
+
+static int repo_info_fields_cmp(const void *va, const void *vb)
+{
+ const struct field *a = va;
+ const struct field *b = vb;
+
+ return strcmp(a->key, b->key);
+}
+
+static get_value_fn *get_value_fn_for_key(const char *key)
+{
+ const struct field search_key = { key, NULL };
+ const struct field *found = bsearch(&search_key, repo_info_fields,
+ ARRAY_SIZE(repo_info_fields),
+ sizeof(*found),
+ repo_info_fields_cmp);
+ return found ? found->get_value : NULL;
+}
+
+static int print_fields(int argc, const char **argv,
+ struct repository *repo,
+ enum output_format format)
+{
+ int ret = 0;
+ struct strbuf valbuf = STRBUF_INIT;
+ struct strbuf quotbuf = STRBUF_INIT;
+
+ for (int i = 0; i < argc; i++) {
+ get_value_fn *get_value;
+ const char *key = argv[i];
+
+ get_value = get_value_fn_for_key(key);
+
+ if (!get_value) {
+ ret = error(_("key '%s' not found"), key);
+ continue;
+ }
+
+ strbuf_reset(&valbuf);
+ strbuf_reset(&quotbuf);
+
+ get_value(repo, &valbuf);
+
+ switch (format) {
+ case FORMAT_KEYVALUE:
+ quote_c_style(valbuf.buf, &quotbuf, NULL, 0);
+ printf("%s=%s\n", key, quotbuf.buf);
+ break;
+ case FORMAT_NUL_TERMINATED:
+ printf("%s\n%s%c", key, valbuf.buf, '\0');
+ break;
+ default:
+ BUG("not a valid output format: %d", format);
+ }
+ }
+
+ strbuf_release(&valbuf);
+ strbuf_release(&quotbuf);
+ return ret;
+}
+
+static int parse_format_cb(const struct option *opt,
+ const char *arg, int unset UNUSED)
+{
+ enum output_format *format = opt->value;
+
+ if (opt->short_name == 'z')
+ *format = FORMAT_NUL_TERMINATED;
+ else if (!strcmp(arg, "nul"))
+ *format = FORMAT_NUL_TERMINATED;
+ else if (!strcmp(arg, "keyvalue"))
+ *format = FORMAT_KEYVALUE;
+ else
+ die(_("invalid format '%s'"), arg);
+
+ return 0;
+}
+
+static int repo_info(int argc, const char **argv, const char *prefix,
+ struct repository *repo)
+{
+ enum output_format format = FORMAT_KEYVALUE;
+ struct option options[] = {
+ OPT_CALLBACK_F(0, "format", &format, N_("format"),
+ N_("output format"),
+ PARSE_OPT_NONEG, parse_format_cb),
+ OPT_CALLBACK_F('z', NULL, &format, NULL,
+ N_("synonym for --format=nul"),
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+ parse_format_cb),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+ return print_fields(argc, argv, repo, format);
+}
+
+int cmd_repo(int argc, const char **argv, const char *prefix,
+ struct repository *repo)
+{
+ parse_opt_subcommand_fn *fn = NULL;
+ struct option options[] = {
+ OPT_SUBCOMMAND("info", &fn, repo_info),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, options, repo_usage, 0);
+
+ return fn(argc, argv, prefix, repo);
+}
diff --git a/builtin/reset.c b/builtin/reset.c
index 00492c19b0..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),
@@ -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 034ea0a558..99f876ba85 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -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"
@@ -652,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/revert.c b/builtin/revert.c
index b197848bb0..bedc40f368 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -112,7 +112,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/stash.c b/builtin/stash.c
index 821b58a14e..f5ddee5c7f 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -738,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,
@@ -1301,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;
@@ -1326,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)
@@ -1421,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;
@@ -1503,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 "
@@ -1578,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));
@@ -1589,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;
@@ -1659,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;
}
@@ -1833,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")),
@@ -1840,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")),
@@ -1895,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);
@@ -1921,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")),
@@ -1928,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")),
@@ -1946,8 +1967,22 @@ 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;
@@ -2173,7 +2208,8 @@ struct stash_entry_data {
size_t count;
};
-static int collect_stash_entries(struct object_id *old_oid UNUSED,
+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,
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 28f34f7bc1..07a1935cbe 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -32,6 +32,8 @@
#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)
@@ -3307,6 +3309,8 @@ 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);
repo_config_set_gently(the_repository, key, add_data->realrepo);
@@ -3349,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 (!repo_config_get(the_repository, "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);
repo_config_set_gently(the_repository, key, "true");
free(key);
}
- } else {
- key = xstrfmt("submodule.%s.active", add_data->sm_name);
- repo_config_set_gently(the_repository, key, "true");
- free(key);
}
}
@@ -3423,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")),
@@ -3525,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);
@@ -3540,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/tag.c b/builtin/tag.c
index 25f30e3f9b..f0665af3ac 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -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;
}
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 26aa885da9..28124b324d 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -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;
}
@@ -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)
@@ -583,6 +584,7 @@ static void unpack_all(void)
{
int i;
unsigned char *hdr = fill(sizeof(struct pack_header));
+ struct odb_transaction *transaction;
if (get_be32(hdr) != PACK_SIGNATURE)
die("bad pack file");
@@ -598,12 +600,12 @@ static void unpack_all(void)
progress = start_progress(the_repository,
_("Unpacking objects"), nr_objects);
CALLOC_ARRAY(obj_list, nr_objects);
- begin_odb_transaction();
+ transaction = begin_odb_transaction(the_repository->objects);
for (i = 0; i < nr_objects; i++) {
unpack_one(i);
display_progress(progress, i + 1);
}
- end_odb_transaction();
+ end_odb_transaction(transaction);
stop_progress(&progress);
if (delta_list)
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 2380f3ccd6..2ba2d29c95 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -77,7 +77,7 @@ static void report(const char *fmt, ...)
* objects invisible while a transaction is active, so flush the
* transaction here before reporting a change made by update-index.
*/
- flush_odb_transaction();
+ flush_odb_transaction(the_repository->objects->transaction);
va_start(vp, fmt);
vprintf(fmt, vp);
putchar('\n');
@@ -940,6 +940,7 @@ int cmd_update_index(int argc,
strbuf_getline_fn getline_fn;
int parseopt_state = PARSE_OPT_UNKNOWN;
struct repository *r = the_repository;
+ struct odb_transaction *transaction;
struct option options[] = {
OPT_BIT('q', NULL, &refresh_args.flags,
N_("continue refresh even when index needs update"),
@@ -1130,7 +1131,7 @@ int cmd_update_index(int argc,
* Allow the object layer to optimize adding multiple objects in
* a batch.
*/
- begin_odb_transaction();
+ transaction = begin_odb_transaction(the_repository->objects);
while (ctx.argc) {
if (parseopt_state != PARSE_OPT_DONE)
parseopt_state = parse_options_step(&ctx, options,
@@ -1213,7 +1214,7 @@ int cmd_update_index(int argc,
/*
* By now we have added all of the new objects
*/
- end_odb_transaction();
+ end_odb_transaction(transaction);
if (split_index > 0) {
if (repo_config_get_split_index(the_repository) == 0)
diff --git a/builtin/var.c b/builtin/var.c
index a2d790d453..cc3a43cde2 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -182,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);