aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/CodingGuidelines12
-rw-r--r--Documentation/RelNotes/2.54.0.adoc31
-rw-r--r--Documentation/git-fast-import.adoc9
-rw-r--r--Documentation/git-replay.adoc45
-rw-r--r--Documentation/line-range-options.adoc4
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--add-patch.c8
-rw-r--r--apply.c12
-rw-r--r--builtin/backfill.c2
-rw-r--r--builtin/cat-file.c2
-rw-r--r--builtin/fast-export.c15
-rw-r--r--builtin/fast-import.c71
-rw-r--r--builtin/fetch.c4
-rw-r--r--builtin/fsck.c275
-rw-r--r--builtin/history.c8
-rw-r--r--builtin/index-pack.c6
-rw-r--r--builtin/mktag.c5
-rw-r--r--builtin/receive-pack.c41
-rw-r--r--builtin/refs.c6
-rw-r--r--builtin/remote.c2
-rw-r--r--builtin/replay.c38
-rw-r--r--builtin/show-ref.c2
-rw-r--r--builtin/unpack-objects.c8
-rw-r--r--cache-tree.c14
-rw-r--r--commit-graph.c37
-rw-r--r--diff.c279
-rw-r--r--diffcore.h16
-rw-r--r--fetch-pack.c13
-rw-r--r--fsck.c76
-rw-r--r--fsck.h42
-rw-r--r--gpg-interface.c2
-rw-r--r--gpg-interface.h1
-rw-r--r--http-push.c8
-rw-r--r--http-walker.c4
-rw-r--r--line-log.c196
-rw-r--r--line-log.h14
-rw-r--r--list-objects.c2
-rw-r--r--notes.c2
-rw-r--r--object-file.c12
-rw-r--r--object-file.h3
-rw-r--r--odb.c10
-rw-r--r--odb.h30
-rw-r--r--odb/source-files.c2
-rw-r--r--odb/source.h4
-rw-r--r--pack-check.c7
-rw-r--r--pack.h9
-rw-r--r--packfile.c2
-rw-r--r--packfile.h2
-rw-r--r--path-walk.c2
-rw-r--r--read-cache.c33
-rw-r--r--reflog.c2
-rw-r--r--refs.c2
-rw-r--r--refs/reftable-backend.c6
-rw-r--r--reftable/blocksource.c19
-rw-r--r--reftable/fsck.c2
-rw-r--r--reftable/reftable-basics.h2
-rw-r--r--reftable/reftable-block.h3
-rw-r--r--reftable/reftable-blocksource.h2
-rw-r--r--reftable/reftable-error.h2
-rw-r--r--reftable/reftable-fsck.h1
-rw-r--r--reftable/reftable-iterator.h1
-rw-r--r--reftable/reftable-merged.h1
-rw-r--r--reftable/reftable-record.h2
-rw-r--r--reftable/reftable-stack.h1
-rw-r--r--reftable/reftable-system.h18
-rw-r--r--reftable/reftable-table.h1
-rw-r--r--reftable/reftable-writer.h10
-rw-r--r--reftable/stack.c40
-rw-r--r--reftable/system.c32
-rw-r--r--reftable/system.h32
-rw-r--r--remote.c2
-rw-r--r--replay.c35
-rw-r--r--replay.h7
-rw-r--r--revision.c2
-rw-r--r--shallow.c6
-rwxr-xr-xt/t1800-hook.sh12
-rwxr-xr-xt/t2200-add-update.sh38
-rwxr-xr-xt/t3650-replay-basics.sh66
-rwxr-xr-xt/t4124-apply-ws-rule.sh16
-rwxr-xr-xt/t4211-line-log.sh348
-rw-r--r--t/t4211/sha1/expect.beginning-of-file4
-rw-r--r--t/t4211/sha1/expect.end-of-file11
-rw-r--r--t/t4211/sha1/expect.move-support-f5
-rw-r--r--t/t4211/sha1/expect.multiple10
-rw-r--r--t/t4211/sha1/expect.multiple-overlapping7
-rw-r--r--t/t4211/sha1/expect.multiple-superset7
-rw-r--r--t/t4211/sha1/expect.no-assertion-error12
-rw-r--r--t/t4211/sha1/expect.parallel-change-f-to-main7
-rw-r--r--t/t4211/sha1/expect.simple-f4
-rw-r--r--t/t4211/sha1/expect.simple-f-to-main5
-rw-r--r--t/t4211/sha1/expect.simple-main11
-rw-r--r--t/t4211/sha1/expect.simple-main-to-end11
-rw-r--r--t/t4211/sha1/expect.two-ranges10
-rw-r--r--t/t4211/sha1/expect.vanishes-early10
-rw-r--r--t/t4211/sha256/expect.beginning-of-file4
-rw-r--r--t/t4211/sha256/expect.end-of-file11
-rw-r--r--t/t4211/sha256/expect.move-support-f5
-rw-r--r--t/t4211/sha256/expect.multiple10
-rw-r--r--t/t4211/sha256/expect.multiple-overlapping7
-rw-r--r--t/t4211/sha256/expect.multiple-superset7
-rw-r--r--t/t4211/sha256/expect.no-assertion-error12
-rw-r--r--t/t4211/sha256/expect.parallel-change-f-to-main7
-rw-r--r--t/t4211/sha256/expect.simple-f4
-rw-r--r--t/t4211/sha256/expect.simple-f-to-main5
-rw-r--r--t/t4211/sha256/expect.simple-main11
-rw-r--r--t/t4211/sha256/expect.simple-main-to-end11
-rw-r--r--t/t4211/sha256/expect.two-ranges10
-rw-r--r--t/t4211/sha256/expect.vanishes-early10
-rwxr-xr-xt/t5318-commit-graph.sh20
-rwxr-xr-xt/t5516-fetch-push.sh15
-rwxr-xr-xt/t5620-backfill.sh15
-rwxr-xr-xt/t7004-tag.sh15
-rwxr-xr-xt/t9305-fast-import-signatures.sh10
-rwxr-xr-xt/t9306-fast-import-signed-tags.sh118
-rw-r--r--walker.c2
115 files changed, 1892 insertions, 672 deletions
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index b8670751f5..4992e52093 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -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.:
diff --git a/Documentation/RelNotes/2.54.0.adoc b/Documentation/RelNotes/2.54.0.adoc
index c692dddb4a..27dbfdc6a5 100644
--- a/Documentation/RelNotes/2.54.0.adoc
+++ b/Documentation/RelNotes/2.54.0.adoc
@@ -121,6 +121,9 @@ UI, Workflows & Features
* 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.
--------------------------------------------------------------
@@ -300,6 +303,19 @@ Performance, Internal Implementation, Development Support etc.
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
-----------------
@@ -478,6 +494,21 @@ 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).
+
* 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).
diff --git a/Documentation/git-fast-import.adoc b/Documentation/git-fast-import.adoc
index b3f42d4637..d68bc52b7e 100644
--- a/Documentation/git-fast-import.adoc
+++ b/Documentation/git-fast-import.adoc
@@ -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
~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/git-replay.adoc b/Documentation/git-replay.adoc
index 997097e420..a32f72aead 100644
--- a/Documentation/git-replay.adoc
+++ b/Documentation/git-replay.adoc
@@ -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
diff --git a/Documentation/line-range-options.adoc b/Documentation/line-range-options.adoc
index c44ba05320..ecb2c79fb9 100644
--- a/Documentation/line-range-options.adoc
+++ b/Documentation/line-range-options.adoc
@@ -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[]
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 92ea811ae6..9c55beb496 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,6 +1,6 @@
#!/bin/sh
-DEF_VER=v2.54.0-rc0
+DEF_VER=v2.54.0-rc1
LF='
'
diff --git a/add-patch.c b/add-patch.c
index 4e28e5c187..f27edcbe8d 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -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);
diff --git a/apply.c b/apply.c
index 63d5e3c460..4aa1694cfa 100644
--- a/apply.c
+++ b/apply.c
@@ -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)
diff --git a/builtin/backfill.c b/builtin/backfill.c
index 2c5ce56fb7..d794dd842f 100644
--- a/builtin/backfill.c
+++ b/builtin/backfill.c
@@ -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[] = {
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index cd13a3a89f..d9fbad5358 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -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':
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 13621b0d6a..2eb43a28da 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -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);
}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 570fd048d7..82bc6dcc00 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -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;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 4795b2a13c..a22c319467 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -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;
}
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 9bab32effe..248f8ff5a0 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -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",
diff --git a/builtin/history.c b/builtin/history.c
index 568dc75ee7..9526938085 100644
--- a/builtin/history.c
+++ b/builtin/history.c
@@ -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")),
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index d1e47279a8..ca7784dc2c 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -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);
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 7cf6e1230a..f40264a878 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -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);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index cb3656a034..dada55884a 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -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";
diff --git a/builtin/refs.c b/builtin/refs.c
index 3064f888b2..e3125bc61b 100644
--- a/builtin/refs.c
+++ b/builtin/refs.c
@@ -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"));
diff --git a/builtin/remote.c b/builtin/remote.c
index 0fddaa1773..de989ea3ba 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -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
diff --git a/builtin/replay.c b/builtin/replay.c
index a0879b020f..39e3a86f6c 100644
--- a/builtin/replay.c
+++ b/builtin/replay.c
@@ -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);
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 5d31acea7c..d508441632 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -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));
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 6fc64e9e4b..e01cf6e360 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -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];
diff --git a/cache-tree.c b/cache-tree.c
index 60bcc07c3b..7881b42aa2 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -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;
diff --git a/commit-graph.c b/commit-graph.c
index df4b4a125e..9abe62bd5a 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -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++;
}
diff --git a/diff.c b/diff.c
index e87847fa4b..397e38b41c 100644
--- a/diff.c
+++ b/diff.c
@@ -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;
diff --git a/diffcore.h b/diffcore.h
index 9c0a0e7aaf..d75038d1b3 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -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;
diff --git a/fetch-pack.c b/fetch-pack.c
index a32224ed02..c8fa0a609a 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -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,
diff --git a/fsck.c b/fsck.c
index 0f02cf8f77..b72200c352 100644
--- a/fsck.c
+++ b/fsck.c
@@ -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);
diff --git a/fsck.h b/fsck.h
index 65ecbb7fe1..e77935c8a9 100644
--- a/fsck.h
+++ b/fsck.h
@@ -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.
*/
diff --git a/gpg-interface.c b/gpg-interface.c
index d517425034..dafd5371fa 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -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")) {
diff --git a/gpg-interface.h b/gpg-interface.h
index a365586ce1..3d95f5ec14 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -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,
diff --git a/http-push.c b/http-push.c
index 9ae6062198..06c3acbb5d 100644
--- a/http-push.c
+++ b/http-push.c
@@ -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)) {
/*
diff --git a/http-walker.c b/http-walker.c
index e886e64866..1b6d496548 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -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);
diff --git a/line-log.c b/line-log.c
index eeaf68454e..858a899cd2 100644
--- a/line-log.c
+++ b/line-log.c
@@ -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()) {
+ struct diff_options rename_opts;
+
+ /*
+ * 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 */
- clear_pathspec(&opt->pathspec);
diff_queue_clear(&diff_queued_diff);
-
- diff_tree_oid(parent_tree_oid, tree_oid, "", opt);
+ 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;
}
diff --git a/line-log.h b/line-log.h
index e9dadbc1a5..04a6ea64d3 100644
--- a/line-log.h
+++ b/line-log.h
@@ -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 {
diff --git a/list-objects.c b/list-objects.c
index 91b23e22f7..724d723c48 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -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;
diff --git a/notes.c b/notes.c
index 51a7ef9f83..8f315e2a00 100644
--- a/notes.c
+++ b/notes.c
@@ -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 */
diff --git a/object-file.c b/object-file.c
index 63408fc290..2acc9522df 100644
--- a/object-file.c
+++ b/object-file.c
@@ -909,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 "
@@ -1042,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);
}
@@ -1169,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;
@@ -1282,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))
@@ -1377,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 */
diff --git a/object-file.h b/object-file.h
index 3686f182e4..5241b8dd5c 100644
--- a/object-file.h
+++ b/object-file.h
@@ -68,7 +68,8 @@ 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,
diff --git a/odb.c b/odb.c
index 3f94a53df1..9b28fe25ef 100644
--- a/odb.c
+++ b/odb.c
@@ -872,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;
@@ -922,7 +922,7 @@ 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)
{
struct odb_for_each_object_options opts = {
.flags = flags,
@@ -1053,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);
diff --git a/odb.h b/odb.h
index 984bafca9d..3a711f6547 100644
--- a/odb.h
+++ b/odb.h
@@ -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);
@@ -522,7 +516,7 @@ 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 {
/*
@@ -561,19 +555,19 @@ int odb_find_abbrev_len(struct object_database *odb,
int min_len,
unsigned *out);
-enum {
+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),
};
/*
@@ -589,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,
diff --git a/odb/source-files.c b/odb/source-files.c
index 76797569de..b5abd20e97 100644
--- a/odb/source-files.c
+++ b/odb/source-files.c
@@ -161,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);
diff --git a/odb/source.h b/odb/source.h
index a9d7d0b96f..f706e0608a 100644
--- a/odb/source.h
+++ b/odb/source.h
@@ -197,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
@@ -405,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);
diff --git a/pack-check.c b/pack-check.c
index 7378c80730..79992bb509 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -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;
diff --git a/pack.h b/pack.h
index ec76472e49..1cde92082b 100644
--- a/pack.h
+++ b/pack.h
@@ -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,
diff --git a/packfile.c b/packfile.c
index 48c88748b6..b012d648ad 100644
--- a/packfile.c
+++ b/packfile.c
@@ -2300,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;
diff --git a/packfile.h b/packfile.h
index 6e8802e2ed..9b647da7dd 100644
--- a/packfile.h
+++ b/packfile.h
@@ -354,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
diff --git a/path-walk.c b/path-walk.c
index 2aa3e7d8a4..6e426af433 100644
--- a/path-walk.c
+++ b/path-walk.c
@@ -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;
}
diff --git a/read-cache.c b/read-cache.c
index 5049f9baca..38a04b8de3 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -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 */
/*
diff --git a/reflog.c b/reflog.c
index 1460ae9d0d..82337078d0 100644
--- a/reflog.c
+++ b/reflog.c
@@ -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;
diff --git a/refs.c b/refs.c
index 5d1d28523d..bfcb9c7ac3 100644
--- a/refs.c
+++ b/refs.c
@@ -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;
}
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index b124404663..daea30a5b4 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -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);
diff --git a/reftable/blocksource.c b/reftable/blocksource.c
index 573c81287f..7f7441f751 100644
--- a/reftable/blocksource.c
+++ b/reftable/blocksource.c
@@ -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;
diff --git a/reftable/fsck.c b/reftable/fsck.c
index 26b9115b14..8e73fc83f2 100644
--- a/reftable/fsck.c
+++ b/reftable/fsck.c
@@ -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[] = {
diff --git a/reftable/reftable-basics.h b/reftable/reftable-basics.h
index 6d73f19c85..dc8622682d 100644
--- a/reftable/reftable-basics.h
+++ b/reftable/reftable-basics.h
@@ -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 {
diff --git a/reftable/reftable-block.h b/reftable/reftable-block.h
index 0b05a8f7e3..94c79b5c58 100644
--- a/reftable/reftable-block.h
+++ b/reftable/reftable-block.h
@@ -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"
diff --git a/reftable/reftable-blocksource.h b/reftable/reftable-blocksource.h
index f5ba867bd6..40c1e94646 100644
--- a/reftable/reftable-blocksource.h
+++ b/reftable/reftable-blocksource.h
@@ -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.
diff --git a/reftable/reftable-error.h b/reftable/reftable-error.h
index d100e0df92..0535e1478b 100644
--- a/reftable/reftable-error.h
+++ b/reftable/reftable-error.h
@@ -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.
diff --git a/reftable/reftable-fsck.h b/reftable/reftable-fsck.h
index 007a392cf9..340fc7762e 100644
--- a/reftable/reftable-fsck.h
+++ b/reftable/reftable-fsck.h
@@ -1,6 +1,7 @@
#ifndef REFTABLE_FSCK_H
#define REFTABLE_FSCK_H
+#include "reftable-system.h"
#include "reftable-stack.h"
enum reftable_fsck_error {
diff --git a/reftable/reftable-iterator.h b/reftable/reftable-iterator.h
index af582028c2..a050cc153b 100644
--- a/reftable/reftable-iterator.h
+++ b/reftable/reftable-iterator.h
@@ -9,6 +9,7 @@
#ifndef REFTABLE_ITERATOR_H
#define REFTABLE_ITERATOR_H
+#include "reftable-system.h"
#include "reftable-record.h"
struct reftable_iterator_vtable;
diff --git a/reftable/reftable-merged.h b/reftable/reftable-merged.h
index e5af846b32..02a9966835 100644
--- a/reftable/reftable-merged.h
+++ b/reftable/reftable-merged.h
@@ -9,6 +9,7 @@
#ifndef REFTABLE_MERGED_H
#define REFTABLE_MERGED_H
+#include "reftable-system.h"
#include "reftable-iterator.h"
/*
diff --git a/reftable/reftable-record.h b/reftable/reftable-record.h
index 385a74cc86..e18c538238 100644
--- a/reftable/reftable-record.h
+++ b/reftable/reftable-record.h
@@ -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
diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h
index c2415cbc6e..5f7be573fa 100644
--- a/reftable/reftable-stack.h
+++ b/reftable/reftable-stack.h
@@ -9,6 +9,7 @@
#ifndef REFTABLE_STACK_H
#define REFTABLE_STACK_H
+#include "reftable-system.h"
#include "reftable-writer.h"
/*
diff --git a/reftable/reftable-system.h b/reftable/reftable-system.h
new file mode 100644
index 0000000000..76f3e33e90
--- /dev/null
+++ b/reftable/reftable-system.h
@@ -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
diff --git a/reftable/reftable-table.h b/reftable/reftable-table.h
index 5f935d02e3..d7666b53a1 100644
--- a/reftable/reftable-table.h
+++ b/reftable/reftable-table.h
@@ -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"
diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h
index 1e7003cd69..a66db415c8 100644
--- a/reftable/reftable-writer.h
+++ b/reftable/reftable-writer.h
@@ -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. */
@@ -64,12 +62,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
* the old stack's data. The payload data will be passed as argument to
diff --git a/reftable/stack.c b/reftable/stack.c
index 1c9f21dfe1..1fba96ddb3 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -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);
diff --git a/reftable/system.c b/reftable/system.c
index 725a25844e..9063641f30 100644
--- a/reftable/system.c
+++ b/reftable/system.c
@@ -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;
+}
diff --git a/reftable/system.h b/reftable/system.h
index c54ed4cad6..c0e2cbe0ff 100644
--- a/reftable/system.h
+++ b/reftable/system.h
@@ -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
diff --git a/remote.c b/remote.c
index 7ca2a6501b..a664cd166a 100644
--- a/remote.c
+++ b/remote.c
@@ -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))
diff --git a/replay.c b/replay.c
index cf1f0bcba0..f96f1f6551 100644
--- a/replay.c
+++ b/replay.c
@@ -358,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;
@@ -375,6 +377,27 @@ int replay_revisions(struct rev_info *revs,
set_up_replay_mode(revs->repo, &revs->cmdline, opts->onto,
&detached_head, &advance, &revert, &onto, &update_refs);
+ 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"));
goto out;
@@ -406,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);
@@ -440,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;
diff --git a/replay.h b/replay.h
index e916a5f975..0ab74b9805 100644
--- a/replay.h
+++ b/replay.h
@@ -25,6 +25,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.
* This option is mutually exclusive with `onto` and `advance`.
diff --git a/revision.c b/revision.c
index fda405bf65..599b3a66c3 100644
--- a/revision.c
+++ b/revision.c
@@ -3129,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))
diff --git a/shallow.c b/shallow.c
index 7a3dd56795..a8ad92e303 100644
--- a/shallow.c
+++ b/shallow.c
@@ -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;
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index 96749fc06d..33decc66c0 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -6,16 +6,16 @@ test_description='git-hook command and config-managed multihooks'
. "$TEST_DIRECTORY"/lib-terminal.sh
setup_hooks () {
- test_config hook.ghi.command "/path/ghi"
- test_config hook.ghi.event pre-commit --add
- test_config hook.ghi.event test-hook --add
- test_config_global hook.def.command "/path/def"
+ test_config hook.ghi.command "/path/ghi" &&
+ test_config hook.ghi.event pre-commit --add &&
+ test_config hook.ghi.event test-hook --add &&
+ test_config_global hook.def.command "/path/def" &&
test_config_global hook.def.event pre-commit --add
}
setup_hookdir () {
- mkdir .git/hooks
- write_script .git/hooks/pre-commit <<-EOF
+ mkdir -p .git/hooks &&
+ write_script .git/hooks/pre-commit <<-EOF &&
echo \"Legacy Hook\"
EOF
test_when_finished rm -rf .git/hooks
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index 06e83d3333..0a96655cfe 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -200,6 +200,44 @@ test_expect_success 'add -u resolves unmerged paths' '
test_cmp expect actual
'
+test_expect_success 'add -u avoids rename pairing on unmerged paths' '
+ test_create_repo rename-crash &&
+ (
+ cd rename-crash &&
+ test_seq 1 100 |
+ sed "s/.*/line &: same text/" >conflict.txt &&
+ cp conflict.txt bystander.txt &&
+ git add conflict.txt bystander.txt &&
+ git commit -m "initial: two files with identical content" &&
+ main_branch=$(git symbolic-ref --short HEAD) &&
+ git checkout -b feature &&
+ sed "s/^line 50:.*/line 50: FEATURE/" \
+ conflict.txt >conflict.txt.tmp &&
+ mv conflict.txt.tmp conflict.txt &&
+ git add conflict.txt &&
+ git commit -m "feature: modify line 50" &&
+ git checkout "$main_branch" &&
+ sed "s/^line 50:.*/line 50: MAIN/" \
+ conflict.txt >conflict.txt.tmp &&
+ mv conflict.txt.tmp conflict.txt &&
+ git add conflict.txt &&
+ git commit -m "main: modify line 50 differently" &&
+ test_must_fail git merge feature &&
+ rm bystander.txt &&
+ git add -u >out &&
+ test_must_be_empty out &&
+ git ls-files -u >actual &&
+ test_must_be_empty actual &&
+ git ls-files bystander.txt conflict.txt >actual &&
+ cat >expect <<-\EOF &&
+ conflict.txt
+ EOF
+ test_cmp expect actual &&
+ git diff-files --name-only >actual &&
+ test_must_be_empty actual
+ )
+'
+
test_expect_success '"add -u non-existent" should fail' '
test_must_fail git add -u non-existent &&
git ls-files >actual &&
diff --git a/t/t3650-replay-basics.sh b/t/t3650-replay-basics.sh
index 89819ad4d2..3353bc4a4d 100755
--- a/t/t3650-replay-basics.sh
+++ b/t/t3650-replay-basics.sh
@@ -499,4 +499,70 @@ test_expect_success 'git replay --revert incompatible with --advance' '
test_grep "cannot be used together" error
'
+test_expect_success 'using --onto with --ref' '
+ git branch test-ref-onto topic2 &&
+ test_when_finished "git branch -D test-ref-onto" &&
+
+ git replay --ref-action=print --onto=main --ref=refs/heads/test-ref-onto topic1..topic2 >result &&
+
+ test_line_count = 1 result &&
+ test_grep "^update refs/heads/test-ref-onto " result &&
+
+ git log --format=%s $(cut -f 3 -d " " result) >actual &&
+ test_write_lines E D M L B A >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'using --advance with --ref' '
+ git branch test-ref-advance main &&
+ git branch test-ref-target main &&
+ test_when_finished "git branch -D test-ref-advance test-ref-target" &&
+
+ git replay --ref-action=print --advance=test-ref-advance --ref=refs/heads/test-ref-target topic1..topic2 >result &&
+
+ test_line_count = 1 result &&
+ test_grep "^update refs/heads/test-ref-target " result
+'
+
+test_expect_success 'using --revert with --ref' '
+ git branch test-ref-revert topic4 &&
+ git branch test-ref-revert-target topic4 &&
+ test_when_finished "git branch -D test-ref-revert test-ref-revert-target" &&
+
+ git replay --ref-action=print --revert=test-ref-revert --ref=refs/heads/test-ref-revert-target topic4~1..topic4 >result &&
+
+ test_line_count = 1 result &&
+ test_grep "^update refs/heads/test-ref-revert-target " result
+'
+
+test_expect_success '--ref is incompatible with --contained' '
+ test_must_fail git replay --onto=main --ref=refs/heads/main --contained topic1..topic2 2>err &&
+ test_grep "cannot be used together" err
+'
+
+test_expect_success '--ref with nonexistent fully-qualified ref' '
+ test_when_finished "git update-ref -d refs/heads/new-branch" &&
+
+ git replay --onto=main --ref=refs/heads/new-branch topic1..topic2 &&
+
+ git log --format=%s -2 new-branch >actual &&
+ test_write_lines E D >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success '--ref must be a valid refname' '
+ test_must_fail git replay --onto=main --ref="refs/heads/bad..ref" topic1..topic2 2>err &&
+ test_grep "is not a valid refname" err
+'
+
+test_expect_success '--ref requires fully qualified ref' '
+ test_must_fail git replay --onto=main --ref=main topic1..topic2 2>err &&
+ test_grep "is not a valid refname" err
+'
+
+test_expect_success '--onto with --ref rejects multiple revision ranges' '
+ test_must_fail git replay --onto=main --ref=refs/heads/topic2 ^topic1 topic2 topic4 2>err &&
+ test_grep "cannot be used with multiple revision ranges" err
+'
+
test_done
diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh
index 29ea7d4268..205d86d05e 100755
--- a/t/t4124-apply-ws-rule.sh
+++ b/t/t4124-apply-ws-rule.sh
@@ -561,6 +561,22 @@ test_expect_success 'check incomplete lines (setup)' '
git config core.whitespace incomplete-line
'
+test_expect_success 'no incomplete context line (not an error)' '
+ test_when_finished "rm -f sample*-i patch patch-new target" &&
+ test_write_lines 1 2 3 "" 4 5 >sample-i &&
+ test_write_lines 1 2 3 "" 0 5 >sample2-i &&
+ cat sample-i >target &&
+ git add target &&
+ cat sample2-i >target &&
+ git diff-files -p target >patch &&
+ sed -e "s/^ $//" <patch >patch-new &&
+
+ cat sample-i >target &&
+ git apply --whitespace=fix <patch-new 2>error &&
+ test_cmp sample2-i target &&
+ test_must_be_empty error
+'
+
test_expect_success 'incomplete context line (not an error)' '
(test_write_lines 1 2 3 4 5 && printf 6) >sample-i &&
(test_write_lines 1 2 3 0 5 && printf 6) >sample2-i &&
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index 0a7c3ca42f..aaf197d2ed 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -129,7 +129,7 @@ test_expect_success '-L with --output' '
git checkout parallel-change &&
git log --output=log -L :main:b.c >output &&
test_must_be_empty output &&
- test_line_count = 70 log
+ test_line_count = 75 log
'
test_expect_success 'range_set_union' '
@@ -339,14 +339,106 @@ test_expect_success 'zero-width regex .* matches any function name' '
test_cmp expect actual
'
+test_expect_success 'setup for diff pipeline tests' '
+ git checkout parent-oids &&
+
+ head_blob_old=$(git rev-parse --short HEAD^:file.c) &&
+ head_blob_new=$(git rev-parse --short HEAD:file.c) &&
+ root_blob=$(git rev-parse --short HEAD~4:file.c) &&
+ null_blob=$(test_oid zero | cut -c1-7) &&
+ head_blob_old_full=$(git rev-parse HEAD^:file.c) &&
+ head_blob_new_full=$(git rev-parse HEAD:file.c) &&
+ root_blob_full=$(git rev-parse HEAD~4:file.c) &&
+ null_blob_full=$(test_oid zero)
+'
+
+test_expect_success '-L diff output includes index and new file mode' '
+ git log -L:func2:file.c --format= >actual &&
+
+ # Output should contain index headers (not present in old code path)
+ grep "^index $head_blob_old\.\.$head_blob_new 100644" actual &&
+
+ # Root commit should show new file mode and null index
+ grep "^new file mode 100644" actual &&
+ grep "^index $null_blob\.\.$root_blob$" actual &&
+
+ # Hunk headers should include funcname context
+ grep "^@@ .* @@ int func1()" actual
+'
+
+test_expect_success '-L with --word-diff' '
+ cat >expect <<-\EOF &&
+
+ diff --git a/file.c b/file.c
+ --- a/file.c
+ +++ b/file.c
+ @@ -6,4 +6,4 @@ int func1()
+ int func2()
+ {
+ return [-F2;-]{+F2 + 2;+}
+ }
+
+ diff --git a/file.c b/file.c
+ new file mode 100644
+ --- /dev/null
+ +++ b/file.c
+ @@ -0,0 +6,4 @@
+ {+int func2()+}
+ {+{+}
+ {+ return F2;+}
+ {+}+}
+ EOF
+ git log -L:func2:file.c --word-diff --format= >actual &&
+ grep -v "^index " actual >actual.filtered &&
+ grep -v "^index " expect >expect.filtered &&
+ test_cmp expect.filtered actual.filtered
+'
+
+test_expect_success '-L with --no-prefix' '
+ git log -L:func2:file.c --no-prefix --format= >actual &&
+ grep "^diff --git file.c file.c" actual &&
+ grep "^--- file.c" actual &&
+ ! grep "^--- a/" actual
+'
+
+test_expect_success '-L with --full-index' '
+ git log -L:func2:file.c --full-index --format= >actual &&
+ grep "^index $head_blob_old_full\.\.$head_blob_new_full 100644" actual &&
+ grep "^index $null_blob_full\.\.$root_blob_full$" actual
+'
+
+test_expect_success 'setup -L with whitespace change' '
+ git checkout -b ws-change parent-oids &&
+ sed "s/ return F2 + 2;/ return F2 + 2;/" file.c >tmp &&
+ mv tmp file.c &&
+ git commit -a -m "Whitespace change in func2()"
+'
+
+test_expect_success '-L with --ignore-all-space suppresses whitespace-only diff' '
+ git log -L:func2:file.c --format= >without_w &&
+ git log -L:func2:file.c --format= -w >with_w &&
+
+ # Without -w: three commits produce diffs (whitespace, modify, root)
+ test $(grep -c "^diff --git" without_w) = 3 &&
+
+ # With -w: whitespace-only commit produces no hunk, so only two diffs
+ test $(grep -c "^diff --git" with_w) = 2
+'
+
test_expect_success 'show line-log with graph' '
+ git checkout parent-oids &&
+ head_blob_old=$(git rev-parse --short HEAD^:file.c) &&
+ head_blob_new=$(git rev-parse --short HEAD:file.c) &&
+ root_blob=$(git rev-parse --short HEAD~4:file.c) &&
+ null_blob=$(test_oid zero | cut -c1-7) &&
qz_to_tab_space >expect <<-EOF &&
* $head_oid Modify func2() in file.c
|Z
| diff --git a/file.c b/file.c
+ | index $head_blob_old..$head_blob_new 100644
| --- a/file.c
| +++ b/file.c
- | @@ -6,4 +6,4 @@
+ | @@ -6,4 +6,4 @@ int func1()
| int func2()
| {
| - return F2;
@@ -355,6 +447,8 @@ test_expect_success 'show line-log with graph' '
* $root_oid Add func1() and func2() in file.c
ZZ
diff --git a/file.c b/file.c
+ new file mode 100644
+ index $null_blob..$root_blob
--- /dev/null
+++ b/file.c
@@ -0,0 +6,4 @@
@@ -367,4 +461,254 @@ test_expect_success 'show line-log with graph' '
test_cmp expect actual
'
+test_expect_success 'setup for -L with -G/-S/--find-object and a merge with rename' '
+ git checkout --orphan pickaxe-rename &&
+ git reset --hard &&
+
+ echo content >file &&
+ git add file &&
+ git commit -m "add file" &&
+
+ git checkout -b pickaxe-rename-side &&
+ git mv file renamed-file &&
+ git commit -m "rename file" &&
+
+ git checkout pickaxe-rename &&
+ git commit --allow-empty -m "diverge" &&
+ git merge --no-edit pickaxe-rename-side &&
+
+ git mv renamed-file file &&
+ git commit -m "rename back"
+'
+
+test_expect_success '-L -G does not crash with merge and rename' '
+ git log --format="%s" --no-patch -L 1,1:file -G "." >actual
+'
+
+test_expect_success '-L -S does not crash with merge and rename' '
+ git log --format="%s" --no-patch -L 1,1:file -S content >actual
+'
+
+test_expect_success '-L --find-object does not crash with merge and rename' '
+ git log --format="%s" --no-patch -L 1,1:file \
+ --find-object=$(git rev-parse HEAD:file) >actual
+'
+
+# Commit-level filtering with pickaxe does not yet work for -L.
+# show_log() prints the commit header before diffcore_std() runs
+# pickaxe, so commits cannot be suppressed even when no diff pairs
+# survive filtering. Fixing this would require deferring show_log()
+# until after diffcore_std(), which is a larger restructuring of the
+# log-tree output pipeline.
+test_expect_failure '-L -G should filter commits by pattern' '
+ git log --format="%s" --no-patch -L 1,1:file -G "nomatch" >actual &&
+ test_must_be_empty actual
+'
+
+test_expect_failure '-L -S should filter commits by pattern' '
+ git log --format="%s" --no-patch -L 1,1:file -S "nomatch" >actual &&
+ test_must_be_empty actual
+'
+
+test_expect_failure '-L --find-object should filter commits by object' '
+ git log --format="%s" --no-patch -L 1,1:file \
+ --find-object=$ZERO_OID >actual &&
+ test_must_be_empty actual
+'
+
+test_expect_success '-L with --word-diff-regex' '
+ git checkout parent-oids &&
+ git log -L:func2:file.c --word-diff \
+ --word-diff-regex="[a-zA-Z0-9_]+" --format= >actual &&
+ # Word-diff markers must be present
+ grep "{+" actual &&
+ grep "+}" actual &&
+ # No line-level +/- markers (word-diff replaces them);
+ # exclude --- header lines from the check
+ ! grep "^+[^+]" actual &&
+ ! grep "^-[^-]" actual
+'
+
+test_expect_success '-L with --src-prefix and --dst-prefix' '
+ git checkout parent-oids &&
+ git log -L:func2:file.c --src-prefix=old/ --dst-prefix=new/ \
+ --format= >actual &&
+ grep "^diff --git old/file.c new/file.c" actual &&
+ grep "^--- old/file.c" actual &&
+ grep "^+++ new/file.c" actual &&
+ ! grep "^--- a/" actual
+'
+
+test_expect_success '-L with --abbrev' '
+ git checkout parent-oids &&
+ git log -L:func2:file.c --abbrev=4 --format= -1 >actual &&
+ # 4-char abbreviated hashes on index line
+ grep "^index [0-9a-f]\{4\}\.\.[0-9a-f]\{4\}" actual
+'
+
+test_expect_success '-L with -b suppresses whitespace-only diff' '
+ git checkout ws-change &&
+ git log -L:func2:file.c --format= >without_b &&
+ git log -L:func2:file.c --format= -b >with_b &&
+ test $(grep -c "^diff --git" without_b) = 3 &&
+ test $(grep -c "^diff --git" with_b) = 2
+'
+
+test_expect_success '-L with --output-indicator-*' '
+ git checkout parent-oids &&
+ git log -L:func2:file.c --output-indicator-new=">" \
+ --output-indicator-old="<" --output-indicator-context="|" \
+ --format= -1 >actual &&
+ grep "^>" actual &&
+ grep "^<" actual &&
+ grep "^|" actual &&
+ # No standard +/-/space content markers; exclude ---/+++ headers
+ ! grep "^+[^+]" actual &&
+ ! grep "^-[^-]" actual &&
+ ! grep "^ " actual
+'
+
+test_expect_success '-L with -R reverses diff' '
+ git checkout parent-oids &&
+ git log -L:func2:file.c -R --format= -1 >actual &&
+ grep "^diff --git b/file.c a/file.c" actual &&
+ grep "^--- b/file.c" actual &&
+ grep "^+++ a/file.c" actual &&
+ # The modification added "F2 + 2", so reversed it is removed
+ grep "^-.*F2 + 2" actual &&
+ grep "^+.*return F2;" actual
+'
+
+test_expect_success 'setup for color-moved test' '
+ git checkout -b color-moved-test parent-oids &&
+ cat >big.c <<-\EOF &&
+ int bigfunc()
+ {
+ int a = 1;
+ int b = 2;
+ int c = 3;
+ return a + b + c;
+ }
+ EOF
+ git add big.c &&
+ git commit -m "add bigfunc" &&
+ sed "s/ / /" big.c >tmp && mv tmp big.c &&
+ git commit -a -m "reindent bigfunc"
+'
+
+test_expect_success '-L with --color-moved' '
+ git log -L:bigfunc:big.c --color-moved=zebra \
+ --color-moved-ws=ignore-all-space \
+ --color=always --format= -1 >actual.raw &&
+ test_decode_color <actual.raw >actual &&
+ # Old moved lines: bold magenta; new moved lines: bold cyan
+ grep "BOLD;MAGENTA" actual &&
+ grep "BOLD;CYAN" actual
+'
+
+test_expect_success 'setup for no-newline-at-eof tests' '
+ git checkout --orphan no-newline &&
+ git reset --hard &&
+ printf "int top()\n{\n return 1;\n}\n\nint bot()\n{\n return 2;\n}" >noeol.c &&
+ git add noeol.c &&
+ test_tick &&
+ git commit -m "add noeol.c (no trailing newline)" &&
+ sed "s/return 2/return 22/" noeol.c >tmp && mv tmp noeol.c &&
+ git commit -a -m "modify bot()" &&
+ printf "int top()\n{\n return 1;\n}\n\nint bot()\n{\n return 33;\n}\n" >noeol.c &&
+ git commit -a -m "modify bot() and add trailing newline"
+'
+
+# When the tracked function is at the end of a file with no trailing
+# newline, the "\ No newline at end of file" marker should appear.
+test_expect_success '-L no-newline-at-eof appears in tracked range' '
+ git log -L:bot:noeol.c --format= -1 HEAD~1 >actual &&
+ grep "No newline at end of file" actual
+'
+
+# When tracking a function that ends before the no-newline content,
+# the marker should not appear in the output.
+test_expect_success '-L no-newline-at-eof suppressed outside range' '
+ git log -L:top:noeol.c --format= >actual &&
+ ! grep "No newline at end of file" actual
+'
+
+# When a commit removes a no-newline last line and replaces it with
+# a newline-terminated line, the marker should still appear (on the
+# old side of the diff).
+test_expect_success '-L no-newline-at-eof marker with deleted line' '
+ git log -L:bot:noeol.c --format= -1 >actual &&
+ grep "No newline at end of file" actual
+'
+
+test_expect_success 'setup for range boundary deletion test' '
+ git checkout --orphan range-boundary &&
+ git reset --hard &&
+ cat >boundary.c <<-\EOF &&
+ void above()
+ {
+ return;
+ }
+
+ void tracked()
+ {
+ int x = 1;
+ int y = 2;
+ }
+
+ void below()
+ {
+ return;
+ }
+ EOF
+ git add boundary.c &&
+ test_tick &&
+ git commit -m "add boundary.c" &&
+ cat >boundary.c <<-\EOF &&
+ void above()
+ {
+ return;
+ }
+
+ void tracked()
+ {
+ int x = 1;
+ int y = 2;
+ }
+
+ void below_renamed()
+ {
+ return 0;
+ }
+ EOF
+ git commit -a -m "modify below() only"
+'
+
+# When only a function below the tracked range is modified, the
+# tracked function should not produce a diff.
+test_expect_success '-L suppresses deletions outside tracked range' '
+ git log -L:tracked:boundary.c --format= >actual &&
+ test $(grep -c "^diff --git" actual) = 1
+'
+
+test_expect_success '-L with -S filters to string-count changes' '
+ git checkout parent-oids &&
+ git log -L:func2:file.c -S "F2 + 2" --format= >actual &&
+ # -S searches the whole file, not just the tracked range;
+ # combined with the -L range walk, this selects commits that
+ # both touch func2 and change the count of "F2 + 2" in the file.
+ test $(grep -c "^diff --git" actual) = 1 &&
+ grep "F2 + 2" actual
+'
+
+test_expect_success '-L with -G filters to diff-text matches' '
+ git checkout parent-oids &&
+ git log -L:func2:file.c -G "F2 [+] 2" --format= >actual &&
+ # -G greps the whole-file diff text, not just the tracked range;
+ # combined with -L, this selects commits that both touch func2
+ # and have "F2 + 2" in their diff.
+ test $(grep -c "^diff --git" actual) = 1 &&
+ grep "F2 + 2" actual
+'
+
test_done
diff --git a/t/t4211/sha1/expect.beginning-of-file b/t/t4211/sha1/expect.beginning-of-file
index 91b4054898..52c90afb3a 100644
--- a/t/t4211/sha1/expect.beginning-of-file
+++ b/t/t4211/sha1/expect.beginning-of-file
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:47:40 2013 +0100
change at very beginning
diff --git a/a.c b/a.c
+index bdb2bb1..5e709a1 100644
--- a/a.c
+++ b/a.c
@@ -1,3 +1,4 @@
@@ -20,6 +21,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
@@ -1,3 +1,3 @@
@@ -35,6 +37,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +1,3 @@
diff --git a/t/t4211/sha1/expect.end-of-file b/t/t4211/sha1/expect.end-of-file
index bd25bb2f59..c40036899a 100644
--- a/t/t4211/sha1/expect.end-of-file
+++ b/t/t4211/sha1/expect.end-of-file
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index 0b9cae5..5de3ea4 100644
--- a/a.c
+++ b/a.c
-@@ -20,3 +20,5 @@
+@@ -20,3 +20,5 @@ long f(long x)
printf("%ld\n", f(15));
return 0;
-}
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index 5e709a1..0b9cae5 100644
--- a/a.c
+++ b/a.c
-@@ -20,3 +20,3 @@
+@@ -20,3 +20,3 @@ int main ()
printf("%ld\n", f(15));
return 0;
-}
@@ -39,9 +41,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
-@@ -19,3 +19,3 @@
+@@ -19,3 +19,3 @@ int f(int x)
- printf("%d\n", f(15));
+ printf("%ld\n", f(15));
return 0;
@@ -54,6 +57,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +18,3 @@
diff --git a/t/t4211/sha1/expect.move-support-f b/t/t4211/sha1/expect.move-support-f
index c905e01bc2..ead6500d4d 100644
--- a/t/t4211/sha1/expect.move-support-f
+++ b/t/t4211/sha1/expect.move-support-f
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:49:50 2013 +0100
another simple change
diff --git a/b.c b/b.c
+index 5de3ea4..bf79c2f 100644
--- a/b.c
+++ b/b.c
@@ -4,9 +4,9 @@
@@ -26,6 +27,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
@@ -3,9 +3,9 @@
@@ -47,6 +49,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 444e415..3233403 100644
--- a/a.c
+++ b/a.c
@@ -3,8 +3,9 @@
@@ -67,6 +70,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +3,8 @@
diff --git a/t/t4211/sha1/expect.multiple b/t/t4211/sha1/expect.multiple
index 1eee8a7801..a41851a51d 100644
--- a/t/t4211/sha1/expect.multiple
+++ b/t/t4211/sha1/expect.multiple
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index 0b9cae5..5de3ea4 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,7 @@
+@@ -18,5 +18,7 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index 5e709a1..0b9cae5 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -43,6 +45,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
@@ -3,9 +3,9 @@
@@ -71,6 +74,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 444e415..3233403 100644
--- a/a.c
+++ b/a.c
@@ -3,8 +3,9 @@
@@ -91,6 +95,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +3,8 @@
diff --git a/t/t4211/sha1/expect.multiple-overlapping b/t/t4211/sha1/expect.multiple-overlapping
index d930b6eec4..0ec9990eab 100644
--- a/t/t4211/sha1/expect.multiple-overlapping
+++ b/t/t4211/sha1/expect.multiple-overlapping
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index 0b9cae5..5de3ea4 100644
--- a/a.c
+++ b/a.c
@@ -4,19 +4,21 @@
@@ -39,6 +40,7 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index 5e709a1..0b9cae5 100644
--- a/a.c
+++ b/a.c
@@ -4,19 +4,19 @@
@@ -71,6 +73,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
touch comment
diff --git a/a.c b/a.c
+index e51de13..bdb2bb1 100644
--- a/a.c
+++ b/a.c
@@ -3,19 +3,19 @@
@@ -102,6 +105,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
@@ -3,19 +3,19 @@
@@ -134,6 +138,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 444e415..3233403 100644
--- a/a.c
+++ b/a.c
@@ -3,18 +3,19 @@
@@ -164,6 +169,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +3,18 @@
diff --git a/t/t4211/sha1/expect.multiple-superset b/t/t4211/sha1/expect.multiple-superset
index d930b6eec4..0ec9990eab 100644
--- a/t/t4211/sha1/expect.multiple-superset
+++ b/t/t4211/sha1/expect.multiple-superset
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index 0b9cae5..5de3ea4 100644
--- a/a.c
+++ b/a.c
@@ -4,19 +4,21 @@
@@ -39,6 +40,7 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index 5e709a1..0b9cae5 100644
--- a/a.c
+++ b/a.c
@@ -4,19 +4,19 @@
@@ -71,6 +73,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
touch comment
diff --git a/a.c b/a.c
+index e51de13..bdb2bb1 100644
--- a/a.c
+++ b/a.c
@@ -3,19 +3,19 @@
@@ -102,6 +105,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
@@ -3,19 +3,19 @@
@@ -134,6 +138,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 444e415..3233403 100644
--- a/a.c
+++ b/a.c
@@ -3,18 +3,19 @@
@@ -164,6 +169,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +3,18 @@
diff --git a/t/t4211/sha1/expect.no-assertion-error b/t/t4211/sha1/expect.no-assertion-error
index 994c37db1e..54c568f273 100644
--- a/t/t4211/sha1/expect.no-assertion-error
+++ b/t/t4211/sha1/expect.no-assertion-error
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:50:24 2013 +0100
move within the file
diff --git a/b.c b/b.c
+index bf79c2f..27c829c 100644
--- a/b.c
+++ b/b.c
@@ -25,0 +18,9 @@
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index 0b9cae5..5de3ea4 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,7 @@
+@@ -18,5 +18,7 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -45,9 +47,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index 5e709a1..0b9cae5 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -63,9 +66,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
-@@ -17,5 +17,5 @@
+@@ -17,5 +17,5 @@ int f(int x)
int main ()
{
- printf("%d\n", f(15));
@@ -80,6 +84,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +16,5 @@
diff --git a/t/t4211/sha1/expect.parallel-change-f-to-main b/t/t4211/sha1/expect.parallel-change-f-to-main
index 052def8074..65a8cc673a 100644
--- a/t/t4211/sha1/expect.parallel-change-f-to-main
+++ b/t/t4211/sha1/expect.parallel-change-f-to-main
@@ -13,6 +13,7 @@ Date: Thu Feb 28 10:49:50 2013 +0100
another simple change
diff --git a/b.c b/b.c
+index 5de3ea4..bf79c2f 100644
--- a/b.c
+++ b/b.c
@@ -4,14 +4,14 @@
@@ -39,6 +40,7 @@ Date: Fri Apr 12 16:15:57 2013 +0200
change on another line of history while rename happens
diff --git a/a.c b/a.c
+index 5de3ea4..01b5b65 100644
--- a/a.c
+++ b/a.c
@@ -4,14 +4,14 @@
@@ -65,6 +67,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
touch comment
diff --git a/a.c b/a.c
+index e51de13..bdb2bb1 100644
--- a/a.c
+++ b/a.c
@@ -3,14 +3,14 @@
@@ -91,6 +94,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
@@ -3,14 +3,14 @@
@@ -117,6 +121,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 444e415..3233403 100644
--- a/a.c
+++ b/a.c
@@ -3,13 +3,14 @@
@@ -142,6 +147,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +3,13 @@
diff --git a/t/t4211/sha1/expect.simple-f b/t/t4211/sha1/expect.simple-f
index a1f5bc49c8..b24ae40e03 100644
--- a/t/t4211/sha1/expect.simple-f
+++ b/t/t4211/sha1/expect.simple-f
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
@@ -3,9 +3,9 @@
@@ -26,6 +27,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 444e415..3233403 100644
--- a/a.c
+++ b/a.c
@@ -3,8 +3,9 @@
@@ -46,6 +48,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +3,8 @@
diff --git a/t/t4211/sha1/expect.simple-f-to-main b/t/t4211/sha1/expect.simple-f-to-main
index a475768710..cd92100dfc 100644
--- a/t/t4211/sha1/expect.simple-f-to-main
+++ b/t/t4211/sha1/expect.simple-f-to-main
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
touch comment
diff --git a/a.c b/a.c
+index e51de13..bdb2bb1 100644
--- a/a.c
+++ b/a.c
@@ -3,14 +3,14 @@
@@ -31,6 +32,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
@@ -3,14 +3,14 @@
@@ -57,6 +59,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 444e415..3233403 100644
--- a/a.c
+++ b/a.c
@@ -3,13 +3,14 @@
@@ -82,6 +85,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +3,13 @@
diff --git a/t/t4211/sha1/expect.simple-main b/t/t4211/sha1/expect.simple-main
index 39ce39bebe..ff31291d34 100644
--- a/t/t4211/sha1/expect.simple-main
+++ b/t/t4211/sha1/expect.simple-main
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index 0b9cae5..5de3ea4 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index 5e709a1..0b9cae5 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -41,9 +43,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
-@@ -17,5 +17,5 @@
+@@ -17,5 +17,5 @@ int f(int x)
int main ()
{
- printf("%d\n", f(15));
@@ -58,6 +61,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +16,5 @@
diff --git a/t/t4211/sha1/expect.simple-main-to-end b/t/t4211/sha1/expect.simple-main-to-end
index 8480bd9cc4..4bef21e657 100644
--- a/t/t4211/sha1/expect.simple-main-to-end
+++ b/t/t4211/sha1/expect.simple-main-to-end
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index 0b9cae5..5de3ea4 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,7 @@
+@@ -18,5 +18,7 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index 5e709a1..0b9cae5 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -43,9 +45,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
-@@ -17,5 +17,5 @@
+@@ -17,5 +17,5 @@ int f(int x)
int main ()
{
- printf("%d\n", f(15));
@@ -60,6 +63,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +16,5 @@
diff --git a/t/t4211/sha1/expect.two-ranges b/t/t4211/sha1/expect.two-ranges
index c5164f3be3..aed01522e3 100644
--- a/t/t4211/sha1/expect.two-ranges
+++ b/t/t4211/sha1/expect.two-ranges
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index 0b9cae5..5de3ea4 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index 5e709a1..0b9cae5 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -41,6 +43,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 3233403..e51de13 100644
--- a/a.c
+++ b/a.c
@@ -3,9 +3,9 @@
@@ -69,6 +72,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 444e415..3233403 100644
--- a/a.c
+++ b/a.c
@@ -3,8 +3,9 @@
@@ -89,6 +93,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +3,8 @@
diff --git a/t/t4211/sha1/expect.vanishes-early b/t/t4211/sha1/expect.vanishes-early
index 1f7cd06941..a413ad3659 100644
--- a/t/t4211/sha1/expect.vanishes-early
+++ b/t/t4211/sha1/expect.vanishes-early
@@ -5,11 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index 0b9cae5..5de3ea4 100644
--- a/a.c
+++ b/a.c
-@@ -22,1 +24,1 @@
--}
-\ No newline at end of file
+@@ -23,0 +24,1 @@ int main ()
+/* incomplete lines are bad! */
commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
@@ -19,9 +18,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index 5e709a1..0b9cae5 100644
--- a/a.c
+++ b/a.c
-@@ -22,1 +22,1 @@
+@@ -22,1 +22,1 @@ int main ()
-}
+}
\ No newline at end of file
@@ -33,6 +33,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..444e415
--- /dev/null
+++ b/a.c
@@ -0,0 +20,1 @@
diff --git a/t/t4211/sha256/expect.beginning-of-file b/t/t4211/sha256/expect.beginning-of-file
index 5adfdfc1a1..e8d62328cf 100644
--- a/t/t4211/sha256/expect.beginning-of-file
+++ b/t/t4211/sha256/expect.beginning-of-file
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:47:40 2013 +0100
change at very beginning
diff --git a/a.c b/a.c
+index 3a78aaf..d325124 100644
--- a/a.c
+++ b/a.c
@@ -1,3 +1,4 @@
@@ -20,6 +21,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
@@ -1,3 +1,3 @@
@@ -35,6 +37,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +1,3 @@
diff --git a/t/t4211/sha256/expect.end-of-file b/t/t4211/sha256/expect.end-of-file
index 03ab5c1784..3b2e2384da 100644
--- a/t/t4211/sha256/expect.end-of-file
+++ b/t/t4211/sha256/expect.end-of-file
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index e4fa1d8..62c1fc2 100644
--- a/a.c
+++ b/a.c
-@@ -20,3 +20,5 @@
+@@ -20,3 +20,5 @@ long f(long x)
printf("%ld\n", f(15));
return 0;
-}
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index d325124..e4fa1d8 100644
--- a/a.c
+++ b/a.c
-@@ -20,3 +20,3 @@
+@@ -20,3 +20,3 @@ int main ()
printf("%ld\n", f(15));
return 0;
-}
@@ -39,9 +41,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
-@@ -19,3 +19,3 @@
+@@ -19,3 +19,3 @@ int f(int x)
- printf("%d\n", f(15));
+ printf("%ld\n", f(15));
return 0;
@@ -54,6 +57,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +18,3 @@
diff --git a/t/t4211/sha256/expect.move-support-f b/t/t4211/sha256/expect.move-support-f
index 223b4ed2a0..f49abcea3e 100644
--- a/t/t4211/sha256/expect.move-support-f
+++ b/t/t4211/sha256/expect.move-support-f
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:49:50 2013 +0100
another simple change
diff --git a/b.c b/b.c
+index 62c1fc2..69cb69c 100644
--- a/b.c
+++ b/b.c
@@ -4,9 +4,9 @@
@@ -26,6 +27,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
@@ -3,9 +3,9 @@
@@ -47,6 +49,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 9f550c3..7a296b9 100644
--- a/a.c
+++ b/a.c
@@ -3,8 +3,9 @@
@@ -67,6 +70,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +3,8 @@
diff --git a/t/t4211/sha256/expect.multiple b/t/t4211/sha256/expect.multiple
index dbd987b74a..0dee50ffb7 100644
--- a/t/t4211/sha256/expect.multiple
+++ b/t/t4211/sha256/expect.multiple
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index e4fa1d8..62c1fc2 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,7 @@
+@@ -18,5 +18,7 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index d325124..e4fa1d8 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -43,6 +45,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
@@ -3,9 +3,9 @@
@@ -71,6 +74,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 9f550c3..7a296b9 100644
--- a/a.c
+++ b/a.c
@@ -3,8 +3,9 @@
@@ -91,6 +95,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +3,8 @@
diff --git a/t/t4211/sha256/expect.multiple-overlapping b/t/t4211/sha256/expect.multiple-overlapping
index 9015a45a25..b8c260e8ae 100644
--- a/t/t4211/sha256/expect.multiple-overlapping
+++ b/t/t4211/sha256/expect.multiple-overlapping
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index e4fa1d8..62c1fc2 100644
--- a/a.c
+++ b/a.c
@@ -4,19 +4,21 @@
@@ -39,6 +40,7 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index d325124..e4fa1d8 100644
--- a/a.c
+++ b/a.c
@@ -4,19 +4,19 @@
@@ -71,6 +73,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
touch comment
diff --git a/a.c b/a.c
+index 75c0119..3a78aaf 100644
--- a/a.c
+++ b/a.c
@@ -3,19 +3,19 @@
@@ -102,6 +105,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
@@ -3,19 +3,19 @@
@@ -134,6 +138,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 9f550c3..7a296b9 100644
--- a/a.c
+++ b/a.c
@@ -3,18 +3,19 @@
@@ -164,6 +169,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +3,18 @@
diff --git a/t/t4211/sha256/expect.multiple-superset b/t/t4211/sha256/expect.multiple-superset
index 9015a45a25..b8c260e8ae 100644
--- a/t/t4211/sha256/expect.multiple-superset
+++ b/t/t4211/sha256/expect.multiple-superset
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index e4fa1d8..62c1fc2 100644
--- a/a.c
+++ b/a.c
@@ -4,19 +4,21 @@
@@ -39,6 +40,7 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index d325124..e4fa1d8 100644
--- a/a.c
+++ b/a.c
@@ -4,19 +4,19 @@
@@ -71,6 +73,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
touch comment
diff --git a/a.c b/a.c
+index 75c0119..3a78aaf 100644
--- a/a.c
+++ b/a.c
@@ -3,19 +3,19 @@
@@ -102,6 +105,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
@@ -3,19 +3,19 @@
@@ -134,6 +138,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 9f550c3..7a296b9 100644
--- a/a.c
+++ b/a.c
@@ -3,18 +3,19 @@
@@ -164,6 +169,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +3,18 @@
diff --git a/t/t4211/sha256/expect.no-assertion-error b/t/t4211/sha256/expect.no-assertion-error
index 36ed12aa9c..c25f2ce19c 100644
--- a/t/t4211/sha256/expect.no-assertion-error
+++ b/t/t4211/sha256/expect.no-assertion-error
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:50:24 2013 +0100
move within the file
diff --git a/b.c b/b.c
+index 69cb69c..a0d566e 100644
--- a/b.c
+++ b/b.c
@@ -25,0 +18,9 @@
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index e4fa1d8..62c1fc2 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,7 @@
+@@ -18,5 +18,7 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -45,9 +47,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index d325124..e4fa1d8 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -63,9 +66,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
-@@ -17,5 +17,5 @@
+@@ -17,5 +17,5 @@ int f(int x)
int main ()
{
- printf("%d\n", f(15));
@@ -80,6 +84,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +16,5 @@
diff --git a/t/t4211/sha256/expect.parallel-change-f-to-main b/t/t4211/sha256/expect.parallel-change-f-to-main
index e68f8928ea..3178989253 100644
--- a/t/t4211/sha256/expect.parallel-change-f-to-main
+++ b/t/t4211/sha256/expect.parallel-change-f-to-main
@@ -13,6 +13,7 @@ Date: Thu Feb 28 10:49:50 2013 +0100
another simple change
diff --git a/b.c b/b.c
+index 62c1fc2..69cb69c 100644
--- a/b.c
+++ b/b.c
@@ -4,14 +4,14 @@
@@ -39,6 +40,7 @@ Date: Fri Apr 12 16:15:57 2013 +0200
change on another line of history while rename happens
diff --git a/a.c b/a.c
+index 62c1fc2..e1e8475 100644
--- a/a.c
+++ b/a.c
@@ -4,14 +4,14 @@
@@ -65,6 +67,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
touch comment
diff --git a/a.c b/a.c
+index 75c0119..3a78aaf 100644
--- a/a.c
+++ b/a.c
@@ -3,14 +3,14 @@
@@ -91,6 +94,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
@@ -3,14 +3,14 @@
@@ -117,6 +121,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 9f550c3..7a296b9 100644
--- a/a.c
+++ b/a.c
@@ -3,13 +3,14 @@
@@ -142,6 +147,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +3,13 @@
diff --git a/t/t4211/sha256/expect.simple-f b/t/t4211/sha256/expect.simple-f
index 65508d7c0b..983c711fe3 100644
--- a/t/t4211/sha256/expect.simple-f
+++ b/t/t4211/sha256/expect.simple-f
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
@@ -3,9 +3,9 @@
@@ -26,6 +27,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 9f550c3..7a296b9 100644
--- a/a.c
+++ b/a.c
@@ -3,8 +3,9 @@
@@ -46,6 +48,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +3,8 @@
diff --git a/t/t4211/sha256/expect.simple-f-to-main b/t/t4211/sha256/expect.simple-f-to-main
index 77b721c196..e67fa017a7 100644
--- a/t/t4211/sha256/expect.simple-f-to-main
+++ b/t/t4211/sha256/expect.simple-f-to-main
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
touch comment
diff --git a/a.c b/a.c
+index 75c0119..3a78aaf 100644
--- a/a.c
+++ b/a.c
@@ -3,14 +3,14 @@
@@ -31,6 +32,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
@@ -3,14 +3,14 @@
@@ -57,6 +59,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 9f550c3..7a296b9 100644
--- a/a.c
+++ b/a.c
@@ -3,13 +3,14 @@
@@ -82,6 +85,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +3,13 @@
diff --git a/t/t4211/sha256/expect.simple-main b/t/t4211/sha256/expect.simple-main
index d20708c9f9..0792b27cad 100644
--- a/t/t4211/sha256/expect.simple-main
+++ b/t/t4211/sha256/expect.simple-main
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index e4fa1d8..62c1fc2 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index d325124..e4fa1d8 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -41,9 +43,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
-@@ -17,5 +17,5 @@
+@@ -17,5 +17,5 @@ int f(int x)
int main ()
{
- printf("%d\n", f(15));
@@ -58,6 +61,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +16,5 @@
diff --git a/t/t4211/sha256/expect.simple-main-to-end b/t/t4211/sha256/expect.simple-main-to-end
index 617cdf3481..d3bd7c7bc6 100644
--- a/t/t4211/sha256/expect.simple-main-to-end
+++ b/t/t4211/sha256/expect.simple-main-to-end
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index e4fa1d8..62c1fc2 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,7 @@
+@@ -18,5 +18,7 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index d325124..e4fa1d8 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -43,9 +45,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
-@@ -17,5 +17,5 @@
+@@ -17,5 +17,5 @@ int f(int x)
int main ()
{
- printf("%d\n", f(15));
@@ -60,6 +63,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +16,5 @@
diff --git a/t/t4211/sha256/expect.two-ranges b/t/t4211/sha256/expect.two-ranges
index 6a94d3b9cb..7735b19723 100644
--- a/t/t4211/sha256/expect.two-ranges
+++ b/t/t4211/sha256/expect.two-ranges
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index e4fa1d8..62c1fc2 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index d325124..e4fa1d8 100644
--- a/a.c
+++ b/a.c
-@@ -18,5 +18,5 @@
+@@ -18,5 +18,5 @@ long f(long x)
int main ()
{
printf("%ld\n", f(15));
@@ -41,6 +43,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
touch both functions
diff --git a/a.c b/a.c
+index 7a296b9..75c0119 100644
--- a/a.c
+++ b/a.c
@@ -3,9 +3,9 @@
@@ -69,6 +72,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
change f()
diff --git a/a.c b/a.c
+index 9f550c3..7a296b9 100644
--- a/a.c
+++ b/a.c
@@ -3,8 +3,9 @@
@@ -89,6 +93,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +3,8 @@
diff --git a/t/t4211/sha256/expect.vanishes-early b/t/t4211/sha256/expect.vanishes-early
index 11ec9bdecf..bc33b963dc 100644
--- a/t/t4211/sha256/expect.vanishes-early
+++ b/t/t4211/sha256/expect.vanishes-early
@@ -5,11 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
change back to complete line
diff --git a/a.c b/a.c
+index e4fa1d8..62c1fc2 100644
--- a/a.c
+++ b/a.c
-@@ -22,1 +24,1 @@
--}
-\ No newline at end of file
+@@ -23,0 +24,1 @@ int main ()
+/* incomplete lines are bad! */
commit 29f32ac3141c48b22803e5c4127b719917b67d0f8ca8c5248bebfa2a19f7da10
@@ -19,9 +18,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
change to an incomplete line at end
diff --git a/a.c b/a.c
+index d325124..e4fa1d8 100644
--- a/a.c
+++ b/a.c
-@@ -22,1 +22,1 @@
+@@ -22,1 +22,1 @@ int main ()
-}
+}
\ No newline at end of file
@@ -33,6 +33,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
initial
diff --git a/a.c b/a.c
+new file mode 100644
+index 0000000..9f550c3
--- /dev/null
+++ b/a.c
@@ -0,0 +20,1 @@
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index 98c6910963..1c40f904f8 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -417,6 +417,26 @@ test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow ch
test_cmp full/.git/objects/info/commit-graph commit-graph-upgraded
'
+test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'overflow chunk when replacing commit-graph' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ cat >commit <<-EOF &&
+ tree $(test_oid empty_tree)
+ author Example <committer@example.com> 9223372036854775 +0000
+ committer Example <committer@example.com> 9223372036854775 +0000
+
+ Weird commit date
+ EOF
+ commit_id=$(git hash-object -t commit -w commit) &&
+ git reset --hard "$commit_id" &&
+ git commit-graph write --reachable &&
+ git commit-graph write --reachable --split=replace &&
+ git log
+ )
+'
+
# the verify tests below expect the commit-graph to contain
# exactly the commits reachable from the commits/8 branch.
# If the file changes the set of commits in the list, then the
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 29e2f17608..117cfa051f 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1792,6 +1792,7 @@ test_expect_success 'updateInstead with push-to-checkout hook' '
'
test_expect_success 'denyCurrentBranch and worktrees' '
+ test_when_finished "rm -fr cloned && git worktree remove --force new-wt" &&
git worktree add new-wt &&
git clone . cloned &&
test_commit -C cloned first &&
@@ -1816,6 +1817,20 @@ test_expect_success 'denyCurrentBranch and bare repository worktrees' '
test_must_fail git push --delete bare.git wt
'
+test_expect_success 'updateInstead with bare repository worktree and unborn bare HEAD' '
+ test_when_finished "rm -fr bare.git cloned" &&
+ git clone --bare . bare.git &&
+ git -C bare.git worktree add wt &&
+ git -C bare.git config receive.denyCurrentBranch updateInstead &&
+ git -C bare.git symbolic-ref HEAD refs/heads/unborn &&
+ test_must_fail git -C bare.git rev-parse -q --verify HEAD^{commit} &&
+ git clone . cloned &&
+ test_commit -C cloned mozzarella &&
+ git -C cloned push ../bare.git HEAD:wt &&
+ test_path_exists bare.git/wt/mozzarella.t &&
+ test "$(git -C cloned rev-parse HEAD)" = "$(git -C bare.git/wt rev-parse HEAD)"
+'
+
test_expect_success 'refuse fetch to current branch of worktree' '
test_when_finished "git worktree remove --force wt && git branch -D wt" &&
git worktree add wt &&
diff --git a/t/t5620-backfill.sh b/t/t5620-backfill.sh
index 2c347a91fe..f3b5e39493 100755
--- a/t/t5620-backfill.sh
+++ b/t/t5620-backfill.sh
@@ -175,6 +175,21 @@ test_expect_success 'backfill --sparse' '
test_line_count = 0 missing
'
+test_expect_success 'backfill auto-detects sparse-checkout from config' '
+ git clone --sparse --filter=blob:none \
+ --single-branch --branch=main \
+ "file://$(pwd)/srv.bare" backfill-auto-sparse &&
+
+ git -C backfill-auto-sparse rev-list --quiet --objects --missing=print HEAD >missing &&
+ test_line_count = 44 missing &&
+
+ GIT_TRACE2_EVENT="$(pwd)/auto-sparse-trace" git \
+ -C backfill-auto-sparse backfill &&
+
+ test_trace2_data promisor fetch_count 4 <auto-sparse-trace &&
+ test_trace2_data path-walk paths 5 <auto-sparse-trace
+'
+
test_expect_success 'backfill --sparse without cone mode (positive)' '
git clone --no-checkout --filter=blob:none \
--single-branch --branch=main \
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index ce2ff2a28a..faf7d97fc4 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -33,8 +33,10 @@ test_expect_success 'listing all tags in an empty tree should succeed' '
'
test_expect_success 'listing all tags in an empty tree should output nothing' '
- test $(git tag -l | wc -l) -eq 0 &&
- test $(git tag | wc -l) -eq 0
+ git tag -l >actual &&
+ test_must_be_empty actual &&
+ git tag >actual &&
+ test_must_be_empty actual
'
test_expect_success 'sort tags, ignore case' '
@@ -178,7 +180,8 @@ test_expect_success 'listing tags using a non-matching pattern should succeed' '
'
test_expect_success 'listing tags using a non-matching pattern should output nothing' '
- test $(git tag -l xxx | wc -l) -eq 0
+ git tag -l xxx >actual &&
+ test_must_be_empty actual
'
# special cases for creating tags:
@@ -188,13 +191,15 @@ test_expect_success 'trying to create a tag with the name of one existing should
'
test_expect_success 'trying to create a tag with a non-valid name should fail' '
- test $(git tag -l | wc -l) -eq 1 &&
+ git tag -l >actual &&
+ test_line_count = 1 actual &&
test_must_fail git tag "" &&
test_must_fail git tag .othertag &&
test_must_fail git tag "other tag" &&
test_must_fail git tag "othertag^" &&
test_must_fail git tag "other~tag" &&
- test $(git tag -l | wc -l) -eq 1
+ git tag -l >actual &&
+ test_line_count = 1 actual
'
test_expect_success 'creating a tag using HEAD directly should succeed' '
diff --git a/t/t9305-fast-import-signatures.sh b/t/t9305-fast-import-signatures.sh
index 18707b3f6c..5667693afd 100755
--- a/t/t9305-fast-import-signatures.sh
+++ b/t/t9305-fast-import-signatures.sh
@@ -103,7 +103,7 @@ test_expect_success RUST,GPG 'strip both OpenPGP signatures with --signed-commit
test_line_count = 2 out
'
-for mode in strip-if-invalid sign-if-invalid
+for mode in strip-if-invalid sign-if-invalid abort-if-invalid
do
test_expect_success GPG "import commit with no signature with --signed-commits=$mode" '
git fast-export main >output &&
@@ -135,6 +135,14 @@ do
# corresponding `data <length>` command would have to be changed too.
sed "s/OpenPGP signed commit/OpenPGP forged commit/" output >modified &&
+ if test "$mode" = abort-if-invalid
+ then
+ test_must_fail git -C new fast-import --quiet \
+ --signed-commits=$mode <modified >log 2>&1 &&
+ test_grep "aborting due to invalid signature" log &&
+ return 0
+ fi &&
+
git -C new fast-import --quiet --signed-commits=$mode <modified >log 2>&1 &&
IMPORTED=$(git -C new rev-parse --verify refs/heads/openpgp-signing) &&
diff --git a/t/t9306-fast-import-signed-tags.sh b/t/t9306-fast-import-signed-tags.sh
index 363619e7d1..ec2b241cdb 100755
--- a/t/t9306-fast-import-signed-tags.sh
+++ b/t/t9306-fast-import-signed-tags.sh
@@ -77,4 +77,122 @@ test_expect_success GPGSSH 'import SSH signed tag with --signed-tags=strip' '
test_grep ! "SSH SIGNATURE" out
'
+for mode in strip-if-invalid sign-if-invalid abort-if-invalid
+do
+ test_expect_success GPG "import tag with no signature with --signed-tags=$mode" '
+ test_when_finished rm -rf import &&
+ git init import &&
+
+ git fast-export --signed-tags=verbatim >output &&
+ git -C import fast-import --quiet --signed-tags=$mode <output >log 2>&1 &&
+ test_must_be_empty log
+ '
+
+ test_expect_success GPG "keep valid OpenPGP signature with --signed-tags=$mode" '
+ test_when_finished rm -rf import &&
+ git init import &&
+
+ git fast-export --signed-tags=verbatim openpgp-signed >output &&
+ git -C import fast-import --quiet --signed-tags=$mode <output >log 2>&1 &&
+ IMPORTED=$(git -C import rev-parse --verify refs/tags/openpgp-signed) &&
+ test $OPENPGP_SIGNED = $IMPORTED &&
+ git -C import cat-file tag "$IMPORTED" >actual &&
+ test_grep -E "^-----BEGIN PGP SIGNATURE-----" actual &&
+ test_must_be_empty log
+ '
+
+ test_expect_success GPG "handle signature invalidated by message change with --signed-tags=$mode" '
+ test_when_finished rm -rf import &&
+ git init import &&
+
+ git fast-export --signed-tags=verbatim openpgp-signed >output &&
+
+ # Change the tag message, which invalidates the signature. The tag
+ # message length should not change though, otherwise the corresponding
+ # `data <length>` command would have to be changed too.
+ sed "s/OpenPGP signed tag/OpenPGP forged tag/" output >modified &&
+
+ if test "$mode" = abort-if-invalid
+ then
+ test_must_fail git -C import fast-import --quiet \
+ --signed-tags=$mode <modified >log 2>&1 &&
+ test_grep "aborting due to invalid signature" log &&
+ return 0
+ fi &&
+
+ git -C import fast-import --quiet --signed-tags=$mode <modified >log 2>&1 &&
+
+ IMPORTED=$(git -C import rev-parse --verify refs/tags/openpgp-signed) &&
+ test $OPENPGP_SIGNED != $IMPORTED &&
+ git -C import cat-file tag "$IMPORTED" >actual &&
+
+ if test "$mode" = strip-if-invalid
+ then
+ test_grep ! -E "^-----BEGIN PGP SIGNATURE-----" actual
+ else
+ test_grep -E "^-----BEGIN PGP SIGNATURE-----" actual &&
+ git -C import verify-tag "$IMPORTED"
+ fi &&
+
+ test_must_be_empty log
+ '
+
+ test_expect_success GPGSM "keep valid X.509 signature with --signed-tags=$mode" '
+ test_when_finished rm -rf import &&
+ git init import &&
+
+ git fast-export --signed-tags=verbatim x509-signed >output &&
+ git -C import fast-import --quiet --signed-tags=$mode <output >log 2>&1 &&
+ IMPORTED=$(git -C import rev-parse --verify refs/tags/x509-signed) &&
+ test $X509_SIGNED = $IMPORTED &&
+ git -C import cat-file tag x509-signed >actual &&
+ test_grep -E "^-----BEGIN SIGNED MESSAGE-----" actual &&
+ test_must_be_empty log
+ '
+
+ test_expect_success GPGSSH "keep valid SSH signature with --signed-tags=$mode" '
+ test_when_finished rm -rf import &&
+ git init import &&
+
+ test_config -C import gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+
+ git fast-export --signed-tags=verbatim ssh-signed >output &&
+ git -C import fast-import --quiet --signed-tags=$mode <output >log 2>&1 &&
+ IMPORTED=$(git -C import rev-parse --verify refs/tags/ssh-signed) &&
+ test $SSH_SIGNED = $IMPORTED &&
+ git -C import cat-file tag ssh-signed >actual &&
+ test_grep -E "^-----BEGIN SSH SIGNATURE-----" actual &&
+ test_must_be_empty log
+ '
+done
+
+test_expect_success GPGSSH 'sign invalid tag with explicit keyid' '
+ test_when_finished rm -rf import &&
+ git init import &&
+
+ git fast-export --signed-tags=verbatim ssh-signed >output &&
+
+ # Change the tag message, which invalidates the signature. The tag
+ # message length should not change though, otherwise the corresponding
+ # `data <length>` command would have to be changed too.
+ sed "s/SSH signed tag/SSH forged tag/" output >modified &&
+
+ # Configure the target repository with an invalid default signing key.
+ test_config -C import user.signingkey "not-a-real-key-id" &&
+ test_config -C import gpg.format ssh &&
+ test_config -C import gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+ test_must_fail git -C import fast-import --quiet \
+ --signed-tags=sign-if-invalid <modified >/dev/null 2>&1 &&
+
+ # Import using explicitly provided signing key.
+ git -C import fast-import --quiet \
+ --signed-tags=sign-if-invalid="${GPGSSH_KEY_PRIMARY}" <modified &&
+
+ IMPORTED=$(git -C import rev-parse --verify refs/tags/ssh-signed) &&
+ test $SSH_SIGNED != $IMPORTED &&
+ git -C import cat-file tag "$IMPORTED" >actual &&
+ test_grep -E "^-----BEGIN SSH SIGNATURE-----" actual &&
+ git -C import verify-tag "$IMPORTED"
+'
+
test_done
diff --git a/walker.c b/walker.c
index 91332539d3..e98eb6da53 100644
--- a/walker.c
+++ b/walker.c
@@ -155,7 +155,7 @@ static int process(struct walker *walker, struct object *obj)
obj->flags |= SEEN;
if (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)) {
/* We already have it, so we should scan it now. */
obj->flags |= TO_SCAN;
}