summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c9
-rw-r--r--builtin/am.c19
-rw-r--r--builtin/apply.c2
-rw-r--r--builtin/archive.c2
-rw-r--r--builtin/blame.c15
-rw-r--r--builtin/branch.c22
-rw-r--r--builtin/cat-file.c112
-rw-r--r--builtin/check-attr.c6
-rw-r--r--builtin/checkout-index.c3
-rw-r--r--builtin/checkout.c182
-rw-r--r--builtin/clean.c2
-rw-r--r--builtin/clone.c27
-rw-r--r--builtin/commit-graph.c101
-rw-r--r--builtin/commit-tree.c5
-rw-r--r--builtin/commit.c47
-rw-r--r--builtin/config.c77
-rw-r--r--builtin/count-objects.c2
-rw-r--r--builtin/describe.c14
-rw-r--r--builtin/diff-tree.c17
-rw-r--r--builtin/diff.c7
-rw-r--r--builtin/difftool.c11
-rw-r--r--builtin/fast-export.c57
-rw-r--r--builtin/fetch.c201
-rw-r--r--builtin/fmt-merge-msg.c30
-rw-r--r--builtin/fsck.c48
-rw-r--r--builtin/gc.c11
-rw-r--r--builtin/grep.c28
-rw-r--r--builtin/hash-object.c1
-rw-r--r--builtin/index-pack.c7
-rw-r--r--builtin/init-db.c3
-rw-r--r--builtin/interpret-trailers.c1
-rw-r--r--builtin/log.c158
-rw-r--r--builtin/ls-files.c17
-rw-r--r--builtin/ls-tree.c1
-rw-r--r--builtin/merge-base.c8
-rw-r--r--builtin/merge-recursive.c4
-rw-r--r--builtin/merge-tree.c4
-rw-r--r--builtin/merge.c83
-rw-r--r--builtin/mktag.c1
-rw-r--r--builtin/mktree.c1
-rw-r--r--builtin/multi-pack-index.c47
-rw-r--r--builtin/name-rev.c13
-rw-r--r--builtin/notes.c4
-rw-r--r--builtin/pack-objects.c361
-rw-r--r--builtin/pack-redundant.c4
-rw-r--r--builtin/prune-packed.c1
-rw-r--r--builtin/prune.c7
-rw-r--r--builtin/pull.c28
-rw-r--r--builtin/push.c8
-rw-r--r--builtin/range-diff.c101
-rw-r--r--builtin/read-tree.c2
-rw-r--r--builtin/receive-pack.c27
-rw-r--r--builtin/reflog.c16
-rw-r--r--builtin/remote.c9
-rw-r--r--builtin/repack.c201
-rw-r--r--builtin/replace.c96
-rw-r--r--builtin/reset.c8
-rw-r--r--builtin/rev-list.c18
-rw-r--r--builtin/rev-parse.c10
-rw-r--r--builtin/revert.c9
-rw-r--r--builtin/rm.c4
-rw-r--r--builtin/send-pack.c4
-rw-r--r--builtin/shortlog.c5
-rw-r--r--builtin/show-branch.c7
-rw-r--r--builtin/show-ref.c1
-rw-r--r--builtin/submodule--helper.c201
-rw-r--r--builtin/tag.c3
-rw-r--r--builtin/unpack-file.c1
-rw-r--r--builtin/unpack-objects.c10
-rw-r--r--builtin/update-index.c46
-rw-r--r--builtin/upload-archive.c3
-rw-r--r--builtin/upload-pack.c2
-rw-r--r--builtin/verify-commit.c5
-rw-r--r--builtin/worktree.c20
-rw-r--r--builtin/write-tree.c5
75 files changed, 1851 insertions, 782 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 8a155dd41e..9916498a29 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -40,7 +40,7 @@ static void chmod_pathspec(struct pathspec *pathspec, char flip)
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
- if (pathspec && !ce_path_match(ce, pathspec, NULL))
+ if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
continue;
if (chmod_cache_entry(ce, flip) < 0)
@@ -135,7 +135,7 @@ static int renormalize_tracked_files(const struct pathspec *pathspec, int flags)
continue; /* do not touch unmerged paths */
if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))
continue; /* do not touch non blobs */
- if (pathspec && !ce_path_match(ce, pathspec, NULL))
+ if (pathspec && !ce_path_match(&the_index, ce, pathspec, NULL))
continue;
retval |= add_file_to_cache(ce->name, flags | HASH_RENORMALIZE);
}
@@ -155,7 +155,7 @@ static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,
i = dir->nr;
while (--i >= 0) {
struct dir_entry *entry = *src++;
- if (dir_path_match(entry, pathspec, prefix, seen))
+ if (dir_path_match(&the_index, entry, pathspec, prefix, seen))
*dst++ = entry;
}
dir->nr = dst - dir->entries;
@@ -304,7 +304,8 @@ static struct option builtin_add_options[] = {
OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
- OPT_STRING( 0 , "chmod", &chmod_arg, N_("(+/-)x"), N_("override the executable bit of the listed files")),
+ OPT_STRING(0, "chmod", &chmod_arg, "(+|-)x",
+ N_("override the executable bit of the listed files")),
OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
N_("warn when adding an embedded repository")),
OPT_END(),
diff --git a/builtin/am.c b/builtin/am.c
index 6273ea5195..5e866d17c7 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -32,6 +32,7 @@
#include "apply.h"
#include "string-list.h"
#include "packfile.h"
+#include "repository.h"
/**
* Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -1400,9 +1401,10 @@ static void write_index_patch(const struct am_state *state)
FILE *fp;
if (!get_oid_tree("HEAD", &head))
- tree = lookup_tree(&head);
+ tree = lookup_tree(the_repository, &head);
else
- tree = lookup_tree(the_hash_algo->empty_tree);
+ tree = lookup_tree(the_repository,
+ the_repository->hash_algo->empty_tree);
fp = xfopen(am_path(state, "patch"), "w");
init_revisions(&rev_info, NULL);
@@ -1462,7 +1464,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
int force_apply = 0;
int options = 0;
- if (init_apply_state(&apply_state, NULL))
+ if (init_apply_state(&apply_state, the_repository, NULL))
BUG("init_apply_state() failed");
argv_array_push(&apply_opts, "apply");
@@ -1596,6 +1598,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
o.branch1 = "HEAD";
their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
o.branch2 = their_tree_name;
+ o.detect_directory_renames = 0;
if (state->quiet)
o.verbosity = 0;
@@ -1631,7 +1634,8 @@ static void do_commit(const struct am_state *state)
if (!get_oid_commit("HEAD", &parent)) {
old_oid = &parent;
- commit_list_insert(lookup_commit(&parent), &parents);
+ commit_list_insert(lookup_commit(the_repository, &parent),
+ &parents);
} else {
old_oid = NULL;
say(state, stderr, _("applying to an empty history"));
@@ -1763,7 +1767,7 @@ static void am_run(struct am_state *state, int resume)
refresh_and_write_cache();
- if (index_has_changes(&sb)) {
+ if (index_has_changes(&the_index, NULL, &sb)) {
write_state_bool(state, "dirtyindex", 1);
die(_("Dirty index: cannot apply patches (dirty: %s)"), sb.buf);
}
@@ -1820,7 +1824,8 @@ static void am_run(struct am_state *state, int resume)
* Applying the patch to an earlier tree and merging
* the result may have produced the same tree as ours.
*/
- if (!apply_status && !index_has_changes(NULL)) {
+ if (!apply_status &&
+ !index_has_changes(&the_index, NULL, NULL)) {
say(state, stdout, _("No changes -- Patch already applied."));
goto next;
}
@@ -1874,7 +1879,7 @@ static void am_resolve(struct am_state *state)
say(state, stdout, _("Applying: %.*s"), linelen(state->msg), state->msg);
- if (!index_has_changes(NULL)) {
+ if (!index_has_changes(&the_index, NULL, NULL)) {
printf_ln(_("No changes - did you forget to use 'git add'?\n"
"If there is nothing left to stage, chances are that something else\n"
"already introduced the same changes; you might want to skip this patch."));
diff --git a/builtin/apply.c b/builtin/apply.c
index 48d3989331..3f099b9605 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -16,7 +16,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
int ret;
struct apply_state state;
- if (init_apply_state(&state, prefix))
+ if (init_apply_state(&state, the_repository, prefix))
exit(128);
argc = apply_parse_options(argc, argv,
diff --git a/builtin/archive.c b/builtin/archive.c
index 73971d0dd2..e74f675390 100644
--- a/builtin/archive.c
+++ b/builtin/archive.c
@@ -105,5 +105,5 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
- return write_archive(argc, argv, prefix, output, 0);
+ return write_archive(argc, argv, prefix, the_repository, output, 0);
}
diff --git a/builtin/blame.c b/builtin/blame.c
index 5a0388aaef..c2da673ac8 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -9,6 +9,7 @@
#include "config.h"
#include "color.h"
#include "builtin.h"
+#include "repository.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
@@ -23,6 +24,7 @@
#include "line-log.h"
#include "dir.h"
#include "progress.h"
+#include "object-store.h"
#include "blame.h"
#include "string-list.h"
@@ -408,7 +410,7 @@ static void parse_color_fields(const char *s)
}
if (next == EXPECT_COLOR)
- die (_("must end with a color"));
+ die(_("must end with a color"));
colorfield[colorfield_nr].hop = TIME_MAX;
string_list_clear(&l, 0);
@@ -576,7 +578,7 @@ static int read_ancestry(const char *graft_file)
/* The format is just "Commit Parent1 Parent2 ...\n" */
struct commit_graft *graft = read_graft_line(&buf);
if (graft)
- register_commit_graft(graft, 0);
+ register_commit_graft(the_repository, graft, 0);
}
fclose(fp);
strbuf_release(&buf);
@@ -986,6 +988,7 @@ parse_done:
sb.revs = &revs;
sb.contents_from = contents_from;
sb.reverse = reverse;
+ sb.repo = the_repository;
setup_scoreboard(&sb, path, &o);
lno = sb.num_lines;
@@ -1000,13 +1003,13 @@ parse_done:
nth_line_cb, &sb, lno, anchor,
&bottom, &top, sb.path))
usage(blame_usage);
- if (lno < top || ((lno || bottom) && lno < bottom))
+ if ((!lno && (top || bottom)) || lno < bottom)
die(Q_("file %s has only %lu line",
"file %s has only %lu lines",
lno), path, lno);
if (bottom < 1)
bottom = 1;
- if (top < 1)
+ if (top < 1 || lno < top)
top = lno;
bottom--;
range_set_append_unsafe(&ranges, bottom, top);
@@ -1069,7 +1072,9 @@ parse_done:
find_alignment(&sb, &output_option);
if (!*repeated_meta_color &&
(output_option & OUTPUT_COLOR_LINE))
- strcpy(repeated_meta_color, GIT_COLOR_CYAN);
+ xsnprintf(repeated_meta_color,
+ sizeof(repeated_meta_color),
+ "%s", GIT_COLOR_CYAN);
}
if (output_option & OUTPUT_ANNOTATE_COMPAT)
output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
diff --git a/builtin/branch.c b/builtin/branch.c
index 1876ca9e79..c396c41533 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -23,6 +23,7 @@
#include "ref-filter.h"
#include "worktree.h"
#include "help.h"
+#include "commit-reach.h"
static const char * const builtin_branch_usage[] = {
N_("git branch [<options>] [-r | -a] [--merged | --no-merged]"),
@@ -73,6 +74,14 @@ define_list_config_array(color_branch_slots);
static int git_branch_config(const char *var, const char *value, void *cb)
{
const char *slot_name;
+ struct ref_sorting **sorting_tail = (struct ref_sorting **)cb;
+
+ if (!strcmp(var, "branch.sort")) {
+ if (!value)
+ return config_error_nonbool(var);
+ parse_ref_sorting(sorting_tail, value);
+ return 0;
+ }
if (starts_with(var, "column."))
return git_column_config(var, value, "branch", &colopts);
@@ -121,7 +130,8 @@ static int branch_merged(int kind, const char *name,
(reference_name = reference_name_to_free =
resolve_refdup(upstream, RESOLVE_REF_READING,
&oid, NULL)) != NULL)
- reference_rev = lookup_commit_reference(&oid);
+ reference_rev = lookup_commit_reference(the_repository,
+ &oid);
}
if (!reference_rev)
reference_rev = head_rev;
@@ -154,7 +164,7 @@ static int check_branch_commit(const char *branchname, const char *refname,
const struct object_id *oid, struct commit *head_rev,
int kinds, int force)
{
- struct commit *rev = lookup_commit_reference(oid);
+ struct commit *rev = lookup_commit_reference(the_repository, oid);
if (!rev) {
error(_("Couldn't look up commit object for '%s'"), refname);
return -1;
@@ -208,7 +218,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
}
if (!force) {
- head_rev = lookup_commit_reference(&head_oid);
+ head_rev = lookup_commit_reference(the_repository, &head_oid);
if (!head_rev)
die(_("Couldn't look up commit object for HEAD"));
}
@@ -609,8 +619,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
OPT_BIT('c', "copy", &copy, N_("copy a branch and its reflog"), 1),
OPT_BIT('C', NULL, &copy, N_("copy a branch, even if target exists"), 2),
- OPT_BOOL(0, "list", &list, N_("list branch names")),
- OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
+ OPT_BOOL('l', "list", &list, N_("list branch names")),
+ OPT_BOOL(0, "create-reflog", &reflog, N_("create the branch's reflog")),
OPT_BOOL(0, "edit-description", &edit_description,
N_("edit the description for the branch")),
OPT__FORCE(&force, N_("force creation, move/rename, deletion"), PARSE_OPT_NOCOMPLETE),
@@ -637,7 +647,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_branch_usage, options);
- git_config(git_branch_config, NULL);
+ git_config(git_branch_config, sorting_tail);
track = git_branch_track;
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 665b581949..64ec1745ab 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -13,6 +13,7 @@
#include "tree-walk.h"
#include "sha1-array.h"
#include "packfile.h"
+#include "object-store.h"
struct batch_options {
int enabled;
@@ -20,6 +21,7 @@ struct batch_options {
int print_contents;
int buffer_output;
int all_objects;
+ int unordered;
int cmdmode; /* may be 'w' or 'c' for --filters or --textconv */
const char *format;
};
@@ -38,7 +40,7 @@ static int filter_object(const char *path, unsigned mode,
oid_to_hex(oid), path);
if ((type == OBJ_BLOB) && S_ISREG(mode)) {
struct strbuf strbuf = STRBUF_INIT;
- if (convert_to_working_tree(path, *buf, *size, &strbuf)) {
+ if (convert_to_working_tree(&the_index, path, *buf, *size, &strbuf)) {
free(*buf);
*size = strbuf.len;
*buf = strbuf_detach(&strbuf, NULL);
@@ -336,11 +338,11 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
}
}
-static void batch_object_write(const char *obj_name, struct batch_options *opt,
+static void batch_object_write(const char *obj_name,
+ struct strbuf *scratch,
+ struct batch_options *opt,
struct expand_data *data)
{
- struct strbuf buf = STRBUF_INIT;
-
if (!data->skip_object_info &&
oid_object_info_extended(the_repository, &data->oid, &data->info,
OBJECT_INFO_LOOKUP_REPLACE) < 0) {
@@ -350,10 +352,10 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt,
return;
}
- strbuf_expand(&buf, opt->format, expand_format, data);
- strbuf_addch(&buf, '\n');
- batch_write(opt, buf.buf, buf.len);
- strbuf_release(&buf);
+ strbuf_reset(scratch);
+ strbuf_expand(scratch, opt->format, expand_format, data);
+ strbuf_addch(scratch, '\n');
+ batch_write(opt, scratch->buf, scratch->len);
if (opt->print_contents) {
print_object_or_die(opt, data);
@@ -361,7 +363,9 @@ static void batch_object_write(const char *obj_name, struct batch_options *opt,
}
}
-static void batch_one_object(const char *obj_name, struct batch_options *opt,
+static void batch_one_object(const char *obj_name,
+ struct strbuf *scratch,
+ struct batch_options *opt,
struct expand_data *data)
{
struct object_context ctx;
@@ -403,42 +407,70 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
return;
}
- batch_object_write(obj_name, opt, data);
+ batch_object_write(obj_name, scratch, opt, data);
}
struct object_cb_data {
struct batch_options *opt;
struct expand_data *expand;
+ struct oidset *seen;
+ struct strbuf *scratch;
};
static int batch_object_cb(const struct object_id *oid, void *vdata)
{
struct object_cb_data *data = vdata;
oidcpy(&data->expand->oid, oid);
- batch_object_write(NULL, data->opt, data->expand);
+ batch_object_write(NULL, data->scratch, data->opt, data->expand);
return 0;
}
-static int batch_loose_object(const struct object_id *oid,
- const char *path,
- void *data)
+static int collect_loose_object(const struct object_id *oid,
+ const char *path,
+ void *data)
{
oid_array_append(data, oid);
return 0;
}
-static int batch_packed_object(const struct object_id *oid,
- struct packed_git *pack,
- uint32_t pos,
- void *data)
+static int collect_packed_object(const struct object_id *oid,
+ struct packed_git *pack,
+ uint32_t pos,
+ void *data)
{
oid_array_append(data, oid);
return 0;
}
+static int batch_unordered_object(const struct object_id *oid, void *vdata)
+{
+ struct object_cb_data *data = vdata;
+
+ if (oidset_insert(data->seen, oid))
+ return 0;
+
+ return batch_object_cb(oid, data);
+}
+
+static int batch_unordered_loose(const struct object_id *oid,
+ const char *path,
+ void *data)
+{
+ return batch_unordered_object(oid, data);
+}
+
+static int batch_unordered_packed(const struct object_id *oid,
+ struct packed_git *pack,
+ uint32_t pos,
+ void *data)
+{
+ return batch_unordered_object(oid, data);
+}
+
static int batch_objects(struct batch_options *opt)
{
- struct strbuf buf = STRBUF_INIT;
+ struct strbuf input = STRBUF_INIT;
+ struct strbuf output = STRBUF_INIT;
struct expand_data data;
int save_warning;
int retval = 0;
@@ -453,8 +485,9 @@ static int batch_objects(struct batch_options *opt)
*/
memset(&data, 0, sizeof(data));
data.mark_query = 1;
- strbuf_expand(&buf, opt->format, expand_format, &data);
+ strbuf_expand(&output, opt->format, expand_format, &data);
data.mark_query = 0;
+ strbuf_release(&output);
if (opt->cmdmode)
data.split_on_whitespace = 1;
@@ -472,19 +505,37 @@ static int batch_objects(struct batch_options *opt)
data.info.typep = &data.type;
if (opt->all_objects) {
- struct oid_array sa = OID_ARRAY_INIT;
struct object_cb_data cb;
- for_each_loose_object(batch_loose_object, &sa, 0);
- for_each_packed_object(batch_packed_object, &sa, 0);
if (repository_format_partial_clone)
warning("This repository has extensions.partialClone set. Some objects may not be loaded.");
cb.opt = opt;
cb.expand = &data;
- oid_array_for_each_unique(&sa, batch_object_cb, &cb);
+ cb.scratch = &output;
+
+ if (opt->unordered) {
+ struct oidset seen = OIDSET_INIT;
+
+ cb.seen = &seen;
+
+ for_each_loose_object(batch_unordered_loose, &cb, 0);
+ for_each_packed_object(batch_unordered_packed, &cb,
+ FOR_EACH_OBJECT_PACK_ORDER);
+
+ oidset_clear(&seen);
+ } else {
+ struct oid_array sa = OID_ARRAY_INIT;
+
+ for_each_loose_object(collect_loose_object, &sa, 0);
+ for_each_packed_object(collect_packed_object, &sa, 0);
+
+ oid_array_for_each_unique(&sa, batch_object_cb, &cb);
+
+ oid_array_clear(&sa);
+ }
- oid_array_clear(&sa);
+ strbuf_release(&output);
return 0;
}
@@ -498,14 +549,14 @@ static int batch_objects(struct batch_options *opt)
save_warning = warn_on_object_refname_ambiguity;
warn_on_object_refname_ambiguity = 0;
- while (strbuf_getline(&buf, stdin) != EOF) {
+ while (strbuf_getline(&input, stdin) != EOF) {
if (data.split_on_whitespace) {
/*
* Split at first whitespace, tying off the beginning
* of the string and saving the remainder (or NULL) in
* data.rest.
*/
- char *p = strpbrk(buf.buf, " \t");
+ char *p = strpbrk(input.buf, " \t");
if (p) {
while (*p && strchr(" \t", *p))
*p++ = '\0';
@@ -513,10 +564,11 @@ static int batch_objects(struct batch_options *opt)
data.rest = p;
}
- batch_one_object(buf.buf, opt, &data);
+ batch_one_object(input.buf, &output, opt, &data);
}
- strbuf_release(&buf);
+ strbuf_release(&input);
+ strbuf_release(&output);
warn_on_object_refname_ambiguity = save_warning;
return retval;
}
@@ -585,6 +637,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
N_("follow in-tree symlinks (used with --batch or --batch-check)")),
OPT_BOOL(0, "batch-all-objects", &batch.all_objects,
N_("show all objects with --batch or --batch-check")),
+ OPT_BOOL(0, "unordered", &batch.unordered,
+ N_("do not order --batch-all-objects output")),
OPT_END()
};
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 91444dc044..c05573ff9c 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -63,9 +63,9 @@ static void check_attr(const char *prefix,
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
if (collect_all) {
- git_all_attrs(full_path, check);
+ git_all_attrs(&the_index, full_path, check);
} else {
- if (git_check_attr(full_path, check))
+ if (git_check_attr(&the_index, full_path, check))
die("git_check_attr died");
}
output_attr(check, file);
@@ -120,7 +120,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
}
if (cached_attrs)
- git_attr_set_direction(GIT_ATTR_INDEX, NULL);
+ git_attr_set_direction(GIT_ATTR_INDEX);
doubledash = -1;
for (i = 0; doubledash < 0 && i < argc; i++) {
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index a730f6a1aa..88b86c8d9f 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -172,7 +172,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
N_("write the content to temporary files")),
OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
N_("when creating files, prepend <string>")),
- { OPTION_CALLBACK, 0, "stage", NULL, "1-3|all",
+ { OPTION_CALLBACK, 0, "stage", NULL, "(1|2|3|all)",
N_("copy out the files from named stage"),
PARSE_OPT_NONEG, option_parse_stage },
OPT_END()
@@ -190,6 +190,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, builtin_checkout_index_options,
builtin_checkout_index_usage, 0);
+ state.istate = &the_index;
state.force = force;
state.quiet = quiet;
state.not_new = not_new;
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 4c41d8b4c8..67a83fb95b 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -4,6 +4,7 @@
#include "lockfile.h"
#include "parse-options.h"
#include "refs.h"
+#include "object-store.h"
#include "commit.h"
#include "tree.h"
#include "tree-walk.h"
@@ -22,6 +23,9 @@
#include "resolve-undo.h"
#include "submodule-config.h"
#include "submodule.h"
+#include "advice.h"
+
+static int checkout_optimize_new_branch;
static const char * const checkout_usage[] = {
N_("git checkout [<options>] <branch>"),
@@ -40,6 +44,10 @@ struct checkout_opts {
int ignore_skipworktree;
int ignore_other_worktrees;
int show_progress;
+ /*
+ * If new checkout options are added, skip_merge_working_tree
+ * should be updated accordingly.
+ */
const char *new_branch;
const char *new_branch_force;
@@ -77,7 +85,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
return READ_TREE_RECURSIVE;
len = base->len + strlen(pathname);
- ce = xcalloc(1, cache_entry_size(len));
+ ce = make_empty_cache_entry(&the_index, len);
oidcpy(&ce->oid, oid);
memcpy(ce->name, base->buf, base->len);
memcpy(ce->name + base->len, pathname, len - base->len);
@@ -96,7 +104,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
if (ce->ce_mode == old->ce_mode &&
!oidcmp(&ce->oid, &old->oid)) {
old->ce_flags |= CE_UPDATE;
- free(ce);
+ discard_cache_entry(ce);
return 0;
}
}
@@ -230,11 +238,11 @@ static int checkout_merged(int pos, const struct checkout *state)
if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
die(_("Unable to add merge result for '%s'"), path);
free(result_buf.ptr);
- ce = make_cache_entry(mode, oid.hash, path, 2, 0);
+ ce = make_transient_cache_entry(mode, &oid, path, 2);
if (!ce)
die(_("make_cache_entry failed for path '%s'"), path);
status = checkout_entry(ce, state, NULL);
- free(ce);
+ discard_cache_entry(ce);
return status;
}
@@ -316,7 +324,7 @@ static int checkout_paths(const struct checkout_opts *opts,
* match_pathspec() for _all_ entries when
* opts->source_tree != NULL.
*/
- if (ce_path_match(ce, &opts->pathspec, ps_matched))
+ if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))
ce->ce_flags |= CE_MATCHED;
}
@@ -378,7 +386,7 @@ static int checkout_paths(const struct checkout_opts *opts,
die(_("unable to write new index file"));
read_ref_full("HEAD", 0, &rev, NULL);
- head = lookup_commit_reference_gently(&rev, 1);
+ head = lookup_commit_reference_gently(the_repository, &rev, 1);
errs |= post_checkout_hook(head, head, 0);
return errs;
@@ -470,6 +478,98 @@ static void setup_branch_path(struct branch_info *branch)
branch->path = strbuf_detach(&buf, NULL);
}
+/*
+ * Skip merging the trees, updating the index and working directory if and
+ * only if we are creating a new branch via "git checkout -b <new_branch>."
+ */
+static int skip_merge_working_tree(const struct checkout_opts *opts,
+ const struct branch_info *old_branch_info,
+ const struct branch_info *new_branch_info)
+{
+ /*
+ * Do the merge if sparse checkout is on and the user has not opted in
+ * to the optimized behavior
+ */
+ if (core_apply_sparse_checkout && !checkout_optimize_new_branch)
+ return 0;
+
+ /*
+ * We must do the merge if we are actually moving to a new commit.
+ */
+ if (!old_branch_info->commit || !new_branch_info->commit ||
+ oidcmp(&old_branch_info->commit->object.oid, &new_branch_info->commit->object.oid))
+ return 0;
+
+ /*
+ * opts->patch_mode cannot be used with switching branches so is
+ * not tested here
+ */
+
+ /*
+ * opts->quiet only impacts output so doesn't require a merge
+ */
+
+ /*
+ * Honor the explicit request for a three-way merge or to throw away
+ * local changes
+ */
+ if (opts->merge || opts->force)
+ return 0;
+
+ /*
+ * --detach is documented as "updating the index and the files in the
+ * working tree" but this optimization skips those steps so fall through
+ * to the regular code path.
+ */
+ if (opts->force_detach)
+ return 0;
+
+ /*
+ * opts->writeout_stage cannot be used with switching branches so is
+ * not tested here
+ */
+
+ /*
+ * Honor the explicit ignore requests
+ */
+ if (!opts->overwrite_ignore || opts->ignore_skipworktree ||
+ opts->ignore_other_worktrees)
+ return 0;
+
+ /*
+ * opts->show_progress only impacts output so doesn't require a merge
+ */
+
+ /*
+ * If we aren't creating a new branch any changes or updates will
+ * happen in the existing branch. Since that could only be updating
+ * the index and working directory, we don't want to skip those steps
+ * or we've defeated any purpose in running the command.
+ */
+ if (!opts->new_branch)
+ return 0;
+
+ /*
+ * new_branch_force is defined to "create/reset and checkout a branch"
+ * so needs to go through the merge to do the reset
+ */
+ if (opts->new_branch_force)
+ return 0;
+
+ /*
+ * A new orphaned branch requrires the index and the working tree to be
+ * adjusted to <start_point>
+ */
+ if (opts->new_orphan_branch)
+ return 0;
+
+ /*
+ * Remaining variables are not checkout options but used to track state
+ */
+
+ return 1;
+}
+
static int merge_working_tree(const struct checkout_opts *opts,
struct branch_info *old_branch_info,
struct branch_info *new_branch_info,
@@ -829,7 +929,7 @@ static int switch_branches(const struct checkout_opts *opts,
memset(&old_branch_info, 0, sizeof(old_branch_info));
old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
if (old_branch_info.path)
- old_branch_info.commit = lookup_commit_reference_gently(&rev, 1);
+ old_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);
if (!(flag & REF_ISSYMREF))
old_branch_info.path = NULL;
@@ -844,10 +944,19 @@ static int switch_branches(const struct checkout_opts *opts,
parse_commit_or_die(new_branch_info->commit);
}
- ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
- if (ret) {
- free(path_to_free);
- return ret;
+ /* optimize the "checkout -b <new_branch> path */
+ if (skip_merge_working_tree(opts, &old_branch_info, new_branch_info)) {
+ if (!checkout_optimize_new_branch && !opts->quiet) {
+ if (read_cache_preload(NULL) < 0)
+ return error(_("index file corrupt"));
+ show_local_changes(&new_branch_info->commit->object, &opts->diff_options);
+ }
+ } else {
+ ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
+ if (ret) {
+ free(path_to_free);
+ return ret;
+ }
}
if (!opts->quiet && !old_branch_info.path && old_branch_info.commit && new_branch_info->commit != old_branch_info.commit)
@@ -862,6 +971,11 @@ static int switch_branches(const struct checkout_opts *opts,
static int git_checkout_config(const char *var, const char *value, void *cb)
{
+ if (!strcmp(var, "checkout.optimizenewbranch")) {
+ checkout_optimize_new_branch = git_config_bool(var, value);
+ return 0;
+ }
+
if (!strcmp(var, "diff.ignoresubmodules")) {
struct checkout_opts *opts = cb;
handle_ignore_submodules_arg(&opts->diff_options, value);
@@ -878,7 +992,8 @@ static int parse_branchname_arg(int argc, const char **argv,
int dwim_new_local_branch_ok,
struct branch_info *new_branch_info,
struct checkout_opts *opts,
- struct object_id *rev)
+ struct object_id *rev,
+ int *dwim_remotes_matched)
{
struct tree **source_tree = &opts->source_tree;
const char **new_branch = &opts->new_branch;
@@ -910,8 +1025,10 @@ static int parse_branchname_arg(int argc, const char **argv,
* (b) If <something> is _not_ a commit, either "--" is present
* or <something> is not a path, no -t or -b was given, and
* and there is a tracking branch whose name is <something>
- * in one and only one remote, then this is a short-hand to
- * fork local <something> from that remote-tracking branch.
+ * in one and only one remote (or if the branch exists on the
+ * remote named in checkout.defaultRemote), then this is a
+ * short-hand to fork local <something> from that
+ * remote-tracking branch.
*
* (c) Otherwise, if "--" is present, treat it like case (1).
*
@@ -972,7 +1089,8 @@ static int parse_branchname_arg(int argc, const char **argv,
recover_with_dwim = 0;
if (recover_with_dwim) {
- const char *remote = unique_tracking_name(arg, rev);
+ const char *remote = unique_tracking_name(arg, rev,
+ dwim_remotes_matched);
if (remote) {
*new_branch = arg;
arg = remote;
@@ -1003,7 +1121,7 @@ static int parse_branchname_arg(int argc, const char **argv,
else
new_branch_info->path = NULL; /* not an existing branch */
- new_branch_info->commit = lookup_commit_reference_gently(rev, 1);
+ new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
if (!new_branch_info->commit) {
/* not a commit */
*source_tree = parse_tree_indirect(rev);
@@ -1109,6 +1227,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
struct branch_info new_branch_info;
char *conflict_style = NULL;
int dwim_new_local_branch = 1;
+ int dwim_remotes_matched = 0;
struct option options[] = {
OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
@@ -1191,12 +1310,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
if (opts.track != BRANCH_TRACK_UNSPECIFIED && !opts.new_branch) {
const char *argv0 = argv[0];
if (!argc || !strcmp(argv0, "--"))
- die (_("--track needs a branch name"));
+ die(_("--track needs a branch name"));
skip_prefix(argv0, "refs/", &argv0);
skip_prefix(argv0, "remotes/", &argv0);
argv0 = strchr(argv0, '/');
if (!argv0 || !argv0[1])
- die (_("Missing branch name; try -b"));
+ die(_("missing branch name; try -b"));
opts.new_branch = argv0 + 1;
}
@@ -1221,7 +1340,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
opts.track == BRANCH_TRACK_UNSPECIFIED &&
!opts.new_branch;
int n = parse_branchname_arg(argc, argv, dwim_ok,
- &new_branch_info, &opts, &rev);
+ &new_branch_info, &opts, &rev,
+ &dwim_remotes_matched);
argv += n;
argc -= n;
}
@@ -1263,8 +1383,26 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
}
UNLEAK(opts);
- if (opts.patch_mode || opts.pathspec.nr)
- return checkout_paths(&opts, new_branch_info.name);
- else
+ if (opts.patch_mode || opts.pathspec.nr) {
+ int ret = checkout_paths(&opts, new_branch_info.name);
+ if (ret && dwim_remotes_matched > 1 &&
+ advice_checkout_ambiguous_remote_branch_name)
+ advise(_("'%s' matched more than one remote tracking branch.\n"
+ "We found %d remotes with a reference that matched. So we fell back\n"
+ "on trying to resolve the argument as a path, but failed there too!\n"
+ "\n"
+ "If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
+ "you can do so by fully qualifying the name with the --track option:\n"
+ "\n"
+ " git checkout --track origin/<name>\n"
+ "\n"
+ "If you'd like to always have checkouts of an ambiguous <name> prefer\n"
+ "one remote, e.g. the 'origin' remote, consider setting\n"
+ "checkout.defaultRemote=origin in your config."),
+ argv[0],
+ dwim_remotes_matched);
+ return ret;
+ } else {
return checkout_branch(&opts, &new_branch_info);
+ }
}
diff --git a/builtin/clean.c b/builtin/clean.c
index ab402c204c..8d9a7dc206 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -976,7 +976,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
continue;
if (pathspec.nr)
- matches = dir_path_match(ent, &pathspec, 0, NULL);
+ matches = dir_path_match(&the_index, ent, &pathspec, 0, NULL);
if (pathspec.nr && !matches)
continue;
diff --git a/builtin/clone.c b/builtin/clone.c
index 74a804f2e8..15b142d646 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -15,6 +15,7 @@
#include "fetch-pack.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "tree.h"
#include "tree-walk.h"
#include "unpack-trees.h"
@@ -695,7 +696,8 @@ static void update_head(const struct ref *our, const struct ref *remote,
install_branch_config(0, head, option_origin, our->name);
}
} else if (our) {
- struct commit *c = lookup_commit_reference(&our->old_oid);
+ struct commit *c = lookup_commit_reference(the_repository,
+ &our->old_oid);
/* --branch specifies a non-branch (i.e. tags), detach HEAD */
update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
UPDATE_REFS_DIE_ON_ERR);
@@ -746,6 +748,7 @@ static int checkout(int submodule_progress)
memset(&opts, 0, sizeof opts);
opts.update = 1;
opts.merge = 1;
+ opts.clone = 1;
opts.fn = oneway_merge;
opts.verbose_update = (option_verbosity >= 0);
opts.src_index = &the_index;
@@ -895,7 +898,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int err = 0, complete_refs_before_fetch = 1;
int submodule_progress;
- struct refspec_item refspec;
+ struct refspec rs = REFSPEC_INIT_FETCH;
+ struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
fetch_if_missing = 0;
@@ -1077,7 +1081,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();
- refspec_item_init_or_die(&refspec, value.buf, REFSPEC_FETCH);
+ refspec_append(&rs, value.buf);
strbuf_reset(&value);
@@ -1134,10 +1138,18 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (transport->smart_options && !deepen && !filter_options.choice)
transport->smart_options->check_self_contained_and_connected = 1;
- refs = transport_get_remote_refs(transport, NULL);
+
+ argv_array_push(&ref_prefixes, "HEAD");
+ refspec_ref_prefixes(&rs, &ref_prefixes);
+ if (option_branch)
+ expand_ref_prefix(&ref_prefixes, option_branch);
+ if (!option_no_tags)
+ argv_array_push(&ref_prefixes, "refs/tags/");
+
+ refs = transport_get_remote_refs(transport, &ref_prefixes);
if (refs) {
- mapped_refs = wanted_peer_refs(refs, &refspec);
+ mapped_refs = wanted_peer_refs(refs, &rs.items[0]);
/*
* transport_get_remote_refs() may return refs with null sha-1
* in mapped_refs (see struct transport->get_refs_list
@@ -1201,7 +1213,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
update_remote_refs(refs, mapped_refs, remote_head_points_at,
branch_top.buf, reflog_msg.buf, transport,
- !is_local && !filter_options.choice);
+ !is_local);
update_head(our_head_points_at, remote_head, reflog_msg.buf);
@@ -1231,6 +1243,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_release(&value);
junk_mode = JUNK_LEAVE_ALL;
- refspec_item_clear(&refspec);
+ refspec_clear(&rs);
+ argv_array_clear(&ref_prefixes);
return err;
}
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 37420ae0fd..0bf0c48657 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -3,12 +3,19 @@
#include "dir.h"
#include "lockfile.h"
#include "parse-options.h"
+#include "repository.h"
#include "commit-graph.h"
static char const * const builtin_commit_graph_usage[] = {
N_("git commit-graph [--object-dir <objdir>]"),
N_("git commit-graph read [--object-dir <objdir>]"),
- N_("git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--stdin-commits]"),
+ N_("git commit-graph verify [--object-dir <objdir>]"),
+ N_("git commit-graph write [--object-dir <objdir>] [--append] [--reachable|--stdin-packs|--stdin-commits]"),
+ NULL
+};
+
+static const char * const builtin_commit_graph_verify_usage[] = {
+ N_("git commit-graph verify [--object-dir <objdir>]"),
NULL
};
@@ -18,17 +25,48 @@ static const char * const builtin_commit_graph_read_usage[] = {
};
static const char * const builtin_commit_graph_write_usage[] = {
- N_("git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--stdin-commits]"),
+ N_("git commit-graph write [--object-dir <objdir>] [--append] [--reachable|--stdin-packs|--stdin-commits]"),
NULL
};
static struct opts_commit_graph {
const char *obj_dir;
+ int reachable;
int stdin_packs;
int stdin_commits;
int append;
} opts;
+
+static int graph_verify(int argc, const char **argv)
+{
+ struct commit_graph *graph = NULL;
+ char *graph_name;
+
+ static struct option builtin_commit_graph_verify_options[] = {
+ OPT_STRING(0, "object-dir", &opts.obj_dir,
+ N_("dir"),
+ N_("The object directory to store the graph")),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, NULL,
+ builtin_commit_graph_verify_options,
+ builtin_commit_graph_verify_usage, 0);
+
+ if (!opts.obj_dir)
+ opts.obj_dir = get_object_directory();
+
+ graph_name = get_commit_graph_filename(opts.obj_dir);
+ graph = load_commit_graph_one(graph_name);
+ FREE_AND_NULL(graph_name);
+
+ if (!graph)
+ return 0;
+
+ return verify_commit_graph(the_repository, graph);
+}
+
static int graph_read(int argc, const char **argv)
{
struct commit_graph *graph = NULL;
@@ -51,8 +89,11 @@ static int graph_read(int argc, const char **argv)
graph_name = get_commit_graph_filename(opts.obj_dir);
graph = load_commit_graph_one(graph_name);
- if (!graph)
+ if (!graph) {
+ UNLEAK(graph_name);
die("graph file %s does not exist", graph_name);
+ }
+
FREE_AND_NULL(graph_name);
printf("header: %08x %d %d %d %d\n",
@@ -74,23 +115,23 @@ static int graph_read(int argc, const char **argv)
printf(" large_edges");
printf("\n");
+ free_commit_graph(graph);
+
return 0;
}
static int graph_write(int argc, const char **argv)
{
- const char **pack_indexes = NULL;
- int packs_nr = 0;
- const char **commit_hex = NULL;
- int commits_nr = 0;
- const char **lines = NULL;
- int lines_nr = 0;
- int lines_alloc = 0;
+ struct string_list *pack_indexes = NULL;
+ struct string_list *commit_hex = NULL;
+ struct string_list lines;
static struct option builtin_commit_graph_write_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
N_("dir"),
N_("The object directory to store the graph")),
+ OPT_BOOL(0, "reachable", &opts.reachable,
+ N_("start walk at all refs")),
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
N_("scan pack-indexes listed by stdin for commits")),
OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
@@ -104,39 +145,35 @@ static int graph_write(int argc, const char **argv)
builtin_commit_graph_write_options,
builtin_commit_graph_write_usage, 0);
- if (opts.stdin_packs && opts.stdin_commits)
- die(_("cannot use both --stdin-commits and --stdin-packs"));
+ if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
+ die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
if (!opts.obj_dir)
opts.obj_dir = get_object_directory();
+ if (opts.reachable) {
+ write_commit_graph_reachable(opts.obj_dir, opts.append);
+ return 0;
+ }
+
+ string_list_init(&lines, 0);
if (opts.stdin_packs || opts.stdin_commits) {
struct strbuf buf = STRBUF_INIT;
- lines_nr = 0;
- lines_alloc = 128;
- ALLOC_ARRAY(lines, lines_alloc);
-
- while (strbuf_getline(&buf, stdin) != EOF) {
- ALLOC_GROW(lines, lines_nr + 1, lines_alloc);
- lines[lines_nr++] = strbuf_detach(&buf, NULL);
- }
-
- if (opts.stdin_packs) {
- pack_indexes = lines;
- packs_nr = lines_nr;
- }
- if (opts.stdin_commits) {
- commit_hex = lines;
- commits_nr = lines_nr;
- }
+
+ while (strbuf_getline(&buf, stdin) != EOF)
+ string_list_append(&lines, strbuf_detach(&buf, NULL));
+
+ if (opts.stdin_packs)
+ pack_indexes = &lines;
+ if (opts.stdin_commits)
+ commit_hex = &lines;
}
write_commit_graph(opts.obj_dir,
pack_indexes,
- packs_nr,
commit_hex,
- commits_nr,
opts.append);
+ string_list_clear(&lines, 0);
return 0;
}
@@ -162,6 +199,8 @@ int cmd_commit_graph(int argc, const char **argv, const char *prefix)
if (argc > 0) {
if (!strcmp(argv[0], "read"))
return graph_read(argc, argv);
+ if (!strcmp(argv[0], "verify"))
+ return graph_verify(argc, argv);
if (!strcmp(argv[0], "write"))
return graph_write(argc, argv);
}
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index ecf42191da..9ec36a82b6 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -5,6 +5,8 @@
*/
#include "cache.h"
#include "config.h"
+#include "object-store.h"
+#include "repository.h"
#include "commit.h"
#include "tree.h"
#include "builtin.h"
@@ -59,7 +61,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
if (get_oid_commit(argv[i], &oid))
die("Not a valid object name %s", argv[i]);
assert_oid_type(&oid, OBJ_COMMIT);
- new_parent(lookup_commit(&oid), &parents);
+ new_parent(lookup_commit(the_repository, &oid),
+ &parents);
continue;
}
diff --git a/builtin/commit.c b/builtin/commit.c
index 9bcbb0c25c..fa3e53232d 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -33,6 +33,7 @@
#include "sequencer.h"
#include "mailmap.h"
#include "help.h"
+#include "commit-reach.h"
static const char * const builtin_commit_usage[] = {
N_("git commit [<options>] [--] <pathspec>..."),
@@ -168,9 +169,9 @@ static int opt_parse_rename_score(const struct option *opt, const char *arg, int
static void determine_whence(struct wt_status *s)
{
- if (file_exists(git_path_merge_head()))
+ if (file_exists(git_path_merge_head(the_repository)))
whence = FROM_MERGE;
- else if (file_exists(git_path_cherry_pick_head())) {
+ else if (file_exists(git_path_cherry_pick_head(the_repository))) {
whence = FROM_CHERRY_PICK;
if (file_exists(git_path_seq_dir()))
sequencer_in_use = 1;
@@ -251,7 +252,7 @@ static int list_paths(struct string_list *list, const char *with_tree,
if (ce->ce_flags & CE_UPDATE)
continue;
- if (!ce_path_match(ce, pattern, m))
+ if (!ce_path_match(&the_index, ce, pattern, m))
continue;
item = string_list_insert(list, ce->name);
if (ce_skip_worktree(ce))
@@ -718,21 +719,21 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (have_option_m)
strbuf_addbuf(&sb, &message);
hook_arg1 = "message";
- } else if (!stat(git_path_merge_msg(), &statbuf)) {
+ } else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
/*
* prepend SQUASH_MSG here if it exists and a
* "merge --squash" was originally performed
*/
- if (!stat(git_path_squash_msg(), &statbuf)) {
- if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
+ if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
+ if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
die_errno(_("could not read SQUASH_MSG"));
hook_arg1 = "squash";
} else
hook_arg1 = "merge";
- if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
+ if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
die_errno(_("could not read MERGE_MSG"));
- } else if (!stat(git_path_squash_msg(), &statbuf)) {
- if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
+ } else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
+ if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
die_errno(_("could not read SQUASH_MSG"));
hook_arg1 = "squash";
} else if (template_file) {
@@ -813,8 +814,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
" %s\n"
"and try again.\n"),
whence == FROM_MERGE ?
- git_path_merge_head() :
- git_path_cherry_pick_head());
+ git_path_merge_head(the_repository) :
+ git_path_cherry_pick_head(the_repository));
}
fprintf(s->fp, "\n");
@@ -1564,7 +1565,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!reflog_msg)
reflog_msg = "commit (merge)";
pptr = commit_list_append(current_head, pptr);
- fp = xfopen(git_path_merge_head(), "r");
+ fp = xfopen(git_path_merge_head(the_repository), "r");
while (strbuf_getline_lf(&m, fp) != EOF) {
struct commit *parent;
@@ -1575,8 +1576,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
}
fclose(fp);
strbuf_release(&m);
- if (!stat(git_path_merge_mode(), &statbuf)) {
- if (strbuf_read_file(&sb, git_path_merge_mode(), 0) < 0)
+ if (!stat(git_path_merge_mode(the_repository), &statbuf)) {
+ if (strbuf_read_file(&sb, git_path_merge_mode(the_repository), 0) < 0)
die_errno(_("could not read MERGE_MODE"));
if (!strcmp(sb.buf, "no-ff"))
allow_fast_forward = 0;
@@ -1639,17 +1640,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
die("%s", err.buf);
}
- unlink(git_path_cherry_pick_head());
- unlink(git_path_revert_head());
- unlink(git_path_merge_head());
- unlink(git_path_merge_msg());
- unlink(git_path_merge_mode());
- unlink(git_path_squash_msg());
+ unlink(git_path_cherry_pick_head(the_repository));
+ unlink(git_path_revert_head(the_repository));
+ unlink(git_path_merge_head(the_repository));
+ unlink(git_path_merge_msg(the_repository));
+ unlink(git_path_merge_mode(the_repository));
+ unlink(git_path_squash_msg(the_repository));
if (commit_index_files())
- die (_("Repository has been updated, but unable to write\n"
- "new_index file. Check that disk is not full and quota is\n"
- "not exceeded, and then \"git reset HEAD\" to recover."));
+ die(_("repository has been updated, but unable to write\n"
+ "new_index file. Check that disk is not full and quota is\n"
+ "not exceeded, and then \"git reset HEAD\" to recover."));
rerere(0);
run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
diff --git a/builtin/config.c b/builtin/config.c
index b29d26dede..97b58c4aea 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -67,7 +67,7 @@ static int show_origin;
{ OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \
PARSE_OPT_NONEG, option_parse_type, (i) }
-static struct option builtin_config_options[];
+static NORETURN void usage_builtin_config(void);
static int option_parse_type(const struct option *opt, const char *arg,
int unset)
@@ -110,9 +110,8 @@ static int option_parse_type(const struct option *opt, const char *arg,
* --int' and '--type=bool
* --type=int'.
*/
- error("only one type at a time.");
- usage_with_options(builtin_config_usage,
- builtin_config_options);
+ error(_("only one type at a time"));
+ usage_builtin_config();
}
*to_type = new_type;
@@ -157,11 +156,20 @@ static struct option builtin_config_options[] = {
OPT_END(),
};
+static NORETURN void usage_builtin_config(void)
+{
+ usage_with_options(builtin_config_usage, builtin_config_options);
+}
+
static void check_argc(int argc, int min, int max) {
if (argc >= min && argc <= max)
return;
- error("wrong number of arguments");
- usage_with_options(builtin_config_usage, builtin_config_options);
+ if (min == max)
+ error(_("wrong number of arguments, should be %d"), min);
+ else
+ error(_("wrong number of arguments, should be from %d to %d"),
+ min, max);
+ usage_builtin_config();
}
static void show_config_origin(struct strbuf *buf)
@@ -293,7 +301,7 @@ static int get_value(const char *key_, const char *regex_)
key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
if (regcomp(key_regexp, key, REG_EXTENDED)) {
- error("invalid key pattern: %s", key_);
+ error(_("invalid key pattern: %s"), key_);
FREE_AND_NULL(key_regexp);
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
@@ -313,7 +321,7 @@ static int get_value(const char *key_, const char *regex_)
regexp = (regex_t*)xmalloc(sizeof(regex_t));
if (regcomp(regexp, regex_, REG_EXTENDED)) {
- error("invalid pattern: %s", regex_);
+ error(_("invalid pattern: %s"), regex_);
FREE_AND_NULL(regexp);
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
@@ -386,7 +394,7 @@ static char *normalize_value(const char *key, const char *value)
if (type == TYPE_COLOR) {
char v[COLOR_MAXLEN];
if (git_config_color(v, key, value))
- die("cannot parse color '%s'", value);
+ die(_("cannot parse color '%s'"), value);
/*
* The contents of `v` now contain an ANSI escape
@@ -481,13 +489,13 @@ static int get_colorbool(const char *var, int print)
static void check_write(void)
{
if (!given_config_source.file && !startup_info->have_repository)
- die("not in a git directory");
+ die(_("not in a git directory"));
if (given_config_source.use_stdin)
- die("writing to stdin is not supported");
+ die(_("writing to stdin is not supported"));
if (given_config_source.blob)
- die("writing config blobs is not supported");
+ die(_("writing config blobs is not supported"));
}
struct urlmatch_current_candidate_value {
@@ -595,8 +603,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (use_global_config + use_system_config + use_local_config +
!!given_config_source.file + !!given_config_source.blob > 1) {
- error("only one config file at a time.");
- usage_with_options(builtin_config_usage, builtin_config_options);
+ error(_("only one config file at a time"));
+ usage_builtin_config();
}
if (use_local_config && nongit)
@@ -622,7 +630,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
* location; error out even if XDG_CONFIG_HOME
* is set and points at a sane location.
*/
- die("$HOME not set");
+ die(_("$HOME not set"));
if (access_or_warn(user_config, R_OK, 0) &&
xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
@@ -659,13 +667,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
}
if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) {
- error("--get-color and variable type are incoherent");
- usage_with_options(builtin_config_usage, builtin_config_options);
+ error(_("--get-color and variable type are incoherent"));
+ usage_builtin_config();
}
if (HAS_MULTI_BITS(actions)) {
- error("only one action at a time.");
- usage_with_options(builtin_config_usage, builtin_config_options);
+ error(_("only one action at a time"));
+ usage_builtin_config();
}
if (actions == 0)
switch (argc) {
@@ -673,25 +681,24 @@ int cmd_config(int argc, const char **argv, const char *prefix)
case 2: actions = ACTION_SET; break;
case 3: actions = ACTION_SET_ALL; break;
default:
- usage_with_options(builtin_config_usage, builtin_config_options);
+ usage_builtin_config();
}
if (omit_values &&
!(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
- error("--name-only is only applicable to --list or --get-regexp");
- usage_with_options(builtin_config_usage, builtin_config_options);
+ error(_("--name-only is only applicable to --list or --get-regexp"));
+ usage_builtin_config();
}
if (show_origin && !(actions &
(ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) {
- error("--show-origin is only applicable to --get, --get-all, "
- "--get-regexp, and --list.");
- usage_with_options(builtin_config_usage, builtin_config_options);
+ error(_("--show-origin is only applicable to --get, --get-all, "
+ "--get-regexp, and --list"));
+ usage_builtin_config();
}
if (default_value && !(actions & ACTION_GET)) {
- error("--default is only applicable to --get");
- usage_with_options(builtin_config_usage,
- builtin_config_options);
+ error(_("--default is only applicable to --get"));
+ usage_builtin_config();
}
if (actions & PAGING_ACTIONS)
@@ -703,10 +710,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
&given_config_source,
&config_options) < 0) {
if (given_config_source.file)
- die_errno("unable to read config file '%s'",
+ die_errno(_("unable to read config file '%s'"),
given_config_source.file);
else
- die("error processing config file(s)");
+ die(_("error processing config file(s)"));
}
}
else if (actions == ACTION_EDIT) {
@@ -714,11 +721,11 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_argc(argc, 0, 0);
if (!given_config_source.file && nongit)
- die("not in a git directory");
+ die(_("not in a git directory"));
if (given_config_source.use_stdin)
- die("editing stdin is not supported");
+ die(_("editing stdin is not supported"));
if (given_config_source.blob)
- die("editing blobs is not supported");
+ die(_("editing blobs is not supported"));
git_config(git_default_config, NULL);
config_file = given_config_source.file ?
xstrdup(given_config_source.file) :
@@ -819,7 +826,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (ret < 0)
return ret;
if (ret == 0)
- die("No such section!");
+ die(_("no such section: %s"), argv[0]);
}
else if (actions == ACTION_REMOVE_SECTION) {
int ret;
@@ -830,7 +837,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
if (ret < 0)
return ret;
if (ret == 0)
- die("No such section!");
+ die(_("no such section: %s"), argv[0]);
}
else if (actions == ACTION_GET_COLOR) {
check_argc(argc, 1, 2);
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index d51e2ce1ec..a7cad052c6 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -123,7 +123,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
struct strbuf pack_buf = STRBUF_INIT;
struct strbuf garbage_buf = STRBUF_INIT;
- for (p = get_packed_git(the_repository); p; p = p->next) {
+ for (p = get_all_packs(the_repository); p; p = p->next) {
if (!p->pack_local)
continue;
if (open_pack_index(p))
diff --git a/builtin/describe.c b/builtin/describe.c
index bec2513b66..41606c8a90 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -13,6 +13,7 @@
#include "hashmap.h"
#include "argv-array.h"
#include "run-command.h"
+#include "object-store.h"
#include "revision.h"
#include "list-objects.h"
#include "commit-slab.h"
@@ -92,13 +93,13 @@ static int replace_name(struct commit_name *e,
struct tag *t;
if (!e->tag) {
- t = lookup_tag(&e->oid);
+ t = lookup_tag(the_repository, &e->oid);
if (!t || parse_tag(t))
return 1;
e->tag = t;
}
- t = lookup_tag(oid);
+ t = lookup_tag(the_repository, oid);
if (!t || parse_tag(t))
return 0;
*tag = t;
@@ -266,7 +267,7 @@ static unsigned long finish_depth_computation(
static void append_name(struct commit_name *n, struct strbuf *dst)
{
if (n->prio == 2 && !n->tag) {
- n->tag = lookup_tag(&n->oid);
+ n->tag = lookup_tag(the_repository, &n->oid);
if (!n->tag || parse_tag(n->tag))
die(_("annotated tag %s not available"), n->path);
}
@@ -302,7 +303,7 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
unsigned long seen_commits = 0;
unsigned int unannotated_cnt = 0;
- cmit = lookup_commit_reference(oid);
+ cmit = lookup_commit_reference(the_repository, oid);
n = find_commit_name(&cmit->object.oid);
if (n && (tags || all || n->prio == 2)) {
@@ -330,7 +331,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
init_commit_names(&commit_names);
n = hashmap_iter_first(&names, &iter);
for (; n; n = hashmap_iter_next(&iter)) {
- c = lookup_commit_reference_gently(&n->peeled, 1);
+ c = lookup_commit_reference_gently(the_repository,
+ &n->peeled, 1);
if (c)
*commit_names_at(&commit_names, c) = n;
}
@@ -508,7 +510,7 @@ static void describe(const char *arg, int last_one)
if (get_oid(arg, &oid))
die(_("Not a valid object name %s"), arg);
- cmit = lookup_commit_reference_gently(&oid, 1);
+ cmit = lookup_commit_reference_gently(the_repository, &oid, 1);
if (cmit)
describe_commit(&oid, &sb);
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 473615117e..d07bf2e4c4 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -5,12 +5,13 @@
#include "log-tree.h"
#include "builtin.h"
#include "submodule.h"
+#include "repository.h"
static struct rev_info log_tree_opt;
static int diff_tree_commit_oid(const struct object_id *oid)
{
- struct commit *commit = lookup_commit_reference(oid);
+ struct commit *commit = lookup_commit_reference(the_repository, oid);
if (!commit)
return -1;
return log_tree_commit(&log_tree_opt, commit);
@@ -24,7 +25,7 @@ static int stdin_diff_commit(struct commit *commit, const char *p)
/* Graft the fake parents locally to the commit */
while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) {
- struct commit *parent = lookup_commit(&oid);
+ struct commit *parent = lookup_commit(the_repository, &oid);
if (!pptr) {
/* Free the real parent list */
free_commit_list(commit->parents);
@@ -45,7 +46,7 @@ static int stdin_diff_trees(struct tree *tree1, const char *p)
struct tree *tree2;
if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p)
return error("Need exactly two trees, separated by a space");
- tree2 = lookup_tree(&oid);
+ tree2 = lookup_tree(the_repository, &oid);
if (!tree2 || parse_tree(tree2))
return -1;
printf("%s %s\n", oid_to_hex(&tree1->object.oid),
@@ -68,7 +69,7 @@ static int diff_tree_stdin(char *line)
line[len-1] = 0;
if (parse_oid_hex(line, &oid, &p))
return -1;
- obj = parse_object(&oid);
+ obj = parse_object(the_repository, &oid);
if (!obj)
return -1;
if (obj->type == OBJ_COMMIT)
@@ -162,9 +163,11 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
int saved_nrl = 0;
int saved_dcctc = 0;
- if (opt->diffopt.detect_rename)
- opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
- DIFF_SETUP_USE_CACHE);
+ if (opt->diffopt.detect_rename) {
+ if (!the_index.cache)
+ read_index(&the_index);
+ opt->diffopt.setup |= DIFF_SETUP_USE_SIZE_CACHE;
+ }
while (fgets(line, sizeof(line), stdin)) {
struct object_id oid;
diff --git a/builtin/diff.c b/builtin/diff.c
index b709b6e984..361a3c3ed3 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -386,7 +386,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
add_head_to_pending(&rev);
if (!rev.pending.nr) {
struct tree *tree;
- tree = lookup_tree(the_hash_algo->empty_tree);
+ tree = lookup_tree(the_repository,
+ the_repository->hash_algo->empty_tree);
add_pending_object(&rev, &tree->object, "HEAD");
}
break;
@@ -400,8 +401,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
const char *name = entry->name;
int flags = (obj->flags & UNINTERESTING);
if (!obj->parsed)
- obj = parse_object(&obj->oid);
- obj = deref_tag(obj, NULL, 0);
+ obj = parse_object(the_repository, &obj->oid);
+ obj = deref_tag(the_repository, obj, NULL, 0);
if (!obj)
die(_("invalid object '%s' given."), name);
if (obj->type == OBJ_COMMIT)
diff --git a/builtin/difftool.c b/builtin/difftool.c
index bc97d4aef2..cdd585ca76 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -20,6 +20,7 @@
#include "argv-array.h"
#include "strbuf.h"
#include "lockfile.h"
+#include "object-store.h"
#include "dir.h"
static char *diff_gui_tool;
@@ -321,10 +322,10 @@ static int checkout_path(unsigned mode, struct object_id *oid,
struct cache_entry *ce;
int ret;
- ce = make_cache_entry(mode, oid->hash, path, 0, 0);
+ ce = make_transient_cache_entry(mode, oid, path, 0);
ret = checkout_entry(ce, state, NULL);
- free(ce);
+ discard_cache_entry(ce);
return ret;
}
@@ -488,7 +489,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
* index.
*/
struct cache_entry *ce2 =
- make_cache_entry(rmode, roid.hash,
+ make_cache_entry(&wtindex, rmode, &roid,
dst_path, 0, 0);
add_index_entry(&wtindex, ce2,
@@ -702,7 +703,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
1, PARSE_OPT_NONEG | PARSE_OPT_HIDDEN),
OPT_BOOL(0, "symlinks", &symlinks,
N_("use symlinks in dir-diff mode")),
- OPT_STRING('t', "tool", &difftool_cmd, N_("<tool>"),
+ OPT_STRING('t', "tool", &difftool_cmd, N_("tool"),
N_("use the specified diff tool")),
OPT_BOOL(0, "tool-help", &tool_help,
N_("print a list of diff tools that may be used with "
@@ -710,7 +711,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "trust-exit-code", &trust_exit_code,
N_("make 'git-difftool' exit when an invoked diff "
"tool returns a non - zero exit code")),
- OPT_STRING('x', "extcmd", &extcmd, N_("<command>"),
+ OPT_STRING('x', "extcmd", &extcmd, N_("command"),
N_("specify a custom command for viewing diffs")),
OPT_END()
};
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 73d12c1020..9bd8a14b57 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -8,6 +8,7 @@
#include "config.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "commit.h"
#include "object.h"
#include "tag.h"
@@ -229,21 +230,22 @@ static void export_blob(const struct object_id *oid)
if (is_null_oid(oid))
return;
- object = lookup_object(oid->hash);
+ object = lookup_object(the_repository, oid->hash);
if (object && object->flags & SHOWN)
return;
if (anonymize) {
buf = anonymize_blob(&size);
- object = (struct object *)lookup_blob(oid);
+ object = (struct object *)lookup_blob(the_repository, oid);
eaten = 0;
} else {
buf = read_object_file(oid, &type, &size);
if (!buf)
- die ("Could not read blob %s", oid_to_hex(oid));
+ die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(oid, buf, size, type_name(type)) < 0)
die("sha1 mismatch in blob %s", oid_to_hex(oid));
- object = parse_object_buffer(oid, type, size, buf, &eaten);
+ object = parse_object_buffer(the_repository, oid, type,
+ size, buf, &eaten);
}
if (!object)
@@ -253,7 +255,7 @@ static void export_blob(const struct object_id *oid)
printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size);
if (size && fwrite(buf, size, 1, stdout) != 1)
- die_errno ("Could not write blob '%s'", oid_to_hex(oid));
+ die_errno("could not write blob '%s'", oid_to_hex(oid));
printf("\n");
show_progress();
@@ -401,7 +403,8 @@ static void show_filemodify(struct diff_queue_struct *q,
anonymize_sha1(&spec->oid) :
spec->oid.hash));
else {
- struct object *object = lookup_object(spec->oid.hash);
+ struct object *object = lookup_object(the_repository,
+ spec->oid.hash);
printf("M %06o :%d ", spec->mode,
get_object_mark(object));
}
@@ -560,14 +563,14 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
commit_buffer = get_commit_buffer(commit, NULL);
author = strstr(commit_buffer, "\nauthor ");
if (!author)
- die ("Could not find author in commit %s",
- oid_to_hex(&commit->object.oid));
+ die("could not find author in commit %s",
+ oid_to_hex(&commit->object.oid));
author++;
author_end = strchrnul(author, '\n');
committer = strstr(author_end, "\ncommitter ");
if (!committer)
- die ("Could not find committer in commit %s",
- oid_to_hex(&commit->object.oid));
+ die("could not find committer in commit %s",
+ oid_to_hex(&commit->object.oid));
committer++;
committer_end = strchrnul(committer, '\n');
message = strstr(committer_end, "\n\n");
@@ -688,7 +691,7 @@ static void handle_tag(const char *name, struct tag *tag)
buf = read_object_file(&tag->object.oid, &type, &size);
if (!buf)
- die ("Could not read tag %s", oid_to_hex(&tag->object.oid));
+ die("could not read tag %s", oid_to_hex(&tag->object.oid));
message = memmem(buf, size, "\n\n", 2);
if (message) {
message += 2;
@@ -725,18 +728,18 @@ static void handle_tag(const char *name, struct tag *tag)
if (signature)
switch(signed_tag_mode) {
case ABORT:
- die ("Encountered signed tag %s; use "
- "--signed-tags=<mode> to handle it.",
- oid_to_hex(&tag->object.oid));
+ die("encountered signed tag %s; use "
+ "--signed-tags=<mode> to handle it",
+ oid_to_hex(&tag->object.oid));
case WARN:
- warning ("Exporting signed tag %s",
- oid_to_hex(&tag->object.oid));
+ warning("exporting signed tag %s",
+ oid_to_hex(&tag->object.oid));
/* fallthru */
case VERBATIM:
break;
case WARN_STRIP:
- warning ("Stripping signature from tag %s",
- oid_to_hex(&tag->object.oid));
+ warning("stripping signature from tag %s",
+ oid_to_hex(&tag->object.oid));
/* fallthru */
case STRIP:
message_size = signature + 1 - message;
@@ -750,18 +753,18 @@ static void handle_tag(const char *name, struct tag *tag)
if (!tagged_mark) {
switch(tag_of_filtered_mode) {
case ABORT:
- die ("Tag %s tags unexported object; use "
- "--tag-of-filtered-object=<mode> to handle it.",
- oid_to_hex(&tag->object.oid));
+ die("tag %s tags unexported object; use "
+ "--tag-of-filtered-object=<mode> to handle it",
+ oid_to_hex(&tag->object.oid));
case DROP:
/* Ignore this tag altogether */
free(buf);
return;
case REWRITE:
if (tagged->type != OBJ_COMMIT) {
- die ("Tag %s tags unexported %s!",
- oid_to_hex(&tag->object.oid),
- type_name(tagged->type));
+ die("tag %s tags unexported %s!",
+ oid_to_hex(&tag->object.oid),
+ type_name(tagged->type));
}
p = (struct commit *)tagged;
for (;;) {
@@ -772,7 +775,7 @@ static void handle_tag(const char *name, struct tag *tag)
if (!(p->object.flags & TREESAME))
break;
if (!p->parents)
- die ("Can't find replacement commit for tag %s\n",
+ die("can't find replacement commit for tag %s",
oid_to_hex(&tag->object.oid));
p = p->parents->item;
}
@@ -800,7 +803,7 @@ static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
/* handle nested tags */
while (tag && tag->object.type == OBJ_TAG) {
- parse_object(&tag->object.oid);
+ parse_object(the_repository, &tag->object.oid);
string_list_append(&extra_refs, full_name)->util = tag;
tag = (struct tag *)tag->tagged;
}
@@ -960,7 +963,7 @@ static void import_marks(char *input_file)
/* only commits */
continue;
- commit = lookup_commit(&oid);
+ commit = lookup_commit(the_repository, &oid);
if (!commit)
die("not a commit? can't happen: %s", oid_to_hex(&oid));
diff --git a/builtin/fetch.c b/builtin/fetch.c
index ea5b9669ad..eed15c7813 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -6,6 +6,7 @@
#include "repository.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "commit.h"
#include "builtin.h"
#include "string-list.h"
@@ -21,6 +22,7 @@
#include "utf8.h"
#include "packfile.h"
#include "list-objects-filter-options.h"
+#include "commit-reach.h"
static const char * const builtin_fetch_usage[] = {
N_("git fetch [<options>] [<repository> [<refspec>...]]"),
@@ -63,6 +65,7 @@ static int shown_url = 0;
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options;
static struct string_list server_options = STRING_LIST_INIT_DUP;
+static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
@@ -93,19 +96,6 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
return git_default_config(k, v, cb);
}
-static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
-{
- if (!strcmp(var, "submodule.fetchjobs")) {
- max_children = parse_submodule_fetchjobs(var, value);
- return 0;
- } else if (!strcmp(var, "fetch.recursesubmodules")) {
- recurse_submodules = parse_fetch_recurse_submodules_arg(var, value);
- return 0;
- }
-
- return 0;
-}
-
static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
{
/*
@@ -174,6 +164,8 @@ static struct option builtin_fetch_options[] = {
TRANSPORT_FAMILY_IPV4),
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
TRANSPORT_FAMILY_IPV6),
+ OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
+ N_("report that we have only objects reachable from this object")),
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_END()
};
@@ -254,9 +246,9 @@ static int will_fetch(struct ref **head, const unsigned char *sha1)
return 0;
}
-static void find_non_local_tags(struct transport *transport,
- struct ref **head,
- struct ref ***tail)
+static void find_non_local_tags(const struct ref *refs,
+ struct ref **head,
+ struct ref ***tail)
{
struct string_list existing_refs = STRING_LIST_INIT_DUP;
struct string_list remote_refs = STRING_LIST_INIT_NODUP;
@@ -264,7 +256,7 @@ static void find_non_local_tags(struct transport *transport,
struct string_list_item *item = NULL;
for_each_ref(add_existing, &existing_refs);
- for (ref = transport_get_remote_refs(transport, NULL); ref; ref = ref->next) {
+ for (ref = refs; ref; ref = ref->next) {
if (!starts_with(ref->name, "refs/tags/"))
continue;
@@ -338,7 +330,8 @@ static void find_non_local_tags(struct transport *transport,
string_list_clear(&remote_refs, 0);
}
-static struct ref *get_ref_map(struct transport *transport,
+static struct ref *get_ref_map(struct remote *remote,
+ const struct ref *remote_refs,
struct refspec *rs,
int tags, int *autotags)
{
@@ -346,26 +339,11 @@ static struct ref *get_ref_map(struct transport *transport,
struct ref *rm;
struct ref *ref_map = NULL;
struct ref **tail = &ref_map;
- struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
/* opportunistically-updated references: */
struct ref *orefs = NULL, **oref_tail = &orefs;
- const struct ref *remote_refs;
-
- if (rs->nr)
- refspec_ref_prefixes(rs, &ref_prefixes);
- else if (transport->remote && transport->remote->fetch.nr)
- refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
-
- if (ref_prefixes.argc &&
- (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
- argv_array_push(&ref_prefixes, "refs/tags/");
- }
-
- remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
-
- argv_array_clear(&ref_prefixes);
+ struct string_list existing_refs = STRING_LIST_INIT_DUP;
if (rs->nr) {
struct refspec *fetch_refspec;
@@ -402,7 +380,7 @@ static struct ref *get_ref_map(struct transport *transport,
if (refmap.nr)
fetch_refspec = &refmap;
else
- fetch_refspec = &transport->remote->fetch;
+ fetch_refspec = &remote->fetch;
for (i = 0; i < fetch_refspec->nr; i++)
get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
@@ -410,7 +388,6 @@ static struct ref *get_ref_map(struct transport *transport,
die("--refmap option is only meaningful with command-line refspec(s).");
} else {
/* Use the defaults */
- struct remote *remote = transport->remote;
struct branch *branch = branch_get(NULL);
int has_merge = branch_has_merge_config(branch);
if (remote &&
@@ -449,7 +426,7 @@ static struct ref *get_ref_map(struct transport *transport,
/* also fetch all tags */
get_fetch_map(remote_refs, tag_refspec, &tail, 0);
else if (tags == TAGS_DEFAULT && *autotags)
- find_non_local_tags(transport, &ref_map, &tail);
+ find_non_local_tags(remote_refs, &ref_map, &tail);
/* Now append any refs to be updated opportunistically: */
*tail = orefs;
@@ -458,7 +435,23 @@ static struct ref *get_ref_map(struct transport *transport,
tail = &rm->next;
}
- return ref_remove_duplicates(ref_map);
+ ref_map = ref_remove_duplicates(ref_map);
+
+ for_each_ref(add_existing, &existing_refs);
+ for (rm = ref_map; rm; rm = rm->next) {
+ if (rm->peer_ref) {
+ struct string_list_item *peer_item =
+ string_list_lookup(&existing_refs,
+ rm->peer_ref->name);
+ if (peer_item) {
+ struct object_id *old_oid = peer_item->util;
+ oidcpy(&rm->peer_ref->old_oid, old_oid);
+ }
+ }
+ }
+ string_list_clear(&existing_refs, 1);
+
+ return ref_map;
}
#define STORE_REF_ERROR_OTHER 1
@@ -683,8 +676,10 @@ static int update_local_ref(struct ref *ref,
return r;
}
- current = lookup_commit_reference_gently(&ref->old_oid, 1);
- updated = lookup_commit_reference_gently(&ref->new_oid, 1);
+ current = lookup_commit_reference_gently(the_repository,
+ &ref->old_oid, 1);
+ updated = lookup_commit_reference_gently(the_repository,
+ &ref->new_oid, 1);
if (!current || !updated) {
const char *msg;
const char *what;
@@ -768,7 +763,7 @@ static int iterate_ref_map(void *cb_data, struct object_id *oid)
}
static int store_updated_refs(const char *raw_url, const char *remote_name,
- struct ref *ref_map)
+ int connectivity_checked, struct ref *ref_map)
{
FILE *fp;
struct commit *commit;
@@ -777,7 +772,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
const char *what, *kind;
struct ref *rm;
char *url;
- const char *filename = dry_run ? "/dev/null" : git_path_fetch_head();
+ const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(the_repository);
int want_status;
int summary_width = transport_summary_width(ref_map);
@@ -790,10 +785,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
else
url = xstrdup("foreign");
- rm = ref_map;
- if (check_connected(iterate_ref_map, &rm, NULL)) {
- rc = error(_("%s did not send all necessary objects\n"), url);
- goto abort;
+ if (!connectivity_checked) {
+ rm = ref_map;
+ if (check_connected(iterate_ref_map, &rm, NULL)) {
+ rc = error(_("%s did not send all necessary objects\n"), url);
+ goto abort;
+ }
}
prepare_format_display(ref_map);
@@ -817,7 +814,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
continue;
}
- commit = lookup_commit_reference_gently(&rm->old_oid,
+ commit = lookup_commit_reference_gently(the_repository,
+ &rm->old_oid,
1);
if (!commit)
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
@@ -951,9 +949,24 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
if (ret)
ret = transport_fetch_refs(transport, ref_map);
if (!ret)
- ret |= store_updated_refs(transport->url,
- transport->remote->name,
- ref_map);
+ /*
+ * Keep the new pack's ".keep" file around to allow the caller
+ * time to update refs to reference the new objects.
+ */
+ return 0;
+ transport_unlock_pack(transport);
+ return ret;
+}
+
+/* Update local refs based on the ref values fetched from a remote */
+static int consume_refs(struct transport *transport, struct ref *ref_map)
+{
+ int connectivity_checked = transport->smart_options
+ ? transport->smart_options->connectivity_checked : 0;
+ int ret = store_updated_refs(transport->url,
+ transport->remote->name,
+ connectivity_checked,
+ ref_map);
transport_unlock_pack(transport);
return ret;
}
@@ -1029,7 +1042,7 @@ static void check_not_current_branch(struct ref *ref_map)
static int truncate_fetch_head(void)
{
- const char *filename = git_path_fetch_head();
+ const char *filename = git_path_fetch_head(the_repository);
FILE *fp = fopen_for_writing(filename);
if (!fp)
@@ -1049,6 +1062,40 @@ static void set_option(struct transport *transport, const char *name, const char
name, transport->url);
}
+
+static int add_oid(const char *refname, const struct object_id *oid, int flags,
+ void *cb_data)
+{
+ struct oid_array *oids = cb_data;
+
+ oid_array_append(oids, oid);
+ return 0;
+}
+
+static void add_negotiation_tips(struct git_transport_options *smart_options)
+{
+ struct oid_array *oids = xcalloc(1, sizeof(*oids));
+ int i;
+
+ for (i = 0; i < negotiation_tip.nr; i++) {
+ const char *s = negotiation_tip.items[i].string;
+ int old_nr;
+ if (!has_glob_specials(s)) {
+ struct object_id oid;
+ if (get_oid(s, &oid))
+ die("%s is not a valid object", s);
+ oid_array_append(oids, &oid);
+ continue;
+ }
+ old_nr = oids->nr;
+ for_each_glob_ref(add_oid, s, oids);
+ if (old_nr == oids->nr)
+ warning("Ignoring --negotiation-tip=%s because it does not match any refs",
+ s);
+ }
+ smart_options->negotiation_tips = oids;
+}
+
static struct transport *prepare_transport(struct remote *remote, int deepen)
{
struct transport *transport;
@@ -1075,6 +1122,12 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
filter_options.filter_spec);
set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
}
+ if (negotiation_tip.nr) {
+ if (transport->smart_options)
+ add_negotiation_tips(transport->smart_options);
+ else
+ warning("Ignoring --negotiation-tip because the protocol does not support it.");
+ }
return transport;
}
@@ -1099,7 +1152,8 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
transport_set_option(transport, TRANS_OPT_DEPTH, "0");
transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
- fetch_refs(transport, ref_map);
+ if (!fetch_refs(transport, ref_map))
+ consume_refs(transport, ref_map);
if (gsecondary) {
transport_disconnect(gsecondary);
@@ -1110,13 +1164,11 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
static int do_fetch(struct transport *transport,
struct refspec *rs)
{
- struct string_list existing_refs = STRING_LIST_INIT_DUP;
struct ref *ref_map;
- struct ref *rm;
int autotags = (transport->remote->fetch_tags == 1);
int retcode = 0;
-
- for_each_ref(add_existing, &existing_refs);
+ const struct ref *remote_refs;
+ struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
if (tags == TAGS_DEFAULT) {
if (transport->remote->fetch_tags == 2)
@@ -1132,22 +1184,24 @@ static int do_fetch(struct transport *transport,
goto cleanup;
}
- ref_map = get_ref_map(transport, rs, tags, &autotags);
- if (!update_head_ok)
- check_not_current_branch(ref_map);
+ if (rs->nr)
+ refspec_ref_prefixes(rs, &ref_prefixes);
+ else if (transport->remote && transport->remote->fetch.nr)
+ refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
- for (rm = ref_map; rm; rm = rm->next) {
- if (rm->peer_ref) {
- struct string_list_item *peer_item =
- string_list_lookup(&existing_refs,
- rm->peer_ref->name);
- if (peer_item) {
- struct object_id *old_oid = peer_item->util;
- oidcpy(&rm->peer_ref->old_oid, old_oid);
- }
- }
+ if (ref_prefixes.argc &&
+ (tags == TAGS_SET || (tags == TAGS_DEFAULT))) {
+ argv_array_push(&ref_prefixes, "refs/tags/");
}
+ remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
+ argv_array_clear(&ref_prefixes);
+
+ ref_map = get_ref_map(transport->remote, remote_refs, rs,
+ tags, &autotags);
+ if (!update_head_ok)
+ check_not_current_branch(ref_map);
+
if (tags == TAGS_DEFAULT && autotags)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
if (prune) {
@@ -1164,7 +1218,7 @@ static int do_fetch(struct transport *transport,
transport->url);
}
}
- if (fetch_refs(transport, ref_map)) {
+ if (fetch_refs(transport, ref_map) || consume_refs(transport, ref_map)) {
free_refs(ref_map);
retcode = 1;
goto cleanup;
@@ -1176,14 +1230,13 @@ static int do_fetch(struct transport *transport,
if (tags == TAGS_DEFAULT && autotags) {
struct ref **tail = &ref_map;
ref_map = NULL;
- find_non_local_tags(transport, &ref_map, &tail);
+ find_non_local_tags(remote_refs, &ref_map, &tail);
if (ref_map)
backfill_tags(transport, ref_map);
free_refs(ref_map);
}
cleanup:
- string_list_clear(&existing_refs, 1);
return retcode;
}
@@ -1433,7 +1486,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
for (i = 1; i < argc; i++)
strbuf_addf(&default_rla, " %s", argv[i]);
- config_from_gitmodules(gitmodules_fetch_config, NULL);
+ fetch_config_from_gitmodules(&max_children, &recurse_submodules);
git_config(git_fetch_config, NULL);
argc = parse_options(argc, argv, prefix,
@@ -1449,7 +1502,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (unshallow) {
if (depth)
die(_("--depth and --unshallow cannot be used together"));
- else if (!is_repository_shallow())
+ else if (!is_repository_shallow(the_repository))
die(_("--unshallow on a complete repository does not make sense"));
else
depth = xstrfmt("%d", INFINITE_DEPTH);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index bd680be687..e5668f27d8 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -2,6 +2,7 @@
#include "cache.h"
#include "config.h"
#include "refs.h"
+#include "object-store.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
@@ -10,6 +11,8 @@
#include "branch.h"
#include "fmt-merge-msg.h"
#include "gpg-interface.h"
+#include "repository.h"
+#include "commit-reach.h"
static const char * const fmt_merge_msg_usage[] = {
N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
@@ -108,14 +111,15 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
struct string_list_item *item;
int pulling_head = 0;
struct object_id oid;
+ const unsigned hexsz = the_hash_algo->hexsz;
- if (len < GIT_SHA1_HEXSZ + 3 || line[GIT_SHA1_HEXSZ] != '\t')
+ if (len < hexsz + 3 || line[hexsz] != '\t')
return 1;
- if (starts_with(line + GIT_SHA1_HEXSZ + 1, "not-for-merge"))
+ if (starts_with(line + hexsz + 1, "not-for-merge"))
return 0;
- if (line[GIT_SHA1_HEXSZ + 1] != '\t')
+ if (line[hexsz + 1] != '\t')
return 2;
i = get_oid_hex(line, &oid);
@@ -130,7 +134,7 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
if (line[len - 1] == '\n')
line[len - 1] = 0;
- line += GIT_SHA1_HEXSZ + 2;
+ line += hexsz + 2;
/*
* At this point, line points at the beginning of comment e.g.
@@ -342,7 +346,9 @@ static void shortlog(const char *name,
const struct object_id *oid = &origin_data->oid;
int limit = opts->shortlog_len;
- branch = deref_tag(parse_object(oid), oid_to_hex(oid), GIT_SHA1_HEXSZ);
+ branch = deref_tag(the_repository, parse_object(the_repository, oid),
+ oid_to_hex(oid),
+ the_hash_algo->hexsz);
if (!branch || branch->type != OBJ_COMMIT)
return;
@@ -545,6 +551,7 @@ static void find_merge_parents(struct merge_parents *result,
int len;
char *p = in->buf + pos;
char *newline = strchr(p, '\n');
+ const char *q;
struct object_id oid;
struct commit *parent;
struct object *obj;
@@ -552,24 +559,23 @@ static void find_merge_parents(struct merge_parents *result,
len = newline ? newline - p : strlen(p);
pos += len + !!newline;
- if (len < GIT_SHA1_HEXSZ + 3 ||
- get_oid_hex(p, &oid) ||
- p[GIT_SHA1_HEXSZ] != '\t' ||
- p[GIT_SHA1_HEXSZ + 1] != '\t')
+ if (parse_oid_hex(p, &oid, &q) ||
+ q[0] != '\t' ||
+ q[1] != '\t')
continue; /* skip not-for-merge */
/*
* Do not use get_merge_parent() here; we do not have
* "name" here and we do not want to contaminate its
* util field yet.
*/
- obj = parse_object(&oid);
+ obj = parse_object(the_repository, &oid);
parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
if (!parent)
continue;
commit_list_insert(parent, &parents);
add_merge_parent(result, &obj->oid, &parent->object.oid);
}
- head_commit = lookup_commit(head);
+ head_commit = lookup_commit(the_repository, head);
if (head_commit)
commit_list_insert(head_commit, &parents);
reduce_heads_replace(&parents);
@@ -623,7 +629,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
i++;
p[len] = 0;
if (handle_line(p, &merge_parents))
- die ("Error in line %d: %.*s", i, len, p);
+ die("error in line %d: %.*s", i, len, p);
}
if (opts->add_title && srcs.nr)
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 3ad4f160f9..63c8578cc1 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -18,6 +18,7 @@
#include "decorate.h"
#include "packfile.h"
#include "object-store.h"
+#include "run-command.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
@@ -47,6 +48,7 @@ static int name_objects;
#define ERROR_REACHABLE 02
#define ERROR_PACK 04
#define ERROR_REFS 010
+#define ERROR_COMMIT_GRAPH 020
static const char *describe_object(struct object *obj)
{
@@ -70,7 +72,7 @@ static const char *printable_type(struct object *obj)
enum object_type type = oid_object_info(the_repository,
&obj->oid, NULL);
if (type > 0)
- object_as_type(obj, type, 0);
+ object_as_type(the_repository, obj, type, 0);
}
ret = type_name(obj->type);
@@ -392,7 +394,8 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
* verify_packfile(), data_valid variable for details.
*/
struct object *obj;
- obj = parse_object_buffer(oid, type, size, buffer, eaten);
+ obj = parse_object_buffer(the_repository, oid, type, size, buffer,
+ eaten);
if (!obj) {
errors_found |= ERROR_OBJECT;
return error("%s: object corrupt or missing", oid_to_hex(oid));
@@ -410,7 +413,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
struct object *obj;
if (!is_null_oid(oid)) {
- obj = lookup_object(oid->hash);
+ obj = lookup_object(the_repository, oid->hash);
if (obj && (obj->flags & HAS_OBJ)) {
if (timestamp && name_objects)
add_decoration(fsck_walk_options.object_names,
@@ -452,7 +455,7 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
{
struct object *obj;
- obj = parse_object(oid);
+ obj = parse_object(the_repository, oid);
if (!obj) {
if (is_promisor_object(oid)) {
/*
@@ -525,7 +528,9 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data)
if (!contents && type != OBJ_BLOB)
BUG("read_loose_object streamed a non-blob");
- obj = parse_object_buffer(oid, type, size, contents, &eaten);
+ obj = parse_object_buffer(the_repository, oid, type, size,
+ contents, &eaten);
+
if (!obj) {
errors_found |= ERROR_OBJECT;
error("%s: object could not be parsed: %s",
@@ -614,7 +619,7 @@ static int fsck_cache_tree(struct cache_tree *it)
fprintf(stderr, "Checking cache tree\n");
if (0 <= it->entry_count) {
- struct object *obj = parse_object(&it->oid);
+ struct object *obj = parse_object(the_repository, &it->oid);
if (!obj) {
error("%s: invalid sha1 pointer in cache-tree",
oid_to_hex(&it->oid));
@@ -689,7 +694,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
fetch_if_missing = 0;
errors_found = 0;
- check_replace_refs = 0;
+ read_replace_refs = 0;
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
@@ -735,7 +740,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
struct progress *progress = NULL;
if (show_progress) {
- for (p = get_packed_git(the_repository); p;
+ for (p = get_all_packs(the_repository); p;
p = p->next) {
if (open_pack_index(p))
continue;
@@ -744,7 +749,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
progress = start_progress(_("Checking objects"), total);
}
- for (p = get_packed_git(the_repository); p;
+ for (p = get_all_packs(the_repository); p;
p = p->next) {
/* verify gives error messages itself */
if (verify_pack(p, fsck_obj_buffer,
@@ -763,7 +768,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
const char *arg = argv[i];
struct object_id oid;
if (!get_oid(arg, &oid)) {
- struct object *obj = lookup_object(oid.hash);
+ struct object *obj = lookup_object(the_repository,
+ oid.hash);
if (!obj || !(obj->flags & HAS_OBJ)) {
if (is_promisor_object(&oid))
@@ -806,7 +812,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
mode = active_cache[i]->ce_mode;
if (S_ISGITLINK(mode))
continue;
- blob = lookup_blob(&active_cache[i]->oid);
+ blob = lookup_blob(the_repository,
+ &active_cache[i]->oid);
if (!blob)
continue;
obj = &blob->object;
@@ -822,5 +829,24 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
}
check_connectivity();
+
+ if (!git_config_get_bool("core.commitgraph", &i) && i) {
+ struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
+ const char *verify_argv[] = { "commit-graph", "verify", NULL, NULL, NULL };
+
+ commit_graph_verify.argv = verify_argv;
+ commit_graph_verify.git_cmd = 1;
+ if (run_command(&commit_graph_verify))
+ errors_found |= ERROR_COMMIT_GRAPH;
+
+ prepare_alt_odb(the_repository);
+ for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) {
+ verify_argv[2] = "--object-dir";
+ verify_argv[3] = alt->path;
+ if (run_command(&commit_graph_verify))
+ errors_found |= ERROR_COMMIT_GRAPH;
+ }
+ }
+
return errors_found;
}
diff --git a/builtin/gc.c b/builtin/gc.c
index ccfb1ceaeb..2b592260e9 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -20,6 +20,7 @@
#include "sigchain.h"
#include "argv-array.h"
#include "commit.h"
+#include "commit-graph.h"
#include "packfile.h"
#include "object-store.h"
#include "pack.h"
@@ -40,6 +41,7 @@ static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
static int gc_auto_pack_limit = 50;
+static int gc_write_commit_graph;
static int detach_auto = 1;
static timestamp_t gc_log_expire_time;
static const char *gc_log_expire = "1.day.ago";
@@ -129,6 +131,7 @@ static void gc_config(void)
git_config_get_int("gc.aggressivedepth", &aggressive_depth);
git_config_get_int("gc.auto", &gc_auto_threshold);
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
+ git_config_get_bool("gc.writecommitgraph", &gc_write_commit_graph);
git_config_get_bool("gc.autodetach", &detach_auto);
git_config_get_expiry("gc.pruneexpire", &prune_expire);
git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
@@ -180,7 +183,7 @@ static struct packed_git *find_base_packs(struct string_list *packs,
{
struct packed_git *p, *base = NULL;
- for (p = get_packed_git(the_repository); p; p = p->next) {
+ for (p = get_all_packs(the_repository); p; p = p->next) {
if (!p->pack_local)
continue;
if (limit) {
@@ -205,7 +208,7 @@ static int too_many_packs(void)
if (gc_auto_pack_limit <= 0)
return 0;
- for (cnt = 0, p = get_packed_git(the_repository); p; p = p->next) {
+ for (cnt = 0, p = get_all_packs(the_repository); p; p = p->next) {
if (!p->pack_local)
continue;
if (p->pack_keep)
@@ -612,6 +615,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
return -1;
if (!repository_format_precious_objects) {
+ close_all_packs(the_repository->objects);
if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
return error(FAILED_RUN, repack.argv[0]);
@@ -641,6 +645,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (pack_garbage.nr > 0)
clean_pack_garbage();
+ if (gc_write_commit_graph)
+ write_commit_graph_reachable(get_object_directory(), 0);
+
if (auto_gc && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "
"run 'git prune' to remove them."));
diff --git a/builtin/grep.c b/builtin/grep.c
index ee753a403e..601f801158 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -489,7 +489,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,
}
if (repo_read_index(repo) < 0)
- die("index file corrupt");
+ die(_("index file corrupt"));
for (nr = 0; nr < repo->index->cache_nr; nr++) {
const struct cache_entry *ce = repo->index->cache[nr];
@@ -497,7 +497,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,
strbuf_addstr(&name, ce->name);
if (S_ISREG(ce->ce_mode) &&
- match_pathspec(pathspec, name.buf, name.len, 0, NULL,
+ match_pathspec(repo->index, pathspec, name.buf, name.len, 0, NULL,
S_ISDIR(ce->ce_mode) ||
S_ISGITLINK(ce->ce_mode))) {
/*
@@ -515,7 +515,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,
hit |= grep_file(opt, name.buf);
}
} else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
- submodule_path_match(pathspec, name.buf, NULL)) {
+ submodule_path_match(repo->index, pathspec, name.buf, NULL)) {
hit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name);
} else {
continue;
@@ -647,7 +647,8 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
for (i = 0; i < nr; i++) {
struct object *real_obj;
- real_obj = deref_tag(list->objects[i].item, NULL, 0);
+ real_obj = deref_tag(the_repository, list->objects[i].item,
+ NULL, 0);
/* load the gitmodules file for this rev */
if (recurse_submodules) {
@@ -678,7 +679,7 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
fill_directory(&dir, &the_index, pathspec);
for (i = 0; i < dir.nr; i++) {
- if (!dir_path_match(dir.entries[i], pathspec, 0, NULL))
+ if (!dir_path_match(&the_index, dir.entries[i], pathspec, 0, NULL))
continue;
hit |= grep_file(opt, dir.entries[i]->name);
if (hit && opt->status_only)
@@ -828,6 +829,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
GREP_PATTERN_TYPE_PCRE),
OPT_GROUP(""),
OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")),
+ OPT_BOOL(0, "column", &opt.columnnum, N_("show column number of first match")),
OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1),
OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1),
OPT_NEGBIT(0, "full-name", &opt.relative,
@@ -842,6 +844,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_BOOL_F('z', "null", &opt.null_following_name,
N_("print NUL after filenames"),
PARSE_OPT_NOCOMPLETE),
+ OPT_BOOL('o', "only-matching", &opt.only_matching,
+ N_("show only matching parts of a line")),
OPT_BOOL('c', "count", &opt.count,
N_("show the number of matches instead of matching lines")),
OPT__COLOR(&opt.color, N_("highlight matches")),
@@ -959,7 +963,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
}
if (!opt.pattern_list)
- die(_("no pattern given."));
+ die(_("no pattern given"));
+
+ /* --only-matching has no effect with --invert. */
+ if (opt.invert)
+ opt.only_matching = 0;
/*
* We have to find "--" in a separate pass, because its presence
@@ -1085,19 +1093,19 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
}
if (recurse_submodules && (!use_index || untracked))
- die(_("option not supported with --recurse-submodules."));
+ die(_("option not supported with --recurse-submodules"));
if (!show_in_pager && !opt.status_only)
setup_pager();
if (!use_index && (untracked || cached))
- die(_("--cached or --untracked cannot be used with --no-index."));
+ die(_("--cached or --untracked cannot be used with --no-index"));
if (!use_index || untracked) {
int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
hit = grep_directory(&opt, &pathspec, use_exclude, use_index);
} else if (0 <= opt_exclude) {
- die(_("--[no-]exclude-standard cannot be used for tracked contents."));
+ die(_("--[no-]exclude-standard cannot be used for tracked contents"));
} else if (!list.nr) {
if (!cached)
setup_work_tree();
@@ -1105,7 +1113,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
hit = grep_cache(&opt, the_repository, &pathspec, cached);
} else {
if (cached)
- die(_("both --cached and trees are given."));
+ die(_("both --cached and trees are given"));
hit = grep_objects(&opt, &pathspec, &list);
}
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index a9a3a198c3..9ada4f4dfd 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -6,6 +6,7 @@
*/
#include "builtin.h"
#include "config.h"
+#include "object-store.h"
#include "blob.h"
#include "quote.h"
#include "parse-options.h"
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 74fe2973e1..9582ead950 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -832,7 +832,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
if (strict || do_fsck_object) {
read_lock();
if (type == OBJ_BLOB) {
- struct blob *blob = lookup_blob(oid);
+ struct blob *blob = lookup_blob(the_repository, oid);
if (blob)
blob->object.flags |= FLAG_CHECKED;
else
@@ -851,7 +851,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
* we do not need to free the memory here, as the
* buf is deleted by the caller.
*/
- obj = parse_object_buffer(oid, type, size, buf,
+ obj = parse_object_buffer(the_repository, oid, type,
+ size, buf,
&eaten);
if (!obj)
die(_("invalid %s"), type_name(type));
@@ -1679,7 +1680,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(index_pack_usage);
- check_replace_refs = 0;
+ read_replace_refs = 0;
fsck_options.walk = mark_link;
reset_pack_idx_option(&opts);
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 4ecf909368..12ddda7e7b 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -73,7 +73,8 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
continue;
else if (S_ISLNK(st_template.st_mode)) {
struct strbuf lnk = STRBUF_INIT;
- if (strbuf_readlink(&lnk, template_path->buf, 0) < 0)
+ if (strbuf_readlink(&lnk, template_path->buf,
+ st_template.st_size) < 0)
die_errno(_("cannot readlink '%s'"), template_path->buf);
if (symlink(lnk.buf, path->buf))
die_errno(_("cannot symlink '%s' '%s'"),
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index b742539d4d..4b87e0dd2e 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -104,6 +104,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")),
{ OPTION_CALLBACK, 0, "parse", &opts, NULL, N_("set parsing options"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse },
+ OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat --- specially")),
OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
N_("trailer(s) to add"), option_parse_trailer),
OPT_END()
diff --git a/builtin/log.c b/builtin/log.c
index 0583f7f383..f09a5789f8 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -7,6 +7,7 @@
#include "cache.h"
#include "config.h"
#include "refs.h"
+#include "object-store.h"
#include "color.h"
#include "commit.h"
#include "diff.h"
@@ -29,6 +30,10 @@
#include "gpg-interface.h"
#include "progress.h"
#include "commit-slab.h"
+#include "repository.h"
+#include "commit-reach.h"
+#include "interdiff.h"
+#include "range-diff.h"
#define MAIL_DEFAULT_WRAP 72
@@ -618,7 +623,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
rev.shown_one = 1;
if (ret)
break;
- o = parse_object(&t->tagged->oid);
+ o = parse_object(the_repository, &t->tagged->oid);
if (!o)
ret = error(_("Could not read object %s"),
oid_to_hex(&t->tagged->oid));
@@ -905,8 +910,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
o2 = rev->pending.objects[1].item;
flags1 = o1->flags;
flags2 = o2->flags;
- c1 = lookup_commit_reference(&o1->oid);
- c2 = lookup_commit_reference(&o2->oid);
+ c1 = lookup_commit_reference(the_repository, &o1->oid);
+ c2 = lookup_commit_reference(the_repository, &o2->oid);
if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
die(_("Not a range."));
@@ -996,6 +1001,26 @@ static char *find_branch_name(struct rev_info *rev)
return branch;
}
+static void show_diffstat(struct rev_info *rev,
+ struct commit *origin, struct commit *head)
+{
+ struct diff_options opts;
+
+ memcpy(&opts, &rev->diffopt, sizeof(opts));
+ opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+ opts.stat_width = MAIL_DEFAULT_WRAP;
+
+ diff_setup_done(&opts);
+
+ diff_tree_oid(get_commit_tree_oid(origin),
+ get_commit_tree_oid(head),
+ "", &opts);
+ diffcore_std(&opts);
+ diff_flush(&opts);
+
+ fprintf(rev->diffopt.file, "\n");
+}
+
static void make_cover_letter(struct rev_info *rev, int use_stdout,
struct commit *origin,
int nr, struct commit **list,
@@ -1009,7 +1034,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
struct strbuf sb = STRBUF_INIT;
int i;
const char *encoding = "UTF-8";
- struct diff_options opts;
int need_8bit_cte = 0;
struct pretty_print_context pp = {0};
struct commit *head = list[0];
@@ -1059,25 +1083,20 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
shortlog_output(&log);
- /*
- * We can only do diffstat with a unique reference point
- */
- if (!origin)
- return;
-
- memcpy(&opts, &rev->diffopt, sizeof(opts));
- opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
- opts.stat_width = MAIL_DEFAULT_WRAP;
-
- diff_setup_done(&opts);
+ /* We can only do diffstat with a unique reference point */
+ if (origin)
+ show_diffstat(rev, origin, head);
- diff_tree_oid(get_commit_tree_oid(origin),
- get_commit_tree_oid(head),
- "", &opts);
- diffcore_std(&opts);
- diff_flush(&opts);
+ if (rev->idiff_oid1) {
+ fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title);
+ show_interdiff(rev, 0);
+ }
- fprintf(rev->diffopt.file, "\n");
+ if (rev->rdiff1) {
+ fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title);
+ show_range_diff(rev->rdiff1, rev->rdiff2,
+ rev->creation_factor, 1, &rev->diffopt);
+ }
}
static const char *clean_message_id(const char *msg_id)
@@ -1417,6 +1436,36 @@ static void print_bases(struct base_tree_info *bases, FILE *file)
oidclr(&bases->base_commit);
}
+static const char *diff_title(struct strbuf *sb, int reroll_count,
+ const char *generic, const char *rerolled)
+{
+ if (reroll_count <= 0)
+ strbuf_addstr(sb, generic);
+ else /* RFC may be v0, so allow -v1 to diff against v0 */
+ strbuf_addf(sb, rerolled, reroll_count - 1);
+ return sb->buf;
+}
+
+static void infer_range_diff_ranges(struct strbuf *r1,
+ struct strbuf *r2,
+ const char *prev,
+ struct commit *origin,
+ struct commit *head)
+{
+ const char *head_oid = oid_to_hex(&head->object.oid);
+
+ if (!strstr(prev, "..")) {
+ strbuf_addf(r1, "%s..%s", head_oid, prev);
+ strbuf_addf(r2, "%s..%s", prev, head_oid);
+ } else if (!origin) {
+ die(_("failed to infer range-diff ranges"));
+ } else {
+ strbuf_addstr(r1, prev);
+ strbuf_addf(r2, "%s..%s",
+ oid_to_hex(&origin->object.oid), head_oid);
+ }
+}
+
int cmd_format_patch(int argc, const char **argv, const char *prefix)
{
struct commit *commit;
@@ -1444,6 +1493,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct base_tree_info bases;
int show_progress = 0;
struct progress *progress = NULL;
+ struct oid_array idiff_prev = OID_ARRAY_INIT;
+ struct strbuf idiff_title = STRBUF_INIT;
+ const char *rdiff_prev = NULL;
+ struct strbuf rdiff1 = STRBUF_INIT;
+ struct strbuf rdiff2 = STRBUF_INIT;
+ struct strbuf rdiff_title = STRBUF_INIT;
+ int creation_factor = -1;
const struct option builtin_format_patch_options[] = {
{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
@@ -1517,6 +1573,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
OPT_BOOL(0, "progress", &show_progress,
N_("show progress while generating patches")),
+ OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"),
+ N_("show changes against <rev> in cover letter or single patch"),
+ parse_opt_object_name),
+ OPT_STRING(0, "range-diff", &rdiff_prev, N_("refspec"),
+ N_("show changes against <refspec> in cover letter or single patch")),
+ OPT_INTEGER(0, "creation-factor", &creation_factor,
+ N_("percentage by which creation is weighted")),
OPT_END()
};
@@ -1606,14 +1669,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
numbered = 0;
if (numbered && keep_subject)
- die (_("-n and -k are mutually exclusive."));
+ die(_("-n and -k are mutually exclusive"));
if (keep_subject && subject_prefix)
- die (_("--subject-prefix/--rfc and -k are mutually exclusive."));
+ die(_("--subject-prefix/--rfc and -k are mutually exclusive"));
rev.preserve_subject = keep_subject;
argc = setup_revisions(argc, argv, &rev, &s_r_opt);
if (argc > 1)
- die (_("unrecognized argument: %s"), argv[1]);
+ die(_("unrecognized argument: %s"), argv[1]);
if (rev.diffopt.output_format & DIFF_FORMAT_NAME)
die(_("--name-only does not make sense"));
@@ -1702,7 +1765,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (rev.pending.nr == 2) {
struct object_array_entry *o = rev.pending.objects;
if (oidcmp(&o[0].item->oid, &o[1].item->oid) == 0)
- return 0;
+ goto done;
}
get_patch_ids(&rev, &ids);
}
@@ -1726,7 +1789,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
if (nr == 0)
/* nothing to do */
- return 0;
+ goto done;
total = nr;
if (cover_letter == -1) {
if (config_cover_letter == COVER_AUTO)
@@ -1739,6 +1802,35 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (numbered)
rev.total = total + start_number - 1;
+ if (idiff_prev.nr) {
+ if (!cover_letter && total != 1)
+ die(_("--interdiff requires --cover-letter or single patch"));
+ rev.idiff_oid1 = &idiff_prev.oid[idiff_prev.nr - 1];
+ rev.idiff_oid2 = get_commit_tree_oid(list[0]);
+ rev.idiff_title = diff_title(&idiff_title, reroll_count,
+ _("Interdiff:"),
+ _("Interdiff against v%d:"));
+ }
+
+ if (creation_factor < 0)
+ creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
+ else if (!rdiff_prev)
+ die(_("--creation-factor requires --range-diff"));
+
+ if (rdiff_prev) {
+ if (!cover_letter && total != 1)
+ die(_("--range-diff requires --cover-letter or single patch"));
+
+ infer_range_diff_ranges(&rdiff1, &rdiff2, rdiff_prev,
+ origin, list[0]);
+ rev.rdiff1 = rdiff1.buf;
+ rev.rdiff2 = rdiff2.buf;
+ rev.creation_factor = creation_factor;
+ rev.rdiff_title = diff_title(&rdiff_title, reroll_count,
+ _("Range-diff:"),
+ _("Range-diff against v%d:"));
+ }
+
if (!signature) {
; /* --no-signature inhibits all signatures */
} else if (signature && signature != git_version_string) {
@@ -1755,6 +1847,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (base_commit || base_auto) {
struct commit *base = get_base_commit(base_commit, list, nr);
reset_revision_walk();
+ clear_object_flags(UNINTERESTING);
prepare_bases(&bases, base, list, nr);
}
@@ -1775,6 +1868,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
print_signature(rev.diffopt.file);
total++;
start_number--;
+ /* interdiff/range-diff in cover-letter; omit from patches */
+ rev.idiff_oid1 = NULL;
+ rev.rdiff1 = NULL;
}
rev.add_signoff = do_signoff;
@@ -1855,6 +1951,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
string_list_clear(&extra_hdr, 0);
if (ignore_if_in_upstream)
free_patch_ids(&ids);
+
+done:
+ oid_array_clear(&idiff_prev);
+ strbuf_release(&idiff_title);
+ strbuf_release(&rdiff1);
+ strbuf_release(&rdiff2);
+ strbuf_release(&rdiff_title);
return 0;
}
@@ -1862,7 +1965,8 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
{
struct object_id oid;
if (get_oid(arg, &oid) == 0) {
- struct commit *commit = lookup_commit_reference(&oid);
+ struct commit *commit = lookup_commit_reference(the_repository,
+ &oid);
if (commit) {
commit->object.flags |= flags;
add_pending_object(revs, &commit->object, arg);
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 88bb2019ad..7f9919a362 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -63,7 +63,7 @@ static void write_eolinfo(const struct index_state *istate,
struct stat st;
const char *i_txt = "";
const char *w_txt = "";
- const char *a_txt = get_convert_attr_ascii(path);
+ const char *a_txt = get_convert_attr_ascii(istate, path);
if (ce && S_ISREG(ce->ce_mode))
i_txt = get_cached_convert_stats_ascii(istate,
ce->name);
@@ -121,18 +121,19 @@ static void print_debug(const struct cache_entry *ce)
}
}
-static void show_dir_entry(const char *tag, struct dir_entry *ent)
+static void show_dir_entry(const struct index_state *istate,
+ const char *tag, struct dir_entry *ent)
{
int len = max_prefix_len;
if (len > ent->len)
die("git ls-files: internal error - directory entry not superset of prefix");
- if (!dir_path_match(ent, &pathspec, len, ps_matched))
+ if (!dir_path_match(istate, ent, &pathspec, len, ps_matched))
return;
fputs(tag, stdout);
- write_eolinfo(NULL, NULL, ent->name);
+ write_eolinfo(istate, NULL, ent->name);
write_name(ent->name);
}
@@ -145,7 +146,7 @@ static void show_other_files(const struct index_state *istate,
struct dir_entry *ent = dir->entries[i];
if (!index_name_is_other(istate, ent->name, ent->len))
continue;
- show_dir_entry(tag_other, ent);
+ show_dir_entry(istate, tag_other, ent);
}
}
@@ -196,7 +197,7 @@ static void show_killed_files(const struct index_state *istate,
}
}
if (killed)
- show_dir_entry(tag_killed, dir->entries[i]);
+ show_dir_entry(istate, tag_killed, dir->entries[i]);
}
}
@@ -228,7 +229,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,
if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
is_submodule_active(repo, ce->name)) {
show_submodule(repo, dir, ce->name);
- } else if (match_pathspec(&pathspec, fullname, strlen(fullname),
+ } else if (match_pathspec(repo->index, &pathspec, fullname, strlen(fullname),
max_prefix_len, ps_matched,
S_ISDIR(ce->ce_mode) ||
S_ISGITLINK(ce->ce_mode))) {
@@ -264,7 +265,7 @@ static void show_ru_info(const struct index_state *istate)
len = strlen(path);
if (len < max_prefix_len)
continue; /* outside of the prefix */
- if (!match_pathspec(&pathspec, path, len,
+ if (!match_pathspec(istate, &pathspec, path, len,
max_prefix_len, ps_matched, 0))
continue; /* uninterested */
for (i = 0; i < 3; i++) {
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 409da4e835..fe3b952cb3 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -5,6 +5,7 @@
*/
#include "cache.h"
#include "config.h"
+#include "object-store.h"
#include "blob.h"
#include "tree.h"
#include "commit.h"
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 3b7600150b..1c92099070 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -6,6 +6,8 @@
#include "diff.h"
#include "revision.h"
#include "parse-options.h"
+#include "repository.h"
+#include "commit-reach.h"
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
@@ -42,7 +44,7 @@ static struct commit *get_commit_reference(const char *arg)
if (get_oid(arg, &revkey))
die("Not a valid object name %s", arg);
- r = lookup_commit_reference(&revkey);
+ r = lookup_commit_reference(the_repository, &revkey);
if (!r)
die("Not a valid commit name %s", arg);
@@ -123,7 +125,7 @@ static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
if (is_null_oid(oid))
return;
- commit = lookup_commit(oid);
+ commit = lookup_commit(the_repository, oid);
if (!commit ||
(commit->object.flags & TMP_MARK) ||
parse_commit(commit))
@@ -171,7 +173,7 @@ static int handle_fork_point(int argc, const char **argv)
if (get_oid(commitname, &oid))
die("Not a valid object name: '%s'", commitname);
- derived = lookup_commit_reference(&oid);
+ derived = lookup_commit_reference(the_repository, &oid);
memset(&revs, 0, sizeof(revs));
revs.initial = 1;
for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 0dd9021958..9b2f707c29 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -9,10 +9,10 @@ static const char builtin_merge_recursive_usage[] =
static const char *better_branch_name(const char *branch)
{
- static char githead_env[8 + GIT_SHA1_HEXSZ + 1];
+ static char githead_env[8 + GIT_MAX_HEXSZ + 1];
char *name;
- if (strlen(branch) != GIT_SHA1_HEXSZ)
+ if (strlen(branch) != the_hash_algo->hexsz)
return branch;
xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch);
name = getenv(githead_env);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index bf01e05808..f8023bae1e 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -1,6 +1,8 @@
#include "builtin.h"
#include "tree-walk.h"
#include "xdiff-interface.h"
+#include "object-store.h"
+#include "repository.h"
#include "blob.h"
#include "exec-cmd.h"
#include "merge-blobs.h"
@@ -169,7 +171,7 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const stru
res->stage = stage;
res->path = path;
res->mode = mode;
- res->blob = lookup_blob(oid);
+ res->blob = lookup_blob(the_repository, oid);
return res;
}
diff --git a/builtin/merge.c b/builtin/merge.c
index 4a4c09496c..7a8e3e274f 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -36,6 +36,7 @@
#include "packfile.h"
#include "tag.h"
#include "alias.h"
+#include "commit-reach.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
@@ -111,6 +112,35 @@ static int option_parse_message(const struct option *opt,
return 0;
}
+static int option_read_message(struct parse_opt_ctx_t *ctx,
+ const struct option *opt, int unset)
+{
+ struct strbuf *buf = opt->value;
+ const char *arg;
+
+ if (unset)
+ BUG("-F cannot be negated");
+
+ if (ctx->opt) {
+ arg = ctx->opt;
+ ctx->opt = NULL;
+ } else if (ctx->argc > 1) {
+ ctx->argc--;
+ arg = *++ctx->argv;
+ } else
+ return opterror(opt, "requires a value", 0);
+
+ if (buf->len)
+ strbuf_addch(buf, '\n');
+ if (ctx->prefix && !is_absolute_path(arg))
+ arg = prefix_filename(ctx->prefix, arg);
+ if (strbuf_read_file(buf, arg, 0) < 0)
+ return error(_("could not read file '%s'"), arg);
+ have_message = 1;
+
+ return 0;
+}
+
static struct strategy *get_strategy(const char *name)
{
int i;
@@ -228,6 +258,9 @@ static struct option builtin_merge_options[] = {
OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
+ { OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
+ N_("read message from file"), PARSE_OPT_NONEG,
+ (parse_opt_cb *) option_read_message },
OPT__VERBOSITY(&verbosity),
OPT_BOOL(0, "abort", &abort_current_merge,
N_("abort the current in-progress merge")),
@@ -247,9 +280,9 @@ static struct option builtin_merge_options[] = {
/* Cleans up metadata that is uninteresting after a succeeded merge. */
static void drop_save(void)
{
- unlink(git_path_merge_head());
- unlink(git_path_merge_msg());
- unlink(git_path_merge_mode());
+ unlink(git_path_merge_head(the_repository));
+ unlink(git_path_merge_msg(the_repository));
+ unlink(git_path_merge_mode(the_repository));
}
static int save_state(struct object_id *stash)
@@ -382,7 +415,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead
oid_to_hex(&commit->object.oid));
pretty_print_commit(&ctx, commit, &out);
}
- write_file_buf(git_path_squash_msg(), out.buf, out.len);
+ write_file_buf(git_path_squash_msg(the_repository), out.buf, out.len);
strbuf_release(&out);
}
@@ -693,7 +726,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
exit(128);
if (write_locked_index(&the_index, &lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
- die (_("unable to write %s"), get_index_file());
+ die(_("unable to write %s"), get_index_file());
return clean ? 0 : 1;
} else {
return try_merge_command(strategy, xopts_nr, xopts,
@@ -741,7 +774,7 @@ static void add_strategies(const char *string, unsigned attr)
static void read_merge_msg(struct strbuf *msg)
{
- const char *filename = git_path_merge_msg();
+ const char *filename = git_path_merge_msg(the_repository);
strbuf_reset(msg);
if (strbuf_read_file(msg, filename, 0) < 0)
die_errno(_("Could not read from '%s'"), filename);
@@ -778,18 +811,18 @@ static void prepare_to_commit(struct commit_list *remoteheads)
if (signoff)
append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
write_merge_heads(remoteheads);
- write_file_buf(git_path_merge_msg(), msg.buf, msg.len);
+ write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
- git_path_merge_msg(), "merge", NULL))
+ git_path_merge_msg(the_repository), "merge", NULL))
abort_commit(remoteheads, NULL);
if (0 < option_edit) {
- if (launch_editor(git_path_merge_msg(), NULL, NULL))
+ if (launch_editor(git_path_merge_msg(the_repository), NULL, NULL))
abort_commit(remoteheads, NULL);
}
if (verify_msg && run_commit_hook(0 < option_edit, get_index_file(),
"commit-msg",
- git_path_merge_msg(), NULL))
+ git_path_merge_msg(the_repository), NULL))
abort_commit(remoteheads, NULL);
read_merge_msg(&msg);
@@ -859,7 +892,7 @@ static int suggest_conflicts(void)
FILE *fp;
struct strbuf msgbuf = STRBUF_INIT;
- filename = git_path_merge_msg();
+ filename = git_path_merge_msg(the_repository);
fp = xfopen(filename, "a");
append_conflicts_hint(&msgbuf);
@@ -942,12 +975,12 @@ static void write_merge_heads(struct commit_list *remoteheads)
}
strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
}
- write_file_buf(git_path_merge_head(), buf.buf, buf.len);
+ write_file_buf(git_path_merge_head(the_repository), buf.buf, buf.len);
strbuf_reset(&buf);
if (fast_forward == FF_NO)
strbuf_addstr(&buf, "no-ff");
- write_file_buf(git_path_merge_mode(), buf.buf, buf.len);
+ write_file_buf(git_path_merge_mode(the_repository), buf.buf, buf.len);
strbuf_release(&buf);
}
@@ -955,7 +988,8 @@ static void write_merge_state(struct commit_list *remoteheads)
{
write_merge_heads(remoteheads);
strbuf_addch(&merge_msg, '\n');
- write_file_buf(git_path_merge_msg(), merge_msg.buf, merge_msg.len);
+ write_file_buf(git_path_merge_msg(the_repository), merge_msg.buf,
+ merge_msg.len);
}
static int default_edit_option(void)
@@ -1034,11 +1068,12 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
const char *filename;
int fd, pos, npos;
struct strbuf fetch_head_file = STRBUF_INIT;
+ const unsigned hexsz = the_hash_algo->hexsz;
if (!merge_names)
merge_names = &fetch_head_file;
- filename = git_path_fetch_head();
+ filename = git_path_fetch_head(the_repository);
fd = open(filename, O_RDONLY);
if (fd < 0)
die_errno(_("could not open '%s' for reading"), filename);
@@ -1059,16 +1094,16 @@ static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge
else
npos = merge_names->len;
- if (npos - pos < GIT_SHA1_HEXSZ + 2 ||
+ if (npos - pos < hexsz + 2 ||
get_oid_hex(merge_names->buf + pos, &oid))
commit = NULL; /* bad */
- else if (memcmp(merge_names->buf + pos + GIT_SHA1_HEXSZ, "\t\t", 2))
+ else if (memcmp(merge_names->buf + pos + hexsz, "\t\t", 2))
continue; /* not-for-merge */
else {
- char saved = merge_names->buf[pos + GIT_SHA1_HEXSZ];
- merge_names->buf[pos + GIT_SHA1_HEXSZ] = '\0';
+ char saved = merge_names->buf[pos + hexsz];
+ merge_names->buf[pos + hexsz] = '\0';
commit = get_merge_parent(merge_names->buf + pos);
- merge_names->buf[pos + GIT_SHA1_HEXSZ] = saved;
+ merge_names->buf[pos + hexsz] = saved;
}
if (!commit) {
if (ptr)
@@ -1213,7 +1248,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
usage_msg_opt(_("--abort expects no arguments"),
builtin_merge_usage, builtin_merge_options);
- if (!file_exists(git_path_merge_head()))
+ if (!file_exists(git_path_merge_head(the_repository)))
die(_("There is no merge to abort (MERGE_HEAD missing)."));
/* Invoke 'git reset --merge' */
@@ -1229,7 +1264,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
usage_msg_opt(_("--continue expects no arguments"),
builtin_merge_usage, builtin_merge_options);
- if (!file_exists(git_path_merge_head()))
+ if (!file_exists(git_path_merge_head(the_repository)))
die(_("There is no merge in progress (MERGE_HEAD missing)."));
/* Invoke 'git commit' */
@@ -1240,7 +1275,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (read_cache_unmerged())
die_resolve_conflict("merge");
- if (file_exists(git_path_merge_head())) {
+ if (file_exists(git_path_merge_head(the_repository))) {
/*
* There is no unmerged entry, don't advise 'git
* add/rm <file>', just 'git commit'.
@@ -1251,7 +1286,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
else
die(_("You have not concluded your merge (MERGE_HEAD exists)."));
}
- if (file_exists(git_path_cherry_pick_head())) {
+ if (file_exists(git_path_cherry_pick_head(the_repository))) {
if (advice_resolve_conflict)
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you merge."));
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 82a6e86077..6fb7dc8578 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "tag.h"
#include "replace-object.h"
+#include "object-store.h"
/*
* A signature file has a very simple fixed format: four lines
diff --git a/builtin/mktree.c b/builtin/mktree.c
index bb76b469fd..2dc4ad6ba8 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -7,6 +7,7 @@
#include "quote.h"
#include "tree.h"
#include "parse-options.h"
+#include "object-store.h"
static struct treeent {
unsigned mode;
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
new file mode 100644
index 0000000000..2633efd95d
--- /dev/null
+++ b/builtin/multi-pack-index.c
@@ -0,0 +1,47 @@
+#include "builtin.h"
+#include "cache.h"
+#include "config.h"
+#include "parse-options.h"
+#include "midx.h"
+
+static char const * const builtin_multi_pack_index_usage[] = {
+ N_("git multi-pack-index [--object-dir=<dir>] write"),
+ NULL
+};
+
+static struct opts_multi_pack_index {
+ const char *object_dir;
+} opts;
+
+int cmd_multi_pack_index(int argc, const char **argv,
+ const char *prefix)
+{
+ static struct option builtin_multi_pack_index_options[] = {
+ OPT_FILENAME(0, "object-dir", &opts.object_dir,
+ N_("object directory containing set of packfile and pack-index pairs")),
+ OPT_END(),
+ };
+
+ git_config(git_default_config, NULL);
+
+ argc = parse_options(argc, argv, prefix,
+ builtin_multi_pack_index_options,
+ builtin_multi_pack_index_usage, 0);
+
+ if (!opts.object_dir)
+ opts.object_dir = get_object_directory();
+
+ if (argc == 0)
+ usage_with_options(builtin_multi_pack_index_usage,
+ builtin_multi_pack_index_options);
+
+ if (argc > 1) {
+ die(_("too many arguments"));
+ return 1;
+ }
+
+ if (!strcmp(argv[0], "write"))
+ return write_midx_file(opts.object_dir);
+
+ die(_("unrecognized verb: %s"), argv[0]);
+}
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 0eb440359d..f1cb45c227 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "cache.h"
+#include "repository.h"
#include "config.h"
#include "commit.h"
#include "tag.h"
@@ -203,7 +204,7 @@ static int tipcmp(const void *a_, const void *b_)
static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data)
{
- struct object *o = parse_object(oid);
+ struct object *o = parse_object(the_repository, oid);
struct name_ref_data *data = cb_data;
int can_abbreviate_output = data->tags_only && data->name_only;
int deref = 0;
@@ -261,7 +262,7 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
struct tag *t = (struct tag *) o;
if (!t->tagged)
break; /* broken repository */
- o = parse_object(&t->tagged->oid);
+ o = parse_object(the_repository, &t->tagged->oid);
deref = 1;
taggerdate = t->date;
}
@@ -378,7 +379,8 @@ static void name_rev_line(char *p, struct name_ref_data *data)
*(p+1) = 0;
if (!get_oid(p - (GIT_SHA1_HEXSZ - 1), &oid)) {
struct object *o =
- lookup_object(oid.hash);
+ lookup_object(the_repository,
+ oid.hash);
if (o)
name = get_rev_name(o, &buf);
}
@@ -451,9 +453,10 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
}
commit = NULL;
- object = parse_object(&oid);
+ object = parse_object(the_repository, &oid);
if (object) {
- struct object *peeled = deref_tag(object, *argv, 0);
+ struct object *peeled = deref_tag(the_repository,
+ object, *argv, 0);
if (peeled && peeled->type == OBJ_COMMIT)
commit = (struct commit *)peeled;
}
diff --git a/builtin/notes.c b/builtin/notes.c
index 6981e2d906..c05cd004ab 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -11,6 +11,8 @@
#include "config.h"
#include "builtin.h"
#include "notes.h"
+#include "object-store.h"
+#include "repository.h"
#include "blob.h"
#include "pretty.h"
#include "refs.h"
@@ -710,7 +712,7 @@ static int merge_commit(struct notes_merge_options *o)
if (get_oid("NOTES_MERGE_PARTIAL", &oid))
die(_("failed to read ref NOTES_MERGE_PARTIAL"));
- else if (!(partial = lookup_commit_reference(&oid)))
+ else if (!(partial = lookup_commit_reference(the_repository, &oid)))
die(_("could not find commit from NOTES_MERGE_PARTIAL."));
else if (parse_commit(partial))
die(_("could not parse commit from NOTES_MERGE_PARTIAL."));
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 71056d8294..425bdc8ac5 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -24,6 +24,7 @@
#include "streaming.h"
#include "thread-utils.h"
#include "pack-bitmap.h"
+#include "delta-islands.h"
#include "reachable.h"
#include "sha1-array.h"
#include "argv-array.h"
@@ -31,6 +32,7 @@
#include "packfile.h"
#include "object-store.h"
#include "dir.h"
+#include "midx.h"
#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
#define SIZE(obj) oe_size(&to_pack, obj)
@@ -40,6 +42,7 @@
#define DELTA_CHILD(obj) oe_delta_child(&to_pack, obj)
#define DELTA_SIBLING(obj) oe_delta_sibling(&to_pack, obj)
#define SET_DELTA(obj, val) oe_set_delta(&to_pack, obj, val)
+#define SET_DELTA_EXT(obj, oid) oe_set_delta_ext(&to_pack, obj, oid)
#define SET_DELTA_SIZE(obj, val) oe_set_delta_size(&to_pack, obj, val)
#define SET_DELTA_CHILD(obj, val) oe_set_delta_child(&to_pack, obj, val)
#define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val)
@@ -59,6 +62,8 @@ static struct packing_data to_pack;
static struct pack_idx_entry **written_list;
static uint32_t nr_result, nr_written, nr_seen;
+static struct bitmap_index *bitmap_git;
+static uint32_t write_layer;
static int non_empty;
static int reuse_delta = 1, reuse_object = 1;
@@ -79,6 +84,7 @@ static unsigned long pack_size_limit;
static int depth = 50;
static int delta_search_threads;
static int pack_to_stdout;
+static int thin;
static int num_preferred_base;
static struct progress *progress_state;
@@ -93,6 +99,8 @@ static uint16_t write_bitmap_options;
static int exclude_promisor_objects;
+static int use_delta_islands;
+
static unsigned long delta_cache_size = 0;
static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
static unsigned long cache_max_small_delta_size = 1000;
@@ -140,7 +148,7 @@ static void *get_delta(struct object_entry *entry)
buf = read_object_file(&entry->idx.oid, &type, &size);
if (!buf)
- die("unable to read %s", oid_to_hex(&entry->idx.oid));
+ die(_("unable to read %s"), oid_to_hex(&entry->idx.oid));
base_buf = read_object_file(&DELTA(entry)->idx.oid, &type,
&base_size);
if (!base_buf)
@@ -148,8 +156,13 @@ static void *get_delta(struct object_entry *entry)
oid_to_hex(&DELTA(entry)->idx.oid));
delta_buf = diff_delta(base_buf, base_size,
buf, size, &delta_size, 0);
+ /*
+ * We succesfully computed this delta once but dropped it for
+ * memory reasons. Something is very wrong if this time we
+ * recompute and create a different delta.
+ */
if (!delta_buf || delta_size != DELTA_SIZE(entry))
- die("delta size changed");
+ BUG("delta size changed");
free(buf);
free(base_buf);
return delta_buf;
@@ -406,7 +419,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
datalen = revidx[1].offset - offset;
if (!pack_to_stdout && p->index_version > 1 &&
check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
- error("bad packed object CRC for %s",
+ error(_("bad packed object CRC for %s"),
oid_to_hex(&entry->idx.oid));
unuse_pack(&w_curs);
return write_no_reuse_object(f, entry, limit, usable_delta);
@@ -417,7 +430,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
if (!pack_to_stdout && p->index_version == 1 &&
check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) {
- error("corrupt packed object for %s",
+ error(_("corrupt packed object for %s"),
oid_to_hex(&entry->idx.oid));
unuse_pack(&w_curs);
return write_no_reuse_object(f, entry, limit, usable_delta);
@@ -548,7 +561,7 @@ static enum write_one_status write_one(struct hashfile *f,
*/
recursing = (e->idx.offset == 1);
if (recursing) {
- warning("recursive delta detected for object %s",
+ warning(_("recursive delta detected for object %s"),
oid_to_hex(&e->idx.oid));
return WRITE_ONE_RECURSIVE;
} else if (e->idx.offset || e->preferred_base) {
@@ -582,7 +595,7 @@ static enum write_one_status write_one(struct hashfile *f,
/* make sure off_t is sufficiently large not to wrap */
if (signed_add_overflows(*offset, size))
- die("pack too large for current definition of off_t");
+ die(_("pack too large for current definition of off_t"));
*offset += size;
return WRITE_ONE_WRITTEN;
}
@@ -607,7 +620,7 @@ static inline void add_to_write_order(struct object_entry **wo,
unsigned int *endp,
struct object_entry *e)
{
- if (e->filled)
+ if (e->filled || oe_layer(&to_pack, e) != write_layer)
return;
wo[(*endp)++] = e;
e->filled = 1;
@@ -667,48 +680,15 @@ static void add_family_to_write_order(struct object_entry **wo,
add_descendants_to_write_order(wo, endp, root);
}
-static struct object_entry **compute_write_order(void)
+static void compute_layer_order(struct object_entry **wo, unsigned int *wo_end)
{
- unsigned int i, wo_end, last_untagged;
-
- struct object_entry **wo;
+ unsigned int i, last_untagged;
struct object_entry *objects = to_pack.objects;
for (i = 0; i < to_pack.nr_objects; i++) {
- objects[i].tagged = 0;
- objects[i].filled = 0;
- SET_DELTA_CHILD(&objects[i], NULL);
- SET_DELTA_SIBLING(&objects[i], NULL);
- }
-
- /*
- * Fully connect delta_child/delta_sibling network.
- * Make sure delta_sibling is sorted in the original
- * recency order.
- */
- for (i = to_pack.nr_objects; i > 0;) {
- struct object_entry *e = &objects[--i];
- if (!DELTA(e))
- continue;
- /* Mark me as the first child */
- e->delta_sibling_idx = DELTA(e)->delta_child_idx;
- SET_DELTA_CHILD(DELTA(e), e);
- }
-
- /*
- * Mark objects that are at the tip of tags.
- */
- for_each_tag_ref(mark_tagged, NULL);
-
- /*
- * Give the objects in the original recency order until
- * we see a tagged tip.
- */
- ALLOC_ARRAY(wo, to_pack.nr_objects);
- for (i = wo_end = 0; i < to_pack.nr_objects; i++) {
if (objects[i].tagged)
break;
- add_to_write_order(wo, &wo_end, &objects[i]);
+ add_to_write_order(wo, wo_end, &objects[i]);
}
last_untagged = i;
@@ -717,7 +697,7 @@ static struct object_entry **compute_write_order(void)
*/
for (; i < to_pack.nr_objects; i++) {
if (objects[i].tagged)
- add_to_write_order(wo, &wo_end, &objects[i]);
+ add_to_write_order(wo, wo_end, &objects[i]);
}
/*
@@ -727,7 +707,7 @@ static struct object_entry **compute_write_order(void)
if (oe_type(&objects[i]) != OBJ_COMMIT &&
oe_type(&objects[i]) != OBJ_TAG)
continue;
- add_to_write_order(wo, &wo_end, &objects[i]);
+ add_to_write_order(wo, wo_end, &objects[i]);
}
/*
@@ -736,19 +716,64 @@ static struct object_entry **compute_write_order(void)
for (i = last_untagged; i < to_pack.nr_objects; i++) {
if (oe_type(&objects[i]) != OBJ_TREE)
continue;
- add_to_write_order(wo, &wo_end, &objects[i]);
+ add_to_write_order(wo, wo_end, &objects[i]);
}
/*
* Finally all the rest in really tight order
*/
for (i = last_untagged; i < to_pack.nr_objects; i++) {
- if (!objects[i].filled)
- add_family_to_write_order(wo, &wo_end, &objects[i]);
+ if (!objects[i].filled && oe_layer(&to_pack, &objects[i]) == write_layer)
+ add_family_to_write_order(wo, wo_end, &objects[i]);
+ }
+}
+
+static struct object_entry **compute_write_order(void)
+{
+ uint32_t max_layers = 1;
+ unsigned int i, wo_end;
+
+ struct object_entry **wo;
+ struct object_entry *objects = to_pack.objects;
+
+ for (i = 0; i < to_pack.nr_objects; i++) {
+ objects[i].tagged = 0;
+ objects[i].filled = 0;
+ SET_DELTA_CHILD(&objects[i], NULL);
+ SET_DELTA_SIBLING(&objects[i], NULL);
+ }
+
+ /*
+ * Fully connect delta_child/delta_sibling network.
+ * Make sure delta_sibling is sorted in the original
+ * recency order.
+ */
+ for (i = to_pack.nr_objects; i > 0;) {
+ struct object_entry *e = &objects[--i];
+ if (!DELTA(e))
+ continue;
+ /* Mark me as the first child */
+ e->delta_sibling_idx = DELTA(e)->delta_child_idx;
+ SET_DELTA_CHILD(DELTA(e), e);
}
+ /*
+ * Mark objects that are at the tip of tags.
+ */
+ for_each_tag_ref(mark_tagged, NULL);
+
+ if (use_delta_islands)
+ max_layers = compute_pack_layers(&to_pack);
+
+ ALLOC_ARRAY(wo, to_pack.nr_objects);
+ wo_end = 0;
+
+ for (; write_layer < max_layers; ++write_layer)
+ compute_layer_order(wo, &wo_end);
+
if (wo_end != to_pack.nr_objects)
- die("ordered %u objects, expected %"PRIu32, wo_end, to_pack.nr_objects);
+ die(_("ordered %u objects, expected %"PRIu32),
+ wo_end, to_pack.nr_objects);
return wo;
}
@@ -760,15 +785,15 @@ static off_t write_reused_pack(struct hashfile *f)
int fd;
if (!is_pack_valid(reuse_packfile))
- die("packfile is invalid: %s", reuse_packfile->pack_name);
+ die(_("packfile is invalid: %s"), reuse_packfile->pack_name);
fd = git_open(reuse_packfile->pack_name);
if (fd < 0)
- die_errno("unable to open packfile for reuse: %s",
+ die_errno(_("unable to open packfile for reuse: %s"),
reuse_packfile->pack_name);
if (lseek(fd, sizeof(struct pack_header), SEEK_SET) == -1)
- die_errno("unable to seek in reused packfile");
+ die_errno(_("unable to seek in reused packfile"));
if (reuse_packfile_offset < 0)
reuse_packfile_offset = reuse_packfile->pack_size - the_hash_algo->rawsz;
@@ -779,7 +804,7 @@ static off_t write_reused_pack(struct hashfile *f)
int read_pack = xread(fd, buffer, sizeof(buffer));
if (read_pack <= 0)
- die_errno("unable to read from reused packfile");
+ die_errno(_("unable to read from reused packfile"));
if (read_pack > to_write)
read_pack = to_write;
@@ -882,7 +907,7 @@ static void write_pack_file(void)
* to preserve this property.
*/
if (stat(pack_tmp_name, &st) < 0) {
- warning_errno("failed to stat %s", pack_tmp_name);
+ warning_errno(_("failed to stat %s"), pack_tmp_name);
} else if (!last_mtime) {
last_mtime = st.st_mtime;
} else {
@@ -890,7 +915,7 @@ static void write_pack_file(void)
utb.actime = st.st_atime;
utb.modtime = --last_mtime;
if (utime(pack_tmp_name, &utb) < 0)
- warning_errno("failed utime() on %s", pack_tmp_name);
+ warning_errno(_("failed utime() on %s"), pack_tmp_name);
}
strbuf_addf(&tmpname, "%s-", base_name);
@@ -935,8 +960,8 @@ static void write_pack_file(void)
free(write_order);
stop_progress(&progress_state);
if (written != nr_result)
- die("wrote %"PRIu32" objects while expecting %"PRIu32,
- written, nr_result);
+ die(_("wrote %"PRIu32" objects while expecting %"PRIu32),
+ written, nr_result);
}
static int no_try_delta(const char *path)
@@ -945,7 +970,7 @@ static int no_try_delta(const char *path)
if (!check)
check = attr_check_initl("delta", NULL);
- if (git_check_attr(path, check))
+ if (git_check_attr(&the_index, path, check))
return 0;
if (ATTR_FALSE(check->items[0].value))
return 1;
@@ -1034,6 +1059,7 @@ static int want_object_in_pack(const struct object_id *oid,
{
int want;
struct list_head *pos;
+ struct multi_pack_index *m;
if (!exclude && local && has_loose_object_nonlocal(oid))
return 0;
@@ -1048,6 +1074,32 @@ static int want_object_in_pack(const struct object_id *oid,
if (want != -1)
return want;
}
+
+ for (m = get_multi_pack_index(the_repository); m; m = m->next) {
+ struct pack_entry e;
+ if (fill_midx_entry(oid, &e, m)) {
+ struct packed_git *p = e.p;
+ off_t offset;
+
+ if (p == *found_pack)
+ offset = *found_offset;
+ else
+ offset = find_pack_entry_one(oid->hash, p);
+
+ if (offset) {
+ if (!*found_pack) {
+ if (!is_pack_valid(p))
+ continue;
+ *found_offset = offset;
+ *found_pack = p;
+ }
+ want = want_found_object(exclude, p);
+ if (want != -1)
+ return want;
+ }
+ }
+ }
+
list_for_each(pos, get_packed_git_mru(the_repository)) {
struct packed_git *p = list_entry(pos, struct packed_git, mru);
off_t offset;
@@ -1480,7 +1532,7 @@ static void check_object(struct object_entry *entry)
while (c & 128) {
ofs += 1;
if (!ofs || MSB(ofs, 7)) {
- error("delta base offset overflow in pack for %s",
+ error(_("delta base offset overflow in pack for %s"),
oid_to_hex(&entry->idx.oid));
goto give_up;
}
@@ -1489,7 +1541,7 @@ static void check_object(struct object_entry *entry)
}
ofs = entry->in_pack_offset - ofs;
if (ofs <= 0 || ofs >= entry->in_pack_offset) {
- error("delta base offset out of bound for %s",
+ error(_("delta base offset out of bound for %s"),
oid_to_hex(&entry->idx.oid));
goto give_up;
}
@@ -1504,11 +1556,16 @@ static void check_object(struct object_entry *entry)
break;
}
- if (base_ref && (base_entry = packlist_find(&to_pack, base_ref, NULL))) {
+ if (base_ref && (
+ (base_entry = packlist_find(&to_pack, base_ref, NULL)) ||
+ (thin &&
+ bitmap_has_sha1_in_uninteresting(bitmap_git, base_ref))) &&
+ in_same_island(&entry->idx.oid, &base_entry->idx.oid)) {
/*
* If base_ref was set above that means we wish to
- * reuse delta data, and we even found that base
- * in the list of objects we want to pack. Goodie!
+ * reuse delta data, and either we found that object in
+ * the list of objects we want to pack, or it's one we
+ * know the receiver has.
*
* Depth value does not matter - find_deltas() will
* never consider reused delta as the base object to
@@ -1517,10 +1574,16 @@ static void check_object(struct object_entry *entry)
*/
oe_set_type(entry, entry->in_pack_type);
SET_SIZE(entry, in_pack_size); /* delta size */
- SET_DELTA(entry, base_entry);
SET_DELTA_SIZE(entry, in_pack_size);
- entry->delta_sibling_idx = base_entry->delta_child_idx;
- SET_DELTA_CHILD(base_entry, entry);
+
+ if (base_entry) {
+ SET_DELTA(entry, base_entry);
+ entry->delta_sibling_idx = base_entry->delta_child_idx;
+ SET_DELTA_CHILD(base_entry, entry);
+ } else {
+ SET_DELTA_EXT(entry, base_ref);
+ }
+
unuse_pack(&w_curs);
return;
}
@@ -1820,6 +1883,11 @@ static int type_size_sort(const void *_a, const void *_b)
return -1;
if (a->preferred_base < b->preferred_base)
return 1;
+ if (use_delta_islands) {
+ int island_cmp = island_delta_cmp(&a->idx.oid, &b->idx.oid);
+ if (island_cmp)
+ return island_cmp;
+ }
if (a_size > b_size)
return -1;
if (a_size < b_size)
@@ -1852,18 +1920,30 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
#ifndef NO_PTHREADS
+/* Protect access to object database */
static pthread_mutex_t read_mutex;
#define read_lock() pthread_mutex_lock(&read_mutex)
#define read_unlock() pthread_mutex_unlock(&read_mutex)
+/* Protect delta_cache_size */
static pthread_mutex_t cache_mutex;
#define cache_lock() pthread_mutex_lock(&cache_mutex)
#define cache_unlock() pthread_mutex_unlock(&cache_mutex)
+/*
+ * Protect object list partitioning (e.g. struct thread_param) and
+ * progress_state
+ */
static pthread_mutex_t progress_mutex;
#define progress_lock() pthread_mutex_lock(&progress_mutex)
#define progress_unlock() pthread_mutex_unlock(&progress_mutex)
+/*
+ * Access to struct object_entry is unprotected since each thread owns
+ * a portion of the main object list. Just don't access object entries
+ * ahead in the list because they can be stolen and would need
+ * progress_mutex for protection.
+ */
#else
#define read_lock() (void)0
@@ -1968,16 +2048,19 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
if (trg_size < src_size / 32)
return 0;
+ if (!in_same_island(&trg->entry->idx.oid, &src->entry->idx.oid))
+ return 0;
+
/* Load data if not already done */
if (!trg->data) {
read_lock();
trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz);
read_unlock();
if (!trg->data)
- die("object %s cannot be read",
+ die(_("object %s cannot be read"),
oid_to_hex(&trg_entry->idx.oid));
if (sz != trg_size)
- die("object %s inconsistent object length (%lu vs %lu)",
+ die(_("object %s inconsistent object length (%lu vs %lu)"),
oid_to_hex(&trg_entry->idx.oid), sz,
trg_size);
*mem_usage += sz;
@@ -1990,7 +2073,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
if (src_entry->preferred_base) {
static int warned = 0;
if (!warned++)
- warning("object %s cannot be read",
+ warning(_("object %s cannot be read"),
oid_to_hex(&src_entry->idx.oid));
/*
* Those objects are not included in the
@@ -2000,11 +2083,11 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
*/
return 0;
}
- die("object %s cannot be read",
+ die(_("object %s cannot be read"),
oid_to_hex(&src_entry->idx.oid));
}
if (sz != src_size)
- die("object %s inconsistent object length (%lu vs %lu)",
+ die(_("object %s inconsistent object length (%lu vs %lu)"),
oid_to_hex(&src_entry->idx.oid), sz,
src_size);
*mem_usage += sz;
@@ -2014,7 +2097,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
if (!src->index) {
static int warned = 0;
if (!warned++)
- warning("suboptimal pack - out of memory");
+ warning(_("suboptimal pack - out of memory"));
return 0;
}
*mem_usage += sizeof_delta_index(src->index);
@@ -2023,10 +2106,6 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
if (!delta_buf)
return 0;
- if (delta_size >= (1U << OE_DELTA_SIZE_BITS)) {
- free(delta_buf);
- return 0;
- }
if (DELTA(trg_entry)) {
/* Prefer only shallower same-sized deltas. */
@@ -2245,12 +2324,19 @@ static void try_to_free_from_threads(size_t size)
static try_to_free_t old_try_to_free_routine;
/*
+ * The main object list is split into smaller lists, each is handed to
+ * one worker.
+ *
* The main thread waits on the condition that (at least) one of the workers
* has stopped working (which is indicated in the .working member of
* struct thread_params).
+ *
* When a work thread has completed its work, it sets .working to 0 and
* signals the main thread and waits on the condition that .data_ready
* becomes 1.
+ *
+ * The main thread steals half of the work from the worker that has
+ * most work left to hand it to the idle worker.
*/
struct thread_params {
@@ -2278,6 +2364,7 @@ static void init_threaded_search(void)
pthread_mutex_init(&cache_mutex, NULL);
pthread_mutex_init(&progress_mutex, NULL);
pthread_cond_init(&progress_cond, NULL);
+ pthread_mutex_init(&to_pack.lock, NULL);
old_try_to_free_routine = set_try_to_free_routine(try_to_free_from_threads);
}
@@ -2341,8 +2428,8 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
return;
}
if (progress > pack_to_stdout)
- fprintf(stderr, "Delta compression using up to %d threads.\n",
- delta_search_threads);
+ fprintf_ln(stderr, _("Delta compression using up to %d threads"),
+ delta_search_threads);
p = xcalloc(delta_search_threads, sizeof(*p));
/* Partition the work amongst work threads. */
@@ -2382,7 +2469,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
ret = pthread_create(&p[i].thread, NULL,
threaded_find_deltas, &p[i]);
if (ret)
- die("unable to create thread: %s", strerror(ret));
+ die(_("unable to create thread: %s"), strerror(ret));
active_threads++;
}
@@ -2474,10 +2561,10 @@ static void add_tag_chain(const struct object_id *oid)
if (packlist_find(&to_pack, oid->hash, NULL))
return;
- tag = lookup_tag(oid);
+ tag = lookup_tag(the_repository, oid);
while (1) {
if (!tag || parse_tag(tag) || !tag->tagged)
- die("unable to pack objects reachable from tag %s",
+ die(_("unable to pack objects reachable from tag %s"),
oid_to_hex(oid));
add_object_entry(&tag->object.oid, OBJ_TAG, NULL, 0);
@@ -2506,6 +2593,9 @@ static void prepare_pack(int window, int depth)
uint32_t i, nr_deltas;
unsigned n;
+ if (use_delta_islands)
+ resolve_tree_islands(progress, &to_pack);
+
get_object_details();
/*
@@ -2543,7 +2633,7 @@ static void prepare_pack(int window, int depth)
if (!entry->preferred_base) {
nr_deltas++;
if (oe_type(entry) < 0)
- die("unable to get type of object %s",
+ die(_("unable to get type of object %s"),
oid_to_hex(&entry->idx.oid));
} else {
if (oe_type(entry) < 0) {
@@ -2567,7 +2657,7 @@ static void prepare_pack(int window, int depth)
ll_find_deltas(delta_list, n, window+1, depth, &nr_done);
stop_progress(&progress_state);
if (nr_done != nr_deltas)
- die("inconsistency with delta count");
+ die(_("inconsistency with delta count"));
}
free(delta_list);
}
@@ -2607,11 +2697,11 @@ static int git_pack_config(const char *k, const char *v, void *cb)
if (!strcmp(k, "pack.threads")) {
delta_search_threads = git_config_int(k, v);
if (delta_search_threads < 0)
- die("invalid number of threads specified (%d)",
+ die(_("invalid number of threads specified (%d)"),
delta_search_threads);
#ifdef NO_PTHREADS
if (delta_search_threads != 1) {
- warning("no threads support, ignoring %s", k);
+ warning(_("no threads support, ignoring %s"), k);
delta_search_threads = 0;
}
#endif
@@ -2620,7 +2710,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
if (!strcmp(k, "pack.indexversion")) {
pack_idx_opts.version = git_config_int(k, v);
if (pack_idx_opts.version > 2)
- die("bad pack.indexversion=%"PRIu32,
+ die(_("bad pack.indexversion=%"PRIu32),
pack_idx_opts.version);
return 0;
}
@@ -2638,7 +2728,7 @@ static void read_object_list_from_stdin(void)
if (feof(stdin))
break;
if (!ferror(stdin))
- die("fgets returned NULL, not EOF, not error!");
+ die("BUG: fgets returned NULL, not EOF, not error!");
if (errno != EINTR)
die_errno("fgets");
clearerr(stdin);
@@ -2646,13 +2736,13 @@ static void read_object_list_from_stdin(void)
}
if (line[0] == '-') {
if (get_oid_hex(line+1, &oid))
- die("expected edge object ID, got garbage:\n %s",
+ die(_("expected edge object ID, got garbage:\n %s"),
line);
add_preferred_base(&oid);
continue;
}
if (parse_oid_hex(line, &oid, &p))
- die("expected object ID, got garbage:\n %s", line);
+ die(_("expected object ID, got garbage:\n %s"), line);
add_preferred_base_object(p + 1);
add_object_entry(&oid, OBJ_NONE, p + 1, 0);
@@ -2669,6 +2759,9 @@ static void show_commit(struct commit *commit, void *data)
if (write_bitmap_index)
index_commit_for_bitmap(commit);
+
+ if (use_delta_islands)
+ propagate_island_marks(commit);
}
static void show_object(struct object *obj, const char *name, void *data)
@@ -2676,6 +2769,19 @@ static void show_object(struct object *obj, const char *name, void *data)
add_preferred_base_object(name);
add_object_entry(&obj->oid, obj->type, name, 0);
obj->flags |= OBJECT_ADDED;
+
+ if (use_delta_islands) {
+ const char *p;
+ unsigned depth = 0;
+ struct object_entry *ent;
+
+ for (p = strchr(name, '/'); p; p = strchr(p + 1, '/'))
+ depth++;
+
+ ent = packlist_find(&to_pack, obj->oid.hash, NULL);
+ if (ent && depth > oe_tree_depth(&to_pack, ent))
+ oe_set_tree_depth(&to_pack, ent, depth);
+ }
}
static void show_object__ma_allow_any(struct object *obj, const char *name, void *data)
@@ -2784,14 +2890,14 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
memset(&in_pack, 0, sizeof(in_pack));
- for (p = get_packed_git(the_repository); p; p = p->next) {
+ for (p = get_all_packs(the_repository); p; p = p->next) {
struct object_id oid;
struct object *o;
if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
continue;
if (open_pack_index(p))
- die("cannot open pack index");
+ die(_("cannot open pack index"));
ALLOC_GROW(in_pack.array,
in_pack.nr + p->num_objects,
@@ -2822,7 +2928,7 @@ static int add_loose_object(const struct object_id *oid, const char *path,
enum object_type type = oid_object_info(the_repository, oid, NULL);
if (type < 0) {
- warning("loose object at %s could not be examined", path);
+ warning(_("loose object at %s could not be examined"), path);
return 0;
}
@@ -2848,7 +2954,7 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
struct packed_git *p;
p = (last_found != (void *)1) ? last_found :
- get_packed_git(the_repository);
+ get_all_packs(the_repository);
while (p) {
if ((!p->pack_local || p->pack_keep ||
@@ -2858,7 +2964,7 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
return 1;
}
if (p == last_found)
- p = get_packed_git(the_repository);
+ p = get_all_packs(the_repository);
else
p = p->next;
if (p == last_found)
@@ -2894,12 +3000,12 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
uint32_t i;
struct object_id oid;
- for (p = get_packed_git(the_repository); p; p = p->next) {
+ for (p = get_all_packs(the_repository); p; p = p->next) {
if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
continue;
if (open_pack_index(p))
- die("cannot open pack index");
+ die(_("cannot open pack index"));
for (i = 0; i < p->num_objects; i++) {
nth_packed_object_oid(&oid, p, i);
@@ -2907,7 +3013,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
!has_sha1_pack_kept_or_nonlocal(&oid) &&
!loosened_object_can_be_discarded(&oid, p->mtime))
if (force_object_loose(&oid, p->mtime))
- die("unable to force loose object");
+ die(_("unable to force loose object"));
}
}
}
@@ -2929,11 +3035,12 @@ static int pack_options_allow_reuse(void)
static int get_object_list_from_bitmap(struct rev_info *revs)
{
- if (prepare_bitmap_walk(revs) < 0)
+ if (!(bitmap_git = prepare_bitmap_walk(revs)))
return -1;
if (pack_options_allow_reuse() &&
!reuse_partial_packfile_from_bitmap(
+ bitmap_git,
&reuse_packfile,
&reuse_packfile_objects,
&reuse_packfile_offset)) {
@@ -2942,7 +3049,7 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
display_progress(progress_state, nr_result);
}
- traverse_bitmap_commit_list(&add_object_entry_from_bitmap);
+ traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap);
return 0;
}
@@ -2969,7 +3076,7 @@ static void get_object_list(int ac, const char **av)
setup_revisions(ac, av, &revs, NULL);
/* make sure shallows are read */
- is_repository_shallow();
+ is_repository_shallow(the_repository);
while (fgets(line, sizeof(line), stdin) != NULL) {
int len = strlen(line);
@@ -2987,21 +3094,24 @@ static void get_object_list(int ac, const char **av)
struct object_id oid;
if (get_oid_hex(line + 10, &oid))
die("not an SHA-1 '%s'", line + 10);
- register_shallow(&oid);
+ register_shallow(the_repository, &oid);
use_bitmap_index = 0;
continue;
}
- die("not a rev '%s'", line);
+ die(_("not a rev '%s'"), line);
}
if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME))
- die("bad revision '%s'", line);
+ die(_("bad revision '%s'"), line);
}
if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
return;
+ if (use_delta_islands)
+ load_delta_islands();
+
if (prepare_revision_walk(&revs))
- die("revision walk setup failed");
+ die(_("revision walk setup failed"));
mark_edges_uninteresting(&revs, show_edge);
if (!fn_show_object)
@@ -3014,9 +3124,9 @@ static void get_object_list(int ac, const char **av)
revs.ignore_missing_links = 1;
if (add_unseen_recent_objects_to_traversal(&revs,
unpack_unreachable_expiration))
- die("unable to add recent objects");
+ die(_("unable to add recent objects"));
if (prepare_revision_walk(&revs))
- die("revision walk setup failed");
+ die(_("revision walk setup failed"));
traverse_commit_list(&revs, record_recent_commit,
record_recent_object, NULL);
}
@@ -3038,7 +3148,7 @@ static void add_extra_kept_packs(const struct string_list *names)
if (!names->nr)
return;
- for (p = get_packed_git(the_repository); p; p = p->next) {
+ for (p = get_all_packs(the_repository); p; p = p->next) {
const char *name = basename(p->pack_name);
int i;
@@ -3090,7 +3200,6 @@ static int option_parse_unpack_unreachable(const struct option *opt,
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
- int thin = 0;
int shallow = 0;
int all_progress_implied = 0;
struct argv_array rp = ARGV_ARRAY_INIT;
@@ -3107,7 +3216,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "all-progress-implied",
&all_progress_implied,
N_("similar to --all-progress when progress meter is shown")),
- { OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"),
+ { OPTION_CALLBACK, 0, "index-version", NULL, N_("<version>[,<offset>]"),
N_("write the pack index file in the specified idx format version"),
0, option_parse_index_version },
OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
@@ -3179,13 +3288,15 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
option_parse_missing_action },
OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
N_("do not pack objects in promisor packfiles")),
+ OPT_BOOL(0, "delta-islands", &use_delta_islands,
+ N_("respect islands during delta compression")),
OPT_END(),
};
if (DFS_NUM_STATES > (1 << OE_DFS_STATE_BITS))
BUG("too many dfs states, increase OE_DFS_STATE_BITS");
- check_replace_refs = 0;
+ read_replace_refs = 0;
reset_pack_idx_option(&pack_idx_opts);
git_config(git_pack_config, NULL);
@@ -3251,35 +3362,35 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (pack_compression_level == -1)
pack_compression_level = Z_DEFAULT_COMPRESSION;
else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)
- die("bad pack compression level %d", pack_compression_level);
+ die(_("bad pack compression level %d"), pack_compression_level);
if (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads = online_cpus();
#ifdef NO_PTHREADS
if (delta_search_threads != 1)
- warning("no threads support, ignoring --threads");
+ warning(_("no threads support, ignoring --threads"));
#endif
if (!pack_to_stdout && !pack_size_limit)
pack_size_limit = pack_size_limit_cfg;
if (pack_to_stdout && pack_size_limit)
- die("--max-pack-size cannot be used to build a pack for transfer.");
+ die(_("--max-pack-size cannot be used to build a pack for transfer"));
if (pack_size_limit && pack_size_limit < 1024*1024) {
- warning("minimum pack size limit is 1 MiB");
+ warning(_("minimum pack size limit is 1 MiB"));
pack_size_limit = 1024*1024;
}
if (!pack_to_stdout && thin)
- die("--thin cannot be used to build an indexable pack.");
+ die(_("--thin cannot be used to build an indexable pack"));
if (keep_unreachable && unpack_unreachable)
- die("--keep-unreachable and --unpack-unreachable are incompatible.");
+ die(_("--keep-unreachable and --unpack-unreachable are incompatible"));
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
unpack_unreachable_expiration = 0;
if (filter_options.choice) {
if (!pack_to_stdout)
- die("cannot use --filter without --stdout.");
+ die(_("cannot use --filter without --stdout"));
use_bitmap_index = 0;
}
@@ -3299,19 +3410,22 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
use_bitmap_index = use_bitmap_index_default;
/* "hard" reasons not to use bitmaps; these just won't work at all */
- if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow())
+ if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow(the_repository))
use_bitmap_index = 0;
if (pack_to_stdout || !rev_list_all)
write_bitmap_index = 0;
+ if (use_delta_islands)
+ argv_array_push(&rp, "--topo-order");
+
if (progress && all_progress_implied)
progress = 2;
add_extra_kept_packs(&keep_pack_list);
if (ignore_packed_keep_on_disk) {
struct packed_git *p;
- for (p = get_packed_git(the_repository); p; p = p->next)
+ for (p = get_all_packs(the_repository); p; p = p->next)
if (p->pack_local && p->pack_keep)
break;
if (!p) /* no keep-able packs found */
@@ -3324,7 +3438,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
* it also covers non-local objects
*/
struct packed_git *p;
- for (p = get_packed_git(the_repository); p; p = p->next) {
+ for (p = get_all_packs(the_repository); p; p = p->next) {
if (!p->pack_local) {
have_non_local_packs = 1;
break;
@@ -3353,8 +3467,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
prepare_pack(window, depth);
write_pack_file();
if (progress)
- fprintf(stderr, "Total %"PRIu32" (delta %"PRIu32"),"
- " reused %"PRIu32" (delta %"PRIu32")\n",
- written, written_delta, reused, reused_delta);
+ fprintf_ln(stderr,
+ _("Total %"PRIu32" (delta %"PRIu32"),"
+ " reused %"PRIu32" (delta %"PRIu32")"),
+ written, written_delta, reused, reused_delta);
return 0;
}
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 0494dceff7..cf9a9aabd4 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -577,7 +577,7 @@ static struct pack_list * add_pack(struct packed_git *p)
static struct pack_list * add_pack_file(const char *filename)
{
- struct packed_git *p = get_packed_git(the_repository);
+ struct packed_git *p = get_all_packs(the_repository);
if (strlen(filename) < 40)
die("Bad pack filename: %s", filename);
@@ -592,7 +592,7 @@ static struct pack_list * add_pack_file(const char *filename)
static void load_all(void)
{
- struct packed_git *p = get_packed_git(the_repository);
+ struct packed_git *p = get_all_packs(the_repository);
while (p) {
add_pack(p);
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index 4ff525e50f..a9e7b552b9 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -3,6 +3,7 @@
#include "progress.h"
#include "parse-options.h"
#include "packfile.h"
+#include "object-store.h"
static const char * const prune_packed_usage[] = {
N_("git prune-packed [-n | --dry-run] [-q | --quiet]"),
diff --git a/builtin/prune.c b/builtin/prune.c
index 518ffbea13..4916a4daa2 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -6,6 +6,7 @@
#include "reachable.h"
#include "parse-options.h"
#include "progress.h"
+#include "object-store.h"
static const char * const prune_usage[] = {
N_("git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"),
@@ -39,7 +40,7 @@ static int prune_object(const struct object_id *oid, const char *fullpath,
* Do we know about this object?
* It must have been reachable
*/
- if (lookup_object(oid->hash))
+ if (lookup_object(the_repository, oid->hash))
return 0;
if (lstat(fullpath, &st)) {
@@ -117,7 +118,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
expire = TIME_MAX;
save_commit_buffer = 0;
- check_replace_refs = 0;
+ read_replace_refs = 0;
ref_paranoia = 1;
init_revisions(&revs, prefix);
@@ -159,7 +160,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
remove_temporary_files(s);
free(s);
- if (is_repository_shallow())
+ if (is_repository_shallow(the_repository))
prune_shallow(show_only);
return 0;
diff --git a/builtin/pull.c b/builtin/pull.c
index fe002a72f8..2514bfb9cd 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -22,6 +22,7 @@
#include "tempfile.h"
#include "lockfile.h"
#include "wt-status.h"
+#include "commit-reach.h"
enum rebase_type {
REBASE_INVALID = -1,
@@ -48,11 +49,11 @@ static enum rebase_type parse_config_rebase(const char *key, const char *value,
return REBASE_FALSE;
else if (v > 0)
return REBASE_TRUE;
- else if (!strcmp(value, "preserve"))
+ else if (!strcmp(value, "preserve") || !strcmp(value, "p"))
return REBASE_PRESERVE;
- else if (!strcmp(value, "merges"))
+ else if (!strcmp(value, "merges") || !strcmp(value, "m"))
return REBASE_MERGES;
- else if (!strcmp(value, "interactive"))
+ else if (!strcmp(value, "interactive") || !strcmp(value, "i"))
return REBASE_INTERACTIVE;
if (fatal)
@@ -135,7 +136,7 @@ static struct option pull_options[] = {
/* Options passed to git-merge or git-rebase */
OPT_GROUP(N_("Options related to merging")),
{ OPTION_CALLBACK, 'r', "rebase", &opt_rebase,
- "false|true|merges|preserve|interactive",
+ "(false|true|merges|preserve|interactive)",
N_("incorporate changes by rebasing rather than merging"),
PARSE_OPT_OPTARG, parse_opt_rebase },
OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL,
@@ -356,7 +357,7 @@ static int git_pull_config(const char *var, const char *value, void *cb)
*/
static void get_merge_heads(struct oid_array *merge_heads)
{
- const char *filename = git_path_fetch_head();
+ const char *filename = git_path_fetch_head(the_repository);
FILE *fp;
struct strbuf sb = STRBUF_INIT;
struct object_id oid;
@@ -765,10 +766,13 @@ static int get_octopus_merge_base(struct object_id *merge_base,
{
struct commit_list *revs = NULL, *result;
- commit_list_insert(lookup_commit_reference(curr_head), &revs);
- commit_list_insert(lookup_commit_reference(merge_head), &revs);
+ commit_list_insert(lookup_commit_reference(the_repository, curr_head),
+ &revs);
+ commit_list_insert(lookup_commit_reference(the_repository, merge_head),
+ &revs);
if (!is_null_oid(fork_point))
- commit_list_insert(lookup_commit_reference(fork_point), &revs);
+ commit_list_insert(lookup_commit_reference(the_repository, fork_point),
+ &revs);
result = get_octopus_merge_bases(revs);
free_commit_list(revs);
@@ -864,7 +868,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
if (read_cache_unmerged())
die_resolve_conflict("pull");
- if (file_exists(git_path_merge_head()))
+ if (file_exists(git_path_merge_head(the_repository)))
die_conclude_merge();
if (get_oid("HEAD", &orig_head))
@@ -944,9 +948,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
struct commit_list *list = NULL;
struct commit *merge_head, *head;
- head = lookup_commit_reference(&orig_head);
+ head = lookup_commit_reference(the_repository,
+ &orig_head);
commit_list_insert(head, &list);
- merge_head = lookup_commit_reference(&merge_heads.oid[0]);
+ merge_head = lookup_commit_reference(the_repository,
+ &merge_heads.oid[0]);
if (is_descendant_of(merge_head, list)) {
/* we can fast-forward this without invoking rebase */
opt_ff = "--ff-only";
diff --git a/builtin/push.c b/builtin/push.c
index 9cd8e8cd56..d09a42062c 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -558,10 +558,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
{ OPTION_CALLBACK,
- 0, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
+ 0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
- PARSE_OPT_OPTARG, parseopt_push_cas_option },
- { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "check|on-demand|no",
+ PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option },
+ { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)",
N_("control recursive pushing of submodules"),
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE),
@@ -576,7 +576,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"),
TRANSPORT_PUSH_FOLLOW_TAGS),
{ OPTION_CALLBACK,
- 0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
+ 0, "signed", &push_cert, "(yes|no|if-asked)", N_("GPG sign the push"),
PARSE_OPT_OPTARG, option_parse_push_signed },
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")),
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
new file mode 100644
index 0000000000..96af537493
--- /dev/null
+++ b/builtin/range-diff.c
@@ -0,0 +1,101 @@
+#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+#include "range-diff.h"
+#include "config.h"
+
+static const char * const builtin_range_diff_usage[] = {
+N_("git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"),
+N_("git range-diff [<options>] <old-tip>...<new-tip>"),
+N_("git range-diff [<options>] <base> <old-tip> <new-tip>"),
+NULL
+};
+
+int cmd_range_diff(int argc, const char **argv, const char *prefix)
+{
+ int creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
+ struct diff_options diffopt = { NULL };
+ int simple_color = -1;
+ struct option options[] = {
+ OPT_INTEGER(0, "creation-factor", &creation_factor,
+ N_("Percentage by which creation is weighted")),
+ OPT_BOOL(0, "no-dual-color", &simple_color,
+ N_("use simple diff colors")),
+ OPT_END()
+ };
+ int i, j, res = 0;
+ struct strbuf range1 = STRBUF_INIT, range2 = STRBUF_INIT;
+
+ git_config(git_diff_ui_config, NULL);
+
+ diff_setup(&diffopt);
+
+ argc = parse_options(argc, argv, NULL, options,
+ builtin_range_diff_usage, PARSE_OPT_KEEP_UNKNOWN |
+ PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
+
+ for (i = j = 1; i < argc && strcmp("--", argv[i]); ) {
+ int c = diff_opt_parse(&diffopt, argv + i, argc - i, prefix);
+
+ if (!c)
+ argv[j++] = argv[i++];
+ else
+ i += c;
+ }
+ while (i < argc)
+ argv[j++] = argv[i++];
+ argc = j;
+ diff_setup_done(&diffopt);
+
+ /* Make sure that there are no unparsed options */
+ argc = parse_options(argc, argv, NULL,
+ options + ARRAY_SIZE(options) - 1, /* OPT_END */
+ builtin_range_diff_usage, 0);
+
+ /* force color when --dual-color was used */
+ if (!simple_color)
+ diffopt.use_color = 1;
+
+ if (argc == 2) {
+ if (!strstr(argv[0], ".."))
+ die(_("no .. in range: '%s'"), argv[0]);
+ strbuf_addstr(&range1, argv[0]);
+
+ if (!strstr(argv[1], ".."))
+ die(_("no .. in range: '%s'"), argv[1]);
+ strbuf_addstr(&range2, argv[1]);
+ } else if (argc == 3) {
+ strbuf_addf(&range1, "%s..%s", argv[0], argv[1]);
+ strbuf_addf(&range2, "%s..%s", argv[0], argv[2]);
+ } else if (argc == 1) {
+ const char *b = strstr(argv[0], "..."), *a = argv[0];
+ int a_len;
+
+ if (!b) {
+ error(_("single arg format must be symmetric range"));
+ usage_with_options(builtin_range_diff_usage, options);
+ }
+
+ a_len = (int)(b - a);
+ if (!a_len) {
+ a = "HEAD";
+ a_len = strlen(a);
+ }
+ b += 3;
+ if (!*b)
+ b = "HEAD";
+ strbuf_addf(&range1, "%s..%.*s", b, a_len, a);
+ strbuf_addf(&range2, "%.*s..%s", a_len, a, b);
+ } else {
+ error(_("need two commit ranges"));
+ usage_with_options(builtin_range_diff_usage, options);
+ }
+
+ res = show_range_diff(range1.buf, range2.buf, creation_factor,
+ simple_color < 1, &diffopt);
+
+ strbuf_release(&range1);
+ strbuf_release(&range2);
+
+ return res;
+}
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index ebc43eb805..fbbc98e516 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -133,7 +133,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
N_("same as -m, but discard unmerged entries")),
{ OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"),
N_("read the tree into the index under <subdirectory>/"),
- PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP },
+ PARSE_OPT_NONEG },
OPT_BOOL('u', NULL, &opts.update,
N_("update working tree with merge result")),
{ OPTION_CALLBACK, 0, "exclude-per-directory", &opts,
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 68d36e0a56..35a3fcfbd9 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -25,7 +25,9 @@
#include "tmp-objdir.h"
#include "oidset.h"
#include "packfile.h"
+#include "object-store.h"
#include "protocol.h"
+#include "commit-reach.h"
static const char * const receive_pack_usage[] = {
N_("git receive-pack <git-dir>"),
@@ -629,8 +631,6 @@ static void prepare_push_cert_sha1(struct child_process *proc)
return;
if (!already_done) {
- struct strbuf gpg_output = STRBUF_INIT;
- struct strbuf gpg_status = STRBUF_INIT;
int bogs /* beginning_of_gpg_sig */;
already_done = 1;
@@ -639,22 +639,11 @@ static void prepare_push_cert_sha1(struct child_process *proc)
oidclr(&push_cert_oid);
memset(&sigcheck, '\0', sizeof(sigcheck));
- sigcheck.result = 'N';
bogs = parse_signature(push_cert.buf, push_cert.len);
- if (verify_signed_buffer(push_cert.buf, bogs,
- push_cert.buf + bogs, push_cert.len - bogs,
- &gpg_output, &gpg_status) < 0) {
- ; /* error running gpg */
- } else {
- sigcheck.payload = push_cert.buf;
- sigcheck.gpg_output = gpg_output.buf;
- sigcheck.gpg_status = gpg_status.buf;
- parse_gpg_output(&sigcheck);
- }
+ check_signature(push_cert.buf, bogs, push_cert.buf + bogs,
+ push_cert.len - bogs, &sigcheck);
- strbuf_release(&gpg_output);
- strbuf_release(&gpg_status);
nonce_status = check_nonce(push_cert.buf, bogs);
}
if (!is_null_oid(&push_cert_oid)) {
@@ -905,7 +894,7 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
* not lose these new roots..
*/
for (i = 0; i < extra.nr; i++)
- register_shallow(&extra.oid[i]);
+ register_shallow(the_repository, &extra.oid[i]);
si->shallow_ref[cmd->index] = 0;
oid_array_clear(&extra);
@@ -1107,8 +1096,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
struct object *old_object, *new_object;
struct commit *old_commit, *new_commit;
- old_object = parse_object(old_oid);
- new_object = parse_object(new_oid);
+ old_object = parse_object(the_repository, old_oid);
+ new_object = parse_object(the_repository, new_oid);
if (!old_object || !new_object ||
old_object->type != OBJ_COMMIT ||
@@ -1131,7 +1120,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (is_null_oid(new_oid)) {
struct strbuf err = STRBUF_INIT;
- if (!parse_object(old_oid)) {
+ if (!parse_object(the_repository, old_oid)) {
old_oid = NULL;
if (ref_exists(name)) {
rp_warning("Allowing deletion of corrupt ref.");
diff --git a/builtin/reflog.c b/builtin/reflog.c
index a48984d37e..3acef5a0ab 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -1,6 +1,8 @@
#include "builtin.h"
#include "config.h"
#include "lockfile.h"
+#include "object-store.h"
+#include "repository.h"
#include "commit.h"
#include "refs.h"
#include "dir.h"
@@ -64,7 +66,7 @@ static int tree_is_complete(const struct object_id *oid)
int complete;
struct tree *tree;
- tree = lookup_tree(oid);
+ tree = lookup_tree(the_repository, oid);
if (!tree)
return 0;
if (tree->object.flags & SEEN)
@@ -128,7 +130,7 @@ static int commit_is_complete(struct commit *commit)
struct commit_list *parent;
c = (struct commit *)object_array_pop(&study);
- if (!c->object.parsed && !parse_object(&c->object.oid))
+ if (!c->object.parsed && !parse_object(the_repository, &c->object.oid))
c->object.flags |= INCOMPLETE;
if (c->object.flags & INCOMPLETE) {
@@ -194,7 +196,7 @@ static int keep_entry(struct commit **it, struct object_id *oid)
if (is_null_oid(oid))
return 1;
- commit = lookup_commit_reference_gently(oid, 1);
+ commit = lookup_commit_reference_gently(the_repository, oid, 1);
if (!commit)
return 0;
@@ -263,7 +265,8 @@ static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit
if (is_null_oid(oid))
return 0;
- commit = lookup_commit_reference_gently(oid, 1);
+ commit = lookup_commit_reference_gently(the_repository, oid,
+ 1);
/* Not a commit -- keep it */
if (!commit)
@@ -320,7 +323,7 @@ static int push_tip_to_list(const char *refname, const struct object_id *oid,
struct commit *tip_commit;
if (flags & REF_ISSYMREF)
return 0;
- tip_commit = lookup_commit_reference_gently(oid, 1);
+ tip_commit = lookup_commit_reference_gently(the_repository, oid, 1);
if (!tip_commit)
return 0;
commit_list_insert(tip_commit, list);
@@ -337,7 +340,8 @@ static void reflog_expiry_prepare(const char *refname,
cb->tip_commit = NULL;
cb->unreachable_expire_kind = UE_HEAD;
} else {
- cb->tip_commit = lookup_commit_reference_gently(oid, 1);
+ cb->tip_commit = lookup_commit_reference_gently(the_repository,
+ oid, 1);
if (!cb->tip_commit)
cb->unreachable_expire_kind = UE_ALWAYS;
else
diff --git a/builtin/remote.c b/builtin/remote.c
index 1a82d850a2..61479bc428 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -8,7 +8,9 @@
#include "run-command.h"
#include "refs.h"
#include "refspec.h"
+#include "object-store.h"
#include "argv-array.h"
+#include "commit-reach.h"
static const char * const builtin_remote_usage[] = {
N_("git remote [-v | --verbose]"),
@@ -167,7 +169,7 @@ static int add(int argc, const char **argv)
OPT_STRING_LIST('t', "track", &track, N_("branch"),
N_("branch(es) to track")),
OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
- { OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"),
+ { OPTION_CALLBACK, 0, "mirror", &mirror, "(push|fetch)",
N_("set up remote as a mirror to push to or fetch from"),
PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt },
OPT_END()
@@ -565,7 +567,7 @@ static int read_remote_branches(const char *refname,
strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name);
if (starts_with(refname, buf.buf)) {
- item = string_list_append(rename->remote_branches, xstrdup(refname));
+ item = string_list_append(rename->remote_branches, refname);
symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
NULL, &flag);
if (symref && (flag & REF_ISSYMREF))
@@ -611,7 +613,7 @@ static int mv(int argc, const char **argv)
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_NODUP;
+ struct string_list remote_branches = STRING_LIST_INIT_DUP;
struct rename_info rename;
int i, refspec_updated = 0;
@@ -733,6 +735,7 @@ static int mv(int argc, const char **argv)
if (create_symref(buf.buf, buf2.buf, buf3.buf))
die(_("creating '%s' failed"), buf.buf);
}
+ string_list_clear(&remote_branches, 1);
return 0;
}
diff --git a/builtin/repack.c b/builtin/repack.c
index 6c636e159e..c6a7943d5c 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -8,10 +8,14 @@
#include "strbuf.h"
#include "string-list.h"
#include "argv-array.h"
+#include "midx.h"
+#include "packfile.h"
+#include "object-store.h"
static int delta_base_offset = 1;
static int pack_kept_objects = -1;
static int write_bitmaps;
+static int use_delta_islands;
static char *packdir, *packtmp;
static const char *const git_repack_usage[] = {
@@ -40,6 +44,10 @@ static int repack_config(const char *var, const char *value, void *cb)
write_bitmaps = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "repack.usedeltaislands")) {
+ use_delta_islands = git_config_bool(var, value);
+ return 0;
+ }
return git_default_config(var, value, cb);
}
@@ -83,7 +91,7 @@ static void remove_pack_on_signal(int signo)
/*
* Adds all packs hex strings to the fname list, which do not
- * have a corresponding .keep or .promisor file. These packs are not to
+ * have a corresponding .keep file. These packs are not to
* be kept if we are going to pack everything into one file.
*/
static void get_non_kept_pack_filenames(struct string_list *fname_list,
@@ -111,8 +119,7 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list,
fname = xmemdupz(e->d_name, len);
- if (!file_exists(mkpath("%s/%s.keep", packdir, fname)) &&
- !file_exists(mkpath("%s/%s.promisor", packdir, fname)))
+ if (!file_exists(mkpath("%s/%s.keep", packdir, fname)))
string_list_append_nodup(fname_list, fname);
else
free(fname);
@@ -122,7 +129,7 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list,
static void remove_redundant_pack(const char *dir_name, const char *base_name)
{
- const char *exts[] = {".pack", ".idx", ".keep", ".bitmap"};
+ const char *exts[] = {".pack", ".idx", ".keep", ".bitmap", ".promisor"};
int i;
struct strbuf buf = STRBUF_INIT;
size_t plen;
@@ -138,6 +145,117 @@ static void remove_redundant_pack(const char *dir_name, const char *base_name)
strbuf_release(&buf);
}
+struct pack_objects_args {
+ const char *window;
+ const char *window_memory;
+ const char *depth;
+ const char *threads;
+ const char *max_pack_size;
+ int no_reuse_delta;
+ int no_reuse_object;
+ int quiet;
+ int local;
+};
+
+static void prepare_pack_objects(struct child_process *cmd,
+ const struct pack_objects_args *args)
+{
+ argv_array_push(&cmd->args, "pack-objects");
+ if (args->window)
+ argv_array_pushf(&cmd->args, "--window=%s", args->window);
+ if (args->window_memory)
+ argv_array_pushf(&cmd->args, "--window-memory=%s", args->window_memory);
+ if (args->depth)
+ argv_array_pushf(&cmd->args, "--depth=%s", args->depth);
+ if (args->threads)
+ argv_array_pushf(&cmd->args, "--threads=%s", args->threads);
+ if (args->max_pack_size)
+ argv_array_pushf(&cmd->args, "--max-pack-size=%s", args->max_pack_size);
+ if (args->no_reuse_delta)
+ argv_array_pushf(&cmd->args, "--no-reuse-delta");
+ if (args->no_reuse_object)
+ argv_array_pushf(&cmd->args, "--no-reuse-object");
+ if (args->local)
+ argv_array_push(&cmd->args, "--local");
+ if (args->quiet)
+ argv_array_push(&cmd->args, "--quiet");
+ if (delta_base_offset)
+ argv_array_push(&cmd->args, "--delta-base-offset");
+ argv_array_push(&cmd->args, packtmp);
+ cmd->git_cmd = 1;
+ cmd->out = -1;
+}
+
+/*
+ * Write oid to the given struct child_process's stdin, starting it first if
+ * necessary.
+ */
+static int write_oid(const struct object_id *oid, struct packed_git *pack,
+ uint32_t pos, void *data)
+{
+ struct child_process *cmd = data;
+
+ if (cmd->in == -1) {
+ if (start_command(cmd))
+ die("Could not start pack-objects to repack promisor objects");
+ }
+
+ xwrite(cmd->in, oid_to_hex(oid), GIT_SHA1_HEXSZ);
+ xwrite(cmd->in, "\n", 1);
+ return 0;
+}
+
+static void repack_promisor_objects(const struct pack_objects_args *args,
+ struct string_list *names)
+{
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ FILE *out;
+ struct strbuf line = STRBUF_INIT;
+
+ prepare_pack_objects(&cmd, args);
+ cmd.in = -1;
+
+ /*
+ * NEEDSWORK: Giving pack-objects only the OIDs without any ordering
+ * hints may result in suboptimal deltas in the resulting pack. See if
+ * the OIDs can be sent with fake paths such that pack-objects can use a
+ * {type -> existing pack order} ordering when computing deltas instead
+ * of a {type -> size} ordering, which may produce better deltas.
+ */
+ for_each_packed_object(write_oid, &cmd,
+ FOR_EACH_OBJECT_PROMISOR_ONLY);
+
+ if (cmd.in == -1)
+ /* No packed objects; cmd was never started */
+ return;
+
+ close(cmd.in);
+
+ out = xfdopen(cmd.out, "r");
+ while (strbuf_getline_lf(&line, out) != EOF) {
+ char *promisor_name;
+ int fd;
+ if (line.len != 40)
+ die("repack: Expecting 40 character sha1 lines only from pack-objects.");
+ string_list_append(names, line.buf);
+
+ /*
+ * pack-objects creates the .pack and .idx files, but not the
+ * .promisor file. Create the .promisor file, which is empty.
+ */
+ promisor_name = mkpathdup("%s-%s.promisor", packtmp,
+ line.buf);
+ fd = open(promisor_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
+ if (fd < 0)
+ die_errno("unable to create '%s'", promisor_name);
+ close(fd);
+ free(promisor_name);
+ }
+ fclose(out);
+ if (finish_command(&cmd))
+ die("Could not finish pack-objects to repack promisor objects");
+}
+
#define ALL_INTO_ONE 1
#define LOOSEN_UNREACHABLE 2
@@ -150,6 +268,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
{".pack"},
{".idx"},
{".bitmap", 1},
+ {".promisor", 1},
};
struct child_process cmd = CHILD_PROCESS_INIT;
struct string_list_item *item;
@@ -165,15 +284,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
int delete_redundant = 0;
const char *unpack_unreachable = NULL;
int keep_unreachable = 0;
- const char *window = NULL, *window_memory = NULL;
- const char *depth = NULL;
- const char *threads = NULL;
- const char *max_pack_size = NULL;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
- int no_reuse_delta = 0, no_reuse_object = 0;
int no_update_server_info = 0;
- int quiet = 0;
- int local = 0;
+ int midx_cleared = 0;
+ struct pack_objects_args po_args = {NULL};
struct option builtin_repack_options[] = {
OPT_BIT('a', NULL, &pack_everything,
@@ -183,30 +297,32 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
LOOSEN_UNREACHABLE | ALL_INTO_ONE),
OPT_BOOL('d', NULL, &delete_redundant,
N_("remove redundant packs, and run git-prune-packed")),
- OPT_BOOL('f', NULL, &no_reuse_delta,
+ OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
N_("pass --no-reuse-delta to git-pack-objects")),
- OPT_BOOL('F', NULL, &no_reuse_object,
+ OPT_BOOL('F', NULL, &po_args.no_reuse_object,
N_("pass --no-reuse-object to git-pack-objects")),
OPT_BOOL('n', NULL, &no_update_server_info,
N_("do not run git-update-server-info")),
- OPT__QUIET(&quiet, N_("be quiet")),
- OPT_BOOL('l', "local", &local,
+ OPT__QUIET(&po_args.quiet, N_("be quiet")),
+ OPT_BOOL('l', "local", &po_args.local,
N_("pass --local to git-pack-objects")),
OPT_BOOL('b', "write-bitmap-index", &write_bitmaps,
N_("write bitmap index")),
+ OPT_BOOL('i', "delta-islands", &use_delta_islands,
+ N_("pass --delta-islands to git-pack-objects")),
OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
N_("with -A, do not loosen objects older than this")),
OPT_BOOL('k', "keep-unreachable", &keep_unreachable,
N_("with -a, repack unreachable objects")),
- OPT_STRING(0, "window", &window, N_("n"),
+ OPT_STRING(0, "window", &po_args.window, N_("n"),
N_("size of the window used for delta compression")),
- OPT_STRING(0, "window-memory", &window_memory, N_("bytes"),
+ OPT_STRING(0, "window-memory", &po_args.window_memory, N_("bytes"),
N_("same as the above, but limit memory size instead of entries count")),
- OPT_STRING(0, "depth", &depth, N_("n"),
+ OPT_STRING(0, "depth", &po_args.depth, N_("n"),
N_("limits the maximum delta depth")),
- OPT_STRING(0, "threads", &threads, N_("n"),
+ OPT_STRING(0, "threads", &po_args.threads, N_("n"),
N_("limits the maximum number of threads")),
- OPT_STRING(0, "max-pack-size", &max_pack_size, N_("bytes"),
+ OPT_STRING(0, "max-pack-size", &po_args.max_pack_size, N_("bytes"),
N_("maximum size of each packfile")),
OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
N_("repack objects in packs marked with .keep")),
@@ -238,7 +354,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
sigchain_push_common(remove_pack_on_signal);
- argv_array_push(&cmd.args, "pack-objects");
+ prepare_pack_objects(&cmd, &po_args);
+
argv_array_push(&cmd.args, "--keep-true-parents");
if (!pack_kept_objects)
argv_array_push(&cmd.args, "--honor-pack-keep");
@@ -251,26 +368,16 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
argv_array_push(&cmd.args, "--indexed-objects");
if (repository_format_partial_clone)
argv_array_push(&cmd.args, "--exclude-promisor-objects");
- if (window)
- argv_array_pushf(&cmd.args, "--window=%s", window);
- if (window_memory)
- argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory);
- if (depth)
- argv_array_pushf(&cmd.args, "--depth=%s", depth);
- if (threads)
- argv_array_pushf(&cmd.args, "--threads=%s", threads);
- if (max_pack_size)
- argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size);
- if (no_reuse_delta)
- argv_array_pushf(&cmd.args, "--no-reuse-delta");
- if (no_reuse_object)
- argv_array_pushf(&cmd.args, "--no-reuse-object");
if (write_bitmaps)
argv_array_push(&cmd.args, "--write-bitmap-index");
+ if (use_delta_islands)
+ argv_array_push(&cmd.args, "--delta-islands");
if (pack_everything & ALL_INTO_ONE) {
get_non_kept_pack_filenames(&existing_packs, &keep_pack_list);
+ repack_promisor_objects(&po_args, &names);
+
if (existing_packs.nr && delete_redundant) {
if (unpack_unreachable) {
argv_array_pushf(&cmd.args,
@@ -292,17 +399,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
argv_array_push(&cmd.args, "--incremental");
}
- if (local)
- argv_array_push(&cmd.args, "--local");
- if (quiet)
- argv_array_push(&cmd.args, "--quiet");
- if (delta_base_offset)
- argv_array_push(&cmd.args, "--delta-base-offset");
-
- argv_array_push(&cmd.args, packtmp);
-
- cmd.git_cmd = 1;
- cmd.out = -1;
cmd.no_stdin = 1;
ret = start_command(&cmd);
@@ -320,7 +416,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (ret)
return ret;
- if (!names.nr && !quiet)
+ if (!names.nr && !po_args.quiet)
printf("Nothing new to pack.\n");
/*
@@ -333,6 +429,13 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
for_each_string_list_item(item, &names) {
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname, *fname_old;
+
+ if (!midx_cleared) {
+ /* if we move a packfile, it will invalidated the midx */
+ clear_midx_file(get_object_directory());
+ midx_cleared = 1;
+ }
+
fname = mkpathdup("%s/pack-%s%s", packdir,
item->string, exts[ext].name);
if (!file_exists(fname)) {
@@ -429,6 +532,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
/* End of pack replacement. */
+ reprepare_packed_git(the_repository);
+
if (delete_redundant) {
int opts = 0;
string_list_sort(&names);
@@ -441,7 +546,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (!string_list_has_string(&names, sha1))
remove_redundant_pack(packdir, item->string);
}
- if (!quiet && isatty(2))
+ if (!po_args.quiet && isatty(2))
opts |= PRUNE_PACKED_VERBOSE;
prune_packed_objects(opts);
}
diff --git a/builtin/replace.c b/builtin/replace.c
index 6da2411e14..4f05791f3e 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -54,7 +54,7 @@ static int show_reference(const char *refname, const struct object_id *oid,
enum object_type obj_type, repl_type;
if (get_oid(refname, &object))
- return error("Failed to resolve '%s' as a valid ref.", refname);
+ return error(_("failed to resolve '%s' as a valid ref"), refname);
obj_type = oid_object_info(the_repository, &object,
NULL);
@@ -83,8 +83,8 @@ static int list_replace_refs(const char *pattern, const char *format)
else if (!strcmp(format, "long"))
data.format = REPLACE_FORMAT_LONG;
else
- return error("invalid replace format '%s'\n"
- "valid formats are 'short', 'medium' and 'long'\n",
+ return error(_("invalid replace format '%s'\n"
+ "valid formats are 'short', 'medium' and 'long'"),
format);
for_each_replace_ref(the_repository, show_reference, (void *)&data);
@@ -108,7 +108,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
for (p = argv; *p; p++) {
if (get_oid(*p, &oid)) {
- error("Failed to resolve '%s' as a valid ref.", *p);
+ error("failed to resolve '%s' as a valid ref", *p);
had_error = 1;
continue;
}
@@ -118,7 +118,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
full_hex = ref.buf + base_len;
if (read_ref(ref.buf, &oid)) {
- error("replace ref '%s' not found.", full_hex);
+ error(_("replace ref '%s' not found"), full_hex);
had_error = 1;
continue;
}
@@ -134,7 +134,7 @@ static int delete_replace_ref(const char *name, const char *ref,
{
if (delete_ref(NULL, ref, oid, 0))
return 1;
- printf("Deleted replace ref '%s'\n", name);
+ printf_ln(_("Deleted replace ref '%s'"), name);
return 0;
}
@@ -146,12 +146,12 @@ static int check_ref_valid(struct object_id *object,
strbuf_reset(ref);
strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object));
if (check_refname_format(ref->buf, 0))
- return error("'%s' is not a valid ref name.", ref->buf);
+ return error(_("'%s' is not a valid ref name"), ref->buf);
if (read_ref(ref->buf, prev))
oidclr(prev);
else if (!force)
- return error("replace ref '%s' already exists", ref->buf);
+ return error(_("replace ref '%s' already exists"), ref->buf);
return 0;
}
@@ -171,10 +171,10 @@ static int replace_object_oid(const char *object_ref,
obj_type = oid_object_info(the_repository, object, NULL);
repl_type = oid_object_info(the_repository, repl, NULL);
if (!force && obj_type != repl_type)
- return error("Objects must be of the same type.\n"
- "'%s' points to a replaced object of type '%s'\n"
- "while '%s' points to a replacement object of "
- "type '%s'.",
+ return error(_("Objects must be of the same type.\n"
+ "'%s' points to a replaced object of type '%s'\n"
+ "while '%s' points to a replacement object of "
+ "type '%s'."),
object_ref, type_name(obj_type),
replace_ref, type_name(repl_type));
@@ -200,10 +200,10 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
struct object_id object, repl;
if (get_oid(object_ref, &object))
- return error("Failed to resolve '%s' as a valid ref.",
+ return error(_("failed to resolve '%s' as a valid ref"),
object_ref);
if (get_oid(replace_ref, &repl))
- return error("Failed to resolve '%s' as a valid ref.",
+ return error(_("failed to resolve '%s' as a valid ref"),
replace_ref);
return replace_object_oid(object_ref, &object, replace_ref, &repl, force);
@@ -222,7 +222,7 @@ static int export_object(const struct object_id *oid, enum object_type type,
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
- return error_errno("unable to open %s for writing", filename);
+ return error_errno(_("unable to open %s for writing"), filename);
argv_array_push(&cmd.args, "--no-replace-objects");
argv_array_push(&cmd.args, "cat-file");
@@ -235,7 +235,7 @@ static int export_object(const struct object_id *oid, enum object_type type,
cmd.out = fd;
if (run_command(&cmd))
- return error("cat-file reported failure");
+ return error(_("cat-file reported failure"));
return 0;
}
@@ -251,7 +251,7 @@ static int import_object(struct object_id *oid, enum object_type type,
fd = open(filename, O_RDONLY);
if (fd < 0)
- return error_errno("unable to open %s for reading", filename);
+ return error_errno(_("unable to open %s for reading"), filename);
if (!raw && type == OBJ_TREE) {
const char *argv[] = { "mktree", NULL };
@@ -265,11 +265,11 @@ static int import_object(struct object_id *oid, enum object_type type,
if (start_command(&cmd)) {
close(fd);
- return error("unable to spawn mktree");
+ return error(_("unable to spawn mktree"));
}
if (strbuf_read(&result, cmd.out, 41) < 0) {
- error_errno("unable to read from mktree");
+ error_errno(_("unable to read from mktree"));
close(fd);
close(cmd.out);
return -1;
@@ -278,11 +278,11 @@ static int import_object(struct object_id *oid, enum object_type type,
if (finish_command(&cmd)) {
strbuf_release(&result);
- return error("mktree reported failure");
+ return error(_("mktree reported failure"));
}
if (get_oid_hex(result.buf, oid) < 0) {
strbuf_release(&result);
- return error("mktree did not return an object name");
+ return error(_("mktree did not return an object name"));
}
strbuf_release(&result);
@@ -291,12 +291,12 @@ static int import_object(struct object_id *oid, enum object_type type,
int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT;
if (fstat(fd, &st) < 0) {
- error_errno("unable to fstat %s", filename);
+ error_errno(_("unable to fstat %s"), filename);
close(fd);
return -1;
}
if (index_fd(oid, fd, &st, type, NULL, flags) < 0)
- return error("unable to write object to database");
+ return error(_("unable to write object to database"));
/* index_fd close()s fd for us */
}
@@ -315,11 +315,11 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
struct strbuf ref = STRBUF_INIT;
if (get_oid(object_ref, &old_oid) < 0)
- return error("Not a valid object name: '%s'", object_ref);
+ return error(_("not a valid object name: '%s'"), object_ref);
type = oid_object_info(the_repository, &old_oid, NULL);
if (type < 0)
- return error("unable to get object type for %s",
+ return error(_("unable to get object type for %s"),
oid_to_hex(&old_oid));
if (check_ref_valid(&old_oid, &prev, &ref, force)) {
@@ -335,7 +335,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
}
if (launch_editor(tmpfile, NULL, NULL) < 0) {
free(tmpfile);
- return error("editing object file failed");
+ return error(_("editing object file failed"));
}
if (import_object(&new_oid, type, raw, tmpfile)) {
free(tmpfile);
@@ -344,7 +344,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
free(tmpfile);
if (!oidcmp(&old_oid, &new_oid))
- return error("new object is the same as the old one: '%s'", oid_to_hex(&old_oid));
+ return error(_("new object is the same as the old one: '%s'"), oid_to_hex(&old_oid));
return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force);
}
@@ -368,10 +368,10 @@ static int replace_parents(struct strbuf *buf, int argc, const char **argv)
struct object_id oid;
if (get_oid(argv[i], &oid) < 0) {
strbuf_release(&new_parents);
- return error(_("Not a valid object name: '%s'"),
+ return error(_("not a valid object name: '%s'"),
argv[i]);
}
- if (!lookup_commit_reference(&oid)) {
+ if (!lookup_commit_reference(the_repository, &oid)) {
strbuf_release(&new_parents);
return error(_("could not parse %s"), argv[i]);
}
@@ -402,17 +402,17 @@ static int check_one_mergetag(struct commit *commit,
int i;
hash_object_file(extra->value, extra->len, type_name(OBJ_TAG), &tag_oid);
- tag = lookup_tag(&tag_oid);
+ tag = lookup_tag(the_repository, &tag_oid);
if (!tag)
return error(_("bad mergetag in commit '%s'"), ref);
- if (parse_tag_buffer(tag, extra->value, extra->len))
+ if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
return error(_("malformed mergetag in commit '%s'"), ref);
/* iterate over new parents */
for (i = 1; i < mergetag_data->argc; i++) {
struct object_id oid;
if (get_oid(mergetag_data->argv[i], &oid) < 0)
- return error(_("Not a valid object name: '%s'"),
+ return error(_("not a valid object name: '%s'"),
mergetag_data->argv[i]);
if (!oidcmp(&tag->tagged->oid, &oid))
return 0; /* found */
@@ -442,8 +442,8 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
unsigned long size;
if (get_oid(old_ref, &old_oid) < 0)
- return error(_("Not a valid object name: '%s'"), old_ref);
- commit = lookup_commit_reference(&old_oid);
+ return error(_("not a valid object name: '%s'"), old_ref);
+ commit = lookup_commit_reference(the_repository, &old_oid);
if (!commit)
return error(_("could not parse %s"), old_ref);
@@ -457,7 +457,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
}
if (remove_signature(&buf)) {
- warning(_("the original commit '%s' has a gpg signature."), old_ref);
+ warning(_("the original commit '%s' has a gpg signature"), old_ref);
warning(_("the signature will be removed in the replacement commit!"));
}
@@ -476,10 +476,10 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
if (!oidcmp(&old_oid, &new_oid)) {
if (gentle) {
- warning("graft for '%s' unnecessary", oid_to_hex(&old_oid));
+ warning(_("graft for '%s' unnecessary"), oid_to_hex(&old_oid));
return 0;
}
- return error("new commit is the same as the old one: '%s'", oid_to_hex(&old_oid));
+ return error(_("new commit is the same as the old one: '%s'"), oid_to_hex(&old_oid));
}
return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, force);
@@ -487,7 +487,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
static int convert_graft_file(int force)
{
- const char *graft_file = get_graft_file();
+ const char *graft_file = get_graft_file(the_repository);
FILE *fp = fopen_or_warn(graft_file, "r");
struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
struct argv_array args = ARGV_ARRAY_INIT;
@@ -544,7 +544,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
OPT_END()
};
- check_replace_refs = 0;
+ read_replace_refs = 0;
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
@@ -553,7 +553,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
cmdmode = argc ? MODE_REPLACE : MODE_LIST;
if (format && cmdmode != MODE_LIST)
- usage_msg_opt("--format cannot be used when not listing",
+ usage_msg_opt(_("--format cannot be used when not listing"),
git_replace_usage, options);
if (force &&
@@ -561,47 +561,47 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
cmdmode != MODE_EDIT &&
cmdmode != MODE_GRAFT &&
cmdmode != MODE_CONVERT_GRAFT_FILE)
- usage_msg_opt("-f only makes sense when writing a replacement",
+ usage_msg_opt(_("-f only makes sense when writing a replacement"),
git_replace_usage, options);
if (raw && cmdmode != MODE_EDIT)
- usage_msg_opt("--raw only makes sense with --edit",
+ usage_msg_opt(_("--raw only makes sense with --edit"),
git_replace_usage, options);
switch (cmdmode) {
case MODE_DELETE:
if (argc < 1)
- usage_msg_opt("-d needs at least one argument",
+ usage_msg_opt(_("-d needs at least one argument"),
git_replace_usage, options);
return for_each_replace_name(argv, delete_replace_ref);
case MODE_REPLACE:
if (argc != 2)
- usage_msg_opt("bad number of arguments",
+ usage_msg_opt(_("bad number of arguments"),
git_replace_usage, options);
return replace_object(argv[0], argv[1], force);
case MODE_EDIT:
if (argc != 1)
- usage_msg_opt("-e needs exactly one argument",
+ usage_msg_opt(_("-e needs exactly one argument"),
git_replace_usage, options);
return edit_and_replace(argv[0], force, raw);
case MODE_GRAFT:
if (argc < 1)
- usage_msg_opt("-g needs at least one argument",
+ usage_msg_opt(_("-g needs at least one argument"),
git_replace_usage, options);
return create_graft(argc, argv, force, 0);
case MODE_CONVERT_GRAFT_FILE:
if (argc != 0)
- usage_msg_opt("--convert-graft-file takes no argument",
+ usage_msg_opt(_("--convert-graft-file takes no argument"),
git_replace_usage, options);
return !!convert_graft_file(force);
case MODE_LIST:
if (argc > 1)
- usage_msg_opt("only one pattern can be given with -l",
+ usage_msg_opt(_("only one pattern can be given with -l"),
git_replace_usage, options);
return list_replace_refs(argv[0], format);
diff --git a/builtin/reset.c b/builtin/reset.c
index a862c70fab..11cd0dcb8c 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -39,7 +39,7 @@ static const char *reset_type_names[] = {
static inline int is_merge(void)
{
- return !access(git_path_merge_head(), F_OK);
+ return !access(git_path_merge_head(the_repository), F_OK);
}
static int reset_index(const struct object_id *oid, int reset_type, int quiet)
@@ -134,7 +134,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
continue;
}
- ce = make_cache_entry(one->mode, one->oid.hash, one->path,
+ ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
0, 0);
if (!ce)
die(_("make_cache_entry failed for path '%s'"),
@@ -319,7 +319,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
struct commit *commit;
if (get_oid_committish(rev, &oid))
die(_("Failed to resolve '%s' as a valid revision."), rev);
- commit = lookup_commit_reference(&oid);
+ commit = lookup_commit_reference(the_repository, &oid);
if (!commit)
die(_("Could not parse object '%s'."), rev);
oidcpy(&oid, &commit->object.oid);
@@ -396,7 +396,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
update_ref_status = reset_refs(rev, &oid);
if (reset_type == HARD && !update_ref_status && !quiet)
- print_new_head_line(lookup_commit_reference(&oid));
+ print_new_head_line(lookup_commit_reference(the_repository, &oid));
}
if (!pathspec.nr)
remove_branch_state();
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index fadd3ec14c..ed0ea7dc5b 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -6,6 +6,7 @@
#include "list-objects.h"
#include "list-objects-filter.h"
#include "list-objects-filter-options.h"
+#include "object-store.h"
#include "pack.h"
#include "pack-bitmap.h"
#include "builtin.h"
@@ -16,6 +17,7 @@
#include "reflog-walk.h"
#include "oidset.h"
#include "packfile.h"
+#include "object-store.h"
static const char rev_list_usage[] =
"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@@ -238,7 +240,7 @@ static int finish_object(struct object *obj, const char *name, void *cb_data)
return 1;
}
if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
- parse_object(&obj->oid);
+ parse_object(the_repository, &obj->oid);
return 0;
}
@@ -491,7 +493,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if ((!revs.commits && reflog_walk_empty(revs.reflog_info) &&
(!(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
!revs.pending.nr) &&
- !revs.rev_input_given) ||
+ !revs.rev_input_given && !revs.read_from_stdin) ||
revs.diff)
usage(rev_list_usage);
@@ -514,17 +516,21 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
if (revs.count && !revs.left_right && !revs.cherry_mark) {
uint32_t commit_count;
int max_count = revs.max_count;
- if (!prepare_bitmap_walk(&revs)) {
- count_bitmap_commit_list(&commit_count, NULL, NULL, NULL);
+ struct bitmap_index *bitmap_git;
+ if ((bitmap_git = prepare_bitmap_walk(&revs))) {
+ count_bitmap_commit_list(bitmap_git, &commit_count, NULL, NULL, NULL);
if (max_count >= 0 && max_count < commit_count)
commit_count = max_count;
printf("%d\n", commit_count);
+ free_bitmap_index(bitmap_git);
return 0;
}
} else if (revs.max_count < 0 &&
revs.tag_objects && revs.tree_objects && revs.blob_objects) {
- if (!prepare_bitmap_walk(&revs)) {
- traverse_bitmap_commit_list(&show_object_fast);
+ struct bitmap_index *bitmap_git;
+ if ((bitmap_git = prepare_bitmap_walk(&revs))) {
+ traverse_bitmap_commit_list(bitmap_git, &show_object_fast);
+ free_bitmap_index(bitmap_git);
return 0;
}
}
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 4f49e96bfd..455f62246d 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -14,6 +14,7 @@
#include "revision.h"
#include "split-index.h"
#include "submodule.h"
+#include "commit-reach.h"
#define DO_REVS 1
#define DO_NOREV 2
@@ -280,8 +281,8 @@ static int try_difference(const char *arg)
if (symmetric) {
struct commit_list *exclude;
struct commit *a, *b;
- a = lookup_commit_reference(&start_oid);
- b = lookup_commit_reference(&end_oid);
+ a = lookup_commit_reference(the_repository, &start_oid);
+ b = lookup_commit_reference(the_repository, &end_oid);
if (!a || !b) {
*dotdot = '.';
return 0;
@@ -333,7 +334,7 @@ static int try_parent_shorthands(const char *arg)
*dotdot = 0;
if (get_oid_committish(arg, &oid) ||
- !(commit = lookup_commit_reference(&oid))) {
+ !(commit = lookup_commit_reference(the_repository, &oid))) {
*dotdot = '^';
return 0;
}
@@ -883,7 +884,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(arg, "--is-shallow-repository")) {
- printf("%s\n", is_repository_shallow() ? "true"
+ printf("%s\n",
+ is_repository_shallow(the_repository) ? "true"
: "false");
continue;
}
diff --git a/builtin/revert.c b/builtin/revert.c
index 76f0a35b07..9a66720cfc 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -7,6 +7,7 @@
#include "rerere.h"
#include "dir.h"
#include "sequencer.h"
+#include "branch.h"
/*
* This implements the builtins revert and cherry-pick.
@@ -191,8 +192,12 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
opts->gpg_sign = xstrdup_or_null(opts->gpg_sign);
opts->strategy = xstrdup_or_null(opts->strategy);
- if (cmd == 'q')
- return sequencer_remove_state(opts);
+ if (cmd == 'q') {
+ int ret = sequencer_remove_state(opts);
+ if (!ret)
+ remove_branch_state();
+ return ret;
+ }
if (cmd == 'c')
return sequencer_continue(opts);
if (cmd == 'a')
diff --git a/builtin/rm.c b/builtin/rm.c
index 65b448ef8e..2cbe89e0ae 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -278,14 +278,14 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
- if (!ce_path_match(ce, &pathspec, seen))
+ if (!ce_path_match(&the_index, ce, &pathspec, seen))
continue;
ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
list.entry[list.nr].name = xstrdup(ce->name);
list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
if (list.entry[list.nr++].is_submodule &&
!is_staging_gitmodules_ok(&the_index))
- die (_("Please stage your changes to .gitmodules or stash them to proceed"));
+ die(_("please stage your changes to .gitmodules or stash them to proceed"));
}
if (pathspec.nr) {
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 42fd8d1a35..8e3c7490f7 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -166,7 +166,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "mirror", &send_mirror, N_("mirror all refs")),
OPT_BOOL('f', "force", &force_update, N_("force updates")),
{ OPTION_CALLBACK,
- 0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
+ 0, "signed", &push_cert, "(yes|no|if-asked)", N_("GPG sign the push"),
PARSE_OPT_OPTARG, option_parse_push_signed },
OPT_STRING_LIST(0, "push-option", &push_options,
N_("server-specific"),
@@ -178,7 +178,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")),
OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")),
{ OPTION_CALLBACK,
- 0, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
+ 0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
N_("require old value of ref to be at this value"),
PARSE_OPT_OPTARG, parseopt_push_cas_option },
OPT_END()
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 608d6ba77b..3898a2c9c4 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -268,8 +268,9 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
N_("Suppress commit descriptions, only provides commit count")),
OPT_BOOL('e', "email", &log.email,
N_("Show the email address of each author")),
- { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"),
- N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args },
+ { OPTION_CALLBACK, 'w', NULL, &log, N_("<w>[,<i1>[,<i2>]]"),
+ N_("Linewrap output"), PARSE_OPT_OPTARG,
+ &parse_wrap_args },
OPT_END(),
};
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index f2e985c00a..363cf8509a 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -378,7 +378,8 @@ static void sort_ref_range(int bottom, int top)
static int append_ref(const char *refname, const struct object_id *oid,
int allow_dups)
{
- struct commit *commit = lookup_commit_reference_gently(oid, 1);
+ struct commit *commit = lookup_commit_reference_gently(the_repository,
+ oid, 1);
int i;
if (!commit)
@@ -673,7 +674,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
{ OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
N_("show <n> most recent ref-log entries starting at "
"base"),
- PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP,
+ PARSE_OPT_OPTARG,
parse_reflog_param },
OPT_END()
};
@@ -830,7 +831,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
MAX_REVS), MAX_REVS);
if (get_oid(ref_name[num_rev], &revkey))
die(_("'%s' is not a valid ref."), ref_name[num_rev]);
- commit = lookup_commit_reference(&revkey);
+ commit = lookup_commit_reference(the_repository, &revkey);
if (!commit)
die(_("cannot find commit %s (%s)"),
ref_name[num_rev], oid_to_hex(&revkey));
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index f2eb1a7724..2f13f1316f 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "cache.h"
#include "refs.h"
+#include "object-store.h"
#include "object.h"
#include "tag.h"
#include "string-list.h"
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 20ae9191ca..40844870cf 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -331,7 +331,7 @@ static int module_list_compute(int argc, const char **argv,
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
- if (!match_pathspec(pathspec, ce->name, ce_namelen(ce),
+ if (!match_pathspec(&the_index, pathspec, ce->name, ce_namelen(ce),
0, ps_matched, 1) ||
!S_ISGITLINK(ce->ce_mode))
continue;
@@ -542,7 +542,7 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
argv_array_pushv(&cpr.args, info->argv);
if (run_command(&cpr))
- die(_("run_command returned non-zero status while"
+ die(_("run_command returned non-zero status while "
"recursing in the nested submodules of %s\n."),
displaypath);
}
@@ -1024,7 +1024,6 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data
{
struct sync_cb *info = cb_data;
sync_submodule(list_item->name, info->prefix, info->flags);
-
}
static int module_sync(int argc, const char **argv, const char *prefix)
@@ -1444,6 +1443,72 @@ static int module_clone(int argc, const char **argv, const char *prefix)
return 0;
}
+static void determine_submodule_update_strategy(struct repository *r,
+ int just_cloned,
+ const char *path,
+ const char *update,
+ struct submodule_update_strategy *out)
+{
+ const struct submodule *sub = submodule_from_path(r, &null_oid, path);
+ char *key;
+ const char *val;
+
+ key = xstrfmt("submodule.%s.update", sub->name);
+
+ if (update) {
+ trace_printf("parsing update");
+ if (parse_submodule_update_strategy(update, out) < 0)
+ die(_("Invalid update mode '%s' for submodule path '%s'"),
+ update, path);
+ } else if (!repo_config_get_string_const(r, key, &val)) {
+ if (parse_submodule_update_strategy(val, out) < 0)
+ die(_("Invalid update mode '%s' configured for submodule path '%s'"),
+ val, path);
+ } else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
+ trace_printf("loaded thing");
+ out->type = sub->update_strategy.type;
+ out->command = sub->update_strategy.command;
+ } else
+ out->type = SM_UPDATE_CHECKOUT;
+
+ if (just_cloned &&
+ (out->type == SM_UPDATE_MERGE ||
+ out->type == SM_UPDATE_REBASE ||
+ out->type == SM_UPDATE_NONE))
+ out->type = SM_UPDATE_CHECKOUT;
+
+ free(key);
+}
+
+static int module_update_module_mode(int argc, const char **argv, const char *prefix)
+{
+ const char *path, *update = NULL;
+ int just_cloned;
+ struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
+
+ if (argc < 3 || argc > 4)
+ die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
+
+ just_cloned = git_config_int("just_cloned", argv[1]);
+ path = argv[2];
+
+ if (argc == 4)
+ update = argv[3];
+
+ determine_submodule_update_strategy(the_repository,
+ just_cloned, path, update,
+ &update_strategy);
+ fputs(submodule_strategy_to_string(&update_strategy), stdout);
+
+ return 0;
+}
+
+struct update_clone_data {
+ const struct submodule *sub;
+ struct object_id oid;
+ unsigned just_cloned;
+};
+
struct submodule_update_clone {
/* index into 'list', the list of submodules to look into for cloning */
int current;
@@ -1463,8 +1528,9 @@ struct submodule_update_clone {
const char *recursive_prefix;
const char *prefix;
- /* Machine-readable status lines to be consumed by git-submodule.sh */
- struct string_list projectlines;
+ /* to be consumed by git-submodule.sh */
+ struct update_clone_data *update_clone;
+ int update_clone_nr; int update_clone_alloc;
/* If we want to stop as fast as possible and return an error */
unsigned quickstop : 1;
@@ -1472,11 +1538,13 @@ struct submodule_update_clone {
/* failed clones to be retried again */
const struct cache_entry **failed_clones;
int failed_clones_nr, failed_clones_alloc;
+
+ int max_jobs;
};
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
NULL, NULL, NULL, \
- STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
+ NULL, 0, 0, 0, NULL, 0, 0, 0}
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
@@ -1570,11 +1638,12 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
strbuf_addf(&sb, "%s/.git", ce->name);
needs_cloning = !file_exists(sb.buf);
- strbuf_reset(&sb);
- strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode,
- oid_to_hex(&ce->oid), ce_stage(ce),
- needs_cloning, ce->name);
- string_list_append(&suc->projectlines, sb.buf);
+ ALLOC_GROW(suc->update_clone, suc->update_clone_nr + 1,
+ suc->update_clone_alloc);
+ oidcpy(&suc->update_clone[suc->update_clone_nr].oid, &ce->oid);
+ suc->update_clone[suc->update_clone_nr].just_cloned = needs_cloning;
+ suc->update_clone[suc->update_clone_nr].sub = sub;
+ suc->update_clone_nr++;
if (!needs_cloning)
goto cleanup;
@@ -1706,8 +1775,8 @@ static int update_clone_task_finished(int result,
return 0;
}
-static int gitmodules_update_clone_config(const char *var, const char *value,
- void *cb)
+static int git_update_clone_config(const char *var, const char *value,
+ void *cb)
{
int *max_jobs = cb;
if (!strcmp(var, "submodule.fetchjobs"))
@@ -1715,11 +1784,44 @@ static int gitmodules_update_clone_config(const char *var, const char *value,
return 0;
}
+static void update_submodule(struct update_clone_data *ucd)
+{
+ fprintf(stdout, "dummy %s %d\t%s\n",
+ oid_to_hex(&ucd->oid),
+ ucd->just_cloned,
+ ucd->sub->path);
+}
+
+static int update_submodules(struct submodule_update_clone *suc)
+{
+ int i;
+
+ run_processes_parallel(suc->max_jobs,
+ update_clone_get_next_task,
+ update_clone_start_failure,
+ update_clone_task_finished,
+ suc);
+
+ /*
+ * We saved the output and put it out all at once now.
+ * That means:
+ * - the listener does not have to interleave their (checkout)
+ * work with our fetching. The writes involved in a
+ * checkout involve more straightforward sequential I/O.
+ * - the listener can avoid doing any work if fetching failed.
+ */
+ if (suc->quickstop)
+ return 1;
+
+ for (i = 0; i < suc->update_clone_nr; i++)
+ update_submodule(&suc->update_clone[i]);
+
+ return 0;
+}
+
static int update_clone(int argc, const char **argv, const char *prefix)
{
const char *update = NULL;
- int max_jobs = 1;
- struct string_list_item *item;
struct pathspec pathspec;
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
@@ -1741,7 +1843,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
OPT_STRING(0, "depth", &suc.depth, "<depth>",
N_("Create a shallow clone truncated to the "
"specified number of revisions")),
- OPT_INTEGER('j', "jobs", &max_jobs,
+ OPT_INTEGER('j', "jobs", &suc.max_jobs,
N_("parallel jobs")),
OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
N_("whether the initial clone should follow the shallow recommendation")),
@@ -1757,8 +1859,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
};
suc.prefix = prefix;
- config_from_gitmodules(gitmodules_update_clone_config, &max_jobs);
- git_config(gitmodules_update_clone_config, &max_jobs);
+ update_clone_config_from_gitmodules(&suc.max_jobs);
+ git_config(git_update_clone_config, &suc.max_jobs);
argc = parse_options(argc, argv, prefix, module_update_clone_options,
git_submodule_helper_usage, 0);
@@ -1773,27 +1875,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
if (pathspec.nr)
suc.warn_if_uninitialized = 1;
- run_processes_parallel(max_jobs,
- update_clone_get_next_task,
- update_clone_start_failure,
- update_clone_task_finished,
- &suc);
-
- /*
- * We saved the output and put it out all at once now.
- * That means:
- * - the listener does not have to interleave their (checkout)
- * work with our fetching. The writes involved in a
- * checkout involve more straightforward sequential I/O.
- * - the listener can avoid doing any work if fetching failed.
- */
- if (suc.quickstop)
- return 1;
-
- for_each_string_list_item(item, &suc.projectlines)
- fprintf(stdout, "%s", item->string);
-
- return 0;
+ return update_submodules(&suc);
}
static int resolve_relative_path(int argc, const char **argv, const char *prefix)
@@ -1939,6 +2021,45 @@ static int push_check(int argc, const char **argv, const char *prefix)
return 0;
}
+static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
+{
+ const struct submodule *sub;
+ const char *path;
+ char *cw;
+ struct repository subrepo;
+
+ if (argc != 2)
+ BUG("submodule--helper connect-gitdir-workingtree <name> <path>");
+
+ path = argv[1];
+
+ sub = submodule_from_path(the_repository, &null_oid, path);
+ if (!sub)
+ BUG("We could get the submodule handle before?");
+
+ if (repo_submodule_init(&subrepo, the_repository, path))
+ die(_("could not get a repository handle for submodule '%s'"), path);
+
+ if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) {
+ char *cfg_file, *abs_path;
+ const char *rel_path;
+ struct strbuf sb = STRBUF_INIT;
+
+ cfg_file = repo_git_path(&subrepo, "config");
+
+ abs_path = absolute_pathdup(path);
+ rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
+
+ git_config_set_in_file(cfg_file, "core.worktree", rel_path);
+
+ free(cfg_file);
+ free(abs_path);
+ strbuf_release(&sb);
+ }
+
+ return 0;
+}
+
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
{
int i;
@@ -2016,7 +2137,9 @@ static struct cmd_struct commands[] = {
{"list", module_list, 0},
{"name", module_name, 0},
{"clone", module_clone, 0},
+ {"update-module-mode", module_update_module_mode, 0},
{"update-clone", update_clone, 0},
+ {"ensure-core-worktree", ensure_core_worktree, 0},
{"relative-path", resolve_relative_path, 0},
{"resolve-relative-url", resolve_relative_url, 0},
{"resolve-relative-url-test", resolve_relative_url_test, 0},
diff --git a/builtin/tag.c b/builtin/tag.c
index 5d0dd11240..9a19ffb49f 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -10,6 +10,7 @@
#include "config.h"
#include "builtin.h"
#include "refs.h"
+#include "object-store.h"
#include "tag.h"
#include "run-command.h"
#include "parse-options.h"
@@ -312,7 +313,7 @@ static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
}
free(buf);
- if ((c = lookup_commit_reference(oid)) != NULL)
+ if ((c = lookup_commit_reference(the_repository, oid)) != NULL)
strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
break;
case OBJ_TREE:
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 300eb59657..58652229f2 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,5 +1,6 @@
#include "builtin.h"
#include "config.h"
+#include "object-store.h"
static char *create_temp_file(struct object_id *oid)
{
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 6e81ca8ca2..30d9413b4b 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "cache.h"
#include "config.h"
+#include "object-store.h"
#include "object.h"
#include "delta.h"
#include "pack.h"
@@ -253,7 +254,7 @@ static void write_object(unsigned nr, enum object_type type,
added_object(nr, type, buf, size);
free(buf);
- blob = lookup_blob(&obj_list[nr].oid);
+ blob = lookup_blob(the_repository, &obj_list[nr].oid);
if (blob)
blob->object.flags |= FLAG_WRITTEN;
else
@@ -264,7 +265,8 @@ static void write_object(unsigned nr, enum object_type type,
int eaten;
hash_object_file(buf, size, type_name(type), &obj_list[nr].oid);
added_object(nr, type, buf, size);
- obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf,
+ obj = parse_object_buffer(the_repository, &obj_list[nr].oid,
+ type, size, buf,
&eaten);
if (!obj)
die("invalid %s", type_name(type));
@@ -330,7 +332,7 @@ static int resolve_against_held(unsigned nr, const struct object_id *base,
{
struct object *obj;
struct obj_buffer *obj_buffer;
- obj = lookup_object(base->hash);
+ obj = lookup_object(the_repository, base->hash);
if (!obj)
return 0;
obj_buffer = lookup_object_buffer(obj);
@@ -512,7 +514,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
int i;
struct object_id oid;
- check_replace_refs = 0;
+ read_replace_refs = 0;
git_config(git_default_config, NULL);
diff --git a/builtin/update-index.c b/builtin/update-index.c
index a8709a26ec..fe84003b4f 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -268,15 +268,14 @@ static int process_lstat_error(const char *path, int err)
static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st)
{
- int option, size;
+ int option;
struct cache_entry *ce;
/* Was the old index entry already up-to-date? */
if (old && !ce_stage(old) && !ce_match_stat(old, st, 0))
return 0;
- size = cache_entry_size(len);
- ce = xcalloc(1, size);
+ ce = make_empty_cache_entry(&the_index, len);
memcpy(ce->name, path, len);
ce->ce_flags = create_ce_flags(0);
ce->ce_namelen = len;
@@ -285,13 +284,13 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
if (index_path(&ce->oid, path, st,
info_only ? 0 : HASH_WRITE_OBJECT)) {
- free(ce);
+ discard_cache_entry(ce);
return -1;
}
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
if (add_cache_entry(ce, option)) {
- free(ce);
+ discard_cache_entry(ce);
return error("%s: cannot add to the index - missing --add option?", path);
}
return 0;
@@ -402,15 +401,14 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
const char *path, int stage)
{
- int size, len, option;
+ int len, option;
struct cache_entry *ce;
if (!verify_path(path, mode))
return error("Invalid path '%s'", path);
len = strlen(path);
- size = cache_entry_size(len);
- ce = xcalloc(1, size);
+ ce = make_empty_cache_entry(&the_index, len);
oidcpy(&ce->oid, oid);
memcpy(ce->name, path, len);
@@ -492,6 +490,7 @@ static void update_one(const char *path)
static void read_index_info(int nul_term_line)
{
+ const int hexsz = the_hash_algo->hexsz;
struct strbuf buf = STRBUF_INIT;
struct strbuf uq = STRBUF_INIT;
strbuf_getline_fn getline_fn;
@@ -529,7 +528,7 @@ static void read_index_info(int nul_term_line)
mode = ul;
tab = strchr(ptr, '\t');
- if (!tab || tab - ptr < GIT_SHA1_HEXSZ + 1)
+ if (!tab || tab - ptr < hexsz + 1)
goto bad_line;
if (tab[-2] == ' ' && '0' <= tab[-1] && tab[-1] <= '3') {
@@ -542,8 +541,8 @@ static void read_index_info(int nul_term_line)
ptr = tab + 1; /* point at the head of path */
}
- if (get_oid_hex(tab - GIT_SHA1_HEXSZ, &oid) ||
- tab[-(GIT_SHA1_HEXSZ + 1)] != ' ')
+ if (get_oid_hex(tab - hexsz, &oid) ||
+ tab[-(hexsz + 1)] != ' ')
goto bad_line;
path_name = ptr;
@@ -571,7 +570,7 @@ static void read_index_info(int nul_term_line)
* ptr[-1] points at tab,
* ptr[-41] is at the beginning of sha1
*/
- ptr[-(GIT_SHA1_HEXSZ + 2)] = ptr[-1] = 0;
+ ptr[-(hexsz + 2)] = ptr[-1] = 0;
if (add_cacheinfo(mode, &oid, path_name, stage))
die("git update-index: unable to update %s",
path_name);
@@ -599,7 +598,6 @@ static struct cache_entry *read_one_ent(const char *which,
{
unsigned mode;
struct object_id oid;
- int size;
struct cache_entry *ce;
if (get_tree_entry(ent, path, &oid, &mode)) {
@@ -612,8 +610,7 @@ static struct cache_entry *read_one_ent(const char *which,
error("%s: not a blob in %s branch.", path, which);
return NULL;
}
- size = cache_entry_size(namelen);
- ce = xcalloc(1, size);
+ ce = make_empty_cache_entry(&the_index, namelen);
oidcpy(&ce->oid, &oid);
memcpy(ce->name, path, namelen);
@@ -690,8 +687,8 @@ static int unresolve_one(const char *path)
error("%s: cannot add their version to the index.", path);
ret = -1;
free_return:
- free(ce_2);
- free(ce_3);
+ discard_cache_entry(ce_2);
+ discard_cache_entry(ce_3);
return ret;
}
@@ -751,14 +748,14 @@ static int do_reupdate(int ac, const char **av,
int save_nr;
char *path;
- if (ce_stage(ce) || !ce_path_match(ce, &pathspec, NULL))
+ if (ce_stage(ce) || !ce_path_match(&the_index, ce, &pathspec, NULL))
continue;
if (has_head)
old = read_one_ent(NULL, &head_oid,
ce->name, ce_namelen(ce), 0);
if (old && ce->ce_mode == old->ce_mode &&
!oidcmp(&ce->oid, &old->oid)) {
- free(old);
+ discard_cache_entry(old);
continue; /* unchanged */
}
/* Be careful. The working tree may not have the
@@ -769,7 +766,7 @@ static int do_reupdate(int ac, const char **av,
path = xstrdup(ce->name);
update_one(path);
free(path);
- free(old);
+ discard_cache_entry(old);
if (save_nr != active_nr)
goto redo;
}
@@ -826,6 +823,7 @@ static int parse_new_style_cacheinfo(const char *arg,
{
unsigned long ul;
char *endp;
+ const char *p;
if (!arg)
return -1;
@@ -836,9 +834,9 @@ static int parse_new_style_cacheinfo(const char *arg,
return -1; /* not a new-style cacheinfo */
*mode = ul;
endp++;
- if (get_oid_hex(endp, oid) || endp[GIT_SHA1_HEXSZ] != ',')
+ if (parse_oid_hex(endp, oid, &p) || *p != ',')
return -1;
- *path = endp + GIT_SHA1_HEXSZ + 1;
+ *path = p + 1;
return 0;
}
@@ -971,9 +969,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
(parse_opt_cb *) cacheinfo_callback},
- {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, N_("(+/-)x"),
+ {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+|-)x",
N_("override the executable bit of the listed files"),
- PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
+ PARSE_OPT_NONEG,
chmod_callback},
{OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL,
N_("mark files as \"not changing\""),
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 84532ae9a9..25d9116356 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -43,7 +43,8 @@ int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
}
/* parse all options sent by the client */
- return write_archive(sent_argv.argc, sent_argv.argv, prefix, NULL, 1);
+ return write_archive(sent_argv.argc, sent_argv.argv, prefix,
+ the_repository, NULL, 1);
}
__attribute__((format (printf, 1, 2)))
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index decde5a3b1..42dc4da5a1 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -31,7 +31,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
};
packet_trace_identity("upload-pack");
- check_replace_refs = 0;
+ read_replace_refs = 0;
argc = parse_options(argc, argv, NULL, options, upload_pack_usage, 0);
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index dcdaada111..7772c07ed7 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -8,6 +8,8 @@
#include "cache.h"
#include "config.h"
#include "builtin.h"
+#include "object-store.h"
+#include "repository.h"
#include "commit.h"
#include "run-command.h"
#include <signal.h>
@@ -26,7 +28,8 @@ static int run_gpg_verify(const struct object_id *oid, const char *buf, unsigned
memset(&signature_check, 0, sizeof(signature_check));
- ret = check_commit_signature(lookup_commit(oid), &signature_check);
+ ret = check_commit_signature(lookup_commit(the_repository, oid),
+ &signature_check);
print_signature_buffer(&signature_check, flags);
signature_check_clear(&signature_check);
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 5c7d2bb180..41e7714396 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -27,6 +27,7 @@ static const char * const worktree_usage[] = {
struct add_opts {
int force;
int detach;
+ int quiet;
int checkout;
int keep_locked;
};
@@ -303,9 +304,13 @@ static int add_worktree(const char *path, const char *refname,
if (!is_branch)
argv_array_pushl(&cp.args, "update-ref", "HEAD",
oid_to_hex(&commit->object.oid), NULL);
- else
+ else {
argv_array_pushl(&cp.args, "symbolic-ref", "HEAD",
symref.buf, NULL);
+ if (opts->quiet)
+ argv_array_push(&cp.args, "--quiet");
+ }
+
cp.env = child_env.argv;
ret = run_command(&cp);
if (ret)
@@ -315,6 +320,8 @@ static int add_worktree(const char *path, const char *refname,
cp.argv = NULL;
argv_array_clear(&cp.args);
argv_array_pushl(&cp.args, "reset", "--hard", NULL);
+ if (opts->quiet)
+ argv_array_push(&cp.args, "--quiet");
cp.env = child_env.argv;
ret = run_command(&cp);
if (ret)
@@ -412,7 +419,7 @@ static const char *dwim_branch(const char *path, const char **new_branch)
if (guess_remote) {
struct object_id oid;
const char *remote =
- unique_tracking_name(*new_branch, &oid);
+ unique_tracking_name(*new_branch, &oid, NULL);
return remote;
}
return NULL;
@@ -437,6 +444,7 @@ static int add(int ac, const char **av, const char *prefix)
OPT_BOOL(0, "detach", &opts.detach, N_("detach HEAD at named commit")),
OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
OPT_BOOL(0, "lock", &opts.keep_locked, N_("keep the new working tree locked")),
+ OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
OPT_PASSTHRU(0, "track", &opt_track, NULL,
N_("set up tracking mode (see git-branch(1))"),
PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
@@ -484,15 +492,15 @@ static int add(int ac, const char **av, const char *prefix)
commit = lookup_commit_reference_by_name(branch);
if (!commit) {
- remote = unique_tracking_name(branch, &oid);
+ remote = unique_tracking_name(branch, &oid, NULL);
if (remote) {
new_branch = branch;
branch = remote;
}
}
}
-
- print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force);
+ if (!opts.quiet)
+ print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force);
if (new_branch) {
struct child_process cp = CHILD_PROCESS_INIT;
@@ -500,6 +508,8 @@ static int add(int ac, const char **av, const char *prefix)
argv_array_push(&cp.args, "branch");
if (new_branch_force)
argv_array_push(&cp.args, "--force");
+ if (opts.quiet)
+ argv_array_push(&cp.args, "--quiet");
argv_array_push(&cp.args, new_branch);
argv_array_push(&cp.args, branch);
if (opt_track)
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index c9d3c544e7..cdcbf8264e 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -24,9 +24,8 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
struct option write_tree_options[] = {
OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"),
WRITE_TREE_MISSING_OK),
- { OPTION_STRING, 0, "prefix", &prefix, N_("<prefix>/"),
- N_("write tree object for a subdirectory <prefix>") ,
- PARSE_OPT_LITERAL_ARGHELP },
+ OPT_STRING(0, "prefix", &prefix, N_("<prefix>/"),
+ N_("write tree object for a subdirectory <prefix>")),
{ OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL,
N_("only useful for debugging"),
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL,