summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c14
-rw-r--r--builtin/am.c9
-rw-r--r--builtin/bisect--helper.c95
-rw-r--r--builtin/blame.c8
-rw-r--r--builtin/branch.c70
-rw-r--r--builtin/bundle.c1
-rw-r--r--builtin/cat-file.c189
-rw-r--r--builtin/checkout-index.c41
-rw-r--r--builtin/checkout.c67
-rw-r--r--builtin/clean.c3
-rw-r--r--builtin/clone.c64
-rw-r--r--builtin/commit-graph.c6
-rw-r--r--builtin/commit.c54
-rw-r--r--builtin/config.c4
-rw-r--r--builtin/count-objects.c2
-rw-r--r--builtin/difftool.c5
-rw-r--r--builtin/fast-export.c4
-rw-r--r--builtin/fast-import.c27
-rw-r--r--builtin/fetch.c250
-rw-r--r--builtin/grep.c39
-rw-r--r--builtin/hash-object.c13
-rw-r--r--builtin/help.c67
-rw-r--r--builtin/index-pack.c25
-rw-r--r--builtin/log.c33
-rw-r--r--builtin/ls-files.c4
-rw-r--r--builtin/ls-remote.c3
-rw-r--r--builtin/ls-tree.c2
-rw-r--r--builtin/merge-base.c11
-rw-r--r--builtin/merge-recursive.c2
-rw-r--r--builtin/merge.c34
-rw-r--r--builtin/mktag.c11
-rw-r--r--builtin/mktree.c4
-rw-r--r--builtin/name-rev.c2
-rw-r--r--builtin/notes.c8
-rw-r--r--builtin/pack-objects.c21
-rw-r--r--builtin/patch-id.c9
-rw-r--r--builtin/prune-packed.c2
-rw-r--r--builtin/pull.c12
-rw-r--r--builtin/push.c2
-rw-r--r--builtin/read-tree.c14
-rw-r--r--builtin/rebase.c103
-rw-r--r--builtin/receive-pack.c28
-rw-r--r--builtin/reflog.c463
-rw-r--r--builtin/remote.c49
-rw-r--r--builtin/replace.c6
-rw-r--r--builtin/reset.c13
-rw-r--r--builtin/rev-list.c31
-rw-r--r--builtin/send-pack.c2
-rw-r--r--builtin/shortlog.c11
-rw-r--r--builtin/show-branch.c1
-rw-r--r--builtin/sparse-checkout.c117
-rw-r--r--builtin/stash.c30
-rw-r--r--builtin/stripspace.c4
-rw-r--r--builtin/submodule--helper.c77
-rw-r--r--builtin/tag.c3
-rw-r--r--builtin/unpack-objects.c8
-rw-r--r--builtin/update-index.c17
-rw-r--r--builtin/update-server-info.c2
-rw-r--r--builtin/worktree.c97
59 files changed, 1321 insertions, 972 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 84dff3e796..3ffb86a433 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -32,7 +32,6 @@ static int add_renormalize;
static int pathspec_file_nul;
static int include_sparse;
static const char *pathspec_from_file;
-static int legacy_stash_p; /* support for the scripted `git stash` */
struct update_callback_data {
int flags;
@@ -388,8 +387,6 @@ static struct option builtin_add_options[] = {
N_("override the executable bit of the listed files")),
OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
N_("warn when adding an embedded repository")),
- OPT_HIDDEN_BOOL(0, "legacy-stash-p", &legacy_stash_p,
- N_("backend for `git stash -p`")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END(),
@@ -512,17 +509,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch");
exit(interactive_add(argv + 1, prefix, patch_interactive));
}
- if (legacy_stash_p) {
- struct pathspec pathspec;
-
- parse_pathspec(&pathspec, 0,
- PATHSPEC_PREFER_FULL |
- PATHSPEC_SYMLINK_LEADING_PATH |
- PATHSPEC_PREFIX_ORIGIN,
- prefix, argv);
-
- return run_add_interactive(NULL, "--patch=stash", &pathspec);
- }
if (edit_interactive) {
if (pathspec_from_file)
diff --git a/builtin/am.c b/builtin/am.c
index 7de2c89ef2..0f4111bafa 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -34,6 +34,7 @@
#include "string-list.h"
#include "packfile.h"
#include "repository.h"
+#include "pretty.h"
/**
* Returns the length of the first line of msg.
@@ -199,7 +200,7 @@ static int am_option_parse_empty(const struct option *opt,
else if (!strcmp(arg, "keep"))
*opt_value = KEEP_EMPTY_COMMIT;
else
- return error(_("Invalid value for --empty: %s"), arg);
+ return error(_("invalid value for '%s': '%s'"), "--empty", arg);
return 0;
}
@@ -2239,7 +2240,8 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
* when you add new options
*/
else
- return error(_("Invalid value for --patch-format: %s"), arg);
+ return error(_("invalid value for '%s': '%s'"),
+ "--patch-format", arg);
return 0;
}
@@ -2282,7 +2284,8 @@ static int parse_opt_show_current_patch(const struct option *opt, const char *ar
break;
}
if (new_value >= ARRAY_SIZE(valid_modes))
- return error(_("Invalid value for --show-current-patch: %s"), arg);
+ return error(_("invalid value for '%s': '%s'"),
+ "--show-current-patch", arg);
}
if (resume->mode == RESUME_SHOW_PATCH && new_value != resume->sub_mode)
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 28a2e6a575..8b2b259ff0 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -22,15 +22,15 @@ static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
static const char * const git_bisect_helper_usage[] = {
N_("git bisect--helper --bisect-reset [<commit>]"),
- N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
+ "git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
- N_("git bisect--helper --bisect-next"),
+ "git bisect--helper --bisect-next",
N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
N_("git bisect--helper --bisect-replay <filename>"),
N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
- N_("git bisect--helper --bisect-visualize"),
+ "git bisect--helper --bisect-visualize",
N_("git bisect--helper --bisect-run <cmd>..."),
NULL
};
@@ -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/blame.c b/builtin/blame.c
index 7fafeac408..8d15b68afc 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -721,8 +721,8 @@ static int git_blame_config(const char *var, const char *value, void *cb)
}
if (!strcmp(var, "color.blame.repeatedlines")) {
if (color_parse_mem(value, strlen(value), repeated_meta_color))
- warning(_("invalid color '%s' in color.blame.repeatedLines"),
- value);
+ warning(_("invalid value for '%s': '%s'"),
+ "color.blame.repeatedLines", value);
return 0;
}
if (!strcmp(var, "color.blame.highlightrecent")) {
@@ -739,7 +739,8 @@ static int git_blame_config(const char *var, const char *value, void *cb)
coloring_mode &= ~(OUTPUT_COLOR_LINE |
OUTPUT_SHOW_AGE_WITH_COLOR);
} else {
- warning(_("invalid value for blame.coloring"));
+ warning(_("invalid value for '%s': '%s'"),
+ "blame.coloring", value);
return 0;
}
}
@@ -934,6 +935,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
parse_revision_opt(&revs, &ctx, options, blame_opt_usage);
}
parse_done:
+ revision_opts_finish(&revs);
no_whole_file_rename = !revs.diffopt.flags.follow_renames;
xdl_opts |= revs.diffopt.xdl_opts & XDF_INDENT_HEURISTIC;
revs.diffopt.flags.follow_renames = 0;
diff --git a/builtin/branch.c b/builtin/branch.c
index 4ce2a24754..5d00d0b8d3 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -27,7 +27,8 @@
static const char * const builtin_branch_usage[] = {
N_("git branch [<options>] [-r | -a] [--merged] [--no-merged]"),
- N_("git branch [<options>] [-l] [-f] <branch-name> [<start-point>]"),
+ N_("git branch [<options>] [-f] [--recurse-submodules] <branch-name> [<start-point>]"),
+ N_("git branch [<options>] [-l] [<pattern>...]"),
N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
N_("git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"),
@@ -38,6 +39,8 @@ static const char * const builtin_branch_usage[] = {
static const char *head;
static struct object_id head_oid;
+static int recurse_submodules = 0;
+static int submodule_propagate_branches = 0;
static int branch_use_color = -1;
static char branch_colors[][COLOR_MAXLEN] = {
@@ -99,6 +102,15 @@ static int git_branch_config(const char *var, const char *value, void *cb)
return config_error_nonbool(var);
return color_parse(value, branch_colors[slot]);
}
+ if (!strcmp(var, "submodule.recurse")) {
+ recurse_submodules = git_config_bool(var, value);
+ return 0;
+ }
+ if (!strcasecmp(var, "submodule.propagateBranches")) {
+ submodule_propagate_branches = git_config_bool(var, value);
+ return 0;
+ }
+
return git_color_default_config(var, value, cb);
}
@@ -621,14 +633,16 @@ static int edit_branch_description(const char *branch_name)
int cmd_branch(int argc, const char **argv, const char *prefix)
{
- int delete = 0, rename = 0, copy = 0, force = 0, list = 0;
- int show_current = 0;
- int reflog = 0, edit_description = 0;
- int quiet = 0, unset_upstream = 0;
+ /* possible actions */
+ int delete = 0, rename = 0, copy = 0, list = 0,
+ unset_upstream = 0, show_current = 0, edit_description = 0;
const char *new_upstream = NULL;
+ int noncreate_actions = 0;
+ /* possible options */
+ int reflog = 0, quiet = 0, icase = 0, force = 0,
+ recurse_submodules_explicit = 0;
enum branch_track track;
struct ref_filter filter;
- int icase = 0;
static struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
@@ -677,6 +691,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_CALLBACK(0, "points-at", &filter.points_at, N_("object"),
N_("print only branches of the object"), parse_opt_object_name),
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
+ OPT_BOOL(0, "recurse-submodules", &recurse_submodules_explicit, N_("recurse through submodules")),
OPT_STRING( 0 , "format", &format.format, N_("format"), N_("format to use for the output")),
OPT_END(),
};
@@ -713,10 +728,23 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
filter.reachable_from || filter.unreachable_from || filter.points_at.nr)
list = 1;
- if (!!delete + !!rename + !!copy + !!new_upstream + !!show_current +
- list + edit_description + unset_upstream > 1)
+ noncreate_actions = !!delete + !!rename + !!copy + !!new_upstream +
+ !!show_current + !!list + !!edit_description +
+ !!unset_upstream;
+ if (noncreate_actions > 1)
usage_with_options(builtin_branch_usage, options);
+ if (recurse_submodules_explicit) {
+ if (!submodule_propagate_branches)
+ die(_("branch with --recurse-submodules can only be used if submodule.propagateBranches is enabled"));
+ if (noncreate_actions)
+ die(_("--recurse-submodules can only be used to create branches"));
+ }
+
+ recurse_submodules =
+ (recurse_submodules || recurse_submodules_explicit) &&
+ submodule_propagate_branches;
+
if (filter.abbrev == -1)
filter.abbrev = DEFAULT_ABBREV;
filter.ignore_case = icase;
@@ -828,12 +856,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!ref_exists(branch->refname))
die(_("branch '%s' does not exist"), branch->name);
- /*
- * create_branch takes care of setting up the tracking
- * info and making sure new_upstream is correct
- */
- create_branch(the_repository, branch->name, new_upstream,
- 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
+ dwim_and_setup_tracking(the_repository, branch->name,
+ new_upstream, BRANCH_TRACK_OVERRIDE,
+ quiet);
} else if (unset_upstream) {
struct branch *branch = branch_get(argv[0]);
struct strbuf buf = STRBUF_INIT;
@@ -857,7 +882,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
strbuf_addf(&buf, "branch.%s.merge", branch->name);
git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_release(&buf);
- } else if (argc > 0 && argc <= 2) {
+ } else if (!noncreate_actions && argc > 0 && argc <= 2) {
+ const char *branch_name = argv[0];
+ const char *start_name = argc == 2 ? argv[1] : head;
+
if (filter.kind != FILTER_REFS_BRANCHES)
die(_("The -a, and -r, options to 'git branch' do not take a branch name.\n"
"Did you mean to use: -a|-r --list <pattern>?"));
@@ -865,10 +893,14 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (track == BRANCH_TRACK_OVERRIDE)
die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead."));
- create_branch(the_repository,
- argv[0], (argc == 2) ? argv[1] : head,
- force, 0, reflog, quiet, track);
-
+ if (recurse_submodules) {
+ create_branches_recursively(the_repository, branch_name,
+ start_name, NULL, force,
+ reflog, quiet, track, 0);
+ return 0;
+ }
+ create_branch(the_repository, branch_name, start_name, force, 0,
+ reflog, quiet, track, 0);
} else
usage_with_options(builtin_branch_usage, options);
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-index.c b/builtin/checkout-index.c
index e21620d964..97e06e8c52 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -7,6 +7,7 @@
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "builtin.h"
#include "config.h"
+#include "dir.h"
#include "lockfile.h"
#include "quote.h"
#include "cache-tree.h"
@@ -17,6 +18,7 @@
#define CHECKOUT_ALL 4
static int nul_term_line;
static int checkout_stage; /* default to checkout stage0 */
+static int ignore_skip_worktree; /* default to 0 */
static int to_tempfile;
static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
@@ -65,6 +67,8 @@ static int checkout_file(const char *name, const char *prefix)
int namelen = strlen(name);
int pos = cache_name_pos(name, namelen);
int has_same_name = 0;
+ int is_file = 0;
+ int is_skipped = 1;
int did_checkout = 0;
int errs = 0;
@@ -78,6 +82,12 @@ static int checkout_file(const char *name, const char *prefix)
break;
has_same_name = 1;
pos++;
+ if (S_ISSPARSEDIR(ce->ce_mode))
+ break;
+ is_file = 1;
+ if (!ignore_skip_worktree && ce_skip_worktree(ce))
+ break;
+ is_skipped = 0;
if (ce_stage(ce) != checkout_stage
&& (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
continue;
@@ -106,6 +116,11 @@ static int checkout_file(const char *name, const char *prefix)
fprintf(stderr, "git checkout-index: %s ", name);
if (!has_same_name)
fprintf(stderr, "is not in the cache");
+ else if (!is_file)
+ fprintf(stderr, "is a sparse directory");
+ else if (is_skipped)
+ fprintf(stderr, "has skip-worktree enabled; "
+ "use '--ignore-skip-worktree-bits' to checkout");
else if (checkout_stage)
fprintf(stderr, "does not exist at stage %d",
checkout_stage);
@@ -121,10 +136,27 @@ static int checkout_all(const char *prefix, int prefix_length)
int i, errs = 0;
struct cache_entry *last_ce = NULL;
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
for (i = 0; i < active_nr ; i++) {
struct cache_entry *ce = active_cache[i];
+
+ if (S_ISSPARSEDIR(ce->ce_mode)) {
+ if (!ce_skip_worktree(ce))
+ BUG("sparse directory '%s' does not have skip-worktree set", ce->name);
+
+ /*
+ * If the current entry is a sparse directory and skip-worktree
+ * entries are being checked out, expand the index and continue
+ * the loop on the current index position (now pointing to the
+ * first entry inside the expanded sparse directory).
+ */
+ if (ignore_skip_worktree) {
+ ensure_full_index(&the_index);
+ ce = active_cache[i];
+ }
+ }
+
+ if (!ignore_skip_worktree && ce_skip_worktree(ce))
+ continue;
if (ce_stage(ce) != checkout_stage
&& (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
continue;
@@ -185,6 +217,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
struct option builtin_checkout_index_options[] = {
OPT_BOOL('a', "all", &all,
N_("check out all files in the index")),
+ OPT_BOOL(0, "ignore-skip-worktree-bits", &ignore_skip_worktree,
+ N_("do not skip files with skip-worktree set")),
OPT__FORCE(&force, N_("force overwrite of existing files"), 0),
OPT__QUIET(&quiet,
N_("no warning for existing files and files not in index")),
@@ -212,6 +246,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
prefix_length = prefix ? strlen(prefix) : 0;
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
if (read_cache() < 0) {
die("invalid cache");
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 8f010412a9..797681481d 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -246,6 +246,7 @@ static int checkout_merged(int pos, const struct checkout *state,
struct cache_entry *ce = active_cache[pos];
const char *path = ce->name;
mmfile_t ancestor, ours, theirs;
+ enum ll_merge_result merge_status;
int status;
struct object_id oid;
mmbuffer_t result_buf;
@@ -276,13 +277,16 @@ static int checkout_merged(int pos, const struct checkout *state,
memset(&ll_opts, 0, sizeof(ll_opts));
git_config_get_bool("merge.renormalize", &renormalize);
ll_opts.renormalize = renormalize;
- status = ll_merge(&result_buf, path, &ancestor, "base",
- &ours, "ours", &theirs, "theirs",
- state->istate, &ll_opts);
+ merge_status = ll_merge(&result_buf, path, &ancestor, "base",
+ &ours, "ours", &theirs, "theirs",
+ state->istate, &ll_opts);
free(ancestor.ptr);
free(ours.ptr);
free(theirs.ptr);
- if (status < 0 || !result_buf.ptr) {
+ if (merge_status == LL_MERGE_BINARY_CONFLICT)
+ warning("Cannot merge binary files: %s (%s vs. %s)",
+ path, "ours", "theirs");
+ if (merge_status < 0 || !result_buf.ptr) {
free(result_buf.ptr);
return error(_("path '%s': cannot merge"), path);
}
@@ -299,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);
@@ -734,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;
@@ -761,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;
@@ -905,7 +916,8 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
opts->new_branch_force ? 1 : 0,
opts->new_branch_log,
opts->quiet,
- opts->track);
+ opts->track,
+ 0);
free(new_branch_info->name);
free(new_branch_info->refname);
new_branch_info->name = xstrdup(opts->new_branch);
@@ -1392,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)
@@ -1603,9 +1623,10 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->show_progress = -1;
git_config(git_checkout_config, opts);
-
- prepare_repo_settings(the_repository);
- the_repository->settings.command_requires_full_index = 0;
+ if (the_repository->gitdir) {
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+ }
opts->track = BRANCH_TRACK_UNSPECIFIED;
diff --git a/builtin/clean.c b/builtin/clean.c
index 3ff02bbbff..5466636e66 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -1009,6 +1009,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
dir.flags |= DIR_KEEP_UNTRACKED_CONTENTS;
}
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+
if (read_cache() < 0)
die(_("index file corrupt"));
diff --git a/builtin/clone.c b/builtin/clone.c
index 9c29093b35..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:
@@ -72,6 +73,8 @@ static int option_dissociate;
static int max_jobs = -1;
static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
static struct list_objects_filter_options filter_options;
+static int option_filter_submodules = -1; /* unspecified */
+static int config_filter_submodules = -1; /* unspecified */
static struct string_list server_options = STRING_LIST_INIT_NODUP;
static int option_remote_submodules;
@@ -151,6 +154,8 @@ static struct option builtin_clone_options[] = {
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
TRANSPORT_FAMILY_IPV6),
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+ OPT_BOOL(0, "also-filter-submodules", &option_filter_submodules,
+ N_("apply partial clone filters to submodules")),
OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
N_("any cloned submodules will use their remote-tracking branch")),
OPT_BOOL(0, "sparse", &option_sparse_checkout,
@@ -651,7 +656,7 @@ static int git_sparse_checkout_init(const char *repo)
return result;
}
-static int checkout(int submodule_progress)
+static int checkout(int submodule_progress, int filter_submodules)
{
struct object_id oid;
char *head;
@@ -696,6 +701,8 @@ static int checkout(int submodule_progress)
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)
@@ -730,6 +737,10 @@ static int checkout(int submodule_progress)
strvec_push(&args, "--no-fetch");
}
+ if (filter_submodules && filter_options.choice)
+ strvec_pushf(&args, "--filter=%s",
+ expand_list_objects_filter_spec(&filter_options));
+
if (option_single_branch >= 0)
strvec_push(&args, option_single_branch ?
"--single-branch" :
@@ -750,6 +761,8 @@ static int git_clone_config(const char *k, const char *v, void *cb)
}
if (!strcmp(k, "clone.rejectshallow"))
config_reject_shallow = git_config_bool(k, v);
+ if (!strcmp(k, "clone.filtersubmodules"))
+ config_filter_submodules = git_config_bool(k, v);
return git_default_config(k, v, cb);
}
@@ -872,6 +885,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct remote *remote;
int err = 0, complete_refs_before_fetch = 1;
int submodule_progress;
+ int filter_submodules = 0;
struct transport_ls_refs_options transport_ls_refs_options =
TRANSPORT_LS_REFS_OPTIONS_INIT;
@@ -1068,6 +1082,27 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
reject_shallow = option_reject_shallow;
/*
+ * If option_filter_submodules is specified from CLI option,
+ * ignore config_filter_submodules from git_clone_config.
+ */
+ if (config_filter_submodules != -1)
+ filter_submodules = config_filter_submodules;
+ if (option_filter_submodules != -1)
+ filter_submodules = option_filter_submodules;
+
+ /*
+ * Exit if the user seems to be doing something silly with submodule
+ * filter flags (but not with filter configs, as those should be
+ * set-and-forget).
+ */
+ if (option_filter_submodules > 0 && !filter_options.choice)
+ die(_("the option '%s' requires '%s'"),
+ "--also-filter-submodules", "--filter");
+ if (option_filter_submodules > 0 && !option_recurse_submodules.nr)
+ die(_("the option '%s' requires '%s'"),
+ "--also-filter-submodules", "--recurse-submodules");
+
+ /*
* apply the remote name provided by --origin only after this second
* call to git_config, to ensure it overrides all config-based values.
*/
@@ -1138,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)
@@ -1235,7 +1282,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
else {
const char *branch;
- char *ref;
+ const char *ref;
+ char *ref_free = NULL;
if (option_branch)
die(_("Remote branch %s not found in upstream %s"),
@@ -1251,17 +1299,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
skip_prefix(transport_ls_refs_options.unborn_head_target,
"refs/heads/", &branch)) {
ref = transport_ls_refs_options.unborn_head_target;
- transport_ls_refs_options.unborn_head_target = NULL;
create_symref("HEAD", ref, reflog_msg.buf);
} else {
branch = git_default_branch_name(0);
- ref = xstrfmt("refs/heads/%s", branch);
+ ref_free = xstrfmt("refs/heads/%s", branch);
+ ref = ref_free;
}
if (!option_bare)
install_branch_config(0, branch, remote_name, ref);
-
- free(ref);
+ free(ref_free);
}
write_refspec_config(src_ref_prefix, our_head_points_at,
@@ -1300,7 +1347,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
junk_mode = JUNK_LEAVE_REPO;
- err = checkout(submodule_progress);
+ err = checkout(submodule_progress, filter_submodules);
free(remote_name);
strbuf_release(&reflog_msg);
@@ -1313,7 +1360,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
UNLEAK(repo);
junk_mode = JUNK_LEAVE_ALL;
- strvec_clear(&transport_ls_refs_options.ref_prefixes);
- free(transport_ls_refs_options.unborn_head_target);
+ transport_ls_refs_options_release(&transport_ls_refs_options);
return err;
}
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/commit.c b/builtin/commit.c
index b9ed0374e3..009a1de0a3 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -37,6 +37,7 @@
#include "help.h"
#include "commit-reach.h"
#include "commit-graph.h"
+#include "pretty.h"
static const char * const builtin_commit_usage[] = {
N_("git commit [<options>] [--] <pathspec>..."),
@@ -725,11 +726,13 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
int old_display_comment_prefix;
int merge_contains_scissors = 0;
+ int invoked_hook;
/* This checks and barfs if author is badly specified */
determine_author_info(author_ident);
- if (!no_verify && run_commit_hook(use_editor, index_file, "pre-commit", NULL))
+ if (!no_verify && run_commit_hook(use_editor, index_file, &invoked_hook,
+ "pre-commit", NULL))
return 0;
if (squash_message) {
@@ -1052,10 +1055,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
return 0;
}
- if (!no_verify && hook_exists("pre-commit")) {
+ if (!no_verify && invoked_hook) {
/*
- * Re-read the index as pre-commit hook could have updated it,
- * and write it out as a tree. We must do this before we invoke
+ * Re-read the index as the pre-commit-commit hook was invoked
+ * and could have updated it. We must do this before we invoke
* the editor and after we invoke run_status above.
*/
discard_cache();
@@ -1067,7 +1070,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
return 0;
}
- if (run_commit_hook(use_editor, index_file, "prepare-commit-msg",
+ if (run_commit_hook(use_editor, index_file, NULL, "prepare-commit-msg",
git_path_commit_editmsg(), hook_arg1, hook_arg2, NULL))
return 0;
@@ -1084,7 +1087,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
}
if (!no_verify &&
- run_commit_hook(use_editor, index_file, "commit-msg", git_path_commit_editmsg(), NULL)) {
+ run_commit_hook(use_editor, index_file, NULL, "commit-msg",
+ git_path_commit_editmsg(), NULL)) {
return 0;
}
@@ -1242,8 +1246,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
struct commit *current_head,
struct wt_status *s)
{
- int f = 0;
-
argc = parse_options(argc, argv, prefix, options, usage, 0);
finalize_deferred_config(s);
@@ -1251,7 +1253,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
force_author = find_author_by_nickname(force_author);
if (force_author && renew_authorship)
- die(_("Using both --reset-author and --author does not make sense"));
+ die(_("options '%s' and '%s' cannot be used together"), "--reset-author", "--author");
if (logfile || have_option_m || use_message)
use_editor = 0;
@@ -1268,20 +1270,16 @@ static int parse_and_validate_options(int argc, const char *argv[],
die(_("You are in the middle of a rebase -- cannot amend."));
}
if (fixup_message && squash_message)
- die(_("Options --squash and --fixup cannot be used together"));
- if (use_message)
- f++;
- if (edit_message)
- f++;
- if (fixup_message)
- f++;
- if (logfile)
- f++;
- if (f > 1)
- die(_("Only one of -c/-C/-F/--fixup can be used."));
- if (have_option_m && (edit_message || use_message || logfile))
- die((_("Option -m cannot be combined with -c/-C/-F.")));
- if (f || have_option_m)
+ die(_("options '%s' and '%s' cannot be used together"), "--squash", "--fixup");
+ die_for_incompatible_opt4(!!use_message, "-C",
+ !!edit_message, "-c",
+ !!logfile, "-F",
+ !!fixup_message, "--fixup");
+ die_for_incompatible_opt4(have_option_m, "-m",
+ !!edit_message, "-c",
+ !!use_message, "-C",
+ !!logfile, "-F");
+ if (use_message || edit_message || logfile ||fixup_message || have_option_m)
template_file = NULL;
if (edit_message)
use_message = edit_message;
@@ -1306,9 +1304,10 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (patch_interactive)
interactive = 1;
- if (also + only + all + interactive > 1)
- die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
-
+ die_for_incompatible_opt4(also, "-i/--include",
+ only, "-o/--only",
+ all, "-a/--all",
+ interactive, "--interactive/-p/--patch");
if (fixup_message) {
/*
* We limit --fixup's suboptions to only alpha characters.
@@ -1845,7 +1844,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
repo_rerere(the_repository, 0);
run_auto_maintenance(quiet);
- run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
+ run_commit_hook(use_editor, get_index_file(), NULL, "post-commit",
+ NULL);
if (amend && !no_post_rewrite) {
commit_post_rewrite(the_repository, current_head, &oid);
}
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/count-objects.c b/builtin/count-objects.c
index 3fae474f6f..07b9419596 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -87,7 +87,7 @@ static int print_alternate(struct object_directory *odb, void *data)
}
static char const * const count_objects_usage[] = {
- N_("git count-objects [-v] [-H | --human-readable]"),
+ "git count-objects [-v] [-H | --human-readable]",
NULL
};
diff --git a/builtin/difftool.c b/builtin/difftool.c
index c79fbbf67e..faa3507369 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -732,8 +732,9 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
} else if (dir_diff)
die(_("options '%s' and '%s' cannot be used together"), "--dir-diff", "--no-index");
- if (use_gui_tool + !!difftool_cmd + !!extcmd > 1)
- die(_("options '%s', '%s', and '%s' cannot be used together"), "--gui", "--tool", "--extcmd");
+ die_for_incompatible_opt3(use_gui_tool, "--gui",
+ !!difftool_cmd, "--tool",
+ !!extcmd, "--extcmd");
if (use_gui_tool)
setenv("GIT_MERGETOOL_GUI", "true", 1);
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 9f1c730e58..a7d72697fb 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -26,7 +26,7 @@
#include "commit-slab.h"
static const char *fast_export_usage[] = {
- N_("git fast-export [rev-list-opts]"),
+ N_("git fast-export [<rev-list-opts>]"),
NULL
};
@@ -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 2b2e28bad7..ad045c7c2d 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -19,6 +19,7 @@
#include "mem-pool.h"
#include "commit-reach.h"
#include "khash.h"
+#include "date.h"
#define PACK_ID_BITS 16
#define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
@@ -176,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;
@@ -205,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;
@@ -231,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;
@@ -937,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);
@@ -1091,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);
@@ -2483,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);
@@ -2555,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);
@@ -2651,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 6f5e157863..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;
@@ -764,8 +786,8 @@ static void prepare_format_display(struct ref *ref_map)
else if (!strcasecmp(format, "compact"))
compact_format = 1;
else
- die(_("configuration fetch.output contains invalid value %s"),
- format);
+ die(_("invalid value for '%s': '%s'"),
+ "fetch.output", format);
for (rm = ref_map; rm; rm = rm->next) {
if (rm->status == REF_STATUS_REJECT_SHALLOW ||
@@ -1083,22 +1105,20 @@ 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 = transport_summary_width(ref_map);
+ int summary_width = 0;
- rc = open_fetch_head(&fetch_head);
- if (rc)
- return -1;
+ if (verbosity >= 0)
+ summary_width = transport_summary_width(ref_map);
if (raw_url)
url = transport_anonymize_url(raw_url);
@@ -1115,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);
/*
@@ -1134,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) {
@@ -1145,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)
@@ -1206,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);
@@ -1238,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 "
@@ -1266,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;
}
@@ -1308,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;
@@ -1331,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:
@@ -1339,13 +1353,15 @@ 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;
- int summary_width = transport_summary_width(stale_refs);
const char *dangling_msg = dry_run
? _(" (%s will become dangling)")
: _(" (%s has become dangling)");
@@ -1364,16 +1380,27 @@ 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) {
+ int summary_width = transport_summary_width(stale_refs);
+
for (ref = stale_refs; ref; ref = ref->next) {
struct strbuf sb = STRBUF_INIT;
if (!shown_url) {
@@ -1389,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;
@@ -1503,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
@@ -1525,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;
@@ -1544,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)
@@ -1594,13 +1631,25 @@ static int do_fetch(struct transport *transport,
} else
remote_refs = NULL;
- strvec_clear(&transport_ls_refs_options.ref_prefixes);
+ transport_ls_refs_options_release(&transport_ls_refs_options);
ref_map = get_ref_map(transport->remote, remote_refs, rs,
tags, &autotags);
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) {
@@ -1610,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;
@@ -1644,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;
}
@@ -1658,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") ||
@@ -1678,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;
}
@@ -2017,8 +2101,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
}
git_config(git_fetch_config, NULL);
- prepare_repo_settings(the_repository);
- the_repository->settings.command_requires_full_index = 0;
+ if (the_repository->gitdir) {
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+ }
argc = parse_options(argc, argv, prefix,
builtin_fetch_options, builtin_fetch_usage, 0);
diff --git a/builtin/grep.c b/builtin/grep.c
index 9e34a820ad..bcb07ea7f7 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -26,6 +26,8 @@
#include "object-store.h"
#include "packfile.h"
+static const char *grep_prefix;
+
static char const * const grep_usage[] = {
N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
NULL
@@ -284,7 +286,7 @@ static int wait_all(void)
static int grep_cmd_config(const char *var, const char *value, void *cb)
{
int st = grep_config(var, value, cb);
- if (git_color_default_config(var, value, cb) < 0)
+ if (git_color_default_config(var, value, NULL) < 0)
st = -1;
if (!strcmp(var, "grep.threads")) {
@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,
strbuf_reset(out);
if (opt->null_following_name) {
- if (opt->relative && opt->prefix_length) {
+ if (opt->relative && grep_prefix) {
struct strbuf rel_buf = STRBUF_INIT;
const char *rel_name =
relative_path(filename + tree_name_len,
- opt->prefix, &rel_buf);
+ grep_prefix, &rel_buf);
if (tree_name_len)
strbuf_add(out, filename, tree_name_len);
@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,
return;
}
- if (opt->relative && opt->prefix_length)
- quote_path(filename + tree_name_len, opt->prefix, out, 0);
+ if (opt->relative && grep_prefix)
+ quote_path(filename + tree_name_len, grep_prefix, out, 0);
else
quote_c_style(filename + tree_name_len, out, NULL, 0);
@@ -482,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));
@@ -651,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));
@@ -843,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
int i;
int dummy;
int use_index = 1;
- int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
int allow_revs;
struct option options[] = {
@@ -877,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
NULL, 1 },
OPT_GROUP(""),
- OPT_SET_INT('E', "extended-regexp", &pattern_type_arg,
+ OPT_SET_INT('E', "extended-regexp", &opt.pattern_type_option,
N_("use extended POSIX regular expressions"),
GREP_PATTERN_TYPE_ERE),
- OPT_SET_INT('G', "basic-regexp", &pattern_type_arg,
+ OPT_SET_INT('G', "basic-regexp", &opt.pattern_type_option,
N_("use basic POSIX regular expressions (default)"),
GREP_PATTERN_TYPE_BRE),
- OPT_SET_INT('F', "fixed-strings", &pattern_type_arg,
+ OPT_SET_INT('F', "fixed-strings", &opt.pattern_type_option,
N_("interpret patterns as fixed strings"),
GREP_PATTERN_TYPE_FIXED),
- OPT_SET_INT('P', "perl-regexp", &pattern_type_arg,
+ OPT_SET_INT('P', "perl-regexp", &opt.pattern_type_option,
N_("use Perl-compatible regular expressions"),
GREP_PATTERN_TYPE_PCRE),
OPT_GROUP(""),
@@ -962,9 +963,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOCOMPLETE),
OPT_END()
};
+ grep_prefix = prefix;
- git_config(grep_cmd_config, NULL);
- grep_init(&opt, the_repository, prefix);
+ grep_init(&opt, the_repository);
+ git_config(grep_cmd_config, &opt);
/*
* If there is no -- then the paths must exist in the working
@@ -979,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, grep_usage,
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_STOP_AT_NON_OPTION);
- grep_commit_pattern_type(pattern_type_arg, &opt);
if (use_index && !startup_info->have_repository) {
int fallback = 0;
@@ -1167,11 +1168,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!show_in_pager && !opt.status_only)
setup_pager();
- if (!use_index && (untracked || cached))
- die(_("--cached or --untracked cannot be used with --no-index"));
-
- if (untracked && cached)
- die(_("--untracked cannot be used with --cached"));
+ die_for_incompatible_opt3(!use_index, "--no-index",
+ untracked, "--untracked",
+ cached, "--cached");
if (!use_index || untracked) {
int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index c7b3ad74c6..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;
@@ -81,7 +81,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
{
static const char * const hash_object_usage[] = {
N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] [--] <file>..."),
- N_("git hash-object --stdin-paths"),
+ "git hash-object --stdin-paths",
NULL
};
const char *type = blob_type;
@@ -92,6 +92,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
int nongit = 0;
unsigned flags = HASH_FORMAT_CHECK;
const char *vpath = NULL;
+ char *vpath_free = NULL;
const struct option hash_object_options[] = {
OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
OPT_BIT('w', NULL, &flags, N_("write the object into the object database"),
@@ -114,8 +115,10 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
else
prefix = setup_git_directory_gently(&nongit);
- if (vpath && prefix)
- vpath = prefix_filename(prefix, vpath);
+ if (vpath && prefix) {
+ vpath_free = prefix_filename(prefix, vpath);
+ vpath = vpath_free;
+ }
git_config(git_default_config, NULL);
@@ -156,5 +159,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
if (stdin_paths)
hash_stdin_paths(type, no_filters, flags, literally);
+ free(vpath_free);
+
return 0;
}
diff --git a/builtin/help.c b/builtin/help.c
index d387131dd8..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,10 +80,10 @@ 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>]"),
- N_("git help [-g|--guides]"),
- N_("git help [-c|--config]"),
+ "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..8a5a644744 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
@@ -579,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;
@@ -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/log.c b/builtin/log.c
index 4b493408cc..c211d66d1d 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -35,6 +35,7 @@
#include "repository.h"
#include "commit-reach.h"
#include "range-diff.h"
+#include "tmp-objdir.h"
#define MAIL_DEFAULT_WRAP 72
#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
@@ -422,6 +423,13 @@ static int cmd_log_walk(struct rev_info *rev)
int saved_nrl = 0;
int saved_dcctc = 0;
+ if (rev->remerge_diff) {
+ rev->remerge_objdir = tmp_objdir_create("remerge-diff");
+ if (!rev->remerge_objdir)
+ die(_("unable to create temporary object directory"));
+ tmp_objdir_replace_primary_odb(rev->remerge_objdir, 1);
+ }
+
if (rev->early_output)
setup_early_output();
@@ -464,6 +472,11 @@ static int cmd_log_walk(struct rev_info *rev)
rev->diffopt.no_free = 0;
diff_free(&rev->diffopt);
+ if (rev->remerge_diff) {
+ tmp_objdir_destroy(rev->remerge_objdir);
+ rev->remerge_objdir = NULL;
+ }
+
if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
rev->diffopt.flags.check_failed) {
return 02;
@@ -520,8 +533,6 @@ static int git_log_config(const char *var, const char *value, void *cb)
return 0;
}
- if (grep_config(var, value, cb) < 0)
- return -1;
if (git_gpg_config(var, value, cb) < 0)
return -1;
return git_diff_ui_config(var, value, cb);
@@ -536,6 +547,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
git_config(git_log_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
+ git_config(grep_config, &rev.grep_filter);
+
rev.diff = 1;
rev.simplify_history = 0;
memset(&opt, 0, sizeof(opt));
@@ -650,6 +663,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)
memset(&match_all, 0, sizeof(match_all));
repo_init_revisions(the_repository, &rev, prefix);
+ git_config(grep_config, &rev.grep_filter);
+
rev.diff = 1;
rev.always_show_header = 1;
rev.no_walk = 1;
@@ -733,6 +748,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
repo_init_revisions(the_repository, &rev, prefix);
init_reflog_walk(&rev.reflog_info);
+ git_config(grep_config, &rev.grep_filter);
+
rev.verbose_header = 1;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
@@ -766,6 +783,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)
git_config(git_log_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
+ git_config(grep_config, &rev.grep_filter);
+
rev.always_show_header = 1;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
@@ -1848,10 +1867,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
extra_hdr.strdup_strings = 1;
extra_to.strdup_strings = 1;
extra_cc.strdup_strings = 1;
+
init_log_defaults();
init_display_notes(&notes_opt);
git_config(git_format_config, NULL);
repo_init_revisions(the_repository, &rev, prefix);
+ git_config(grep_config, &rev.grep_filter);
+
rev.show_notes = show_notes;
memcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));
rev.commit_format = CMIT_FMT_EMAIL;
@@ -1958,6 +1980,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
die(_("--name-status does not make sense"));
if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
die(_("--check does not make sense"));
+ if (rev.remerge_diff)
+ die(_("--remerge-diff does not make sense"));
if (!use_patch_format &&
(!rev.diffopt.output_format ||
@@ -1978,8 +2002,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (rev.show_notes)
load_display_notes(&rev.notes_opt);
- if (use_stdout + rev.diffopt.close_file + !!output_directory > 1)
- die(_("options '%s', '%s', and '%s' cannot be used together"), "--stdout", "--output", "--output-directory");
+ die_for_incompatible_opt3(use_stdout, "--stdout",
+ rev.diffopt.close_file, "--output",
+ !!output_directory, "--output-directory");
if (use_stdout) {
setup_pager();
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/ls-remote.c b/builtin/ls-remote.c
index 44448fa61d..d856085e94 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -155,6 +155,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
ref_array_clear(&ref_array);
if (transport_disconnect(transport))
- return 1;
+ status = 1;
+ transport_ls_refs_options_release(&transport_options);
return status;
}
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 3a442631c7..6cb554cbb0 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
ls_tree_prefix = prefix;
- if (prefix && *prefix)
+ if (prefix)
chomp_prefix = strlen(prefix);
argc = parse_options(argc, argv, prefix, ls_tree_options,
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 6719ac198d..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")),
@@ -159,12 +160,14 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
if (argc < 2)
usage_with_options(merge_base_usage, options);
if (show_all)
- die("--is-ancestor cannot be used with --all");
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--is-ancestor", "--all");
return handle_is_ancestor(argc, argv);
}
if (cmdmode == 'r' && show_all)
- die("--independent cannot be used with --all");
+ die(_("options '%s' and '%s' cannot be used together"),
+ "--independent", "--all");
if (cmdmode == 'o')
return handle_octopus(argc, argv, show_all);
@@ -184,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/merge.c b/builtin/merge.c
index 133831d42f..f178f5a3ee 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -845,15 +845,20 @@ static void prepare_to_commit(struct commit_list *remoteheads)
struct strbuf msg = STRBUF_INIT;
const char *index_file = get_index_file();
- if (!no_verify && run_commit_hook(0 < option_edit, index_file, "pre-merge-commit", NULL))
- abort_commit(remoteheads, NULL);
- /*
- * Re-read the index as pre-merge-commit hook could have updated it,
- * and write it out as a tree. We must do this before we invoke
- * the editor and after we invoke run_status above.
- */
- if (hook_exists("pre-merge-commit"))
- discard_cache();
+ if (!no_verify) {
+ int invoked_hook;
+
+ if (run_commit_hook(0 < option_edit, index_file, &invoked_hook,
+ "pre-merge-commit", NULL))
+ abort_commit(remoteheads, NULL);
+ /*
+ * Re-read the index as pre-merge-commit hook could have updated it,
+ * and write it out as a tree. We must do this before we invoke
+ * the editor and after we invoke run_status above.
+ */
+ if (invoked_hook)
+ discard_cache();
+ }
read_cache_from(index_file);
strbuf_addbuf(&msg, &merge_msg);
if (squash)
@@ -875,7 +880,8 @@ static void prepare_to_commit(struct commit_list *remoteheads)
append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
write_merge_heads(remoteheads);
write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
- if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
+ if (run_commit_hook(0 < option_edit, get_index_file(), NULL,
+ "prepare-commit-msg",
git_path_merge_msg(the_repository), "merge", NULL))
abort_commit(remoteheads, NULL);
if (0 < option_edit) {
@@ -884,7 +890,7 @@ static void prepare_to_commit(struct commit_list *remoteheads)
}
if (!no_verify && run_commit_hook(0 < option_edit, get_index_file(),
- "commit-msg",
+ NULL, "commit-msg",
git_path_merge_msg(the_repository), NULL))
abort_commit(remoteheads, NULL);
@@ -1568,8 +1574,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (autostash)
create_autostash(the_repository,
- git_path_merge_autostash(the_repository),
- "merge");
+ git_path_merge_autostash(the_repository));
if (checkout_fast_forward(the_repository,
&head_commit->object.oid,
&commit->object.oid,
@@ -1640,8 +1645,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (autostash)
create_autostash(the_repository,
- git_path_merge_autostash(the_repository),
- "merge");
+ git_path_merge_autostash(the_repository));
/* We are going to make a new commit. */
git_committer_info(IDENT_STRICT);
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 3b2dbbb37e..5d22909122 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -7,7 +7,7 @@
#include "config.h"
static char const * const builtin_mktag_usage[] = {
- N_("git mktag"),
+ "git mktag",
NULL
};
static int option_strict = 1;
@@ -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 ae78ca1c02..902edba6d2 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -58,12 +58,12 @@ 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);
}
static const char *mktree_usage[] = {
- N_("git mktree [-z] [--missing] [--batch]"),
+ "git mktree [-z] [--missing] [--batch]",
NULL
};
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 138e3c30a2..929591269d 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -473,7 +473,7 @@ static void show_name(const struct object *obj,
static char const * const name_rev_usage[] = {
N_("git name-rev [<options>] <commit>..."),
N_("git name-rev [<options>] --all"),
- N_("git name-rev [<options>] --stdin"),
+ N_("git name-rev [<options>] --annotate-stdin"),
NULL
};
diff --git a/builtin/notes.c b/builtin/notes.c
index 05d60483e8..a3d0d15a22 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -32,8 +32,8 @@ static const char * const git_notes_usage[] = {
N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
N_("git notes [--ref <notes-ref>] show [<object>]"),
N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
- N_("git notes merge --commit [-v | -q]"),
- N_("git notes merge --abort [-v | -q]"),
+ "git notes merge --commit [-v | -q]",
+ "git notes merge --abort [-v | -q]",
N_("git notes [--ref <notes-ref>] remove [<object>...]"),
N_("git notes [--ref <notes-ref>] prune [-n] [-v]"),
N_("git notes [--ref <notes-ref>] get-ref"),
@@ -89,7 +89,7 @@ static const char * const git_notes_prune_usage[] = {
};
static const char * const git_notes_get_ref_usage[] = {
- N_("git notes get-ref"),
+ "git notes get-ref",
NULL
};
@@ -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 ba2006f221..829ca359cf 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;
@@ -3504,7 +3504,7 @@ static int option_parse_missing_action(const struct option *opt,
return 0;
}
- die(_("invalid value for --missing"));
+ die(_("invalid value for '%s': '%s'"), "--missing", arg);
return 0;
}
@@ -3651,7 +3651,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 +3727,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 +3778,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;
@@ -3976,9 +3977,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
read_replace_refs = 0;
sparse = git_env_bool("GIT_TEST_PACK_SPARSE", -1);
- prepare_repo_settings(the_repository);
- if (sparse < 0)
- sparse = the_repository->settings.pack_use_sparse;
+ if (the_repository->gitdir) {
+ prepare_repo_settings(the_repository);
+ if (sparse < 0)
+ sparse = the_repository->settings.pack_use_sparse;
+ }
reset_pack_idx_option(&pack_idx_opts);
git_config(git_pack_config, NULL);
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 822ffff51f..881fcf3273 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -32,8 +32,12 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
n = strspn(q, digits);
if (q[n] == ',') {
q += n + 1;
+ *p_before = atoi(q);
n = strspn(q, digits);
+ } else {
+ *p_before = 1;
}
+
if (n == 0 || q[n] != ' ' || q[n+1] != '+')
return 0;
@@ -41,13 +45,14 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
n = strspn(r, digits);
if (r[n] == ',') {
r += n + 1;
+ *p_after = atoi(r);
n = strspn(r, digits);
+ } else {
+ *p_after = 1;
}
if (n == 0)
return 0;
- *p_before = atoi(q);
- *p_after = atoi(r);
return 1;
}
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index b7b9281a8c..da3273a268 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -3,7 +3,7 @@
#include "prune-packed.h"
static const char * const prune_packed_usage[] = {
- N_("git prune-packed [-n | --dry-run] [-q | --quiet]"),
+ "git prune-packed [-n | --dry-run] [-q | --quiet]",
NULL
};
diff --git a/builtin/pull.c b/builtin/pull.c
index 8f37880a48..4d667abc19 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -42,9 +42,9 @@ static enum rebase_type parse_config_rebase(const char *key, const char *value,
return v;
if (fatal)
- die(_("Invalid value for %s: %s"), key, value);
+ die(_("invalid value for '%s': '%s'"), key, value);
else
- error(_("Invalid value for %s: %s"), key, value);
+ error(_("invalid value for '%s': '%s'"), key, value);
return REBASE_INVALID;
}
@@ -318,7 +318,7 @@ static const char *config_get_ff(void)
if (!strcmp(value, "only"))
return "--ff-only";
- die(_("Invalid value for pull.ff: %s"), value);
+ die(_("invalid value for '%s': '%s'"), "pull.ff", value);
}
/**
@@ -994,8 +994,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
set_reflog_message(argc, argv);
git_config(git_pull_config, NULL);
- prepare_repo_settings(the_repository);
- the_repository->settings.command_requires_full_index = 0;
+ if (the_repository->gitdir) {
+ prepare_repo_settings(the_repository);
+ the_repository->settings.command_requires_full_index = 0;
+ }
argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
diff --git a/builtin/push.c b/builtin/push.c
index 359db90321..cad997965a 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -486,7 +486,7 @@ static int git_push_config(const char *k, const char *v, void *cb)
if (value && !strcasecmp(value, "if-asked"))
set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);
else
- return error("Invalid value for '%s'", k);
+ return error(_("invalid value for '%s'"), k);
}
}
} else if (!strcmp(k, "push.recursesubmodules")) {
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 2e6d8fa34e..b29ad2b65e 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -37,7 +37,7 @@ static char const * const builtin_rebase_usage[] = {
"[--onto <newbase> | --keep-base] [<upstream> [<branch>]]"),
N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
"--root [<branch>]"),
- N_("git rebase --continue | --abort | --skip | --edit-todo"),
+ "git rebase --continue | --abort | --skip | --edit-todo",
NULL
};
@@ -571,7 +571,8 @@ static int finish_rebase(struct rebase_options *opts)
static int move_to_original_branch(struct rebase_options *opts)
{
- struct strbuf orig_head_reflog = STRBUF_INIT, head_reflog = STRBUF_INIT;
+ struct strbuf branch_reflog = STRBUF_INIT, head_reflog = STRBUF_INIT;
+ struct reset_head_opts ropts = { 0 };
int ret;
if (!opts->head_name)
@@ -580,16 +581,17 @@ static int move_to_original_branch(struct rebase_options *opts)
if (!opts->onto)
BUG("move_to_original_branch without onto");
- strbuf_addf(&orig_head_reflog, "rebase finished: %s onto %s",
+ strbuf_addf(&branch_reflog, "rebase finished: %s onto %s",
opts->head_name, oid_to_hex(&opts->onto->object.oid));
strbuf_addf(&head_reflog, "rebase finished: returning to %s",
opts->head_name);
- ret = reset_head(the_repository, NULL, "", opts->head_name,
- RESET_HEAD_REFS_ONLY,
- orig_head_reflog.buf, head_reflog.buf,
- DEFAULT_REFLOG_ACTION);
+ ropts.branch = opts->head_name;
+ ropts.flags = RESET_HEAD_REFS_ONLY;
+ ropts.branch_msg = branch_reflog.buf;
+ ropts.head_msg = head_reflog.buf;
+ ret = reset_head(the_repository, &ropts);
- strbuf_release(&orig_head_reflog);
+ strbuf_release(&branch_reflog);
strbuf_release(&head_reflog);
return ret;
}
@@ -671,13 +673,15 @@ static int run_am(struct rebase_options *opts)
status = run_command(&format_patch);
if (status) {
+ struct reset_head_opts ropts = { 0 };
unlink(rebased_patches);
free(rebased_patches);
strvec_clear(&am.args);
- reset_head(the_repository, &opts->orig_head, "checkout",
- opts->head_name, 0,
- "HEAD", NULL, DEFAULT_REFLOG_ACTION);
+ ropts.oid = &opts->orig_head;
+ ropts.branch = opts->head_name;
+ ropts.default_reflog_action = DEFAULT_REFLOG_ACTION;
+ reset_head(the_repository, &ropts);
error(_("\ngit encountered an error while preparing the "
"patches to replay\n"
"these revisions:\n"
@@ -813,6 +817,26 @@ static int rebase_config(const char *var, const char *value, void *data)
return git_default_config(var, value, data);
}
+static int checkout_up_to_date(struct rebase_options *options)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct reset_head_opts ropts = { 0 };
+ int ret = 0;
+
+ strbuf_addf(&buf, "%s: checkout %s",
+ getenv(GIT_REFLOG_ACTION_ENVIRONMENT),
+ options->switch_to);
+ ropts.oid = &options->orig_head;
+ ropts.branch = options->head_name;
+ ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
+ ropts.head_msg = buf.buf;
+ if (reset_head(the_repository, &ropts) < 0)
+ ret = error(_("could not switch to %s"), options->switch_to);
+ strbuf_release(&buf);
+
+ return ret;
+}
+
/*
* Determines whether the commits in from..to are linear, i.e. contain
* no merge commits. This function *expects* `from` to be an ancestor of
@@ -1018,6 +1042,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
int reschedule_failed_exec = -1;
int allow_preemptive_ff = 1;
int preserve_merges_selected = 0;
+ struct reset_head_opts ropts = { 0 };
struct option builtin_rebase_options[] = {
OPT_STRING(0, "onto", &options.onto_name,
N_("revision"),
@@ -1255,9 +1280,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
rerere_clear(the_repository, &merge_rr);
string_list_clear(&merge_rr, 1);
-
- if (reset_head(the_repository, NULL, "reset", NULL, RESET_HEAD_HARD,
- NULL, NULL, DEFAULT_REFLOG_ACTION) < 0)
+ ropts.flags = RESET_HEAD_HARD;
+ if (reset_head(the_repository, &ropts) < 0)
die(_("could not discard worktree changes"));
remove_branch_state(the_repository, 0);
if (read_basic_state(&options))
@@ -1274,9 +1298,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (read_basic_state(&options))
exit(1);
- if (reset_head(the_repository, &options.orig_head, "reset",
- options.head_name, RESET_HEAD_HARD,
- NULL, NULL, DEFAULT_REFLOG_ACTION) < 0)
+ ropts.oid = &options.orig_head;
+ ropts.branch = options.head_name;
+ ropts.flags = RESET_HEAD_HARD;
+ ropts.default_reflog_action = DEFAULT_REFLOG_ACTION;
+ if (reset_head(the_repository, &ropts) < 0)
die(_("could not move back to %s"),
oid_to_hex(&options.orig_head));
remove_branch_state(the_repository, 0);
@@ -1642,10 +1668,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (repo_read_index(the_repository) < 0)
die(_("could not read index"));
- if (options.autostash) {
- create_autostash(the_repository, state_dir_path("autostash", &options),
- DEFAULT_REFLOG_ACTION);
- }
+ if (options.autostash)
+ create_autostash(the_repository,
+ state_dir_path("autostash", &options));
+
if (require_clean_work_tree(the_repository, "rebase",
_("Please commit or stash them."), 1, 1)) {
@@ -1674,21 +1700,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (!(options.flags & REBASE_FORCE)) {
/* Lazily switch to the target branch if needed... */
if (options.switch_to) {
- strbuf_reset(&buf);
- strbuf_addf(&buf, "%s: checkout %s",
- getenv(GIT_REFLOG_ACTION_ENVIRONMENT),
- options.switch_to);
- if (reset_head(the_repository,
- &options.orig_head, "checkout",
- options.head_name,
- RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
- NULL, buf.buf,
- DEFAULT_REFLOG_ACTION) < 0) {
- ret = error(_("could not switch to "
- "%s"),
- options.switch_to);
+ ret = checkout_up_to_date(&options);
+ if (ret)
goto cleanup;
- }
}
if (!(options.flags & REBASE_NO_QUIET))
@@ -1755,10 +1769,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
strbuf_addf(&msg, "%s: checkout %s",
getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name);
- if (reset_head(the_repository, &options.onto->object.oid, "checkout", NULL,
- RESET_HEAD_DETACH | RESET_ORIG_HEAD |
- RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
- NULL, msg.buf, DEFAULT_REFLOG_ACTION))
+ ropts.oid = &options.onto->object.oid;
+ ropts.orig_head = &options.orig_head,
+ ropts.flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD |
+ RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
+ ropts.head_msg = msg.buf;
+ ropts.default_reflog_action = DEFAULT_REFLOG_ACTION;
+ if (reset_head(the_repository, &ropts))
die(_("Could not detach HEAD"));
strbuf_release(&msg);
@@ -1773,9 +1790,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
strbuf_addf(&msg, "rebase finished: %s onto %s",
options.head_name ? options.head_name : "detached HEAD",
oid_to_hex(&options.onto->object.oid));
- reset_head(the_repository, NULL, "Fast-forwarded", options.head_name,
- RESET_HEAD_REFS_ONLY, "HEAD", msg.buf,
- DEFAULT_REFLOG_ACTION);
+ memset(&ropts, 0, sizeof(ropts));
+ ropts.branch = options.head_name;
+ ropts.flags = RESET_HEAD_REFS_ONLY;
+ ropts.head_msg = msg.buf;
+ reset_head(the_repository, &ropts);
strbuf_release(&msg);
ret = finish_rebase(&options);
goto cleanup;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index c427ca09aa..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");
@@ -1408,10 +1409,12 @@ static const char *push_to_deploy(unsigned char *sha1,
static const char *push_to_checkout_hook = "push-to-checkout";
static const char *push_to_checkout(unsigned char *hash,
+ int *invoked_hook,
struct strvec *env,
const char *work_tree)
{
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ opt.invoked_hook = invoked_hook;
strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
strvec_pushv(&opt.env, env->v);
@@ -1426,6 +1429,7 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
{
const char *retval, *git_dir;
struct strvec env = STRVEC_INIT;
+ int invoked_hook;
if (!worktree || !worktree->path)
BUG("worktree->path must be non-NULL");
@@ -1436,10 +1440,9 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
strvec_pushf(&env, "GIT_DIR=%s", absolute_path(git_dir));
- if (!hook_exists(push_to_checkout_hook))
+ retval = push_to_checkout(sha1, &invoked_hook, &env, worktree->path);
+ if (!invoked_hook)
retval = push_to_deploy(sha1, &env, worktree->path);
- else
- retval = push_to_checkout(sha1, &env, worktree->path);
strvec_clear(&env);
return retval;
@@ -1962,6 +1965,15 @@ static void execute_commands(struct command *commands,
}
/*
+ * If there is no command ready to run, should return directly to destroy
+ * temporary data in the quarantine area.
+ */
+ for (cmd = commands; cmd && cmd->error_string; cmd = cmd->next)
+ ; /* nothing */
+ if (!cmd)
+ return;
+
+ /*
* Now we'll start writing out refs, which means the objects need
* to be in their final positions so that other processes can see them.
*/
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 85b838720c..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;
@@ -600,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,
@@ -613,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()
};
@@ -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),
@@ -736,54 +325,18 @@ 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()
};
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;
}
@@ -818,7 +371,7 @@ static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
*/
static const char reflog_usage[] =
-N_("git reflog [ show | expire | delete | exists ]");
+"git reflog [ show | expire | delete | exists ]";
int cmd_reflog(int argc, const char **argv, const char *prefix)
{
diff --git a/builtin/remote.c b/builtin/remote.c
index 299c466116..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[] = {
- N_("git remote [-v | --verbose]"),
+ "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 6ff1734d58..5068f4f0b2 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -22,7 +22,7 @@ static const char * const git_replace_usage[] = {
N_("git replace [-f] <object> <replacement>"),
N_("git replace [-f] --edit <object>"),
N_("git replace [-f] --graft <commit> [<parent>...]"),
- N_("git replace [-f] --convert-graft-file"),
+ "git replace [-f] --convert-graft-file",
N_("git replace -d <object>..."),
N_("git replace [--format=<format>] [-l [<pattern>]]"),
NULL
@@ -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/reset.c b/builtin/reset.c
index b97745ee94..6e65e90c5d 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -204,10 +204,16 @@ static int pathspec_needs_expanded_index(const struct pathspec *pathspec)
/*
* Special case: if the pattern is a path inside the cone
* followed by only wildcards, the pattern cannot match
- * partial sparse directories, so we don't expand the index.
+ * partial sparse directories, so we know we don't need to
+ * expand the index.
+ *
+ * Examples:
+ * - in-cone/foo***: doesn't need expanded index
+ * - not-in-cone/bar*: may need expanded index
+ * - **.c: may need expanded index
*/
- if (path_in_cone_mode_sparse_checkout(item.original, &the_index) &&
- strspn(item.original + item.nowildcard_len, "*") == item.len - item.nowildcard_len)
+ if (strspn(item.original + item.nowildcard_len, "*") == item.len - item.nowildcard_len &&
+ path_in_cone_mode_sparse_checkout(item.original, &the_index))
continue;
for (pos = 0; pos < active_nr; pos++) {
@@ -274,7 +280,6 @@ static int read_from_tree(const struct pathspec *pathspec,
return 1;
diffcore_std(&opt);
diff_flush(&opt);
- clear_pathspec(&opt.pathspec);
return 0;
}
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 777558e9b0..572da1472e 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -20,7 +20,7 @@
#include "packfile.h"
static const char rev_list_usage[] =
-"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
+"git rev-list [<options>] <commit-id>... [-- <path>...]\n"
" limiting output:\n"
" --max-count=<n>\n"
" --max-age=<epoch>\n"
@@ -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/send-pack.c b/builtin/send-pack.c
index 69c432ef1a..64962be016 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -145,7 +145,7 @@ static int send_pack_config(const char *k, const char *v, void *cb)
if (value && !strcasecmp(value, "if-asked"))
args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
else
- return error("Invalid value for '%s'", k);
+ return error(_("invalid value for '%s'"), k);
}
}
}
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index e7f7af5de3..26c5c0cf93 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -388,6 +388,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
parse_revision_opt(&rev, &ctx, options, shortlog_usage);
}
parse_done:
+ revision_opts_finish(&rev);
argc = parse_options_end(&ctx);
if (nongit && argc > 1) {
@@ -434,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)
@@ -447,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/show-branch.c b/builtin/show-branch.c
index e12c5e80e3..330b0553b9 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -8,6 +8,7 @@
#include "parse-options.h"
#include "dir.h"
#include "commit-slab.h"
+#include "date.h"
static const char* show_branch_usage[] = {
N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index a311483a7d..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"
@@ -15,6 +16,7 @@
#include "wt-status.h"
#include "quote.h"
#include "sparse-index.h"
+#include "worktree.h"
static const char *empty_base = "";
@@ -43,7 +45,7 @@ static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
}
static char const * const builtin_sparse_checkout_list_usage[] = {
- N_("git sparse-checkout list"),
+ "git sparse-checkout list",
NULL
};
@@ -327,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;
@@ -347,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;
@@ -361,26 +362,23 @@ enum sparse_checkout_mode {
static int set_config(enum sparse_checkout_mode mode)
{
- const char *config_path;
-
- if (upgrade_repository_format(1) < 0)
- die(_("unable to upgrade repository format to enable worktreeConfig"));
- if (git_config_set_gently("extensions.worktreeConfig", "true")) {
- error(_("failed to set extensions.worktreeConfig setting"));
+ /* Update to use worktree config, if not already. */
+ if (init_worktree_config(the_repository)) {
+ error(_("failed to initialize worktree config"));
return 1;
}
- config_path = git_path("config.worktree");
- git_config_set_in_file_gently(config_path,
- "core.sparseCheckout",
- mode ? "true" : NULL);
-
- git_config_set_in_file_gently(config_path,
- "core.sparseCheckoutCone",
- mode == MODE_CONE_PATTERNS ? "true" : NULL);
+ if (repo_config_set_worktree_gently(the_repository,
+ "core.sparseCheckout",
+ mode ? "true" : "false") ||
+ repo_config_set_worktree_gently(the_repository,
+ "core.sparseCheckoutCone",
+ mode == MODE_CONE_PATTERNS ?
+ "true" : "false"))
+ return 1;
if (mode == MODE_NO_PATTERNS)
- set_sparse_index_config(the_repository, 0);
+ return set_sparse_index_config(the_repository, 0);
return 0;
}
@@ -403,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;
@@ -421,7 +420,7 @@ static int update_modes(int *cone_mode, int *sparse_index)
}
static char const * const builtin_sparse_checkout_init_usage[] = {
- N_("git sparse-checkout init [--cone] [--[no-]sparse-index]"),
+ "git sparse-checkout init [--cone] [--[no-]sparse-index]",
NULL
};
@@ -683,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(),
@@ -710,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;
@@ -734,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),
@@ -761,13 +824,15 @@ 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);
}
static char const * const builtin_sparse_checkout_reapply_usage[] = {
- N_("git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]"),
+ "git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]",
NULL
};
@@ -789,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;
@@ -805,7 +870,7 @@ static int sparse_checkout_reapply(int argc, const char **argv)
}
static char const * const builtin_sparse_checkout_disable_usage[] = {
- N_("git sparse-checkout disable"),
+ "git sparse-checkout disable",
NULL
};
diff --git a/builtin/stash.c b/builtin/stash.c
index 9638c56303..242e73cbb0 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -17,6 +17,7 @@
#include "diffcore.h"
#include "exec-cmd.h"
#include "entry.h"
+#include "reflog.h"
#define INCLUDE_ALL_FILES 2
@@ -634,20 +635,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));
@@ -788,7 +778,6 @@ static int list_stash(int argc, const char **argv, const char *prefix)
static int show_stat = 1;
static int show_patch;
static int show_include_untracked;
-static int use_legacy_stash;
static int git_stash_config(const char *var, const char *value, void *cb)
{
@@ -804,10 +793,6 @@ static int git_stash_config(const char *var, const char *value, void *cb)
show_include_untracked = git_config_bool(var, value);
return 0;
}
- if (!strcmp(var, "stash.usebuiltin")) {
- use_legacy_stash = !git_config_bool(var, value);
- return 0;
- }
return git_diff_basic_config(var, value, cb);
}
@@ -1332,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);
@@ -1782,11 +1767,6 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
git_config(git_stash_config, NULL);
- if (use_legacy_stash ||
- !git_env_bool("GIT_TEST_STASH_USE_BUILTIN", -1))
- warning(_("the stash.useBuiltin support has been removed!\n"
- "See its entry in 'git help config' for details."));
-
argc = parse_options(argc, argv, prefix, options, git_stash_usage,
PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
index be33eb83c1..1e34cf2beb 100644
--- a/builtin/stripspace.c
+++ b/builtin/stripspace.c
@@ -15,8 +15,8 @@ static void comment_lines(struct strbuf *buf)
}
static const char * const stripspace_usage[] = {
- N_("git stripspace [-s | --strip-comments]"),
- N_("git stripspace [-c | --comment-lines]"),
+ "git stripspace [-s | --strip-comments]",
+ "git stripspace [-c | --comment-lines]",
NULL
};
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c5d3fc3817..2f7c58362b 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -20,6 +20,8 @@
#include "diff.h"
#include "object-store.h"
#include "advice.h"
+#include "branch.h"
+#include "list-objects-filter-options.h"
#define OPT_QUIET (1 << 0)
#define OPT_CACHED (1 << 1)
@@ -1630,6 +1632,7 @@ struct module_clone_data {
const char *name;
const char *url;
const char *depth;
+ struct list_objects_filter_options *filter_options;
struct string_list reference;
unsigned int quiet: 1;
unsigned int progress: 1;
@@ -1796,6 +1799,10 @@ static int clone_submodule(struct module_clone_data *clone_data)
strvec_push(&cp.args, "--dissociate");
if (sm_gitdir && *sm_gitdir)
strvec_pushl(&cp.args, "--separate-git-dir", sm_gitdir, NULL);
+ if (clone_data->filter_options && clone_data->filter_options->choice)
+ strvec_pushf(&cp.args, "--filter=%s",
+ expand_list_objects_filter_spec(
+ clone_data->filter_options));
if (clone_data->single_branch >= 0)
strvec_push(&cp.args, clone_data->single_branch ?
"--single-branch" :
@@ -1852,6 +1859,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
{
int dissociate = 0, quiet = 0, progress = 0, require_init = 0;
struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
+ struct list_objects_filter_options filter_options;
struct option module_clone_options[] = {
OPT_STRING(0, "prefix", &clone_data.prefix,
@@ -1874,24 +1882,26 @@ 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,
N_("disallow cloning into non-empty directory")),
OPT_BOOL(0, "single-branch", &clone_data.single_branch,
N_("clone only one branch, HEAD or --branch")),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_END()
};
const char *const git_submodule_helper_usage[] = {
N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
"[--reference <repository>] [--name <name>] [--depth <depth>] "
- "[--single-branch] "
+ "[--single-branch] [--filter <filter-spec>]"
"--url <url> --path <path>"),
NULL
};
+ memset(&filter_options, 0, sizeof(filter_options));
argc = parse_options(argc, argv, prefix, module_clone_options,
git_submodule_helper_usage, 0);
@@ -1899,12 +1909,14 @@ static int module_clone(int argc, const char **argv, const char *prefix)
clone_data.quiet = !!quiet;
clone_data.progress = !!progress;
clone_data.require_init = !!require_init;
+ clone_data.filter_options = &filter_options;
if (argc || !clone_data.url || !clone_data.path || !*(clone_data.path))
usage_with_options(git_submodule_helper_usage,
module_clone_options);
clone_submodule(&clone_data);
+ list_objects_filter_release(&filter_options);
return 0;
}
@@ -1994,6 +2006,7 @@ struct submodule_update_clone {
const char *recursive_prefix;
const char *prefix;
int single_branch;
+ struct list_objects_filter_options *filter_options;
/* to be consumed by git-submodule.sh */
struct update_clone_data *update_clone;
@@ -2154,6 +2167,9 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
strvec_pushl(&child->args, "--prefix", suc->prefix, NULL);
if (suc->recommend_shallow && sub->recommend_shallow == 1)
strvec_push(&child->args, "--depth=1");
+ if (suc->filter_options && suc->filter_options->choice)
+ strvec_pushf(&child->args, "--filter=%s",
+ expand_list_objects_filter_spec(suc->filter_options));
if (suc->require_init)
strvec_push(&child->args, "--require-init");
strvec_pushl(&child->args, "--path", sub->path, NULL);
@@ -2498,6 +2514,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
const char *update = NULL;
struct pathspec pathspec;
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
+ struct list_objects_filter_options filter_options;
+ int ret;
struct option module_update_clone_options[] = {
OPT_STRING(0, "prefix", &prefix,
@@ -2528,6 +2546,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
N_("disallow cloning into non-empty directory")),
OPT_BOOL(0, "single-branch", &suc.single_branch,
N_("clone only one branch, HEAD or --branch")),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_END()
};
@@ -2540,20 +2559,26 @@ static int update_clone(int argc, const char **argv, const char *prefix)
update_clone_config_from_gitmodules(&suc.max_jobs);
git_config(git_update_clone_config, &suc.max_jobs);
+ memset(&filter_options, 0, sizeof(filter_options));
argc = parse_options(argc, argv, prefix, module_update_clone_options,
git_submodule_helper_usage, 0);
+ suc.filter_options = &filter_options;
if (update)
if (parse_submodule_update_strategy(update, &suc.update) < 0)
die(_("bad value for update parameter"));
- if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0)
+ if (module_list_compute(argc, argv, prefix, &pathspec, &suc.list) < 0) {
+ list_objects_filter_release(&filter_options);
return 1;
+ }
if (pathspec.nr)
suc.warn_if_uninitialized = 1;
- return update_submodules(&suc);
+ ret = update_submodules(&suc);
+ list_objects_filter_release(&filter_options);
+ return ret;
}
static int run_update_procedure(int argc, const char **argv, const char *prefix)
@@ -2883,7 +2908,7 @@ static int module_config(int argc, const char **argv, const char *prefix)
const char *const git_submodule_helper_usage[] = {
N_("git submodule--helper config <name> [<value>]"),
N_("git submodule--helper config --unset <name>"),
- N_("git submodule--helper config --check-writeable"),
+ "git submodule--helper config --check-writeable",
NULL
};
@@ -2984,6 +3009,42 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
return !!ret;
}
+static int module_create_branch(int argc, const char **argv, const char *prefix)
+{
+ enum branch_track track;
+ int quiet = 0, force = 0, reflog = 0, dry_run = 0;
+
+ struct option options[] = {
+ OPT__QUIET(&quiet, N_("print only error messages")),
+ OPT__FORCE(&force, N_("force creation"), 0),
+ OPT_BOOL(0, "create-reflog", &reflog,
+ N_("create the branch's reflog")),
+ OPT_SET_INT('t', "track", &track,
+ N_("set up tracking mode (see git-pull(1))"),
+ BRANCH_TRACK_EXPLICIT),
+ OPT__DRY_RUN(&dry_run,
+ N_("show whether the branch would be created")),
+ OPT_END()
+ };
+ const char *const usage[] = {
+ N_("git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--quiet] [-t|--track] [-n|--dry-run] <name> <start_oid> <start_name>"),
+ NULL
+ };
+
+ git_config(git_default_config, NULL);
+ track = git_branch_track;
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+ if (argc != 3)
+ usage_with_options(usage, options);
+
+ if (!quiet && !dry_run)
+ printf_ln(_("creating branch '%s'"), argv[0]);
+
+ create_branches_recursively(the_repository, argv[0], argv[1], argv[2],
+ force, reflog, quiet, track, dry_run);
+ return 0;
+}
struct add_data {
const char *prefix;
const char *branch;
@@ -3248,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"),
@@ -3299,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 {
@@ -3352,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;
}
@@ -3390,6 +3454,7 @@ static struct cmd_struct commands[] = {
{"config", module_config, 0},
{"set-url", module_set_url, 0},
{"set-branch", module_set_branch, 0},
+ {"create-branch", module_create_branch, 0},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/builtin/tag.c b/builtin/tag.c
index 134b3f1edf..e5a8f85693 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -20,6 +20,7 @@
#include "oid-array.h"
#include "column.h"
#include "ref-filter.h"
+#include "date.h"
static const char * const git_tag_usage[] = {
N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]\n"
@@ -238,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/update-index.c b/builtin/update-index.c
index 7e0a0d9bf8..aafe7eeac2 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -606,7 +606,7 @@ static struct cache_entry *read_one_ent(const char *which,
error("%s: not in %s branch.", path, which);
return NULL;
}
- if (mode == S_IFDIR) {
+ if (!the_index.sparse_index && mode == S_IFDIR) {
if (which)
error("%s: not a blob in %s branch.", path, which);
return NULL;
@@ -743,8 +743,6 @@ static int do_reupdate(int ac, const char **av,
*/
has_head = 0;
redo:
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
for (pos = 0; pos < active_nr; pos++) {
const struct cache_entry *ce = active_cache[pos];
struct cache_entry *old = NULL;
@@ -761,6 +759,16 @@ static int do_reupdate(int ac, const char **av,
discard_cache_entry(old);
continue; /* unchanged */
}
+
+ /* At this point, we know the contents of the sparse directory are
+ * modified with respect to HEAD, so we expand the index and restart
+ * to process each path individually
+ */
+ if (S_ISSPARSEDIR(ce->ce_mode)) {
+ ensure_full_index(&the_index);
+ goto redo;
+ }
+
/* Be careful. The working tree may not have the
* path anymore, in which case, under 'allow_remove',
* or worse yet 'allow_replace', active_nr may decrease.
@@ -1088,6 +1096,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
+ prepare_repo_settings(r);
+ the_repository->settings.command_requires_full_index = 0;
+
/* we will diagnose later if it turns out that we need to update it */
newfd = hold_locked_index(&lock_file, 0);
if (newfd < 0)
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
index 4321a34456..880fffec58 100644
--- a/builtin/update-server-info.c
+++ b/builtin/update-server-info.c
@@ -4,7 +4,7 @@
#include "parse-options.h"
static const char * const update_server_info_usage[] = {
- N_("git update-server-info [--force]"),
+ "git update-server-info [--force]",
NULL
};
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 0d0809276f..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)
{
@@ -335,6 +403,21 @@ static int add_worktree(const char *path, const char *refname,
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
+ /*
+ * If the current worktree has sparse-checkout enabled, then copy
+ * the sparse-checkout patterns from the current worktree.
+ */
+ 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)
+ 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);
cp.git_cmd = 1;
@@ -354,17 +437,9 @@ static int add_worktree(const char *path, const char *refname,
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);