Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ CODE_OF_CONDUCT.md -whitespace
/Documentation/gitk.adoc conflict-marker-size=32
/Documentation/user-manual.adoc conflict-marker-size=32
/t/t????-*.sh conflict-marker-size=32
/t/unit-tests/clar/test/expected/* whitespace=-blank-at-eof
7 changes: 7 additions & 0 deletions Documentation/RelNotes/2.53.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ UI, Workflows & Features
* More object database related information are shown in "git repo
structure" output.

* Improve the error message when a bad argument is given to the
`--onto` option of "git replay". Test coverage of "git replay" has
been improved.


Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
Expand Down Expand Up @@ -92,6 +96,9 @@ Performance, Internal Implementation, Development Support etc.
* Use hook API to replace ad-hoc invocation of hook scripts with the
run_command() API.
* Import newer version of "clar", unit testing framework.
(merge 84071a6dea ps/clar-integers later to maint).
Fixes since v2.52
-----------------
Expand Down
2 changes: 1 addition & 1 deletion GIT-VERSION-GEN
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/sh

DEF_VER=v2.52.GIT
DEF_VER=v2.53.0-rc0

LF='
'
Expand Down
8 changes: 5 additions & 3 deletions builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1130,8 +1130,10 @@ static int dfs_on_ref(const struct reference *ref, void *cb_data)
return 0;

commit = lookup_commit(the_repository, maybe_peeled);
if (!commit)
if (!commit || commit->object.flags & SEEN)
return 0;
commit->object.flags |= SEEN;

if (repo_parse_commit(the_repository, commit) ||
commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
return 0;
Expand All @@ -1141,7 +1143,7 @@ static int dfs_on_ref(const struct reference *ref, void *cb_data)
if (data->num_not_in_graph >= data->limit)
return 1;

commit_list_append(commit, &stack);
commit_list_insert(commit, &stack);

while (!result && stack) {
struct commit_list *parent;
Expand All @@ -1162,7 +1164,7 @@ static int dfs_on_ref(const struct reference *ref, void *cb_data)
break;
}

commit_list_append(parent->item, &stack);
commit_list_insert(parent->item, &stack);
}
}

Expand Down
87 changes: 25 additions & 62 deletions builtin/replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@ static const char *short_commit_name(struct repository *repo,
DEFAULT_ABBREV);
}

static struct commit *peel_committish(struct repository *repo, const char *name)
static struct commit *peel_committish(struct repository *repo,
const char *name,
const char *mode)
{
struct object *obj;
struct object_id oid;

if (repo_get_oid(repo, name, &oid))
return NULL;
obj = parse_object(repo, &oid);
die(_("'%s' is not a valid commit-ish for %s"), name, mode);
obj = parse_object_or_die(repo, &oid, name);
return (struct commit *)repo_peel_to_type(repo, name, 0, obj,
OBJ_COMMIT);
}
Expand Down Expand Up @@ -162,12 +164,12 @@ static void get_ref_information(struct repository *repo,
}
}

static void determine_replay_mode(struct repository *repo,
struct rev_cmdline_info *cmd_info,
const char *onto_name,
char **advance_name,
struct commit **onto,
struct strset **update_refs)
static void set_up_replay_mode(struct repository *repo,
struct rev_cmdline_info *cmd_info,
const char *onto_name,
char **advance_name,
struct commit **onto,
struct strset **update_refs)
{
struct ref_info rinfo;

Expand All @@ -178,69 +180,30 @@ static void determine_replay_mode(struct repository *repo,
die_for_incompatible_opt2(!!onto_name, "--onto",
!!*advance_name, "--advance");
if (onto_name) {
*onto = peel_committish(repo, onto_name);
*onto = peel_committish(repo, onto_name, "--onto");
if (rinfo.positive_refexprs <
strset_get_size(&rinfo.positive_refs))
die(_("all positive revisions given must be references"));
} else if (*advance_name) {
*update_refs = xcalloc(1, sizeof(**update_refs));
**update_refs = rinfo.positive_refs;
memset(&rinfo.positive_refs, 0, sizeof(**update_refs));
} else {
struct object_id oid;
char *fullname = NULL;

*onto = peel_committish(repo, *advance_name);
if (!*advance_name)
BUG("expected either onto_name or *advance_name in this function");

if (repo_dwim_ref(repo, *advance_name, strlen(*advance_name),
&oid, &fullname, 0) == 1) {
free(*advance_name);
*advance_name = fullname;
} else {
die(_("argument to --advance must be a reference"));
}
*onto = peel_committish(repo, *advance_name, "--advance");
if (rinfo.positive_refexprs > 1)
die(_("cannot advance target with multiple sources because ordering would be ill-defined"));
} else {
int positive_refs_complete = (
rinfo.positive_refexprs ==
strset_get_size(&rinfo.positive_refs));
int negative_refs_complete = (
rinfo.negative_refexprs ==
strset_get_size(&rinfo.negative_refs));
/*
* We need either positive_refs_complete or
* negative_refs_complete, but not both.
*/
if (rinfo.negative_refexprs > 0 &&
positive_refs_complete == negative_refs_complete)
die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
if (negative_refs_complete) {
struct hashmap_iter iter;
struct strmap_entry *entry;
const char *last_key = NULL;

if (rinfo.negative_refexprs == 0)
die(_("all positive revisions given must be references"));
else if (rinfo.negative_refexprs > 1)
die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
else if (rinfo.positive_refexprs > 1)
die(_("cannot advance target with multiple source branches because ordering would be ill-defined"));

/* Only one entry, but we have to loop to get it */
strset_for_each_entry(&rinfo.negative_refs,
&iter, entry) {
last_key = entry->key;
}

free(*advance_name);
*advance_name = xstrdup_or_null(last_key);
} else { /* positive_refs_complete */
if (rinfo.negative_refexprs > 1)
die(_("cannot implicitly determine correct base for --onto"));
if (rinfo.negative_refexprs == 1)
*onto = rinfo.onto;
}
}
if (!*advance_name) {
*update_refs = xcalloc(1, sizeof(**update_refs));
**update_refs = rinfo.positive_refs;
memset(&rinfo.positive_refs, 0, sizeof(**update_refs));
}
strset_clear(&rinfo.negative_refs);
strset_clear(&rinfo.positive_refs);
Expand Down Expand Up @@ -451,11 +414,11 @@ int cmd_replay(int argc,
revs.simplify_history = 0;
}

determine_replay_mode(repo, &revs.cmdline, onto_name, &advance_name,
&onto, &update_refs);
set_up_replay_mode(repo, &revs.cmdline,
onto_name, &advance_name,
&onto, &update_refs);

if (!onto) /* FIXME: Should handle replaying down to root commit */
die("Replaying down to root commit is not supported yet!");
/* FIXME: Should allow replaying commits with the first as a root commit */

/* Build reflog message */
if (advance_name_opt)
Expand Down Expand Up @@ -491,7 +454,7 @@ int cmd_replay(int argc,
int hr;

if (!commit->parents)
die(_("replaying down to root commit is not supported yet!"));
die(_("replaying down from root commit is not supported yet!"));
if (commit->parents->next)
die(_("replaying merge commits is not supported yet!"));

Expand Down
2 changes: 1 addition & 1 deletion odb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1117,13 +1117,13 @@ void odb_free(struct object_database *o)
oidmap_clear(&o->replace_map, 1);
pthread_mutex_destroy(&o->replace_mutex);

odb_close(o);
odb_free_sources(o);

for (size_t i = 0; i < o->cached_object_nr; i++)
free((char *) o->cached_objects[i].value.buf);
free(o->cached_objects);

odb_close(o);
packfile_store_free(o->packfiles);
string_list_clear(&o->submodule_source_paths, 0);

Expand Down
54 changes: 54 additions & 0 deletions t/t3650-replay-basics.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ test_expect_success 'setup' '
test_commit L &&
test_commit M &&

git switch --detach topic4 &&
test_commit N &&
test_commit O &&
git switch -c topic-with-merge topic4 &&
test_merge P O --no-ff &&
git switch main &&

git switch -c conflict B &&
test_commit C.conflict C.t conflict
'
Expand All @@ -51,6 +58,53 @@ test_expect_success 'setup bare' '
git clone --bare . bare
'

test_expect_success 'argument to --advance must be a reference' '
echo "fatal: argument to --advance must be a reference" >expect &&
oid=$(git rev-parse main) &&
test_must_fail git replay --advance=$oid topic1..topic2 2>actual &&
test_cmp expect actual
'

test_expect_success '--onto with invalid commit-ish' '
printf "fatal: ${SQ}refs/not-valid${SQ} is not " >expect &&
printf "a valid commit-ish for --onto\n" >>expect &&
test_must_fail git replay --onto=refs/not-valid topic1..topic2 2>actual &&
test_cmp expect actual
'

test_expect_success 'option --onto or --advance is mandatory' '
echo "error: option --onto or --advance is mandatory" >expect &&
test_might_fail git replay -h >>expect &&
test_must_fail git replay topic1..topic2 2>actual &&
test_cmp expect actual
'

test_expect_success 'no base or negative ref gives no-replaying down to root error' '
echo "fatal: replaying down from root commit is not supported yet!" >expect &&
test_must_fail git replay --onto=topic1 topic2 2>actual &&
test_cmp expect actual
'

test_expect_success 'options --advance and --contained cannot be used together' '
printf "fatal: options ${SQ}--advance${SQ} " >expect &&
printf "and ${SQ}--contained${SQ} cannot be used together\n" >>expect &&
test_must_fail git replay --advance=main --contained \
topic1..topic2 2>actual &&
test_cmp expect actual
'

test_expect_success 'cannot advance target ... ordering would be ill-defined' '
echo "fatal: cannot advance target with multiple sources because ordering would be ill-defined" >expect &&
test_must_fail git replay --advance=main main topic1 topic2 2>actual &&
test_cmp expect actual
'

test_expect_success 'replaying merge commits is not supported yet' '
echo "fatal: replaying merge commits is not supported yet!" >expect &&
test_must_fail git replay --advance=main main..topic-with-merge 2>actual &&
test_cmp expect actual
'

test_expect_success 'using replay to rebase two branches, one on top of other' '
git replay --ref-action=print --onto main topic1..topic2 >result &&

Expand Down
6 changes: 3 additions & 3 deletions t/t7800-difftool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -647,21 +647,21 @@ test_expect_success SYMLINKS 'difftool --dir-diff --symlinks without unstaged ch
'

write_script modify-right-file <<\EOF
echo "new content" >"$2/file"
echo "modified content" >"$2/file"
EOF

run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' '
test_when_finished git reset --hard &&
echo "orig content" >file &&
git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
echo "new content" >expect &&
echo "modified content" >expect &&
test_cmp expect file
'

run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
test_when_finished git reset --hard &&
git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
echo "new content" >expect &&
echo "modified content" >expect &&
test_cmp expect file
'

Expand Down
25 changes: 25 additions & 0 deletions t/t7900-maintenance.sh
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,31 @@ test_expect_success 'commit-graph auto condition' '
test_subcommand $COMMIT_GRAPH_WRITE <cg-two-satisfied.txt
'

test_expect_success 'commit-graph auto condition with merges' '
test_when_finished "rm -rf repo" &&
git init repo &&
(
cd repo &&
git config set maintenance.auto false &&
test_commit initial &&
git switch --create feature &&
test_commit feature-1 &&
test_commit feature-2 &&
git switch - &&
test_commit main-1 &&
test_commit main-2 &&
git merge feature &&

# We have 6 commits, none of which are covered by a commit
# graph. So this must be the boundary at which we start to
# perform maintenance.
test_must_fail git -c maintenance.commit-graph.auto=7 \
maintenance is-needed --auto --task=commit-graph &&
git -c maintenance.commit-graph.auto=6 \
maintenance is-needed --auto --task=commit-graph
)
'

test_expect_success 'run --task=bogus' '
test_must_fail git maintenance run --task=bogus 2>err &&
test_grep "is not a valid task" err
Expand Down
2 changes: 1 addition & 1 deletion t/unit-tests/clar/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
if: matrix.platform.image == 'i386/debian:latest'
run: apt -q update && apt -q -y install cmake gcc libc6-amd64 lib64stdc++6 make python3
- name: Check out
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build
shell: bash
run: |
Expand Down
Loading