summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c9
-rw-r--r--builtin/am.c64
-rw-r--r--builtin/blame.c4
-rw-r--r--builtin/cat-file.c26
-rw-r--r--builtin/checkout-index.c2
-rw-r--r--builtin/clean.c1
-rw-r--r--builtin/commit.c7
-rw-r--r--builtin/config.c19
-rw-r--r--builtin/describe.c2
-rw-r--r--builtin/fetch.c148
-rw-r--r--builtin/fsck.c68
-rw-r--r--builtin/grep.c110
-rw-r--r--builtin/index-pack.c63
-rw-r--r--builtin/init-db.c1
-rw-r--r--builtin/interpret-trailers.c2
-rw-r--r--builtin/log.c14
-rw-r--r--builtin/ls-files.c14
-rw-r--r--builtin/ls-remote.c13
-rw-r--r--builtin/merge-file.c2
-rw-r--r--builtin/merge-tree.c3
-rw-r--r--builtin/merge.c31
-rw-r--r--builtin/notes.c11
-rw-r--r--builtin/pack-objects.c37
-rw-r--r--builtin/pull.c11
-rw-r--r--builtin/read-tree.c3
-rw-r--r--builtin/rebase.c204
-rw-r--r--builtin/reflog.c46
-rw-r--r--builtin/repack.c7
-rw-r--r--builtin/rerere.c3
-rw-r--r--builtin/reset.c15
-rw-r--r--builtin/rev-parse.c1
-rw-r--r--builtin/show-branch.c3
-rw-r--r--builtin/show-ref.c1
-rw-r--r--builtin/submodule--helper.c40
-rw-r--r--builtin/tag.c6
-rw-r--r--builtin/update-index.c23
-rw-r--r--builtin/worktree.c10
37 files changed, 597 insertions, 427 deletions
diff --git a/builtin/add.c b/builtin/add.c
index ad49806ebf..f65c172299 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -445,11 +445,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
return 0;
}
- if (read_cache() < 0)
- die(_("index file corrupt"));
-
- die_in_unpopulated_submodule(&the_index, prefix);
-
/*
* Check the "pathspec '%s' did not match any files" block
* below before enabling new magic.
@@ -459,6 +454,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, argv);
+ if (read_cache_preload(&pathspec) < 0)
+ die(_("index file corrupt"));
+
+ die_in_unpopulated_submodule(&the_index, prefix);
die_path_inside_submodule(&the_index, &pathspec);
if (add_new_files) {
diff --git a/builtin/am.c b/builtin/am.c
index 3ee9a9d2a9..8f27f3375b 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -261,32 +261,6 @@ static int read_state_file(struct strbuf *sb, const struct am_state *state,
}
/**
- * Take a series of KEY='VALUE' lines where VALUE part is
- * sq-quoted, and append <KEY, VALUE> at the end of the string list
- */
-static int parse_key_value_squoted(char *buf, struct string_list *list)
-{
- while (*buf) {
- struct string_list_item *item;
- char *np;
- char *cp = strchr(buf, '=');
- if (!cp)
- return -1;
- np = strchrnul(cp, '\n');
- *cp++ = '\0';
- item = string_list_append(list, buf);
-
- buf = np + (*np == '\n');
- *np = '\0';
- cp = sq_dequote(cp);
- if (!cp)
- return -1;
- item->util = xstrdup(cp);
- }
- return 0;
-}
-
-/**
* Reads and parses the state directory's "author-script" file, and sets
* state->author_name, state->author_email and state->author_date accordingly.
* Returns 0 on success, -1 if the file could not be parsed.
@@ -302,42 +276,16 @@ static int parse_key_value_squoted(char *buf, struct string_list *list)
* script, and thus if the file differs from what this function expects, it is
* better to bail out than to do something that the user does not expect.
*/
-static int read_author_script(struct am_state *state)
+static int read_am_author_script(struct am_state *state)
{
const char *filename = am_path(state, "author-script");
- struct strbuf buf = STRBUF_INIT;
- struct string_list kv = STRING_LIST_INIT_DUP;
- int retval = -1; /* assume failure */
- int fd;
assert(!state->author_name);
assert(!state->author_email);
assert(!state->author_date);
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- if (errno == ENOENT)
- return 0;
- die_errno(_("could not open '%s' for reading"), filename);
- }
- strbuf_read(&buf, fd, 0);
- close(fd);
- if (parse_key_value_squoted(buf.buf, &kv))
- goto finish;
-
- if (kv.nr != 3 ||
- strcmp(kv.items[0].string, "GIT_AUTHOR_NAME") ||
- strcmp(kv.items[1].string, "GIT_AUTHOR_EMAIL") ||
- strcmp(kv.items[2].string, "GIT_AUTHOR_DATE"))
- goto finish;
- state->author_name = kv.items[0].util;
- state->author_email = kv.items[1].util;
- state->author_date = kv.items[2].util;
- retval = 0;
-finish:
- string_list_clear(&kv, !!retval);
- strbuf_release(&buf);
- return retval;
+ return read_author_script(filename, &state->author_name,
+ &state->author_email, &state->author_date, 1);
}
/**
@@ -411,7 +359,7 @@ static void am_load(struct am_state *state)
BUG("state file 'last' does not exist");
state->last = strtol(sb.buf, NULL, 10);
- if (read_author_script(state) < 0)
+ if (read_am_author_script(state) < 0)
die(_("could not parse author script"));
read_commit_msg(state);
@@ -2165,7 +2113,9 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
{
int *opt_value = opt->value;
- if (!strcmp(arg, "mbox"))
+ if (unset)
+ *opt_value = PATCH_FORMAT_UNKNOWN;
+ else if (!strcmp(arg, "mbox"))
*opt_value = PATCH_FORMAT_MBOX;
else if (!strcmp(arg, "stgit"))
*opt_value = PATCH_FORMAT_STGIT;
diff --git a/builtin/blame.c b/builtin/blame.c
index a443af9ee9..06a7163ffe 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -732,6 +732,8 @@ static int blame_copy_callback(const struct option *option, const char *arg, int
{
int *opt = option->value;
+ BUG_ON_OPT_NEG(unset);
+
/*
* -C enables copy from removed files;
* -C -C enables copy from existing files, but only
@@ -754,6 +756,8 @@ static int blame_move_callback(const struct option *option, const char *arg, int
{
int *opt = option->value;
+ BUG_ON_OPT_NEG(unset);
+
*opt |= PICKAXE_BLAME_MOVE;
if (arg)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 05decee33f..2ca56fd086 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -50,6 +50,13 @@ static int filter_object(const char *path, unsigned mode,
return 0;
}
+static int stream_blob(const struct object_id *oid)
+{
+ if (stream_blob_to_fd(1, oid, NULL, 0))
+ die("unable to stream %s to stdout", oid_to_hex(oid));
+ return 0;
+}
+
static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
int unknown_type)
{
@@ -132,7 +139,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
}
if (type == OBJ_BLOB)
- return stream_blob_to_fd(1, &oid, NULL, 0);
+ return stream_blob(&oid);
buf = read_object_file(&oid, &type, &size);
if (!buf)
die("Cannot read object %s", obj_name);
@@ -155,7 +162,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
oidcpy(&blob_oid, &oid);
if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB)
- return stream_blob_to_fd(1, &blob_oid, NULL, 0);
+ return stream_blob(&blob_oid);
/*
* we attempted to dereference a tag to a blob
* and failed; there may be new dereference
@@ -319,8 +326,9 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
BUG("invalid cmdmode: %c", opt->cmdmode);
batch_write(opt, contents, size);
free(contents);
- } else if (stream_blob_to_fd(1, oid, NULL, 0) < 0)
- die("unable to stream %s to stdout", oid_to_hex(oid));
+ } else {
+ stream_blob(oid);
+ }
}
else {
enum object_type type;
@@ -595,8 +603,10 @@ static int batch_option_callback(const struct option *opt,
{
struct batch_options *bo = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
if (bo->enabled) {
- return 1;
+ return error(_("only one batch option may be specified"));
}
bo->enabled = 1;
@@ -631,10 +641,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "buffer", &batch.buffer_output, N_("buffer --batch output")),
{ OPTION_CALLBACK, 0, "batch", &batch, "format",
N_("show info and content of objects fed from the standard input"),
- PARSE_OPT_OPTARG, batch_option_callback },
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+ batch_option_callback },
{ OPTION_CALLBACK, 0, "batch-check", &batch, "format",
N_("show info about objects fed from the standard input"),
- PARSE_OPT_OPTARG, batch_option_callback },
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+ batch_option_callback },
OPT_BOOL(0, "follow-symlinks", &batch.follow_symlinks,
N_("follow in-tree symlinks (used with --batch or --batch-check)")),
OPT_BOOL(0, "batch-all-objects", &batch.all_objects,
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 88b86c8d9f..eb74774cbc 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -132,6 +132,8 @@ static const char * const builtin_checkout_index_usage[] = {
static int option_parse_stage(const struct option *opt,
const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+
if (!strcmp(arg, "all")) {
to_tempfile = 1;
checkout_stage = CHECKOUT_ALL;
diff --git a/builtin/clean.c b/builtin/clean.c
index 8d9a7dc206..bbcdeb2d9e 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -140,6 +140,7 @@ static void clean_print_color(enum color_clean ix)
static int exclude_cb(const struct option *opt, const char *arg, int unset)
{
struct string_list *exclude_list = opt->value;
+ BUG_ON_OPT_NEG(unset);
string_list_append(exclude_list, arg);
return 0;
}
diff --git a/builtin/commit.c b/builtin/commit.c
index 074bd9a551..c021b119bb 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -161,6 +161,9 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
static int opt_parse_rename_score(const struct option *opt, const char *arg, int unset)
{
const char **value = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+
if (arg != NULL && *arg == '=')
arg = arg + 1;
@@ -1335,7 +1338,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")),
{ OPTION_CALLBACK, 'M', "find-renames", &rename_score_arg,
N_("n"), N_("detect renames, optionally set similarity index"),
- PARSE_OPT_OPTARG, opt_parse_rename_score },
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG, opt_parse_rename_score },
OPT_END(),
};
@@ -1363,7 +1366,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
if (status_format != STATUS_FORMAT_PORCELAIN &&
status_format != STATUS_FORMAT_PORCELAIN_V2)
progress_flag = REFRESH_PROGRESS;
- read_index_preload(&the_index, &s.pathspec, progress_flag);
+ read_index(&the_index);
refresh_index(&the_index,
REFRESH_QUIET|REFRESH_UNMERGED|progress_flag,
&s.pathspec, NULL, NULL);
diff --git a/builtin/config.c b/builtin/config.c
index 97b58c4aea..84385ef165 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -5,6 +5,7 @@
#include "parse-options.h"
#include "urlmatch.h"
#include "quote.h"
+#include "worktree.h"
static const char *const builtin_config_usage[] = {
N_("git config [<options>]"),
@@ -24,6 +25,7 @@ static char key_delim = ' ';
static char term = '\n';
static int use_global_config, use_system_config, use_local_config;
+static int use_worktree_config;
static struct git_config_source given_config_source;
static int actions, type;
static char *default_value;
@@ -123,6 +125,7 @@ static struct option builtin_config_options[] = {
OPT_BOOL(0, "global", &use_global_config, N_("use global config file")),
OPT_BOOL(0, "system", &use_system_config, N_("use system config file")),
OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")),
+ OPT_BOOL(0, "worktree", &use_worktree_config, N_("use per-worktree config file")),
OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")),
OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")),
OPT_GROUP(N_("Action")),
@@ -602,6 +605,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
PARSE_OPT_STOP_AT_NON_OPTION);
if (use_global_config + use_system_config + use_local_config +
+ use_worktree_config +
!!given_config_source.file + !!given_config_source.blob > 1) {
error(_("only one config file at a time"));
usage_builtin_config();
@@ -645,7 +649,20 @@ int cmd_config(int argc, const char **argv, const char *prefix)
given_config_source.file = git_etc_gitconfig();
else if (use_local_config)
given_config_source.file = git_pathdup("config");
- else if (given_config_source.file) {
+ else if (use_worktree_config) {
+ struct worktree **worktrees = get_worktrees(0);
+ if (repository_format_worktree_config)
+ given_config_source.file = git_pathdup("config.worktree");
+ else if (worktrees[0] && worktrees[1])
+ die(_("--worktree cannot be used with multiple "
+ "working trees unless the config\n"
+ "extension worktreeConfig is enabled. "
+ "Please read \"CONFIGURATION FILE\"\n"
+ "section in \"git help worktree\" for details"));
+ else
+ given_config_source.file = git_pathdup("config");
+ free_worktrees(worktrees);
+ } else if (given_config_source.file) {
if (!is_absolute_path(given_config_source.file) && prefix)
given_config_source.file =
prefix_filename(prefix, given_config_source.file);
diff --git a/builtin/describe.c b/builtin/describe.c
index c48c34e866..cc118448ee 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -629,7 +629,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
struct argv_array args = ARGV_ARRAY_INIT;
int fd, result;
- read_cache_preload(NULL);
+ read_cache();
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
NULL, NULL, NULL);
fd = hold_locked_index(&index_lock, 0);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 8f7249f2b1..e0140327aa 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -98,6 +98,8 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+
/*
* "git fetch --refmap='' origin foo"
* can be used to tell the command not to store anywhere
@@ -223,18 +225,6 @@ static void add_merge_config(struct ref **head,
}
}
-static int add_existing(const char *refname, const struct object_id *oid,
- int flag, void *cbdata)
-{
- struct string_list *list = (struct string_list *)cbdata;
- struct string_list_item *item = string_list_insert(list, refname);
- struct object_id *old_oid = xmalloc(sizeof(*old_oid));
-
- oidcpy(old_oid, oid);
- item->util = old_oid;
- return 0;
-}
-
static int will_fetch(struct ref **head, const unsigned char *sha1)
{
struct ref *rm = *head;
@@ -246,16 +236,72 @@ static int will_fetch(struct ref **head, const unsigned char *sha1)
return 0;
}
+struct refname_hash_entry {
+ struct hashmap_entry ent; /* must be the first member */
+ struct object_id oid;
+ char refname[FLEX_ARRAY];
+};
+
+static int refname_hash_entry_cmp(const void *hashmap_cmp_fn_data,
+ const void *e1_,
+ const void *e2_,
+ const void *keydata)
+{
+ const struct refname_hash_entry *e1 = e1_;
+ const struct refname_hash_entry *e2 = e2_;
+
+ return strcmp(e1->refname, keydata ? keydata : e2->refname);
+}
+
+static struct refname_hash_entry *refname_hash_add(struct hashmap *map,
+ const char *refname,
+ const struct object_id *oid)
+{
+ struct refname_hash_entry *ent;
+ size_t len = strlen(refname);
+
+ FLEX_ALLOC_MEM(ent, refname, refname, len);
+ hashmap_entry_init(ent, strhash(refname));
+ oidcpy(&ent->oid, oid);
+ hashmap_add(map, ent);
+ return ent;
+}
+
+static int add_one_refname(const char *refname,
+ const struct object_id *oid,
+ int flag, void *cbdata)
+{
+ struct hashmap *refname_map = cbdata;
+
+ (void) refname_hash_add(refname_map, refname, oid);
+ return 0;
+}
+
+static void refname_hash_init(struct hashmap *map)
+{
+ hashmap_init(map, refname_hash_entry_cmp, NULL, 0);
+}
+
+static int refname_hash_exists(struct hashmap *map, const char *refname)
+{
+ return !!hashmap_get_from_hash(map, strhash(refname), refname);
+}
+
static void find_non_local_tags(const struct ref *refs,
struct ref **head,
struct ref ***tail)
{
- struct string_list existing_refs = STRING_LIST_INIT_DUP;
- struct string_list remote_refs = STRING_LIST_INIT_NODUP;
+ struct hashmap existing_refs;
+ struct hashmap remote_refs;
+ struct string_list remote_refs_list = STRING_LIST_INIT_NODUP;
+ struct string_list_item *remote_ref_item;
const struct ref *ref;
- struct string_list_item *item = NULL;
+ struct refname_hash_entry *item = NULL;
- for_each_ref(add_existing, &existing_refs);
+ refname_hash_init(&existing_refs);
+ refname_hash_init(&remote_refs);
+
+ for_each_ref(add_one_refname, &existing_refs);
for (ref = refs; ref; ref = ref->next) {
if (!starts_with(ref->name, "refs/tags/"))
continue;
@@ -271,10 +317,10 @@ static void find_non_local_tags(const struct ref *refs,
!has_object_file_with_flags(&ref->old_oid,
OBJECT_INFO_QUICK) &&
!will_fetch(head, ref->old_oid.hash) &&
- !has_sha1_file_with_flags(item->util,
+ !has_sha1_file_with_flags(item->oid.hash,
OBJECT_INFO_QUICK) &&
- !will_fetch(head, item->util))
- item->util = NULL;
+ !will_fetch(head, item->oid.hash))
+ oidclr(&item->oid);
item = NULL;
continue;
}
@@ -286,48 +332,53 @@ static void find_non_local_tags(const struct ref *refs,
* fetch.
*/
if (item &&
- !has_sha1_file_with_flags(item->util, OBJECT_INFO_QUICK) &&
- !will_fetch(head, item->util))
- item->util = NULL;
+ !has_sha1_file_with_flags(item->oid.hash, OBJECT_INFO_QUICK) &&
+ !will_fetch(head, item->oid.hash))
+ oidclr(&item->oid);
item = NULL;
/* skip duplicates and refs that we already have */
- if (string_list_has_string(&remote_refs, ref->name) ||
- string_list_has_string(&existing_refs, ref->name))
+ if (refname_hash_exists(&remote_refs, ref->name) ||
+ refname_hash_exists(&existing_refs, ref->name))
continue;
- item = string_list_insert(&remote_refs, ref->name);
- item->util = (void *)&ref->old_oid;
+ item = refname_hash_add(&remote_refs, ref->name, &ref->old_oid);
+ string_list_insert(&remote_refs_list, ref->name);
}
- string_list_clear(&existing_refs, 1);
+ hashmap_free(&existing_refs, 1);
/*
* We may have a final lightweight tag that needs to be
* checked to see if it needs fetching.
*/
if (item &&
- !has_sha1_file_with_flags(item->util, OBJECT_INFO_QUICK) &&
- !will_fetch(head, item->util))
- item->util = NULL;
+ !has_sha1_file_with_flags(item->oid.hash, OBJECT_INFO_QUICK) &&
+ !will_fetch(head, item->oid.hash))
+ oidclr(&item->oid);
/*
- * For all the tags in the remote_refs string list,
+ * For all the tags in the remote_refs_list,
* add them to the list of refs to be fetched
*/
- for_each_string_list_item(item, &remote_refs) {
+ for_each_string_list_item(remote_ref_item, &remote_refs_list) {
+ const char *refname = remote_ref_item->string;
+
+ item = hashmap_get_from_hash(&remote_refs, strhash(refname), refname);
+ if (!item)
+ BUG("unseen remote ref?");
+
/* Unless we have already decided to ignore this item... */
- if (item->util)
- {
- struct ref *rm = alloc_ref(item->string);
- rm->peer_ref = alloc_ref(item->string);
- oidcpy(&rm->old_oid, item->util);
+ if (!is_null_oid(&item->oid)) {
+ struct ref *rm = alloc_ref(item->refname);
+ rm->peer_ref = alloc_ref(item->refname);
+ oidcpy(&rm->old_oid, &item->oid);
**tail = rm;
*tail = &rm->next;
}
}
-
- string_list_clear(&remote_refs, 0);
+ hashmap_free(&remote_refs, 1);
+ string_list_clear(&remote_refs_list, 0);
}
static struct ref *get_ref_map(struct remote *remote,
@@ -343,7 +394,7 @@ static struct ref *get_ref_map(struct remote *remote,
/* opportunistically-updated references: */
struct ref *orefs = NULL, **oref_tail = &orefs;
- struct string_list existing_refs = STRING_LIST_INIT_DUP;
+ struct hashmap existing_refs;
if (rs->nr) {
struct refspec *fetch_refspec;
@@ -437,19 +488,24 @@ static struct ref *get_ref_map(struct remote *remote,
ref_map = ref_remove_duplicates(ref_map);
- for_each_ref(add_existing, &existing_refs);
+ refname_hash_init(&existing_refs);
+ for_each_ref(add_one_refname, &existing_refs);
+
for (rm = ref_map; rm; rm = rm->next) {
if (rm->peer_ref) {
- struct string_list_item *peer_item =
- string_list_lookup(&existing_refs,
- rm->peer_ref->name);
+ const char *refname = rm->peer_ref->name;
+ struct refname_hash_entry *peer_item;
+
+ peer_item = hashmap_get_from_hash(&existing_refs,
+ strhash(refname),
+ refname);
if (peer_item) {
- struct object_id *old_oid = peer_item->util;
+ struct object_id *old_oid = &peer_item->oid;
oidcpy(&rm->peer_ref->old_oid, old_oid);
}
}
}
- string_list_clear(&existing_refs, 1);
+ hashmap_free(&existing_refs, 1);
return ref_map;
}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 06eb421720..3c3e0f06e7 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -19,6 +19,7 @@
#include "packfile.h"
#include "object-store.h"
#include "run-command.h"
+#include "worktree.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
@@ -36,8 +37,6 @@ static int check_strict;
static int keep_cache_objects;
static struct fsck_options fsck_walk_options = FSCK_OPTIONS_DEFAULT;
static struct fsck_options fsck_obj_options = FSCK_OPTIONS_DEFAULT;
-static struct object_id head_oid;
-static const char *head_points_at;
static int errors_found;
static int write_lost_and_found;
static int verbose;
@@ -446,7 +445,11 @@ static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid
static int fsck_handle_reflog(const char *logname, const struct object_id *oid,
int flag, void *cb_data)
{
- for_each_reflog_ent(logname, fsck_handle_reflog_ent, (void *)logname);
+ struct strbuf refname = STRBUF_INIT;
+
+ strbuf_worktree_ref(cb_data, &refname, logname);
+ for_each_reflog_ent(refname.buf, fsck_handle_reflog_ent, refname.buf);
+ strbuf_release(&refname);
return 0;
}
@@ -484,13 +487,34 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
return 0;
}
+static int fsck_head_link(const char *head_ref_name,
+ const char **head_points_at,
+ struct object_id *head_oid);
+
static void get_default_heads(void)
{
- if (head_points_at && !is_null_oid(&head_oid))
- fsck_handle_ref("HEAD", &head_oid, 0, NULL);
+ struct worktree **worktrees, **p;
+ const char *head_points_at;
+ struct object_id head_oid;
+
for_each_rawref(fsck_handle_ref, NULL);
- if (include_reflogs)
- for_each_reflog(fsck_handle_reflog, NULL);
+
+ worktrees = get_worktrees(0);
+ for (p = worktrees; *p; p++) {
+ struct worktree *wt = *p;
+ struct strbuf ref = STRBUF_INIT;
+
+ strbuf_worktree_ref(wt, &ref, "HEAD");
+ fsck_head_link(ref.buf, &head_points_at, &head_oid);
+ if (head_points_at && !is_null_oid(&head_oid))
+ fsck_handle_ref(ref.buf, &head_oid, 0, NULL);
+ strbuf_release(&ref);
+
+ if (include_reflogs)
+ refs_for_each_reflog(get_worktree_ref_store(wt),
+ fsck_handle_reflog, wt);
+ }
+ free_worktrees(worktrees);
/*
* Not having any default heads isn't really fatal, but
@@ -579,33 +603,36 @@ static void fsck_object_dir(const char *path)
stop_progress(&progress);
}
-static int fsck_head_link(void)
+static int fsck_head_link(const char *head_ref_name,
+ const char **head_points_at,
+ struct object_id *head_oid)
{
int null_is_error = 0;
if (verbose)
- fprintf(stderr, "Checking HEAD link\n");
+ fprintf(stderr, "Checking %s link\n", head_ref_name);
- head_points_at = resolve_ref_unsafe("HEAD", 0, &head_oid, NULL);
- if (!head_points_at) {
+ *head_points_at = resolve_ref_unsafe(head_ref_name, 0, head_oid, NULL);
+ if (!*head_points_at) {
errors_found |= ERROR_REFS;
- return error("Invalid HEAD");
+ return error("Invalid %s", head_ref_name);
}
- if (!strcmp(head_points_at, "HEAD"))
+ if (!strcmp(*head_points_at, head_ref_name))
/* detached HEAD */
null_is_error = 1;
- else if (!starts_with(head_points_at, "refs/heads/")) {
+ else if (!starts_with(*head_points_at, "refs/heads/")) {
errors_found |= ERROR_REFS;
- return error("HEAD points to something strange (%s)",
- head_points_at);
+ return error("%s points to something strange (%s)",
+ head_ref_name, *head_points_at);
}
- if (is_null_oid(&head_oid)) {
+ if (is_null_oid(head_oid)) {
if (null_is_error) {
errors_found |= ERROR_REFS;
- return error("HEAD: detached HEAD points at nothing");
+ return error("%s: detached HEAD points at nothing",
+ head_ref_name);
}
- fprintf(stderr, "notice: HEAD points to an unborn branch (%s)\n",
- head_points_at + 11);
+ fprintf(stderr, "notice: %s points to an unborn branch (%s)\n",
+ head_ref_name, *head_points_at + 11);
}
return 0;
}
@@ -720,7 +747,6 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
git_config(fsck_config, NULL);
- fsck_head_link();
if (connectivity_only) {
for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
for_each_packed_object(mark_packed_for_connectivity, NULL, 0);
diff --git a/builtin/grep.c b/builtin/grep.c
index d8508ddf79..71df52a333 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -34,7 +34,6 @@ static int recurse_submodules;
#define GREP_NUM_THREADS_DEFAULT 8
static int num_threads;
-#ifndef NO_PTHREADS
static pthread_t *threads;
/* We use one producer thread and THREADS consumer
@@ -70,13 +69,11 @@ static pthread_mutex_t grep_mutex;
static inline void grep_lock(void)
{
- assert(num_threads);
pthread_mutex_lock(&grep_mutex);
}
static inline void grep_unlock(void)
{
- assert(num_threads);
pthread_mutex_unlock(&grep_mutex);
}
@@ -234,6 +231,9 @@ static int wait_all(void)
int hit = 0;
int i;
+ if (!HAVE_THREADS)
+ BUG("Never call this function unless you have started threads");
+
grep_lock();
all_work_added = 1;
@@ -265,13 +265,6 @@ static int wait_all(void)
return hit;
}
-#else /* !NO_PTHREADS */
-
-static int wait_all(void)
-{
- return 0;
-}
-#endif
static int grep_cmd_config(const char *var, const char *value, void *cb)
{
@@ -284,17 +277,15 @@ static int grep_cmd_config(const char *var, const char *value, void *cb)
if (num_threads < 0)
die(_("invalid number of threads specified (%d) for %s"),
num_threads, var);
-#ifdef NO_PTHREADS
- else if (num_threads && num_threads != 1) {
+ else if (!HAVE_THREADS && num_threads > 1) {
/*
* TRANSLATORS: %s is the configuration
* variable for tweaking threads, currently
* grep.threads
*/
warning(_("no threads support, ignoring %s"), var);
- num_threads = 0;
+ num_threads = 1;
}
-#endif
}
if (!strcmp(var, "submodule.recurse"))
@@ -330,17 +321,14 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid);
strbuf_release(&pathbuf);
-#ifndef NO_PTHREADS
- if (num_threads) {
+ if (num_threads > 1) {
/*
* add_work() copies gs and thus assumes ownership of
* its fields, so do not call grep_source_clear()
*/
add_work(opt, &gs);
return 0;
- } else
-#endif
- {
+ } else {
int hit;
hit = grep_source(opt, &gs);
@@ -363,17 +351,14 @@ static int grep_file(struct grep_opt *opt, const char *filename)
grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename);
strbuf_release(&buf);
-#ifndef NO_PTHREADS
- if (num_threads) {
+ if (num_threads > 1) {
/*
* add_work() copies gs and thus assumes ownership of
* its fields, so do not call grep_source_clear()
*/
add_work(opt, &gs);
return 0;
- } else
-#endif
- {
+ } else {
int hit;
hit = grep_source(opt, &gs);
@@ -422,11 +407,23 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
struct repository submodule;
int hit;
- if (!is_submodule_active(superproject, path))
+ /*
+ * NEEDSWORK: submodules functions need to be protected because they
+ * access the object store via config_from_gitmodules(): the latter
+ * uses get_oid() which, for now, relies on the global the_repository
+ * object.
+ */
+ grep_read_lock();
+
+ if (!is_submodule_active(superproject, path)) {
+ grep_read_unlock();
return 0;
+ }
- if (repo_submodule_init(&submodule, superproject, path))
+ if (repo_submodule_init(&submodule, superproject, path)) {
+ grep_read_unlock();
return 0;
+ }
repo_read_gitmodules(&submodule);
@@ -440,7 +437,6 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
* store is no longer global and instead is a member of the repository
* object.
*/
- grep_read_lock();
add_to_alternates_memory(submodule.objects->objectdir);
grep_read_unlock();
@@ -712,11 +708,14 @@ static int context_callback(const struct option *opt, const char *arg,
static int file_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
- int from_stdin = !strcmp(arg, "-");
+ int from_stdin;
FILE *patterns;
int lno = 0;
struct strbuf sb = STRBUF_INIT;
+ BUG_ON_OPT_NEG(unset);
+
+ from_stdin = !strcmp(arg, "-");
patterns = from_stdin ? stdin : fopen(arg, "r");
if (!patterns)
die_errno(_("cannot open '%s'"), arg);
@@ -737,6 +736,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
static int not_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT);
return 0;
}
@@ -744,6 +745,8 @@ static int not_callback(const struct option *opt, const char *arg, int unset)
static int and_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND);
return 0;
}
@@ -751,6 +754,8 @@ static int and_callback(const struct option *opt, const char *arg, int unset)
static int open_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN);
return 0;
}
@@ -758,6 +763,8 @@ static int open_callback(const struct option *opt, const char *arg, int unset)
static int close_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN);
return 0;
}
@@ -766,6 +773,7 @@ static int pattern_callback(const struct option *opt, const char *arg,
int unset)
{
struct grep_opt *grep_opt = opt->value;
+ BUG_ON_OPT_NEG(unset);
append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN);
return 0;
}
@@ -1038,39 +1046,35 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
pathspec.recursive = 1;
pathspec.recurse_submodules = !!recurse_submodules;
-#ifndef NO_PTHREADS
- if (list.nr || cached || show_in_pager)
- num_threads = 0;
- else if (num_threads == 0)
- num_threads = GREP_NUM_THREADS_DEFAULT;
- else if (num_threads < 0)
- die(_("invalid number of threads specified (%d)"), num_threads);
- if (num_threads == 1)
- num_threads = 0;
-#else
- if (num_threads)
+ if (list.nr || cached || show_in_pager) {
+ if (num_threads > 1)
+ warning(_("invalid option combination, ignoring --threads"));
+ num_threads = 1;
+ } else if (!HAVE_THREADS && num_threads > 1) {
warning(_("no threads support, ignoring --threads"));
- num_threads = 0;
-#endif
+ num_threads = 1;
+ } else if (num_threads < 0)
+ die(_("invalid number of threads specified (%d)"), num_threads);
+ else if (num_threads == 0)
+ num_threads = HAVE_THREADS ? GREP_NUM_THREADS_DEFAULT : 1;
- if (!num_threads)
+ if (num_threads > 1) {
+ if (!HAVE_THREADS)
+ BUG("Somebody got num_threads calculation wrong!");
+ if (!(opt.name_only || opt.unmatch_name_only || opt.count)
+ && (opt.pre_context || opt.post_context ||
+ opt.file_break || opt.funcbody))
+ skip_first_line = 1;
+ start_threads(&opt);
+ } else {
/*
* The compiled patterns on the main path are only
* used when not using threading. Otherwise
- * start_threads() below calls compile_grep_patterns()
+ * start_threads() above calls compile_grep_patterns()
* for each thread.
*/
compile_grep_patterns(&opt);
-
-#ifndef NO_PTHREADS
- if (num_threads) {
- if (!(opt.name_only || opt.unmatch_name_only || opt.count)
- && (opt.pre_context || opt.post_context ||
- opt.file_break || opt.funcbody))
- skip_first_line = 1;
- start_threads(&opt);
}
-#endif
if (show_in_pager && (cached || list.nr))
die(_("--open-files-in-pager only works on the worktree"));
@@ -1121,7 +1125,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
hit = grep_objects(&opt, &pathspec, &list);
}
- if (num_threads)
+ if (num_threads > 1)
hit |= wait_all();
if (hit && show_in_pager)
run_pager(&opt, prefix);
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 2a8ada432b..ac1f4ea9a7 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -42,9 +42,7 @@ struct base_data {
};
struct thread_local {
-#ifndef NO_PTHREADS
pthread_t thread;
-#endif
struct base_data *base_cache;
size_t base_cache_used;
int pack_fd;
@@ -98,8 +96,6 @@ static uint32_t input_crc32;
static int input_fd, output_fd;
static const char *curr_pack;
-#ifndef NO_PTHREADS
-
static struct thread_local *thread_data;
static int nr_dispatched;
static int threads_active;
@@ -179,26 +175,6 @@ static void cleanup_thread(void)
free(thread_data);
}
-#else
-
-#define read_lock()
-#define read_unlock()
-
-#define counter_lock()
-#define counter_unlock()
-
-#define work_lock()
-#define work_unlock()
-
-#define deepest_delta_lock()
-#define deepest_delta_unlock()
-
-#define type_cas_lock()
-#define type_cas_unlock()
-
-#endif
-
-
static int mark_link(struct object *obj, int type, void *data, struct fsck_options *options)
{
if (!obj)
@@ -364,22 +340,20 @@ static NORETURN void bad_object(off_t offset, const char *format, ...)
static inline struct thread_local *get_thread_data(void)
{
-#ifndef NO_PTHREADS
- if (threads_active)
- return pthread_getspecific(key);
- assert(!threads_active &&
- "This should only be reached when all threads are gone");
-#endif
+ if (HAVE_THREADS) {
+ if (threads_active)
+ return pthread_getspecific(key);
+ assert(!threads_active &&
+ "This should only be reached when all threads are gone");
+ }
return &nothread_data;
}
-#ifndef NO_PTHREADS
static void set_thread_data(struct thread_local *data)
{
if (threads_active)
pthread_setspecific(key, data);
}
-#endif
static struct base_data *alloc_base_data(void)
{
@@ -1093,7 +1067,6 @@ static void resolve_base(struct object_entry *obj)
find_unresolved_deltas(base_obj);
}
-#ifndef NO_PTHREADS
static void *threaded_second_pass(void *data)
{
set_thread_data(data);
@@ -1117,7 +1090,6 @@ static void *threaded_second_pass(void *data)
}
return NULL;
}
-#endif
/*
* First pass:
@@ -1214,7 +1186,6 @@ static void resolve_deltas(void)
progress = start_progress(_("Resolving deltas"),
nr_ref_deltas + nr_ofs_deltas);
-#ifndef NO_PTHREADS
nr_dispatched = 0;
if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) {
init_thread();
@@ -1230,7 +1201,6 @@ static void resolve_deltas(void)
cleanup_thread();
return;
}
-#endif
for (i = 0; i < nr_objects; i++) {
struct object_entry *obj = &objects[i];
@@ -1532,11 +1502,10 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
if (nr_threads < 0)
die(_("invalid number of threads specified (%d)"),
nr_threads);
-#ifdef NO_PTHREADS
- if (nr_threads != 1)
+ if (!HAVE_THREADS && nr_threads != 1) {
warning(_("no threads support, ignoring %s"), k);
- nr_threads = 1;
-#endif
+ nr_threads = 1;
+ }
return 0;
}
return git_default_config(k, v, cb);
@@ -1724,12 +1693,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
nr_threads = strtoul(arg+10, &end, 0);
if (!arg[10] || *end || nr_threads < 0)
usage(index_pack_usage);
-#ifdef NO_PTHREADS
- if (nr_threads != 1)
- warning(_("no threads support, "
- "ignoring %s"), arg);
- nr_threads = 1;
-#endif
+ if (!HAVE_THREADS && nr_threads != 1) {
+ warning(_("no threads support, ignoring %s"), arg);
+ nr_threads = 1;
+ }
} else if (starts_with(arg, "--pack_header=")) {
struct pack_header *hdr;
char *c;
@@ -1792,14 +1759,12 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (strict)
opts.flags |= WRITE_IDX_STRICT;
-#ifndef NO_PTHREADS
- if (!nr_threads) {
+ if (HAVE_THREADS && !nr_threads) {
nr_threads = online_cpus();
/* An experiment showed that more threads does not mean faster */
if (nr_threads > 3)
nr_threads = 3;
}
-#endif
curr_pack = open_pack_file(pack_name);
parse_pack_header();
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 12ddda7e7b..41faffd28d 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -451,6 +451,7 @@ static int guess_repository_type(const char *git_dir)
static int shared_callback(const struct option *opt, const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
*((int *) opt->value) = (arg) ? git_config_perm("arg", arg) : PERM_GROUP;
return 0;
}
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
index 4b87e0dd2e..8ae40dec47 100644
--- a/builtin/interpret-trailers.c
+++ b/builtin/interpret-trailers.c
@@ -80,6 +80,8 @@ static int parse_opt_parse(const struct option *opt, const char *arg,
v->only_trailers = 1;
v->only_input = 1;
v->unfold = 1;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
return 0;
}
diff --git a/builtin/log.c b/builtin/log.c
index 061d4fd864..0fe6f9ba1e 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -107,6 +107,8 @@ static int log_line_range_callback(const struct option *option, const char *arg,
{
struct line_opt_callback_data *data = option->value;
+ BUG_ON_OPT_NEG(unset);
+
if (!arg)
return -1;
@@ -1009,8 +1011,6 @@ static void show_diffstat(struct rev_info *rev,
memcpy(&opts, &rev->diffopt, sizeof(opts));
opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
- opts.stat_width = MAIL_DEFAULT_WRAP;
-
diff_setup_done(&opts);
diff_tree_oid(get_commit_tree_oid(origin),
@@ -1151,6 +1151,8 @@ static int keep_subject = 0;
static int keep_callback(const struct option *opt, const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
((struct rev_info *)opt->value)->total = -1;
keep_subject = 1;
return 0;
@@ -1161,6 +1163,7 @@ static int subject_prefix = 0;
static int subject_prefix_callback(const struct option *opt, const char *arg,
int unset)
{
+ BUG_ON_OPT_NEG(unset);
subject_prefix = 1;
((struct rev_info *)opt->value)->subject_prefix = arg;
return 0;
@@ -1168,6 +1171,8 @@ static int subject_prefix_callback(const struct option *opt, const char *arg,
static int rfc_callback(const struct option *opt, const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
return subject_prefix_callback(opt, "RFC PATCH", unset);
}
@@ -1176,6 +1181,7 @@ static int numbered_cmdline_opt = 0;
static int numbered_callback(const struct option *opt, const char *arg,
int unset)
{
+ BUG_ON_OPT_ARG(arg);
*(int *)opt->value = numbered_cmdline_opt = unset ? 0 : 1;
if (unset)
auto_number = 0;
@@ -1185,6 +1191,7 @@ static int numbered_callback(const struct option *opt, const char *arg,
static int no_numbered_callback(const struct option *opt, const char *arg,
int unset)
{
+ BUG_ON_OPT_NEG(unset);
return numbered_callback(opt, arg, 1);
}
@@ -1192,6 +1199,7 @@ static int output_directory_callback(const struct option *opt, const char *arg,
int unset)
{
const char **dir = (const char **)opt->value;
+ BUG_ON_OPT_NEG(unset);
if (*dir)
die(_("Two output directories?"));
*dir = arg;
@@ -1508,7 +1516,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
PARSE_OPT_NOARG, numbered_callback },
{ OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL,
N_("use [PATCH] even with multiple patches"),
- PARSE_OPT_NOARG, no_numbered_callback },
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback },
OPT_BOOL('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
OPT_BOOL(0, "stdout", &use_stdout,
N_("print patches to standard out")),
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 7f9919a362..c70a9c7158 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -475,6 +475,8 @@ static int option_parse_exclude(const struct option *opt,
{
struct string_list *exclude_list = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
exc_given = 1;
string_list_append(exclude_list, arg);
@@ -486,6 +488,8 @@ static int option_parse_exclude_from(const struct option *opt,
{
struct dir_struct *dir = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
exc_given = 1;
add_excludes_from_file(dir, arg);
@@ -497,6 +501,9 @@ static int option_parse_exclude_standard(const struct option *opt,
{
struct dir_struct *dir = opt->value;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
+
exc_given = 1;
setup_standard_excludes(dir);
@@ -548,15 +555,16 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
N_("show resolve-undo information")),
{ OPTION_CALLBACK, 'x', "exclude", &exclude_list, N_("pattern"),
N_("skip files matching pattern"),
- 0, option_parse_exclude },
+ PARSE_OPT_NONEG, option_parse_exclude },
{ OPTION_CALLBACK, 'X', "exclude-from", &dir, N_("file"),
N_("exclude patterns are read from <file>"),
- 0, option_parse_exclude_from },
+ PARSE_OPT_NONEG, option_parse_exclude_from },
OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, N_("file"),
N_("read additional per-directory exclude patterns in <file>")),
{ OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
N_("add the standard git exclusions"),
- PARSE_OPT_NOARG, option_parse_exclude_standard },
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+ option_parse_exclude_standard },
OPT_SET_INT_F(0, "full-name", &prefix_len,
N_("make the output relative to the project top directory"),
0, PARSE_OPT_NONEG),
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 6a0cdec30d..1d7f1f5ce2 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -88,18 +88,15 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
int i;
pattern = xcalloc(argc, sizeof(const char *));
for (i = 1; i < argc; i++) {
- const char *glob;
pattern[i - 1] = xstrfmt("*/%s", argv[i]);
-
- glob = strchr(argv[i], '*');
- if (glob)
- argv_array_pushf(&ref_prefixes, "%.*s",
- (int)(glob - argv[i]), argv[i]);
- else
- expand_ref_prefix(&ref_prefixes, argv[i]);
}
}
+ if (flags & REF_TAGS)
+ argv_array_push(&ref_prefixes, "refs/tags/");
+ if (flags & REF_HEADS)
+ argv_array_push(&ref_prefixes, "refs/heads/");
+
remote = remote_get(dest);
if (!remote) {
if (dest)
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index b08803e611..06a2f90c48 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -15,6 +15,8 @@ static int label_cb(const struct option *opt, const char *arg, int unset)
static int label_count = 0;
const char **names = (const char **)opt->value;
+ BUG_ON_OPT_NEG(unset);
+
if (label_count >= 3)
return error("too many labels on the command line");
names[label_count++] = arg;
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 8fc108d305..70f6fc9167 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -110,7 +110,8 @@ static void show_diff(struct merge_list *entry)
xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
- ecb.outf = show_outf;
+ ecb.out_hunk = NULL;
+ ecb.out_line = show_outf;
ecb.priv = NULL;
src.ptr = origin(entry, &size);
diff --git a/builtin/merge.c b/builtin/merge.c
index 4aa6071598..c3c976d471 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -224,6 +224,7 @@ static int option_parse_x(const struct option *opt,
static int option_parse_n(const struct option *opt,
const char *arg, int unset)
{
+ BUG_ON_OPT_ARG(arg);
show_diffstat = unset;
return 0;
}
@@ -1336,6 +1337,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
die(_("%s - not something we can merge"), argv[0]);
if (remoteheads->next)
die(_("Can merge only exactly one commit into empty head"));
+
+ if (verify_signatures)
+ verify_merge_signature(remoteheads->item, verbosity);
+
remote_head_oid = &remoteheads->item->object.oid;
read_empty(remote_head_oid, 0);
update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
@@ -1357,31 +1362,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
if (verify_signatures) {
for (p = remoteheads; p; p = p->next) {
- struct commit *commit = p->item;
- char hex[GIT_MAX_HEXSZ + 1];
- struct signature_check signature_check;
- memset(&signature_check, 0, sizeof(signature_check));
-
- check_commit_signature(commit, &signature_check);
-
- find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV);
- switch (signature_check.result) {
- case 'G':
- break;
- case 'U':
- die(_("Commit %s has an untrusted GPG signature, "
- "allegedly by %s."), hex, signature_check.signer);
- case 'B':
- die(_("Commit %s has a bad GPG signature "
- "allegedly by %s."), hex, signature_check.signer);
- default: /* 'N' */
- die(_("Commit %s does not have a GPG signature."), hex);
- }
- if (verbosity >= 0 && signature_check.result == 'G')
- printf(_("Commit %s has a good GPG signature by %s\n"),
- hex, signature_check.signer);
-
- signature_check_clear(&signature_check);
+ verify_merge_signature(p->item, verbosity);
}
}
diff --git a/builtin/notes.c b/builtin/notes.c
index c05cd004ab..c78b7a0c5b 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -215,6 +215,8 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
strbuf_grow(&d->buf, strlen(arg) + 2);
if (d->buf.len)
strbuf_addch(&d->buf, '\n');
@@ -229,6 +231,8 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
if (d->buf.len)
strbuf_addch(&d->buf, '\n');
if (!strcmp(arg, "-")) {
@@ -250,15 +254,15 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
enum object_type type;
unsigned long len;
+ BUG_ON_OPT_NEG(unset);
+
if (d->buf.len)
strbuf_addch(&d->buf, '\n');
if (get_oid(arg, &object))
die(_("failed to resolve '%s' as a valid ref."), arg);
- if (!(buf = read_object_file(&object, &type, &len))) {
- free(buf);
+ if (!(buf = read_object_file(&object, &type, &len)))
die(_("failed to read object '%s'."), arg);
- }
if (type != OBJ_BLOB) {
free(buf);
die(_("cannot read note data from non-blob object '%s'."), arg);
@@ -273,6 +277,7 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)
{
struct note_data *d = opt->value;
+ BUG_ON_OPT_NEG(unset);
d->use_editor = 1;
return parse_reuse_arg(opt, arg, unset);
}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 0d3921e009..e7ea206c08 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1953,8 +1953,6 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
return 0;
}
-#ifndef NO_PTHREADS
-
/* Protect access to object database */
static pthread_mutex_t read_mutex;
#define read_lock() pthread_mutex_lock(&read_mutex)
@@ -1979,16 +1977,6 @@ static pthread_mutex_t progress_mutex;
* ahead in the list because they can be stolen and would need
* progress_mutex for protection.
*/
-#else
-
-#define read_lock() (void)0
-#define read_unlock() (void)0
-#define cache_lock() (void)0
-#define cache_unlock() (void)0
-#define progress_lock() (void)0
-#define progress_unlock() (void)0
-
-#endif
/*
* Return the size of the object without doing any delta
@@ -2347,8 +2335,6 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
free(array);
}
-#ifndef NO_PTHREADS
-
static void try_to_free_from_threads(size_t size)
{
read_lock();
@@ -2577,10 +2563,6 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
free(p);
}
-#else
-#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p)
-#endif
-
static void add_tag_chain(const struct object_id *oid)
{
struct tag *tag;
@@ -2733,12 +2715,10 @@ static int git_pack_config(const char *k, const char *v, void *cb)
if (delta_search_threads < 0)
die(_("invalid number of threads specified (%d)"),
delta_search_threads);
-#ifdef NO_PTHREADS
- if (delta_search_threads != 1) {
+ if (!HAVE_THREADS && delta_search_threads != 1) {
warning(_("no threads support, ignoring %s"), k);
delta_search_threads = 0;
}
-#endif
return 0;
}
if (!strcmp(k, "pack.indexversion")) {
@@ -3104,6 +3084,7 @@ static void get_object_list(int ac, const char **av)
struct rev_info revs;
char line[1000];
int flags = 0;
+ int save_warning;
repo_init_revisions(the_repository, &revs, NULL);
save_commit_buffer = 0;
@@ -3113,6 +3094,9 @@ static void get_object_list(int ac, const char **av)
/* make sure shallows are read */
is_repository_shallow(the_repository);
+ save_warning = warn_on_object_refname_ambiguity;
+ warn_on_object_refname_ambiguity = 0;
+
while (fgets(line, sizeof(line), stdin) != NULL) {
int len = strlen(line);
if (len && line[len - 1] == '\n')
@@ -3139,6 +3123,8 @@ static void get_object_list(int ac, const char **av)
die(_("bad revision '%s'"), line);
}
+ warn_on_object_refname_ambiguity = save_warning;
+
if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
return;
@@ -3207,6 +3193,9 @@ static int option_parse_index_version(const struct option *opt,
{
char *c;
const char *val = arg;
+
+ BUG_ON_OPT_NEG(unset);
+
pack_idx_opts.version = strtoul(val, &c, 10);
if (pack_idx_opts.version > 2)
die(_("unsupported index version %s"), val);
@@ -3253,7 +3242,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
N_("similar to --all-progress when progress meter is shown")),
{ OPTION_CALLBACK, 0, "index-version", NULL, N_("<version>[,<offset>]"),
N_("write the pack index file in the specified idx format version"),
- 0, option_parse_index_version },
+ PARSE_OPT_NONEG, option_parse_index_version },
OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
N_("maximum size of each output pack file")),
OPT_BOOL(0, "local", &local,
@@ -3402,10 +3391,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads = online_cpus();
-#ifdef NO_PTHREADS
- if (delta_search_threads != 1)
+ if (!HAVE_THREADS && delta_search_threads != 1)
warning(_("no threads support, ignoring --threads"));
-#endif
if (!pack_to_stdout && !pack_size_limit)
pack_size_limit = pack_size_limit_cfg;
if (pack_to_stdout && pack_size_limit)
diff --git a/builtin/pull.c b/builtin/pull.c
index c21aa276f1..1b90622b13 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -557,6 +557,17 @@ static int run_fetch(const char *repo, const char **refspecs)
static int pull_into_void(const struct object_id *merge_head,
const struct object_id *curr_head)
{
+ if (opt_verify_signatures) {
+ struct commit *commit;
+
+ commit = lookup_commit(the_repository, merge_head);
+ if (!commit)
+ die(_("unable to access commit %s"),
+ oid_to_hex(merge_head));
+
+ verify_merge_signature(commit, opt_verbosity);
+ }
+
/*
* Two-way merge: we treat the index as based on an empty tree,
* and try to fast-forward to HEAD. This ensures we will not lose
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index fbbc98e516..183ee8c1e5 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -44,6 +44,7 @@ static const char * const read_tree_usage[] = {
static int index_output_cb(const struct option *opt, const char *arg,
int unset)
{
+ BUG_ON_OPT_NEG(unset);
set_alternate_index_output(arg);
return 0;
}
@@ -54,6 +55,8 @@ static int exclude_per_directory_cb(const struct option *opt, const char *arg,
struct dir_struct *dir;
struct unpack_trees_options *opts;
+ BUG_ON_OPT_NEG(unset);
+
opts = (struct unpack_trees_options *)opt->value;
if (opts->dir)
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 0ee06aa363..1a2758756a 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -23,6 +23,7 @@
#include "revision.h"
#include "commit-reach.h"
#include "rerere.h"
+#include "branch.h"
static char const * const builtin_rebase_usage[] = {
N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -48,7 +49,10 @@ static int use_builtin_rebase(void)
{
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf out = STRBUF_INIT;
- int ret;
+ int ret, env = git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1);
+
+ if (env != -1)
+ return env;
argv_array_pushl(&cp.args,
"config", "--bool", "rebase.usebuiltin", NULL);
@@ -87,7 +91,7 @@ struct rebase_options {
REBASE_FORCE = 1<<3,
REBASE_INTERACTIVE_EXPLICIT = 1<<4,
} flags;
- struct strbuf git_am_opt;
+ struct argv_array git_am_opts;
const char *action;
int signoff;
int allow_rerere_autoupdate;
@@ -339,7 +343,7 @@ N_("Resolve all conflicts manually, mark them as resolved with\n"
static int run_specific_rebase(struct rebase_options *opts)
{
const char *argv[] = { NULL, NULL };
- struct strbuf script_snippet = STRBUF_INIT;
+ struct strbuf script_snippet = STRBUF_INIT, buf = STRBUF_INIT;
int status;
const char *backend, *backend_func;
@@ -433,7 +437,9 @@ static int run_specific_rebase(struct rebase_options *opts)
oid_to_hex(&opts->restrict_revision->object.oid) : NULL);
add_var(&script_snippet, "GIT_QUIET",
opts->flags & REBASE_NO_QUIET ? "" : "t");
- add_var(&script_snippet, "git_am_opt", opts->git_am_opt.buf);
+ sq_quote_argv_pretty(&buf, opts->git_am_opts.argv);
+ add_var(&script_snippet, "git_am_opt", buf.buf);
+ strbuf_release(&buf);
add_var(&script_snippet, "verbose",
opts->flags & REBASE_VERBOSE ? "t" : "");
add_var(&script_snippet, "diffstat",
@@ -522,12 +528,17 @@ finished_rebase:
#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
+#define RESET_HEAD_DETACH (1<<0)
+#define RESET_HEAD_HARD (1<<1)
+
static int reset_head(struct object_id *oid, const char *action,
- const char *switch_to_branch, int detach_head,
+ const char *switch_to_branch, unsigned flags,
const char *reflog_orig_head, const char *reflog_head)
{
+ unsigned detach_head = flags & RESET_HEAD_DETACH;
+ unsigned reset_hard = flags & RESET_HEAD_HARD;
struct object_id head_oid;
- struct tree_desc desc;
+ struct tree_desc desc[2] = { { NULL }, { NULL } };
struct lock_file lock = LOCK_INIT;
struct unpack_trees_options unpack_tree_opts;
struct tree *tree;
@@ -536,60 +547,62 @@ static int reset_head(struct object_id *oid, const char *action,
size_t prefix_len;
struct object_id *orig = NULL, oid_orig,
*old_orig = NULL, oid_old_orig;
- int ret = 0;
+ int ret = 0, nr = 0;
if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
BUG("Not a fully qualified branch: '%s'", switch_to_branch);
- if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
- return -1;
+ if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) {
+ ret = -1;
+ goto leave_reset_head;
+ }
- if (!oid) {
- if (get_oid("HEAD", &head_oid)) {
- rollback_lock_file(&lock);
- return error(_("could not determine HEAD revision"));
- }
- oid = &head_oid;
+ if ((!oid || !reset_hard) && get_oid("HEAD", &head_oid)) {
+ ret = error(_("could not determine HEAD revision"));
+ goto leave_reset_head;
}
+ if (!oid)
+ oid = &head_oid;
+
memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
setup_unpack_trees_porcelain(&unpack_tree_opts, action);
unpack_tree_opts.head_idx = 1;
unpack_tree_opts.src_index = the_repository->index;
unpack_tree_opts.dst_index = the_repository->index;
- unpack_tree_opts.fn = oneway_merge;
+ unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
unpack_tree_opts.update = 1;
unpack_tree_opts.merge = 1;
if (!detach_head)
unpack_tree_opts.reset = 1;
if (read_index_unmerged(the_repository->index) < 0) {
- rollback_lock_file(&lock);
- return error(_("could not read index"));
+ ret = error(_("could not read index"));
+ goto leave_reset_head;
}
- if (!fill_tree_descriptor(&desc, oid)) {
- error(_("failed to find tree of %s"), oid_to_hex(oid));
- rollback_lock_file(&lock);
- free((void *)desc.buffer);
- return -1;
+ if (!reset_hard && !fill_tree_descriptor(&desc[nr++], &head_oid)) {
+ ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
+ goto leave_reset_head;
}
- if (unpack_trees(1, &desc, &unpack_tree_opts)) {
- rollback_lock_file(&lock);
- free((void *)desc.buffer);
- return -1;
+ if (!fill_tree_descriptor(&desc[nr++], oid)) {
+ ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
+ goto leave_reset_head;
+ }
+
+ if (unpack_trees(nr, desc, &unpack_tree_opts)) {
+ ret = -1;
+ goto leave_reset_head;
}
tree = parse_tree_indirect(oid);
prime_cache_tree(the_repository->index, tree);
- if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0)
+ if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) {
ret = error(_("could not write index"));
- free((void *)desc.buffer);
-
- if (ret)
- return ret;
+ goto leave_reset_head;
+ }
reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase");
@@ -613,7 +626,8 @@ static int reset_head(struct object_id *oid, const char *action,
reflog_head = msg.buf;
}
if (!switch_to_branch)
- ret = update_ref(reflog_head, "HEAD", oid, orig, REF_NO_DEREF,
+ ret = update_ref(reflog_head, "HEAD", oid, orig,
+ detach_head ? REF_NO_DEREF : 0,
UPDATE_REFS_MSG_ON_ERR);
else {
ret = create_symref("HEAD", switch_to_branch, msg.buf);
@@ -622,7 +636,11 @@ static int reset_head(struct object_id *oid, const char *action,
UPDATE_REFS_MSG_ON_ERR);
}
+leave_reset_head:
strbuf_release(&msg);
+ rollback_lock_file(&lock);
+ while (nr)
+ free((void *)desc[--nr].buffer);
return ret;
}
@@ -703,6 +721,9 @@ static int parse_opt_merge(const struct option *opt, const char *arg, int unset)
{
struct rebase_options *opts = opt->value;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
+
if (!is_interactive(opts))
opts->type = REBASE_MERGE;
@@ -715,6 +736,9 @@ static int parse_opt_interactive(const struct option *opt, const char *arg,
{
struct rebase_options *opts = opt->value;
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
+
opts->type = REBASE_INTERACTIVE;
opts->flags |= REBASE_INTERACTIVE_EXPLICIT;
@@ -756,7 +780,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct rebase_options options = {
.type = REBASE_UNSPECIFIED,
.flags = REBASE_NO_QUIET,
- .git_am_opt = STRBUF_INIT,
+ .git_am_opts = ARGV_ARRAY_INIT,
.allow_rerere_autoupdate = -1,
.allow_empty_message = 1,
.git_format_patch_opt = STRBUF_INIT,
@@ -777,12 +801,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
ACTION_EDIT_TODO,
ACTION_SHOW_CURRENT_PATCH,
} action = NO_ACTION;
- int committer_date_is_author_date = 0;
- int ignore_date = 0;
- int ignore_whitespace = 0;
const char *gpg_sign = NULL;
- int opt_c = -1;
- struct string_list whitespace = STRING_LIST_INIT_NODUP;
struct string_list exec = STRING_LIST_INIT_NODUP;
const char *rebase_merges = NULL;
int fork_point = -1;
@@ -804,15 +823,20 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
N_("do not show diffstat of what changed upstream"),
PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
- OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
- N_("passed to 'git apply'")),
OPT_BOOL(0, "signoff", &options.signoff,
N_("add a Signed-off-by: line to each commit")),
- OPT_BOOL(0, "committer-date-is-author-date",
- &committer_date_is_author_date,
- N_("passed to 'git am'")),
- OPT_BOOL(0, "ignore-date", &ignore_date,
- N_("passed to 'git am'")),
+ OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &options.git_am_opts,
+ NULL, N_("passed to 'git am'"),
+ PARSE_OPT_NOARG),
+ OPT_PASSTHRU_ARGV(0, "committer-date-is-author-date",
+ &options.git_am_opts, NULL,
+ N_("passed to 'git am'"), PARSE_OPT_NOARG),
+ OPT_PASSTHRU_ARGV(0, "ignore-date", &options.git_am_opts, NULL,
+ N_("passed to 'git am'"), PARSE_OPT_NOARG),
+ OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
+ N_("passed to 'git apply'"), 0),
+ OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
+ N_("action"), N_("passed to 'git apply'"), 0),
OPT_BIT('f', "force-rebase", &options.flags,
N_("cherry-pick all commits, even if unchanged"),
REBASE_FORCE),
@@ -856,10 +880,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
{ OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
N_("GPG-sign commits"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
- OPT_STRING_LIST(0, "whitespace", &whitespace,
- N_("whitespace"), N_("passed to 'git apply'")),
- OPT_SET_INT('C', NULL, &opt_c, N_("passed to 'git apply'"),
- REBASE_AM),
OPT_BOOL(0, "autostash", &options.autostash,
N_("automatically stash/stash pop before and after")),
OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
@@ -884,6 +904,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
N_("rebase all reachable commits up to the root(s)")),
OPT_END(),
};
+ int i;
/*
* NEEDSWORK: Once the builtin rebase has been tested enough
@@ -1000,8 +1021,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
rerere_clear(&merge_rr);
string_list_clear(&merge_rr, 1);
- if (reset_head(NULL, "reset", NULL, 0, NULL, NULL) < 0)
+ if (reset_head(NULL, "reset", NULL, RESET_HEAD_HARD,
+ NULL, NULL) < 0)
die(_("could not discard worktree changes"));
+ remove_branch_state();
if (read_basic_state(&options))
exit(1);
goto run_rebase;
@@ -1016,9 +1039,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (read_basic_state(&options))
exit(1);
if (reset_head(&options.orig_head, "reset",
- options.head_name, 0, NULL, NULL) < 0)
+ options.head_name, RESET_HEAD_HARD,
+ NULL, NULL) < 0)
die(_("could not move back to %s"),
oid_to_hex(&options.orig_head));
+ remove_branch_state();
ret = finish_rebase(&options);
goto cleanup;
}
@@ -1064,22 +1089,27 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
state_dir_base, cmd_live_rebase, buf.buf);
}
- if (!(options.flags & REBASE_NO_QUIET))
- strbuf_addstr(&options.git_am_opt, " -q");
-
- if (committer_date_is_author_date) {
- strbuf_addstr(&options.git_am_opt,
- " --committer-date-is-author-date");
- options.flags |= REBASE_FORCE;
+ for (i = 0; i < options.git_am_opts.argc; i++) {
+ const char *option = options.git_am_opts.argv[i], *p;
+ if (!strcmp(option, "--committer-date-is-author-date") ||
+ !strcmp(option, "--ignore-date") ||
+ !strcmp(option, "--whitespace=fix") ||
+ !strcmp(option, "--whitespace=strip"))
+ options.flags |= REBASE_FORCE;
+ else if (skip_prefix(option, "-C", &p)) {
+ while (*p)
+ if (!isdigit(*(p++)))
+ die(_("switch `C' expects a "
+ "numerical value"));
+ } else if (skip_prefix(option, "--whitespace=", &p)) {
+ if (*p && strcmp(p, "warn") && strcmp(p, "nowarn") &&
+ strcmp(p, "error") && strcmp(p, "error-all"))
+ die("Invalid whitespace option: '%s'", p);
+ }
}
- if (ignore_whitespace)
- strbuf_addstr(&options.git_am_opt, " --ignore-whitespace");
-
- if (ignore_date) {
- strbuf_addstr(&options.git_am_opt, " --ignore-date");
- options.flags |= REBASE_FORCE;
- }
+ if (!(options.flags & REBASE_NO_QUIET))
+ argv_array_push(&options.git_am_opts, "-q");
if (options.keep_empty)
imply_interactive(&options, "--keep-empty");
@@ -1089,23 +1119,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
}
- if (opt_c >= 0)
- strbuf_addf(&options.git_am_opt, " -C%d", opt_c);
-
- if (whitespace.nr) {
- int i;
-
- for (i = 0; i < whitespace.nr; i++) {
- const char *item = whitespace.items[i].string;
-
- strbuf_addf(&options.git_am_opt, " --whitespace=%s",
- item);
-
- if ((!strcmp(item, "fix")) || (!strcmp(item, "strip")))
- options.flags |= REBASE_FORCE;
- }
- }
-
if (exec.nr) {
int i;
@@ -1181,23 +1194,18 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
break;
}
- if (options.git_am_opt.len) {
- const char *p;
-
+ if (options.git_am_opts.argc) {
/* all am options except -q are compatible only with --am */
- strbuf_reset(&buf);
- strbuf_addbuf(&buf, &options.git_am_opt);
- strbuf_addch(&buf, ' ');
- while ((p = strstr(buf.buf, " -q ")))
- strbuf_splice(&buf, p - buf.buf, 4, " ", 1);
- strbuf_trim(&buf);
+ for (i = options.git_am_opts.argc - 1; i >= 0; i--)
+ if (strcmp(options.git_am_opts.argv[i], "-q"))
+ break;
- if (is_interactive(&options) && buf.len)
+ if (is_interactive(&options) && i >= 0)
die(_("error: cannot combine interactive options "
"(--interactive, --exec, --rebase-merges, "
"--preserve-merges, --keep-empty, --root + "
"--onto) with am options (%s)"), buf.buf);
- if (options.type == REBASE_MERGE && buf.len)
+ if (options.type == REBASE_MERGE && i >= 0)
die(_("error: cannot combine merge options (--merge, "
"--strategy, --strategy-option) with am options "
"(%s)"), buf.buf);
@@ -1207,7 +1215,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.type == REBASE_PRESERVE_MERGES)
die("cannot combine '--signoff' with "
"'--preserve-merges'");
- strbuf_addstr(&options.git_am_opt, " --signoff");
+ argv_array_push(&options.git_am_opts, "--signoff");
options.flags |= REBASE_FORCE;
}
@@ -1380,7 +1388,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
write_file(autostash, "%s", oid_to_hex(&oid));
printf(_("Created autostash: %s\n"), buf.buf);
if (reset_head(&head->object.oid, "reset --hard",
- NULL, 0, NULL, NULL) < 0)
+ NULL, RESET_HEAD_HARD, NULL, NULL) < 0)
die(_("could not reset --hard"));
printf(_("HEAD is now at %s"),
find_unique_abbrev(&head->object.oid,
@@ -1500,8 +1508,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
"it...\n"));
strbuf_addf(&msg, "rebase: checkout %s", options.onto_name);
- if (reset_head(&options.onto->object.oid, "checkout", NULL, 1,
- NULL, msg.buf))
+ if (reset_head(&options.onto->object.oid, "checkout", NULL,
+ RESET_HEAD_DETACH, NULL, msg.buf))
die(_("Could not detach HEAD"));
strbuf_release(&msg);
diff --git a/builtin/reflog.c b/builtin/reflog.c
index b5941c1ff3..7a85e4b164 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -10,6 +10,7 @@
#include "diff.h"
#include "revision.h"
#include "reachable.h"
+#include "worktree.h"
/* NEEDSWORK: switch to using parse_options */
static const char reflog_expire_usage[] =
@@ -52,6 +53,7 @@ struct collect_reflog_cb {
struct collected_reflog **e;
int alloc;
int nr;
+ struct worktree *wt;
};
/* Remember to update object flag allocation in object.h */
@@ -330,13 +332,27 @@ static int push_tip_to_list(const char *refname, const struct object_id *oid,
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;
- if (!cb->cmd.expire_unreachable || !strcmp(refname, "HEAD")) {
+ if (!cb->cmd.expire_unreachable || is_head(refname)) {
cb->tip_commit = NULL;
cb->unreachable_expire_kind = UE_HEAD;
} else {
@@ -388,8 +404,19 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus
{
struct collected_reflog *e;
struct collect_reflog_cb *cb = cb_data;
+ struct strbuf newref = STRBUF_INIT;
+
+ /*
+ * Avoid collecting the same shared ref multiple times because
+ * they are available via all worktrees.
+ */
+ if (!cb->wt->is_current && ref_type(ref) == REF_TYPE_NORMAL)
+ return 0;
+
+ strbuf_worktree_ref(cb->wt, &newref, ref);
+ FLEX_ALLOC_STR(e, reflog, newref.buf);
+ strbuf_release(&newref);
- FLEX_ALLOC_STR(e, reflog, ref);
oidcpy(&e->oid, oid);
ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
cb->e[cb->nr++] = e;
@@ -512,7 +539,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
{
struct expire_reflog_policy_cb cb;
timestamp_t now = time(NULL);
- int i, status, do_all;
+ int i, status, do_all, all_worktrees = 1;
int explicit_expiry = 0;
unsigned int flags = 0;
@@ -549,6 +576,8 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
flags |= EXPIRE_REFLOGS_UPDATE_REF;
else if (!strcmp(arg, "--all"))
do_all = 1;
+ else if (!strcmp(arg, "--single-worktree"))
+ all_worktrees = 0;
else if (!strcmp(arg, "--verbose"))
flags |= EXPIRE_REFLOGS_VERBOSE;
else if (!strcmp(arg, "--")) {
@@ -577,10 +606,19 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
if (do_all) {
struct collect_reflog_cb collected;
+ struct worktree **worktrees, **p;
int i;
memset(&collected, 0, sizeof(collected));
- for_each_reflog(collect_reflog, &collected);
+ worktrees = get_worktrees(0);
+ for (p = worktrees; *p; p++) {
+ if (!all_worktrees && !(*p)->is_current)
+ continue;
+ collected.wt = *p;
+ refs_for_each_reflog(get_worktree_ref_store(*p),
+ collect_reflog, &collected);
+ }
+ free_worktrees(worktrees);
for (i = 0; i < collected.nr; i++) {
struct collected_reflog *e = collected.e[i];
set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
diff --git a/builtin/repack.c b/builtin/repack.c
index 82c19b7555..45583683ee 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -431,8 +431,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
char *fname, *fname_old;
if (!midx_cleared) {
- /* if we move a packfile, it will invalidated the midx */
- clear_midx_file(get_object_directory());
+ clear_midx_file(the_repository);
midx_cleared = 1;
}
@@ -561,6 +560,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (!no_update_server_info)
update_server_info(0);
remove_temporary_files();
+
+ if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0))
+ write_midx_file(get_object_directory());
+
string_list_clear(&names, 0);
string_list_clear(&rollback, 0);
string_list_clear(&existing_packs, 0);
diff --git a/builtin/rerere.c b/builtin/rerere.c
index e89ccbc524..d78eeaed32 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -41,7 +41,8 @@ static int diff_two(const char *file1, const char *label1,
xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
- ecb.outf = outf;
+ ecb.out_hunk = NULL;
+ ecb.out_line = outf;
ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
free(minus.ptr);
diff --git a/builtin/reset.c b/builtin/reset.c
index 6d37a35e2e..58166964f8 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -25,6 +25,8 @@
#include "submodule.h"
#include "submodule-config.h"
+#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
+
static const char * const git_reset_usage[] = {
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
N_("git reset [-q] [<tree-ish>] [--] <paths>..."),
@@ -307,6 +309,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
};
git_config(git_reset_config, NULL);
+ git_config_get_bool("reset.quiet", &quiet);
argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
@@ -376,9 +379,19 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
if (read_from_tree(&pathspec, &oid, intent_to_add))
return 1;
- if (get_git_work_tree())
+ if (!quiet && get_git_work_tree()) {
+ uint64_t t_begin, t_delta_in_ms;
+
+ t_begin = getnanotime();
refresh_index(&the_index, flags, NULL, NULL,
_("Unstaged changes after reset:"));
+ t_delta_in_ms = (getnanotime() - t_begin) / 1000000;
+ if (advice_reset_quiet_warning && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) {
+ printf(_("\nIt took %.2f seconds to enumerate unstaged changes after reset. You can\n"
+ "use '--quiet' to avoid this. Set the config setting reset.quiet to true\n"
+ "to make this the default.\n"), t_delta_in_ms / 1000.0);
+ }
+ }
} else {
int err = reset_index(&oid, reset_type, quiet);
if (reset_type == KEEP && !err)
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 455f62246d..10d4dab894 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -765,6 +765,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
}
if (!strcmp(arg, "--all")) {
for_each_ref(show_reference, NULL);
+ clear_ref_exclusion(&ref_excludes);
continue;
}
if (skip_prefix(arg, "--disambiguate=", &arg)) {
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 65f4a4c83c..934e514944 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -604,6 +604,7 @@ static int parse_reflog_param(const struct option *opt, const char *arg,
{
char *ep;
const char **base = (const char **)opt->value;
+ BUG_ON_OPT_NEG(unset);
if (!arg)
arg = "";
reflog = strtoul(arg, &ep, 10);
@@ -674,7 +675,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
{ OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
N_("show <n> most recent ref-log entries starting at "
"base"),
- PARSE_OPT_OPTARG,
+ PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
parse_reflog_param },
OPT_END()
};
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 2f13f1316f..ed888ffa48 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -151,6 +151,7 @@ static int hash_callback(const struct option *opt, const char *arg, int unset)
static int exclude_existing_callback(const struct option *opt, const char *arg,
int unset)
{
+ BUG_ON_OPT_NEG(unset);
exclude_arg = 1;
*(const char **)opt->value = arg;
return 0;
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 676175b9be..d38113a31a 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2141,6 +2141,45 @@ static int check_name(int argc, const char **argv, const char *prefix)
return 0;
}
+static int module_config(int argc, const char **argv, const char *prefix)
+{
+ enum {
+ CHECK_WRITEABLE = 1
+ } command = 0;
+
+ struct option module_config_options[] = {
+ OPT_CMDMODE(0, "check-writeable", &command,
+ N_("check if it is safe to write to the .gitmodules file"),
+ CHECK_WRITEABLE),
+ OPT_END()
+ };
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule--helper config name [value]"),
+ N_("git submodule--helper config --check-writeable"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_config_options,
+ git_submodule_helper_usage, PARSE_OPT_KEEP_ARGV0);
+
+ if (argc == 1 && command == CHECK_WRITEABLE)
+ return is_writing_gitmodules_ok() ? 0 : -1;
+
+ /* Equivalent to ACTION_GET in builtin/config.c */
+ if (argc == 2)
+ return print_config_from_gitmodules(the_repository, argv[1]);
+
+ /* Equivalent to ACTION_SET in builtin/config.c */
+ if (argc == 3) {
+ if (!is_writing_gitmodules_ok())
+ die(_("please make sure that the .gitmodules file is in the working tree"));
+
+ return config_set_in_gitmodules_file_gently(argv[1], argv[2]);
+ }
+
+ usage_with_options(git_submodule_helper_usage, module_config_options);
+}
+
#define SUPPORT_SUPER_PREFIX (1<<0)
struct cmd_struct {
@@ -2170,6 +2209,7 @@ static struct cmd_struct commands[] = {
{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
{"is-active", is_active, 0},
{"check-name", check_name, 0},
+ {"config", module_config, 0},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/builtin/tag.c b/builtin/tag.c
index f623632186..02f6bd1279 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -338,6 +338,8 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
{
struct msg_arg *msg = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
if (!arg)
return -1;
if (msg->buf.len)
@@ -390,8 +392,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_GROUP(N_("Tag creation options")),
OPT_BOOL('a', "annotate", &annotate,
N_("annotated tag, needs a message")),
- OPT_CALLBACK('m', "message", &msg, N_("message"),
- N_("tag message"), parse_msg_arg),
+ { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+ N_("tag message"), PARSE_OPT_NONEG, parse_msg_arg },
OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 07c10bcb7d..31e7cce301 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -782,7 +782,7 @@ struct refresh_params {
static int refresh(struct refresh_params *o, unsigned int flag)
{
setup_work_tree();
- read_cache_preload(NULL);
+ read_cache();
*o->has_errors |= refresh_cache(o->flags | flag);
return 0;
}
@@ -790,12 +790,16 @@ static int refresh(struct refresh_params *o, unsigned int flag)
static int refresh_callback(const struct option *opt,
const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
return refresh(opt->value, 0);
}
static int really_refresh_callback(const struct option *opt,
const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
return refresh(opt->value, REFRESH_REALLY);
}
@@ -803,6 +807,7 @@ static int chmod_callback(const struct option *opt,
const char *arg, int unset)
{
char *flip = opt->value;
+ BUG_ON_OPT_NEG(unset);
if ((arg[0] != '-' && arg[0] != '+') || arg[1] != 'x' || arg[2])
return error("option 'chmod' expects \"+x\" or \"-x\"");
*flip = arg[0];
@@ -812,6 +817,8 @@ static int chmod_callback(const struct option *opt,
static int resolve_undo_clear_callback(const struct option *opt,
const char *arg, int unset)
{
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
resolve_undo_clear();
return 0;
}
@@ -847,6 +854,8 @@ static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,
unsigned int mode;
const char *path;
+ BUG_ON_OPT_NEG(unset);
+
if (!parse_new_style_cacheinfo(ctx->argv[1], &mode, &oid, &path)) {
if (add_cacheinfo(mode, &oid, path, 0))
die("git update-index: --cacheinfo cannot add %s", path);
@@ -869,6 +878,8 @@ static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx,
{
int *nul_term_line = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
if (ctx->argc != 1)
return error("option '%s' must be the last argument", opt->long_name);
allow_add = allow_replace = allow_remove = 1;
@@ -881,6 +892,8 @@ static int stdin_callback(struct parse_opt_ctx_t *ctx,
{
int *read_from_stdin = opt->value;
+ BUG_ON_OPT_NEG(unset);
+
if (ctx->argc != 1)
return error("option '%s' must be the last argument", opt->long_name);
*read_from_stdin = 1;
@@ -888,11 +901,13 @@ static int stdin_callback(struct parse_opt_ctx_t *ctx,
}
static int unresolve_callback(struct parse_opt_ctx_t *ctx,
- const struct option *opt, int flags)
+ const struct option *opt, int unset)
{
int *has_errors = opt->value;
const char *prefix = startup_info->prefix;
+ BUG_ON_OPT_NEG(unset);
+
/* consume remaining arguments. */
*has_errors = do_unresolve(ctx->argc, ctx->argv,
prefix, prefix ? strlen(prefix) : 0);
@@ -905,11 +920,13 @@ static int unresolve_callback(struct parse_opt_ctx_t *ctx,
}
static int reupdate_callback(struct parse_opt_ctx_t *ctx,
- const struct option *opt, int flags)
+ const struct option *opt, int unset)
{
int *has_errors = opt->value;
const char *prefix = startup_info->prefix;
+ BUG_ON_OPT_NEG(unset);
+
/* consume remaining arguments. */
setup_work_tree();
*has_errors = do_reupdate(ctx->argc, ctx->argv,
diff --git a/builtin/worktree.c b/builtin/worktree.c
index c4abbde2b8..5e84026177 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -245,7 +245,7 @@ static void validate_worktree_add(const char *path, const struct add_opts *opts)
if (!wt)
goto done;
- locked = !!is_worktree_locked(wt);
+ locked = !!worktree_lock_reason(wt);
if ((!locked && opts->force) || (locked && opts->force > 1)) {
if (delete_git_dir(wt->id))
die(_("unable to re-add worktree '%s'"), path);
@@ -682,7 +682,7 @@ static int lock_worktree(int ac, const char **av, const char *prefix)
if (is_main_worktree(wt))
die(_("The main working tree cannot be locked or unlocked"));
- old_reason = is_worktree_locked(wt);
+ old_reason = worktree_lock_reason(wt);
if (old_reason) {
if (*old_reason)
die(_("'%s' is already locked, reason: %s"),
@@ -714,7 +714,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
die(_("'%s' is not a working tree"), av[0]);
if (is_main_worktree(wt))
die(_("The main working tree cannot be locked or unlocked"));
- if (!is_worktree_locked(wt))
+ if (!worktree_lock_reason(wt))
die(_("'%s' is not locked"), av[0]);
ret = unlink_or_warn(git_common_path("worktrees/%s/locked", wt->id));
free_worktrees(worktrees);
@@ -787,7 +787,7 @@ static int move_worktree(int ac, const char **av, const char *prefix)
validate_no_submodules(wt);
if (force < 2)
- reason = is_worktree_locked(wt);
+ reason = worktree_lock_reason(wt);
if (reason) {
if (*reason)
die(_("cannot move a locked working tree, lock reason: %s\nuse 'move -f -f' to override or unlock first"),
@@ -900,7 +900,7 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
if (is_main_worktree(wt))
die(_("'%s' is a main working tree"), av[0]);
if (force < 2)
- reason = is_worktree_locked(wt);
+ reason = worktree_lock_reason(wt);
if (reason) {
if (*reason)
die(_("cannot remove a locked working tree, lock reason: %s\nuse 'remove -f -f' to override or unlock first"),