diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index b8670751f5c705..4992e52093efdc 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 27dbfdc6a59e13..30ec959e7e5bf2 100644 --- a/Documentation/RelNotes/2.54.0.adoc +++ b/Documentation/RelNotes/2.54.0.adoc @@ -509,6 +509,12 @@ Fixes since v2.53 working tree, which was broken. (merge 339eba65a7 th/backfill-auto-detect-sparseness-fix later to maint). + * add_files_to_cache() used diff_files() to detect only the paths that + are different between the index and the working tree and add them, + which does not need rename detection, which interfered with unnecessary + conflicts. + (merge c0ce43376b ng/add-files-to-cache-wo-rename later to maint). + * Other code cleanup, docfix, build fix, etc. (merge d79fff4a11 jk/remote-tracking-ref-leakfix later to maint). (merge 7a747f972d dd/t5403-modernise later to maint). diff --git a/Documentation/git-replay.adoc b/Documentation/git-replay.adoc index 997097e4205523..a32f72aead3750 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 | --advance | --revert ) [--ref-action[=]] +(EXPERIMENTAL!) 'git replay' ([--contained] --onto= | --advance= | --revert=) + [--ref=] [--ref-action=] DESCRIPTION ----------- @@ -26,7 +27,7 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE. OPTIONS ------- ---onto :: +--onto=:: 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 :: +--advance=:: 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 and 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 :: +--revert=:: 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 . Requires `--onto`. +--ref=:: + Override which reference is updated with the result of the replay. + The ref must be fully qualified. + When used with `--onto`, the `` 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[=]:: 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 :: Range of commits to replay; see "Specifying Ranges" in - linkgit:git-rev-parse[1]. In `--advance ` or - `--revert ` mode, the range should have a single tip, + linkgit:git-rev-parse[1]. In `--advance=` or + `--revert=` mode, the range should have a single tip, so that it's clear to which tip the advanced or reverted 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/builtin/cat-file.c b/builtin/cat-file.c index cd13a3a89f1851..d9fbad535868bb 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/fetch.c b/builtin/fetch.c index 4795b2a13c30e3..a22c3194670e9a 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 99696604b8c32f..248f8ff5a03bc9 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -162,7 +162,7 @@ static int mark_object(struct object *obj, enum object_type type, if (!(obj->flags & HAS_OBJ)) { if (parent && !odb_has_object(options->repo->objects, &obj->oid, - HAS_OBJECT_RECHECK_PACKED)) { + ODB_HAS_OBJECT_RECHECK_PACKED)) { printf_ln(_("broken link from %7s %s\n" " to %7s %s"), printable_type(options->repo, &parent->oid, parent->type), diff --git a/builtin/index-pack.c b/builtin/index-pack.c index e4129bd605e89c..ca7784dc2c4969 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -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(); } diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 49090c4d4c7516..dada55884a0b06 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1541,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/remote.c b/builtin/remote.c index 0fddaa177331f6..de989ea3ba9691 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 a0879b020f456a..39e3a86f6c10ab 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 | --advance | --revert ) " - "[--ref-action[=]] "), + "([--contained] --onto= | --advance= | --revert=)\n" + "[--ref=] [--ref-action=] "), 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 ")), - 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 5d31acea7c779a..d50844163269df 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 d863912b24fae5..e01cf6e360f6d1 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -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)) diff --git a/cache-tree.c b/cache-tree.c index 60bcc07c3b8357..7881b42aa24c80 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/fetch-pack.c b/fetch-pack.c index 7b580920a39a3b..c8fa0a609ac6de 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -144,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; @@ -2016,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/http-push.c b/http-push.c index 9ae6062198e14f..06c3acbb5d9a21 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 e886e6486646d1..1b6d496548373e 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/list-objects.c b/list-objects.c index 91b23e22f71aac..724d723c484de4 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 51a7ef9f830a13..8f315e2a00d265 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 9e57eb6c27f44a..2acc9522df2daa 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 @@ int odb_source_loose_write_stream(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) { const struct git_hash_algo *algo = source->odb->repo->hash_algo; const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo; @@ -1378,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 */ @@ -1641,6 +1642,34 @@ static int index_blob_packfile_transaction(struct odb_transaction_files *transac return 0; } +static int hash_blob_stream(const struct git_hash_algo *hash_algo, + struct object_id *result_oid, int fd, size_t size) +{ + unsigned char buf[16384]; + struct git_hash_ctx ctx; + unsigned header_len; + + header_len = format_object_header((char *)buf, sizeof(buf), + OBJ_BLOB, size); + hash_algo->init_fn(&ctx); + git_hash_update(&ctx, buf, header_len); + + while (size) { + size_t rsize = size < sizeof(buf) ? size : sizeof(buf); + ssize_t read_result = read_in_full(fd, buf, rsize); + + if ((read_result < 0) || ((size_t)read_result != rsize)) + return -1; + + git_hash_update(&ctx, buf, rsize); + size -= read_result; + } + + git_hash_final_oid(result_oid, &ctx); + + return 0; +} + int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags) @@ -1662,18 +1691,23 @@ int index_fd(struct index_state *istate, struct object_id *oid, ret = index_core(istate, oid, fd, xsize_t(st->st_size), type, path, flags); } else { - struct object_database *odb = the_repository->objects; - struct odb_transaction_files *files_transaction; - struct odb_transaction *transaction; - - transaction = odb_transaction_begin(odb); - files_transaction = container_of(odb->transaction, - struct odb_transaction_files, - base); - ret = index_blob_packfile_transaction(files_transaction, oid, fd, - xsize_t(st->st_size), - path, flags); - odb_transaction_commit(transaction); + if (flags & INDEX_WRITE_OBJECT) { + struct object_database *odb = the_repository->objects; + struct odb_transaction_files *files_transaction; + struct odb_transaction *transaction; + + transaction = odb_transaction_begin(odb); + files_transaction = container_of(odb->transaction, + struct odb_transaction_files, + base); + ret = index_blob_packfile_transaction(files_transaction, oid, fd, + xsize_t(st->st_size), + path, flags); + odb_transaction_commit(transaction); + } else { + ret = hash_blob_stream(the_repository->hash_algo, oid, + fd, xsize_t(st->st_size)); + } } close(fd); diff --git a/object-file.h b/object-file.h index 3686f182e4deb0..5241b8dd5c564d 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 3f94a53df157e1..9b28fe25ef2b14 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 984bafca9d652b..3a711f6547bb00 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 76797569de4280..b5abd20e971e78 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 a9d7d0b96fde72..f706e0608a4855 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/packfile.c b/packfile.c index 48c88748b6c325..b012d648adaf2e 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 6e8802e2ed4487..9b647da7dda7c1 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/read-cache.c b/read-cache.c index b1074fbf061b64..38a04b8de3d7fb 100644 --- a/read-cache.c +++ b/read-cache.c @@ -4033,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 1460ae9d0dd5f7..82337078d00611 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 5d1d28523d617f..bfcb9c7ac3d38c 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 b124404663edf6..daea30a5b4cad9 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 573c81287fe5d8..7f7441f751342a 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 26b9115b14acd8..8e73fc83f225e5 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 6d73f19c85b6d3..dc8622682d7d06 100644 --- a/reftable/reftable-basics.h +++ b/reftable/reftable-basics.h @@ -9,7 +9,7 @@ #ifndef REFTABLE_BASICS_H #define REFTABLE_BASICS_H -#include +#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 0b05a8f7e376bc..94c79b5c58fb76 100644 --- a/reftable/reftable-block.h +++ b/reftable/reftable-block.h @@ -9,8 +9,7 @@ #ifndef REFTABLE_BLOCK_H #define REFTABLE_BLOCK_H -#include - +#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 f5ba867bd60a10..40c1e946462921 100644 --- a/reftable/reftable-blocksource.h +++ b/reftable/reftable-blocksource.h @@ -9,7 +9,7 @@ #ifndef REFTABLE_BLOCKSOURCE_H #define REFTABLE_BLOCKSOURCE_H -#include +#include "reftable-system.h" /* * Generic wrapper for a seekable readable file. diff --git a/reftable/reftable-error.h b/reftable/reftable-error.h index d100e0df927ca2..0535e1478bda2d 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 007a392cf906c7..340fc7762ed76f 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 af582028c27fdc..a050cc153be711 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 e5af846b32a95f..02a9966835eb15 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 385a74cc864985..e18c5382381c4b 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 /* * Basic data types diff --git a/reftable/reftable-stack.h b/reftable/reftable-stack.h index c2415cbc6e46a6..5f7be573fabf8e 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 00000000000000..76f3e33e901397 --- /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 5f935d02e3b195..d7666b53a1ee0c 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 1e7003cd698879..a66db415c87637 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 -#include /* ssize_t */ - /* Writing single reftables */ /* reftable_write_options sets options for writing a single reftable. */ @@ -63,12 +61,6 @@ struct reftable_write_options { */ long lock_timeout_ms; - /* - * Optional callback used to fsync files to disk. Falls back to using - * fsync(3P) when unset. - */ - int (*fsync)(int fd); - /* * Callback function to execute whenever the stack is being reloaded. * This can be used e.g. to discard cached information that relies on diff --git a/reftable/stack.c b/reftable/stack.c index 1c9f21dfe1eb45..1fba96ddb3366f 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 @@ static int reftable_stack_reload_once(struct reftable_stack *st, 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 725a25844ea179..9063641f304c1b 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 c54ed4cad61f73..c0e2cbe0ffb90c 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 7ca2a6501b4920..a664cd166aa3b9 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 cf1f0bcba0b333..f96f1f6551ae63 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 e916a5f975be26..0ab74b9805af16 100644 --- a/replay.h +++ b/replay.h @@ -24,6 +24,13 @@ struct replay_revisions_options { */ const char *onto; + /* + * Reference to update with the result of the replay. This will not + * update any refs from `onto`, `advance`, or `revert`. Ignores + * `contained`. + */ + const char *ref; + /* * Starting point at which to create revert commits; must be a branch * name. The branch will be updated to point to the revert commits. diff --git a/run-command.c b/run-command.c index 32c290ee6a221f..574d5c40f0a1a5 100644 --- a/run-command.c +++ b/run-command.c @@ -1895,14 +1895,19 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts) "max:%"PRIuMAX, (uintmax_t)opts->processes); + pp_init(&pp, opts, &pp_sig); + /* * Child tasks might receive input via stdin, terminating early (or not), so * ignore the default SIGPIPE which gets handled by each feed_pipe_fn which * actually writes the data to children stdin fds. + * + * This _must_ come after pp_init(), because it installs its own + * SIGPIPE handler (to cleanup children), and we want to supersede + * that. */ sigchain_push(SIGPIPE, SIG_IGN); - pp_init(&pp, opts, &pp_sig); while (1) { for (i = 0; i < spawn_cap && !pp.shutdown && @@ -1928,10 +1933,10 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts) } } - pp_cleanup(&pp, opts); - sigchain_pop(SIGPIPE); + pp_cleanup(&pp, opts); + if (do_trace2) trace2_region_leave(tr2_category, tr2_label, NULL); } diff --git a/shallow.c b/shallow.c index 7a3dd567950dea..a8ad92e303d24d 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/t1517-outside-repo.sh b/t/t1517-outside-repo.sh index c824c1a25cf27e..e1d35170de61a3 100755 --- a/t/t1517-outside-repo.sh +++ b/t/t1517-outside-repo.sh @@ -93,6 +93,14 @@ test_expect_success 'diff outside repository' ' test_cmp expect actual ' +test_expect_success 'hash object exceeding bigFileThreshold outside repository' ' + ( + cd non-repo && + echo foo >foo && + git -c core.bigFileThreshold=1 hash-object --stdin 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 89819ad4d26de1..3353bc4a4dc6ed 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/t7004-tag.sh b/t/t7004-tag.sh index ce2ff2a28abaa3..faf7d97fc487d3 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/walker.c b/walker.c index 91332539d3a286..e98eb6da53692e 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; }