summaryrefslogtreecommitdiff
path: root/revision.c
diff options
context:
space:
mode:
Diffstat (limited to 'revision.c')
-rw-r--r--revision.c97
1 files changed, 77 insertions, 20 deletions
diff --git a/revision.c b/revision.c
index 18f300d455..cf5e6c1ec9 100644
--- a/revision.c
+++ b/revision.c
@@ -671,12 +671,17 @@ static void trace2_bloom_filter_statistics_atexit(void)
static int forbid_bloom_filters(struct pathspec *spec)
{
- if (spec->has_wildcard)
- return 1;
- if (spec->magic & ~PATHSPEC_LITERAL)
+ unsigned int allowed_magic =
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ATTR;
+
+ if (spec->magic & ~allowed_magic)
return 1;
for (size_t nr = 0; nr < spec->nr; nr++)
- if (spec->items[nr].magic & ~PATHSPEC_LITERAL)
+ if (spec->items[nr].magic & ~allowed_magic)
return 1;
return 0;
@@ -691,23 +696,34 @@ static int convert_pathspec_to_bloom_keyvec(struct bloom_keyvec **out,
char *path_alloc = NULL;
const char *path;
size_t len;
- int res = 0;
+ int res = -1;
+ len = pi->nowildcard_len;
+ if (len != pi->len) {
+ /*
+ * for path like "dir/file*", nowildcard part would be
+ * "dir/file", but only "dir" should be used for the
+ * bloom filter.
+ */
+ while (len > 0 && pi->match[len - 1] != '/')
+ len--;
+ }
/* remove single trailing slash from path, if needed */
- if (pi->len > 0 && pi->match[pi->len - 1] == '/') {
- path_alloc = xmemdupz(pi->match, pi->len - 1);
+ if (len > 0 && pi->match[len - 1] == '/')
+ len--;
+
+ if (!len)
+ goto cleanup;
+
+ if (len != pi->len) {
+ path_alloc = xmemdupz(pi->match, len);
path = path_alloc;
} else
path = pi->match;
- len = strlen(path);
- if (!len) {
- res = -1;
- goto cleanup;
- }
-
*out = bloom_keyvec_new(path, len, settings);
+ res = 0;
cleanup:
free(path_alloc);
return res;
@@ -758,9 +774,6 @@ static int check_maybe_different_in_bloom_filter(struct rev_info *revs,
struct bloom_filter *filter;
int result = 0;
- if (!revs->repo->objects->commit_graph)
- return -1;
-
if (commit_graph_generation(commit) == GENERATION_NUMBER_INFINITY)
return -1;
@@ -1689,7 +1702,8 @@ static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)
}
}
-static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
+static int handle_one_reflog_ent(const char *refname UNUSED,
+ struct object_id *ooid, struct object_id *noid,
const char *email UNUSED,
timestamp_t timestamp UNUSED,
int tz UNUSED,
@@ -2304,6 +2318,24 @@ static timestamp_t parse_age(const char *arg)
return num;
}
+static void overwrite_argv(int *argc, const char **argv,
+ const char **value,
+ const struct setup_revision_opt *opt)
+{
+ /*
+ * Detect the case when we are overwriting ourselves. The assignment
+ * itself would be a noop either way, but this lets us avoid corner
+ * cases around the free() and NULL operations.
+ */
+ if (*value != argv[*argc]) {
+ if (opt && opt->free_removed_argv_elements)
+ free((char *)argv[*argc]);
+ argv[*argc] = *value;
+ *value = NULL;
+ }
+ (*argc)++;
+}
+
static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
int *unkc, const char **unkv,
const struct setup_revision_opt* opt)
@@ -2325,7 +2357,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
{
- unkv[(*unkc)++] = arg;
+ overwrite_argv(unkc, unkv, &argv[0], opt);
return 1;
}
@@ -2689,7 +2721,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
} else {
int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix);
if (!opts)
- unkv[(*unkc)++] = arg;
+ overwrite_argv(unkc, unkv, &argv[0], opt);
return opts;
}
@@ -3001,7 +3033,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
if (!strcmp(arg, "--stdin")) {
if (revs->disable_stdin) {
- argv[left++] = arg;
+ overwrite_argv(&left, argv, &argv[i], opt);
continue;
}
if (revs->read_from_stdin++)
@@ -3157,9 +3189,34 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
revs->show_notes_given = 1;
}
+ if (argv) {
+ if (opt && opt->free_removed_argv_elements)
+ free((char *)argv[left]);
+ argv[left] = NULL;
+ }
+
return left;
}
+void setup_revisions_from_strvec(struct strvec *argv, struct rev_info *revs,
+ struct setup_revision_opt *opt)
+{
+ struct setup_revision_opt fallback_opt;
+ int ret;
+
+ if (!opt) {
+ memset(&fallback_opt, 0, sizeof(fallback_opt));
+ opt = &fallback_opt;
+ }
+ opt->free_removed_argv_elements = 1;
+
+ ret = setup_revisions(argv->nr, argv->v, revs, opt);
+
+ for (size_t i = ret; i < argv->nr; i++)
+ free((char *)argv->v[i]);
+ argv->nr = ret;
+}
+
static void release_revisions_cmdline(struct rev_cmdline_info *cmdline)
{
unsigned int i;