When using git-cherry-pick(1) with `--allow-empty` while on an unborn branch, an error is thrown. This is inconsistent with the same cherry-pick when `--allow-empty` is not specified. Treat a failure reading HEAD as an unborn branch in `is_index_unchanged`. This is consistent with other sequencer logic such as `do_pick_commit`. When on an unborn branch, use the `empty_tree` as the tree to compare against. Add a new test to cover this scenario. While modelled off of the existing 'cherry-pick on unborn branch' test, some improvements can be made: - Use `git switch --orphan unborn` instead of `git checkout --orphan unborn` to avoid the need for a separate `rm -rf *` call - Avoid using `--quiet` in the `git diff` call to make debugging easier in the event of a failure Make these improvements to the existing test as well as the new test. Helped-by: Phillip Wood <phillip.wood@xxxxxxxxxxxxx> Signed-off-by: Brian Lyles <brianmlyles@xxxxxxxxx> --- Differences from v2: - Minor code and test cleanup per [1] and the other replies in that thread [1]: https://lore.kernel.org/git/62247a1c-0249-4ce1-8626-fe97b89c23dc@xxxxxxxxx/ sequencer.c | 35 +++++++++++++++++++++-------------- t/t3501-revert-cherry-pick.sh | 14 +++++++++++--- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/sequencer.c b/sequencer.c index f49a871ac0..a62ce244c1 100644 --- a/sequencer.c +++ b/sequencer.c @@ -770,29 +770,36 @@ static struct object_id *get_cache_tree_oid(struct index_state *istate) static int is_index_unchanged(struct repository *r) { struct object_id head_oid, *cache_tree_oid; + const struct object_id *head_tree_oid; struct commit *head_commit; struct index_state *istate = r->index; - if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) - return error(_("could not resolve HEAD commit")); + if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) { + /* + * Treat an error reading HEAD as an unborn branch. + */ + head_tree_oid = the_hash_algo->empty_tree; + } else { + head_commit = lookup_commit(r, &head_oid); - head_commit = lookup_commit(r, &head_oid); + /* + * If head_commit is NULL, check_commit, called from + * lookup_commit, would have indicated that head_commit is not + * a commit object already. repo_parse_commit() will return failure + * without further complaints in such a case. Otherwise, if + * the commit is invalid, repo_parse_commit() will complain. So + * there is nothing for us to say here. Just return failure. + */ + if (repo_parse_commit(r, head_commit)) + return -1; - /* - * If head_commit is NULL, check_commit, called from - * lookup_commit, would have indicated that head_commit is not - * a commit object already. repo_parse_commit() will return failure - * without further complaints in such a case. Otherwise, if - * the commit is invalid, repo_parse_commit() will complain. So - * there is nothing for us to say here. Just return failure. - */ - if (repo_parse_commit(r, head_commit)) - return -1; + head_tree_oid = get_commit_tree_oid(head_commit); + } if (!(cache_tree_oid = get_cache_tree_oid(istate))) return -1; - return oideq(cache_tree_oid, get_commit_tree_oid(head_commit)); + return oideq(cache_tree_oid, head_tree_oid); } static int write_author_script(const char *message) diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh index aeab689a98..8a1d154ca6 100755 --- a/t/t3501-revert-cherry-pick.sh +++ b/t/t3501-revert-cherry-pick.sh @@ -104,11 +104,19 @@ test_expect_success 'revert forbidden on dirty working tree' ' ' test_expect_success 'cherry-pick on unborn branch' ' - git checkout --orphan unborn && + git switch --orphan unborn && git rm --cached -r . && - rm -rf * && git cherry-pick initial && - git diff --quiet initial && + git diff initial && + test_cmp_rev ! initial HEAD +' + +test_expect_success 'cherry-pick on unborn branch with --allow-empty' ' + git checkout --detach && + git branch -D unborn && + git switch --orphan unborn && + git cherry-pick initial --allow-empty && + git diff initial && test_cmp_rev ! initial HEAD ' -- 2.43.0