Skip to content

Commit ac2b0e8

Browse files
committed
cherry-pick: regression fix for empty commits
The earlier "--keep-redundant-commit" series broke "cherry-pick" that is given a commit whose change is already in the current history. Such a cherry-pick would result in an empty change, and should stop with an error, telling the user that conflict resolution may have made the result empty (which is exactly what is happening), but we silently dropped the change on the floor without any message nor non-zero exit code. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4b58006 commit ac2b0e8

File tree

2 files changed

+75
-28
lines changed

2 files changed

+75
-28
lines changed

sequencer.c

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ static int is_index_unchanged(void)
291291
* If we are revert, or if our cherry-pick results in a hand merge,
292292
* we had better say that the current user is responsible for that.
293293
*/
294-
static int run_git_commit(const char *defmsg, struct replay_opts *opts)
294+
static int run_git_commit(const char *defmsg, struct replay_opts *opts,
295+
int allow_empty)
295296
{
296297
struct argv_array array;
297298
int rc;
@@ -307,7 +308,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)
307308
argv_array_push(&array, defmsg);
308309
}
309310

310-
if (opts->allow_empty)
311+
if (allow_empty)
311312
argv_array_push(&array, "--allow-empty");
312313

313314
rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
@@ -335,6 +336,44 @@ static int is_original_commit_empty(struct commit *commit)
335336
return !hashcmp(ptree_sha1, commit->tree->object.sha1);
336337
}
337338

339+
/*
340+
* Do we run "git commit" with "--allow-empty"?
341+
*/
342+
static int allow_empty(struct replay_opts *opts, struct commit *commit)
343+
{
344+
int index_unchanged, empty_commit;
345+
346+
/*
347+
* Three cases:
348+
*
349+
* (1) we do not allow empty at all and error out.
350+
*
351+
* (2) we allow ones that were initially empty, but
352+
* forbid the ones that become empty;
353+
*
354+
* (3) we allow both.
355+
*/
356+
if (!opts->allow_empty)
357+
return 0; /* let "git commit" barf as necessary */
358+
359+
index_unchanged = is_index_unchanged();
360+
if (index_unchanged < 0)
361+
return index_unchanged;
362+
if (!index_unchanged)
363+
return 0; /* we do not have to say --allow-empty */
364+
365+
if (opts->keep_redundant_commits)
366+
return 1;
367+
368+
empty_commit = is_original_commit_empty(commit);
369+
if (empty_commit < 0)
370+
return empty_commit;
371+
if (!empty_commit)
372+
return 0;
373+
else
374+
return 1;
375+
}
376+
338377
static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
339378
{
340379
unsigned char head[20];
@@ -344,8 +383,6 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
344383
char *defmsg = NULL;
345384
struct strbuf msgbuf = STRBUF_INIT;
346385
int res;
347-
int empty_commit;
348-
int index_unchanged;
349386

350387
if (opts->no_commit) {
351388
/*
@@ -471,10 +508,6 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
471508
free_commit_list(remotes);
472509
}
473510

474-
empty_commit = is_original_commit_empty(commit);
475-
if (empty_commit < 0)
476-
return empty_commit;
477-
478511
/*
479512
* If the merge was clean or if it failed due to conflict, we write
480513
* CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
@@ -495,27 +528,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
495528
print_advice(res == 1, opts);
496529
rerere(opts->allow_rerere_auto);
497530
} else {
498-
index_unchanged = is_index_unchanged();
499-
/*
500-
* If index_unchanged is less than 0, that indicates we either
501-
* couldn't parse HEAD or the index, so error out here.
502-
*/
503-
if (index_unchanged < 0)
504-
return index_unchanged;
505-
506-
if (!empty_commit && !opts->keep_redundant_commits && index_unchanged)
507-
/*
508-
* The head tree and the index match
509-
* meaning the commit is empty. Since it wasn't created
510-
* empty (based on the previous test), we can conclude
511-
* the commit has been made redundant. Since we don't
512-
* want to keep redundant commits, we can just return
513-
* here, skipping this commit
514-
*/
515-
return 0;
516-
531+
int allow = allow_empty(opts, commit);
532+
if (allow < 0)
533+
return allow;
517534
if (!opts->no_commit)
518-
res = run_git_commit(defmsg, opts);
535+
res = run_git_commit(defmsg, opts, allow);
519536
}
520537

521538
free_message(&msg);

t/t3505-cherry-pick-empty.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,34 @@ test_expect_success 'cherry pick with --keep-redundant-commits' '
7171
git cherry-pick --keep-redundant-commits HEAD^
7272
'
7373

74+
test_expect_success 'cherry-pick a commit that becomes no-op (prep)' '
75+
git checkout master &&
76+
git branch fork &&
77+
echo foo >file2 &&
78+
git add file2 &&
79+
test_tick &&
80+
git commit -m "add file2 on master" &&
81+
82+
git checkout fork &&
83+
echo foo >file2 &&
84+
git add file2 &&
85+
test_tick &&
86+
git commit -m "add file2 on the side"
87+
'
88+
89+
test_expect_success 'cherry-pick a no-op without --keep-redundant' '
90+
git reset --hard &&
91+
git checkout fork^0 &&
92+
test_must_fail git cherry-pick master
93+
'
94+
95+
test_expect_success 'cherry-pick a no-op with --keep-redundant' '
96+
git reset --hard &&
97+
git checkout fork^0 &&
98+
git cherry-pick --keep-redundant-commits master &&
99+
git show -s --format='%s' >actual &&
100+
echo "add file2 on master" >expect &&
101+
test_cmp expect actual
102+
'
103+
74104
test_done

0 commit comments

Comments
 (0)