summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/bundle.c1
-rw-r--r--builtin/cat-file.c218
-rw-r--r--builtin/checkout.c15
-rw-r--r--builtin/clone.c15
-rw-r--r--builtin/commit-graph.c6
-rw-r--r--builtin/config.c4
-rw-r--r--builtin/fast-export.c2
-rw-r--r--builtin/fast-import.c14
-rw-r--r--builtin/fetch.c246
-rw-r--r--builtin/gc.c1
-rw-r--r--builtin/grep.c4
-rw-r--r--builtin/hash-object.c2
-rw-r--r--builtin/help.c63
-rw-r--r--builtin/index-pack.c21
-rw-r--r--builtin/merge-base.c5
-rw-r--r--builtin/merge-recursive.c2
-rw-r--r--builtin/mktag.c9
-rw-r--r--builtin/mktree.c2
-rw-r--r--builtin/name-rev.c71
-rw-r--r--builtin/notes.c2
-rw-r--r--builtin/pack-objects.c35
-rw-r--r--builtin/read-tree.c14
-rw-r--r--builtin/rebase.c2
-rw-r--r--builtin/receive-pack.c11
-rw-r--r--builtin/reflog.c455
-rw-r--r--builtin/remote.c47
-rw-r--r--builtin/repack.c12
-rw-r--r--builtin/replace.c4
-rw-r--r--builtin/rev-list.c29
-rw-r--r--builtin/shortlog.c10
-rw-r--r--builtin/sparse-checkout.c4
-rw-r--r--builtin/stash.c19
-rw-r--r--builtin/submodule--helper.c253
-rw-r--r--builtin/tag.c2
-rw-r--r--builtin/unpack-objects.c8
35 files changed, 795 insertions, 813 deletions
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 5a85d7cd0f..2adad545a2 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -93,6 +93,7 @@ static int cmd_bundle_create(int argc, const char **argv, const char *prefix) {
if (!startup_info->have_repository)
die(_("Need a repository to create a bundle."));
ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
+ strvec_clear(&pack_opts);
free(bundle_file);
return ret;
}
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 7b3f42950e..50cf38999d 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -17,14 +17,20 @@
#include "object-store.h"
#include "promisor-remote.h"
+enum batch_mode {
+ BATCH_MODE_CONTENTS,
+ BATCH_MODE_INFO,
+ BATCH_MODE_QUEUE_AND_DISPATCH,
+};
+
struct batch_options {
int enabled;
int follow_symlinks;
- int print_contents;
+ enum batch_mode batch_mode;
int buffer_output;
int all_objects;
int unordered;
- int cmdmode; /* may be 'w' or 'c' for --filters or --textconv */
+ int transform_mode; /* may be 'w' or 'c' for --filters or --textconv */
const char *format;
};
@@ -150,7 +156,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
break;
case 0:
- if (type_from_string(exp_type) == OBJ_BLOB) {
+ {
+ enum object_type exp_type_id = type_from_string(exp_type);
+
+ if (exp_type_id == OBJ_BLOB) {
struct object_id blob_oid;
if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {
char *buffer = read_object_file(&oid, &type,
@@ -172,10 +181,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
* fall-back to the usual case.
*/
}
- buf = read_object_with_reference(the_repository,
- &oid, exp_type, &size, NULL);
+ buf = read_object_with_reference(the_repository, &oid,
+ exp_type_id, &size, NULL);
break;
-
+ }
default:
die("git cat-file: unknown option: %s", exp_type);
}
@@ -302,19 +311,19 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
if (data->type == OBJ_BLOB) {
if (opt->buffer_output)
fflush(stdout);
- if (opt->cmdmode) {
+ if (opt->transform_mode) {
char *contents;
unsigned long size;
if (!data->rest)
die("missing path for '%s'", oid_to_hex(oid));
- if (opt->cmdmode == 'w') {
+ if (opt->transform_mode == 'w') {
if (filter_object(data->rest, 0100644, oid,
&contents, &size))
die("could not convert '%s' %s",
oid_to_hex(oid), data->rest);
- } else if (opt->cmdmode == 'c') {
+ } else if (opt->transform_mode == 'c') {
enum object_type type;
if (!textconv_object(the_repository,
data->rest, 0100644, oid,
@@ -326,7 +335,7 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
die("could not convert '%s' %s",
oid_to_hex(oid), data->rest);
} else
- BUG("invalid cmdmode: %c", opt->cmdmode);
+ BUG("invalid transform_mode: %c", opt->transform_mode);
batch_write(opt, contents, size);
free(contents);
} else {
@@ -351,6 +360,13 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
}
}
+static void print_default_format(struct strbuf *scratch, struct expand_data *data)
+{
+ strbuf_addf(scratch, "%s %s %"PRIuMAX"\n", oid_to_hex(&data->oid),
+ type_name(data->type),
+ (uintmax_t)data->size);
+}
+
/*
* If "pack" is non-NULL, then "offset" is the byte offset within the pack from
* which the object may be accessed (though note that we may also rely on
@@ -382,11 +398,17 @@ static void batch_object_write(const char *obj_name,
}
strbuf_reset(scratch);
- strbuf_expand(scratch, opt->format, expand_format, data);
- strbuf_addch(scratch, '\n');
+
+ if (!opt->format) {
+ print_default_format(scratch, data);
+ } else {
+ strbuf_expand(scratch, opt->format, expand_format, data);
+ strbuf_addch(scratch, '\n');
+ }
+
batch_write(opt, scratch->buf, scratch->len);
- if (opt->print_contents) {
+ if (opt->batch_mode == BATCH_MODE_CONTENTS) {
print_object_or_die(opt, data);
batch_write(opt, "\n", 1);
}
@@ -508,6 +530,137 @@ static int batch_unordered_packed(const struct object_id *oid,
data);
}
+typedef void (*parse_cmd_fn_t)(struct batch_options *, const char *,
+ struct strbuf *, struct expand_data *);
+
+struct queued_cmd {
+ parse_cmd_fn_t fn;
+ char *line;
+};
+
+static void parse_cmd_contents(struct batch_options *opt,
+ const char *line,
+ struct strbuf *output,
+ struct expand_data *data)
+{
+ opt->batch_mode = BATCH_MODE_CONTENTS;
+ batch_one_object(line, output, opt, data);
+}
+
+static void parse_cmd_info(struct batch_options *opt,
+ const char *line,
+ struct strbuf *output,
+ struct expand_data *data)
+{
+ opt->batch_mode = BATCH_MODE_INFO;
+ batch_one_object(line, output, opt, data);
+}
+
+static void dispatch_calls(struct batch_options *opt,
+ struct strbuf *output,
+ struct expand_data *data,
+ struct queued_cmd *cmd,
+ int nr)
+{
+ int i;
+
+ if (!opt->buffer_output)
+ die(_("flush is only for --buffer mode"));
+
+ for (i = 0; i < nr; i++)
+ cmd[i].fn(opt, cmd[i].line, output, data);
+
+ fflush(stdout);
+}
+
+static void free_cmds(struct queued_cmd *cmd, size_t *nr)
+{
+ size_t i;
+
+ for (i = 0; i < *nr; i++)
+ FREE_AND_NULL(cmd[i].line);
+
+ *nr = 0;
+}
+
+
+static const struct parse_cmd {
+ const char *name;
+ parse_cmd_fn_t fn;
+ unsigned takes_args;
+} commands[] = {
+ { "contents", parse_cmd_contents, 1},
+ { "info", parse_cmd_info, 1},
+ { "flush", NULL, 0},
+};
+
+static void batch_objects_command(struct batch_options *opt,
+ struct strbuf *output,
+ struct expand_data *data)
+{
+ struct strbuf input = STRBUF_INIT;
+ struct queued_cmd *queued_cmd = NULL;
+ size_t alloc = 0, nr = 0;
+
+ while (!strbuf_getline(&input, stdin)) {
+ int i;
+ const struct parse_cmd *cmd = NULL;
+ const char *p = NULL, *cmd_end;
+ struct queued_cmd call = {0};
+
+ if (!input.len)
+ die(_("empty command in input"));
+ if (isspace(*input.buf))
+ die(_("whitespace before command: '%s'"), input.buf);
+
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ if (!skip_prefix(input.buf, commands[i].name, &cmd_end))
+ continue;
+
+ cmd = &commands[i];
+ if (cmd->takes_args) {
+ if (*cmd_end != ' ')
+ die(_("%s requires arguments"),
+ commands[i].name);
+
+ p = cmd_end + 1;
+ } else if (*cmd_end) {
+ die(_("%s takes no arguments"),
+ commands[i].name);
+ }
+
+ break;
+ }
+
+ if (!cmd)
+ die(_("unknown command: '%s'"), input.buf);
+
+ if (!strcmp(cmd->name, "flush")) {
+ dispatch_calls(opt, output, data, queued_cmd, nr);
+ free_cmds(queued_cmd, &nr);
+ } else if (!opt->buffer_output) {
+ cmd->fn(opt, p, output, data);
+ } else {
+ ALLOC_GROW(queued_cmd, nr + 1, alloc);
+ call.fn = cmd->fn;
+ call.line = xstrdup_or_null(p);
+ queued_cmd[nr++] = call;
+ }
+ }
+
+ if (opt->buffer_output &&
+ nr &&
+ !git_env_bool("GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT", 0)) {
+ dispatch_calls(opt, output, data, queued_cmd, nr);
+ free_cmds(queued_cmd, &nr);
+ }
+
+ free(queued_cmd);
+ strbuf_release(&input);
+}
+
+#define DEFAULT_FORMAT "%(objectname) %(objecttype) %(objectsize)"
+
static int batch_objects(struct batch_options *opt)
{
struct strbuf input = STRBUF_INIT;
@@ -516,9 +669,6 @@ static int batch_objects(struct batch_options *opt)
int save_warning;
int retval = 0;
- if (!opt->format)
- opt->format = "%(objectname) %(objecttype) %(objectsize)";
-
/*
* Expand once with our special mark_query flag, which will prime the
* object_info to be handed to oid_object_info_extended for each
@@ -526,17 +676,22 @@ static int batch_objects(struct batch_options *opt)
*/
memset(&data, 0, sizeof(data));
data.mark_query = 1;
- strbuf_expand(&output, opt->format, expand_format, &data);
+ strbuf_expand(&output,
+ opt->format ? opt->format : DEFAULT_FORMAT,
+ expand_format,
+ &data);
data.mark_query = 0;
strbuf_release(&output);
- if (opt->cmdmode)
+ if (opt->transform_mode)
data.split_on_whitespace = 1;
+ if (opt->format && !strcmp(opt->format, DEFAULT_FORMAT))
+ opt->format = NULL;
/*
* If we are printing out the object, then always fill in the type,
* since we will want to decide whether or not to stream.
*/
- if (opt->print_contents)
+ if (opt->batch_mode == BATCH_MODE_CONTENTS)
data.info.typep = &data.type;
if (opt->all_objects) {
@@ -590,6 +745,11 @@ static int batch_objects(struct batch_options *opt)
save_warning = warn_on_object_refname_ambiguity;
warn_on_object_refname_ambiguity = 0;
+ if (opt->batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH) {
+ batch_objects_command(opt, &output, &data);
+ goto cleanup;
+ }
+
while (strbuf_getline(&input, stdin) != EOF) {
if (data.split_on_whitespace) {
/*
@@ -608,6 +768,7 @@ static int batch_objects(struct batch_options *opt)
batch_one_object(input.buf, &output, opt, &data);
}
+ cleanup:
strbuf_release(&input);
strbuf_release(&output);
warn_on_object_refname_ambiguity = save_warning;
@@ -635,7 +796,16 @@ static int batch_option_callback(const struct option *opt,
}
bo->enabled = 1;
- bo->print_contents = !strcmp(opt->long_name, "batch");
+
+ if (!strcmp(opt->long_name, "batch"))
+ bo->batch_mode = BATCH_MODE_CONTENTS;
+ else if (!strcmp(opt->long_name, "batch-check"))
+ bo->batch_mode = BATCH_MODE_INFO;
+ else if (!strcmp(opt->long_name, "batch-command"))
+ bo->batch_mode = BATCH_MODE_QUEUE_AND_DISPATCH;
+ else
+ BUG("%s given to batch-option-callback", opt->long_name);
+
bo->format = arg;
return 0;
@@ -654,7 +824,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
N_("git cat-file <type> <object>"),
N_("git cat-file (-e | -p) <object>"),
N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
- N_("git cat-file (--batch | --batch-check) [--batch-all-objects]\n"
+ N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
" [--buffer] [--follow-symlinks] [--unordered]\n"
" [--textconv | --filters]"),
N_("git cat-file (--textconv | --filters)\n"
@@ -683,6 +853,10 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
N_("like --batch, but don't emit <contents>"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
batch_option_callback),
+ OPT_CALLBACK_F(0, "batch-command", &batch, N_("format"),
+ N_("read commands from stdin"),
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+ batch_option_callback),
OPT_CMDMODE(0, "batch-all-objects", &opt,
N_("with --batch[-check]: ignores stdin, batches all known objects"), 'b'),
/* Batch-specific options */
@@ -742,7 +916,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
/* Return early if we're in batch mode? */
if (batch.enabled) {
if (opt_cw)
- batch.cmdmode = opt;
+ batch.transform_mode = opt;
else if (opt && opt != 'b')
usage_msg_optf(_("'-%c' is incompatible with batch mode"),
usage, options, opt);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 9244827ca0..797681481d 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -303,7 +303,7 @@ static int checkout_merged(int pos, const struct checkout *state,
* (it also writes the merge result to the object database even
* when it may contain conflicts).
*/
- if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
+ if (write_object_file(result_buf.ptr, result_buf.size, OBJ_BLOB, &oid))
die(_("Unable to add merge result for '%s'"), path);
free(result_buf.ptr);
ce = make_transient_cache_entry(mode, &oid, path, 2, ce_mem_pool);
@@ -738,6 +738,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
struct tree_desc trees[2];
struct tree *tree;
struct unpack_trees_options topts;
+ const struct object_id *old_commit_oid;
memset(&topts, 0, sizeof(topts));
topts.head_idx = -1;
@@ -765,9 +766,15 @@ static int merge_working_tree(const struct checkout_opts *opts,
&new_branch_info->commit->object.oid :
&new_branch_info->oid, NULL);
topts.preserve_ignored = !opts->overwrite_ignore;
- tree = parse_tree_indirect(old_branch_info->commit ?
- &old_branch_info->commit->object.oid :
- the_hash_algo->empty_tree);
+
+ old_commit_oid = old_branch_info->commit ?
+ &old_branch_info->commit->object.oid :
+ the_hash_algo->empty_tree;
+ tree = parse_tree_indirect(old_commit_oid);
+ if (!tree)
+ die(_("unable to parse commit %s"),
+ oid_to_hex(old_commit_oid));
+
init_tree_desc(&trees[0], tree->buffer, tree->size);
parse_tree(new_tree);
tree = new_tree;
diff --git a/builtin/clone.c b/builtin/clone.c
index a572cda503..5231656379 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -33,6 +33,7 @@
#include "packfile.h"
#include "list-objects-filter-options.h"
#include "hook.h"
+#include "bundle.h"
/*
* Overall FIXMEs:
@@ -700,6 +701,8 @@ static int checkout(int submodule_progress, int filter_submodules)
init_checkout_metadata(&opts.meta, head, &oid, NULL);
tree = parse_tree_indirect(&oid);
+ if (!tree)
+ die(_("unable to parse commit %s"), oid_to_hex(&oid));
parse_tree(tree);
init_tree_desc(&t, tree->buffer, tree->size);
if (unpack_trees(1, &t, &opts) < 0)
@@ -1170,6 +1173,18 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
warning(_("--local is ignored"));
transport->cloning = 1;
+ if (is_bundle) {
+ struct bundle_header header = BUNDLE_HEADER_INIT;
+ int fd = read_bundle_header(path, &header);
+ int has_filter = header.filter.choice != LOFC_DISABLED;
+
+ if (fd > 0)
+ close(fd);
+ bundle_header_release(&header);
+ if (has_filter)
+ die(_("cannot clone from filtered bundle"));
+ }
+
transport_set_option(transport, TRANS_OPT_KEEP, "yes");
if (reject_shallow)
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 4247fbde95..51c4040ea6 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -192,7 +192,7 @@ static int git_commit_graph_write_config(const char *var, const char *value,
static int graph_write(int argc, const char **argv)
{
- struct string_list pack_indexes = STRING_LIST_INIT_NODUP;
+ struct string_list pack_indexes = STRING_LIST_INIT_DUP;
struct strbuf buf = STRBUF_INIT;
struct oidset commits = OIDSET_INIT;
struct object_directory *odb = NULL;
@@ -273,8 +273,8 @@ static int graph_write(int argc, const char **argv)
if (opts.stdin_packs) {
while (strbuf_getline(&buf, stdin) != EOF)
- string_list_append(&pack_indexes,
- strbuf_detach(&buf, NULL));
+ string_list_append_nodup(&pack_indexes,
+ strbuf_detach(&buf, NULL));
} else if (opts.stdin_commits) {
oidset_init(&commits, 0);
if (opts.progress)
diff --git a/builtin/config.c b/builtin/config.c
index 542d8d02b2..e7b88a9c08 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -151,7 +151,7 @@ static struct option builtin_config_options[] = {
OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR),
OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL),
OPT_GROUP(N_("Type")),
- OPT_CALLBACK('t', "type", &type, "", N_("value is given this type"), option_parse_type),
+ OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type),
OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL),
OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT),
OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
@@ -612,7 +612,7 @@ static int get_urlmatch(const char *var, const char *url)
strbuf_release(&matched->value);
}
- string_list_clear(&config.vars, 1);
+ urlmatch_config_release(&config);
string_list_clear(&values, 1);
free(config.url.url);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 510139e9b5..a7d72697fb 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -300,7 +300,7 @@ static void export_blob(const struct object_id *oid)
if (!buf)
die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(the_repository, oid, buf, size,
- type_name(type), NULL) < 0)
+ type) < 0)
die("oid mismatch in blob %s", oid_to_hex(oid));
object = parse_object_buffer(the_repository, oid, type,
size, buf, &eaten);
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index b7105fcad9..28d3193c38 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -865,7 +865,7 @@ static void end_packfile(void)
struct tag *t;
close_pack_windows(pack_data);
- finalize_hashfile(pack_file, cur_pack_oid.hash, 0);
+ finalize_hashfile(pack_file, cur_pack_oid.hash, FSYNC_COMPONENT_PACK, 0);
fixup_pack_header_footer(pack_data->pack_fd, pack_data->hash,
pack_data->pack_name, object_count,
cur_pack_oid.hash, pack_size);
@@ -944,8 +944,8 @@ static int store_object(
git_hash_ctx c;
git_zstream s;
- hdrlen = xsnprintf((char *)hdr, sizeof(hdr), "%s %lu",
- type_name(type), (unsigned long)dat->len) + 1;
+ hdrlen = format_object_header((char *)hdr, sizeof(hdr), type,
+ dat->len);
the_hash_algo->init_fn(&c);
the_hash_algo->update_fn(&c, hdr, hdrlen);
the_hash_algo->update_fn(&c, dat->buf, dat->len);
@@ -1098,7 +1098,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
hashfile_checkpoint(pack_file, &checkpoint);
offset = checkpoint.offset;
- hdrlen = xsnprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1;
+ hdrlen = format_object_header((char *)out_buf, out_sz, OBJ_BLOB, len);
the_hash_algo->init_fn(&c);
the_hash_algo->update_fn(&c, out_buf, hdrlen);
@@ -2490,7 +2490,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
unsigned long size;
char *buf = read_object_with_reference(the_repository,
&commit_oid,
- commit_type, &size,
+ OBJ_COMMIT, &size,
&commit_oid);
if (!buf || size < the_hash_algo->hexsz + 6)
die("Not a valid commit: %s", p);
@@ -2562,7 +2562,7 @@ static void parse_from_existing(struct branch *b)
char *buf;
buf = read_object_with_reference(the_repository,
- &b->oid, commit_type, &size,
+ &b->oid, OBJ_COMMIT, &size,
&b->oid);
parse_from_commit(b, buf, size);
free(buf);
@@ -2658,7 +2658,7 @@ static struct hash_list *parse_merge(unsigned int *count)
unsigned long size;
char *buf = read_object_with_reference(the_repository,
&n->oid,
- commit_type,
+ OBJ_COMMIT,
&size, &n->oid);
if (!buf || size < the_hash_algo->hexsz + 6)
die("Not a valid commit: %s", from);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 95832ba1df..9b4018f62c 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -349,7 +349,19 @@ static void clear_item(struct refname_hash_entry *item)
item->ignore = 1;
}
+
+static void add_already_queued_tags(const char *refname,
+ const struct object_id *old_oid,
+ const struct object_id *new_oid,
+ void *cb_data)
+{
+ struct hashmap *queued_tags = cb_data;
+ if (starts_with(refname, "refs/tags/") && new_oid)
+ (void) refname_hash_add(queued_tags, refname, new_oid);
+}
+
static void find_non_local_tags(const struct ref *refs,
+ struct ref_transaction *transaction,
struct ref **head,
struct ref ***tail)
{
@@ -367,6 +379,16 @@ static void find_non_local_tags(const struct ref *refs,
create_fetch_oidset(head, &fetch_oids);
for_each_ref(add_one_refname, &existing_refs);
+
+ /*
+ * If we already have a transaction, then we need to filter out all
+ * tags which have already been queued up.
+ */
+ if (transaction)
+ ref_transaction_for_each_queued_update(transaction,
+ add_already_queued_tags,
+ &existing_refs);
+
for (ref = refs; ref; ref = ref->next) {
if (!starts_with(ref->name, "refs/tags/"))
continue;
@@ -600,7 +622,7 @@ static struct ref *get_ref_map(struct remote *remote,
/* also fetch all tags */
get_fetch_map(remote_refs, tag_refspec, &tail, 0);
else if (tags == TAGS_DEFAULT && *autotags)
- find_non_local_tags(remote_refs, &ref_map, &tail);
+ find_non_local_tags(remote_refs, NULL, &ref_map, &tail);
/* Now append any refs to be updated opportunistically: */
*tail = orefs;
@@ -1083,23 +1105,18 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
"to avoid this check\n");
static int store_updated_refs(const char *raw_url, const char *remote_name,
- int connectivity_checked, struct ref *ref_map,
- struct worktree **worktrees)
+ int connectivity_checked,
+ struct ref_transaction *transaction, struct ref *ref_map,
+ struct fetch_head *fetch_head, struct worktree **worktrees)
{
- struct fetch_head fetch_head;
int url_len, i, rc = 0;
struct strbuf note = STRBUF_INIT, err = STRBUF_INIT;
- struct ref_transaction *transaction = NULL;
const char *what, *kind;
struct ref *rm;
char *url;
int want_status;
int summary_width = 0;
- rc = open_fetch_head(&fetch_head);
- if (rc)
- return -1;
-
if (verbosity >= 0)
summary_width = transport_summary_width(ref_map);
@@ -1118,14 +1135,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
}
}
- if (atomic_fetch) {
- transaction = ref_transaction_begin(&err);
- if (!transaction) {
- error("%s", err.buf);
- goto abort;
- }
- }
-
prepare_format_display(ref_map);
/*
@@ -1137,7 +1146,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
want_status <= FETCH_HEAD_IGNORE;
want_status++) {
for (rm = ref_map; rm; rm = rm->next) {
- struct commit *commit = NULL;
struct ref *ref = NULL;
if (rm->status == REF_STATUS_REJECT_SHALLOW) {
@@ -1148,21 +1156,34 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
}
/*
- * References in "refs/tags/" are often going to point
- * to annotated tags, which are not part of the
- * commit-graph. We thus only try to look up refs in
- * the graph which are not in that namespace to not
- * regress performance in repositories with many
- * annotated tags.
+ * When writing FETCH_HEAD we need to determine whether
+ * we already have the commit or not. If not, then the
+ * reference is not for merge and needs to be written
+ * to the reflog after other commits which we already
+ * have. We're not interested in this property though
+ * in case FETCH_HEAD is not to be updated, so we can
+ * skip the classification in that case.
*/
- if (!starts_with(rm->name, "refs/tags/"))
- commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
- if (!commit) {
- commit = lookup_commit_reference_gently(the_repository,
- &rm->old_oid,
- 1);
- if (!commit)
- rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
+ if (fetch_head->fp) {
+ struct commit *commit = NULL;
+
+ /*
+ * References in "refs/tags/" are often going to point
+ * to annotated tags, which are not part of the
+ * commit-graph. We thus only try to look up refs in
+ * the graph which are not in that namespace to not
+ * regress performance in repositories with many
+ * annotated tags.
+ */
+ if (!starts_with(rm->name, "refs/tags/"))
+ commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
+ if (!commit) {
+ commit = lookup_commit_reference_gently(the_repository,
+ &rm->old_oid,
+ 1);
+ if (!commit)
+ rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
+ }
}
if (rm->fetch_head_status != want_status)
@@ -1209,7 +1230,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
strbuf_addf(&note, "'%s' of ", what);
}
- append_fetch_head(&fetch_head, &rm->old_oid,
+ append_fetch_head(fetch_head, &rm->old_oid,
rm->fetch_head_status,
note.buf, url, url_len);
@@ -1241,17 +1262,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
}
}
- if (!rc && transaction) {
- rc = ref_transaction_commit(transaction, &err);
- if (rc) {
- error("%s", err.buf);
- goto abort;
- }
- }
-
- if (!rc)
- commit_fetch_head(&fetch_head);
-
if (rc & STORE_REF_ERROR_DF_CONFLICT)
error(_("some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting "
@@ -1269,9 +1279,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
abort:
strbuf_release(&note);
strbuf_release(&err);
- ref_transaction_free(transaction);
free(url);
- close_fetch_head(&fetch_head);
return rc;
}
@@ -1311,7 +1319,9 @@ static int check_exist_and_connected(struct ref *ref_map)
}
static int fetch_and_consume_refs(struct transport *transport,
+ struct ref_transaction *transaction,
struct ref *ref_map,
+ struct fetch_head *fetch_head,
struct worktree **worktrees)
{
int connectivity_checked = 1;
@@ -1334,7 +1344,8 @@ static int fetch_and_consume_refs(struct transport *transport,
trace2_region_enter("fetch", "consume_refs", the_repository);
ret = store_updated_refs(transport->url, transport->remote->name,
- connectivity_checked, ref_map, worktrees);
+ connectivity_checked, transaction, ref_map,
+ fetch_head, worktrees);
trace2_region_leave("fetch", "consume_refs", the_repository);
out:
@@ -1342,11 +1353,14 @@ out:
return ret;
}
-static int prune_refs(struct refspec *rs, struct ref *ref_map,
+static int prune_refs(struct refspec *rs,
+ struct ref_transaction *transaction,
+ struct ref *ref_map,
const char *raw_url)
{
int url_len, i, result = 0;
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
+ struct strbuf err = STRBUF_INIT;
char *url;
const char *dangling_msg = dry_run
? _(" (%s will become dangling)")
@@ -1366,13 +1380,22 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
url_len = i - 3;
if (!dry_run) {
- struct string_list refnames = STRING_LIST_INIT_NODUP;
+ if (transaction) {
+ for (ref = stale_refs; ref; ref = ref->next) {
+ result = ref_transaction_delete(transaction, ref->name, NULL, 0,
+ "fetch: prune", &err);
+ if (result)
+ goto cleanup;
+ }
+ } else {
+ struct string_list refnames = STRING_LIST_INIT_NODUP;
- for (ref = stale_refs; ref; ref = ref->next)
- string_list_append(&refnames, ref->name);
+ for (ref = stale_refs; ref; ref = ref->next)
+ string_list_append(&refnames, ref->name);
- result = delete_refs("fetch: prune", &refnames, 0);
- string_list_clear(&refnames, 0);
+ result = delete_refs("fetch: prune", &refnames, 0);
+ string_list_clear(&refnames, 0);
+ }
}
if (verbosity >= 0) {
@@ -1393,6 +1416,8 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
}
}
+cleanup:
+ strbuf_release(&err);
free(url);
free_refs(stale_refs);
return result;
@@ -1507,10 +1532,13 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
return transport;
}
-static void backfill_tags(struct transport *transport, struct ref *ref_map,
- struct worktree **worktrees)
+static int backfill_tags(struct transport *transport,
+ struct ref_transaction *transaction,
+ struct ref *ref_map,
+ struct fetch_head *fetch_head,
+ struct worktree **worktrees)
{
- int cannot_reuse;
+ int retcode, cannot_reuse;
/*
* Once we have set TRANS_OPT_DEEPEN_SINCE, we can't unset it
@@ -1529,18 +1557,21 @@ 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_and_consume_refs(transport, ref_map, worktrees);
+ retcode = fetch_and_consume_refs(transport, transaction, ref_map, fetch_head, worktrees);
if (gsecondary) {
transport_disconnect(gsecondary);
gsecondary = NULL;
}
+
+ return retcode;
}
static int do_fetch(struct transport *transport,
struct refspec *rs)
{
- struct ref *ref_map;
+ struct ref_transaction *transaction = NULL;
+ struct ref *ref_map = NULL;
int autotags = (transport->remote->fetch_tags == 1);
int retcode = 0;
const struct ref *remote_refs;
@@ -1548,6 +1579,8 @@ static int do_fetch(struct transport *transport,
TRANSPORT_LS_REFS_OPTIONS_INIT;
int must_list_refs = 1;
struct worktree **worktrees = get_worktrees();
+ struct fetch_head fetch_head = { 0 };
+ struct strbuf err = STRBUF_INIT;
if (tags == TAGS_DEFAULT) {
if (transport->remote->fetch_tags == 2)
@@ -1605,6 +1638,18 @@ static int do_fetch(struct transport *transport,
if (!update_head_ok)
check_not_current_branch(ref_map, worktrees);
+ retcode = open_fetch_head(&fetch_head);
+ if (retcode)
+ goto cleanup;
+
+ if (atomic_fetch) {
+ transaction = ref_transaction_begin(&err);
+ if (!transaction) {
+ retcode = error("%s", err.buf);
+ goto cleanup;
+ }
+ }
+
if (tags == TAGS_DEFAULT && autotags)
transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
if (prune) {
@@ -1614,21 +1659,61 @@ static int do_fetch(struct transport *transport,
* don't care whether --tags was specified.
*/
if (rs->nr) {
- retcode = prune_refs(rs, ref_map, transport->url);
+ retcode = prune_refs(rs, transaction, ref_map, transport->url);
} else {
retcode = prune_refs(&transport->remote->fetch,
- ref_map,
+ transaction, ref_map,
transport->url);
}
if (retcode != 0)
retcode = 1;
}
- if (fetch_and_consume_refs(transport, ref_map, worktrees)) {
- free_refs(ref_map);
+
+ if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head, worktrees)) {
retcode = 1;
goto cleanup;
}
+ /*
+ * If neither --no-tags nor --tags was specified, do automated tag
+ * following.
+ */
+ if (tags == TAGS_DEFAULT && autotags) {
+ struct ref *tags_ref_map = NULL, **tail = &tags_ref_map;
+
+ find_non_local_tags(remote_refs, transaction, &tags_ref_map, &tail);
+ if (tags_ref_map) {
+ /*
+ * If backfilling of tags fails then we want to tell
+ * the user so, but we have to continue regardless to
+ * populate upstream information of the references we
+ * have already fetched above. The exception though is
+ * when `--atomic` is passed: in that case we'll abort
+ * the transaction and don't commit anything.
+ */
+ if (backfill_tags(transport, transaction, tags_ref_map,
+ &fetch_head, worktrees))
+ retcode = 1;
+ }
+
+ free_refs(tags_ref_map);
+ }
+
+ if (transaction) {
+ if (retcode)
+ goto cleanup;
+
+ retcode = ref_transaction_commit(transaction, &err);
+ if (retcode) {
+ error("%s", err.buf);
+ ref_transaction_free(transaction);
+ transaction = NULL;
+ goto cleanup;
+ }
+ }
+
+ commit_fetch_head(&fetch_head);
+
if (set_upstream) {
struct branch *branch = branch_get("HEAD");
struct ref *rm;
@@ -1648,7 +1733,7 @@ static int do_fetch(struct transport *transport,
if (!rm->peer_ref) {
if (source_ref) {
warning(_("multiple branches detected, incompatible with --set-upstream"));
- goto skip;
+ goto cleanup;
} else {
source_ref = rm;
}
@@ -1662,7 +1747,7 @@ static int do_fetch(struct transport *transport,
warning(_("could not set upstream of HEAD to '%s' from '%s' when "
"it does not point to any branch."),
shortname, transport->remote->name);
- goto skip;
+ goto cleanup;
}
if (!strcmp(source_ref->name, "HEAD") ||
@@ -1682,21 +1767,16 @@ static int do_fetch(struct transport *transport,
"you need to specify exactly one branch with the --set-upstream option"));
}
}
-skip:
- free_refs(ref_map);
- /* if neither --no-tags nor --tags was specified, do automated tag
- * following ... */
- if (tags == TAGS_DEFAULT && autotags) {
- struct ref **tail = &ref_map;
- ref_map = NULL;
- find_non_local_tags(remote_refs, &ref_map, &tail);
- if (ref_map)
- backfill_tags(transport, ref_map, worktrees);
- free_refs(ref_map);
+cleanup:
+ if (retcode && transaction) {
+ ref_transaction_abort(transaction, &err);
+ error("%s", err.buf);
}
-cleanup:
+ close_fetch_head(&fetch_head);
+ strbuf_release(&err);
+ free_refs(ref_map);
free_worktrees(worktrees);
return retcode;
}
@@ -2178,13 +2258,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
max_children = fetch_parallel_config;
add_options_to_argv(&options);
- result = fetch_populated_submodules(the_repository,
- &options,
- submodule_prefix,
- recurse_submodules,
- recurse_submodules_default,
- verbosity < 0,
- max_children);
+ result = fetch_submodules(the_repository,
+ &options,
+ submodule_prefix,
+ recurse_submodules,
+ recurse_submodules_default,
+ verbosity < 0,
+ max_children);
strvec_clear(&options);
}
diff --git a/builtin/gc.c b/builtin/gc.c
index ffaf0daf5d..b335cffa33 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -30,7 +30,6 @@
#include "promisor-remote.h"
#include "refs.h"
#include "remote.h"
-#include "object-store.h"
#include "exec-cmd.h"
#include "hook.h"
diff --git a/builtin/grep.c b/builtin/grep.c
index f1a924eade..bcb07ea7f7 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -484,7 +484,7 @@ static int grep_submodule(struct grep_opt *opt,
object_type = oid_object_info(subrepo, oid, NULL);
obj_read_unlock();
data = read_object_with_reference(subrepo,
- oid, tree_type,
+ oid, OBJ_TREE,
&size, NULL);
if (!data)
die(_("unable to read tree (%s)"), oid_to_hex(oid));
@@ -653,7 +653,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
int hit, len;
data = read_object_with_reference(opt->repo,
- &obj->oid, tree_type,
+ &obj->oid, OBJ_TREE,
&size, NULL);
if (!data)
die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 0837849288..fbae878c2b 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -25,7 +25,7 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig
if (strbuf_read(&buf, fd, 4096) < 0)
ret = -1;
else
- ret = hash_object_file_literally(buf.buf, buf.len, type, oid,
+ ret = write_object_file_literally(buf.buf, buf.len, type, oid,
flags);
strbuf_release(&buf);
return ret;
diff --git a/builtin/help.c b/builtin/help.c
index b4f2ad3f94..222f994f86 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -51,9 +51,14 @@ static const char *html_path;
static int verbose = 1;
static enum help_format help_format = HELP_FORMAT_NONE;
static int exclude_guides;
+static int show_external_commands = -1;
+static int show_aliases = -1;
static struct option builtin_help_options[] = {
OPT_CMDMODE('a', "all", &cmd_mode, N_("print all available commands"),
HELP_ACTION_ALL),
+ OPT_BOOL(0, "external-commands", &show_external_commands,
+ N_("show external commands in --all")),
+ OPT_BOOL(0, "aliases", &show_aliases, N_("show aliases in --all")),
OPT_HIDDEN_BOOL(0, "exclude-guides", &exclude_guides, N_("exclude guides")),
OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN),
OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"),
@@ -75,8 +80,8 @@ static struct option builtin_help_options[] = {
};
static const char * const builtin_help_usage[] = {
- N_("git help [-a|--all] [--[no-]verbose]]\n"
- " [[-i|--info] [-m|--man] [-w|--web]] [<command>]"),
+ "git help [-a|--all] [--[no-]verbose]] [--[no-]external-commands] [--[no-]aliases]",
+ N_("git help [[-i|--info] [-m|--man] [-w|--web]] [<command>]"),
"git help [-g|--guides]",
"git help [-c|--config]",
NULL
@@ -574,11 +579,40 @@ static const char *check_git_cmd(const char* cmd)
return cmd;
}
-static void no_extra_argc(int argc)
+static void no_help_format(const char *opt_mode, enum help_format fmt)
+{
+ const char *opt_fmt;
+
+ switch (fmt) {
+ case HELP_FORMAT_NONE:
+ return;
+ case HELP_FORMAT_MAN:
+ opt_fmt = "--man";
+ break;
+ case HELP_FORMAT_INFO:
+ opt_fmt = "--info";
+ break;
+ case HELP_FORMAT_WEB:
+ opt_fmt = "--web";
+ break;
+ default:
+ BUG("unreachable");
+ }
+
+ usage_msg_optf(_("options '%s' and '%s' cannot be used together"),
+ builtin_help_usage, builtin_help_options, opt_mode,
+ opt_fmt);
+}
+
+static void opt_mode_usage(int argc, const char *opt_mode,
+ enum help_format fmt)
{
if (argc)
- usage_msg_opt(_("this option doesn't take any other arguments"),
- builtin_help_usage, builtin_help_options);
+ usage_msg_optf(_("the '%s' option doesn't take any non-option arguments"),
+ builtin_help_usage, builtin_help_options,
+ opt_mode);
+
+ no_help_format(opt_mode, fmt);
}
int cmd_help(int argc, const char **argv, const char *prefix)
@@ -591,11 +625,19 @@ int cmd_help(int argc, const char **argv, const char *prefix)
builtin_help_usage, 0);
parsed_help_format = help_format;
+ if (cmd_mode != HELP_ACTION_ALL &&
+ (show_external_commands >= 0 ||
+ show_aliases >= 0))
+ usage_msg_opt(_("the '--no-[external-commands|aliases]' options can only be used with '--all'"),
+ builtin_help_usage, builtin_help_options);
+
switch (cmd_mode) {
case HELP_ACTION_ALL:
+ opt_mode_usage(argc, "--all", help_format);
if (verbose) {
setup_pager();
- list_all_cmds_help();
+ list_all_cmds_help(show_external_commands,
+ show_aliases);
return 0;
}
printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
@@ -604,20 +646,21 @@ int cmd_help(int argc, const char **argv, const char *prefix)
printf("%s\n", _(git_more_info_string));
break;
case HELP_ACTION_GUIDES:
- no_extra_argc(argc);
+ opt_mode_usage(argc, "--guides", help_format);
list_guides_help();
printf("%s\n", _(git_more_info_string));
return 0;
case HELP_ACTION_CONFIG_FOR_COMPLETION:
- no_extra_argc(argc);
+ opt_mode_usage(argc, "--config-for-completion", help_format);
list_config_help(SHOW_CONFIG_VARS);
return 0;
case HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION:
- no_extra_argc(argc);
+ opt_mode_usage(argc, "--config-sections-for-completion",
+ help_format);
list_config_help(SHOW_CONFIG_SECTIONS);
return 0;
case HELP_ACTION_CONFIG:
- no_extra_argc(argc);
+ opt_mode_usage(argc, "--config", help_format);
setup_pager();
list_config_help(SHOW_CONFIG_HUMAN);
printf("\n%s\n", _("'git help config' for more information"));
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index c45273de3b..680b66b063 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -453,8 +453,7 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
int hdrlen;
if (!is_delta_type(type)) {
- hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %"PRIuMAX,
- type_name(type),(uintmax_t)size) + 1;
+ hdrlen = format_object_header(hdr, sizeof(hdr), type, size);
the_hash_algo->init_fn(&c);
the_hash_algo->update_fn(&c, hdr, hdrlen);
} else
@@ -583,7 +582,7 @@ static void *unpack_data(struct object_entry *obj,
if (!n)
die(Q_("premature end of pack file, %"PRIuMAX" byte missing",
"premature end of pack file, %"PRIuMAX" bytes missing",
- (unsigned int)len),
+ len),
(uintmax_t)len);
from += n;
len -= n;
@@ -975,7 +974,7 @@ static struct base_data *resolve_delta(struct object_entry *delta_obj,
if (!result_data)
bad_object(delta_obj->idx.offset, _("failed to apply delta"));
hash_object_file(the_hash_algo, result_data, result_size,
- type_name(delta_obj->real_type), &delta_obj->idx.oid);
+ delta_obj->real_type, &delta_obj->idx.oid);
sha1_object(result_data, NULL, result_size, delta_obj->real_type,
&delta_obj->idx.oid);
@@ -1113,6 +1112,7 @@ static void *threaded_second_pass(void *data)
list_add(&child->list, &work_head);
base_cache_used += child->size;
prune_base_data(NULL);
+ free_base_data(child);
} else {
/*
* This child does not have its own children. It may be
@@ -1135,6 +1135,7 @@ static void *threaded_second_pass(void *data)
p = next_p;
}
+ FREE_AND_NULL(child);
}
work_unlock();
}
@@ -1290,7 +1291,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha
nr_objects - nr_objects_initial);
stop_progress_msg(&progress, msg.buf);
strbuf_release(&msg);
- finalize_hashfile(f, tail_hash, 0);
+ finalize_hashfile(f, tail_hash, FSYNC_COMPONENT_PACK, 0);
hashcpy(read_hash, pack_hash);
fixup_pack_header_footer(output_fd, pack_hash,
curr_pack, nr_objects,
@@ -1417,9 +1418,8 @@ static void fix_unresolved_deltas(struct hashfile *f)
if (!data)
continue;
- if (check_object_signature(the_repository, &d->oid,
- data, size,
- type_name(type), NULL))
+ if (check_object_signature(the_repository, &d->oid, data, size,
+ type) < 0)
die(_("local object %s is corrupt"), oid_to_hex(&d->oid));
/*
@@ -1428,6 +1428,7 @@ static void fix_unresolved_deltas(struct hashfile *f)
* object).
*/
append_obj_to_pack(f, d->oid.hash, data, size, type);
+ free(data);
threaded_second_pass(NULL);
display_progress(progress, nr_resolved_deltas);
@@ -1512,7 +1513,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
if (!from_stdin) {
close(input_fd);
} else {
- fsync_or_die(output_fd, curr_pack_name);
+ fsync_component_or_die(FSYNC_COMPONENT_PACK, output_fd, curr_pack_name);
err = close(output_fd);
if (err)
die_errno(_("error while closing pack file"));
@@ -1707,6 +1708,7 @@ static void show_pack_info(int stat_only)
i + 1,
chain_histogram[i]);
}
+ free(chain_histogram);
}
int cmd_index_pack(int argc, const char **argv, const char *prefix)
@@ -1936,6 +1938,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (do_fsck_object && fsck_finish(&fsck_options))
die(_("fsck error in pack objects"));
+ free(opts.anomaly);
free(objects);
strbuf_release(&index_name_buf);
strbuf_release(&rev_index_name_buf);
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 26b84980db..a11f8c6e4b 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -138,6 +138,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
int rev_nr = 0;
int show_all = 0;
int cmdmode = 0;
+ int ret;
struct option options[] = {
OPT_BOOL('a', "all", &show_all, N_("output all common ancestors")),
@@ -186,5 +187,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
ALLOC_ARRAY(rev, argc);
while (argc-- > 0)
rev[rev_nr++] = get_commit_reference(*argv++);
- return show_merge_base(rev, rev_nr, show_all);
+ ret = show_merge_base(rev, rev_nr, show_all);
+ free(rev);
+ return ret;
}
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index a4bfd8fc51..b9acbf5d34 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -58,7 +58,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
"Ignoring %s.",
"cannot handle more than %d bases. "
"Ignoring %s.",
- (int)ARRAY_SIZE(bases)-1),
+ ARRAY_SIZE(bases)-1),
(int)ARRAY_SIZE(bases)-1, argv[i]);
}
if (argc - i != 3) /* "--" "<head>" "<remote>" */
diff --git a/builtin/mktag.c b/builtin/mktag.c
index c7b905c614..5d22909122 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -61,9 +61,8 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
type_name(*tagged_type), type_name(type));
repl = lookup_replace_object(the_repository, tagged_oid);
- ret = check_object_signature(the_repository, repl,
- buffer, size, type_name(*tagged_type),
- NULL);
+ ret = check_object_signature(the_repository, repl, buffer, size,
+ *tagged_type);
free(buffer);
return ret;
@@ -97,10 +96,10 @@ int cmd_mktag(int argc, const char **argv, const char *prefix)
&tagged_oid, &tagged_type))
die(_("tag on stdin did not pass our strict fsck check"));
- if (verify_object_in_tag(&tagged_oid, &tagged_type))
+ if (verify_object_in_tag(&tagged_oid, &tagged_type) < 0)
die(_("tag on stdin did not refer to a valid object"));
- if (write_object_file(buf.buf, buf.len, tag_type, &result) < 0)
+ if (write_object_file(buf.buf, buf.len, OBJ_TAG, &result) < 0)
die(_("unable to write tag file"));
strbuf_release(&buf);
diff --git a/builtin/mktree.c b/builtin/mktree.c
index 8bdaada922..902edba6d2 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -58,7 +58,7 @@ static void write_tree(struct object_id *oid)
strbuf_add(&buf, ent->oid.hash, the_hash_algo->rawsz);
}
- write_object_file(buf.buf, buf.len, tree_type, oid);
+ write_object_file(buf.buf, buf.len, OBJ_TREE, oid);
strbuf_release(&buf);
}
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 929591269d..c59b5699fe 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -9,6 +9,7 @@
#include "prio-queue.h"
#include "hash-lookup.h"
#include "commit-slab.h"
+#include "commit-graph.h"
/*
* One day. See the 'name a rev shortly after epoch' test in t6120 when
@@ -26,9 +27,58 @@ struct rev_name {
define_commit_slab(commit_rev_name, struct rev_name);
+static timestamp_t generation_cutoff = GENERATION_NUMBER_INFINITY;
static timestamp_t cutoff = TIME_MAX;
static struct commit_rev_name rev_names;
+/* Disable the cutoff checks entirely */
+static void disable_cutoff(void)
+{
+ generation_cutoff = 0;
+ cutoff = 0;
+}
+
+/* Cutoff searching any commits older than this one */
+static void set_commit_cutoff(struct commit *commit)
+{
+
+ if (cutoff > commit->date)
+ cutoff = commit->date;
+
+ if (generation_cutoff) {
+ timestamp_t generation = commit_graph_generation(commit);
+
+ if (generation_cutoff > generation)
+ generation_cutoff = generation;
+ }
+}
+
+/* adjust the commit date cutoff with a slop to allow for slightly incorrect
+ * commit timestamps in case of clock skew.
+ */
+static void adjust_cutoff_timestamp_for_slop(void)
+{
+ if (cutoff) {
+ /* check for undeflow */
+ if (cutoff > TIME_MIN + CUTOFF_DATE_SLOP)
+ cutoff = cutoff - CUTOFF_DATE_SLOP;
+ else
+ cutoff = TIME_MIN;
+ }
+}
+
+/* Check if a commit is before the cutoff. Prioritize generation numbers
+ * first, but use the commit timestamp if we lack generation data.
+ */
+static int commit_is_before_cutoff(struct commit *commit)
+{
+ if (generation_cutoff < GENERATION_NUMBER_INFINITY)
+ return generation_cutoff &&
+ commit_graph_generation(commit) < generation_cutoff;
+
+ return commit->date < cutoff;
+}
+
/* How many generations are maximally preferred over _one_ merge traversal? */
#define MERGE_TRAVERSAL_WEIGHT 65535
@@ -151,7 +201,7 @@ static void name_rev(struct commit *start_commit,
struct rev_name *start_name;
parse_commit(start_commit);
- if (start_commit->date < cutoff)
+ if (commit_is_before_cutoff(start_commit))
return;
start_name = create_or_update_name(start_commit, taggerdate, 0, 0,
@@ -181,7 +231,7 @@ static void name_rev(struct commit *start_commit,
int generation, distance;
parse_commit(parent);
- if (parent->date < cutoff)
+ if (commit_is_before_cutoff(parent))
continue;
if (parent_number > 1) {
@@ -568,7 +618,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
usage_with_options(name_rev_usage, opts);
}
if (all || annotate_stdin)
- cutoff = 0;
+ disable_cutoff();
for (; argc; argc--, argv++) {
struct object_id oid;
@@ -596,10 +646,8 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
continue;
}
- if (commit) {
- if (cutoff > commit->date)
- cutoff = commit->date;
- }
+ if (commit)
+ set_commit_cutoff(commit);
if (peel_tag) {
if (!commit) {
@@ -612,13 +660,8 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
add_object_array(object, *argv, &revs);
}
- if (cutoff) {
- /* check for undeflow */
- if (cutoff > TIME_MIN + CUTOFF_DATE_SLOP)
- cutoff = cutoff - CUTOFF_DATE_SLOP;
- else
- cutoff = TIME_MIN;
- }
+ adjust_cutoff_timestamp_for_slop();
+
for_each_ref(name_ref, &data);
name_tips();
diff --git a/builtin/notes.c b/builtin/notes.c
index f99593a185..a3d0d15a22 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -199,7 +199,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
static void write_note_data(struct note_data *d, struct object_id *oid)
{
- if (write_object_file(d->buf.buf, d->buf.len, blob_type, oid)) {
+ if (write_object_file(d->buf.buf, d->buf.len, OBJ_BLOB, oid)) {
int status = die_message(_("unable to write note object"));
if (d->edit_path)
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 178e611f09..c23b788ac8 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1199,16 +1199,26 @@ static void write_pack_file(void)
display_progress(progress_state, written);
}
- /*
- * Did we write the wrong # entries in the header?
- * If so, rewrite it like in fast-import
- */
if (pack_to_stdout) {
- finalize_hashfile(f, hash, CSUM_HASH_IN_STREAM | CSUM_CLOSE);
+ /*
+ * We never fsync when writing to stdout since we may
+ * not be writing to an actual pack file. For instance,
+ * the upload-pack code passes a pipe here. Calling
+ * fsync on a pipe results in unnecessary
+ * synchronization with the reader on some platforms.
+ */
+ finalize_hashfile(f, hash, FSYNC_COMPONENT_NONE,
+ CSUM_HASH_IN_STREAM | CSUM_CLOSE);
} else if (nr_written == nr_remaining) {
- finalize_hashfile(f, hash, CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
+ finalize_hashfile(f, hash, FSYNC_COMPONENT_PACK,
+ CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
} else {
- int fd = finalize_hashfile(f, hash, 0);
+ /*
+ * If we wrote the wrong number of entries in the
+ * header, rewrite it like in fast-import.
+ */
+
+ int fd = finalize_hashfile(f, hash, FSYNC_COMPONENT_PACK, 0);
fixup_pack_header_footer(fd, hash, pack_tmp_name,
nr_written, hash, offset);
close(fd);
@@ -1802,7 +1812,7 @@ static void add_preferred_base(struct object_id *oid)
return;
data = read_object_with_reference(the_repository, oid,
- tree_type, &size, &tree_oid);
+ OBJ_TREE, &size, &tree_oid);
if (!data)
return;
@@ -3651,7 +3661,7 @@ static int pack_options_allow_reuse(void)
static int get_object_list_from_bitmap(struct rev_info *revs)
{
- if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options, 0)))
+ if (!(bitmap_git = prepare_bitmap_walk(revs, 0)))
return -1;
if (pack_options_allow_reuse() &&
@@ -3727,6 +3737,7 @@ static void get_object_list(int ac, const char **av)
repo_init_revisions(the_repository, &revs, NULL);
save_commit_buffer = 0;
setup_revisions(ac, av, &revs, &s_r_opt);
+ list_objects_filter_copy(&revs.filter, &filter_options);
/* make sure shallows are read */
is_repository_shallow(the_repository);
@@ -3777,9 +3788,9 @@ static void get_object_list(int ac, const char **av)
if (!fn_show_object)
fn_show_object = show_object;
- traverse_commit_list_filtered(&filter_options, &revs,
- show_commit, fn_show_object, NULL,
- NULL);
+ traverse_commit_list(&revs,
+ show_commit, fn_show_object,
+ NULL);
if (unpack_unreachable_expiration) {
revs.ignore_missing_links = 1;
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 2109c4c9e5..9f1f33e954 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -160,15 +160,22 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
argc = parse_options(argc, argv, cmd_prefix, read_tree_options,
read_tree_usage, 0);
- hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
-
prefix_set = opts.prefix ? 1 : 0;
if (1 < opts.merge + opts.reset + prefix_set)
die("Which one? -m, --reset, or --prefix?");
+ /* Prefix should not start with a directory separator */
+ if (opts.prefix && opts.prefix[0] == '/')
+ die("Invalid prefix, prefix cannot start with '/'");
+
if (opts.reset)
opts.reset = UNPACK_RESET_OVERWRITE_UNTRACKED;
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+
/*
* NEEDSWORK
*
@@ -210,6 +217,9 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
if (opts.merge && !opts.index_only)
setup_work_tree();
+ if (opts.skip_sparse_checkout)
+ ensure_full_index(&the_index);
+
if (opts.merge) {
switch (stage - 1) {
case 0:
diff --git a/builtin/rebase.c b/builtin/rebase.c
index b29ad2b65e..27fde7bf28 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -829,6 +829,8 @@ static int checkout_up_to_date(struct rebase_options *options)
ropts.oid = &options->orig_head;
ropts.branch = options->head_name;
ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
+ if (!ropts.branch)
+ ropts.flags |= RESET_HEAD_DETACH;
ropts.head_msg = buf.buf;
if (reset_head(the_repository, &ropts) < 0)
ret = error(_("could not switch to %s"), options->switch_to);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d4db577669..9aabffa1af 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -749,7 +749,7 @@ static void prepare_push_cert_sha1(struct child_process *proc)
int bogs /* beginning_of_gpg_sig */;
already_done = 1;
- if (write_object_file(push_cert.buf, push_cert.len, "blob",
+ if (write_object_file(push_cert.buf, push_cert.len, OBJ_BLOB,
&push_cert_oid))
oidclr(&push_cert_oid);
@@ -813,13 +813,14 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
proc.trace2_hook_name = hook_name;
if (feed_state->push_options) {
- int i;
+ size_t i;
for (i = 0; i < feed_state->push_options->nr; i++)
strvec_pushf(&proc.env_array,
- "GIT_PUSH_OPTION_%d=%s", i,
+ "GIT_PUSH_OPTION_%"PRIuMAX"=%s",
+ (uintmax_t)i,
feed_state->push_options->items[i].string);
- strvec_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT=%d",
- feed_state->push_options->nr);
+ strvec_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT=%"PRIuMAX"",
+ (uintmax_t)feed_state->push_options->nr);
} else
strvec_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT");
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 016466852f..9407f835cb 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -1,16 +1,9 @@
#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"
-#include "tree-walk.h"
-#include "diff.h"
#include "revision.h"
#include "reachable.h"
#include "worktree.h"
+#include "reflog.h"
static const char reflog_exists_usage[] =
N_("git reflog exists <ref>");
@@ -18,404 +11,11 @@ N_("git reflog exists <ref>");
static timestamp_t default_reflog_expire;
static timestamp_t default_reflog_expire_unreachable;
-struct cmd_reflog_expire_cb {
- int stalefix;
- int explicit_expiry;
- timestamp_t expire_total;
- timestamp_t expire_unreachable;
- int recno;
-};
-
-struct expire_reflog_policy_cb {
- enum {
- UE_NORMAL,
- UE_ALWAYS,
- UE_HEAD
- } unreachable_expire_kind;
- struct commit_list *mark_list;
- unsigned long mark_limit;
- struct cmd_reflog_expire_cb cmd;
- struct commit *tip_commit;
- struct commit_list *tips;
- unsigned int dry_run:1;
-};
-
struct worktree_reflogs {
struct worktree *worktree;
struct string_list reflogs;
};
-/* Remember to update object flag allocation in object.h */
-#define INCOMPLETE (1u<<10)
-#define STUDYING (1u<<11)
-#define REACHABLE (1u<<12)
-
-static int tree_is_complete(const struct object_id *oid)
-{
- struct tree_desc desc;
- struct name_entry entry;
- int complete;
- struct tree *tree;
-
- tree = lookup_tree(the_repository, oid);
- if (!tree)
- return 0;
- if (tree->object.flags & SEEN)
- return 1;
- if (tree->object.flags & INCOMPLETE)
- return 0;
-
- if (!tree->buffer) {
- enum object_type type;
- unsigned long size;
- void *data = read_object_file(oid, &type, &size);
- if (!data) {
- tree->object.flags |= INCOMPLETE;
- return 0;
- }
- tree->buffer = data;
- tree->size = size;
- }
- init_tree_desc(&desc, tree->buffer, tree->size);
- complete = 1;
- while (tree_entry(&desc, &entry)) {
- if (!has_object_file(&entry.oid) ||
- (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
- tree->object.flags |= INCOMPLETE;
- complete = 0;
- }
- }
- free_tree_buffer(tree);
-
- if (complete)
- tree->object.flags |= SEEN;
- return complete;
-}
-
-static int commit_is_complete(struct commit *commit)
-{
- struct object_array study;
- struct object_array found;
- int is_incomplete = 0;
- int i;
-
- /* early return */
- if (commit->object.flags & SEEN)
- return 1;
- if (commit->object.flags & INCOMPLETE)
- return 0;
- /*
- * Find all commits that are reachable and are not marked as
- * SEEN. Then make sure the trees and blobs contained are
- * complete. After that, mark these commits also as SEEN.
- * If some of the objects that are needed to complete this
- * commit are missing, mark this commit as INCOMPLETE.
- */
- memset(&study, 0, sizeof(study));
- memset(&found, 0, sizeof(found));
- add_object_array(&commit->object, NULL, &study);
- add_object_array(&commit->object, NULL, &found);
- commit->object.flags |= STUDYING;
- while (study.nr) {
- struct commit *c;
- struct commit_list *parent;
-
- c = (struct commit *)object_array_pop(&study);
- if (!c->object.parsed && !parse_object(the_repository, &c->object.oid))
- c->object.flags |= INCOMPLETE;
-
- if (c->object.flags & INCOMPLETE) {
- is_incomplete = 1;
- break;
- }
- else if (c->object.flags & SEEN)
- continue;
- for (parent = c->parents; parent; parent = parent->next) {
- struct commit *p = parent->item;
- if (p->object.flags & STUDYING)
- continue;
- p->object.flags |= STUDYING;
- add_object_array(&p->object, NULL, &study);
- add_object_array(&p->object, NULL, &found);
- }
- }
- if (!is_incomplete) {
- /*
- * make sure all commits in "found" array have all the
- * necessary objects.
- */
- for (i = 0; i < found.nr; i++) {
- struct commit *c =
- (struct commit *)found.objects[i].item;
- if (!tree_is_complete(get_commit_tree_oid(c))) {
- is_incomplete = 1;
- c->object.flags |= INCOMPLETE;
- }
- }
- if (!is_incomplete) {
- /* mark all found commits as complete, iow SEEN */
- for (i = 0; i < found.nr; i++)
- found.objects[i].item->flags |= SEEN;
- }
- }
- /* clear flags from the objects we traversed */
- for (i = 0; i < found.nr; i++)
- found.objects[i].item->flags &= ~STUDYING;
- if (is_incomplete)
- commit->object.flags |= INCOMPLETE;
- else {
- /*
- * If we come here, we have (1) traversed the ancestry chain
- * from the "commit" until we reach SEEN commits (which are
- * known to be complete), and (2) made sure that the commits
- * encountered during the above traversal refer to trees that
- * are complete. Which means that we know *all* the commits
- * we have seen during this process are complete.
- */
- for (i = 0; i < found.nr; i++)
- found.objects[i].item->flags |= SEEN;
- }
- /* free object arrays */
- object_array_clear(&study);
- object_array_clear(&found);
- return !is_incomplete;
-}
-
-static int keep_entry(struct commit **it, struct object_id *oid)
-{
- struct commit *commit;
-
- if (is_null_oid(oid))
- return 1;
- commit = lookup_commit_reference_gently(the_repository, oid, 1);
- if (!commit)
- return 0;
-
- /*
- * Make sure everything in this commit exists.
- *
- * We have walked all the objects reachable from the refs
- * and cache earlier. The commits reachable by this commit
- * must meet SEEN commits -- and then we should mark them as
- * SEEN as well.
- */
- if (!commit_is_complete(commit))
- return 0;
- *it = commit;
- return 1;
-}
-
-/*
- * Starting from commits in the cb->mark_list, mark commits that are
- * reachable from them. Stop the traversal at commits older than
- * the expire_limit and queue them back, so that the caller can call
- * us again to restart the traversal with longer expire_limit.
- */
-static void mark_reachable(struct expire_reflog_policy_cb *cb)
-{
- struct commit_list *pending;
- timestamp_t expire_limit = cb->mark_limit;
- struct commit_list *leftover = NULL;
-
- for (pending = cb->mark_list; pending; pending = pending->next)
- pending->item->object.flags &= ~REACHABLE;
-
- pending = cb->mark_list;
- while (pending) {
- struct commit_list *parent;
- struct commit *commit = pop_commit(&pending);
- if (commit->object.flags & REACHABLE)
- continue;
- if (parse_commit(commit))
- continue;
- commit->object.flags |= REACHABLE;
- if (commit->date < expire_limit) {
- commit_list_insert(commit, &leftover);
- continue;
- }
- commit->object.flags |= REACHABLE;
- parent = commit->parents;
- while (parent) {
- commit = parent->item;
- parent = parent->next;
- if (commit->object.flags & REACHABLE)
- continue;
- commit_list_insert(commit, &pending);
- }
- }
- cb->mark_list = leftover;
-}
-
-static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid)
-{
- /*
- * We may or may not have the commit yet - if not, look it
- * up using the supplied sha1.
- */
- if (!commit) {
- if (is_null_oid(oid))
- return 0;
-
- commit = lookup_commit_reference_gently(the_repository, oid,
- 1);
-
- /* Not a commit -- keep it */
- if (!commit)
- return 0;
- }
-
- /* Reachable from the current ref? Don't prune. */
- if (commit->object.flags & REACHABLE)
- return 0;
-
- if (cb->mark_list && cb->mark_limit) {
- cb->mark_limit = 0; /* dig down to the root */
- mark_reachable(cb);
- }
-
- return !(commit->object.flags & REACHABLE);
-}
-
-/*
- * Return true iff the specified reflog entry should be expired.
- */
-static int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
- const char *email, timestamp_t timestamp, int tz,
- const char *message, void *cb_data)
-{
- struct expire_reflog_policy_cb *cb = cb_data;
- struct commit *old_commit, *new_commit;
-
- if (timestamp < cb->cmd.expire_total)
- return 1;
-
- old_commit = new_commit = NULL;
- if (cb->cmd.stalefix &&
- (!keep_entry(&old_commit, ooid) || !keep_entry(&new_commit, noid)))
- return 1;
-
- if (timestamp < cb->cmd.expire_unreachable) {
- switch (cb->unreachable_expire_kind) {
- case UE_ALWAYS:
- return 1;
- case UE_NORMAL:
- case UE_HEAD:
- if (unreachable(cb, old_commit, ooid) || unreachable(cb, new_commit, noid))
- return 1;
- break;
- }
- }
-
- if (cb->cmd.recno && --(cb->cmd.recno) == 0)
- return 1;
-
- return 0;
-}
-
-static int should_expire_reflog_ent_verbose(struct object_id *ooid,
- struct object_id *noid,
- const char *email,
- timestamp_t timestamp, int tz,
- const char *message, void *cb_data)
-{
- struct expire_reflog_policy_cb *cb = cb_data;
- int expire;
-
- expire = should_expire_reflog_ent(ooid, noid, email, timestamp, tz,
- message, cb);
-
- if (!expire)
- printf("keep %s", message);
- else if (cb->dry_run)
- printf("would prune %s", message);
- else
- printf("prune %s", message);
-
- return expire;
-}
-
-static int push_tip_to_list(const char *refname, const struct object_id *oid,
- int flags, void *cb_data)
-{
- struct commit_list **list = cb_data;
- struct commit *tip_commit;
- if (flags & REF_ISSYMREF)
- return 0;
- tip_commit = lookup_commit_reference_gently(the_repository, oid, 1);
- if (!tip_commit)
- return 0;
- commit_list_insert(tip_commit, list);
- return 0;
-}
-
-static int is_head(const char *refname)
-{
- switch (ref_type(refname)) {
- case REF_TYPE_OTHER_PSEUDOREF:
- case REF_TYPE_MAIN_PSEUDOREF:
- if (parse_worktree_ref(refname, NULL, NULL, &refname))
- BUG("not a worktree ref: %s", refname);
- break;
- default:
- break;
- }
- return !strcmp(refname, "HEAD");
-}
-
-static void reflog_expiry_prepare(const char *refname,
- const struct object_id *oid,
- void *cb_data)
-{
- struct expire_reflog_policy_cb *cb = cb_data;
- struct commit_list *elem;
- struct commit *commit = NULL;
-
- if (!cb->cmd.expire_unreachable || is_head(refname)) {
- cb->unreachable_expire_kind = UE_HEAD;
- } else {
- commit = lookup_commit(the_repository, oid);
- cb->unreachable_expire_kind = commit ? UE_NORMAL : UE_ALWAYS;
- }
-
- if (cb->cmd.expire_unreachable <= cb->cmd.expire_total)
- cb->unreachable_expire_kind = UE_ALWAYS;
-
- switch (cb->unreachable_expire_kind) {
- case UE_ALWAYS:
- return;
- case UE_HEAD:
- for_each_ref(push_tip_to_list, &cb->tips);
- for (elem = cb->tips; elem; elem = elem->next)
- commit_list_insert(elem->item, &cb->mark_list);
- break;
- case UE_NORMAL:
- commit_list_insert(commit, &cb->mark_list);
- /* For reflog_expiry_cleanup() below */
- cb->tip_commit = commit;
- }
- cb->mark_limit = cb->cmd.expire_total;
- mark_reachable(cb);
-}
-
-static void reflog_expiry_cleanup(void *cb_data)
-{
- struct expire_reflog_policy_cb *cb = cb_data;
- struct commit_list *elem;
-
- switch (cb->unreachable_expire_kind) {
- case UE_ALWAYS:
- return;
- case UE_HEAD:
- for (elem = cb->tips; elem; elem = elem->next)
- clear_commit_marks(elem->item, REACHABLE);
- free_commit_list(cb->tips);
- break;
- case UE_NORMAL:
- clear_commit_marks(cb->tip_commit, REACHABLE);
- break;
- }
-}
-
static int collect_reflog(const char *ref, const struct object_id *oid, int unused, void *cb_data)
{
struct worktree_reflogs *cb = cb_data;
@@ -704,16 +304,6 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
return status;
}
-static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
- const char *email, timestamp_t timestamp, int tz,
- const char *message, void *cb_data)
-{
- struct cmd_reflog_expire_cb *cb = cb_data;
- if (!cb->expire_total || timestamp < cb->expire_total)
- cb->recno++;
- return 0;
-}
-
static const char * reflog_delete_usage[] = {
N_("git reflog delete [--rewrite] [--updateref] "
"[--dry-run | -n] [--verbose] <refs>..."),
@@ -722,11 +312,10 @@ static const char * reflog_delete_usage[] = {
static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
{
- struct cmd_reflog_expire_cb cmd = { 0 };
int i, status = 0;
unsigned int flags = 0;
int verbose = 0;
- reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
+
const struct option options[] = {
OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
EXPIRE_REFLOGS_DRY_RUN),
@@ -742,48 +331,12 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, reflog_delete_usage, 0);
- if (verbose)
- should_prune_fn = should_expire_reflog_ent_verbose;
-
if (argc < 1)
return error(_("no reflog specified to delete"));
- for (i = 0; i < argc; i++) {
- const char *spec = strstr(argv[i], "@{");
- char *ep, *ref;
- int recno;
- struct expire_reflog_policy_cb cb = {
- .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
- };
-
- if (!spec) {
- status |= error(_("not a reflog: %s"), argv[i]);
- continue;
- }
+ for (i = 0; i < argc; i++)
+ status |= reflog_delete(argv[i], flags, verbose);
- if (!dwim_log(argv[i], spec - argv[i], NULL, &ref)) {
- status |= error(_("no reflog for '%s'"), argv[i]);
- continue;
- }
-
- recno = strtoul(spec + 2, &ep, 10);
- if (*ep == '}') {
- cmd.recno = -recno;
- for_each_reflog_ent(ref, count_reflog_ent, &cmd);
- } else {
- cmd.expire_total = approxidate(spec + 2);
- for_each_reflog_ent(ref, count_reflog_ent, &cmd);
- cmd.expire_total = 0;
- }
-
- cb.cmd = cmd;
- status |= reflog_expire(ref, flags,
- reflog_expiry_prepare,
- should_prune_fn,
- reflog_expiry_cleanup,
- &cb);
- free(ref);
- }
return status;
}
diff --git a/builtin/remote.c b/builtin/remote.c
index 6f27ddc47b..5f4cde9d78 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -12,11 +12,12 @@
#include "object-store.h"
#include "strvec.h"
#include "commit-reach.h"
+#include "progress.h"
static const char * const builtin_remote_usage[] = {
"git remote [-v | --verbose]",
N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>"),
- N_("git remote rename <old> <new>"),
+ N_("git remote rename [--[no-]progress] <old> <new>"),
N_("git remote remove <name>"),
N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
N_("git remote [-v | --verbose] show [-n] <name>"),
@@ -36,7 +37,7 @@ static const char * const builtin_remote_add_usage[] = {
};
static const char * const builtin_remote_rename_usage[] = {
- N_("git remote rename <old> <new>"),
+ N_("git remote rename [--[no-]progress] <old> <new>"),
NULL
};
@@ -571,6 +572,7 @@ struct rename_info {
const char *old_name;
const char *new_name;
struct string_list *remote_branches;
+ uint32_t symrefs_nr;
};
static int read_remote_branches(const char *refname,
@@ -587,10 +589,12 @@ static int read_remote_branches(const char *refname,
item = string_list_append(rename->remote_branches, refname);
symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
NULL, &flag);
- if (symref && (flag & REF_ISSYMREF))
+ if (symref && (flag & REF_ISSYMREF)) {
item->util = xstrdup(symref);
- else
+ rename->symrefs_nr++;
+ } else {
item->util = NULL;
+ }
}
strbuf_release(&buf);
@@ -674,7 +678,9 @@ static void handle_push_default(const char* old_name, const char* new_name)
static int mv(int argc, const char **argv)
{
+ int show_progress = isatty(2);
struct option options[] = {
+ OPT_BOOL(0, "progress", &show_progress, N_("force progress reporting")),
OPT_END()
};
struct remote *oldremote, *newremote;
@@ -682,14 +688,19 @@ static int mv(int argc, const char **argv)
old_remote_context = STRBUF_INIT;
struct string_list remote_branches = STRING_LIST_INIT_DUP;
struct rename_info rename;
- int i, refspec_updated = 0;
+ int i, refs_renamed_nr = 0, refspec_updated = 0;
+ struct progress *progress = NULL;
+
+ argc = parse_options(argc, argv, NULL, options,
+ builtin_remote_rename_usage, 0);
- if (argc != 3)
+ if (argc != 2)
usage_with_options(builtin_remote_rename_usage, options);
- rename.old_name = argv[1];
- rename.new_name = argv[2];
+ rename.old_name = argv[0];
+ rename.new_name = argv[1];
rename.remote_branches = &remote_branches;
+ rename.symrefs_nr = 0;
oldremote = remote_get(rename.old_name);
if (!remote_is_configured(oldremote, 1)) {
@@ -764,15 +775,26 @@ static int mv(int argc, const char **argv)
* the new symrefs.
*/
for_each_ref(read_remote_branches, &rename);
+ if (show_progress) {
+ /*
+ * Count symrefs twice, since "renaming" them is done by
+ * deleting and recreating them in two separate passes.
+ */
+ progress = start_progress(_("Renaming remote references"),
+ rename.remote_branches->nr + rename.symrefs_nr);
+ }
for (i = 0; i < remote_branches.nr; i++) {
struct string_list_item *item = remote_branches.items + i;
- int flag = 0;
+ struct strbuf referent = STRBUF_INIT;
- read_ref_full(item->string, RESOLVE_REF_READING, NULL, &flag);
- if (!(flag & REF_ISSYMREF))
+ if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
+ &referent))
continue;
if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
die(_("deleting '%s' failed"), item->string);
+
+ strbuf_release(&referent);
+ display_progress(progress, ++refs_renamed_nr);
}
for (i = 0; i < remote_branches.nr; i++) {
struct string_list_item *item = remote_branches.items + i;
@@ -788,6 +810,7 @@ static int mv(int argc, const char **argv)
item->string, buf.buf);
if (rename_ref(item->string, buf.buf, buf2.buf))
die(_("renaming '%s' failed"), item->string);
+ display_progress(progress, ++refs_renamed_nr);
}
for (i = 0; i < remote_branches.nr; i++) {
struct string_list_item *item = remote_branches.items + i;
@@ -807,7 +830,9 @@ static int mv(int argc, const char **argv)
item->string, buf.buf);
if (create_symref(buf.buf, buf2.buf, buf3.buf))
die(_("creating '%s' failed"), buf.buf);
+ display_progress(progress, ++refs_renamed_nr);
}
+ stop_progress(&progress);
string_list_clear(&remote_branches, 1);
handle_push_default(rename.old_name, rename.new_name);
diff --git a/builtin/repack.c b/builtin/repack.c
index da1e364a75..d1a563d5b6 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -22,6 +22,7 @@ static int delta_base_offset = 1;
static int pack_kept_objects = -1;
static int write_bitmaps = -1;
static int use_delta_islands;
+static int run_update_server_info = 1;
static char *packdir, *packtmp_name, *packtmp;
static const char *const git_repack_usage[] = {
@@ -54,6 +55,10 @@ static int repack_config(const char *var, const char *value, void *cb)
use_delta_islands = git_config_bool(var, value);
return 0;
}
+ if (strcmp(var, "repack.updateserverinfo") == 0) {
+ run_update_server_info = git_config_bool(var, value);
+ return 0;
+ }
return git_default_config(var, value, cb);
}
@@ -620,7 +625,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
const char *unpack_unreachable = NULL;
int keep_unreachable = 0;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
- int no_update_server_info = 0;
struct pack_objects_args po_args = {NULL};
int geometric_factor = 0;
int write_midx = 0;
@@ -637,8 +641,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
N_("pass --no-reuse-delta to git-pack-objects")),
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_NEGBIT('n', NULL, &run_update_server_info,
+ N_("do not run git-update-server-info"), 1),
OPT__QUIET(&po_args.quiet, N_("be quiet")),
OPT_BOOL('l', "local", &po_args.local,
N_("pass --local to git-pack-objects")),
@@ -939,7 +943,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
prune_shallow(PRUNE_QUICK);
}
- if (!no_update_server_info)
+ if (run_update_server_info)
update_server_info(0);
remove_temporary_files();
diff --git a/builtin/replace.c b/builtin/replace.c
index ac92337c0e..5068f4f0b2 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -409,7 +409,7 @@ static int check_one_mergetag(struct commit *commit,
int i;
hash_object_file(the_hash_algo, extra->value, extra->len,
- type_name(OBJ_TAG), &tag_oid);
+ OBJ_TAG, &tag_oid);
tag = lookup_tag(the_repository, &tag_oid);
if (!tag)
return error(_("bad mergetag in commit '%s'"), ref);
@@ -474,7 +474,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
return -1;
}
- if (write_object_file(buf.buf, buf.len, commit_type, &new_oid)) {
+ if (write_object_file(buf.buf, buf.len, OBJ_COMMIT, &new_oid)) {
strbuf_release(&buf);
return error(_("could not write replacement commit for: '%s'"),
old_ref);
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 38528c7f15..572da1472e 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -62,7 +62,6 @@ static const char rev_list_usage[] =
static struct progress *progress;
static unsigned progress_counter;
-static struct list_objects_filter_options filter_options;
static struct oidset omitted_objects;
static int arg_print_omitted; /* print objects omitted by filter */
@@ -400,7 +399,6 @@ static inline int parse_missing_action_value(const char *value)
}
static int try_bitmap_count(struct rev_info *revs,
- struct list_objects_filter_options *filter,
int filter_provided_objects)
{
uint32_t commit_count = 0,
@@ -436,7 +434,7 @@ static int try_bitmap_count(struct rev_info *revs,
*/
max_count = revs->max_count;
- bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
+ bitmap_git = prepare_bitmap_walk(revs, filter_provided_objects);
if (!bitmap_git)
return -1;
@@ -453,7 +451,6 @@ static int try_bitmap_count(struct rev_info *revs,
}
static int try_bitmap_traversal(struct rev_info *revs,
- struct list_objects_filter_options *filter,
int filter_provided_objects)
{
struct bitmap_index *bitmap_git;
@@ -465,7 +462,7 @@ static int try_bitmap_traversal(struct rev_info *revs,
if (revs->max_count >= 0)
return -1;
- bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
+ bitmap_git = prepare_bitmap_walk(revs, filter_provided_objects);
if (!bitmap_git)
return -1;
@@ -475,7 +472,6 @@ static int try_bitmap_traversal(struct rev_info *revs,
}
static int try_bitmap_disk_usage(struct rev_info *revs,
- struct list_objects_filter_options *filter,
int filter_provided_objects)
{
struct bitmap_index *bitmap_git;
@@ -483,7 +479,7 @@ static int try_bitmap_disk_usage(struct rev_info *revs,
if (!show_disk_usage)
return -1;
- bitmap_git = prepare_bitmap_walk(revs, filter, filter_provided_objects);
+ bitmap_git = prepare_bitmap_walk(revs, filter_provided_objects);
if (!bitmap_git)
return -1;
@@ -595,17 +591,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
show_progress = arg;
continue;
}
-
- if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
- parse_list_objects_filter(&filter_options, arg);
- if (filter_options.choice && !revs.blob_objects)
- die(_("object filtering requires --objects"));
- continue;
- }
- if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) {
- list_objects_filter_set_no_filter(&filter_options);
- continue;
- }
if (!strcmp(arg, "--filter-provided-objects")) {
filter_provided_objects = 1;
continue;
@@ -688,11 +673,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
progress = start_delayed_progress(show_progress, 0);
if (use_bitmap_index) {
- if (!try_bitmap_count(&revs, &filter_options, filter_provided_objects))
+ if (!try_bitmap_count(&revs, filter_provided_objects))
return 0;
- if (!try_bitmap_disk_usage(&revs, &filter_options, filter_provided_objects))
+ if (!try_bitmap_disk_usage(&revs, filter_provided_objects))
return 0;
- if (!try_bitmap_traversal(&revs, &filter_options, filter_provided_objects))
+ if (!try_bitmap_traversal(&revs, filter_provided_objects))
return 0;
}
@@ -733,7 +718,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
traverse_commit_list_filtered(
- &filter_options, &revs, show_commit, show_object, &info,
+ &revs, show_commit, show_object, &info,
(arg_print_omitted ? &omitted_objects : NULL));
if (arg_print_omitted) {
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 228d782754..26c5c0cf93 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -435,7 +435,7 @@ static void add_wrapped_shortlog_msg(struct strbuf *sb, const char *s,
void shortlog_output(struct shortlog *log)
{
- int i, j;
+ size_t i, j;
struct strbuf sb = STRBUF_INIT;
if (log->sort_by_number)
@@ -448,10 +448,10 @@ void shortlog_output(struct shortlog *log)
(int)UTIL_TO_INT(item), item->string);
} else {
struct string_list *onelines = item->util;
- fprintf(log->file, "%s (%d):\n",
- item->string, onelines->nr);
- for (j = onelines->nr - 1; j >= 0; j--) {
- const char *msg = onelines->items[j].string;
+ fprintf(log->file, "%s (%"PRIuMAX"):\n",
+ item->string, (uintmax_t)onelines->nr);
+ for (j = onelines->nr; j >= 1; j--) {
+ const char *msg = onelines->items[j - 1].string;
if (log->wrap_lines) {
strbuf_reset(&sb);
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 5518ed47f6..0217d44c5b 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -8,7 +8,6 @@
#include "run-command.h"
#include "strbuf.h"
#include "string-list.h"
-#include "cache.h"
#include "cache-tree.h"
#include "lockfile.h"
#include "resolve-undo.h"
@@ -329,11 +328,11 @@ static int write_patterns_and_update(struct pattern_list *pl)
fd = hold_lock_file_for_update(&lk, sparse_filename,
LOCK_DIE_ON_ERROR);
+ free(sparse_filename);
result = update_working_directory(pl);
if (result) {
rollback_lock_file(&lk);
- free(sparse_filename);
clear_pattern_list(pl);
update_working_directory(NULL);
return result;
@@ -349,7 +348,6 @@ static int write_patterns_and_update(struct pattern_list *pl)
fflush(fp);
commit_lock_file(&lk);
- free(sparse_filename);
clear_pattern_list(pl);
return 0;
diff --git a/builtin/stash.c b/builtin/stash.c
index 3e8af210fd..ccdfdab44b 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -16,7 +16,7 @@
#include "log-tree.h"
#include "diffcore.h"
#include "exec-cmd.h"
-#include "entry.h"
+#include "reflog.h"
#define INCLUDE_ALL_FILES 2
@@ -634,20 +634,9 @@ static int reflog_is_empty(const char *refname)
static int do_drop_stash(struct stash_info *info, int quiet)
{
- int ret;
- struct child_process cp_reflog = CHILD_PROCESS_INIT;
-
- /*
- * reflog does not provide a simple function for deleting refs. One will
- * need to be added to avoid implementing too much reflog code here
- */
-
- cp_reflog.git_cmd = 1;
- strvec_pushl(&cp_reflog.args, "reflog", "delete", "--updateref",
- "--rewrite", NULL);
- strvec_push(&cp_reflog.args, info->revision.buf);
- ret = run_command(&cp_reflog);
- if (!ret) {
+ if (!reflog_delete(info->revision.buf,
+ EXPIRE_REFLOGS_REWRITE | EXPIRE_REFLOGS_UPDATE_REF,
+ 0)) {
if (!quiet)
printf_ln(_("Dropped %s (%s)"), info->revision.buf,
oid_to_hex(&info->w_commit));
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index d8638434dc..5301612d24 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -31,11 +31,13 @@
typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
void *cb_data);
-static char *get_default_remote(void)
+static char *repo_get_default_remote(struct repository *repo)
{
char *dest = NULL, *ret;
struct strbuf sb = STRBUF_INIT;
- const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+ struct ref_store *store = get_main_ref_store(repo);
+ const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
+ NULL);
if (!refname)
die(_("No such ref: %s"), "HEAD");
@@ -48,7 +50,7 @@ static char *get_default_remote(void)
die(_("Expecting a full ref name, got %s"), refname);
strbuf_addf(&sb, "branch.%s.remote", refname);
- if (git_config_get_string(sb.buf, &dest))
+ if (repo_config_get_string(repo, sb.buf, &dest))
ret = xstrdup("origin");
else
ret = dest;
@@ -57,19 +59,17 @@ static char *get_default_remote(void)
return ret;
}
-static int print_default_remote(int argc, const char **argv, const char *prefix)
+static char *get_default_remote_submodule(const char *module_path)
{
- char *remote;
-
- if (argc != 1)
- die(_("submodule--helper print-default-remote takes no arguments"));
+ struct repository subrepo;
- remote = get_default_remote();
- if (remote)
- printf("%s\n", remote);
+ repo_submodule_init(&subrepo, the_repository, module_path, null_oid());
+ return repo_get_default_remote(&subrepo);
+}
- free(remote);
- return 0;
+static char *get_default_remote(void)
+{
+ return repo_get_default_remote(the_repository);
}
static int starts_with_dot_slash(const char *str)
@@ -247,11 +247,10 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr
return 0;
}
-/* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *do_get_submodule_displaypath(const char *path,
+ const char *prefix,
+ const char *super_prefix)
{
- const char *super_prefix = get_super_prefix();
-
if (prefix && super_prefix) {
BUG("cannot have prefix '%s' and superprefix '%s'",
prefix, super_prefix);
@@ -267,6 +266,13 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)
}
}
+/* the result should be freed by the caller. */
+static char *get_submodule_displaypath(const char *path, const char *prefix)
+{
+ const char *super_prefix = get_super_prefix();
+ return do_get_submodule_displaypath(path, prefix, super_prefix);
+}
+
static char *compute_rev_name(const char *sub_path, const char* object_id)
{
struct strbuf sb = STRBUF_INIT;
@@ -588,18 +594,22 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
struct init_cb {
const char *prefix;
+ const char *superprefix;
unsigned int flags;
};
#define INIT_CB_INIT { 0 }
static void init_submodule(const char *path, const char *prefix,
- unsigned int flags)
+ const char *superprefix, unsigned int flags)
{
const struct submodule *sub;
struct strbuf sb = STRBUF_INIT;
char *upd = NULL, *url = NULL, *displaypath;
- displaypath = get_submodule_displaypath(path, prefix);
+ /* try superprefix from the environment, if it is not passed explicitly */
+ if (!superprefix)
+ superprefix = get_super_prefix();
+ displaypath = do_get_submodule_displaypath(path, prefix, superprefix);
sub = submodule_from_path(the_repository, null_oid(), path);
@@ -673,7 +683,7 @@ static void init_submodule(const char *path, const char *prefix,
static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
{
struct init_cb *info = cb_data;
- init_submodule(list_item->name, info->prefix, info->flags);
+ init_submodule(list_item->name, info->prefix, info->superprefix, info->flags);
}
static int module_init(int argc, const char **argv, const char *prefix)
@@ -1343,9 +1353,8 @@ static void sync_submodule(const char *path, const char *prefix,
{
const struct submodule *sub;
char *remote_key = NULL;
- char *sub_origin_url, *super_config_url, *displaypath;
+ char *sub_origin_url, *super_config_url, *displaypath, *default_remote;
struct strbuf sb = STRBUF_INIT;
- struct child_process cp = CHILD_PROCESS_INIT;
char *sub_config_path = NULL;
if (!is_submodule_active(the_repository, path))
@@ -1384,21 +1393,15 @@ static void sync_submodule(const char *path, const char *prefix,
if (!is_submodule_populated_gently(path, NULL))
goto cleanup;
- prepare_submodule_repo_env(&cp.env_array);
- cp.git_cmd = 1;
- cp.dir = path;
- strvec_pushl(&cp.args, "submodule--helper",
- "print-default-remote", NULL);
-
strbuf_reset(&sb);
- if (capture_command(&cp, &sb, 0))
+ default_remote = get_default_remote_submodule(path);
+ if (!default_remote)
die(_("failed to get the default remote for submodule '%s'"),
path);
- strbuf_strip_suffix(&sb, "\n");
- remote_key = xstrfmt("remote.%s.url", sb.buf);
+ remote_key = xstrfmt("remote.%s.url", default_remote);
+ free(default_remote);
- strbuf_reset(&sb);
submodule_to_gitdir(&sb, path);
strbuf_addstr(&sb, "/config");
@@ -1957,29 +1960,6 @@ static void determine_submodule_update_strategy(struct repository *r,
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;
@@ -2020,6 +2000,7 @@ struct submodule_update_clone {
int failed_clones_nr, failed_clones_alloc;
int max_jobs;
+ unsigned int init;
};
#define SUBMODULE_UPDATE_CLONE_INIT { \
.list = MODULE_LIST_INIT, \
@@ -2038,10 +2019,11 @@ struct update_data {
struct object_id suboid;
struct submodule_update_strategy update_strategy;
int depth;
- unsigned int force: 1;
- unsigned int quiet: 1;
- unsigned int nofetch: 1;
- unsigned int just_cloned: 1;
+ unsigned int force;
+ unsigned int quiet;
+ unsigned int nofetch;
+ unsigned int just_cloned;
+ unsigned int remote;
};
#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT }
@@ -2475,6 +2457,16 @@ static int do_run_update_procedure(struct update_data *ud)
return run_update_command(ud, subforce);
}
+/*
+ * NEEDSWORK: As we convert "git submodule update" to C,
+ * update_submodule2() will invoke more and more functions, making it
+ * difficult to preserve the function ordering without forward
+ * declarations.
+ *
+ * When the conversion is complete, this forward declaration will be
+ * unnecessary and should be removed.
+ */
+static int update_submodule2(struct update_data *update_data);
static void update_submodule(struct update_clone_data *ucd)
{
fprintf(stdout, "dummy %s %d\t%s\n",
@@ -2518,6 +2510,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
int ret;
struct option module_update_clone_options[] = {
+ OPT_BOOL(0, "init", &suc.init,
+ N_("initialize uninitialized submodules before update")),
OPT_STRING(0, "prefix", &prefix,
N_("path"),
N_("path into the working tree")),
@@ -2551,7 +2545,12 @@ static int update_clone(int argc, const char **argv, const char *prefix)
};
const char *const git_submodule_helper_usage[] = {
- N_("git submodule--helper update-clone [--prefix=<path>] [<path>...]"),
+ N_("git submodule [--quiet] update"
+ " [--init [--filter=<filter-spec>]] [--remote]"
+ " [-N|--no-fetch] [-f|--force]"
+ " [--checkout|--merge|--rebase]"
+ " [--[no-]recommend-shallow] [--reference <repository>]"
+ " [--recursive] [--[no-]single-branch] [--] [<path>...]"),
NULL
};
suc.prefix = prefix;
@@ -2562,6 +2561,19 @@ static int update_clone(int argc, const char **argv, const char *prefix)
memset(&filter_options, 0, sizeof(filter_options));
argc = parse_options(argc, argv, prefix, module_update_clone_options,
git_submodule_helper_usage, 0);
+
+ if (filter_options.choice && !suc.init) {
+ /*
+ * NEEDSWORK: Don't use usage_with_options() because the
+ * usage string is for "git submodule update", but the
+ * options are for "git submodule--helper update-clone".
+ *
+ * This will no longer be an issue when "update-clone"
+ * is replaced by "git submodule--helper update".
+ */
+ usage(git_submodule_helper_usage[0]);
+ }
+
suc.filter_options = &filter_options;
if (update)
@@ -2576,6 +2588,29 @@ static int update_clone(int argc, const char **argv, const char *prefix)
if (pathspec.nr)
suc.warn_if_uninitialized = 1;
+ if (suc.init) {
+ struct module_list list = MODULE_LIST_INIT;
+ struct init_cb info = INIT_CB_INIT;
+
+ if (module_list_compute(argc, argv, suc.prefix,
+ &pathspec, &list) < 0)
+ return 1;
+
+ /*
+ * If there are no path args and submodule.active is set then,
+ * by default, only initialize 'active' modules.
+ */
+ if (!argc && git_config_get_value_multi("submodule.active"))
+ module_list_active(&list);
+
+ info.prefix = suc.prefix;
+ info.superprefix = suc.recursive_prefix;
+ if (suc.quiet)
+ info.flags |= OPT_QUIET;
+
+ for_each_listed_submodule(&list, init_submodule_cb, &info);
+ }
+
ret = update_submodules(&suc);
list_objects_filter_release(&filter_options);
return ret;
@@ -2583,16 +2618,17 @@ static int update_clone(int argc, const char **argv, const char *prefix)
static int run_update_procedure(int argc, const char **argv, const char *prefix)
{
- int force = 0, quiet = 0, nofetch = 0, just_cloned = 0;
char *prefixed_path, *update = NULL;
struct update_data update_data = UPDATE_DATA_INIT;
struct option options[] = {
- OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")),
- OPT__FORCE(&force, N_("force checkout updates"), 0),
- OPT_BOOL('N', "no-fetch", &nofetch,
+ OPT__QUIET(&update_data.quiet,
+ N_("suppress output for update by rebase or merge")),
+ OPT__FORCE(&update_data.force, N_("force checkout updates"),
+ 0),
+ OPT_BOOL('N', "no-fetch", &update_data.nofetch,
N_("don't fetch new objects from the remote site")),
- OPT_BOOL(0, "just-cloned", &just_cloned,
+ OPT_BOOL(0, "just-cloned", &update_data.just_cloned,
N_("overrides update mode in case the repository is a fresh clone")),
OPT_INTEGER(0, "depth", &update_data.depth, N_("depth for shallow fetch")),
OPT_STRING(0, "prefix", &prefix,
@@ -2607,9 +2643,8 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"),
N_("SHA1 expected by superproject"), PARSE_OPT_NONEG,
parse_opt_object_id),
- OPT_CALLBACK_F(0, "suboid", &update_data.suboid, N_("subsha1"),
- N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG,
- parse_opt_object_id),
+ OPT_BOOL(0, "remote", &update_data.remote,
+ N_("use SHA-1 of submodule's remote tracking branch")),
OPT_END()
};
@@ -2623,10 +2658,6 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
if (argc != 1)
usage_with_options(usage, options);
- update_data.force = !!force;
- update_data.quiet = !!quiet;
- update_data.nofetch = !!nofetch;
- update_data.just_cloned = !!just_cloned;
update_data.sm_path = argv[0];
if (update_data.recursive_prefix)
@@ -2641,11 +2672,7 @@ static int run_update_procedure(int argc, const char **argv, const char *prefix)
&update_data.update_strategy);
free(prefixed_path);
-
- if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force)
- return do_run_update_procedure(&update_data);
-
- return 3;
+ return update_submodule2(&update_data);
}
static int resolve_relative_path(int argc, const char **argv, const char *prefix)
@@ -2697,23 +2724,6 @@ static const char *remote_submodule_branch(const char *path)
return branch;
}
-static int resolve_remote_submodule_branch(int argc, const char **argv,
- const char *prefix)
-{
- const char *ret;
- struct strbuf sb = STRBUF_INIT;
- if (argc != 2)
- die("submodule--helper remote-branch takes exactly one arguments, got %d", argc);
-
- ret = remote_submodule_branch(argv[1]);
- if (!ret)
- die("submodule %s doesn't exist", argv[1]);
-
- printf("%s", ret);
- strbuf_release(&sb);
- return 0;
-}
-
static int push_check(int argc, const char **argv, const char *prefix)
{
struct remote *remote;
@@ -2791,17 +2801,11 @@ 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)
+static void ensure_core_worktree(const char *path)
{
- const char *path;
const char *cw;
struct repository subrepo;
- if (argc != 2)
- BUG("submodule--helper ensure-core-worktree <path>");
-
- path = argv[1];
-
if (repo_submodule_init(&subrepo, the_repository, path, null_oid()))
die(_("could not get a repository handle for submodule '%s'"), path);
@@ -2821,8 +2825,6 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
free(abs_path);
strbuf_release(&sb);
}
-
- return 0;
}
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
@@ -3045,6 +3047,42 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)
force, reflog, quiet, track, dry_run);
return 0;
}
+
+/* NEEDSWORK: this is a temporary name until we delete update_submodule() */
+static int update_submodule2(struct update_data *update_data)
+{
+ ensure_core_worktree(update_data->sm_path);
+ if (update_data->just_cloned)
+ oidcpy(&update_data->suboid, null_oid());
+ else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid))
+ die(_("Unable to find current revision in submodule path '%s'"),
+ update_data->displaypath);
+
+ if (update_data->remote) {
+ char *remote_name = get_default_remote_submodule(update_data->sm_path);
+ const char *branch = remote_submodule_branch(update_data->sm_path);
+ char *remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
+
+ if (!update_data->nofetch) {
+ if (fetch_in_submodule(update_data->sm_path, update_data->depth,
+ 0, NULL))
+ die(_("Unable to fetch in submodule path '%s'"),
+ update_data->sm_path);
+ }
+
+ if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid))
+ die(_("Unable to find %s revision in submodule path '%s'"),
+ remote_ref, update_data->sm_path);
+
+ free(remote_ref);
+ }
+
+ if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force)
+ return do_run_update_procedure(update_data);
+
+ return 3;
+}
+
struct add_data {
const char *prefix;
const char *branch;
@@ -3309,6 +3347,7 @@ static int module_add(int argc, const char **argv, const char *prefix)
{
int force = 0, quiet = 0, progress = 0, dissociate = 0;
struct add_data add_data = ADD_DATA_INIT;
+ char *to_free = NULL;
struct option options[] = {
OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
@@ -3360,7 +3399,8 @@ static int module_add(int argc, const char **argv, const char *prefix)
"of the working tree"));
/* dereference source url relative to parent's url */
- add_data.realrepo = resolve_relative_url(add_data.repo, NULL, 1);
+ to_free = resolve_relative_url(add_data.repo, NULL, 1);
+ add_data.realrepo = to_free;
} else if (is_dir_sep(add_data.repo[0]) || strchr(add_data.repo, ':')) {
add_data.realrepo = add_data.repo;
} else {
@@ -3413,6 +3453,7 @@ static int module_add(int argc, const char **argv, const char *prefix)
}
configure_added_submodule(&add_data);
free(add_data.sm_path);
+ free(to_free);
return 0;
}
@@ -3430,20 +3471,16 @@ static struct cmd_struct commands[] = {
{"name", module_name, 0},
{"clone", module_clone, 0},
{"add", module_add, SUPPORT_SUPER_PREFIX},
- {"update-module-mode", module_update_module_mode, 0},
{"update-clone", update_clone, 0},
{"run-update-procedure", run_update_procedure, 0},
- {"ensure-core-worktree", ensure_core_worktree, 0},
{"relative-path", resolve_relative_path, 0},
{"resolve-relative-url-test", resolve_relative_url_test, 0},
{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
{"init", module_init, SUPPORT_SUPER_PREFIX},
{"status", module_status, SUPPORT_SUPER_PREFIX},
- {"print-default-remote", print_default_remote, 0},
{"sync", module_sync, SUPPORT_SUPER_PREFIX},
{"deinit", module_deinit, 0},
{"summary", module_summary, SUPPORT_SUPER_PREFIX},
- {"remote-branch", resolve_remote_submodule_branch, 0},
{"push-check", push_check, 0},
{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
{"is-active", is_active, 0},
diff --git a/builtin/tag.c b/builtin/tag.c
index 2479da0704..e5a8f85693 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -239,7 +239,7 @@ static int build_tag_object(struct strbuf *buf, int sign, struct object_id *resu
{
if (sign && do_sign(buf) < 0)
return error(_("unable to sign the tag"));
- if (write_object_file(buf->buf, buf->len, tag_type, result) < 0)
+ if (write_object_file(buf->buf, buf->len, OBJ_TAG, result) < 0)
return error(_("unable to write tag file"));
return 0;
}
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 4a9466295b..dbeb0680a5 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -177,7 +177,7 @@ static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
struct object_id oid;
if (write_object_file(obj_buf->buffer, obj_buf->size,
- type_name(obj->type), &oid) < 0)
+ obj->type, &oid) < 0)
die("failed to write object %s", oid_to_hex(&obj->oid));
obj->flags |= FLAG_WRITTEN;
}
@@ -243,7 +243,7 @@ static void write_object(unsigned nr, enum object_type type,
void *buf, unsigned long size)
{
if (!strict) {
- if (write_object_file(buf, size, type_name(type),
+ if (write_object_file(buf, size, type,
&obj_list[nr].oid) < 0)
die("failed to write object");
added_object(nr, type, buf, size);
@@ -251,7 +251,7 @@ static void write_object(unsigned nr, enum object_type type,
obj_list[nr].obj = NULL;
} else if (type == OBJ_BLOB) {
struct blob *blob;
- if (write_object_file(buf, size, type_name(type),
+ if (write_object_file(buf, size, type,
&obj_list[nr].oid) < 0)
die("failed to write object");
added_object(nr, type, buf, size);
@@ -266,7 +266,7 @@ static void write_object(unsigned nr, enum object_type type,
} else {
struct object *obj;
int eaten;
- hash_object_file(the_hash_algo, buf, size, type_name(type),
+ hash_object_file(the_hash_algo, buf, size, type,
&obj_list[nr].oid);
added_object(nr, type, buf, size);
obj = parse_object_buffer(the_repository, &obj_list[nr].oid,