Upstream adds 8 new translatable messages.

* 'master' of https://github.com/git/git: (93 commits)
  A bit more post -rc1
  ...

Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
This commit is contained in:
Jiang Xin
2026-04-09 13:48:26 +08:00
153 changed files with 3377 additions and 1467 deletions
+12
View File
@@ -668,6 +668,18 @@ For C programs:
unsigned other_field:1;
unsigned field_with_longer_name:1;
- When a function `F` accepts flags, those flags should be defined as `enum
F_flags`. Individual flag definitions should start with `F` and be in
all-uppercase letters. Flag values should be represented via bit shifts.
E.g.
enum frobnicate_flags {
FROBNICATE_FOO = (1 << 0),
FROBNICATE_BAR = (1 << 1),
};
int frobnicate(enum frobnicate_flags flags);
- Array names should be named in the singular form if the individual items are
subject of use. E.g.:
+63
View File
@@ -119,6 +119,11 @@ UI, Workflows & Features
* "git replay" (experimental) learns, in addition to "pick" and
"replay", a new operating mode "revert".
* git replay now supports replaying down to the root commit.
* Handling of signed commits and tags in fast-import has been made more
configurable.
Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
@@ -277,6 +282,40 @@ Performance, Internal Implementation, Development Support etc.
* In case homebrew breaks REG_ENHANCED again, leave a in-code comment
to suggest use of our replacement regex as a workaround.
* MinGW build updates.
* The way dash 0.5.13 handles non-ASCII contents in here-doc
is buggy and breaks our existing tests, which unfortunately
have been rewritten to avoid triggering the bug.
* Object name handling (disambiguation and abbreviation) has been
refactored to be backend-generic, moving logic into the respective
object database backends.
* pack-objects's --stdin-packs=follow mode learns to handle
excluded-but-open packs.
* A few code paths that spawned child processes for network
connection weren't wait(2)ing for their children and letting "init"
reap them instead; they have been tightened.
* Adjust the codebase for C23 that changes functions like strchr()
that discarded constness when they return a pointer into a const
string to preserve constness.
* A handful of inappropriate uses of the_repository have been
rewritten to use the right repository structure instance in the
read-cache.c codepath.
* Internals of "git fsck" have been refactored to not depend on the
global `the_repository` variable.
* Reduce dependency on `the_repository` in add-patch.c file.
* The way the "git log -L<range>:<file>" feature is bolted onto the
log/diff machinery is being reworked a bit to make the feature
compatible with more diff options, like -S/G.
Fixes since v2.53
-----------------
@@ -455,6 +494,27 @@ Fixes since v2.53
refspec is a single-object refspec, which has been corrected.
(merge 4e5dc601dd kj/refspec-parsing-outside-repository later to maint).
* Fix a regression in writing the commit-graph where commits with dates
exceeding 34 bits (beyond year 2514) could cause an underflow and
crash Git during the generation data overflow chunk writing.
* The value of a wrong pointer variable was referenced in an error
message that reported that it shouldn't be NULL.
(merge 753ecf4205 yc/path-walk-fix-error-reporting later to maint).
* The check in "receive-pack" to prevent a checked out branch from
getting updated via updateInstead mechanism has been corrected.
* "git backfill" is capable of auto-detecting a sparsely checked out
working tree, which was broken.
(merge 339eba65a7 th/backfill-auto-detect-sparseness-fix later to maint).
* add_files_to_cache() used diff_files() to detect only the paths that
are different between the index and the working tree and add them,
which does not need rename detection, which interfered with unnecessary
conflicts.
(merge c0ce43376b ng/add-files-to-cache-wo-rename later to maint).
* Other code cleanup, docfix, build fix, etc.
(merge d79fff4a11 jk/remote-tracking-ref-leakfix later to maint).
(merge 7a747f972d dd/t5403-modernise later to maint).
@@ -506,3 +566,6 @@ Fixes since v2.53
(merge 37182267a0 kh/doc-interpret-trailers-1 later to maint).
(merge f64c50e768 jc/rerere-modern-strbuf-handling later to maint).
(merge 699248d89e th/t8003-unhide-git-failures later to maint).
(merge d8e34f971b za/t2000-modernise later to maint).
(merge 849988bc74 th/t6101-unhide-git-failures later to maint).
(merge 0f0ce07625 sp/doc-gitignore-oowt later to maint).
+5 -4
View File
@@ -66,11 +66,10 @@ fast-import stream! This option is enabled automatically for
remote-helpers that use the `import` capability, as they are
already trusted to run their own code.
`--signed-tags=(verbatim|warn-verbatim|warn-strip|strip|abort)`::
`--signed-tags=<mode>`::
Specify how to handle signed tags. Behaves in the same way as
the `--signed-commits=<mode>` below, except that the
`strip-if-invalid` mode is not yet supported. Like for signed
commits, the default mode is `verbatim`.
the `--signed-commits=<mode>` below. Like for signed commits,
the default mode is `verbatim`.
`--signed-commits=<mode>`::
Specify how to handle signed commits. The following <mode>s
@@ -90,6 +89,8 @@ already trusted to run their own code.
commit signatures and replaces invalid signatures with newly created ones.
Valid signatures are left unchanged. If `<keyid>` is provided, that key is
used for signing; otherwise the configured default signing key is used.
* `abort-if-invalid` will make this program die when encountering a signed
commit that is unable to be verified.
Options for Frontends
~~~~~~~~~~~~~~~~~~~~~
+18 -7
View File
@@ -94,13 +94,24 @@ base-name::
included packs (those not beginning with `^`), excluding any
objects listed in the excluded packs (beginning with `^`).
+
When `mode` is "follow", objects from packs not listed on stdin receive
special treatment. Objects within unlisted packs will be included if
those objects are (1) reachable from the included packs, and (2) not
found in any excluded packs. This mode is useful, for example, to
resurrect once-unreachable objects found in cruft packs to generate
packs which are closed under reachability up to the boundary set by the
excluded packs.
When `mode` is "follow" packs may additionally be prefixed with `!`,
indicating that they are excluded but not necessarily closed under
reachability. In addition to objects in included packs, the resulting
pack may include additional objects based on the following:
+
--
* If any packs are marked with `!`, then objects reachable from such
packs or included ones via objects outside of excluded-closed packs
will be included. In this case, all `^` packs are treated as closed
under reachability.
* Otherwise (if there are no `!` packs), objects within unlisted packs
will be included if those objects are (1) reachable from the
included packs, and (2) not found in any excluded packs.
--
+
This mode is useful, for example, to resurrect once-unreachable
objects found in cruft packs to generate packs which are closed under
reachability up to the boundary set by the excluded packs.
+
Incompatible with `--revs`, or options that imply `--revs` (such as
`--all`), with the exception of `--unpacked`, which is compatible.
+33 -12
View File
@@ -9,7 +9,8 @@ git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos t
SYNOPSIS
--------
[verse]
(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch> | --revert <branch>) [--ref-action[=<mode>]] <revision-range>
(EXPERIMENTAL!) 'git replay' ([--contained] --onto=<newbase> | --advance=<branch> | --revert=<branch>)
[--ref=<ref>] [--ref-action=<mode>] <revision-range>
DESCRIPTION
-----------
@@ -26,7 +27,7 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
OPTIONS
-------
--onto <newbase>::
--onto=<newbase>::
Starting point at which to create the new commits. May be any
valid commit, and not just an existing branch name.
+
@@ -34,7 +35,7 @@ When `--onto` is specified, the branch(es) in the revision range will be
updated to point at the new commits, similar to the way `git rebase --update-refs`
updates multiple branches in the affected range.
--advance <branch>::
--advance=<branch>::
Starting point at which to create the new commits; must be a
branch name.
+
@@ -42,7 +43,7 @@ The history is replayed on top of the <branch> and <branch> is updated to
point at the tip of the resulting history. This is different from `--onto`,
which uses the target only as a starting point without updating it.
--revert <branch>::
--revert=<branch>::
Starting point at which to create the reverted commits; must be a
branch name.
+
@@ -65,6 +66,16 @@ incompatible with `--contained` (which is a modifier for `--onto` only).
Update all branches that point at commits in
<revision-range>. Requires `--onto`.
--ref=<ref>::
Override which reference is updated with the result of the replay.
The ref must be fully qualified.
When used with `--onto`, the `<revision-range>` should have a
single tip and only the specified reference is updated instead of
inferring refs from the revision range.
When used with `--advance` or `--revert`, the specified reference is
updated instead of the branch given to those options.
This option is incompatible with `--contained`.
--ref-action[=<mode>]::
Control how references are updated. The mode can be:
+
@@ -79,8 +90,8 @@ The default mode can be configured via the `replay.refAction` configuration vari
<revision-range>::
Range of commits to replay; see "Specifying Ranges" in
linkgit:git-rev-parse[1]. In `--advance <branch>` or
`--revert <branch>` mode, the range should have a single tip,
linkgit:git-rev-parse[1]. In `--advance=<branch>` or
`--revert=<branch>` mode, the range should have a single tip,
so that it's clear to which tip the advanced or reverted
<branch> should point. Any commits in the range whose changes
are already present in the branch the commits are being
@@ -127,7 +138,7 @@ EXAMPLES
To simply rebase `mybranch` onto `target`:
------------
$ git replay --onto target origin/main..mybranch
$ git replay --onto=target origin/main..mybranch
------------
The refs are updated atomically and no output is produced on success.
@@ -135,14 +146,14 @@ The refs are updated atomically and no output is produced on success.
To see what would be updated without actually updating:
------------
$ git replay --ref-action=print --onto target origin/main..mybranch
$ git replay --ref-action=print --onto=target origin/main..mybranch
update refs/heads/mybranch ${NEW_mybranch_HASH} ${OLD_mybranch_HASH}
------------
To cherry-pick the commits from mybranch onto target:
------------
$ git replay --advance target origin/main..mybranch
$ git replay --advance=target origin/main..mybranch
------------
Note that the first two examples replay the exact same commits and on
@@ -154,7 +165,7 @@ What if you have a stack of branches, one depending upon another, and
you'd really like to rebase the whole set?
------------
$ git replay --contained --onto origin/main origin/main..tipbranch
$ git replay --contained --onto=origin/main origin/main..tipbranch
------------
All three branches (`branch1`, `branch2`, and `tipbranch`) are updated
@@ -165,7 +176,7 @@ commits to replay using the syntax `A..B`; any range expression will
do:
------------
$ git replay --onto origin/main ^base branch1 branch2 branch3
$ git replay --onto=origin/main ^base branch1 branch2 branch3
------------
This will simultaneously rebase `branch1`, `branch2`, and `branch3`,
@@ -176,7 +187,7 @@ that they have in common, but that does not need to be the case.
To revert commits on a branch:
------------
$ git replay --revert main topic~2..topic
$ git replay --revert=main topic~2..topic
------------
This reverts the last two commits from `topic`, creating revert commits on
@@ -188,6 +199,16 @@ NOTE: For reverting an entire merge request as a single commit (rather than
commit-by-commit), consider using `git merge-tree --merge-base $TIP HEAD $BASE`
which can avoid unnecessary merge conflicts.
To replay onto a specific commit while updating a different reference:
------------
$ git replay --onto=112233 --ref=refs/heads/mybranch aabbcc..ddeeff
------------
This replays the range `aabbcc..ddeeff` onto commit `112233` and updates
`refs/heads/mybranch` to point at the result. This can be useful when you want
to use bare commit IDs instead of branch names.
GIT
---
Part of the linkgit:git[1] suite
+4 -6
View File
@@ -14,10 +14,10 @@ git stash drop [-q | --quiet] [<stash>]
git stash pop [--index] [-q | --quiet] [<stash>]
git stash apply [--index] [-q | --quiet] [<stash>]
git stash branch <branchname> [<stash>]
git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
git stash [push] [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
[-u | --include-untracked] [-a | --all] [(-m | --message) <message>]
[--pathspec-from-file=<file> [--pathspec-file-nul]]
[--] [<pathspec>...]]
[--] [<pathspec>...]
git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
[-u | --include-untracked] [-a | --all] [<message>]
git stash clear
@@ -60,10 +60,8 @@ COMMANDS
the description along with the stashed state.
+
For quickly making a snapshot, you can omit "push". In this mode,
non-option arguments are not allowed to prevent a misspelled
subcommand from making an unwanted stash entry. The two exceptions to this
are `stash -p` which acts as alias for `stash push -p` and pathspec elements,
which are allowed after a double hyphen `--` for disambiguation.
pathspec elements are only allowed after a double hyphen `--`
to prevent a misspelled subcommand from making an unwanted stash entry.
`save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-u | --include-untracked] [-a | --all] [-q | --quiet] [<message>]`::
+5
View File
@@ -96,6 +96,11 @@ PATTERN FORMAT
particular `.gitignore` file itself. Otherwise the pattern may also
match at any level below the `.gitignore` level.
- Patterns read from exclude sources that are outside the working tree,
such as $GIT_DIR/info/exclude and core.excludesFile, are treated as if
they are specified at the root of the working tree, i.e. a leading "/"
in such patterns anchors the match at the root of the repository.
- If there is a separator at the end of the pattern then the pattern
will only match directories, otherwise the pattern can match both
files and directories.
+4
View File
@@ -12,4 +12,8 @@
(namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`,
`--name-only`, `--name-status`, `--check`) are not currently implemented.
+
Patch formatting options such as `--word-diff`, `--color-moved`,
`--no-prefix`, and whitespace options (`-w`, `-b`) are supported,
as are pickaxe options (`-S`, `-G`).
+
include::line-range-format.adoc[]
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/sh
DEF_VER=v2.54.0-rc0
DEF_VER=v2.54.0-rc1
LF='
'
+4 -4
View File
@@ -558,8 +558,8 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
strvec_push(&args,
/* could be on an unborn branch */
!strcmp("HEAD", s->revision) &&
repo_get_oid(the_repository, "HEAD", &oid) ?
empty_tree_oid_hex(the_repository->hash_algo) : s->revision);
repo_get_oid(s->r, "HEAD", &oid) ?
empty_tree_oid_hex(s->r->hash_algo) : s->revision);
}
color_arg_index = args.nr;
/* Use `--no-color` explicitly, just in case `diff.color = always`. */
@@ -1271,7 +1271,7 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
"removed, then the edit is\n"
"aborted and the hunk is left unchanged.\n"));
if (strbuf_edit_interactively(the_repository, &s->buf,
if (strbuf_edit_interactively(s->r, &s->buf,
"addp-hunk-edit.diff", NULL) < 0)
return -1;
@@ -1679,7 +1679,7 @@ static size_t patch_update_file(struct add_p_state *s,
if (file_diff->hunk_nr) {
if (rendered_hunk_index != hunk_index) {
if (use_pager) {
setup_pager(the_repository);
setup_pager(s->r);
sigchain_push(SIGPIPE, SIG_IGN);
}
render_hunk(s, hunk, 0, colored, &s->buf);
+10 -2
View File
@@ -1840,8 +1840,16 @@ static int parse_fragment(struct apply_state *state,
trailing++;
check_old_for_crlf(patch, line, len);
if (!state->apply_in_reverse &&
state->ws_error_action == correct_ws_error)
check_whitespace(state, line, len, patch->ws_rule);
state->ws_error_action == correct_ws_error) {
const char *test_line = line;
int test_len = len;
if (*line == '\n') {
test_line = " \n";
test_len = 2;
}
check_whitespace(state, test_line, test_len,
patch->ws_rule);
}
break;
case '-':
if (!state->apply_in_reverse)
+1 -1
View File
@@ -119,7 +119,7 @@ int cmd_backfill(int argc, const char **argv, const char *prefix, struct reposit
.repo = repo,
.current_batch = OID_ARRAY_INIT,
.min_batch_size = 50000,
.sparse = 0,
.sparse = -1,
.revs = REV_INFO_INIT,
};
struct option options[] = {
+6 -3
View File
@@ -161,7 +161,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
case 'e':
ret = !odb_has_object(the_repository->objects, &oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR);
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR);
goto cleanup;
case 'w':
@@ -848,6 +848,9 @@ static void batch_each_object(struct batch_options *opt,
.callback = callback,
.payload = _payload,
};
struct odb_for_each_object_options opts = {
.flags = flags,
};
struct bitmap_index *bitmap = NULL;
struct odb_source *source;
@@ -860,7 +863,7 @@ static void batch_each_object(struct batch_options *opt,
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next) {
int ret = odb_source_loose_for_each_object(source, NULL, batch_one_object_oi,
&payload, flags);
&payload, &opts);
if (ret)
break;
}
@@ -884,7 +887,7 @@ static void batch_each_object(struct batch_options *opt,
for (source = the_repository->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
int ret = packfile_store_for_each_object(files->packed, &oi,
batch_one_object_oi, &payload, flags);
batch_one_object_oi, &payload, &opts);
if (ret)
break;
}
+4 -3
View File
@@ -838,6 +838,7 @@ static int get_urlmatch(const struct config_location_options *opts,
const char *var, const char *url)
{
int ret;
char *section;
char *section_tail;
struct config_display_options display_opts = *_display_opts;
struct string_list_item *item;
@@ -851,8 +852,8 @@ static int get_urlmatch(const struct config_location_options *opts,
if (!url_normalize(url, &config.url))
die("%s", config.url.err);
config.section = xstrdup_tolower(var);
section_tail = strchr(config.section, '.');
config.section = section = xstrdup_tolower(var);
section_tail = strchr(section, '.');
if (section_tail) {
*section_tail = '\0';
config.key = section_tail + 1;
@@ -886,7 +887,7 @@ static int get_urlmatch(const struct config_location_options *opts,
string_list_clear(&values, 1);
free(config.url.url);
free((void *)config.section);
free(section);
return ret;
}
+2 -13
View File
@@ -64,7 +64,8 @@ static int parse_opt_sign_mode(const struct option *opt,
if (unset)
return 0;
if (parse_sign_mode(arg, val, NULL))
if (parse_sign_mode(arg, val, NULL) || (*val == SIGN_STRIP_IF_INVALID) ||
(*val == SIGN_SIGN_IF_INVALID) || (*val == SIGN_ABORT_IF_INVALID))
return error(_("unknown %s mode: %s"), opt->long_name, arg);
return 0;
@@ -822,12 +823,6 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
die(_("encountered signed commit %s; use "
"--signed-commits=<mode> to handle it"),
oid_to_hex(&commit->object.oid));
case SIGN_STRIP_IF_INVALID:
die(_("'strip-if-invalid' is not a valid mode for "
"git fast-export with --signed-commits=<mode>"));
case SIGN_SIGN_IF_INVALID:
die(_("'sign-if-invalid' is not a valid mode for "
"git fast-export with --signed-commits=<mode>"));
default:
BUG("invalid signed_commit_mode value %d", signed_commit_mode);
}
@@ -970,12 +965,6 @@ static void handle_tag(const char *name, struct tag *tag)
die(_("encountered signed tag %s; use "
"--signed-tags=<mode> to handle it"),
oid_to_hex(&tag->object.oid));
case SIGN_STRIP_IF_INVALID:
die(_("'strip-if-invalid' is not a valid mode for "
"git fast-export with --signed-tags=<mode>"));
case SIGN_SIGN_IF_INVALID:
die(_("'sign-if-invalid' is not a valid mode for "
"git fast-export with --signed-tags=<mode>"));
default:
BUG("invalid signed_commit_mode value %d", signed_commit_mode);
}
+60 -11
View File
@@ -191,6 +191,7 @@ static const char *global_prefix;
static enum sign_mode signed_tag_mode = SIGN_VERBATIM;
static enum sign_mode signed_commit_mode = SIGN_VERBATIM;
static const char *signed_commit_keyid;
static const char *signed_tag_keyid;
/* Memory pools */
static struct mem_pool fi_mem_pool = {
@@ -2892,6 +2893,9 @@ static void handle_signature_if_invalid(struct strbuf *new_data,
ret = verify_commit_buffer(tmp_buf.buf, tmp_buf.len, &signature_check);
if (ret) {
if (mode == SIGN_ABORT_IF_INVALID)
die(_("aborting due to invalid signature"));
warn_invalid_signature(&signature_check, msg->buf, mode);
if (mode == SIGN_SIGN_IF_INVALID) {
@@ -2983,6 +2987,7 @@ static void parse_new_commit(const char *arg)
case SIGN_VERBATIM:
case SIGN_STRIP_IF_INVALID:
case SIGN_SIGN_IF_INVALID:
case SIGN_ABORT_IF_INVALID:
import_one_signature(&sig_sha1, &sig_sha256, v);
break;
@@ -3068,7 +3073,8 @@ static void parse_new_commit(const char *arg)
encoding);
if ((signed_commit_mode == SIGN_STRIP_IF_INVALID ||
signed_commit_mode == SIGN_SIGN_IF_INVALID) &&
signed_commit_mode == SIGN_SIGN_IF_INVALID ||
signed_commit_mode == SIGN_ABORT_IF_INVALID) &&
(sig_sha1.hash_algo || sig_sha256.hash_algo))
handle_signature_if_invalid(&new_data, &sig_sha1, &sig_sha256,
&msg, signed_commit_mode);
@@ -3084,7 +3090,50 @@ static void parse_new_commit(const char *arg)
b->last_commit = object_count_by_type[OBJ_COMMIT];
}
static void handle_tag_signature(struct strbuf *msg, const char *name)
static void handle_tag_signature_if_invalid(struct strbuf *buf,
struct strbuf *msg,
size_t sig_offset)
{
struct strbuf signature = STRBUF_INIT;
struct strbuf payload = STRBUF_INIT;
struct signature_check sigc = { 0 };
strbuf_addbuf(&payload, buf);
strbuf_addch(&payload, '\n');
strbuf_add(&payload, msg->buf, sig_offset);
strbuf_add(&signature, msg->buf + sig_offset, msg->len - sig_offset);
sigc.payload_type = SIGNATURE_PAYLOAD_TAG;
sigc.payload = strbuf_detach(&payload, &sigc.payload_len);
if (!check_signature(&sigc, signature.buf, signature.len))
goto out;
if (signed_tag_mode == SIGN_ABORT_IF_INVALID)
die(_("aborting due to invalid signature"));
strbuf_setlen(msg, sig_offset);
if (signed_tag_mode == SIGN_SIGN_IF_INVALID) {
strbuf_attach(&payload, sigc.payload, sigc.payload_len,
sigc.payload_len + 1);
sigc.payload = NULL;
strbuf_reset(&signature);
if (sign_buffer(&payload, &signature, signed_tag_keyid,
SIGN_BUFFER_USE_DEFAULT_KEY))
die(_("failed to sign tag object"));
strbuf_addbuf(msg, &signature);
}
out:
signature_check_clear(&sigc);
strbuf_release(&signature);
strbuf_release(&payload);
}
static void handle_tag_signature(struct strbuf *buf, struct strbuf *msg, const char *name)
{
size_t sig_offset = parse_signed_buffer(msg->buf, msg->len);
@@ -3110,17 +3159,16 @@ static void handle_tag_signature(struct strbuf *msg, const char *name)
/* Truncate the buffer to remove the signature */
strbuf_setlen(msg, sig_offset);
break;
case SIGN_ABORT_IF_INVALID:
case SIGN_SIGN_IF_INVALID:
case SIGN_STRIP_IF_INVALID:
handle_tag_signature_if_invalid(buf, msg, sig_offset);
break;
/* Third, aborting modes */
case SIGN_ABORT:
die(_("encountered signed tag; use "
"--signed-tags=<mode> to handle it"));
case SIGN_STRIP_IF_INVALID:
die(_("'strip-if-invalid' is not a valid mode for "
"git fast-import with --signed-tags=<mode>"));
case SIGN_SIGN_IF_INVALID:
die(_("'sign-if-invalid' is not a valid mode for "
"git fast-import with --signed-tags=<mode>"));
default:
BUG("invalid signed_tag_mode value %d from tag '%s'",
signed_tag_mode, name);
@@ -3190,8 +3238,6 @@ static void parse_new_tag(const char *arg)
/* tag payload/message */
parse_data(&msg, 0, NULL);
handle_tag_signature(&msg, t->name);
/* build the tag object */
strbuf_reset(&new_data);
@@ -3203,6 +3249,9 @@ static void parse_new_tag(const char *arg)
if (tagger)
strbuf_addf(&new_data,
"tagger %s\n", tagger);
handle_tag_signature(&new_data, &msg, t->name);
strbuf_addch(&new_data, '\n');
strbuf_addbuf(&new_data, &msg);
free(tagger);
@@ -3713,7 +3762,7 @@ static int parse_one_option(const char *option)
if (parse_sign_mode(option, &signed_commit_mode, &signed_commit_keyid))
usagef(_("unknown --signed-commits mode '%s'"), option);
} else if (skip_prefix(option, "signed-tags=", &option)) {
if (parse_sign_mode(option, &signed_tag_mode, NULL))
if (parse_sign_mode(option, &signed_tag_mode, &signed_tag_keyid))
usagef(_("unknown --signed-tags mode '%s'"), option);
} else if (!strcmp(option, "quiet")) {
show_stats = 0;
+2 -2
View File
@@ -946,7 +946,7 @@ static int update_local_ref(struct ref *ref,
int fast_forward = 0;
if (!odb_has_object(the_repository->objects, &ref->new_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
die(_("object %s not found"), oid_to_hex(&ref->new_oid));
if (oideq(&ref->old_oid, &ref->new_oid)) {
@@ -1396,7 +1396,7 @@ static int check_exist_and_connected(struct ref *ref_map)
*/
for (r = rm; r; r = r->next) {
if (!odb_has_object(the_repository->objects, &r->old_oid,
HAS_OBJECT_RECHECK_PACKED))
ODB_HAS_OBJECT_RECHECK_PACKED))
return -1;
}
+150 -125
View File
@@ -1,4 +1,3 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
#include "gettext.h"
#include "hex.h"
@@ -42,8 +41,8 @@ static int check_full = 1;
static int connectivity_only;
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 fsck_options fsck_walk_options;
static struct fsck_options fsck_obj_options;
static int errors_found;
static int write_lost_and_found;
static int verbose;
@@ -66,14 +65,14 @@ static const char *describe_object(const struct object_id *oid)
return fsck_describe_object(&fsck_walk_options, oid);
}
static const char *printable_type(const struct object_id *oid,
static const char *printable_type(struct repository *repo,
const struct object_id *oid,
enum object_type type)
{
const char *ret;
if (type == OBJ_NONE)
type = odb_read_object_info(the_repository->objects,
oid, NULL);
type = odb_read_object_info(repo->objects, oid, NULL);
ret = type_name(type);
if (!ret)
@@ -82,17 +81,17 @@ static const char *printable_type(const struct object_id *oid,
return ret;
}
static int objerror(struct object *obj, const char *err)
static int objerror(struct repository *repo, struct object *obj, const char *err)
{
errors_found |= ERROR_OBJECT;
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("error in %s %s: %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid), err);
return -1;
}
static int fsck_objects_error_func(struct fsck_options *o UNUSED,
static int fsck_objects_error_func(struct fsck_options *o,
void *fsck_report,
enum fsck_msg_type msg_type,
enum fsck_msg_id msg_id UNUSED,
@@ -106,13 +105,13 @@ static int fsck_objects_error_func(struct fsck_options *o UNUSED,
case FSCK_WARN:
/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("warning in %s %s: %s"),
printable_type(oid, object_type),
printable_type(o->repo, oid, object_type),
describe_object(oid), message);
return 0;
case FSCK_ERROR:
/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
fprintf_ln(stderr, _("error in %s %s: %s"),
printable_type(oid, object_type),
printable_type(o->repo, oid, object_type),
describe_object(oid), message);
return 1;
default:
@@ -124,7 +123,7 @@ static int fsck_objects_error_func(struct fsck_options *o UNUSED,
static struct object_array pending;
static int mark_object(struct object *obj, enum object_type type,
void *data, struct fsck_options *options UNUSED)
void *data, struct fsck_options *options)
{
struct object *parent = data;
@@ -136,7 +135,7 @@ static int mark_object(struct object *obj, enum object_type type,
if (!obj) {
/* ... these references to parent->fld are safe here */
printf_ln(_("broken link from %7s %s"),
printable_type(&parent->oid, parent->type),
printable_type(options->repo, &parent->oid, parent->type),
describe_object(&parent->oid));
printf_ln(_("broken link from %7s %s"),
(type == OBJ_ANY ? _("unknown") : type_name(type)),
@@ -147,13 +146,13 @@ static int mark_object(struct object *obj, enum object_type type,
if (type != OBJ_ANY && obj->type != type)
/* ... and the reference to parent is safe here */
objerror(parent, _("wrong object type in link"));
objerror(options->repo, parent, _("wrong object type in link"));
if (obj->flags & REACHABLE)
return 0;
obj->flags |= REACHABLE;
if (is_promisor_object(the_repository, &obj->oid))
if (is_promisor_object(options->repo, &obj->oid))
/*
* Further recursion does not need to be performed on this
* object since it is a promisor object (so it does not need to
@@ -162,13 +161,13 @@ static int mark_object(struct object *obj, enum object_type type,
return 0;
if (!(obj->flags & HAS_OBJ)) {
if (parent && !odb_has_object(the_repository->objects, &obj->oid,
HAS_OBJECT_RECHECK_PACKED)) {
if (parent && !odb_has_object(options->repo->objects, &obj->oid,
ODB_HAS_OBJECT_RECHECK_PACKED)) {
printf_ln(_("broken link from %7s %s\n"
" to %7s %s"),
printable_type(&parent->oid, parent->type),
printable_type(options->repo, &parent->oid, parent->type),
describe_object(&parent->oid),
printable_type(&obj->oid, obj->type),
printable_type(options->repo, &obj->oid, obj->type),
describe_object(&obj->oid));
errors_found |= ERROR_REACHABLE;
}
@@ -181,7 +180,7 @@ static int mark_object(struct object *obj, enum object_type type,
static void mark_object_reachable(struct object *obj)
{
mark_object(obj, OBJ_ANY, NULL, NULL);
mark_object(obj, OBJ_ANY, NULL, &fsck_walk_options);
}
static int traverse_one_object(struct object *obj)
@@ -195,13 +194,13 @@ static int traverse_one_object(struct object *obj)
return result;
}
static int traverse_reachable(void)
static int traverse_reachable(struct repository *repo)
{
struct progress *progress = NULL;
unsigned int nr = 0;
int result = 0;
if (show_progress)
progress = start_delayed_progress(the_repository,
progress = start_delayed_progress(repo,
_("Checking connectivity"), 0);
while (pending.nr) {
result |= traverse_one_object(object_array_pop(&pending));
@@ -222,10 +221,11 @@ static int mark_used(struct object *obj, enum object_type type UNUSED,
static int mark_unreachable_referents(const struct object_id *oid,
struct object_info *oi UNUSED,
void *data UNUSED)
void *data)
{
struct fsck_options options = FSCK_OPTIONS_DEFAULT;
struct object *obj = lookup_object(the_repository, oid);
struct repository *repo = data;
struct fsck_options options;
struct object *obj = lookup_object(data, oid);
if (!obj || !(obj->flags & HAS_OBJ))
return 0; /* not part of our original set */
@@ -237,12 +237,13 @@ static int mark_unreachable_referents(const struct object_id *oid,
* (and we want to avoid parsing blobs).
*/
if (obj->type == OBJ_NONE) {
enum object_type type = odb_read_object_info(the_repository->objects,
enum object_type type = odb_read_object_info(repo->objects,
&obj->oid, NULL);
if (type > 0)
object_as_type(obj, type, 0);
}
fsck_options_init(&options, repo, FSCK_OPTIONS_DEFAULT);
options.walk = mark_used;
fsck_walk(obj, NULL, &options);
if (obj->type == OBJ_TREE)
@@ -254,7 +255,7 @@ static int mark_unreachable_referents(const struct object_id *oid,
/*
* Check a single reachable object
*/
static void check_reachable_object(struct object *obj)
static void check_reachable_object(struct repository *repo, struct object *obj)
{
/*
* We obviously want the object to be parsed,
@@ -262,12 +263,12 @@ static void check_reachable_object(struct object *obj)
* do a full fsck
*/
if (!(obj->flags & HAS_OBJ)) {
if (is_promisor_object(the_repository, &obj->oid))
if (is_promisor_object(repo, &obj->oid))
return;
if (has_object_pack(the_repository, &obj->oid))
if (has_object_pack(repo, &obj->oid))
return; /* it is in pack - forget about it */
printf_ln(_("missing %s %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid));
errors_found |= ERROR_REACHABLE;
return;
@@ -277,7 +278,7 @@ static void check_reachable_object(struct object *obj)
/*
* Check a single unreachable object
*/
static void check_unreachable_object(struct object *obj)
static void check_unreachable_object(struct repository *repo, struct object *obj)
{
/*
* Missing unreachable object? Ignore it. It's not like
@@ -294,7 +295,7 @@ static void check_unreachable_object(struct object *obj)
*/
if (show_unreachable) {
printf_ln(_("unreachable %s %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid));
return;
}
@@ -314,22 +315,22 @@ static void check_unreachable_object(struct object *obj)
if (!(obj->flags & USED)) {
if (show_dangling)
printf_ln(_("dangling %s %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid));
if (write_lost_and_found) {
char *filename = repo_git_path(the_repository, "lost-found/%s/%s",
char *filename = repo_git_path(repo, "lost-found/%s/%s",
obj->type == OBJ_COMMIT ? "commit" : "other",
describe_object(&obj->oid));
FILE *f;
if (safe_create_leading_directories_const(the_repository, filename)) {
if (safe_create_leading_directories_const(repo, filename)) {
error(_("could not create lost-found"));
free(filename);
return;
}
f = xfopen(filename, "w");
if (obj->type == OBJ_BLOB) {
if (odb_stream_blob_to_fd(the_repository->objects, fileno(f),
if (odb_stream_blob_to_fd(repo->objects, fileno(f),
&obj->oid, NULL, 1))
die_errno(_("could not write '%s'"), filename);
} else
@@ -349,23 +350,23 @@ static void check_unreachable_object(struct object *obj)
*/
}
static void check_object(struct object *obj)
static void check_object(struct repository *repo, struct object *obj)
{
if (verbose)
fprintf_ln(stderr, _("Checking %s"), describe_object(&obj->oid));
if (obj->flags & REACHABLE)
check_reachable_object(obj);
check_reachable_object(repo, obj);
else
check_unreachable_object(obj);
check_unreachable_object(repo, obj);
}
static void check_connectivity(void)
static void check_connectivity(struct repository *repo)
{
int i, max;
/* Traverse the pending reachable objects */
traverse_reachable();
traverse_reachable(repo);
/*
* With --connectivity-only, we won't have actually opened and marked
@@ -383,24 +384,25 @@ static void check_connectivity(void)
* and ignore any that weren't present in our earlier
* traversal.
*/
odb_for_each_object(the_repository->objects, NULL,
mark_unreachable_referents, NULL, 0);
odb_for_each_object(repo->objects, NULL,
mark_unreachable_referents, repo, 0);
}
/* Look up all the requirements, warn about missing objects.. */
max = get_max_object_index(the_repository);
max = get_max_object_index(repo);
if (verbose)
fprintf_ln(stderr, _("Checking connectivity (%d objects)"), max);
for (i = 0; i < max; i++) {
struct object *obj = get_indexed_object(the_repository, i);
struct object *obj = get_indexed_object(repo, i);
if (obj)
check_object(obj);
check_object(repo, obj);
}
}
static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
static int fsck_obj(struct repository *repo,
struct object *obj, void *buffer, unsigned long size)
{
int err;
@@ -410,11 +412,11 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (verbose)
fprintf_ln(stderr, _("Checking %s %s"),
printable_type(&obj->oid, obj->type),
printable_type(repo, &obj->oid, obj->type),
describe_object(&obj->oid));
if (fsck_walk(obj, NULL, &fsck_obj_options))
objerror(obj, _("broken links"));
objerror(repo, obj, _("broken links"));
err = fsck_object(obj, buffer, size, &fsck_obj_options);
if (err)
goto out;
@@ -432,7 +434,7 @@ static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
if (show_tags && tag->tagged) {
printf_ln(_("tagged %s %s (%s) in %s"),
printable_type(&tag->tagged->oid, tag->tagged->type),
printable_type(repo, &tag->tagged->oid, tag->tagged->type),
describe_object(&tag->tagged->oid),
tag->tag,
describe_object(&tag->object.oid));
@@ -446,15 +448,16 @@ out:
}
static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
unsigned long size, void *buffer, int *eaten)
unsigned long size, void *buffer, int *eaten, void *cb_data)
{
struct repository *repo = cb_data;
struct object *obj;
/*
* Note, buffer may be NULL if type is OBJ_BLOB. See
* verify_packfile(), data_valid variable for details.
*/
struct object *obj;
obj = parse_object_buffer(the_repository, oid, type, size, buffer,
eaten);
obj = parse_object_buffer(repo, oid, type, size, buffer, eaten);
if (!obj) {
errors_found |= ERROR_OBJECT;
return error(_("%s: object corrupt or missing"),
@@ -462,18 +465,19 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
}
obj->flags &= ~(REACHABLE | SEEN);
obj->flags |= HAS_OBJ;
return fsck_obj(obj, buffer, size);
return fsck_obj(repo, obj, buffer, size);
}
static int default_refs;
static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
timestamp_t timestamp)
static void fsck_handle_reflog_oid(struct repository *repo,
const char *refname, struct object_id *oid,
timestamp_t timestamp)
{
struct object *obj;
if (!is_null_oid(oid)) {
obj = lookup_object(the_repository, oid);
obj = lookup_object(repo, oid);
if (obj && (obj->flags & HAS_OBJ)) {
if (timestamp)
fsck_put_object_name(&fsck_walk_options, oid,
@@ -481,7 +485,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
refname, timestamp);
obj->flags |= USED;
mark_object_reachable(obj);
} else if (!is_promisor_object(the_repository, oid)) {
} else if (!is_promisor_object(repo, oid)) {
error(_("%s: invalid reflog entry %s"),
refname, oid_to_hex(oid));
errors_found |= ERROR_REACHABLE;
@@ -493,8 +497,10 @@ static int fsck_handle_reflog_ent(const char *refname,
struct object_id *ooid, struct object_id *noid,
const char *email UNUSED,
timestamp_t timestamp, int tz UNUSED,
const char *message UNUSED, void *cb_data UNUSED)
const char *message UNUSED, void *cb_data)
{
struct repository *repo = cb_data;
if (now && timestamp > now)
return 0;
@@ -502,19 +508,20 @@ static int fsck_handle_reflog_ent(const char *refname,
fprintf_ln(stderr, _("Checking reflog %s->%s"),
oid_to_hex(ooid), oid_to_hex(noid));
fsck_handle_reflog_oid(refname, ooid, 0);
fsck_handle_reflog_oid(refname, noid, timestamp);
fsck_handle_reflog_oid(repo, refname, ooid, 0);
fsck_handle_reflog_oid(repo, refname, noid, timestamp);
return 0;
}
static int fsck_handle_reflog(const char *logname, void *cb_data)
{
struct strbuf refname = STRBUF_INIT;
struct worktree *wt = cb_data;
strbuf_worktree_ref(cb_data, &refname, logname);
refs_for_each_reflog_ent(get_main_ref_store(the_repository),
strbuf_worktree_ref(wt, &refname, logname);
refs_for_each_reflog_ent(get_main_ref_store(wt->repo),
refname.buf, fsck_handle_reflog_ent,
NULL);
wt->repo);
strbuf_release(&refname);
return 0;
}
@@ -532,14 +539,20 @@ struct snapshot {
/* TODO: Consider also snapshotting the index of each worktree. */
};
struct snapshot_ref_data {
struct repository *repo;
struct snapshot *snap;
};
static int snapshot_ref(const struct reference *ref, void *cb_data)
{
struct snapshot *snap = cb_data;
struct snapshot_ref_data *data = cb_data;
struct snapshot *snap = data->snap;
struct object *obj;
obj = parse_object(the_repository, ref->oid);
obj = parse_object(data->repo, ref->oid);
if (!obj) {
if (is_promisor_object(the_repository, ref->oid)) {
if (is_promisor_object(data->repo, ref->oid)) {
/*
* Increment default_refs anyway, because this is a
* valid ref.
@@ -567,11 +580,12 @@ static int snapshot_ref(const struct reference *ref, void *cb_data)
return 0;
}
static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)
static int fsck_handle_ref(const struct reference *ref, void *cb_data)
{
struct repository *repo = cb_data;
struct object *obj;
obj = parse_object(the_repository, ref->oid);
obj = parse_object(repo, ref->oid);
obj->flags |= USED;
fsck_put_object_name(&fsck_walk_options,
ref->oid, "%s", ref->name);
@@ -580,11 +594,16 @@ static int fsck_handle_ref(const struct reference *ref, void *cb_data UNUSED)
return 0;
}
static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
static void snapshot_refs(struct repository *repo,
struct snapshot *snap, int argc, const char **argv)
{
struct refs_for_each_ref_options opts = {
.flags = REFS_FOR_EACH_INCLUDE_BROKEN,
};
struct snapshot_ref_data data = {
.repo = repo,
.snap = snap,
};
struct worktree **worktrees, **p;
const char *head_points_at;
struct object_id head_oid;
@@ -592,13 +611,13 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
for (int i = 0; i < argc; i++) {
const char *arg = argv[i];
struct object_id oid;
if (!repo_get_oid(the_repository, arg, &oid)) {
if (!repo_get_oid(repo, arg, &oid)) {
struct reference ref = {
.name = arg,
.oid = &oid,
};
snapshot_ref(&ref, snap);
snapshot_ref(&ref, &data);
continue;
}
error(_("invalid parameter: expected sha1, got '%s'"), arg);
@@ -610,8 +629,8 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
return;
}
refs_for_each_ref_ext(get_main_ref_store(the_repository),
snapshot_ref, snap, &opts);
refs_for_each_ref_ext(get_main_ref_store(repo),
snapshot_ref, &data, &opts);
worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
@@ -620,7 +639,7 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
strbuf_worktree_ref(wt, &refname, "HEAD");
head_points_at = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
head_points_at = refs_resolve_ref_unsafe(get_main_ref_store(repo),
refname.buf, 0, &head_oid, NULL);
if (head_points_at && !is_null_oid(&head_oid)) {
@@ -629,7 +648,7 @@ static void snapshot_refs(struct snapshot *snap, int argc, const char **argv)
.oid = &head_oid,
};
snapshot_ref(&ref, snap);
snapshot_ref(&ref, &data);
}
strbuf_release(&refname);
@@ -653,7 +672,7 @@ static void free_snapshot_refs(struct snapshot *snap)
free(snap->ref);
}
static void process_refs(struct snapshot *snap)
static void process_refs(struct repository *repo, struct snapshot *snap)
{
struct worktree **worktrees, **p;
@@ -662,7 +681,7 @@ static void process_refs(struct snapshot *snap)
.name = snap->ref[i].refname,
.oid = &snap->ref[i].oid,
};
fsck_handle_ref(&ref, NULL);
fsck_handle_ref(&ref, repo);
}
if (include_reflogs) {
@@ -694,27 +713,28 @@ static void process_refs(struct snapshot *snap)
}
}
struct for_each_loose_cb
{
struct for_each_loose_cb {
struct repository *repo;
struct progress *progress;
};
static int fsck_loose(const struct object_id *oid, const char *path,
void *data UNUSED)
void *cb_data)
{
struct for_each_loose_cb *data = cb_data;
struct object *obj;
enum object_type type = OBJ_NONE;
unsigned long size;
void *contents = NULL;
int eaten;
struct object_info oi = OBJECT_INFO_INIT;
struct object_id real_oid = *null_oid(the_hash_algo);
struct object_id real_oid = *null_oid(data->repo->hash_algo);
int err = 0;
oi.sizep = &size;
oi.typep = &type;
if (read_loose_object(the_repository, path, oid, &real_oid, &contents, &oi) < 0) {
if (read_loose_object(data->repo, path, oid, &real_oid, &contents, &oi) < 0) {
if (contents && !oideq(&real_oid, oid))
err = error(_("%s: hash-path mismatch, found at: %s"),
oid_to_hex(&real_oid), path);
@@ -731,7 +751,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,
if (!contents && type != OBJ_BLOB)
BUG("read_loose_object streamed a non-blob");
obj = parse_object_buffer(the_repository, oid, type, size,
obj = parse_object_buffer(data->repo, oid, type, size,
contents, &eaten);
if (!obj) {
@@ -745,7 +765,7 @@ static int fsck_loose(const struct object_id *oid, const char *path,
obj->flags &= ~(REACHABLE | SEEN);
obj->flags |= HAS_OBJ;
if (fsck_obj(obj, contents, size))
if (fsck_obj(data->repo, obj, contents, size))
errors_found |= ERROR_OBJECT;
if (!eaten)
@@ -769,10 +789,11 @@ static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)
return 0;
}
static void fsck_source(struct odb_source *source)
static void fsck_source(struct repository *repo, struct odb_source *source)
{
struct progress *progress = NULL;
struct for_each_loose_cb cb_data = {
.repo = source->odb->repo,
.progress = progress,
};
@@ -780,7 +801,7 @@ static void fsck_source(struct odb_source *source)
fprintf_ln(stderr, _("Checking object directory"));
if (show_progress)
progress = start_progress(the_repository,
progress = start_progress(repo,
_("Checking object directories"), 256);
for_each_loose_file_in_source(source, fsck_loose,
@@ -789,7 +810,7 @@ static void fsck_source(struct odb_source *source)
stop_progress(&progress);
}
static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
static int fsck_cache_tree(struct repository *repo, struct cache_tree *it, const char *index_path)
{
int i;
int err = 0;
@@ -798,7 +819,7 @@ static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
fprintf_ln(stderr, _("Checking cache tree of %s"), index_path);
if (0 <= it->entry_count) {
struct object *obj = parse_object(the_repository, &it->oid);
struct object *obj = parse_object(repo, &it->oid);
if (!obj) {
error(_("%s: invalid sha1 pointer in cache-tree of %s"),
oid_to_hex(&it->oid), index_path);
@@ -809,10 +830,10 @@ static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
fsck_put_object_name(&fsck_walk_options, &it->oid, ":");
mark_object_reachable(obj);
if (obj->type != OBJ_TREE)
err |= objerror(obj, _("non-tree in cache-tree"));
err |= objerror(repo, obj, _("non-tree in cache-tree"));
}
for (i = 0; i < it->subtree_nr; i++)
err |= fsck_cache_tree(it->down[i]->cache_tree, index_path);
err |= fsck_cache_tree(repo, it->down[i]->cache_tree, index_path);
return err;
}
@@ -838,7 +859,7 @@ static int fsck_resolve_undo(struct index_state *istate,
if (!ru->mode[i] || !S_ISREG(ru->mode[i]))
continue;
obj = parse_object(the_repository, &ru->oid[i]);
obj = parse_object(istate->repo, &ru->oid[i]);
if (!obj) {
error(_("%s: invalid sha1 pointer in resolve-undo of %s"),
oid_to_hex(&ru->oid[i]),
@@ -870,7 +891,7 @@ static void fsck_index(struct index_state *istate, const char *index_path,
mode = istate->cache[i]->ce_mode;
if (S_ISGITLINK(mode))
continue;
blob = lookup_blob(the_repository,
blob = lookup_blob(istate->repo,
&istate->cache[i]->oid);
if (!blob)
continue;
@@ -883,15 +904,16 @@ static void fsck_index(struct index_state *istate, const char *index_path,
mark_object_reachable(obj);
}
if (istate->cache_tree)
fsck_cache_tree(istate->cache_tree, index_path);
fsck_cache_tree(istate->repo, istate->cache_tree, index_path);
fsck_resolve_undo(istate, index_path);
}
static int mark_object_for_connectivity(const struct object_id *oid,
struct object_info *oi UNUSED,
void *cb_data UNUSED)
void *cb_data)
{
struct object *obj = lookup_unknown_object(the_repository, oid);
struct repository *repo = cb_data;
struct object *obj = lookup_unknown_object(repo, oid);
obj->flags |= HAS_OBJ;
return 0;
}
@@ -906,7 +928,7 @@ static int check_pack_rev_indexes(struct repository *r, int show_progress)
if (show_progress) {
repo_for_each_pack(r, p)
pack_count++;
progress = start_delayed_progress(the_repository,
progress = start_delayed_progress(r,
"Verifying reverse pack-indexes", pack_count);
pack_count = 0;
}
@@ -986,7 +1008,7 @@ static struct option fsck_opts[] = {
int cmd_fsck(int argc,
const char **argv,
const char *prefix,
struct repository *repo UNUSED)
struct repository *repo)
{
struct odb_source *source;
struct snapshot snap = {
@@ -1004,7 +1026,10 @@ int cmd_fsck(int argc,
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
fsck_options_init(&fsck_walk_options, repo, FSCK_OPTIONS_DEFAULT);
fsck_walk_options.walk = mark_object;
fsck_options_init(&fsck_obj_options, repo, FSCK_OPTIONS_DEFAULT);
fsck_obj_options.walk = mark_used;
fsck_obj_options.error_func = fsck_objects_error_func;
if (check_strict)
@@ -1023,11 +1048,11 @@ int cmd_fsck(int argc,
if (name_objects)
fsck_enable_object_names(&fsck_walk_options);
repo_config(the_repository, git_fsck_config, &fsck_obj_options);
prepare_repo_settings(the_repository);
repo_config(repo, git_fsck_config, &fsck_obj_options);
prepare_repo_settings(repo);
if (check_references)
fsck_refs(the_repository);
fsck_refs(repo);
/*
* Take a snapshot of the refs before walking objects to avoid looking
@@ -1035,18 +1060,18 @@ int cmd_fsck(int argc,
* objects. We can still walk over new objects that are added during the
* execution of fsck but won't miss any objects that were reachable.
*/
snapshot_refs(&snap, argc, argv);
snapshot_refs(repo, &snap, argc, argv);
/* Ensure we get a "fresh" view of the odb */
odb_reprepare(the_repository->objects);
odb_reprepare(repo->objects);
if (connectivity_only) {
odb_for_each_object(the_repository->objects, NULL,
mark_object_for_connectivity, NULL, 0);
odb_for_each_object(repo->objects, NULL,
mark_object_for_connectivity, repo, 0);
} else {
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next)
fsck_source(source);
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next)
fsck_source(repo, source);
if (check_full) {
struct packed_git *p;
@@ -1054,20 +1079,20 @@ int cmd_fsck(int argc,
struct progress *progress = NULL;
if (show_progress) {
repo_for_each_pack(the_repository, p) {
repo_for_each_pack(repo, p) {
if (open_pack_index(p))
continue;
total += p->num_objects;
}
progress = start_progress(the_repository,
progress = start_progress(repo,
_("Checking objects"), total);
}
repo_for_each_pack(the_repository, p) {
repo_for_each_pack(repo, p) {
/* verify gives error messages itself */
if (verify_pack(the_repository,
p, fsck_obj_buffer,
if (verify_pack(repo,
p, fsck_obj_buffer, repo,
progress, count))
errors_found |= ERROR_PACK;
count += p->num_objects;
@@ -1080,7 +1105,7 @@ int cmd_fsck(int argc,
}
/* Process the snapshotted refs and the reflogs. */
process_refs(&snap);
process_refs(repo, &snap);
/* If not given any explicit objects, process index files too. */
if (!argc)
@@ -1100,7 +1125,7 @@ int cmd_fsck(int argc,
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
struct index_state istate =
INDEX_STATE_INIT(the_repository);
INDEX_STATE_INIT(repo);
char *path, *wt_gitdir;
/*
@@ -1121,17 +1146,17 @@ int cmd_fsck(int argc,
free_worktrees(worktrees);
}
errors_found |= check_pack_rev_indexes(the_repository, show_progress);
if (verify_bitmap_files(the_repository))
errors_found |= check_pack_rev_indexes(repo, show_progress);
if (verify_bitmap_files(repo))
errors_found |= ERROR_BITMAP;
check_connectivity();
check_connectivity(repo);
if (the_repository->settings.core_commit_graph) {
if (repo->settings.core_commit_graph) {
struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next) {
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next) {
child_process_init(&commit_graph_verify);
commit_graph_verify.git_cmd = 1;
strvec_pushl(&commit_graph_verify.args, "commit-graph",
@@ -1145,11 +1170,11 @@ int cmd_fsck(int argc,
}
}
if (the_repository->settings.core_multi_pack_index) {
if (repo->settings.core_multi_pack_index) {
struct child_process midx_verify = CHILD_PROCESS_INIT;
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next) {
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next) {
child_process_init(&midx_verify);
midx_verify.git_cmd = 1;
strvec_pushl(&midx_verify.args, "multi-pack-index",
+4 -4
View File
@@ -437,8 +437,8 @@ static int cmd_history_reword(int argc,
enum ref_action action = REF_ACTION_DEFAULT;
int dry_run = 0;
struct option options[] = {
OPT_CALLBACK_F(0, "update-refs", &action, N_("<action>"),
N_("control which refs should be updated (branches|head)"),
OPT_CALLBACK_F(0, "update-refs", &action, "(branches|head)",
N_("control which refs should be updated"),
PARSE_OPT_NONEG, parse_ref_action),
OPT_BOOL('n', "dry-run", &dry_run,
N_("perform a dry-run without updating any refs")),
@@ -666,8 +666,8 @@ static int cmd_history_split(int argc,
enum ref_action action = REF_ACTION_DEFAULT;
int dry_run = 0;
struct option options[] = {
OPT_CALLBACK_F(0, "update-refs", &action, N_("<refs>"),
N_("control ref update behavior (branches|head|print)"),
OPT_CALLBACK_F(0, "update-refs", &action, "(branches|head)",
N_("control ref update behavior"),
PARSE_OPT_NONEG, parse_ref_action),
OPT_BOOL('n', "dry-run", &dry_run,
N_("perform a dry-run without updating any refs")),
+4 -2
View File
@@ -136,7 +136,7 @@ static int nr_threads;
static int from_stdin;
static int strict;
static int do_fsck_object;
static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;
static struct fsck_options fsck_options;
static int verbose;
static const char *progress_title;
static int show_resolving_progress;
@@ -891,7 +891,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
if (startup_info->have_repository) {
read_lock();
collision_test_needed = odb_has_object(the_repository->objects, oid,
HAS_OBJECT_FETCH_PROMISOR);
ODB_HAS_OBJECT_FETCH_PROMISOR);
read_unlock();
}
@@ -1908,6 +1908,8 @@ int cmd_index_pack(int argc,
show_usage_if_asked(argc, argv, index_pack_usage);
disable_replace_refs();
fsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES);
fsck_options.walk = mark_link;
reset_pack_idx_option(&opts);
+3 -2
View File
@@ -16,7 +16,7 @@ static char const * const builtin_mktag_usage[] = {
};
static int option_strict = 1;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
static struct fsck_options fsck_options;
static int mktag_fsck_error_func(struct fsck_options *o UNUSED,
void *fsck_report UNUSED,
@@ -75,7 +75,7 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
int cmd_mktag(int argc,
const char **argv,
const char *prefix,
struct repository *repo UNUSED)
struct repository *repo)
{
static struct option builtin_mktag_options[] = {
OPT_BOOL(0, "strict", &option_strict,
@@ -94,6 +94,7 @@ int cmd_mktag(int argc,
if (strbuf_read(&buf, 0, 0) < 0)
die_errno(_("could not read from stdin"));
fsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT);
fsck_options.error_func = mktag_fsck_error_func;
fsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY,
FSCK_WARN);
+213 -98
View File
@@ -28,6 +28,7 @@
#include "reachable.h"
#include "oid-array.h"
#include "strvec.h"
#include "strmap.h"
#include "list.h"
#include "packfile.h"
#include "object-file.h"
@@ -217,6 +218,7 @@ static int have_non_local_packs;
static int incremental;
static int ignore_packed_keep_on_disk;
static int ignore_packed_keep_in_core;
static int ignore_packed_keep_in_core_open;
static int ignore_packed_keep_in_core_has_cruft;
static int allow_ofs_delta;
static struct pack_idx_option pack_idx_opts;
@@ -1632,7 +1634,8 @@ static int want_found_object(const struct object_id *oid, int exclude,
/*
* Then handle .keep first, as we have a fast(er) path there.
*/
if (ignore_packed_keep_on_disk || ignore_packed_keep_in_core) {
if (ignore_packed_keep_on_disk || ignore_packed_keep_in_core ||
ignore_packed_keep_in_core_open) {
/*
* Set the flags for the kept-pack cache to be the ones we want
* to ignore.
@@ -1646,6 +1649,8 @@ static int want_found_object(const struct object_id *oid, int exclude,
flags |= KEPT_PACK_ON_DISK;
if (ignore_packed_keep_in_core)
flags |= KEPT_PACK_IN_CORE;
if (ignore_packed_keep_in_core_open)
flags |= KEPT_PACK_IN_CORE_OPEN;
/*
* If the object is in a pack that we want to ignore, *and* we
@@ -1657,6 +1662,8 @@ static int want_found_object(const struct object_id *oid, int exclude,
return 0;
if (ignore_packed_keep_in_core && p->pack_keep_in_core)
return 0;
if (ignore_packed_keep_in_core_open && p->pack_keep_in_core_open)
return 0;
if (has_object_kept_pack(p->repo, oid, flags))
return 0;
} else {
@@ -3756,6 +3763,7 @@ static int add_object_entry_from_pack(const struct object_id *oid,
void *_data)
{
off_t ofs;
struct object_info oi = OBJECT_INFO_INIT;
enum object_type type = OBJ_NONE;
display_progress(progress_state, ++nr_seen);
@@ -3763,29 +3771,34 @@ static int add_object_entry_from_pack(const struct object_id *oid,
if (have_duplicate_entry(oid, 0))
return 0;
stdin_packs_found_nr++;
ofs = nth_packed_object_offset(p, pos);
oi.typep = &type;
if (packed_object_info(p, ofs, &oi) < 0) {
die(_("could not get type of object %s in pack %s"),
oid_to_hex(oid), p->pack_name);
} else if (type == OBJ_COMMIT) {
struct rev_info *revs = _data;
/*
* commits in included packs are used as starting points
* for the subsequent revision walk
*
* Note that we do want to walk through commits that are
* present in excluded-open ('!') packs to pick up any
* objects reachable from them not present in the
* excluded-closed ('^') packs.
*
* However, we'll only add those objects to the packing
* list after checking `want_object_in_pack()` below.
*/
add_pending_oid(revs, NULL, oid, 0);
}
if (!want_object_in_pack(oid, 0, &p, &ofs))
return 0;
if (p) {
struct object_info oi = OBJECT_INFO_INIT;
oi.typep = &type;
if (packed_object_info(p, ofs, &oi) < 0) {
die(_("could not get type of object %s in pack %s"),
oid_to_hex(oid), p->pack_name);
} else if (type == OBJ_COMMIT) {
struct rev_info *revs = _data;
/*
* commits in included packs are used as starting points for the
* subsequent revision walk
*/
add_pending_oid(revs, NULL, oid, 0);
}
stdin_packs_found_nr++;
}
create_object_entry(oid, type, 0, 0, 0, p, ofs);
return 0;
@@ -3835,87 +3848,78 @@ static void show_commit_pack_hint(struct commit *commit, void *data)
}
/*
* stdin_pack_info_kind specifies how a pack specified over stdin
* should be treated when pack-objects is invoked with --stdin-packs.
*
* - STDIN_PACK_INCLUDE: objects in any packs with this flag bit set
* should be included in the output pack, unless they appear in an
* excluded pack.
*
* - STDIN_PACK_EXCLUDE_CLOSED: objects in any packs with this flag
* bit set should be excluded from the output pack.
*
* - STDIN_PACK_EXCLUDE_OPEN: objects in any packs with this flag
* bit set should be excluded from the output pack, but are not
* guaranteed to be closed under reachability.
*
* Objects in packs whose 'kind' bits include STDIN_PACK_INCLUDE or
* STDIN_PACK_EXCLUDE_OPEN are used as traversal tips when invoked
* with --stdin-packs=follow.
*/
enum stdin_pack_info_kind {
STDIN_PACK_INCLUDE = (1<<0),
STDIN_PACK_EXCLUDE_CLOSED = (1<<1),
STDIN_PACK_EXCLUDE_OPEN = (1<<2),
};
struct stdin_pack_info {
struct packed_git *p;
enum stdin_pack_info_kind kind;
};
static int pack_mtime_cmp(const void *_a, const void *_b)
{
struct packed_git *a = ((const struct string_list_item*)_a)->util;
struct packed_git *b = ((const struct string_list_item*)_b)->util;
struct stdin_pack_info *a = ((const struct string_list_item*)_a)->util;
struct stdin_pack_info *b = ((const struct string_list_item*)_b)->util;
/*
* order packs by descending mtime so that objects are laid out
* roughly as newest-to-oldest
*/
if (a->mtime < b->mtime)
if (a->p->mtime < b->p->mtime)
return 1;
else if (b->mtime < a->mtime)
else if (b->p->mtime < a->p->mtime)
return -1;
else
return 0;
}
static void read_packs_list_from_stdin(struct rev_info *revs)
static int stdin_packs_include_check_obj(struct object *obj, void *data UNUSED)
{
struct strbuf buf = STRBUF_INIT;
struct string_list include_packs = STRING_LIST_INIT_DUP;
struct string_list exclude_packs = STRING_LIST_INIT_DUP;
struct string_list_item *item = NULL;
struct packed_git *p;
return !has_object_kept_pack(to_pack.repo, &obj->oid,
KEPT_PACK_IN_CORE);
}
while (strbuf_getline(&buf, stdin) != EOF) {
if (!buf.len)
continue;
static int stdin_packs_include_check(struct commit *commit, void *data)
{
return stdin_packs_include_check_obj((struct object *)commit, data);
}
if (*buf.buf == '^')
string_list_append(&exclude_packs, buf.buf + 1);
else
string_list_append(&include_packs, buf.buf);
static void stdin_packs_add_pack_entries(struct strmap *packs,
struct rev_info *revs)
{
struct string_list keys = STRING_LIST_INIT_NODUP;
struct string_list_item *item;
struct hashmap_iter iter;
struct strmap_entry *entry;
strbuf_reset(&buf);
}
strmap_for_each_entry(packs, &iter, entry) {
struct stdin_pack_info *info = entry->value;
if (!info->p)
die(_("could not find pack '%s'"), entry->key);
string_list_sort_u(&include_packs, 0);
string_list_sort_u(&exclude_packs, 0);
repo_for_each_pack(the_repository, p) {
const char *pack_name = pack_basename(p);
if ((item = string_list_lookup(&include_packs, pack_name))) {
if (exclude_promisor_objects && p->pack_promisor)
die(_("packfile %s is a promisor but --exclude-promisor-objects was given"), p->pack_name);
item->util = p;
}
if ((item = string_list_lookup(&exclude_packs, pack_name)))
item->util = p;
}
/*
* Arguments we got on stdin may not even be packs. First
* check that to avoid segfaulting later on in
* e.g. pack_mtime_cmp(), excluded packs are handled below.
*
* Since we first parsed our STDIN and then sorted the input
* lines the pack we error on will be whatever line happens to
* sort first. This is lazy, it's enough that we report one
* bad case here, we don't need to report the first/last one,
* or all of them.
*/
for_each_string_list_item(item, &include_packs) {
struct packed_git *p = item->util;
if (!p)
die(_("could not find pack '%s'"), item->string);
if (!is_pack_valid(p))
die(_("packfile %s cannot be accessed"), p->pack_name);
}
/*
* Then, handle all of the excluded packs, marking them as
* kept in-core so that later calls to add_object_entry()
* discards any objects that are also found in excluded packs.
*/
for_each_string_list_item(item, &exclude_packs) {
struct packed_git *p = item->util;
if (!p)
die(_("could not find pack '%s'"), item->string);
p->pack_keep_in_core = 1;
string_list_append(&keys, entry->key)->util = info;
}
/*
@@ -3923,19 +3927,118 @@ static void read_packs_list_from_stdin(struct rev_info *revs)
* string_list_item's ->util pointer, which string_list_sort() does not
* provide.
*/
QSORT(include_packs.items, include_packs.nr, pack_mtime_cmp);
QSORT(keys.items, keys.nr, pack_mtime_cmp);
for_each_string_list_item(item, &include_packs) {
struct packed_git *p = item->util;
for_each_object_in_pack(p,
add_object_entry_from_pack,
revs,
ODB_FOR_EACH_OBJECT_PACK_ORDER);
for_each_string_list_item(item, &keys) {
struct stdin_pack_info *info = item->util;
if (info->kind & STDIN_PACK_EXCLUDE_OPEN) {
/*
* When open-excluded packs ("!") are present, stop
* the parent walk at closed-excluded ("^") packs.
* Objects behind a "^" boundary are guaranteed to
* have closure and should not be rescued.
*/
revs->include_check = stdin_packs_include_check;
revs->include_check_obj = stdin_packs_include_check_obj;
}
if ((info->kind & STDIN_PACK_INCLUDE) ||
(info->kind & STDIN_PACK_EXCLUDE_OPEN))
for_each_object_in_pack(info->p,
add_object_entry_from_pack,
revs,
ODB_FOR_EACH_OBJECT_PACK_ORDER);
}
string_list_clear(&keys, 0);
}
static void stdin_packs_read_input(struct rev_info *revs,
enum stdin_packs_mode mode)
{
struct strbuf buf = STRBUF_INIT;
struct strmap packs = STRMAP_INIT;
struct packed_git *p;
while (strbuf_getline(&buf, stdin) != EOF) {
struct stdin_pack_info *info;
enum stdin_pack_info_kind kind = STDIN_PACK_INCLUDE;
const char *key = buf.buf;
if (!*key)
continue;
else if (*key == '^')
kind = STDIN_PACK_EXCLUDE_CLOSED;
else if (*key == '!' && mode == STDIN_PACKS_MODE_FOLLOW)
kind = STDIN_PACK_EXCLUDE_OPEN;
if (kind != STDIN_PACK_INCLUDE)
key++;
info = strmap_get(&packs, key);
if (!info) {
CALLOC_ARRAY(info, 1);
strmap_put(&packs, key, info);
}
info->kind |= kind;
strbuf_reset(&buf);
}
repo_for_each_pack(the_repository, p) {
struct stdin_pack_info *info;
info = strmap_get(&packs, pack_basename(p));
if (!info)
continue;
if (info->kind & STDIN_PACK_INCLUDE) {
if (exclude_promisor_objects && p->pack_promisor)
die(_("packfile %s is a promisor but --exclude-promisor-objects was given"), p->pack_name);
/*
* Arguments we got on stdin may not even be
* packs. First check that to avoid segfaulting
* later on in e.g. pack_mtime_cmp(), excluded
* packs are handled below.
*/
if (!is_pack_valid(p))
die(_("packfile %s cannot be accessed"), p->pack_name);
}
if (info->kind & STDIN_PACK_EXCLUDE_CLOSED) {
/*
* Marking excluded packs as kept in-core so
* that later calls to add_object_entry()
* discards any objects that are also found in
* excluded packs.
*/
p->pack_keep_in_core = 1;
}
if (info->kind & STDIN_PACK_EXCLUDE_OPEN) {
/*
* Marking excluded open packs as kept in-core
* (open) for the same reason as we marked
* exclude closed packs as kept in-core.
*
* Use a separate flag here to ensure we don't
* halt our traversal at these packs, since they
* are not guaranteed to have closure.
*
*/
p->pack_keep_in_core_open = 1;
}
info->p = p;
}
stdin_packs_add_pack_entries(&packs, revs);
strbuf_release(&buf);
string_list_clear(&include_packs, 0);
string_list_clear(&exclude_packs, 0);
strmap_clear(&packs, 1);
}
static void add_unreachable_loose_objects(struct rev_info *revs);
@@ -3972,7 +4075,15 @@ static void read_stdin_packs(enum stdin_packs_mode mode, int rev_list_unpacked)
/* avoids adding objects in excluded packs */
ignore_packed_keep_in_core = 1;
read_packs_list_from_stdin(&revs);
if (mode == STDIN_PACKS_MODE_FOLLOW) {
/*
* In '--stdin-packs=follow' mode, additionally ignore
* objects in excluded-open packs to prevent them from
* appearing in the resulting pack.
*/
ignore_packed_keep_in_core_open = 1;
}
stdin_packs_read_input(&revs, mode);
if (rev_list_unpacked)
add_unreachable_loose_objects(&revs);
@@ -3983,6 +4094,8 @@ static void read_stdin_packs(enum stdin_packs_mode mode, int rev_list_unpacked)
show_object_pack_hint,
&mode);
release_revisions(&revs);
trace2_data_intmax("pack-objects", the_repository, "stdin_packs_found",
stdin_packs_found_nr);
trace2_data_intmax("pack-objects", the_repository, "stdin_packs_hints",
@@ -4359,6 +4472,12 @@ static void add_objects_in_unpacked_packs(void)
{
struct odb_source *source;
time_t mtime;
struct odb_for_each_object_options opts = {
.flags = ODB_FOR_EACH_OBJECT_PACK_ORDER |
ODB_FOR_EACH_OBJECT_LOCAL_ONLY |
ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS,
};
struct object_info oi = {
.mtimep = &mtime,
};
@@ -4371,11 +4490,7 @@ static void add_objects_in_unpacked_packs(void)
continue;
if (packfile_store_for_each_object(files->packed, &oi,
add_object_in_unpacked_pack, NULL,
ODB_FOR_EACH_OBJECT_PACK_ORDER |
ODB_FOR_EACH_OBJECT_LOCAL_ONLY |
ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS))
add_object_in_unpacked_pack, NULL, &opts))
die(_("cannot open pack index"));
}
}
+16 -25
View File
@@ -1384,32 +1384,16 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
return 0;
}
/*
* NEEDSWORK: we should consolidate various implementations of "are we
* on an unborn branch?" test into one, and make the unified one more
* robust. !get_sha1() based check used here and elsewhere would not
* allow us to tell an unborn branch from corrupt ref, for example.
* For the purpose of fixing "deploy-to-update does not work when
* pushing into an empty repository" issue, this should suffice for
* now.
*/
static int head_has_history(void)
{
struct object_id oid;
return !repo_get_oid(the_repository, "HEAD", &oid);
}
static const char *push_to_deploy(unsigned char *sha1,
struct strvec *env,
const char *work_tree)
const struct worktree *worktree)
{
struct child_process child = CHILD_PROCESS_INIT;
strvec_pushl(&child.args, "update-index", "-q", "--ignore-submodules",
"--refresh", NULL);
strvec_pushv(&child.env, env->v);
child.dir = work_tree;
child.dir = worktree->path;
child.no_stdin = 1;
child.stdout_to_stderr = 1;
child.git_cmd = 1;
@@ -1421,7 +1405,7 @@ static const char *push_to_deploy(unsigned char *sha1,
strvec_pushl(&child.args, "diff-files", "--quiet",
"--ignore-submodules", "--", NULL);
strvec_pushv(&child.env, env->v);
child.dir = work_tree;
child.dir = worktree->path;
child.no_stdin = 1;
child.stdout_to_stderr = 1;
child.git_cmd = 1;
@@ -1431,9 +1415,16 @@ static const char *push_to_deploy(unsigned char *sha1,
child_process_init(&child);
strvec_pushl(&child.args, "diff-index", "--quiet", "--cached",
"--ignore-submodules",
/* diff-index with either HEAD or an empty tree */
head_has_history() ? "HEAD" : empty_tree_oid_hex(the_repository->hash_algo),
"--", NULL);
/*
* diff-index with either HEAD or an empty tree
*
* NEEDSWORK: is_null_oid() cannot know whether it's an
* unborn HEAD or a corrupt ref. It works for now because
* it's only needed to know if we are comparing HEAD or an
* empty tree.
*/
!is_null_oid(&worktree->head_oid) ? "HEAD" :
empty_tree_oid_hex(the_repository->hash_algo), "--", NULL);
strvec_pushv(&child.env, env->v);
child.no_stdin = 1;
child.no_stdout = 1;
@@ -1446,7 +1437,7 @@ static const char *push_to_deploy(unsigned char *sha1,
strvec_pushl(&child.args, "read-tree", "-u", "-m", hash_to_hex(sha1),
NULL);
strvec_pushv(&child.env, env->v);
child.dir = work_tree;
child.dir = worktree->path;
child.no_stdin = 1;
child.no_stdout = 1;
child.stdout_to_stderr = 0;
@@ -1494,7 +1485,7 @@ static const char *update_worktree(unsigned char *sha1, const struct worktree *w
retval = push_to_checkout(sha1, &invoked_hook, &env, worktree->path);
if (!invoked_hook)
retval = push_to_deploy(sha1, &env, worktree->path);
retval = push_to_deploy(sha1, &env, worktree);
strvec_clear(&env);
free(git_dir);
@@ -1550,7 +1541,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
if (!is_null_oid(new_oid) &&
!odb_has_object(the_repository->objects, new_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR)) {
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR)) {
error("unpack should have generated %s, "
"but I can't find it!", oid_to_hex(new_oid));
ret = "bad pack";
+4 -2
View File
@@ -78,9 +78,9 @@ out:
}
static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
struct repository *repo)
{
struct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT;
struct fsck_options fsck_refs_options;
struct worktree **worktrees;
const char * const verify_usage[] = {
REFS_VERIFY_USAGE,
@@ -93,6 +93,8 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
};
int ret = 0;
fsck_options_init(&fsck_refs_options, repo, FSCK_OPTIONS_REFS);
argc = parse_options(argc, argv, prefix, options, verify_usage, 0);
if (argc)
usage(_("'git refs verify' takes no arguments"));
+1 -1
View File
@@ -473,7 +473,7 @@ static int get_push_ref_states(const struct ref *remote_refs,
else if (is_null_oid(&ref->old_oid))
info->status = PUSH_STATUS_CREATE;
else if (odb_has_object(the_repository->objects, &ref->old_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR) &&
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR) &&
ref_newer(&ref->new_oid, &ref->old_oid))
info->status = PUSH_STATUS_FASTFORWARD;
else
+17 -2
View File
@@ -369,8 +369,23 @@ int cmd_repack(int argc,
*/
for (i = 0; i < geometry.split; i++)
fprintf(in, "%s\n", pack_basename(geometry.pack[i]));
for (i = geometry.split; i < geometry.pack_nr; i++)
fprintf(in, "^%s\n", pack_basename(geometry.pack[i]));
for (i = geometry.split; i < geometry.pack_nr; i++) {
const char *basename = pack_basename(geometry.pack[i]);
char marker = '^';
if (!midx_must_contain_cruft &&
!string_list_has_string(&existing.midx_packs,
basename)) {
/*
* Assume non-MIDX'd packs are not
* necessarily closed under
* reachability.
*/
marker = '!';
}
fprintf(in, "%c%s\n", marker, basename);
}
fclose(in);
}
+24 -14
View File
@@ -84,25 +84,33 @@ int cmd_replay(int argc,
const char *const replay_usage[] = {
N_("(EXPERIMENTAL!) git replay "
"([--contained] --onto <newbase> | --advance <branch> | --revert <branch>) "
"[--ref-action[=<mode>]] <revision-range>"),
"([--contained] --onto=<newbase> | --advance=<branch> | --revert=<branch>)\n"
"[--ref=<ref>] [--ref-action=<mode>] <revision-range>"),
NULL
};
struct option replay_options[] = {
OPT_STRING(0, "advance", &opts.advance,
N_("branch"),
N_("make replay advance given branch")),
OPT_STRING(0, "onto", &opts.onto,
N_("revision"),
N_("replay onto given commit")),
OPT_BOOL(0, "contained", &opts.contained,
N_("update all branches that point at commits in <revision-range>")),
OPT_STRING(0, "revert", &opts.revert,
N_("branch"),
N_("revert commits onto given branch")),
OPT_STRING(0, "ref-action", &ref_action,
N_("mode"),
N_("control ref update behavior (update|print)")),
OPT_STRING_F(0, "onto", &opts.onto,
N_("revision"),
N_("replay onto given commit"),
PARSE_OPT_NONEG),
OPT_STRING_F(0, "advance", &opts.advance,
N_("branch"),
N_("make replay advance given branch"),
PARSE_OPT_NONEG),
OPT_STRING_F(0, "revert", &opts.revert,
N_("branch"),
N_("revert commits onto given branch"),
PARSE_OPT_NONEG),
OPT_STRING_F(0, "ref", &opts.ref,
N_("branch"),
N_("reference to update with result"),
PARSE_OPT_NONEG),
OPT_STRING_F(0, "ref-action", &ref_action,
N_("mode"),
N_("control ref update behavior (update|print)"),
PARSE_OPT_NONEG),
OPT_END()
};
@@ -122,6 +130,8 @@ int cmd_replay(int argc,
opts.contained, "--contained");
die_for_incompatible_opt2(!!opts.revert, "--revert",
opts.contained, "--contained");
die_for_incompatible_opt2(!!opts.ref, "--ref",
!!opts.contained, "--contained");
/* Parse ref action mode from command line or config */
ref_mode = get_ref_action_mode(repo, ref_action);
+20 -20
View File
@@ -267,21 +267,20 @@ static int show_file(const char *arg, int output_prefix)
static int try_difference(const char *arg)
{
char *dotdot;
const char *dotdot;
struct object_id start_oid;
struct object_id end_oid;
const char *end;
const char *start;
char *to_free;
int symmetric;
static const char head_by_default[] = "HEAD";
if (!(dotdot = strstr(arg, "..")))
return 0;
start = to_free = xmemdupz(arg, dotdot - arg);
end = dotdot + 2;
start = arg;
symmetric = (*end == '.');
*dotdot = 0;
end += symmetric;
if (!*end)
@@ -295,7 +294,7 @@ static int try_difference(const char *arg)
* Just ".."? That is not a range but the
* pathspec for the parent directory.
*/
*dotdot = '.';
free(to_free);
return 0;
}
@@ -308,7 +307,7 @@ static int try_difference(const char *arg)
a = lookup_commit_reference(the_repository, &start_oid);
b = lookup_commit_reference(the_repository, &end_oid);
if (!a || !b) {
*dotdot = '.';
free(to_free);
return 0;
}
if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0)
@@ -318,16 +317,16 @@ static int try_difference(const char *arg)
show_rev(REVERSED, &commit->object.oid, NULL);
}
}
*dotdot = '.';
free(to_free);
return 1;
}
*dotdot = '.';
free(to_free);
return 0;
}
static int try_parent_shorthands(const char *arg)
{
char *dotdot;
const char *mark;
struct object_id oid;
struct commit *commit;
struct commit_list *parents;
@@ -335,38 +334,39 @@ static int try_parent_shorthands(const char *arg)
int include_rev = 0;
int include_parents = 0;
int exclude_parent = 0;
char *to_free;
if ((dotdot = strstr(arg, "^!"))) {
if ((mark = strstr(arg, "^!"))) {
include_rev = 1;
if (dotdot[2])
if (mark[2])
return 0;
} else if ((dotdot = strstr(arg, "^@"))) {
} else if ((mark = strstr(arg, "^@"))) {
include_parents = 1;
if (dotdot[2])
if (mark[2])
return 0;
} else if ((dotdot = strstr(arg, "^-"))) {
} else if ((mark = strstr(arg, "^-"))) {
include_rev = 1;
exclude_parent = 1;
if (dotdot[2]) {
if (mark[2]) {
char *end;
exclude_parent = strtoul(dotdot + 2, &end, 10);
exclude_parent = strtoul(mark + 2, &end, 10);
if (*end != '\0' || !exclude_parent)
return 0;
}
} else
return 0;
*dotdot = 0;
arg = to_free = xmemdupz(arg, mark - arg);
if (repo_get_oid_committish(the_repository, arg, &oid) ||
!(commit = lookup_commit_reference(the_repository, &oid))) {
*dotdot = '^';
free(to_free);
return 0;
}
if (exclude_parent &&
exclude_parent > commit_list_count(commit->parents)) {
*dotdot = '^';
free(to_free);
return 0;
}
@@ -387,7 +387,7 @@ static int try_parent_shorthands(const char *arg)
free(name);
}
*dotdot = '^';
free(to_free);
return 1;
}
+1 -1
View File
@@ -37,7 +37,7 @@ static void show_one(const struct show_one_options *opts,
struct object_id peeled;
if (!odb_has_object(the_repository->objects, ref->oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
die("git show-ref: bad ref %s (%s)", ref->name,
oid_to_hex(ref->oid));
+2 -2
View File
@@ -50,10 +50,10 @@
#define BUILTIN_STASH_STORE_USAGE \
N_("git stash store [(-m | --message) <message>] [-q | --quiet] <commit>")
#define BUILTIN_STASH_PUSH_USAGE \
N_("git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
N_("git stash [push] [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
" [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]\n" \
" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n" \
" [--] [<pathspec>...]]")
" [--] [<pathspec>...]")
#define BUILTIN_STASH_SAVE_USAGE \
N_("git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
" [-u | --include-untracked] [-a | --all] [<message>]")
+5 -3
View File
@@ -29,7 +29,7 @@ static unsigned int offset, len;
static off_t consumed_bytes;
static off_t max_input_size;
static struct git_hash_ctx ctx;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
static struct fsck_options fsck_options;
static struct progress *progress;
/*
@@ -449,7 +449,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
if (!delta_data)
return;
if (odb_has_object(the_repository->objects, &base_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
; /* Ok we have this one */
else if (resolve_against_held(nr, &base_oid,
delta_data, delta_size))
@@ -613,7 +613,7 @@ static void unpack_all(void)
int cmd_unpack_objects(int argc,
const char **argv,
const char *prefix UNUSED,
struct repository *repo UNUSED)
struct repository *repo)
{
int i;
struct object_id oid;
@@ -627,6 +627,8 @@ int cmd_unpack_objects(int argc,
show_usage_if_asked(argc, argv, unpack_usage);
fsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT);
for (i = 1 ; i < argc; i++) {
const char *arg = argv[i];
+7 -7
View File
@@ -239,7 +239,7 @@ int cache_tree_fully_valid(struct cache_tree *it)
return 0;
if (it->entry_count < 0 ||
odb_has_object(the_repository->objects, &it->oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
return 0;
for (i = 0; i < it->subtree_nr; i++) {
if (!cache_tree_fully_valid(it->down[i]->cache_tree))
@@ -292,7 +292,7 @@ static int update_one(struct cache_tree *it,
if (0 <= it->entry_count &&
odb_has_object(the_repository->objects, &it->oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
return it->entry_count;
/*
@@ -400,7 +400,7 @@ static int update_one(struct cache_tree *it,
if (is_null_oid(oid) ||
(!ce_missing_ok &&
!odb_has_object(the_repository->objects, oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))) {
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))) {
strbuf_release(&buffer);
if (expected_missing)
return -1;
@@ -448,7 +448,7 @@ static int update_one(struct cache_tree *it,
struct object_id oid;
hash_object_file(the_hash_algo, buffer.buf, buffer.len,
OBJ_TREE, &oid);
if (odb_has_object(the_repository->objects, &oid, HAS_OBJECT_RECHECK_PACKED))
if (odb_has_object(the_repository->objects, &oid, ODB_HAS_OBJECT_RECHECK_PACKED))
oidcpy(&it->oid, &oid);
else
to_invalidate = 1;
@@ -456,7 +456,7 @@ static int update_one(struct cache_tree *it,
hash_object_file(the_hash_algo, buffer.buf, buffer.len,
OBJ_TREE, &it->oid);
} else if (odb_write_object_ext(the_repository->objects, buffer.buf, buffer.len, OBJ_TREE,
&it->oid, NULL, flags & WRITE_TREE_SILENT ? WRITE_OBJECT_SILENT : 0)) {
&it->oid, NULL, flags & WRITE_TREE_SILENT ? ODB_WRITE_OBJECT_SILENT : 0)) {
strbuf_release(&buffer);
return -1;
}
@@ -488,12 +488,12 @@ int cache_tree_update(struct index_state *istate, int flags)
prefetch_cache_entries(istate, must_check_existence);
trace_performance_enter();
trace2_region_enter("cache_tree", "update", the_repository);
trace2_region_enter("cache_tree", "update", istate->repo);
transaction = odb_transaction_begin(the_repository->objects);
i = update_one(istate->cache_tree, istate->cache, istate->cache_nr,
"", 0, &skip, flags);
odb_transaction_commit(transaction);
trace2_region_leave("cache_tree", "update", the_repository);
trace2_region_leave("cache_tree", "update", istate->repo);
trace_performance_leave("cache_tree_update");
if (i < 0)
return i;
+12 -9
View File
@@ -96,26 +96,28 @@ struct cb_node *cb_lookup(struct cb_tree *t, const uint8_t *k, size_t klen)
return p && !memcmp(p->k, k, klen) ? p : NULL;
}
static enum cb_next cb_descend(struct cb_node *p, cb_iter fn, void *arg)
static int cb_descend(struct cb_node *p, cb_iter fn, void *arg)
{
if (1 & (uintptr_t)p) {
struct cb_node *q = cb_node_of(p);
enum cb_next n = cb_descend(q->child[0], fn, arg);
return n == CB_BREAK ? n : cb_descend(q->child[1], fn, arg);
int ret = cb_descend(q->child[0], fn, arg);
if (ret)
return ret;
return cb_descend(q->child[1], fn, arg);
} else {
return fn(p, arg);
}
}
void cb_each(struct cb_tree *t, const uint8_t *kpfx, size_t klen,
cb_iter fn, void *arg)
int cb_each(struct cb_tree *t, const uint8_t *kpfx, size_t klen,
cb_iter fn, void *arg)
{
struct cb_node *p = t->root;
struct cb_node *top = p;
size_t i = 0;
if (!p) return; /* empty tree */
if (!p)
return 0; /* empty tree */
/* Walk tree, maintaining top pointer */
while (1 & (uintptr_t)p) {
@@ -130,7 +132,8 @@ void cb_each(struct cb_tree *t, const uint8_t *kpfx, size_t klen,
for (i = 0; i < klen; i++) {
if (p->k[i] != kpfx[i])
return; /* "best" match failed */
return 0; /* "best" match failed */
}
cb_descend(top, fn, arg);
return cb_descend(top, fn, arg);
}
+9 -8
View File
@@ -30,11 +30,6 @@ struct cb_tree {
struct cb_node *root;
};
enum cb_next {
CB_CONTINUE = 0,
CB_BREAK = 1
};
#define CBTREE_INIT { 0 }
static inline void cb_init(struct cb_tree *t)
@@ -46,9 +41,15 @@ static inline void cb_init(struct cb_tree *t)
struct cb_node *cb_lookup(struct cb_tree *, const uint8_t *k, size_t klen);
struct cb_node *cb_insert(struct cb_tree *, struct cb_node *, size_t klen);
typedef enum cb_next (*cb_iter)(struct cb_node *, void *arg);
/*
* Callback invoked by `cb_each()` for each node in the critbit tree. A return
* value of 0 will cause the iteration to continue, a non-zero return code will
* cause iteration to abort. The error code will be relayed back from
* `cb_each()` in that case.
*/
typedef int (*cb_iter)(struct cb_node *, void *arg);
void cb_each(struct cb_tree *, const uint8_t *kpfx, size_t klen,
cb_iter, void *arg);
int cb_each(struct cb_tree *, const uint8_t *kpfx, size_t klen,
cb_iter, void *arg);
#endif /* CBTREE_H */
+38 -4
View File
@@ -1319,6 +1319,37 @@ static int write_graph_chunk_data(struct hashfile *f,
return 0;
}
/*
* Compute the generation offset between the commit date and its generation.
* This is what's ultimately stored as generation number in the commit graph.
*
* Note that the computation of the commit date is more involved than you might
* think. Instead of using the full commit date, we're in fact masking bits so
* that only the 34 lowest bits are considered. This results from the fact that
* commit graphs themselves only ever store 34 bits of the commit date
* themselves.
*
* This means that if we have a commit date that exceeds 34 bits we'll end up
* in situations where depending on whether the commit has been parsed from the
* object database or the commit graph we'll have different dates, where the
* ones parsed from the object database would have full 64 bit precision.
*
* But ultimately, we only ever want the offset to be relative to what we
* actually end up storing on disk, and hence we have to mask all the other
* bits.
*/
static timestamp_t compute_generation_offset(struct commit *c)
{
timestamp_t masked_date;
if (sizeof(timestamp_t) > 4)
masked_date = c->date & (((timestamp_t) 1 << 34) - 1);
else
masked_date = c->date;
return commit_graph_data_at(c)->generation - masked_date;
}
static int write_graph_chunk_generation_data(struct hashfile *f,
void *data)
{
@@ -1329,7 +1360,7 @@ static int write_graph_chunk_generation_data(struct hashfile *f,
struct commit *c = ctx->commits.items[i];
timestamp_t offset;
repo_parse_commit(ctx->r, c);
offset = commit_graph_data_at(c)->generation - c->date;
offset = compute_generation_offset(c);
display_progress(ctx->progress, ++ctx->progress_cnt);
if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) {
@@ -1350,7 +1381,7 @@ static int write_graph_chunk_generation_data_overflow(struct hashfile *f,
int i;
for (i = 0; i < ctx->commits.nr; i++) {
struct commit *c = ctx->commits.items[i];
timestamp_t offset = commit_graph_data_at(c)->generation - c->date;
timestamp_t offset = compute_generation_offset(c);
display_progress(ctx->progress, ++ctx->progress_cnt);
if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) {
@@ -1741,7 +1772,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
for (i = 0; i < ctx->commits.nr; i++) {
struct commit *c = ctx->commits.items[i];
timestamp_t offset = commit_graph_data_at(c)->generation - c->date;
timestamp_t offset = compute_generation_offset(c);
if (offset > GENERATION_NUMBER_V2_OFFSET_MAX)
ctx->num_generation_data_overflows++;
}
@@ -1969,6 +2000,9 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
{
struct odb_source *source;
enum object_type type;
struct odb_for_each_object_options opts = {
.flags = ODB_FOR_EACH_OBJECT_PACK_ORDER,
};
struct object_info oi = {
.typep = &type,
};
@@ -1983,7 +2017,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
for (source = ctx->r->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
packfile_store_for_each_object(files->packed, &oi, add_packed_commits_oi,
ctx, ODB_FOR_EACH_OBJECT_PACK_ORDER);
ctx, &opts);
}
if (ctx->progress_done < ctx->approx_nr_objects)
+5 -1
View File
@@ -1394,6 +1394,9 @@ revert_attrs:
size_t mingw_strftime(char *s, size_t max,
const char *format, const struct tm *tm)
{
#ifdef _UCRT
size_t ret = strftime(s, max, format, tm);
#else
/* a pointer to the original strftime in case we can't find the UCRT version */
static size_t (*fallback)(char *, size_t, const char *, const struct tm *) = strftime;
size_t ret;
@@ -1404,6 +1407,7 @@ size_t mingw_strftime(char *s, size_t max,
ret = strftime(s, max, format, tm);
else
ret = fallback(s, max, format, tm);
#endif
if (!ret && errno == EINVAL)
die("invalid strftime format: '%s'", format);
@@ -2460,7 +2464,7 @@ repeat:
if (supports_file_rename_info_ex) {
/*
* Our minimum required Windows version is still set to Windows
* Vista. We thus have to declare required infrastructure for
* 8.1. We thus have to declare required infrastructure for
* FileRenameInfoEx ourselves until we bump _WIN32_WINNT to
* 0x0A00. Furthermore, we have to handle cases where the
* FileRenameInfoEx call isn't supported yet.
+1 -1
View File
@@ -500,7 +500,7 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x403
#define _WIN32_WINNT 0x603
#endif
#include <windows.h>
#define HAVE_MMAP 1
+2 -2
View File
@@ -20,7 +20,7 @@
#define DISABLE_SIGN_COMPARE_WARNINGS
/* To bump the minimum Windows version to Windows Vista */
/* To bump the minimum Windows version to Windows 8.1 */
#include "git-compat-util.h"
/* Tell gcc not to warn about the (nfd < 0) tests, below. */
@@ -41,7 +41,7 @@
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
# define WIN32_NATIVE
# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0502
# define _WIN32_WINNT 0x0603
# endif
# include <winsock2.h>
# include <windows.h>
+1 -1
View File
@@ -76,7 +76,7 @@
#if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
# if !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0600
# define _WIN32_WINNT 0x0603
# endif
#define WIN32_LEAN_AND_MEAN /* stops windows.h including winsock.h */
#include <winsock2.h>
+2
View File
@@ -6,7 +6,9 @@ int win32_fsync_no_flush(int fd)
{
IO_STATUS_BLOCK io_status;
#ifndef FLUSH_FLAGS_FILE_DATA_ONLY
#define FLUSH_FLAGS_FILE_DATA_ONLY 1
#endif
DECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, NtFlushBuffersFileEx,
HANDLE FileHandle, ULONG Flags, PVOID Parameters, ULONG ParameterSize,
+4 -33
View File
@@ -32,47 +32,18 @@ static int non_ascii_used = 0;
static HANDLE hthread, hread, hwrite;
static HANDLE hconsole1, hconsole2;
#ifdef __MINGW32__
#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 5
typedef struct _CONSOLE_FONT_INFOEX {
ULONG cbSize;
DWORD nFont;
COORD dwFontSize;
UINT FontFamily;
UINT FontWeight;
WCHAR FaceName[LF_FACESIZE];
} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
#endif
#endif
static void warn_if_raster_font(void)
{
DWORD fontFamily = 0;
DECLARE_PROC_ADDR(kernel32.dll, BOOL, WINAPI,
GetCurrentConsoleFontEx, HANDLE, BOOL,
PCONSOLE_FONT_INFOEX);
CONSOLE_FONT_INFOEX cfi;
/* don't bother if output was ascii only */
if (!non_ascii_used)
return;
/* GetCurrentConsoleFontEx is available since Vista */
if (INIT_PROC_ADDR(GetCurrentConsoleFontEx)) {
CONSOLE_FONT_INFOEX cfi;
cfi.cbSize = sizeof(cfi);
if (GetCurrentConsoleFontEx(console, 0, &cfi))
fontFamily = cfi.FontFamily;
} else {
/* pre-Vista: check default console font in registry */
HKEY hkey;
if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
0, KEY_READ, &hkey)) {
DWORD size = sizeof(fontFamily);
RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
(LPVOID) &fontFamily, &size);
RegCloseKey(hkey);
}
}
cfi.cbSize = sizeof(cfi);
if (GetCurrentConsoleFontEx(console, 0, &cfi))
fontFamily = cfi.FontFamily;
if (!(fontFamily & TMPF_TRUETYPE)) {
const wchar_t *msg = L"\nWarning: Your console font probably "
+4
View File
@@ -1054,6 +1054,8 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
strvec_push(&proxy->args, port);
proxy->in = -1;
proxy->out = -1;
proxy->clean_on_exit = 1;
proxy->wait_after_clean = 1;
if (start_command(proxy))
die(_("cannot start proxy %s"), git_proxy_command);
fd[0] = proxy->out; /* read from proxy stdout */
@@ -1515,6 +1517,8 @@ struct child_process *git_connect(int fd[2], const char *url,
}
strvec_push(&conn->args, cmd.buf);
conn->clean_on_exit = 1;
conn->wait_after_clean = 1;
if (start_command(conn))
die(_("unable to fork"));
+5 -1
View File
@@ -376,7 +376,7 @@ endif()
#function checks
set(function_checks
strcasestr memmem strlcpy strtoimax strtoumax strtoull
setenv mkdtemp poll pread memmem)
setenv mkdtemp poll pread memmem writev)
#unsetenv,hstrerror are incompatible with windows build
if(NOT WIN32)
@@ -421,6 +421,10 @@ if(NOT HAVE_MEMMEM)
list(APPEND compat_SOURCES compat/memmem.c)
endif()
if(NOT HAVE_WRITEV)
list(APPEND compat_SOURCES compat/writev.c)
endif()
if(NOT WIN32)
if(NOT HAVE_UNSETENV)
list(APPEND compat_SOURCES compat/unsetenv.c)
+277 -2
View File
@@ -608,6 +608,52 @@ struct emit_callback {
struct strbuf *header;
};
/*
* State for the line-range callback wrappers that sit between
* xdi_diff_outf() and fn_out_consume(). xdiff produces a normal,
* unfiltered diff; the wrappers intercept each hunk header and line,
* track post-image position, and forward only lines that fall within
* the requested ranges. Contiguous in-range lines are collected into
* range hunks and flushed with a synthetic @@ header so that
* fn_out_consume() sees well-formed unified-diff fragments.
*
* Removal lines ('-') cannot be classified by post-image position, so
* they are buffered in pending_rm until the next '+' or ' ' line
* reveals whether they precede an in-range line (flush into range hunk) or
* an out-of-range line (discard).
*/
struct line_range_callback {
xdiff_emit_line_fn orig_line_fn;
void *orig_cb_data;
const struct range_set *ranges; /* 0-based [start, end) */
unsigned int cur_range; /* index into the range_set */
/* Post/pre-image line counters (1-based, set from hunk headers) */
long lno_post;
long lno_pre;
/*
* Function name from most recent xdiff hunk header;
* size matches struct func_line.buf in xdiff/xemit.c.
*/
char func[80];
long funclen;
/* Range hunk being accumulated for the current range */
struct strbuf rhunk;
long rhunk_old_begin, rhunk_old_count;
long rhunk_new_begin, rhunk_new_count;
int rhunk_active;
int rhunk_has_changes; /* any '+' or '-' lines? */
/* Removal lines not yet known to be in-range */
struct strbuf pending_rm;
int pending_rm_count;
long pending_rm_pre_begin; /* pre-image line of first pending */
int ret; /* latched error from orig_line_fn */
};
static int count_lines(const char *data, int size)
{
int count, ch, completely_empty = 1, nl_just_seen = 0;
@@ -2493,6 +2539,188 @@ static int quick_consume(void *priv, char *line UNUSED, unsigned long len UNUSED
return 1;
}
static void discard_pending_rm(struct line_range_callback *s)
{
strbuf_reset(&s->pending_rm);
s->pending_rm_count = 0;
}
static void flush_rhunk(struct line_range_callback *s)
{
struct strbuf hdr = STRBUF_INIT;
const char *p, *end;
if (!s->rhunk_active || s->ret)
return;
/* Drain any pending removal lines into the range hunk */
if (s->pending_rm_count) {
strbuf_addbuf(&s->rhunk, &s->pending_rm);
s->rhunk_old_count += s->pending_rm_count;
s->rhunk_has_changes = 1;
discard_pending_rm(s);
}
/*
* Suppress context-only hunks: they contain no actual changes
* and would just be noise. This can happen when the inflated
* ctxlen causes xdiff to emit context covering a range that
* has no changes in this commit.
*/
if (!s->rhunk_has_changes) {
s->rhunk_active = 0;
strbuf_reset(&s->rhunk);
return;
}
strbuf_addf(&hdr, "@@ -%ld,%ld +%ld,%ld @@",
s->rhunk_old_begin, s->rhunk_old_count,
s->rhunk_new_begin, s->rhunk_new_count);
if (s->funclen > 0) {
strbuf_addch(&hdr, ' ');
strbuf_add(&hdr, s->func, s->funclen);
}
strbuf_addch(&hdr, '\n');
s->ret = s->orig_line_fn(s->orig_cb_data, hdr.buf, hdr.len);
strbuf_release(&hdr);
/*
* Replay buffered lines one at a time through fn_out_consume.
* The cast discards const because xdiff_emit_line_fn takes
* char *, though fn_out_consume does not modify the buffer.
*/
p = s->rhunk.buf;
end = p + s->rhunk.len;
while (!s->ret && p < end) {
const char *eol = memchr(p, '\n', end - p);
unsigned long line_len = eol ? (unsigned long)(eol - p + 1)
: (unsigned long)(end - p);
s->ret = s->orig_line_fn(s->orig_cb_data, (char *)p, line_len);
p += line_len;
}
s->rhunk_active = 0;
strbuf_reset(&s->rhunk);
}
static void line_range_hunk_fn(void *data,
long old_begin, long old_nr UNUSED,
long new_begin, long new_nr UNUSED,
const char *func, long funclen)
{
struct line_range_callback *s = data;
/*
* When count > 0, begin is 1-based. When count == 0, begin is
* adjusted down by 1 by xdl_emit_hunk_hdr(), but no lines of
* that type will arrive, so the value is unused.
*
* Any pending removal lines from the previous xdiff hunk are
* intentionally left in pending_rm: the line callback will
* flush or discard them when the next content line reveals
* whether the removals precede in-range content.
*/
s->lno_post = new_begin;
s->lno_pre = old_begin;
if (funclen > 0) {
if (funclen > (long)sizeof(s->func))
funclen = sizeof(s->func);
memcpy(s->func, func, funclen);
}
s->funclen = funclen;
}
static int line_range_line_fn(void *priv, char *line, unsigned long len)
{
struct line_range_callback *s = priv;
const struct range *cur;
long lno_0, cur_pre;
if (s->ret)
return s->ret;
if (line[0] == '-') {
if (!s->pending_rm_count)
s->pending_rm_pre_begin = s->lno_pre;
s->lno_pre++;
strbuf_add(&s->pending_rm, line, len);
s->pending_rm_count++;
return s->ret;
}
if (line[0] == '\\') {
if (s->pending_rm_count)
strbuf_add(&s->pending_rm, line, len);
else if (s->rhunk_active)
strbuf_add(&s->rhunk, line, len);
/* otherwise outside tracked range; drop silently */
return s->ret;
}
if (line[0] != '+' && line[0] != ' ')
BUG("unexpected diff line type '%c'", line[0]);
lno_0 = s->lno_post - 1;
cur_pre = s->lno_pre; /* save before advancing for context lines */
s->lno_post++;
if (line[0] == ' ')
s->lno_pre++;
/* Advance past ranges we've passed */
while (s->cur_range < s->ranges->nr &&
lno_0 >= s->ranges->ranges[s->cur_range].end) {
if (s->rhunk_active)
flush_rhunk(s);
discard_pending_rm(s);
s->cur_range++;
}
/* Past all ranges */
if (s->cur_range >= s->ranges->nr) {
discard_pending_rm(s);
return s->ret;
}
cur = &s->ranges->ranges[s->cur_range];
/* Before current range */
if (lno_0 < cur->start) {
discard_pending_rm(s);
return s->ret;
}
/* In range so start a new range hunk if needed */
if (!s->rhunk_active) {
s->rhunk_active = 1;
s->rhunk_has_changes = 0;
s->rhunk_new_begin = lno_0 + 1;
s->rhunk_old_begin = s->pending_rm_count
? s->pending_rm_pre_begin : cur_pre;
s->rhunk_old_count = 0;
s->rhunk_new_count = 0;
strbuf_reset(&s->rhunk);
}
/* Flush pending removals into range hunk */
if (s->pending_rm_count) {
strbuf_addbuf(&s->rhunk, &s->pending_rm);
s->rhunk_old_count += s->pending_rm_count;
s->rhunk_has_changes = 1;
discard_pending_rm(s);
}
strbuf_add(&s->rhunk, line, len);
s->rhunk_new_count++;
if (line[0] == '+')
s->rhunk_has_changes = 1;
else
s->rhunk_old_count++;
return s->ret;
}
static void pprint_rename(struct strbuf *name, const char *a, const char *b)
{
const char *old_name = a;
@@ -3592,7 +3820,8 @@ static void builtin_diff(const char *name_a,
const char *xfrm_msg,
int must_show_header,
struct diff_options *o,
int complete_rewrite)
int complete_rewrite,
const struct range_set *line_ranges)
{
mmfile_t mf1, mf2;
const char *lbl[2];
@@ -3833,6 +4062,52 @@ static void builtin_diff(const char *name_a,
*/
xdi_diff_outf(&mf1, &mf2, NULL, quick_consume,
&ecbdata, &xpp, &xecfg);
} else if (line_ranges) {
struct line_range_callback lr_state;
unsigned int i;
long max_span = 0;
memset(&lr_state, 0, sizeof(lr_state));
lr_state.orig_line_fn = fn_out_consume;
lr_state.orig_cb_data = &ecbdata;
lr_state.ranges = line_ranges;
strbuf_init(&lr_state.rhunk, 0);
strbuf_init(&lr_state.pending_rm, 0);
/*
* Inflate ctxlen so that all changes within
* any single range are merged into one xdiff
* hunk and the inter-change context is emitted.
* The callback clips back to range boundaries.
*
* The optimal ctxlen depends on where changes
* fall within the range, which is only known
* after xdiff runs; the max range span is the
* upper bound that guarantees correctness in a
* single pass.
*/
for (i = 0; i < line_ranges->nr; i++) {
long span = line_ranges->ranges[i].end -
line_ranges->ranges[i].start;
if (span > max_span)
max_span = span;
}
if (max_span > xecfg.ctxlen)
xecfg.ctxlen = max_span;
if (xdi_diff_outf(&mf1, &mf2,
line_range_hunk_fn,
line_range_line_fn,
&lr_state, &xpp, &xecfg))
die("unable to generate diff for %s",
one->path);
flush_rhunk(&lr_state);
if (lr_state.ret)
die("unable to generate diff for %s",
one->path);
strbuf_release(&lr_state.rhunk);
strbuf_release(&lr_state.pending_rm);
} else if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume,
&ecbdata, &xpp, &xecfg))
die("unable to generate diff for %s", one->path);
@@ -4674,7 +4949,7 @@ static void run_diff_cmd(const struct external_diff *pgm,
builtin_diff(name, other ? other : name,
one, two, xfrm_msg, must_show_header,
o, complete_rewrite);
o, complete_rewrite, p->line_ranges);
if (p->status == DIFF_STATUS_COPIED ||
p->status == DIFF_STATUS_RENAMED)
o->found_changes = 1;
+16
View File
@@ -19,6 +19,17 @@ struct userdiff_driver;
* in anything else.
*/
/* A range [start, end). Lines are numbered starting at 0. */
struct range {
long start, end;
};
/* A set of ranges. The ranges must always be disjoint and sorted. */
struct range_set {
unsigned int alloc, nr;
struct range *ranges;
};
/* We internally use unsigned short as the score value,
* and rely on an int capable to hold 32-bits. -B can take
* -Bmerge_score/break_score format and the two scores are
@@ -106,6 +117,11 @@ int diff_filespec_is_binary(struct repository *, struct diff_filespec *);
struct diff_filepair {
struct diff_filespec *one;
struct diff_filespec *two;
/*
* Tracked line ranges for -L filtering; borrowed from
* line_log_data and must not be freed.
*/
const struct range_set *line_ranges;
unsigned short int score;
char status; /* M C R A D U etc. (see Documentation/diff-format.adoc or DIFF_STATUS_* in diff.h) */
unsigned broken_pair : 1;
+10 -3
View File
@@ -51,7 +51,6 @@ static int server_supports_filtering;
static int advertise_sid;
static struct shallow_lock shallow_lock;
static const char *alternate_shallow_file;
static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;
static struct strbuf fsck_msg_types = STRBUF_INIT;
static struct string_list uri_protocols = STRING_LIST_INIT_DUP;
@@ -145,7 +144,7 @@ static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
if (commit) {
if (mark_tags_complete_and_check_obj_db) {
if (!odb_has_object(the_repository->objects, oid,
HAS_OBJECT_RECHECK_PACKED))
ODB_HAS_OBJECT_RECHECK_PACKED))
die_in_commit_graph_only(oid);
}
return commit;
@@ -1096,6 +1095,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
struct shallow_info *si,
struct string_list *pack_lockfiles)
{
struct fsck_options fsck_options = { 0 };
struct repository *r = the_repository;
struct ref *ref = copy_ref_list(orig_ref);
struct object_id oid;
@@ -1224,6 +1224,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
alternate_shallow_file = setup_temporary_shallow(si->shallow);
} else
alternate_shallow_file = NULL;
fsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES);
if (get_pack(args, fd, pack_lockfiles, NULL, sought, nr_sought,
&fsck_options.gitmodules_found))
die(_("git fetch-pack: fetch failed."));
@@ -1231,6 +1233,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
die("fsck failed");
all_done:
fsck_options_clear(&fsck_options);
if (negotiator)
negotiator->release(negotiator);
return ref;
@@ -1650,6 +1653,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct string_list *pack_lockfiles)
{
struct repository *r = the_repository;
struct fsck_options fsck_options;
struct ref *ref = copy_ref_list(orig_ref);
enum fetch_state state = FETCH_CHECK_LOCAL;
struct oidset common = OIDSET_INIT;
@@ -1667,6 +1671,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct strvec index_pack_args = STRVEC_INIT;
const char *promisor_remote_config;
fsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_MISSING_GITMODULES);
if (server_feature_v2("promisor-remote", &promisor_remote_config))
promisor_remote_reply(promisor_remote_config, NULL);
@@ -1878,6 +1884,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
if (negotiator)
negotiator->release(negotiator);
fsck_options_clear(&fsck_options);
oidset_clear(&common);
return ref;
}
@@ -2009,7 +2016,7 @@ static void update_shallow(struct fetch_pack_args *args,
struct object_id *oid = si->shallow->oid;
for (i = 0; i < si->shallow->nr; i++)
if (odb_has_object(the_repository->objects, &oid[i],
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
oid_array_append(&extra, &oid[i]);
if (extra.nr) {
setup_alternate_shallow(&shallow_lock,
+61 -15
View File
@@ -1,5 +1,3 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
#include "date.h"
#include "dir.h"
@@ -207,7 +205,7 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values)
if (equal == len)
die("skiplist requires a path");
oidset_parse_file(&options->skip_oids, buf + equal + 1,
the_repository->hash_algo);
options->repo->hash_algo);
buf += len + 1;
continue;
}
@@ -360,7 +358,7 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
int res = 0;
const char *name;
if (repo_parse_tree(the_repository, tree))
if (repo_parse_tree(options->repo, tree))
return -1;
name = fsck_get_object_name(options, &tree->object.oid);
@@ -375,14 +373,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
continue;
if (S_ISDIR(entry.mode)) {
obj = (struct object *)lookup_tree(the_repository, &entry.oid);
obj = (struct object *)lookup_tree(options->repo, &entry.oid);
if (name && obj)
fsck_put_object_name(options, &entry.oid, "%s%s/",
name, entry.path);
result = options->walk(obj, OBJ_TREE, data, options);
}
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
obj = (struct object *)lookup_blob(the_repository, &entry.oid);
obj = (struct object *)lookup_blob(options->repo, &entry.oid);
if (name && obj)
fsck_put_object_name(options, &entry.oid, "%s%s",
name, entry.path);
@@ -409,7 +407,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
int result;
const char *name;
if (repo_parse_commit(the_repository, commit))
if (repo_parse_commit(options->repo, commit))
return -1;
name = fsck_get_object_name(options, &commit->object.oid);
@@ -417,7 +415,7 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
fsck_put_object_name(options, get_commit_tree_oid(commit),
"%s:", name);
result = options->walk((struct object *) repo_get_commit_tree(the_repository, commit),
result = options->walk((struct object *) repo_get_commit_tree(options->repo, commit),
OBJ_TREE, data, options);
if (result < 0)
return result;
@@ -474,7 +472,7 @@ static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *optio
{
const char *name = fsck_get_object_name(options, &tag->object.oid);
if (parse_tag(the_repository, tag))
if (parse_tag(options->repo, tag))
return -1;
if (name)
fsck_put_object_name(options, &tag->tagged->oid, "%s", name);
@@ -487,7 +485,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
return -1;
if (obj->type == OBJ_NONE)
parse_object(the_repository, &obj->oid);
parse_object(options->repo, &obj->oid);
switch (obj->type) {
case OBJ_BLOB:
@@ -970,14 +968,14 @@ static int fsck_commit(const struct object_id *oid,
if (buffer >= buffer_end || !skip_prefix(buffer, "tree ", &buffer))
return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') {
if (parse_oid_hex_algop(buffer, &tree_oid, &p, options->repo->hash_algo) || *p != '\n') {
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
if (err)
return err;
}
buffer = p + 1;
while (buffer < buffer_end && skip_prefix(buffer, "parent ", &buffer)) {
if (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\n') {
if (parse_oid_hex_algop(buffer, &parent_oid, &p, options->repo->hash_algo) || *p != '\n') {
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
if (err)
return err;
@@ -1044,7 +1042,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
goto done;
}
if (parse_oid_hex(buffer, tagged_oid, &p) || *p != '\n') {
if (parse_oid_hex_algop(buffer, tagged_oid, &p, options->repo->hash_algo) || *p != '\n') {
ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
if (ret)
goto done;
@@ -1336,9 +1334,9 @@ static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,
if (oidset_contains(blobs_done, oid))
continue;
buf = odb_read_object(the_repository->objects, oid, &type, &size);
buf = odb_read_object(options->repo->objects, oid, &type, &size);
if (!buf) {
if (is_promisor_object(the_repository, oid))
if (is_promisor_object(options->repo, oid))
continue;
ret |= report(options,
oid, OBJ_BLOB, msg_missing,
@@ -1380,6 +1378,54 @@ bool fsck_has_queued_checks(struct fsck_options *options)
!oidset_equal(&options->gitattributes_found, &options->gitattributes_done);
}
void fsck_options_init(struct fsck_options *options,
struct repository *repo,
enum fsck_options_type type)
{
static const struct fsck_options defaults[] = {
[FSCK_OPTIONS_DEFAULT] = {
.skip_oids = OIDSET_INIT,
.gitmodules_found = OIDSET_INIT,
.gitmodules_done = OIDSET_INIT,
.gitattributes_found = OIDSET_INIT,
.gitattributes_done = OIDSET_INIT,
.error_func = fsck_objects_error_function
},
[FSCK_OPTIONS_STRICT] = {
.strict = 1,
.gitmodules_found = OIDSET_INIT,
.gitmodules_done = OIDSET_INIT,
.gitattributes_found = OIDSET_INIT,
.gitattributes_done = OIDSET_INIT,
.error_func = fsck_objects_error_function,
},
[FSCK_OPTIONS_MISSING_GITMODULES] = {
.strict = 1,
.gitmodules_found = OIDSET_INIT,
.gitmodules_done = OIDSET_INIT,
.gitattributes_found = OIDSET_INIT,
.gitattributes_done = OIDSET_INIT,
.error_func = fsck_objects_error_cb_print_missing_gitmodules,
},
[FSCK_OPTIONS_REFS] = {
.error_func = fsck_refs_error_function,
},
};
switch (type) {
case FSCK_OPTIONS_DEFAULT:
case FSCK_OPTIONS_STRICT:
case FSCK_OPTIONS_MISSING_GITMODULES:
case FSCK_OPTIONS_REFS:
memcpy(options, &defaults[type], sizeof(*options));
break;
default:
BUG("unknown fsck options type %d", type);
}
options->repo = repo;
}
void fsck_options_clear(struct fsck_options *options)
{
free(options->msg_type);
+14 -28
View File
@@ -166,7 +166,10 @@ struct fsck_ref_report {
const char *path;
};
struct repository;
struct fsck_options {
struct repository *repo;
fsck_walk_func walk;
fsck_error error_func;
unsigned strict;
@@ -180,34 +183,6 @@ struct fsck_options {
kh_oid_map_t *object_names;
};
#define FSCK_OPTIONS_DEFAULT { \
.skip_oids = OIDSET_INIT, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
.error_func = fsck_objects_error_function \
}
#define FSCK_OPTIONS_STRICT { \
.strict = 1, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
.error_func = fsck_objects_error_function, \
}
#define FSCK_OPTIONS_MISSING_GITMODULES { \
.strict = 1, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
.error_func = fsck_objects_error_cb_print_missing_gitmodules, \
}
#define FSCK_REFS_OPTIONS_DEFAULT { \
.error_func = fsck_refs_error_function, \
}
/* descend in all linked child objects
* the return value is:
* -1 error in processing the object
@@ -255,6 +230,17 @@ int fsck_finish(struct fsck_options *options);
*/
bool fsck_has_queued_checks(struct fsck_options *options);
enum fsck_options_type {
FSCK_OPTIONS_DEFAULT,
FSCK_OPTIONS_STRICT,
FSCK_OPTIONS_MISSING_GITMODULES,
FSCK_OPTIONS_REFS,
};
void fsck_options_init(struct fsck_options *options,
struct repository *repo,
enum fsck_options_type type);
/*
* Clear the fsck_options struct, freeing any allocated memory.
*/
+2
View File
@@ -1164,6 +1164,8 @@ int parse_sign_mode(const char *arg, enum sign_mode *mode, const char **keyid)
*mode = SIGN_WARN_STRIP;
} else if (!strcmp(arg, "strip")) {
*mode = SIGN_STRIP;
} else if (!strcmp(arg, "abort-if-invalid")) {
*mode = SIGN_ABORT_IF_INVALID;
} else if (!strcmp(arg, "strip-if-invalid")) {
*mode = SIGN_STRIP_IF_INVALID;
} else if (!strcmp(arg, "sign-if-invalid")) {
+1
View File
@@ -115,6 +115,7 @@ void print_signature_buffer(const struct signature_check *sigc,
/* Modes for --signed-tags=<mode> and --signed-commits=<mode> options. */
enum sign_mode {
SIGN_ABORT,
SIGN_ABORT_IF_INVALID,
SIGN_WARN_VERBATIM,
SIGN_VERBATIM,
SIGN_WARN_STRIP,
+18
View File
@@ -317,3 +317,21 @@ const struct git_hash_algo *unsafe_hash_algo(const struct git_hash_algo *algop)
/* Otherwise use the default one. */
return algop;
}
unsigned oid_common_prefix_hexlen(const struct object_id *a,
const struct object_id *b)
{
unsigned rawsz = hash_algos[a->algo].rawsz;
for (unsigned i = 0; i < rawsz; i++) {
if (a->hash[i] == b->hash[i])
continue;
if ((a->hash[i] ^ b->hash[i]) & 0xf0)
return i * 2;
else
return i * 2 + 1;
}
return rawsz * 2;
}
+3
View File
@@ -396,6 +396,9 @@ static inline int oideq(const struct object_id *oid1, const struct object_id *oi
return !memcmp(oid1->hash, oid2->hash, GIT_MAX_RAWSZ);
}
unsigned oid_common_prefix_hexlen(const struct object_id *a,
const struct object_id *b);
static inline void oidcpy(struct object_id *dst, const struct object_id *src)
{
memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
+4 -4
View File
@@ -1449,7 +1449,7 @@ static void one_remote_ref(const char *refname)
*/
if (repo->can_update_info_refs &&
!odb_has_object(the_repository->objects, &ref->old_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR)) {
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR)) {
obj = lookup_unknown_object(the_repository, &ref->old_oid);
fprintf(stderr, " fetch %s for %s\n",
oid_to_hex(&ref->old_oid), refname);
@@ -1655,7 +1655,7 @@ static int delete_remote_branch(const char *pattern, int force)
if (is_null_oid(&head_oid))
return error("Unable to resolve remote HEAD");
if (!odb_has_object(the_repository->objects, &head_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", oid_to_hex(&head_oid));
/* Remote branch must resolve to a known object */
@@ -1663,7 +1663,7 @@ static int delete_remote_branch(const char *pattern, int force)
return error("Unable to resolve remote branch %s",
remote_ref->name);
if (!odb_has_object(the_repository->objects, &remote_ref->old_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
return error("Remote branch %s resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", remote_ref->name, oid_to_hex(&remote_ref->old_oid));
/* Remote branch must be an ancestor of remote HEAD */
@@ -1886,7 +1886,7 @@ int cmd_main(int argc, const char **argv)
!is_null_oid(&ref->old_oid) &&
!ref->force) {
if (!odb_has_object(the_repository->objects, &ref->old_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR) ||
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR) ||
!ref_newer(&ref->peer_ref->new_oid,
&ref->old_oid)) {
/*
+2 -2
View File
@@ -139,7 +139,7 @@ static int fill_active_slot(void *data UNUSED)
obj_req = list_entry(pos, struct object_request, node);
if (obj_req->state == WAITING) {
if (odb_has_object(the_repository->objects, &obj_req->oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
obj_req->state = COMPLETE;
else {
start_object_request(obj_req);
@@ -495,7 +495,7 @@ static int fetch_object(struct walker *walker, const struct object_id *oid)
return error("Couldn't find request for %s in the queue", hex);
if (odb_has_object(the_repository->objects, &obj_req->oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR)) {
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR)) {
if (obj_req->req)
abort_http_object_request(&obj_req->req);
abort_object_request(obj_req);
+36 -162
View File
@@ -858,173 +858,33 @@ static void queue_diffs(struct line_log_data *range,
diff_queue_clear(&diff_queued_diff);
diff_tree_oid(parent_tree_oid, tree_oid, "", opt);
if (opt->detect_rename && diff_might_be_rename()) {
/* must look at the full tree diff to detect renames */
clear_pathspec(&opt->pathspec);
diff_queue_clear(&diff_queued_diff);
struct diff_options rename_opts;
diff_tree_oid(parent_tree_oid, tree_oid, "", opt);
/*
* Build a private diff_options for rename detection so
* that any user-specified options on the original opts
* (e.g. pickaxe) cannot discard diff pairs needed for
* rename tracking. Similar to blame's find_rename().
*/
repo_diff_setup(opt->repo, &rename_opts);
rename_opts.flags.recursive = 1;
rename_opts.detect_rename = opt->detect_rename;
rename_opts.rename_score = opt->rename_score;
rename_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_setup_done(&rename_opts);
/* must look at the full tree diff to detect renames */
diff_queue_clear(&diff_queued_diff);
diff_tree_oid(parent_tree_oid, tree_oid, "", &rename_opts);
filter_diffs_for_paths(range, 1);
diffcore_std(opt);
diffcore_std(&rename_opts);
filter_diffs_for_paths(range, 0);
diff_free(&rename_opts);
}
move_diff_queue(queue, &diff_queued_diff);
}
static char *get_nth_line(long line, unsigned long *ends, void *data)
{
if (line == 0)
return (char *)data;
else
return (char *)data + ends[line] + 1;
}
static void print_line(const char *prefix, char first,
long line, unsigned long *ends, void *data,
const char *color, const char *reset, FILE *file)
{
char *begin = get_nth_line(line, ends, data);
char *end = get_nth_line(line+1, ends, data);
int had_nl = 0;
if (end > begin && end[-1] == '\n') {
end--;
had_nl = 1;
}
fputs(prefix, file);
fputs(color, file);
putc(first, file);
fwrite(begin, 1, end-begin, file);
fputs(reset, file);
putc('\n', file);
if (!had_nl)
fputs("\\ No newline at end of file\n", file);
}
static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *range)
{
unsigned int i, j = 0;
long p_lines, t_lines;
unsigned long *p_ends = NULL, *t_ends = NULL;
struct diff_filepair *pair = range->pair;
struct diff_ranges *diff = &range->diff;
struct diff_options *opt = &rev->diffopt;
const char *prefix = diff_line_prefix(opt);
const char *c_reset = diff_get_color(opt->use_color, DIFF_RESET);
const char *c_frag = diff_get_color(opt->use_color, DIFF_FRAGINFO);
const char *c_meta = diff_get_color(opt->use_color, DIFF_METAINFO);
const char *c_old = diff_get_color(opt->use_color, DIFF_FILE_OLD);
const char *c_new = diff_get_color(opt->use_color, DIFF_FILE_NEW);
const char *c_context = diff_get_color(opt->use_color, DIFF_CONTEXT);
if (!pair || !diff)
goto out;
if (pair->one->oid_valid)
fill_line_ends(rev->diffopt.repo, pair->one, &p_lines, &p_ends);
fill_line_ends(rev->diffopt.repo, pair->two, &t_lines, &t_ends);
fprintf(opt->file, "%s%sdiff --git a/%s b/%s%s\n", prefix, c_meta, pair->one->path, pair->two->path, c_reset);
fprintf(opt->file, "%s%s--- %s%s%s\n", prefix, c_meta,
pair->one->oid_valid ? "a/" : "",
pair->one->oid_valid ? pair->one->path : "/dev/null",
c_reset);
fprintf(opt->file, "%s%s+++ b/%s%s\n", prefix, c_meta, pair->two->path, c_reset);
for (i = 0; i < range->ranges.nr; i++) {
long p_start, p_end;
long t_start = range->ranges.ranges[i].start;
long t_end = range->ranges.ranges[i].end;
long t_cur = t_start;
unsigned int j_last;
/*
* If a diff range touches multiple line ranges, then all
* those line ranges should be shown, so take a step back if
* the current line range is still in the previous diff range
* (even if only partially).
*/
if (j > 0 && diff->target.ranges[j-1].end > t_start)
j--;
while (j < diff->target.nr && diff->target.ranges[j].end < t_start)
j++;
if (j == diff->target.nr || diff->target.ranges[j].start >= t_end)
continue;
/* Scan ahead to determine the last diff that falls in this range */
j_last = j;
while (j_last < diff->target.nr && diff->target.ranges[j_last].start < t_end)
j_last++;
if (j_last > j)
j_last--;
/*
* Compute parent hunk headers: we know that the diff
* has the correct line numbers (but not all hunks).
* So it suffices to shift the start/end according to
* the line numbers of the first/last hunk(s) that
* fall in this range.
*/
if (t_start < diff->target.ranges[j].start)
p_start = diff->parent.ranges[j].start - (diff->target.ranges[j].start-t_start);
else
p_start = diff->parent.ranges[j].start;
if (t_end > diff->target.ranges[j_last].end)
p_end = diff->parent.ranges[j_last].end + (t_end-diff->target.ranges[j_last].end);
else
p_end = diff->parent.ranges[j_last].end;
if (!p_start && !p_end) {
p_start = -1;
p_end = -1;
}
/* Now output a diff hunk for this range */
fprintf(opt->file, "%s%s@@ -%ld,%ld +%ld,%ld @@%s\n",
prefix, c_frag,
p_start+1, p_end-p_start, t_start+1, t_end-t_start,
c_reset);
while (j < diff->target.nr && diff->target.ranges[j].start < t_end) {
int k;
for (; t_cur < diff->target.ranges[j].start; t_cur++)
print_line(prefix, ' ', t_cur, t_ends, pair->two->data,
c_context, c_reset, opt->file);
for (k = diff->parent.ranges[j].start; k < diff->parent.ranges[j].end; k++)
print_line(prefix, '-', k, p_ends, pair->one->data,
c_old, c_reset, opt->file);
for (; t_cur < diff->target.ranges[j].end && t_cur < t_end; t_cur++)
print_line(prefix, '+', t_cur, t_ends, pair->two->data,
c_new, c_reset, opt->file);
j++;
}
for (; t_cur < t_end; t_cur++)
print_line(prefix, ' ', t_cur, t_ends, pair->two->data,
c_context, c_reset, opt->file);
}
out:
free(p_ends);
free(t_ends);
}
/*
* NEEDSWORK: manually building a diff here is not the Right
* Thing(tm). log -L should be built into the diff pipeline.
*/
static void dump_diff_hacky(struct rev_info *rev, struct line_log_data *range)
{
const char *prefix = diff_line_prefix(&rev->diffopt);
fprintf(rev->diffopt.file, "%s\n", prefix);
while (range) {
dump_diff_hacky_one(rev, range);
range = range->next;
}
}
/*
* Unlike most other functions, this destructively operates on
* 'range'.
@@ -1088,7 +948,7 @@ static int process_diff_filepair(struct rev_info *rev,
static struct diff_filepair *diff_filepair_dup(struct diff_filepair *pair)
{
struct diff_filepair *new_filepair = xmalloc(sizeof(struct diff_filepair));
struct diff_filepair *new_filepair = xcalloc(1, sizeof(struct diff_filepair));
new_filepair->one = pair->one;
new_filepair->two = pair->two;
new_filepair->one->count++;
@@ -1146,11 +1006,25 @@ static int process_all_files(struct line_log_data **range_out,
int line_log_print(struct rev_info *rev, struct commit *commit)
{
show_log(rev);
if (!(rev->diffopt.output_format & DIFF_FORMAT_NO_OUTPUT)) {
struct line_log_data *range = lookup_line_range(rev, commit);
dump_diff_hacky(rev, range);
struct line_log_data *r;
const char *prefix = diff_line_prefix(&rev->diffopt);
fprintf(rev->diffopt.file, "%s\n", prefix);
for (r = range; r; r = r->next) {
if (r->pair) {
struct diff_filepair *p =
diff_filepair_dup(r->pair);
p->line_ranges = &r->ranges;
diff_q(&diff_queued_diff, p);
}
}
diffcore_std(&rev->diffopt);
diff_flush(&rev->diffopt);
}
return 1;
}
+2 -12
View File
@@ -1,22 +1,12 @@
#ifndef LINE_LOG_H
#define LINE_LOG_H
#include "diffcore.h" /* struct range, struct range_set */
struct rev_info;
struct commit;
struct string_list;
/* A range [start,end]. Lines are numbered starting at 0, and the
* ranges include start but exclude end. */
struct range {
long start, end;
};
/* A set of ranges. The ranges must always be disjoint and sorted. */
struct range_set {
unsigned int alloc, nr;
struct range *ranges;
};
/* A diff, encoded as the set of pre- and post-image ranges where the
* files differ. A pair of ranges corresponds to a hunk. */
struct diff_ranges {
+1 -1
View File
@@ -75,7 +75,7 @@ static void process_blob(struct traversal_context *ctx,
*/
if (ctx->revs->exclude_promisor_objects &&
!odb_has_object(the_repository->objects, &obj->oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR) &&
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR) &&
is_promisor_object(ctx->revs->repo, &obj->oid))
return;
+1 -1
View File
@@ -796,7 +796,7 @@ static int prune_notes_helper(const struct object_id *object_oid,
struct note_delete_list *n;
if (odb_has_object(the_repository->objects, object_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
return 0; /* nothing to do for this note */
/* failed to find object => prune this note */
+121 -22
View File
@@ -33,6 +33,9 @@
/* The maximum size for an object header. */
#define MAX_HEADER_LEN 32
static struct oidtree *odb_source_loose_cache(struct odb_source *source,
const struct object_id *oid);
static int get_conv_flags(unsigned flags)
{
if (flags & INDEX_RENORMALIZE)
@@ -906,7 +909,7 @@ static int start_loose_object_common(struct odb_source *source,
fd = create_tmpfile(source->odb->repo, tmp_file, filename);
if (fd < 0) {
if (flags & WRITE_OBJECT_SILENT)
if (flags & ODB_WRITE_OBJECT_SILENT)
return -1;
else if (errno == EACCES)
return error(_("insufficient permission for adding "
@@ -1039,7 +1042,7 @@ static int write_loose_object(struct odb_source *source,
utb.actime = mtime;
utb.modtime = mtime;
if (utime(tmp_file.buf, &utb) < 0 &&
!(flags & WRITE_OBJECT_SILENT))
!(flags & ODB_WRITE_OBJECT_SILENT))
warning_errno(_("failed utime() on %s"), tmp_file.buf);
}
@@ -1166,7 +1169,8 @@ cleanup:
int odb_source_loose_write_object(struct odb_source *source,
const void *buf, unsigned long len,
enum object_type type, struct object_id *oid,
struct object_id *compat_oid_in, unsigned flags)
struct object_id *compat_oid_in,
enum odb_write_object_flags flags)
{
const struct git_hash_algo *algo = source->odb->repo->hash_algo;
const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;
@@ -1279,8 +1283,9 @@ static int index_mem(struct index_state *istate,
}
}
if (flags & INDEX_FORMAT_CHECK) {
struct fsck_options opts = FSCK_OPTIONS_DEFAULT;
struct fsck_options opts;
fsck_options_init(&opts, the_repository, FSCK_OPTIONS_DEFAULT);
opts.strict = 1;
opts.error_func = hash_format_check_report;
if (fsck_buffer(null_oid(istate->repo->hash_algo), type, buf, size, &opts))
@@ -1374,7 +1379,7 @@ static int already_written(struct odb_transaction_files *transaction,
{
/* The object may already exist in the repository */
if (odb_has_object(transaction->base.source->odb, oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
return 1;
/* Might want to keep the list sorted */
@@ -1637,6 +1642,34 @@ static int index_blob_packfile_transaction(struct odb_transaction_files *transac
return 0;
}
static int hash_blob_stream(const struct git_hash_algo *hash_algo,
struct object_id *result_oid, int fd, size_t size)
{
unsigned char buf[16384];
struct git_hash_ctx ctx;
unsigned header_len;
header_len = format_object_header((char *)buf, sizeof(buf),
OBJ_BLOB, size);
hash_algo->init_fn(&ctx);
git_hash_update(&ctx, buf, header_len);
while (size) {
size_t rsize = size < sizeof(buf) ? size : sizeof(buf);
ssize_t read_result = read_in_full(fd, buf, rsize);
if ((read_result < 0) || ((size_t)read_result != rsize))
return -1;
git_hash_update(&ctx, buf, rsize);
size -= read_result;
}
git_hash_final_oid(result_oid, &ctx);
return 0;
}
int index_fd(struct index_state *istate, struct object_id *oid,
int fd, struct stat *st,
enum object_type type, const char *path, unsigned flags)
@@ -1658,18 +1691,23 @@ int index_fd(struct index_state *istate, struct object_id *oid,
ret = index_core(istate, oid, fd, xsize_t(st->st_size),
type, path, flags);
} else {
struct object_database *odb = the_repository->objects;
struct odb_transaction_files *files_transaction;
struct odb_transaction *transaction;
if (flags & INDEX_WRITE_OBJECT) {
struct object_database *odb = the_repository->objects;
struct odb_transaction_files *files_transaction;
struct odb_transaction *transaction;
transaction = odb_transaction_begin(odb);
files_transaction = container_of(odb->transaction,
struct odb_transaction_files,
base);
ret = index_blob_packfile_transaction(files_transaction, oid, fd,
xsize_t(st->st_size),
path, flags);
odb_transaction_commit(transaction);
transaction = odb_transaction_begin(odb);
files_transaction = container_of(odb->transaction,
struct odb_transaction_files,
base);
ret = index_blob_packfile_transaction(files_transaction, oid, fd,
xsize_t(st->st_size),
path, flags);
odb_transaction_commit(transaction);
} else {
ret = hash_blob_stream(the_repository->hash_algo, oid,
fd, xsize_t(st->st_size));
}
}
close(fd);
@@ -1845,11 +1883,28 @@ static int for_each_object_wrapper_cb(const struct object_id *oid,
}
}
static int for_each_prefixed_object_wrapper_cb(const struct object_id *oid,
void *cb_data)
{
struct for_each_object_wrapper_data *data = cb_data;
if (data->request) {
struct object_info oi = *data->request;
if (odb_source_loose_read_object_info(data->source,
oid, &oi, 0) < 0)
return -1;
return data->cb(oid, &oi, data->cb_data);
} else {
return data->cb(oid, NULL, data->cb_data);
}
}
int odb_source_loose_for_each_object(struct odb_source *source,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags)
const struct odb_for_each_object_options *opts)
{
struct for_each_object_wrapper_data data = {
.source = source,
@@ -1859,11 +1914,16 @@ int odb_source_loose_for_each_object(struct odb_source *source,
};
/* There are no loose promisor objects, so we can return immediately. */
if ((flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
return 0;
if ((flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
return 0;
if (opts->prefix)
return oidtree_each(odb_source_loose_cache(source, opts->prefix),
opts->prefix, opts->prefix_hex_len,
for_each_prefixed_object_wrapper_cb, &data);
return for_each_loose_file_in_source(source, for_each_object_wrapper_cb,
NULL, NULL, &data);
}
@@ -1914,9 +1974,10 @@ int odb_source_loose_count_objects(struct odb_source *source,
*out = count * 256;
ret = 0;
} else {
struct odb_for_each_object_options opts = { 0 };
*out = 0;
ret = odb_source_loose_for_each_object(source, NULL, count_loose_object,
out, 0);
out, &opts);
}
out:
@@ -1926,6 +1987,44 @@ out:
return ret;
}
struct find_abbrev_len_data {
const struct object_id *oid;
unsigned len;
};
static int find_abbrev_len_cb(const struct object_id *oid,
struct object_info *oi UNUSED,
void *cb_data)
{
struct find_abbrev_len_data *data = cb_data;
unsigned len = oid_common_prefix_hexlen(oid, data->oid);
if (len != hash_algos[oid->algo].hexsz && len >= data->len)
data->len = len + 1;
return 0;
}
int odb_source_loose_find_abbrev_len(struct odb_source *source,
const struct object_id *oid,
unsigned min_len,
unsigned *out)
{
struct odb_for_each_object_options opts = {
.prefix = oid,
.prefix_hex_len = min_len,
};
struct find_abbrev_len_data data = {
.oid = oid,
.len = min_len,
};
int ret;
ret = odb_source_loose_for_each_object(source, NULL, find_abbrev_len_cb,
&data, &opts);
*out = data.len;
return ret;
}
static int append_loose_object(const struct object_id *oid,
const char *path UNUSED,
void *data)
@@ -1934,8 +2033,8 @@ static int append_loose_object(const struct object_id *oid,
return 0;
}
struct oidtree *odb_source_loose_cache(struct odb_source *source,
const struct object_id *oid)
static struct oidtree *odb_source_loose_cache(struct odb_source *source,
const struct object_id *oid)
{
struct odb_source_files *files = odb_source_files_downcast(source);
int subdir_nr = oid->hash[0];
+15 -9
View File
@@ -68,19 +68,13 @@ int odb_source_loose_freshen_object(struct odb_source *source,
int odb_source_loose_write_object(struct odb_source *source,
const void *buf, unsigned long len,
enum object_type type, struct object_id *oid,
struct object_id *compat_oid_in, unsigned flags);
struct object_id *compat_oid_in,
enum odb_write_object_flags flags);
int odb_source_loose_write_stream(struct odb_source *source,
struct odb_write_stream *stream, size_t len,
struct object_id *oid);
/*
* Populate and return the loose object cache array corresponding to the
* given object ID.
*/
struct oidtree *odb_source_loose_cache(struct odb_source *source,
const struct object_id *oid);
/*
* Put in `buf` the name of the file in the local object database that
* would be used to store a loose object with the specified oid.
@@ -137,7 +131,7 @@ int odb_source_loose_for_each_object(struct odb_source *source,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags);
const struct odb_for_each_object_options *opts);
/*
* Count the number of loose objects in this source.
@@ -153,6 +147,18 @@ int odb_source_loose_count_objects(struct odb_source *source,
enum odb_count_objects_flags flags,
unsigned long *out);
/*
* Find the shortest unique prefix for the given object ID, where `min_len` is
* the minimum length that the prefix should have.
*
* Returns 0 on success, in which case the computed length will be written to
* `out`. Otherwise, a negative error code is returned.
*/
int odb_source_loose_find_abbrev_len(struct odb_source *source,
const struct object_id *oid,
unsigned min_len,
unsigned *out);
/**
* format_object_header() is a thin wrapper around s xsnprintf() that
* writes the initial "<type> <obj-len>" part of the loose object
+74 -363
View File
@@ -15,11 +15,9 @@
#include "refs.h"
#include "remote.h"
#include "dir.h"
#include "odb.h"
#include "oid-array.h"
#include "oidtree.h"
#include "packfile.h"
#include "pretty.h"
#include "object-file.h"
#include "read-cache-ll.h"
#include "repo-settings.h"
#include "repository.h"
@@ -49,30 +47,29 @@ struct disambiguate_state {
unsigned candidate_ok:1;
unsigned disambiguate_fn_used:1;
unsigned ambiguous:1;
unsigned always_call_fn:1;
};
static void update_candidates(struct disambiguate_state *ds, const struct object_id *current)
static int update_disambiguate_state(const struct object_id *current,
struct object_info *oi UNUSED,
void *cb_data)
{
struct disambiguate_state *ds = cb_data;
/* The hash algorithm of current has already been filtered */
if (ds->always_call_fn) {
ds->ambiguous = ds->fn(ds->repo, current, ds->cb_data) ? 1 : 0;
return;
}
if (!ds->candidate_exists) {
/* this is the first candidate */
oidcpy(&ds->candidate, current);
ds->candidate_exists = 1;
return;
return 0;
} else if (oideq(&ds->candidate, current)) {
/* the same as what we already have seen */
return;
return 0;
}
if (!ds->fn) {
/* cannot disambiguate between ds->candidate and current */
ds->ambiguous = 1;
return;
return ds->ambiguous;
}
if (!ds->candidate_checked) {
@@ -85,7 +82,7 @@ static void update_candidates(struct disambiguate_state *ds, const struct object
/* discard the candidate; we know it does not satisfy fn */
oidcpy(&ds->candidate, current);
ds->candidate_checked = 0;
return;
return 0;
}
/* if we reach this point, we know ds->candidate satisfies fn */
@@ -96,128 +93,12 @@ static void update_candidates(struct disambiguate_state *ds, const struct object
*/
ds->candidate_ok = 0;
ds->ambiguous = 1;
return ds->ambiguous;
}
/* otherwise, current can be discarded and candidate is still good */
}
static int match_hash(unsigned, const unsigned char *, const unsigned char *);
static enum cb_next match_prefix(const struct object_id *oid, void *arg)
{
struct disambiguate_state *ds = arg;
/* no need to call match_hash, oidtree_each did prefix match */
update_candidates(ds, oid);
return ds->ambiguous ? CB_BREAK : CB_CONTINUE;
}
static void find_short_object_filename(struct disambiguate_state *ds)
{
struct odb_source *source;
for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next)
oidtree_each(odb_source_loose_cache(source, &ds->bin_pfx),
&ds->bin_pfx, ds->len, match_prefix, ds);
}
static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
{
do {
if (*a != *b)
return 0;
a++;
b++;
len -= 2;
} while (len > 1);
if (len)
if ((*a ^ *b) & 0xf0)
return 0;
return 1;
}
static void unique_in_midx(struct multi_pack_index *m,
struct disambiguate_state *ds)
{
for (; m; m = m->base_midx) {
uint32_t num, i, first = 0;
const struct object_id *current = NULL;
int len = ds->len > ds->repo->hash_algo->hexsz ?
ds->repo->hash_algo->hexsz : ds->len;
if (!m->num_objects)
continue;
num = m->num_objects + m->num_objects_in_base;
bsearch_one_midx(&ds->bin_pfx, m, &first);
/*
* At this point, "first" is the location of the lowest
* object with an object name that could match
* "bin_pfx". See if we have 0, 1 or more objects that
* actually match(es).
*/
for (i = first; i < num && !ds->ambiguous; i++) {
struct object_id oid;
current = nth_midxed_object_oid(&oid, m, i);
if (!match_hash(len, ds->bin_pfx.hash, current->hash))
break;
update_candidates(ds, current);
}
}
}
static void unique_in_pack(struct packed_git *p,
struct disambiguate_state *ds)
{
uint32_t num, i, first = 0;
int len = ds->len > ds->repo->hash_algo->hexsz ?
ds->repo->hash_algo->hexsz : ds->len;
if (p->multi_pack_index)
return;
if (open_pack_index(p) || !p->num_objects)
return;
num = p->num_objects;
bsearch_pack(&ds->bin_pfx, p, &first);
/*
* At this point, "first" is the location of the lowest object
* with an object name that could match "bin_pfx". See if we have
* 0, 1 or more objects that actually match(es).
*/
for (i = first; i < num && !ds->ambiguous; i++) {
struct object_id oid;
nth_packed_object_id(&oid, p, i);
if (!match_hash(len, ds->bin_pfx.hash, oid.hash))
break;
update_candidates(ds, &oid);
}
}
static void find_short_packed_object(struct disambiguate_state *ds)
{
struct odb_source *source;
struct packed_git *p;
/* Skip, unless oids from the storage hash algorithm are wanted */
if (ds->bin_pfx.algo && (&hash_algos[ds->bin_pfx.algo] != ds->repo->hash_algo))
return;
odb_prepare_alternates(ds->repo->objects);
for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next) {
struct multi_pack_index *m = get_multi_pack_index(source);
if (m)
unique_in_midx(m, ds);
}
repo_for_each_pack(ds->repo, p) {
if (ds->ambiguous)
break;
unique_in_pack(p, ds);
}
return 0;
}
static int finish_object_disambiguation(struct disambiguate_state *ds,
@@ -348,41 +229,57 @@ int set_disambiguate_hint_config(const char *var, const char *value)
return error("unknown hint type for '%s': %s", var, value);
}
static int parse_oid_prefix(const char *name, int len,
const struct git_hash_algo *algo,
char *hex_out,
struct object_id *oid_out)
{
for (int i = 0; i < len; i++) {
unsigned char c = name[i];
unsigned char val;
if (c >= '0' && c <= '9') {
val = c - '0';
} else if (c >= 'a' && c <= 'f') {
val = c - 'a' + 10;
} else if (c >= 'A' && c <='F') {
val = c - 'A' + 10;
c -= 'A' - 'a';
} else {
return -1;
}
if (hex_out)
hex_out[i] = c;
if (oid_out) {
if (!(i & 1))
val <<= 4;
oid_out->hash[i >> 1] |= val;
}
}
if (hex_out)
hex_out[len] = '\0';
if (oid_out)
oid_out->algo = algo ? hash_algo_by_ptr(algo) : GIT_HASH_UNKNOWN;
return 0;
}
static int init_object_disambiguation(struct repository *r,
const char *name, int len,
const struct git_hash_algo *algo,
struct disambiguate_state *ds)
{
int i;
if (len < MINIMUM_ABBREV || len > GIT_MAX_HEXSZ)
return -1;
memset(ds, 0, sizeof(*ds));
for (i = 0; i < len ;i++) {
unsigned char c = name[i];
unsigned char val;
if (c >= '0' && c <= '9')
val = c - '0';
else if (c >= 'a' && c <= 'f')
val = c - 'a' + 10;
else if (c >= 'A' && c <='F') {
val = c - 'A' + 10;
c -= 'A' - 'a';
}
else
return -1;
ds->hex_pfx[i] = c;
if (!(i & 1))
val <<= 4;
ds->bin_pfx.hash[i >> 1] |= val;
}
if (parse_oid_prefix(name, len, algo, ds->hex_pfx, &ds->bin_pfx) < 0)
return -1;
ds->len = len;
ds->hex_pfx[len] = '\0';
ds->repo = r;
ds->bin_pfx.algo = algo ? hash_algo_by_ptr(algo) : GIT_HASH_UNKNOWN;
odb_prepare_alternates(r->objects);
return 0;
}
@@ -510,8 +407,8 @@ static int collect_ambiguous(const struct object_id *oid, void *data)
return 0;
}
static int repo_collect_ambiguous(struct repository *r UNUSED,
const struct object_id *oid,
static int repo_collect_ambiguous(const struct object_id *oid,
struct object_info *oi UNUSED,
void *data)
{
return collect_ambiguous(oid, data);
@@ -561,6 +458,7 @@ static enum get_oid_result get_short_oid(struct repository *r,
struct object_id *oid,
unsigned flags)
{
struct odb_for_each_object_options opts = { 0 };
int status;
struct disambiguate_state ds;
int quietly = !!(flags & GET_OID_QUIETLY);
@@ -588,8 +486,11 @@ static enum get_oid_result get_short_oid(struct repository *r,
else
ds.fn = default_disambiguate_hint;
find_short_object_filename(&ds);
find_short_packed_object(&ds);
opts.prefix = &ds.bin_pfx;
opts.prefix_hex_len = ds.len;
odb_for_each_object_ext(r->objects, NULL, update_disambiguate_state,
&ds, &opts);
status = finish_object_disambiguation(&ds, oid);
/*
@@ -599,8 +500,8 @@ static enum get_oid_result get_short_oid(struct repository *r,
*/
if (status == MISSING_OBJECT) {
odb_reprepare(r->objects);
find_short_object_filename(&ds);
find_short_packed_object(&ds);
odb_for_each_object_ext(r->objects, NULL, update_disambiguate_state,
&ds, &opts);
status = finish_object_disambiguation(&ds, oid);
}
@@ -648,169 +549,25 @@ int repo_for_each_abbrev(struct repository *r, const char *prefix,
const struct git_hash_algo *algo,
each_abbrev_fn fn, void *cb_data)
{
struct object_id prefix_oid = { 0 };
struct odb_for_each_object_options opts = {
.prefix = &prefix_oid,
.prefix_hex_len = strlen(prefix),
};
struct oid_array collect = OID_ARRAY_INIT;
struct disambiguate_state ds;
int ret;
if (init_object_disambiguation(r, prefix, strlen(prefix), algo, &ds) < 0)
if (parse_oid_prefix(prefix, opts.prefix_hex_len, algo, NULL, &prefix_oid) < 0)
return -1;
ds.always_call_fn = 1;
ds.fn = repo_collect_ambiguous;
ds.cb_data = &collect;
find_short_object_filename(&ds);
find_short_packed_object(&ds);
if (odb_for_each_object_ext(r->objects, NULL, repo_collect_ambiguous, &collect, &opts) < 0)
return -1;
ret = oid_array_for_each_unique(&collect, fn, cb_data);
oid_array_clear(&collect);
return ret;
}
/*
* Return the slot of the most-significant bit set in "val". There are various
* ways to do this quickly with fls() or __builtin_clzl(), but speed is
* probably not a big deal here.
*/
static unsigned msb(unsigned long val)
{
unsigned r = 0;
while (val >>= 1)
r++;
return r;
}
struct min_abbrev_data {
unsigned int init_len;
unsigned int cur_len;
char *hex;
struct repository *repo;
const struct object_id *oid;
};
static inline char get_hex_char_from_oid(const struct object_id *oid,
unsigned int pos)
{
static const char hex[] = "0123456789abcdef";
if ((pos & 1) == 0)
return hex[oid->hash[pos >> 1] >> 4];
else
return hex[oid->hash[pos >> 1] & 0xf];
}
static int extend_abbrev_len(const struct object_id *oid,
struct min_abbrev_data *mad)
{
unsigned int i = mad->init_len;
while (mad->hex[i] && mad->hex[i] == get_hex_char_from_oid(oid, i))
i++;
if (mad->hex[i] && i >= mad->cur_len)
mad->cur_len = i + 1;
return 0;
}
static int repo_extend_abbrev_len(struct repository *r UNUSED,
const struct object_id *oid,
void *cb_data)
{
return extend_abbrev_len(oid, cb_data);
}
static void find_abbrev_len_for_midx(struct multi_pack_index *m,
struct min_abbrev_data *mad)
{
for (; m; m = m->base_midx) {
int match = 0;
uint32_t num, first = 0;
struct object_id oid;
const struct object_id *mad_oid;
if (!m->num_objects)
continue;
num = m->num_objects + m->num_objects_in_base;
mad_oid = mad->oid;
match = bsearch_one_midx(mad_oid, m, &first);
/*
* first is now the position in the packfile where we
* would insert mad->hash if it does not exist (or the
* position of mad->hash if it does exist). Hence, we
* consider a maximum of two objects nearby for the
* abbreviation length.
*/
mad->init_len = 0;
if (!match) {
if (nth_midxed_object_oid(&oid, m, first))
extend_abbrev_len(&oid, mad);
} else if (first < num - 1) {
if (nth_midxed_object_oid(&oid, m, first + 1))
extend_abbrev_len(&oid, mad);
}
if (first > 0) {
if (nth_midxed_object_oid(&oid, m, first - 1))
extend_abbrev_len(&oid, mad);
}
mad->init_len = mad->cur_len;
}
}
static void find_abbrev_len_for_pack(struct packed_git *p,
struct min_abbrev_data *mad)
{
int match = 0;
uint32_t num, first = 0;
struct object_id oid;
const struct object_id *mad_oid;
if (p->multi_pack_index)
return;
if (open_pack_index(p) || !p->num_objects)
return;
num = p->num_objects;
mad_oid = mad->oid;
match = bsearch_pack(mad_oid, p, &first);
/*
* first is now the position in the packfile where we would insert
* mad->hash if it does not exist (or the position of mad->hash if
* it does exist). Hence, we consider a maximum of two objects
* nearby for the abbreviation length.
*/
mad->init_len = 0;
if (!match) {
if (!nth_packed_object_id(&oid, p, first))
extend_abbrev_len(&oid, mad);
} else if (first < num - 1) {
if (!nth_packed_object_id(&oid, p, first + 1))
extend_abbrev_len(&oid, mad);
}
if (first > 0) {
if (!nth_packed_object_id(&oid, p, first - 1))
extend_abbrev_len(&oid, mad);
}
mad->init_len = mad->cur_len;
}
static void find_abbrev_len_packed(struct min_abbrev_data *mad)
{
struct packed_git *p;
odb_prepare_alternates(mad->repo->objects);
for (struct odb_source *source = mad->repo->objects->sources; source; source = source->next) {
struct multi_pack_index *m = get_multi_pack_index(source);
if (m)
find_abbrev_len_for_midx(m, mad);
}
repo_for_each_pack(mad->repo, p)
find_abbrev_len_for_pack(p, mad);
}
void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,
const struct object_id *oid, int abbrev_len)
{
@@ -827,65 +584,19 @@ void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,
}
int repo_find_unique_abbrev_r(struct repository *r, char *hex,
const struct object_id *oid, int len)
const struct object_id *oid, int min_len)
{
const struct git_hash_algo *algo =
oid->algo ? &hash_algos[oid->algo] : r->hash_algo;
struct disambiguate_state ds;
struct min_abbrev_data mad;
struct object_id oid_ret;
const unsigned hexsz = algo->hexsz;
unsigned len;
if (len < 0) {
unsigned long count;
if (odb_count_objects(r->objects, ODB_COUNT_OBJECTS_APPROXIMATE, &count) < 0)
count = 0;
/*
* Add one because the MSB only tells us the highest bit set,
* not including the value of all the _other_ bits (so "15"
* is only one off of 2^4, but the MSB is the 3rd bit.
*/
len = msb(count) + 1;
/*
* We now know we have on the order of 2^len objects, which
* expects a collision at 2^(len/2). But we also care about hex
* chars, not bits, and there are 4 bits per hex. So all
* together we need to divide by 2 and round up.
*/
len = DIV_ROUND_UP(len, 2);
/*
* For very small repos, we stick with our regular fallback.
*/
if (len < FALLBACK_DEFAULT_ABBREV)
len = FALLBACK_DEFAULT_ABBREV;
}
if (odb_find_abbrev_len(r->objects, oid, min_len, &len) < 0)
len = algo->hexsz;
oid_to_hex_r(hex, oid);
if (len >= hexsz || !len)
return hexsz;
hex[len] = 0;
mad.repo = r;
mad.init_len = len;
mad.cur_len = len;
mad.hex = hex;
mad.oid = oid;
find_abbrev_len_packed(&mad);
if (init_object_disambiguation(r, hex, mad.cur_len, algo, &ds) < 0)
return -1;
ds.fn = repo_extend_abbrev_len;
ds.always_call_fn = 1;
ds.cb_data = (void *)&mad;
find_short_object_filename(&ds);
(void)finish_object_disambiguation(&ds, &oid_ret);
hex[mad.cur_len] = 0;
return mad.cur_len;
return len;
}
const char *repo_find_unique_abbrev(struct repository *r,
+96 -11
View File
@@ -12,6 +12,7 @@
#include "midx.h"
#include "object-file-convert.h"
#include "object-file.h"
#include "object-name.h"
#include "odb.h"
#include "packfile.h"
#include "path.h"
@@ -871,15 +872,15 @@ void *odb_read_object_peeled(struct object_database *odb,
}
int odb_has_object(struct object_database *odb, const struct object_id *oid,
enum has_object_flags flags)
enum odb_has_object_flags flags)
{
unsigned object_info_flags = 0;
if (!startup_info->have_repository)
return 0;
if (!(flags & HAS_OBJECT_RECHECK_PACKED))
if (!(flags & ODB_HAS_OBJECT_RECHECK_PACKED))
object_info_flags |= OBJECT_INFO_QUICK;
if (!(flags & HAS_OBJECT_FETCH_PROMISOR))
if (!(flags & ODB_HAS_OBJECT_FETCH_PROMISOR))
object_info_flags |= OBJECT_INFO_SKIP_FETCH_OBJECT;
return odb_read_object_info_extended(odb, oid, NULL, object_info_flags) >= 0;
@@ -896,20 +897,20 @@ int odb_freshen_object(struct object_database *odb,
return 0;
}
int odb_for_each_object(struct object_database *odb,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags)
int odb_for_each_object_ext(struct object_database *odb,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
const struct odb_for_each_object_options *opts)
{
int ret;
odb_prepare_alternates(odb);
for (struct odb_source *source = odb->sources; source; source = source->next) {
if (flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !source->local)
if (opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !source->local)
continue;
ret = odb_source_for_each_object(source, request, cb, cb_data, flags);
ret = odb_source_for_each_object(source, request, cb, cb_data, opts);
if (ret)
return ret;
}
@@ -917,6 +918,18 @@ int odb_for_each_object(struct object_database *odb,
return 0;
}
int odb_for_each_object(struct object_database *odb,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
enum odb_for_each_object_flags flags)
{
struct odb_for_each_object_options opts = {
.flags = flags,
};
return odb_for_each_object_ext(odb, request, cb, cb_data, &opts);
}
int odb_count_objects(struct object_database *odb,
enum odb_count_objects_flags flags,
unsigned long *out)
@@ -952,6 +965,78 @@ out:
return ret;
}
/*
* Return the slot of the most-significant bit set in "val". There are various
* ways to do this quickly with fls() or __builtin_clzl(), but speed is
* probably not a big deal here.
*/
static unsigned msb(unsigned long val)
{
unsigned r = 0;
while (val >>= 1)
r++;
return r;
}
int odb_find_abbrev_len(struct object_database *odb,
const struct object_id *oid,
int min_length,
unsigned *out)
{
const struct git_hash_algo *algo =
oid->algo ? &hash_algos[oid->algo] : odb->repo->hash_algo;
const unsigned hexsz = algo->hexsz;
unsigned len;
int ret;
if (min_length < 0) {
unsigned long count;
if (odb_count_objects(odb, ODB_COUNT_OBJECTS_APPROXIMATE, &count) < 0)
count = 0;
/*
* Add one because the MSB only tells us the highest bit set,
* not including the value of all the _other_ bits (so "15"
* is only one off of 2^4, but the MSB is the 3rd bit.
*/
len = msb(count) + 1;
/*
* We now know we have on the order of 2^len objects, which
* expects a collision at 2^(len/2). But we also care about hex
* chars, not bits, and there are 4 bits per hex. So all
* together we need to divide by 2 and round up.
*/
len = DIV_ROUND_UP(len, 2);
/*
* For very small repos, we stick with our regular fallback.
*/
if (len < FALLBACK_DEFAULT_ABBREV)
len = FALLBACK_DEFAULT_ABBREV;
} else {
len = min_length;
}
if (len >= hexsz || !len) {
*out = hexsz;
ret = 0;
goto out;
}
odb_prepare_alternates(odb);
for (struct odb_source *source = odb->sources; source; source = source->next) {
ret = odb_source_find_abbrev_len(source, oid, len, &len);
if (ret)
goto out;
}
ret = 0;
*out = len;
out:
return ret;
}
void odb_assert_oid_type(struct object_database *odb,
const struct object_id *oid, enum object_type expect)
{
@@ -968,7 +1053,7 @@ int odb_write_object_ext(struct object_database *odb,
enum object_type type,
struct object_id *oid,
struct object_id *compat_oid,
unsigned flags)
enum odb_write_object_flags flags)
{
return odb_source_write_object(odb->sources, buf, len, type,
oid, compat_oid, flags);
+51 -18
View File
@@ -1,19 +1,17 @@
#ifndef ODB_H
#define ODB_H
#include "hashmap.h"
#include "object.h"
#include "oidset.h"
#include "oidmap.h"
#include "string-list.h"
#include "thread-utils.h"
struct oidmap;
struct oidtree;
struct cached_object_entry;
struct packed_git;
struct repository;
struct strbuf;
struct strvec;
struct repository;
struct multi_pack_index;
/*
* Set this to 0 to prevent odb_read_object_info_extended() from fetching missing
@@ -31,10 +29,6 @@ extern int fetch_if_missing;
*/
char *compute_alternate_path(const char *path, struct strbuf *err);
struct packed_git;
struct packfile_store;
struct cached_object_entry;
/*
* A transaction may be started for an object database prior to writing new
* objects via odb_transaction_begin(). These objects are not committed until
@@ -395,11 +389,11 @@ int odb_read_object_info(struct object_database *odb,
const struct object_id *oid,
unsigned long *sizep);
enum has_object_flags {
enum odb_has_object_flags {
/* Retry packed storage after checking packed and loose storage */
HAS_OBJECT_RECHECK_PACKED = (1 << 0),
ODB_HAS_OBJECT_RECHECK_PACKED = (1 << 0),
/* Allow fetching the object in case the repository has a promisor remote. */
HAS_OBJECT_FETCH_PROMISOR = (1 << 1),
ODB_HAS_OBJECT_FETCH_PROMISOR = (1 << 1),
};
/*
@@ -408,7 +402,7 @@ enum has_object_flags {
*/
int odb_has_object(struct object_database *odb,
const struct object_id *oid,
enum has_object_flags flags);
enum odb_has_object_flags flags);
int odb_freshen_object(struct object_database *odb,
const struct object_id *oid);
@@ -481,6 +475,22 @@ typedef int (*odb_for_each_object_cb)(const struct object_id *oid,
struct object_info *oi,
void *cb_data);
/*
* Options that can be passed to `odb_for_each_object()` and its
* backend-specific implementations.
*/
struct odb_for_each_object_options {
/* A bitfield of `odb_for_each_object_flags`. */
enum odb_for_each_object_flags flags;
/*
* If set, only iterate through objects whose first `prefix_hex_len`
* hex characters matches the given prefix.
*/
const struct object_id *prefix;
size_t prefix_hex_len;
};
/*
* Iterate through all objects contained in the object database. Note that
* objects may be iterated over multiple times in case they are either stored
@@ -495,11 +505,18 @@ typedef int (*odb_for_each_object_cb)(const struct object_id *oid,
* Returns 0 on success, a negative error code in case a failure occurred, or
* an arbitrary non-zero error code returned by the callback itself.
*/
int odb_for_each_object_ext(struct object_database *odb,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
const struct odb_for_each_object_options *opts);
/* Same as `odb_for_each_object_ext()` with `opts.flags` set to the given flags. */
int odb_for_each_object(struct object_database *odb,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags);
enum odb_for_each_object_flags flags);
enum odb_count_objects_flags {
/*
@@ -522,19 +539,35 @@ int odb_count_objects(struct object_database *odb,
enum odb_count_objects_flags flags,
unsigned long *out);
enum {
/*
* Given an object ID, find the minimum required length required to make the
* object ID unique across the whole object database.
*
* The `min_len` determines the minimum abbreviated length that'll be returned
* by this function. If `min_len < 0`, then the function will set a sensible
* default minimum abbreviation length.
*
* Returns 0 on success, a negative error code otherwise. The computed length
* will be assigned to `*out`.
*/
int odb_find_abbrev_len(struct object_database *odb,
const struct object_id *oid,
int min_len,
unsigned *out);
enum odb_write_object_flags {
/*
* By default, `odb_write_object()` does not actually write anything
* into the object store, but only computes the object ID. This flag
* changes that so that the object will be written as a loose object
* and persisted.
*/
WRITE_OBJECT_PERSIST = (1 << 0),
ODB_WRITE_OBJECT_PERSIST = (1 << 0),
/*
* Do not print an error in case something goes wrong.
*/
WRITE_OBJECT_SILENT = (1 << 1),
ODB_WRITE_OBJECT_SILENT = (1 << 1),
};
/*
@@ -550,7 +583,7 @@ int odb_write_object_ext(struct object_database *odb,
enum object_type type,
struct object_id *oid,
struct object_id *compat_oid,
unsigned flags);
enum odb_write_object_flags flags);
static inline int odb_write_object(struct object_database *odb,
const void *buf, unsigned long len,
+30 -5
View File
@@ -75,18 +75,18 @@ static int odb_source_files_for_each_object(struct odb_source *source,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags)
const struct odb_for_each_object_options *opts)
{
struct odb_source_files *files = odb_source_files_downcast(source);
int ret;
if (!(flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) {
ret = odb_source_loose_for_each_object(source, request, cb, cb_data, flags);
if (!(opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) {
ret = odb_source_loose_for_each_object(source, request, cb, cb_data, opts);
if (ret)
return ret;
}
ret = packfile_store_for_each_object(files->packed, request, cb, cb_data, flags);
ret = packfile_store_for_each_object(files->packed, request, cb, cb_data, opts);
if (ret)
return ret;
@@ -122,6 +122,30 @@ out:
return ret;
}
static int odb_source_files_find_abbrev_len(struct odb_source *source,
const struct object_id *oid,
unsigned min_len,
unsigned *out)
{
struct odb_source_files *files = odb_source_files_downcast(source);
unsigned len = min_len;
int ret;
ret = packfile_store_find_abbrev_len(files->packed, oid, len, &len);
if (ret < 0)
goto out;
ret = odb_source_loose_find_abbrev_len(source, oid, len, &len);
if (ret < 0)
goto out;
*out = len;
ret = 0;
out:
return ret;
}
static int odb_source_files_freshen_object(struct odb_source *source,
const struct object_id *oid)
{
@@ -137,7 +161,7 @@ static int odb_source_files_write_object(struct odb_source *source,
enum object_type type,
struct object_id *oid,
struct object_id *compat_oid,
unsigned flags)
enum odb_write_object_flags flags)
{
return odb_source_loose_write_object(source, buf, len, type,
oid, compat_oid, flags);
@@ -250,6 +274,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
files->base.read_object_stream = odb_source_files_read_object_stream;
files->base.for_each_object = odb_source_files_for_each_object;
files->base.count_objects = odb_source_files_count_objects;
files->base.find_abbrev_len = odb_source_files_find_abbrev_len;
files->base.freshen_object = odb_source_files_freshen_object;
files->base.write_object = odb_source_files_write_object;
files->base.write_object_stream = odb_source_files_write_object_stream;
+29 -5
View File
@@ -140,7 +140,7 @@ struct odb_source {
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags);
const struct odb_for_each_object_options *opts);
/*
* This callback is expected to count objects in the given object
@@ -157,6 +157,18 @@ struct odb_source {
enum odb_count_objects_flags flags,
unsigned long *out);
/*
* This callback is expected to find the minimum required length to
* make the given object ID unique.
*
* The callback is expected to return a negative error code in case it
* failed, 0 otherwise.
*/
int (*find_abbrev_len)(struct odb_source *source,
const struct object_id *oid,
unsigned min_length,
unsigned *out);
/*
* This callback is expected to freshen the given object so that its
* last access time is set to the current time. This is used to ensure
@@ -185,7 +197,7 @@ struct odb_source {
enum object_type type,
struct object_id *oid,
struct object_id *compat_oid,
unsigned flags);
enum odb_write_object_flags flags);
/*
* This callback is expected to persist the given object stream into
@@ -343,9 +355,9 @@ static inline int odb_source_for_each_object(struct odb_source *source,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags)
const struct odb_for_each_object_options *opts)
{
return source->for_each_object(source, request, cb, cb_data, flags);
return source->for_each_object(source, request, cb, cb_data, opts);
}
/*
@@ -360,6 +372,18 @@ static inline int odb_source_count_objects(struct odb_source *source,
return source->count_objects(source, flags, out);
}
/*
* Determine the minimum required length to make the given object ID unique in
* the given source. Returns 0 on success, a negative error code otherwise.
*/
static inline int odb_source_find_abbrev_len(struct odb_source *source,
const struct object_id *oid,
unsigned min_len,
unsigned *out)
{
return source->find_abbrev_len(source, oid, min_len, out);
}
/*
* Freshen an object in the object database by updating its timestamp.
* Returns 1 in case the object has been freshened, 0 in case the object does
@@ -381,7 +405,7 @@ static inline int odb_source_write_object(struct odb_source *source,
enum object_type type,
struct object_id *oid,
struct object_id *compat_oid,
unsigned flags)
enum odb_write_object_flags flags)
{
return source->write_object(source, buf, len, type, oid,
compat_oid, flags);
+32 -31
View File
@@ -6,14 +6,6 @@
#include "oidtree.h"
#include "hash.h"
struct oidtree_iter_data {
oidtree_iter fn;
void *arg;
size_t *last_nibble_at;
uint32_t algo;
uint8_t last_byte;
};
void oidtree_init(struct oidtree *ot)
{
cb_init(&ot->tree);
@@ -54,8 +46,7 @@ void oidtree_insert(struct oidtree *ot, const struct object_id *oid)
cb_insert(&ot->tree, on, sizeof(*oid));
}
int oidtree_contains(struct oidtree *ot, const struct object_id *oid)
bool oidtree_contains(struct oidtree *ot, const struct object_id *oid)
{
struct object_id k;
size_t klen = sizeof(k);
@@ -69,41 +60,51 @@ int oidtree_contains(struct oidtree *ot, const struct object_id *oid)
klen += BUILD_ASSERT_OR_ZERO(offsetof(struct object_id, hash) <
offsetof(struct object_id, algo));
return cb_lookup(&ot->tree, (const uint8_t *)&k, klen) ? 1 : 0;
return !!cb_lookup(&ot->tree, (const uint8_t *)&k, klen);
}
static enum cb_next iter(struct cb_node *n, void *arg)
struct oidtree_each_data {
oidtree_each_cb cb;
void *cb_data;
size_t *last_nibble_at;
uint32_t algo;
uint8_t last_byte;
};
static int iter(struct cb_node *n, void *cb_data)
{
struct oidtree_iter_data *x = arg;
struct oidtree_each_data *data = cb_data;
struct object_id k;
/* Copy to provide 4-byte alignment needed by struct object_id. */
memcpy(&k, n->k, sizeof(k));
if (x->algo != GIT_HASH_UNKNOWN && x->algo != k.algo)
return CB_CONTINUE;
if (data->algo != GIT_HASH_UNKNOWN && data->algo != k.algo)
return 0;
if (x->last_nibble_at) {
if ((k.hash[*x->last_nibble_at] ^ x->last_byte) & 0xf0)
return CB_CONTINUE;
if (data->last_nibble_at) {
if ((k.hash[*data->last_nibble_at] ^ data->last_byte) & 0xf0)
return 0;
}
return x->fn(&k, x->arg);
return data->cb(&k, data->cb_data);
}
void oidtree_each(struct oidtree *ot, const struct object_id *oid,
size_t oidhexsz, oidtree_iter fn, void *arg)
int oidtree_each(struct oidtree *ot, const struct object_id *prefix,
size_t prefix_hex_len, oidtree_each_cb cb, void *cb_data)
{
size_t klen = oidhexsz / 2;
struct oidtree_iter_data x = { 0 };
assert(oidhexsz <= GIT_MAX_HEXSZ);
struct oidtree_each_data data = {
.cb = cb,
.cb_data = cb_data,
.algo = prefix->algo,
};
size_t klen = prefix_hex_len / 2;
assert(prefix_hex_len <= GIT_MAX_HEXSZ);
x.fn = fn;
x.arg = arg;
x.algo = oid->algo;
if (oidhexsz & 1) {
x.last_byte = oid->hash[klen];
x.last_nibble_at = &klen;
if (prefix_hex_len & 1) {
data.last_byte = prefix->hash[klen];
data.last_nibble_at = &klen;
}
cb_each(&ot->tree, (const uint8_t *)oid, klen, iter, &x);
return cb_each(&ot->tree, prefix->hash, klen, iter, &data);
}
+41 -7
View File
@@ -5,18 +5,52 @@
#include "hash.h"
#include "mem-pool.h"
/*
* OID trees are an efficient storage for object IDs that use a critbit tree
* internally. Common prefixes are duplicated and object IDs are stored in a
* way that allow easy iteration over the objects in lexicographic order. As a
* consequence, operations that want to enumerate all object IDs that match a
* given prefix can be answered efficiently.
*
* Note that it is not (yet) possible to store data other than the object IDs
* themselves in this tree.
*/
struct oidtree {
struct cb_tree tree;
struct mem_pool mem_pool;
};
void oidtree_init(struct oidtree *);
void oidtree_clear(struct oidtree *);
void oidtree_insert(struct oidtree *, const struct object_id *);
int oidtree_contains(struct oidtree *, const struct object_id *);
/* Initialize the oidtree so that it is ready for use. */
void oidtree_init(struct oidtree *ot);
typedef enum cb_next (*oidtree_iter)(const struct object_id *, void *data);
void oidtree_each(struct oidtree *, const struct object_id *,
size_t oidhexsz, oidtree_iter, void *data);
/*
* Release all memory associated with the oidtree and reinitialize it for
* subsequent use.
*/
void oidtree_clear(struct oidtree *ot);
/* Insert the object ID into the tree. */
void oidtree_insert(struct oidtree *ot, const struct object_id *oid);
/* Check whether the tree contains the given object ID. */
bool oidtree_contains(struct oidtree *ot, const struct object_id *oid);
/*
* Callback function used for `oidtree_each()`. Returning a non-zero exit code
* will cause iteration to stop. The exit code will be propagated to the caller
* of `oidtree_each()`.
*/
typedef int (*oidtree_each_cb)(const struct object_id *oid,
void *cb_data);
/*
* Iterate through all object IDs in the tree whose prefix matches the given
* object ID prefix and invoke the callback function on each of them.
*
* Returns any non-zero exit code from the provided callback function.
*/
int oidtree_each(struct oidtree *ot,
const struct object_id *prefix, size_t prefix_hex_len,
oidtree_each_cb cb, void *cb_data);
#endif /* OIDTREE_H */
+4 -3
View File
@@ -53,6 +53,7 @@ static int verify_packfile(struct repository *r,
struct packed_git *p,
struct pack_window **w_curs,
verify_fn fn,
void *fn_data,
struct progress *progress, uint32_t base_count)
{
@@ -161,7 +162,7 @@ static int verify_packfile(struct repository *r,
oid_to_hex(&oid), p->pack_name);
else if (fn) {
int eaten = 0;
err |= fn(&oid, type, size, data, &eaten);
err |= fn(&oid, type, size, data, &eaten, fn_data);
if (eaten)
data = NULL;
}
@@ -192,7 +193,7 @@ int verify_pack_index(struct packed_git *p)
return err;
}
int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn,
int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn, void *fn_data,
struct progress *progress, uint32_t base_count)
{
int err = 0;
@@ -202,7 +203,7 @@ int verify_pack(struct repository *r, struct packed_git *p, verify_fn fn,
if (!p->index_data)
return -1;
err |= verify_packfile(r, p, &w_curs, fn, progress, base_count);
err |= verify_packfile(r, p, &w_curs, fn, fn_data, progress, base_count);
unuse_pack(&w_curs);
return err;
+7 -2
View File
@@ -85,7 +85,11 @@ struct pack_idx_entry {
struct progress;
/* Note, the data argument could be NULL if object type is blob */
typedef int (*verify_fn)(const struct object_id *, enum object_type, unsigned long, void*, int*);
typedef int (*verify_fn)(const struct object_id *oid,
enum object_type type,
unsigned long size,
void *buffer, int *eaten,
void *fn_data);
const char *write_idx_file(struct repository *repo,
const char *index_name,
@@ -95,7 +99,8 @@ const char *write_idx_file(struct repository *repo,
const unsigned char *sha1);
int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
int verify_pack_index(struct packed_git *);
int verify_pack(struct repository *, struct packed_git *, verify_fn fn, struct progress *, uint32_t);
int verify_pack(struct repository *, struct packed_git *, verify_fn fn, void *fn_data,
struct progress *, uint32_t);
off_t write_pack_header(struct hashfile *f, uint32_t);
void fixup_pack_header_footer(const struct git_hash_algo *, int,
unsigned char *, const char *, uint32_t,
+294 -8
View File
@@ -2244,7 +2244,8 @@ struct packed_git **packfile_store_get_kept_pack_cache(struct packfile_store *st
struct packed_git *p = e->pack;
if ((p->pack_keep && (flags & KEPT_PACK_ON_DISK)) ||
(p->pack_keep_in_core && (flags & KEPT_PACK_IN_CORE))) {
(p->pack_keep_in_core && (flags & KEPT_PACK_IN_CORE)) ||
(p->pack_keep_in_core_open && (flags & KEPT_PACK_IN_CORE_OPEN))) {
ALLOC_GROW(packs, nr + 1, alloc);
packs[nr++] = p;
}
@@ -2299,7 +2300,7 @@ int has_object_kept_pack(struct repository *r, const struct object_id *oid,
int for_each_object_in_pack(struct packed_git *p,
each_packed_object_fn cb, void *data,
unsigned flags)
enum odb_for_each_object_flags flags)
{
uint32_t i;
int r = 0;
@@ -2371,11 +2372,182 @@ static int packfile_store_for_each_object_wrapper(const struct object_id *oid,
}
}
static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
{
do {
if (*a != *b)
return 0;
a++;
b++;
len -= 2;
} while (len > 1);
if (len)
if ((*a ^ *b) & 0xf0)
return 0;
return 1;
}
static int for_each_prefixed_object_in_midx(
struct packfile_store *store,
struct multi_pack_index *m,
const struct odb_for_each_object_options *opts,
struct packfile_store_for_each_object_wrapper_data *data)
{
int ret;
for (; m; m = m->base_midx) {
uint32_t num, i, first = 0;
int len = opts->prefix_hex_len > m->source->odb->repo->hash_algo->hexsz ?
m->source->odb->repo->hash_algo->hexsz : opts->prefix_hex_len;
if (!m->num_objects)
continue;
num = m->num_objects + m->num_objects_in_base;
bsearch_one_midx(opts->prefix, m, &first);
/*
* At this point, "first" is the location of the lowest
* object with an object name that could match "opts->prefix".
* See if we have 0, 1 or more objects that actually match(es).
*/
for (i = first; i < num; i++) {
const struct object_id *current = NULL;
struct object_id oid;
current = nth_midxed_object_oid(&oid, m, i);
if (!match_hash(len, opts->prefix->hash, current->hash))
break;
if (data->request) {
struct object_info oi = *data->request;
ret = packfile_store_read_object_info(store, current,
&oi, 0);
if (ret)
goto out;
ret = data->cb(&oid, &oi, data->cb_data);
if (ret)
goto out;
} else {
ret = data->cb(&oid, NULL, data->cb_data);
if (ret)
goto out;
}
}
}
ret = 0;
out:
return ret;
}
static int for_each_prefixed_object_in_pack(
struct packfile_store *store,
struct packed_git *p,
const struct odb_for_each_object_options *opts,
struct packfile_store_for_each_object_wrapper_data *data)
{
uint32_t num, i, first = 0;
int len = opts->prefix_hex_len > p->repo->hash_algo->hexsz ?
p->repo->hash_algo->hexsz : opts->prefix_hex_len;
int ret;
num = p->num_objects;
bsearch_pack(opts->prefix, p, &first);
/*
* At this point, "first" is the location of the lowest object
* with an object name that could match "bin_pfx". See if we have
* 0, 1 or more objects that actually match(es).
*/
for (i = first; i < num; i++) {
struct object_id oid;
nth_packed_object_id(&oid, p, i);
if (!match_hash(len, opts->prefix->hash, oid.hash))
break;
if (data->request) {
struct object_info oi = *data->request;
ret = packfile_store_read_object_info(store, &oid, &oi, 0);
if (ret)
goto out;
ret = data->cb(&oid, &oi, data->cb_data);
if (ret)
goto out;
} else {
ret = data->cb(&oid, NULL, data->cb_data);
if (ret)
goto out;
}
}
ret = 0;
out:
return ret;
}
static int packfile_store_for_each_prefixed_object(
struct packfile_store *store,
const struct odb_for_each_object_options *opts,
struct packfile_store_for_each_object_wrapper_data *data)
{
struct packfile_list_entry *e;
struct multi_pack_index *m;
bool pack_errors = false;
int ret;
if (opts->flags)
BUG("flags unsupported");
store->skip_mru_updates = true;
m = get_multi_pack_index(store->source);
if (m) {
ret = for_each_prefixed_object_in_midx(store, m, opts, data);
if (ret)
goto out;
}
for (e = packfile_store_get_packs(store); e; e = e->next) {
if (e->pack->multi_pack_index)
continue;
if (open_pack_index(e->pack)) {
pack_errors = true;
continue;
}
if (!e->pack->num_objects)
continue;
ret = for_each_prefixed_object_in_pack(store, e->pack, opts, data);
if (ret)
goto out;
}
ret = 0;
out:
store->skip_mru_updates = false;
if (!ret && pack_errors)
ret = -1;
return ret;
}
int packfile_store_for_each_object(struct packfile_store *store,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags)
const struct odb_for_each_object_options *opts)
{
struct packfile_store_for_each_object_wrapper_data data = {
.store = store,
@@ -2386,20 +2558,23 @@ int packfile_store_for_each_object(struct packfile_store *store,
struct packfile_list_entry *e;
int pack_errors = 0, ret;
if (opts->prefix)
return packfile_store_for_each_prefixed_object(store, opts, &data);
store->skip_mru_updates = true;
for (e = packfile_store_get_packs(store); e; e = e->next) {
struct packed_git *p = e->pack;
if ((flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
continue;
if ((flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) &&
!p->pack_promisor)
continue;
if ((flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS) &&
p->pack_keep_in_core)
continue;
if ((flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
if ((opts->flags & ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS) &&
p->pack_keep)
continue;
if (open_pack_index(p)) {
@@ -2408,7 +2583,7 @@ int packfile_store_for_each_object(struct packfile_store *store,
}
ret = for_each_object_in_pack(p, packfile_store_for_each_object_wrapper,
&data, flags);
&data, opts->flags);
if (ret)
goto out;
}
@@ -2423,6 +2598,117 @@ out:
return ret;
}
static int extend_abbrev_len(const struct object_id *a,
const struct object_id *b,
unsigned *out)
{
unsigned len = oid_common_prefix_hexlen(a, b);
if (len != hash_algos[a->algo].hexsz && len >= *out)
*out = len + 1;
return 0;
}
static void find_abbrev_len_for_midx(struct multi_pack_index *m,
const struct object_id *oid,
unsigned min_len,
unsigned *out)
{
unsigned len = min_len;
for (; m; m = m->base_midx) {
int match = 0;
uint32_t num, first = 0;
struct object_id found_oid;
if (!m->num_objects)
continue;
num = m->num_objects + m->num_objects_in_base;
match = bsearch_one_midx(oid, m, &first);
/*
* first is now the position in the packfile where we
* would insert the object ID if it does not exist (or the
* position of the object ID if it does exist). Hence, we
* consider a maximum of two objects nearby for the
* abbreviation length.
*/
if (!match) {
if (nth_midxed_object_oid(&found_oid, m, first))
extend_abbrev_len(&found_oid, oid, &len);
} else if (first < num - 1) {
if (nth_midxed_object_oid(&found_oid, m, first + 1))
extend_abbrev_len(&found_oid, oid, &len);
}
if (first > 0) {
if (nth_midxed_object_oid(&found_oid, m, first - 1))
extend_abbrev_len(&found_oid, oid, &len);
}
}
*out = len;
}
static void find_abbrev_len_for_pack(struct packed_git *p,
const struct object_id *oid,
unsigned min_len,
unsigned *out)
{
int match;
uint32_t num, first = 0;
struct object_id found_oid;
unsigned len = min_len;
num = p->num_objects;
match = bsearch_pack(oid, p, &first);
/*
* first is now the position in the packfile where we would insert
* the object ID if it does not exist (or the position of mad->hash if
* it does exist). Hence, we consider a maximum of two objects
* nearby for the abbreviation length.
*/
if (!match) {
if (!nth_packed_object_id(&found_oid, p, first))
extend_abbrev_len(&found_oid, oid, &len);
} else if (first < num - 1) {
if (!nth_packed_object_id(&found_oid, p, first + 1))
extend_abbrev_len(&found_oid, oid, &len);
}
if (first > 0) {
if (!nth_packed_object_id(&found_oid, p, first - 1))
extend_abbrev_len(&found_oid, oid, &len);
}
*out = len;
}
int packfile_store_find_abbrev_len(struct packfile_store *store,
const struct object_id *oid,
unsigned min_len,
unsigned *out)
{
struct packfile_list_entry *e;
struct multi_pack_index *m;
m = get_multi_pack_index(store->source);
if (m)
find_abbrev_len_for_midx(m, oid, min_len, &min_len);
for (e = packfile_store_get_packs(store); e; e = e->next) {
if (e->pack->multi_pack_index)
continue;
if (open_pack_index(e->pack) || !e->pack->num_objects)
continue;
find_abbrev_len_for_pack(e->pack, oid, min_len, &min_len);
}
*out = min_len;
return 0;
}
struct add_promisor_object_data {
struct repository *repo;
struct oidset *set;
+9 -2
View File
@@ -28,6 +28,7 @@ struct packed_git {
unsigned pack_local:1,
pack_keep:1,
pack_keep_in_core:1,
pack_keep_in_core_open:1,
freshened:1,
do_not_close:1,
pack_promisor:1,
@@ -266,6 +267,7 @@ int packfile_store_freshen_object(struct packfile_store *store,
enum kept_pack_type {
KEPT_PACK_ON_DISK = (1 << 0),
KEPT_PACK_IN_CORE = (1 << 1),
KEPT_PACK_IN_CORE_OPEN = (1 << 2),
};
/*
@@ -352,7 +354,7 @@ typedef int each_packed_object_fn(const struct object_id *oid,
void *data);
int for_each_object_in_pack(struct packed_git *p,
each_packed_object_fn, void *data,
unsigned flags);
enum odb_for_each_object_flags flags);
/*
* Iterate through all packed objects in the given packfile store and invoke
@@ -367,7 +369,12 @@ int packfile_store_for_each_object(struct packfile_store *store,
const struct object_info *request,
odb_for_each_object_cb cb,
void *cb_data,
unsigned flags);
const struct odb_for_each_object_options *opts);
int packfile_store_find_abbrev_len(struct packfile_store *store,
const struct object_id *oid,
unsigned min_len,
unsigned *out);
/* A hook to report invalid files in pack directory */
#define PACKDIR_FILE_PACK 1
+1 -1
View File
@@ -174,7 +174,7 @@ static int add_tree_entries(struct path_walk_context *ctx,
if (!o) {
error(_("failed to find object %s"),
oid_to_hex(&o->oid));
oid_to_hex(&entry.oid));
return -1;
}
+9 -24
View File
@@ -2309,13 +2309,9 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
}
munmap((void *)mmap, mmap_size);
/*
* TODO trace2: replace "the_repository" with the actual repo instance
* that is associated with the given "istate".
*/
trace2_data_intmax("index", the_repository, "read/version",
trace2_data_intmax("index", istate->repo, "read/version",
istate->version);
trace2_data_intmax("index", the_repository, "read/cache_nr",
trace2_data_intmax("index", istate->repo, "read/cache_nr",
istate->cache_nr);
/*
@@ -2360,16 +2356,12 @@ int read_index_from(struct index_state *istate, const char *path,
if (istate->initialized)
return istate->cache_nr;
/*
* TODO trace2: replace "the_repository" with the actual repo instance
* that is associated with the given "istate".
*/
trace2_region_enter_printf("index", "do_read_index", the_repository,
trace2_region_enter_printf("index", "do_read_index", istate->repo,
"%s", path);
trace_performance_enter();
ret = do_read_index(istate, path, 0);
trace_performance_leave("read cache %s", path);
trace2_region_leave_printf("index", "do_read_index", the_repository,
trace2_region_leave_printf("index", "do_read_index", istate->repo,
"%s", path);
split_index = istate->split_index;
@@ -3096,13 +3088,9 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
istate->timestamp.nsec = ST_MTIME_NSEC(st);
trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed);
/*
* TODO trace2: replace "the_repository" with the actual repo instance
* that is associated with the given "istate".
*/
trace2_data_intmax("index", the_repository, "write/version",
trace2_data_intmax("index", istate->repo, "write/version",
istate->version);
trace2_data_intmax("index", the_repository, "write/cache_nr",
trace2_data_intmax("index", istate->repo, "write/cache_nr",
istate->cache_nr);
ret = 0;
@@ -3144,14 +3132,10 @@ static int do_write_locked_index(struct index_state *istate,
return ret;
}
/*
* TODO trace2: replace "the_repository" with the actual repo instance
* that is associated with the given "istate".
*/
trace2_region_enter_printf("index", "do_write_index", the_repository,
trace2_region_enter_printf("index", "do_write_index", istate->repo,
"%s", get_lock_file_path(lock));
ret = do_write_index(istate, lock->tempfile, write_extensions, flags);
trace2_region_leave_printf("index", "do_write_index", the_repository,
trace2_region_leave_printf("index", "do_write_index", istate->repo,
"%s", get_lock_file_path(lock));
if (was_full)
@@ -4049,6 +4033,7 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = &data;
rev.diffopt.flags.override_submodule_config = 1;
rev.diffopt.detect_rename = 0; /* staging worktree changes does not need renames */
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
/*
+1 -1
View File
@@ -168,7 +168,7 @@ static int tree_is_complete(const struct object_id *oid)
complete = 1;
while (tree_entry(&desc, &entry)) {
if (!odb_has_object(the_repository->objects, &entry.oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR) ||
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR) ||
(S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
tree->object.flags |= INCOMPLETE;
complete = 0;
+1 -1
View File
@@ -425,7 +425,7 @@ int ref_resolves_to_object(const char *refname,
if (flags & REF_ISBROKEN)
return 0;
if (!odb_has_object(repo->objects, oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR)) {
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR)) {
error(_("%s does not point to a valid object!"), refname);
return 0;
}
-6
View File
@@ -366,11 +366,6 @@ static int reftable_be_config(const char *var, const char *value,
return 0;
}
static int reftable_be_fsync(int fd)
{
return fsync_component(FSYNC_COMPONENT_REFERENCE, fd);
}
static struct ref_store *reftable_be_init(struct repository *repo,
const char *payload,
const char *gitdir,
@@ -408,7 +403,6 @@ static struct ref_store *reftable_be_init(struct repository *repo,
refs->write_options.disable_auto_compact =
!git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1);
refs->write_options.lock_timeout_ms = 100;
refs->write_options.fsync = reftable_be_fsync;
repo_config(the_repository, reftable_be_config, &refs->write_options);
+7 -12
View File
@@ -93,13 +93,12 @@ void block_source_from_buf(struct reftable_block_source *bs,
}
struct file_block_source {
uint64_t size;
unsigned char *data;
struct reftable_mmap mmap;
};
static uint64_t file_size(void *b)
{
return ((struct file_block_source *)b)->size;
return ((struct file_block_source *)b)->mmap.size;
}
static void file_release_data(void *b REFTABLE_UNUSED, struct reftable_block_data *dest REFTABLE_UNUSED)
@@ -109,7 +108,7 @@ static void file_release_data(void *b REFTABLE_UNUSED, struct reftable_block_dat
static void file_close(void *v)
{
struct file_block_source *b = v;
munmap(b->data, b->size);
reftable_munmap(&b->mmap);
reftable_free(b);
}
@@ -117,8 +116,8 @@ static ssize_t file_read_data(void *v, struct reftable_block_data *dest, uint64_
uint32_t size)
{
struct file_block_source *b = v;
assert(off + size <= b->size);
dest->data = b->data + off;
assert(off + size <= b->mmap.size);
dest->data = (unsigned char *) b->mmap.data + off;
dest->len = size;
return size;
}
@@ -156,13 +155,9 @@ int reftable_block_source_from_file(struct reftable_block_source *bs,
goto out;
}
p->size = st.st_size;
p->data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->data == MAP_FAILED) {
err = REFTABLE_IO_ERROR;
p->data = NULL;
err = reftable_mmap(&p->mmap, fd, st.st_size);
if (err < 0)
goto out;
}
assert(!bs->ops);
bs->ops = &file_vtable;
+1 -1
View File
@@ -63,7 +63,7 @@ static int table_check_name(struct reftable_table *table,
static int table_checks(struct reftable_table *table,
reftable_fsck_report_fn report_fn,
reftable_fsck_verbose_fn verbose_fn UNUSED,
reftable_fsck_verbose_fn verbose_fn REFTABLE_UNUSED,
void *cb_data)
{
table_check_fn table_check_fns[] = {
+1 -1
View File
@@ -9,7 +9,7 @@
#ifndef REFTABLE_BASICS_H
#define REFTABLE_BASICS_H
#include <stddef.h>
#include "reftable-system.h"
/* A buffer that contains arbitrary byte slices. */
struct reftable_buf {
+1 -2
View File
@@ -9,8 +9,7 @@
#ifndef REFTABLE_BLOCK_H
#define REFTABLE_BLOCK_H
#include <stdint.h>
#include "reftable-system.h"
#include "reftable-basics.h"
#include "reftable-blocksource.h"
#include "reftable-iterator.h"
+1 -1
View File
@@ -9,7 +9,7 @@
#ifndef REFTABLE_BLOCKSOURCE_H
#define REFTABLE_BLOCKSOURCE_H
#include <stdint.h>
#include "reftable-system.h"
/*
* Generic wrapper for a seekable readable file.
+2
View File
@@ -9,6 +9,8 @@
#ifndef REFTABLE_ERROR_H
#define REFTABLE_ERROR_H
#include "reftable-system.h"
/*
* Errors in reftable calls are signaled with negative integer return values. 0
* means success.
+1
View File
@@ -1,6 +1,7 @@
#ifndef REFTABLE_FSCK_H
#define REFTABLE_FSCK_H
#include "reftable-system.h"
#include "reftable-stack.h"
enum reftable_fsck_error {
+1
View File
@@ -9,6 +9,7 @@
#ifndef REFTABLE_ITERATOR_H
#define REFTABLE_ITERATOR_H
#include "reftable-system.h"
#include "reftable-record.h"
struct reftable_iterator_vtable;
+1
View File
@@ -9,6 +9,7 @@
#ifndef REFTABLE_MERGED_H
#define REFTABLE_MERGED_H
#include "reftable-system.h"
#include "reftable-iterator.h"
/*
+1 -1
View File
@@ -9,8 +9,8 @@
#ifndef REFTABLE_RECORD_H
#define REFTABLE_RECORD_H
#include "reftable-system.h"
#include "reftable-basics.h"
#include <stdint.h>
/*
* Basic data types
+1
View File
@@ -9,6 +9,7 @@
#ifndef REFTABLE_STACK_H
#define REFTABLE_STACK_H
#include "reftable-system.h"
#include "reftable-writer.h"
/*
+18
View File
@@ -0,0 +1,18 @@
#ifndef REFTABLE_SYSTEM_H
#define REFTABLE_SYSTEM_H
/*
* This header defines the platform-specific bits required to compile the
* reftable library. It should provide an environment that bridges over the
* gaps between POSIX and your system, as well as the zlib interfaces. This
* header is expected to be changed by the individual project.
*/
#define MINGW_DONT_HANDLE_IN_USE_ERROR
#include "compat/posix.h"
#include "compat/zlib-compat.h"
int reftable_fsync(int fd);
#define fsync(fd) reftable_fsync(fd)
#endif
+1
View File
@@ -9,6 +9,7 @@
#ifndef REFTABLE_TABLE_H
#define REFTABLE_TABLE_H
#include "reftable-system.h"
#include "reftable-iterator.h"
#include "reftable-block.h"
#include "reftable-blocksource.h"
+1 -9
View File
@@ -9,11 +9,9 @@
#ifndef REFTABLE_WRITER_H
#define REFTABLE_WRITER_H
#include "reftable-system.h"
#include "reftable-record.h"
#include <stdint.h>
#include <unistd.h> /* ssize_t */
/* Writing single reftables */
/* reftable_write_options sets options for writing a single reftable. */
@@ -63,12 +61,6 @@ struct reftable_write_options {
*/
long lock_timeout_ms;
/*
* Optional callback used to fsync files to disk. Falls back to using
* fsync(3P) when unset.
*/
int (*fsync)(int fd);
/*
* Callback function to execute whenever the stack is being reloaded.
* This can be used e.g. to discard cached information that relies on
+7 -33
View File
@@ -29,13 +29,6 @@ static int stack_filename(struct reftable_buf *dest, struct reftable_stack *st,
return 0;
}
static int stack_fsync(const struct reftable_write_options *opts, int fd)
{
if (opts->fsync)
return opts->fsync(fd);
return fsync(fd);
}
static ssize_t reftable_write_data(int fd, const void *data, size_t size)
{
size_t total_written = 0;
@@ -69,7 +62,7 @@ static ssize_t fd_writer_write(void *arg, const void *data, size_t sz)
static int fd_writer_flush(void *arg)
{
struct fd_writer *writer = arg;
return stack_fsync(writer->opts, writer->fd);
return fsync(writer->fd);
}
static int fd_read_lines(int fd, char ***namesp)
@@ -372,45 +365,26 @@ done:
return err;
}
/* return negative if a before b. */
static int tv_cmp(struct timeval *a, struct timeval *b)
{
time_t diff = a->tv_sec - b->tv_sec;
int udiff = a->tv_usec - b->tv_usec;
if (diff != 0)
return diff;
return udiff;
}
static int reftable_stack_reload_maybe_reuse(struct reftable_stack *st,
int reuse_open)
{
char **names = NULL, **names_after = NULL;
struct timeval deadline;
uint64_t deadline;
int64_t delay = 0;
int tries = 0, err;
int fd = -1;
err = gettimeofday(&deadline, NULL);
if (err < 0)
goto out;
deadline.tv_sec += 3;
deadline = reftable_time_ms() + 3000;
while (1) {
struct timeval now;
err = gettimeofday(&now, NULL);
if (err < 0)
goto out;
uint64_t now = reftable_time_ms();
/*
* Only look at deadlines after the first few times. This
* simplifies debugging in GDB.
*/
tries++;
if (tries > 3 && tv_cmp(&now, &deadline) >= 0)
if (tries > 3 && now >= deadline)
goto out;
fd = open(st->list_file, O_RDONLY);
@@ -812,7 +786,7 @@ int reftable_addition_commit(struct reftable_addition *add)
goto done;
}
err = stack_fsync(&add->stack->opts, add->tables_list_lock.fd);
err = fsync(add->tables_list_lock.fd);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
@@ -1480,7 +1454,7 @@ static int stack_compact_range(struct reftable_stack *st,
goto done;
}
err = stack_fsync(&st->opts, tables_list_lock.fd);
err = fsync(tables_list_lock.fd);
if (err < 0) {
err = REFTABLE_IO_ERROR;
unlink(new_table_path.buf);
+32
View File
@@ -4,7 +4,9 @@
#include "basics.h"
#include "reftable-error.h"
#include "../lockfile.h"
#include "../trace.h"
#include "../tempfile.h"
#include "../write-or-die.h"
uint32_t reftable_rand(void)
{
@@ -131,3 +133,33 @@ int flock_commit(struct reftable_flock *l)
return 0;
}
int reftable_fsync(int fd)
{
return fsync_component(FSYNC_COMPONENT_REFERENCE, fd);
}
uint64_t reftable_time_ms(void)
{
return getnanotime() / 1000000;
}
int reftable_mmap(struct reftable_mmap *out, int fd, size_t len)
{
void *data = xmmap_gently(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
if (data == MAP_FAILED)
return REFTABLE_IO_ERROR;
out->data = data;
out->size = len;
return 0;
}
int reftable_munmap(struct reftable_mmap *mmap)
{
if (munmap(mmap->data, mmap->size) < 0)
return REFTABLE_IO_ERROR;
memset(mmap, 0, sizeof(*mmap));
return 0;
}
+28 -4
View File
@@ -9,11 +9,14 @@
#ifndef SYSTEM_H
#define SYSTEM_H
/* This header glues the reftable library to the rest of Git */
/*
* This header defines the platform-agnostic interface that is to be
* implemented by the project to make it work on their respective supported
* systems, and to integrate it into the project itself. This header is not
* expected to be changed by the individual project.
*/
#define MINGW_DONT_HANDLE_IN_USE_ERROR
#include "compat/posix.h"
#include "compat/zlib-compat.h"
#include "reftable-system.h"
/*
* Return a random 32 bit integer. This function is expected to return
@@ -108,4 +111,25 @@ int flock_release(struct reftable_flock *l);
*/
int flock_commit(struct reftable_flock *l);
/* Report the time in milliseconds. */
uint64_t reftable_time_ms(void);
struct reftable_mmap {
void *data;
size_t size;
void *priv;
};
/*
* Map the file into memory. Returns 0 on success, a reftable error code on
* error.
*/
int reftable_mmap(struct reftable_mmap *out, int fd, size_t len);
/*
* Unmap the file from memory. Returns 0 on success, a reftable error code on
* error.
*/
int reftable_munmap(struct reftable_mmap *mmap);
#endif
+1 -1
View File
@@ -1723,7 +1723,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) {
if (starts_with(ref->name, "refs/tags/"))
reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
else if (!odb_has_object(the_repository->objects, &ref->old_oid, HAS_OBJECT_RECHECK_PACKED))
else if (!odb_has_object(the_repository->objects, &ref->old_oid, ODB_HAS_OBJECT_RECHECK_PACKED))
reject_reason = REF_STATUS_REJECT_FETCH_FIRST;
else if (!lookup_commit_reference_gently(the_repository, &ref->old_oid, 1) ||
!lookup_commit_reference_gently(the_repository, &ref->new_oid, 1))
+43 -17
View File
@@ -254,7 +254,10 @@ static struct commit *mapped_commit(kh_oid_map_t *replayed_commits,
struct commit *commit,
struct commit *fallback)
{
khint_t pos = kh_get_oid_map(replayed_commits, commit->object.oid);
khint_t pos;
if (!commit)
return fallback;
pos = kh_get_oid_map(replayed_commits, commit->object.oid);
if (pos == kh_end(replayed_commits))
return fallback;
return kh_value(replayed_commits, pos);
@@ -271,18 +274,26 @@ static struct commit *pick_regular_commit(struct repository *repo,
struct commit *base, *replayed_base;
struct tree *pickme_tree, *base_tree, *replayed_base_tree;
base = pickme->parents->item;
replayed_base = mapped_commit(replayed_commits, base, onto);
if (pickme->parents) {
base = pickme->parents->item;
base_tree = repo_get_commit_tree(repo, base);
} else {
base = NULL;
base_tree = lookup_tree(repo, repo->hash_algo->empty_tree);
}
replayed_base = mapped_commit(replayed_commits, base, onto);
replayed_base_tree = repo_get_commit_tree(repo, replayed_base);
pickme_tree = repo_get_commit_tree(repo, pickme);
base_tree = repo_get_commit_tree(repo, base);
if (mode == REPLAY_MODE_PICK) {
/* Cherry-pick: normal order */
merge_opt->branch1 = short_commit_name(repo, replayed_base);
merge_opt->branch2 = short_commit_name(repo, pickme);
merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2);
if (pickme->parents)
merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2);
else
merge_opt->ancestor = xstrdup("empty tree");
merge_incore_nonrecursive(merge_opt,
base_tree,
@@ -347,13 +358,15 @@ int replay_revisions(struct rev_info *revs,
struct commit *last_commit = NULL;
struct commit *commit;
struct commit *onto = NULL;
struct merge_options merge_opt;
struct merge_options merge_opt = { 0 };
struct merge_result result = {
.clean = 1,
};
bool detached_head;
char *advance;
char *revert;
const char *ref;
struct object_id old_oid;
enum replay_mode mode = REPLAY_MODE_PICK;
int ret;
@@ -364,7 +377,26 @@ int replay_revisions(struct rev_info *revs,
set_up_replay_mode(revs->repo, &revs->cmdline, opts->onto,
&detached_head, &advance, &revert, &onto, &update_refs);
/* FIXME: Should allow replaying commits with the first as a root commit */
if (opts->ref) {
struct object_id oid;
if (update_refs && strset_get_size(update_refs) > 1) {
ret = error(_("'--ref' cannot be used with multiple revision ranges"));
goto out;
}
if (check_refname_format(opts->ref, 0) || !starts_with(opts->ref, "refs/")) {
ret = error(_("'%s' is not a valid refname"), opts->ref);
goto out;
}
ref = opts->ref;
if (!refs_read_ref(get_main_ref_store(revs->repo), opts->ref, &oid))
oidcpy(&old_oid, &oid);
else
oidclr(&old_oid, revs->repo->hash_algo);
} else {
ref = advance ? advance : revert;
oidcpy(&old_oid, &onto->object.oid);
}
if (prepare_revision_walk(revs) < 0) {
ret = error(_("error preparing revisions"));
@@ -380,9 +412,7 @@ int replay_revisions(struct rev_info *revs,
khint_t pos;
int hr;
if (!commit->parents)
die(_("replaying down from root commit is not supported yet!"));
if (commit->parents->next)
if (commit->parents && commit->parents->next)
die(_("replaying merge commits is not supported yet!"));
last_commit = pick_regular_commit(revs->repo, commit, replayed_commits,
@@ -399,7 +429,7 @@ int replay_revisions(struct rev_info *revs,
kh_value(replayed_commits, pos) = last_commit;
/* Update any necessary branches */
if (advance || revert)
if (ref)
continue;
for (decoration = get_name_decoration(&commit->object);
@@ -433,13 +463,9 @@ int replay_revisions(struct rev_info *revs,
goto out;
}
/* In --advance or --revert mode, update the target ref */
if (advance || revert) {
const char *ref = advance ? advance : revert;
replay_result_queue_update(out, ref,
&onto->object.oid,
if (ref)
replay_result_queue_update(out, ref, &old_oid,
&last_commit->object.oid);
}
ret = 0;
+7
View File
@@ -24,6 +24,13 @@ struct replay_revisions_options {
*/
const char *onto;
/*
* Reference to update with the result of the replay. This will not
* update any refs from `onto`, `advance`, or `revert`. Ignores
* `contained`.
*/
const char *ref;
/*
* Starting point at which to create revert commits; must be a branch
* name. The branch will be updated to point to the revert commits.
+36 -33
View File
@@ -2038,41 +2038,32 @@ static void prepare_show_merge(struct rev_info *revs)
free(prune);
}
static int dotdot_missing(const char *arg, char *dotdot,
static int dotdot_missing(const char *full_name,
struct rev_info *revs, int symmetric)
{
if (revs->ignore_missing)
return 0;
/* de-munge so we report the full argument */
*dotdot = '.';
die(symmetric
? "Invalid symmetric difference expression %s"
: "Invalid revision range %s", arg);
: "Invalid revision range %s", full_name);
}
static int handle_dotdot_1(const char *arg, char *dotdot,
static int handle_dotdot_1(const char *a_name, const char *b_name,
const char *full_name, int symmetric,
struct rev_info *revs, int flags,
int cant_be_filename,
struct object_context *a_oc,
struct object_context *b_oc)
{
const char *a_name, *b_name;
struct object_id a_oid, b_oid;
struct object *a_obj, *b_obj;
unsigned int a_flags, b_flags;
int symmetric = 0;
unsigned int flags_exclude = flags ^ (UNINTERESTING | BOTTOM);
unsigned int oc_flags = GET_OID_COMMITTISH | GET_OID_RECORD_PATH;
a_name = arg;
if (!*a_name)
a_name = "HEAD";
b_name = dotdot + 2;
if (*b_name == '.') {
symmetric = 1;
b_name++;
}
if (!*b_name)
b_name = "HEAD";
@@ -2081,15 +2072,13 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
return -1;
if (!cant_be_filename) {
*dotdot = '.';
verify_non_filename(revs->prefix, arg);
*dotdot = '\0';
verify_non_filename(revs->prefix, full_name);
}
a_obj = parse_object(revs->repo, &a_oid);
b_obj = parse_object(revs->repo, &b_oid);
if (!a_obj || !b_obj)
return dotdot_missing(arg, dotdot, revs, symmetric);
return dotdot_missing(full_name, revs, symmetric);
if (!symmetric) {
/* just A..B */
@@ -2103,7 +2092,7 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
a = lookup_commit_reference(revs->repo, &a_obj->oid);
b = lookup_commit_reference(revs->repo, &b_obj->oid);
if (!a || !b)
return dotdot_missing(arg, dotdot, revs, symmetric);
return dotdot_missing(full_name, revs, symmetric);
if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0) {
commit_list_free(exclude);
@@ -2132,16 +2121,23 @@ static int handle_dotdot(const char *arg,
int cant_be_filename)
{
struct object_context a_oc = {0}, b_oc = {0};
char *dotdot = strstr(arg, "..");
const char *dotdot = strstr(arg, "..");
char *tmp;
int symmetric = 0;
int ret;
if (!dotdot)
return -1;
*dotdot = '\0';
ret = handle_dotdot_1(arg, dotdot, revs, flags, cant_be_filename,
&a_oc, &b_oc);
*dotdot = '.';
tmp = xmemdupz(arg, dotdot - arg);
dotdot += 2;
if (*dotdot == '.') {
symmetric = 1;
dotdot++;
}
ret = handle_dotdot_1(tmp, dotdot, arg, symmetric, revs, flags,
cant_be_filename, &a_oc, &b_oc);
free(tmp);
object_context_release(&a_oc);
object_context_release(&b_oc);
@@ -2151,7 +2147,10 @@ static int handle_dotdot(const char *arg,
static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
{
struct object_context oc = {0};
char *mark;
const char *mark;
char *arg_minus_at = NULL;
char *arg_minus_excl = NULL;
char *arg_minus_dash = NULL;
struct object *object;
struct object_id oid;
int local_flags;
@@ -2178,18 +2177,17 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
mark = strstr(arg, "^@");
if (mark && !mark[2]) {
*mark = 0;
if (add_parents_only(revs, arg, flags, 0)) {
arg_minus_at = xmemdupz(arg, mark - arg);
if (add_parents_only(revs, arg_minus_at, flags, 0)) {
ret = 0;
goto out;
}
*mark = '^';
}
mark = strstr(arg, "^!");
if (mark && !mark[2]) {
*mark = 0;
if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), 0))
*mark = '^';
arg_minus_excl = xmemdupz(arg, mark - arg);
if (add_parents_only(revs, arg_minus_excl, flags ^ (UNINTERESTING | BOTTOM), 0))
arg = arg_minus_excl;
}
mark = strstr(arg, "^-");
if (mark) {
@@ -2203,9 +2201,9 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
}
}
*mark = 0;
if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), exclude_parent))
*mark = '^';
arg_minus_dash = xmemdupz(arg, mark - arg);
if (add_parents_only(revs, arg_minus_dash, flags ^ (UNINTERESTING | BOTTOM), exclude_parent))
arg = arg_minus_dash;
}
local_flags = 0;
@@ -2240,6 +2238,9 @@ static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int fl
out:
object_context_release(&oc);
free(arg_minus_at);
free(arg_minus_excl);
free(arg_minus_dash);
return ret;
}
@@ -3128,6 +3129,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
if (want_ancestry(revs))
revs->limited = 1;
revs->topo_order = 1;
if (!revs->diffopt.output_format)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
}
if (revs->topo_order && !generation_numbers_enabled(the_repository))
+8 -3
View File
@@ -1895,14 +1895,19 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
"max:%"PRIuMAX,
(uintmax_t)opts->processes);
pp_init(&pp, opts, &pp_sig);
/*
* Child tasks might receive input via stdin, terminating early (or not), so
* ignore the default SIGPIPE which gets handled by each feed_pipe_fn which
* actually writes the data to children stdin fds.
*
* This _must_ come after pp_init(), because it installs its own
* SIGPIPE handler (to cleanup children), and we want to supersede
* that.
*/
sigchain_push(SIGPIPE, SIG_IGN);
pp_init(&pp, opts, &pp_sig);
while (1) {
for (i = 0;
i < spawn_cap && !pp.shutdown &&
@@ -1928,10 +1933,10 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
}
}
pp_cleanup(&pp, opts);
sigchain_pop(SIGPIPE);
pp_cleanup(&pp, opts);
if (do_trace2)
trace2_region_leave(tr2_category, tr2_label, NULL);
}
+3 -3
View File
@@ -360,7 +360,7 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
return 0;
if (data->flags & QUICK) {
if (!odb_has_object(the_repository->objects, &graft->oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
return 0;
} else if (data->flags & SEEN_ONLY) {
struct commit *c = lookup_commit(the_repository, &graft->oid);
@@ -528,7 +528,7 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
ALLOC_ARRAY(info->theirs, sa->nr);
for (size_t i = 0; i < sa->nr; i++) {
if (odb_has_object(the_repository->objects, sa->oid + i,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR)) {
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR)) {
struct commit_graft *graft;
graft = lookup_commit_graft(the_repository,
&sa->oid[i]);
@@ -567,7 +567,7 @@ void remove_nonexistent_theirs_shallow(struct shallow_info *info)
if (i != dst)
info->theirs[dst] = info->theirs[i];
if (odb_has_object(the_repository->objects, oid + info->theirs[i],
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
dst++;
}
info->nr_theirs = dst;
+3 -1
View File
@@ -675,7 +675,9 @@ test_expect_success 'match percent-encoded values' '
test_expect_success 'match percent-encoded UTF-8 values in path' '
test_config credential.https://example.com.useHttpPath true &&
test_config credential.https://example.com/perú.git.helper "$HELPER" &&
check fill <<-\EOF
# NOTE: do not quote this heredoc, Dash 0.5.13 has a bug with heredocs
# that contain multibyte chars.
check fill <<-EOF
url=https://example.com/per%C3%BA.git
--
protocol=https

Some files were not shown because too many files have changed in this diff Show More