Skip to content

Commit 41fab83

Browse files
pks-tgitster
authored andcommitted
replay: allow callers to control what happens with empty commits
When replaying commits it may happen that some of the commits become empty relative to their parent. Such commits are for now automatically dropped by the replay subsystem without much control from the user. Introduce a new enum that allows the caller to drop, keep or abort in this case. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 94f0577 commit 41fab83

2 files changed

Lines changed: 43 additions & 5 deletions

File tree

replay.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ static struct commit *pick_regular_commit(struct repository *repo,
269269
struct commit *onto,
270270
struct merge_options *merge_opt,
271271
struct merge_result *result,
272-
enum replay_mode mode)
272+
enum replay_mode mode,
273+
enum replay_empty_commit_action empty)
273274
{
274275
struct commit *base, *replayed_base;
275276
struct tree *pickme_tree, *base_tree, *replayed_base_tree;
@@ -321,12 +322,25 @@ static struct commit *pick_regular_commit(struct repository *repo,
321322
}
322323
merge_opt->ancestor = NULL;
323324
merge_opt->branch2 = NULL;
325+
324326
if (!result->clean)
325327
return NULL;
326-
/* Drop commits that become empty */
328+
329+
/* Handle commits that become empty */
327330
if (oideq(&replayed_base_tree->object.oid, &result->tree->object.oid) &&
328-
!oideq(&pickme_tree->object.oid, &base_tree->object.oid))
329-
return replayed_base;
331+
!oideq(&pickme_tree->object.oid, &base_tree->object.oid)) {
332+
switch (empty) {
333+
case REPLAY_EMPTY_COMMIT_DROP:
334+
return replayed_base;
335+
case REPLAY_EMPTY_COMMIT_KEEP:
336+
break;
337+
case REPLAY_EMPTY_COMMIT_ABORT:
338+
result->clean = error(_("commit %s became empty after replay"),
339+
oid_to_hex(&pickme->object.oid));
340+
return NULL;
341+
}
342+
}
343+
330344
return create_commit(repo, result->tree, pickme, replayed_base, mode);
331345
}
332346

@@ -417,7 +431,7 @@ int replay_revisions(struct rev_info *revs,
417431

418432
last_commit = pick_regular_commit(revs->repo, commit, replayed_commits,
419433
mode == REPLAY_MODE_REVERT ? last_commit : onto,
420-
&merge_opt, &result, mode);
434+
&merge_opt, &result, mode, opts->empty);
421435
if (!last_commit)
422436
break;
423437

@@ -458,6 +472,11 @@ int replay_revisions(struct rev_info *revs,
458472
}
459473
}
460474

475+
if (result.clean < 0) {
476+
ret = -1;
477+
goto out;
478+
}
479+
461480
if (!result.clean) {
462481
ret = 1;
463482
goto out;

replay.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@
66
struct repository;
77
struct rev_info;
88

9+
/*
10+
* Controls what happens when a replayed commit becomes empty (i.e. its tree
11+
* is identical to its parent's tree after the replay).
12+
*/
13+
enum replay_empty_commit_action {
14+
/* Silently discard the empty commit. */
15+
REPLAY_EMPTY_COMMIT_DROP,
16+
/* Keep the empty commit as-is. */
17+
REPLAY_EMPTY_COMMIT_KEEP,
18+
/* Abort with an error. */
19+
REPLAY_EMPTY_COMMIT_ABORT,
20+
};
21+
922
/*
1023
* A set of options that can be passed to `replay_revisions()`.
1124
*/
@@ -43,6 +56,12 @@ struct replay_revisions_options {
4356
* Requires `onto` to be set.
4457
*/
4558
int contained;
59+
60+
/*
61+
* Controls what to do when a replayed commit becomes empty.
62+
* Defaults to REPLAY_EMPTY_COMMIT_DROP.
63+
*/
64+
enum replay_empty_commit_action empty;
4665
};
4766

4867
/* This struct is used as an out-parameter by `replay_revisions()`. */

0 commit comments

Comments
 (0)