aboutsummaryrefslogtreecommitdiffstats
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/bisect--helper.c89
-rw-r--r--builtin/bundle.c1
-rw-r--r--builtin/cat-file.c189
-rw-r--r--builtin/checkout.c45
-rw-r--r--builtin/clone.c2
-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.c26
-rw-r--r--builtin/fetch.c232
-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.c23
-rw-r--r--builtin/ls-files.c4
-rw-r--r--builtin/merge-base.c5
-rw-r--r--builtin/mktag.c9
-rw-r--r--builtin/mktree.c2
-rw-r--r--builtin/notes.c2
-rw-r--r--builtin/pack-objects.c2
-rw-r--r--builtin/read-tree.c14
-rw-r--r--builtin/receive-pack.c2
-rw-r--r--builtin/reflog.c6
-rw-r--r--builtin/remote.c47
-rw-r--r--builtin/replace.c4
-rw-r--r--builtin/sparse-checkout.c81
-rw-r--r--builtin/stash.c2
-rw-r--r--builtin/submodule--helper.c7
-rw-r--r--builtin/tag.c2
-rw-r--r--builtin/unpack-objects.c8
-rw-r--r--builtin/worktree.c138
31 files changed, 757 insertions, 266 deletions
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index f962dbd430..8b2b259ff0 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1089,14 +1089,52 @@ static int bisect_visualize(struct bisect_terms *terms, const char **argv, int a
return res;
}
+static int get_first_good(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
+{
+ oidcpy(cb_data, oid);
+ return 1;
+}
+
+static int verify_good(const struct bisect_terms *terms,
+ const char **quoted_argv)
+{
+ int rc;
+ enum bisect_error res;
+ struct object_id good_rev;
+ struct object_id current_rev;
+ char *good_glob = xstrfmt("%s-*", terms->term_good);
+ int no_checkout = ref_exists("BISECT_HEAD");
+
+ for_each_glob_ref_in(get_first_good, good_glob, "refs/bisect/",
+ &good_rev);
+ free(good_glob);
+
+ if (read_ref(no_checkout ? "BISECT_HEAD" : "HEAD", &current_rev))
+ return -1;
+
+ res = bisect_checkout(&good_rev, no_checkout);
+ if (res != BISECT_OK)
+ return -1;
+
+ printf(_("running %s\n"), quoted_argv[0]);
+ rc = run_command_v_opt(quoted_argv, RUN_USING_SHELL);
+
+ res = bisect_checkout(&current_rev, no_checkout);
+ if (res != BISECT_OK)
+ return -1;
+
+ return rc;
+}
+
static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
{
int res = BISECT_OK;
struct strbuf command = STRBUF_INIT;
- struct strvec args = STRVEC_INIT;
struct strvec run_args = STRVEC_INIT;
const char *new_state;
int temporary_stdout_fd, saved_stdout;
+ int is_first_run = 1;
if (bisect_next_check(terms, NULL))
return BISECT_FAILED;
@@ -1111,16 +1149,37 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
strvec_push(&run_args, command.buf);
while (1) {
- strvec_clear(&args);
-
printf(_("running %s\n"), command.buf);
res = run_command_v_opt(run_args.v, RUN_USING_SHELL);
+ /*
+ * Exit code 126 and 127 can either come from the shell
+ * if it was unable to execute or even find the script,
+ * or from the script itself. Check with a known-good
+ * revision to avoid trashing the bisect run due to a
+ * missing or non-executable script.
+ */
+ if (is_first_run && (res == 126 || res == 127)) {
+ int rc = verify_good(terms, run_args.v);
+ is_first_run = 0;
+ if (rc < 0) {
+ error(_("unable to verify '%s' on good"
+ " revision"), command.buf);
+ res = BISECT_FAILED;
+ break;
+ }
+ if (rc == res) {
+ error(_("bogus exit code %d for good revision"),
+ rc);
+ res = BISECT_FAILED;
+ break;
+ }
+ }
+
if (res < 0 || 128 <= res) {
error(_("bisect run failed: exit code %d from"
" '%s' is < 0 or >= 128"), res, command.buf);
- strbuf_release(&command);
- return res;
+ break;
}
if (res == 125)
@@ -1132,8 +1191,10 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
temporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
- if (temporary_stdout_fd < 0)
- return error_errno(_("cannot open file '%s' for writing"), git_path_bisect_run());
+ if (temporary_stdout_fd < 0) {
+ res = error_errno(_("cannot open file '%s' for writing"), git_path_bisect_run());
+ break;
+ }
fflush(stdout);
saved_stdout = dup(1);
@@ -1158,16 +1219,16 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
res = BISECT_OK;
} else if (res) {
error(_("bisect run failed: 'git bisect--helper --bisect-state"
- " %s' exited with error code %d"), args.v[0], res);
+ " %s' exited with error code %d"), new_state, res);
} else {
continue;
}
-
- strbuf_release(&command);
- strvec_clear(&args);
- strvec_clear(&run_args);
- return res;
+ break;
}
+
+ strbuf_release(&command);
+ strvec_clear(&run_args);
+ return res;
}
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
@@ -1209,7 +1270,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
N_("visualize the bisection"), BISECT_VISUALIZE),
OPT_CMDMODE(0, "bisect-run", &cmdmode,
- N_("use <cmd>... to automatically bisect."), BISECT_RUN),
+ N_("use <cmd>... to automatically bisect"), BISECT_RUN),
OPT_BOOL(0, "no-log", &nolog,
N_("no log for BISECT_WRITE")),
OPT_END()
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..0663661c0b 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 {
@@ -386,7 +395,7 @@ static void batch_object_write(const char *obj_name,
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 +517,135 @@ 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);
+}
+
static int batch_objects(struct batch_options *opt)
{
struct strbuf input = STRBUF_INIT;
@@ -529,14 +667,14 @@ static int batch_objects(struct batch_options *opt)
strbuf_expand(&output, opt->format, expand_format, &data);
data.mark_query = 0;
strbuf_release(&output);
- if (opt->cmdmode)
+ if (opt->transform_mode)
data.split_on_whitespace = 1;
/*
* 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 +728,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 +751,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 +779,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 +807,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 +836,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 +899,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 d9b31bbb6d..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;
@@ -1397,23 +1404,31 @@ static void die_expecting_a_branch(const struct branch_info *branch_info)
{
struct object_id oid;
char *to_free;
+ int code;
if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free, 0) == 1) {
const char *ref = to_free;
if (skip_prefix(ref, "refs/tags/", &ref))
- die(_("a branch is expected, got tag '%s'"), ref);
- if (skip_prefix(ref, "refs/remotes/", &ref))
- die(_("a branch is expected, got remote branch '%s'"), ref);
- die(_("a branch is expected, got '%s'"), ref);
+ code = die_message(_("a branch is expected, got tag '%s'"), ref);
+ else if (skip_prefix(ref, "refs/remotes/", &ref))
+ code = die_message(_("a branch is expected, got remote branch '%s'"), ref);
+ else
+ code = die_message(_("a branch is expected, got '%s'"), ref);
}
- if (branch_info->commit)
- die(_("a branch is expected, got commit '%s'"), branch_info->name);
- /*
- * This case should never happen because we already die() on
- * non-commit, but just in case.
- */
- die(_("a branch is expected, got '%s'"), branch_info->name);
+ else if (branch_info->commit)
+ code = die_message(_("a branch is expected, got commit '%s'"), branch_info->name);
+ else
+ /*
+ * This case should never happen because we already die() on
+ * non-commit, but just in case.
+ */
+ code = die_message(_("a branch is expected, got '%s'"), branch_info->name);
+
+ if (advice_enabled(ADVICE_SUGGEST_DETACHING_HEAD))
+ advise(_("If you want to detach HEAD at the commit, try again with the --detach option."));
+
+ exit(code);
}
static void die_if_some_operation_in_progress(void)
diff --git a/builtin/clone.c b/builtin/clone.c
index a572cda503..0aea177660 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -700,6 +700,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)
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 28f2b9cc91..ad045c7c2d 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -177,8 +177,9 @@ static int global_argc;
static const char **global_argv;
/* Memory pools */
-static struct mem_pool fi_mem_pool = {NULL, 2*1024*1024 -
- sizeof(struct mp_block), 0 };
+static struct mem_pool fi_mem_pool = {
+ .block_alloc = 2*1024*1024 - sizeof(struct mp_block),
+};
/* Atom management */
static unsigned int atom_table_sz = 4451;
@@ -206,7 +207,9 @@ static int import_marks_file_done;
static int relative_marks_paths;
/* Our last blob */
-static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 };
+static struct last_object last_blob = {
+ .data = STRBUF_INIT,
+ };
/* Tree management */
static unsigned int tree_entry_alloc = 1000;
@@ -232,7 +235,10 @@ static struct tag *last_tag;
static whenspec_type whenspec = WHENSPEC_RAW;
static struct strbuf command_buf = STRBUF_INIT;
static int unread_command_buf;
-static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};
+static struct recent_command cmd_hist = {
+ .prev = &cmd_hist,
+ .next = &cmd_hist,
+};
static struct recent_command *cmd_tail = &cmd_hist;
static struct recent_command *rc_free;
static unsigned int cmd_save = 100;
@@ -938,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);
@@ -1092,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);
@@ -2484,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);
@@ -2556,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);
@@ -2652,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..4d12c2fd4d 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;
}
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 3c2e6aee3c..2b2e6eeb82 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -323,8 +323,12 @@ static void use(int bytes)
if (signed_add_overflows(consumed_bytes, bytes))
die(_("pack too large for current definition of off_t"));
consumed_bytes += bytes;
- if (max_input_size && consumed_bytes > max_input_size)
- die(_("pack exceeds maximum allowed size"));
+ if (max_input_size && consumed_bytes > max_input_size) {
+ struct strbuf size_limit = STRBUF_INIT;
+ strbuf_humanise_bytes(&size_limit, max_input_size);
+ die(_("pack exceeds maximum allowed size (%s)"),
+ size_limit.buf);
+ }
}
static const char *open_pack_file(const char *pack_name)
@@ -449,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
@@ -971,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);
@@ -1109,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
@@ -1131,6 +1135,7 @@ static void *threaded_second_pass(void *data)
p = next_p;
}
+ FREE_AND_NULL(child);
}
work_unlock();
}
@@ -1413,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));
/*
@@ -1424,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);
@@ -1703,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)
@@ -1932,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/ls-files.c b/builtin/ls-files.c
index f7ea56cc63..e791b65e7e 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -244,7 +244,7 @@ static void show_ce(struct repository *repo, struct dir_struct *dir,
printf("%s%06o %s %d\t",
tag,
ce->ce_mode,
- find_unique_abbrev(&ce->oid, abbrev),
+ repo_find_unique_abbrev(repo, &ce->oid, abbrev),
ce_stage(ce));
}
write_eolinfo(repo->index, ce, fullname);
@@ -726,7 +726,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
setup_work_tree();
if (recurse_submodules &&
- (show_stage || show_deleted || show_others || show_unmerged ||
+ (show_deleted || show_others || show_unmerged ||
show_killed || show_modified || show_resolve_undo || with_tree))
die("ls-files --recurse-submodules unsupported mode");
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/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/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..47b0e1da7d 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1802,7 +1802,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;
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/receive-pack.c b/builtin/receive-pack.c
index d10aeb7e78..380259869d 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);
diff --git a/builtin/reflog.c b/builtin/reflog.c
index ce1c45b7b6..9407f835cb 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -200,7 +200,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "updateref", &flags,
N_("update the reference to the value of the top reflog entry"),
EXPIRE_REFLOGS_UPDATE_REF),
- OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen.")),
+ OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen")),
OPT_CALLBACK_F(0, "expire", &cmd, N_("timestamp"),
N_("prune entries older than the specified time"),
PARSE_OPT_NONEG,
@@ -213,7 +213,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
N_("prune any reflog entries that point to broken commits")),
OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
OPT_BOOL(1, "single-worktree", &all_worktrees,
- N_("limits processing to reflogs from the current worktree only.")),
+ N_("limits processing to reflogs from the current worktree only")),
OPT_END()
};
@@ -325,7 +325,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "updateref", &flags,
N_("update the reference to the value of the top reflog entry"),
EXPIRE_REFLOGS_UPDATE_REF),
- OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen.")),
+ OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen")),
OPT_END()
};
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/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/sparse-checkout.c b/builtin/sparse-checkout.c
index 9c338d33ea..7f02e4352a 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -1,4 +1,5 @@
#include "builtin.h"
+#include "cache.h"
#include "config.h"
#include "dir.h"
#include "parse-options.h"
@@ -328,11 +329,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;
@@ -348,7 +349,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;
@@ -401,6 +401,7 @@ static int update_modes(int *cone_mode, int *sparse_index)
core_sparse_checkout_cone = 1;
} else {
mode = MODE_ALL_PATTERNS;
+ core_sparse_checkout_cone = 0;
}
if (record_mode && set_config(mode))
return 1;
@@ -681,18 +682,76 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
return result;
}
+static void sanitize_paths(int argc, const char **argv,
+ const char *prefix, int skip_checks)
+{
+ int i;
+
+ if (!argc)
+ return;
+
+ if (prefix && *prefix && core_sparse_checkout_cone) {
+ /*
+ * The args are not pathspecs, so unfortunately we
+ * cannot imitate how cmd_add() uses parse_pathspec().
+ */
+ int prefix_len = strlen(prefix);
+
+ for (i = 0; i < argc; i++)
+ argv[i] = prefix_path(prefix, prefix_len, argv[i]);
+ }
+
+ if (skip_checks)
+ return;
+
+ if (prefix && *prefix && !core_sparse_checkout_cone)
+ die(_("please run from the toplevel directory in non-cone mode"));
+
+ if (core_sparse_checkout_cone) {
+ for (i = 0; i < argc; i++) {
+ if (argv[i][0] == '/')
+ die(_("specify directories rather than patterns (no leading slash)"));
+ if (argv[i][0] == '!')
+ die(_("specify directories rather than patterns. If your directory starts with a '!', pass --skip-checks"));
+ if (strpbrk(argv[i], "*?[]"))
+ die(_("specify directories rather than patterns. If your directory really has any of '*?[]\\' in it, pass --skip-checks"));
+ }
+ }
+
+ for (i = 0; i < argc; i++) {
+ struct cache_entry *ce;
+ struct index_state *index = the_repository->index;
+ int pos = index_name_pos(index, argv[i], strlen(argv[i]));
+
+ if (pos < 0)
+ continue;
+ ce = index->cache[pos];
+ if (S_ISSPARSEDIR(ce->ce_mode))
+ continue;
+
+ if (core_sparse_checkout_cone)
+ die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), argv[i]);
+ else
+ warning(_("pass a leading slash before paths such as '%s' if you want a single file (see NON-CONE PROBLEMS in the git-sparse-checkout manual)."), argv[i]);
+ }
+}
+
static char const * const builtin_sparse_checkout_add_usage[] = {
- N_("git sparse-checkout add (--stdin | <patterns>)"),
+ N_("git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"),
NULL
};
static struct sparse_checkout_add_opts {
+ int skip_checks;
int use_stdin;
} add_opts;
static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
{
static struct option builtin_sparse_checkout_add_options[] = {
+ OPT_BOOL_F(0, "skip-checks", &add_opts.skip_checks,
+ N_("skip some sanity checks on the given paths that might give false positives"),
+ PARSE_OPT_NONEG),
OPT_BOOL(0, "stdin", &add_opts.use_stdin,
N_("read patterns from standard in")),
OPT_END(),
@@ -708,17 +767,20 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
builtin_sparse_checkout_add_usage,
PARSE_OPT_KEEP_UNKNOWN);
+ sanitize_paths(argc, argv, prefix, add_opts.skip_checks);
+
return modify_pattern_list(argc, argv, add_opts.use_stdin, ADD);
}
static char const * const builtin_sparse_checkout_set_usage[] = {
- N_("git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] (--stdin | <patterns>)"),
+ N_("git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] (--stdin | <patterns>)"),
NULL
};
static struct sparse_checkout_set_opts {
int cone_mode;
int sparse_index;
+ int skip_checks;
int use_stdin;
} set_opts;
@@ -732,6 +794,9 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
N_("initialize the sparse-checkout in cone mode")),
OPT_BOOL(0, "sparse-index", &set_opts.sparse_index,
N_("toggle the use of a sparse index")),
+ OPT_BOOL_F(0, "skip-checks", &set_opts.skip_checks,
+ N_("skip some sanity checks on the given paths that might give false positives"),
+ PARSE_OPT_NONEG),
OPT_BOOL_F(0, "stdin", &set_opts.use_stdin,
N_("read patterns from standard in"),
PARSE_OPT_NONEG),
@@ -759,6 +824,8 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
if (!core_sparse_checkout_cone && argc == 0) {
argv = default_patterns;
argc = default_patterns_nr;
+ } else {
+ sanitize_paths(argc, argv, prefix, set_opts.skip_checks);
}
return modify_pattern_list(argc, argv, set_opts.use_stdin, REPLACE);
@@ -787,15 +854,15 @@ static int sparse_checkout_reapply(int argc, const char **argv)
if (!core_apply_sparse_checkout)
die(_("must be in a sparse-checkout to reapply sparsity patterns"));
+ reapply_opts.cone_mode = -1;
+ reapply_opts.sparse_index = -1;
+
argc = parse_options(argc, argv, NULL,
builtin_sparse_checkout_reapply_options,
builtin_sparse_checkout_reapply_usage, 0);
repo_read_index(the_repository);
- reapply_opts.cone_mode = -1;
- reapply_opts.sparse_index = -1;
-
if (update_modes(&reapply_opts.cone_mode, &reapply_opts.sparse_index))
return 1;
diff --git a/builtin/stash.c b/builtin/stash.c
index 3e2f478b76..242e73cbb0 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1317,7 +1317,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
if (flags & REF_ISSYMREF)
- branch_name = strrchr(branch_ref, '/') + 1;
+ skip_prefix(branch_ref, "refs/heads/", &branch_name);
head_short_sha1 = find_unique_abbrev(&head_commit->object.oid,
DEFAULT_ABBREV);
strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1);
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index eeacefcc38..2f7c58362b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1882,7 +1882,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
OPT_STRING(0, "depth", &clone_data.depth,
N_("string"),
N_("depth for shallow clones")),
- OPT__QUIET(&quiet, "Suppress output for cloning a submodule"),
+ OPT__QUIET(&quiet, "suppress output for cloning a submodule"),
OPT_BOOL(0, "progress", &progress,
N_("force cloning progress")),
OPT_BOOL(0, "require-init", &require_init,
@@ -3309,6 +3309,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 +3361,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 +3415,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;
}
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,
diff --git a/builtin/worktree.c b/builtin/worktree.c
index e23e6343d0..4eaba2a8fd 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -236,6 +236,74 @@ static void check_candidate_path(const char *path,
die(_("'%s' is a missing but already registered worktree;\nuse '%s -f' to override, or 'prune' or 'remove' to clear"), path, cmd);
}
+static void copy_sparse_checkout(const char *worktree_git_dir)
+{
+ char *from_file = git_pathdup("info/sparse-checkout");
+ char *to_file = xstrfmt("%s/info/sparse-checkout", worktree_git_dir);
+
+ if (file_exists(from_file)) {
+ if (safe_create_leading_directories(to_file) ||
+ copy_file(to_file, from_file, 0666))
+ error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"),
+ from_file, to_file);
+ }
+
+ free(from_file);
+ free(to_file);
+}
+
+static void copy_filtered_worktree_config(const char *worktree_git_dir)
+{
+ char *from_file = git_pathdup("config.worktree");
+ char *to_file = xstrfmt("%s/config.worktree", worktree_git_dir);
+
+ if (file_exists(from_file)) {
+ struct config_set cs = { { 0 } };
+ const char *core_worktree;
+ int bare;
+
+ if (safe_create_leading_directories(to_file) ||
+ copy_file(to_file, from_file, 0666)) {
+ error(_("failed to copy worktree config from '%s' to '%s'"),
+ from_file, to_file);
+ goto worktree_copy_cleanup;
+ }
+
+ git_configset_init(&cs);
+ git_configset_add_file(&cs, from_file);
+
+ if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
+ bare &&
+ git_config_set_multivar_in_file_gently(
+ to_file, "core.bare", NULL, "true", 0))
+ error(_("failed to unset '%s' in '%s'"),
+ "core.bare", to_file);
+ if (!git_configset_get_value(&cs, "core.worktree", &core_worktree) &&
+ git_config_set_in_file_gently(to_file,
+ "core.worktree", NULL))
+ error(_("failed to unset '%s' in '%s'"),
+ "core.worktree", to_file);
+
+ git_configset_clear(&cs);
+ }
+
+worktree_copy_cleanup:
+ free(from_file);
+ free(to_file);
+}
+
+static int checkout_worktree(const struct add_opts *opts,
+ struct strvec *child_env)
+{
+ struct child_process cp = CHILD_PROCESS_INIT;
+ cp.git_cmd = 1;
+ strvec_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
+ if (opts->quiet)
+ strvec_push(&cp.args, "--quiet");
+ strvec_pushv(&cp.env_array, child_env->v);
+ return run_command(&cp);
+}
+
static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
@@ -339,64 +407,16 @@ static int add_worktree(const char *path, const char *refname,
* If the current worktree has sparse-checkout enabled, then copy
* the sparse-checkout patterns from the current worktree.
*/
- if (core_apply_sparse_checkout) {
- char *from_file = git_pathdup("info/sparse-checkout");
- char *to_file = xstrfmt("%s/info/sparse-checkout",
- sb_repo.buf);
-
- if (file_exists(from_file)) {
- if (safe_create_leading_directories(to_file) ||
- copy_file(to_file, from_file, 0666))
- error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"),
- from_file, to_file);
- }
-
- free(from_file);
- free(to_file);
- }
+ if (core_apply_sparse_checkout)
+ copy_sparse_checkout(sb_repo.buf);
/*
* If we are using worktree config, then copy all current config
* values from the current worktree into the new one, that way the
* new worktree behaves the same as this one.
*/
- if (repository_format_worktree_config) {
- char *from_file = git_pathdup("config.worktree");
- char *to_file = xstrfmt("%s/config.worktree",
- sb_repo.buf);
-
- if (file_exists(from_file)) {
- struct config_set cs = { { 0 } };
- const char *core_worktree;
- int bare;
-
- if (safe_create_leading_directories(to_file) ||
- copy_file(to_file, from_file, 0666)) {
- error(_("failed to copy worktree config from '%s' to '%s'"),
- from_file, to_file);
- goto worktree_copy_cleanup;
- }
-
- git_configset_init(&cs);
- git_configset_add_file(&cs, from_file);
-
- if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
- bare &&
- git_config_set_multivar_in_file_gently(
- to_file, "core.bare", NULL, "true", 0))
- error(_("failed to unset 'core.bare' in '%s'"), to_file);
- if (!git_configset_get_value(&cs, "core.worktree", &core_worktree) &&
- git_config_set_in_file_gently(to_file,
- "core.worktree", NULL))
- error(_("failed to unset 'core.worktree' in '%s'"), to_file);
-
- git_configset_clear(&cs);
- }
-
-worktree_copy_cleanup:
- free(from_file);
- free(to_file);
- }
+ if (repository_format_worktree_config)
+ copy_filtered_worktree_config(sb_repo.buf);
strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
@@ -417,17 +437,9 @@ worktree_copy_cleanup:
if (ret)
goto done;
- if (opts->checkout) {
- struct child_process cp = CHILD_PROCESS_INIT;
- cp.git_cmd = 1;
- strvec_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
- if (opts->quiet)
- strvec_push(&cp.args, "--quiet");
- strvec_pushv(&cp.env_array, child_env.v);
- ret = run_command(&cp);
- if (ret)
- goto done;
- }
+ if (opts->checkout &&
+ (ret = checkout_worktree(opts, &child_env)))
+ goto done;
is_junk = 0;
FREE_AND_NULL(junk_work_tree);