2016-06-28 12:54:02 +02:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description='git rebase tests for -Xsubtree
|
|
|
|
|
|
|
|
This test runs git rebase and tests the subtree strategy.
|
|
|
|
'
|
2020-11-19 00:44:25 +01:00
|
|
|
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
tests: mark tests relying on the current default for `init.defaultBranch`
In addition to the manual adjustment to let the `linux-gcc` CI job run
the test suite with `master` and then with `main`, this patch makes sure
that GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME is set in all test scripts
that currently rely on the initial branch name being `master by default.
To determine which test scripts to mark up, the first step was to
force-set the default branch name to `master` in
- all test scripts that contain the keyword `master`,
- t4211, which expects `t/t4211/history.export` with a hard-coded ref to
initialize the default branch,
- t5560 because it sources `t/t556x_common` which uses `master`,
- t8002 and t8012 because both source `t/annotate-tests.sh` which also
uses `master`)
This trick was performed by this command:
$ sed -i '/^ *\. \.\/\(test-lib\|lib-\(bash\|cvs\|git-svn\)\|gitweb-lib\)\.sh$/i\
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\
' $(git grep -l master t/t[0-9]*.sh) \
t/t4211*.sh t/t5560*.sh t/t8002*.sh t/t8012*.sh
After that, careful, manual inspection revealed that some of the test
scripts containing the needle `master` do not actually rely on a
specific default branch name: either they mention `master` only in a
comment, or they initialize that branch specificially, or they do not
actually refer to the current default branch. Therefore, the
aforementioned modification was undone in those test scripts thusly:
$ git checkout HEAD -- \
t/t0027-auto-crlf.sh t/t0060-path-utils.sh \
t/t1011-read-tree-sparse-checkout.sh \
t/t1305-config-include.sh t/t1309-early-config.sh \
t/t1402-check-ref-format.sh t/t1450-fsck.sh \
t/t2024-checkout-dwim.sh \
t/t2106-update-index-assume-unchanged.sh \
t/t3040-subprojects-basic.sh t/t3301-notes.sh \
t/t3308-notes-merge.sh t/t3423-rebase-reword.sh \
t/t3436-rebase-more-options.sh \
t/t4015-diff-whitespace.sh t/t4257-am-interactive.sh \
t/t5323-pack-redundant.sh t/t5401-update-hooks.sh \
t/t5511-refspec.sh t/t5526-fetch-submodules.sh \
t/t5529-push-errors.sh t/t5530-upload-pack-error.sh \
t/t5548-push-porcelain.sh \
t/t5552-skipping-fetch-negotiator.sh \
t/t5572-pull-submodule.sh t/t5608-clone-2gb.sh \
t/t5614-clone-submodules-shallow.sh \
t/t7508-status.sh t/t7606-merge-custom.sh \
t/t9302-fast-import-unpack-limit.sh
We excluded one set of test scripts in these commands, though: the range
of `git p4` tests. The reason? `git p4` stores the (foreign) remote
branch in the branch called `p4/master`, which is obviously not the
default branch. Manual analysis revealed that only five of these tests
actually require a specific default branch name to pass; They were
modified thusly:
$ sed -i '/^ *\. \.\/lib-git-p4\.sh$/i\
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\
' t/t980[0167]*.sh t/t9811*.sh
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-19 00:44:19 +01:00
|
|
|
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
|
|
|
|
2016-06-28 12:54:02 +02:00
|
|
|
. ./test-lib.sh
|
|
|
|
. "$TEST_DIRECTORY"/lib-rebase.sh
|
|
|
|
|
|
|
|
commit_message() {
|
|
|
|
git log --pretty=format:%s -1 "$1"
|
|
|
|
}
|
|
|
|
|
2019-07-31 17:18:42 +02:00
|
|
|
# There are a few bugs in the rebase with regards to the subtree strategy, and
|
|
|
|
# this test script tries to document them. First, the following commit history
|
|
|
|
# is generated (the onelines are shown, time flows from left to right):
|
|
|
|
#
|
2020-09-26 23:04:21 +02:00
|
|
|
# topic_1 - topic_2 - topic_3
|
2019-07-31 17:18:42 +02:00
|
|
|
# \
|
2020-11-19 00:44:25 +01:00
|
|
|
# README ---------------------- Add subproject main - topic_4 - files_subtree/topic_5
|
2019-07-31 17:18:42 +02:00
|
|
|
#
|
2020-11-09 01:09:22 +01:00
|
|
|
# Where the merge moves the files topic_[123].t into the subdirectory
|
2020-09-26 23:04:21 +02:00
|
|
|
# files_subtree/ and topic_4 as well as files_subtree/topic_5 add files to that
|
2019-07-31 17:18:42 +02:00
|
|
|
# directory directly.
|
|
|
|
#
|
|
|
|
# Then, in subsequent test cases, `git filter-branch` is used to distill just
|
|
|
|
# the commits that touch files_subtree/. To give it a final pre-rebase touch,
|
|
|
|
# an empty commit is added on top. The pre-rebase commit history looks like
|
|
|
|
# this:
|
|
|
|
#
|
2020-11-19 00:44:25 +01:00
|
|
|
# Add subproject main - topic_4 - files_subtree/topic_5 - Empty commit
|
2019-07-31 17:18:42 +02:00
|
|
|
#
|
2020-09-26 23:04:21 +02:00
|
|
|
# where the root commit adds three files: topic_1.t, topic_2.t and topic_3.t.
|
2019-07-31 17:18:42 +02:00
|
|
|
#
|
2020-09-26 23:04:21 +02:00
|
|
|
# This commit history is then rebased onto `topic_3` with the
|
2019-07-31 17:18:42 +02:00
|
|
|
# `-Xsubtree=files_subtree` option in three different ways:
|
|
|
|
#
|
|
|
|
# 1. using `--preserve-merges`
|
|
|
|
# 2. using `--preserve-merges` and --keep-empty
|
|
|
|
# 3. without specifying a rebase backend
|
|
|
|
|
2016-06-28 12:54:02 +02:00
|
|
|
test_expect_success 'setup' '
|
|
|
|
test_commit README &&
|
2019-07-31 17:18:42 +02:00
|
|
|
|
|
|
|
git init files &&
|
2020-09-26 23:04:21 +02:00
|
|
|
test_commit -C files topic_1 &&
|
|
|
|
test_commit -C files topic_2 &&
|
|
|
|
test_commit -C files topic_3 &&
|
2019-07-31 17:18:42 +02:00
|
|
|
|
|
|
|
: perform subtree merge into files_subtree/ &&
|
2020-11-19 00:44:25 +01:00
|
|
|
git fetch files refs/heads/main:refs/heads/files-main &&
|
2019-07-31 17:18:42 +02:00
|
|
|
git merge -s ours --no-commit --allow-unrelated-histories \
|
2020-11-19 00:44:25 +01:00
|
|
|
files-main &&
|
|
|
|
git read-tree --prefix=files_subtree -u files-main &&
|
|
|
|
git commit -m "Add subproject main" &&
|
2019-07-31 17:18:42 +02:00
|
|
|
|
|
|
|
: add two extra commits to rebase &&
|
2020-09-26 23:04:21 +02:00
|
|
|
test_commit -C files_subtree topic_4 &&
|
|
|
|
test_commit files_subtree/topic_5 &&
|
2019-07-31 17:18:43 +02:00
|
|
|
|
|
|
|
git checkout -b to-rebase &&
|
2019-09-04 23:40:48 +02:00
|
|
|
git fast-export --no-data HEAD -- files_subtree/ |
|
|
|
|
sed -e "s%\([0-9a-f]\{40\} \)files_subtree/%\1%" |
|
|
|
|
git fast-import --force --quiet &&
|
|
|
|
git reset --hard &&
|
2019-07-31 17:18:43 +02:00
|
|
|
git commit -m "Empty commit" --allow-empty
|
2016-06-28 12:54:02 +02:00
|
|
|
'
|
|
|
|
|
2020-09-26 23:04:21 +02:00
|
|
|
# FAILURE: Does not preserve topic_4.
|
2019-07-31 17:18:44 +02:00
|
|
|
test_expect_failure REBASE_P 'Rebase -Xsubtree --preserve-merges --onto commit' '
|
2016-06-28 12:54:02 +02:00
|
|
|
reset_rebase &&
|
2019-07-31 17:18:44 +02:00
|
|
|
git checkout -b rebase-preserve-merges to-rebase &&
|
2020-11-19 00:44:25 +01:00
|
|
|
git rebase -Xsubtree=files_subtree --preserve-merges --onto files-main main &&
|
2020-09-26 23:04:21 +02:00
|
|
|
verbose test "$(commit_message HEAD~)" = "topic_4" &&
|
|
|
|
verbose test "$(commit_message HEAD)" = "files_subtree/topic_5"
|
2016-06-28 12:54:02 +02:00
|
|
|
'
|
|
|
|
|
2020-09-26 23:04:21 +02:00
|
|
|
# FAILURE: Does not preserve topic_4.
|
2019-07-31 17:18:44 +02:00
|
|
|
test_expect_failure REBASE_P 'Rebase -Xsubtree --keep-empty --preserve-merges --onto commit' '
|
2016-06-28 12:54:02 +02:00
|
|
|
reset_rebase &&
|
2019-07-31 17:18:44 +02:00
|
|
|
git checkout -b rebase-keep-empty to-rebase &&
|
2020-11-19 00:44:25 +01:00
|
|
|
git rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-main main &&
|
2020-09-26 23:04:21 +02:00
|
|
|
verbose test "$(commit_message HEAD~2)" = "topic_4" &&
|
|
|
|
verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
|
2016-06-28 12:54:02 +02:00
|
|
|
verbose test "$(commit_message HEAD)" = "Empty commit"
|
|
|
|
'
|
|
|
|
|
rebase (interactive-backend): fix handling of commits that become empty
As established in the previous commit and commit b00bf1c9a8dd
(git-rebase: make --allow-empty-message the default, 2018-06-27), the
behavior for rebase with different backends in various edge or corner
cases is often more happenstance than design. This commit addresses
another such corner case: commits which "become empty".
A careful reader may note that there are two types of commits which would
become empty due to a rebase:
* [clean cherry-pick] Commits which are clean cherry-picks of upstream
commits, as determined by `git log --cherry-mark ...`. Re-applying
these commits would result in an empty set of changes and a
duplicative commit message; i.e. these are commits that have
"already been applied" upstream.
* [become empty] Commits which are not empty to start, are not clean
cherry-picks of upstream commits, but which still become empty after
being rebased. This happens e.g. when a commit has changes which
are a strict subset of the changes in an upstream commit, or when
the changes of a commit can be found spread across or among several
upstream commits.
Clearly, in both cases the changes in the commit in question are found
upstream already, but the commit message may not be in the latter case.
When cherry-mark can determine a commit is already upstream, then
because of how cherry-mark works this means the upstream commit message
was about the *exact* same set of changes. Thus, the commit messages
can be assumed to be fully interchangeable (and are in fact likely to be
completely identical). As such, the clean cherry-pick case represents a
case when there is no information to be gained by keeping the extra
commit around. All rebase types have always dropped these commits, and
no one to my knowledge has ever requested that we do otherwise.
For many of the become empty cases (and likely even most), we will also
be able to drop the commit without loss of information -- but this isn't
quite always the case. Since these commits represent cases that were
not clean cherry-picks, there is no upstream commit message explaining
the same set of changes. Projects with good commit message hygiene will
likely have the explanation from our commit message contained within or
spread among the relevant upstream commits, but not all projects run
that way. As such, the commit message of the commit being rebased may
have reasoning that suggests additional changes that should be made to
adapt to the new base, or it may have information that someone wants to
add as a note to another commit, or perhaps someone even wants to create
an empty commit with the commit message as-is.
Junio commented on the "become-empty" types of commits as follows[1]:
WRT a change that ends up being empty (as opposed to a change that
is empty from the beginning), I'd think that the current behaviour
is desireable one. "am" based rebase is solely to transplant an
existing history and want to stop much less than "interactive" one
whose purpose is to polish a series before making it publishable,
and asking for confirmation ("this has become empty--do you want to
drop it?") is more appropriate from the workflow point of view.
[1] https://lore.kernel.org/git/xmqqfu1fswdh.fsf@gitster-ct.c.googlers.com/
I would simply add that his arguments for "am"-based rebases actually
apply to all non-explicitly-interactive rebases. Also, since we are
stating that different cases should have different defaults, it may be
worth providing a flag to allow users to select which behavior they want
for these commits.
Introduce a new command line flag for selecting the desired behavior:
--empty={drop,keep,ask}
with the definitions:
drop: drop commits which become empty
keep: keep commits which become empty
ask: provide the user a chance to interact and pick what to do with
commits which become empty on a case-by-case basis
In line with Junio's suggestion, if the --empty flag is not specified,
pick defaults as follows:
explicitly interactive: ask
otherwise: drop
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-15 22:36:25 +01:00
|
|
|
test_expect_success 'Rebase -Xsubtree --empty=ask --onto commit' '
|
2016-06-28 12:54:02 +02:00
|
|
|
reset_rebase &&
|
2019-07-31 17:18:44 +02:00
|
|
|
git checkout -b rebase-onto to-rebase &&
|
2020-11-19 00:44:25 +01:00
|
|
|
test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --onto files-main main &&
|
2019-07-31 17:18:46 +02:00
|
|
|
: first pick results in no changes &&
|
rebase (interactive-backend): make --keep-empty the default
Different rebase backends have different treatment for commits which
start empty (i.e. have no changes relative to their parent), and the
--keep-empty option was added at some point to allow adjusting behavior.
The handling of commits which start empty is actually quite similar to
commit b00bf1c9a8dd (git-rebase: make --allow-empty-message the default,
2018-06-27), which pointed out that the behavior for various backends is
often more happenstance than design. The specific change made in that
commit is actually quite relevant as well and much of the logic there
directly applies here.
It makes a lot of sense in 'git commit' to error out on the creation of
empty commits, unless an override flag is provided. However, once
someone determines that there is a rare case that merits using the
manual override to create such a commit, it is somewhere between
annoying and harmful to have to take extra steps to keep such
intentional commits around. Granted, empty commits are quite rare,
which is why handling of them doesn't get considered much and folks tend
to defer to existing (accidental) behavior and assume there was a reason
for it, leading them to just add flags (--keep-empty in this case) that
allow them to override the bad defaults. Fix the interactive backend so
that --keep-empty is the default, much like we did with
--allow-empty-message. The am backend should also be fixed to have
--keep-empty semantics for commits that start empty, but that is not
included in this patch other than a testcase documenting the failure.
Note that there was one test in t3421 which appears to have been written
expecting --keep-empty to not be the default as correct behavior. This
test was introduced in commit 00b8be5a4d38 ("add tests for rebasing of
empty commits", 2013-06-06), which was part of a series focusing on
rebase topology and which had an interesting original cover letter at
https://lore.kernel.org/git/1347949878-12578-1-git-send-email-martinvonz@gmail.com/
which noted
Your input especially appreciated on whether you agree with the
intent of the test cases.
and then went into a long example about how one of the many tests added
had several questions about whether it was correct. As such, I believe
most the tests in that series were about testing rebase topology with as
many different flags as possible and were not trying to state in general
how those flags should behave otherwise.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-15 22:36:24 +01:00
|
|
|
git rebase --skip &&
|
2020-09-26 23:04:21 +02:00
|
|
|
verbose test "$(commit_message HEAD~2)" = "topic_4" &&
|
|
|
|
verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
|
2016-06-28 12:54:02 +02:00
|
|
|
verbose test "$(commit_message HEAD)" = "Empty commit"
|
|
|
|
'
|
|
|
|
|
rebase (interactive-backend): fix handling of commits that become empty
As established in the previous commit and commit b00bf1c9a8dd
(git-rebase: make --allow-empty-message the default, 2018-06-27), the
behavior for rebase with different backends in various edge or corner
cases is often more happenstance than design. This commit addresses
another such corner case: commits which "become empty".
A careful reader may note that there are two types of commits which would
become empty due to a rebase:
* [clean cherry-pick] Commits which are clean cherry-picks of upstream
commits, as determined by `git log --cherry-mark ...`. Re-applying
these commits would result in an empty set of changes and a
duplicative commit message; i.e. these are commits that have
"already been applied" upstream.
* [become empty] Commits which are not empty to start, are not clean
cherry-picks of upstream commits, but which still become empty after
being rebased. This happens e.g. when a commit has changes which
are a strict subset of the changes in an upstream commit, or when
the changes of a commit can be found spread across or among several
upstream commits.
Clearly, in both cases the changes in the commit in question are found
upstream already, but the commit message may not be in the latter case.
When cherry-mark can determine a commit is already upstream, then
because of how cherry-mark works this means the upstream commit message
was about the *exact* same set of changes. Thus, the commit messages
can be assumed to be fully interchangeable (and are in fact likely to be
completely identical). As such, the clean cherry-pick case represents a
case when there is no information to be gained by keeping the extra
commit around. All rebase types have always dropped these commits, and
no one to my knowledge has ever requested that we do otherwise.
For many of the become empty cases (and likely even most), we will also
be able to drop the commit without loss of information -- but this isn't
quite always the case. Since these commits represent cases that were
not clean cherry-picks, there is no upstream commit message explaining
the same set of changes. Projects with good commit message hygiene will
likely have the explanation from our commit message contained within or
spread among the relevant upstream commits, but not all projects run
that way. As such, the commit message of the commit being rebased may
have reasoning that suggests additional changes that should be made to
adapt to the new base, or it may have information that someone wants to
add as a note to another commit, or perhaps someone even wants to create
an empty commit with the commit message as-is.
Junio commented on the "become-empty" types of commits as follows[1]:
WRT a change that ends up being empty (as opposed to a change that
is empty from the beginning), I'd think that the current behaviour
is desireable one. "am" based rebase is solely to transplant an
existing history and want to stop much less than "interactive" one
whose purpose is to polish a series before making it publishable,
and asking for confirmation ("this has become empty--do you want to
drop it?") is more appropriate from the workflow point of view.
[1] https://lore.kernel.org/git/xmqqfu1fswdh.fsf@gitster-ct.c.googlers.com/
I would simply add that his arguments for "am"-based rebases actually
apply to all non-explicitly-interactive rebases. Also, since we are
stating that different cases should have different defaults, it may be
worth providing a flag to allow users to select which behavior they want
for these commits.
Introduce a new command line flag for selecting the desired behavior:
--empty={drop,keep,ask}
with the definitions:
drop: drop commits which become empty
keep: keep commits which become empty
ask: provide the user a chance to interact and pick what to do with
commits which become empty on a case-by-case basis
In line with Junio's suggestion, if the --empty flag is not specified,
pick defaults as follows:
explicitly interactive: ask
otherwise: drop
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-15 22:36:25 +01:00
|
|
|
test_expect_success 'Rebase -Xsubtree --empty=ask --rebase-merges --onto commit' '
|
2019-07-31 17:18:49 +02:00
|
|
|
reset_rebase &&
|
|
|
|
git checkout -b rebase-merges-onto to-rebase &&
|
2020-11-19 00:44:25 +01:00
|
|
|
test_must_fail git rebase -Xsubtree=files_subtree --empty=ask --rebase-merges --onto files-main --root &&
|
2019-07-31 17:18:49 +02:00
|
|
|
: first pick results in no changes &&
|
rebase (interactive-backend): make --keep-empty the default
Different rebase backends have different treatment for commits which
start empty (i.e. have no changes relative to their parent), and the
--keep-empty option was added at some point to allow adjusting behavior.
The handling of commits which start empty is actually quite similar to
commit b00bf1c9a8dd (git-rebase: make --allow-empty-message the default,
2018-06-27), which pointed out that the behavior for various backends is
often more happenstance than design. The specific change made in that
commit is actually quite relevant as well and much of the logic there
directly applies here.
It makes a lot of sense in 'git commit' to error out on the creation of
empty commits, unless an override flag is provided. However, once
someone determines that there is a rare case that merits using the
manual override to create such a commit, it is somewhere between
annoying and harmful to have to take extra steps to keep such
intentional commits around. Granted, empty commits are quite rare,
which is why handling of them doesn't get considered much and folks tend
to defer to existing (accidental) behavior and assume there was a reason
for it, leading them to just add flags (--keep-empty in this case) that
allow them to override the bad defaults. Fix the interactive backend so
that --keep-empty is the default, much like we did with
--allow-empty-message. The am backend should also be fixed to have
--keep-empty semantics for commits that start empty, but that is not
included in this patch other than a testcase documenting the failure.
Note that there was one test in t3421 which appears to have been written
expecting --keep-empty to not be the default as correct behavior. This
test was introduced in commit 00b8be5a4d38 ("add tests for rebasing of
empty commits", 2013-06-06), which was part of a series focusing on
rebase topology and which had an interesting original cover letter at
https://lore.kernel.org/git/1347949878-12578-1-git-send-email-martinvonz@gmail.com/
which noted
Your input especially appreciated on whether you agree with the
intent of the test cases.
and then went into a long example about how one of the many tests added
had several questions about whether it was correct. As such, I believe
most the tests in that series were about testing rebase topology with as
many different flags as possible and were not trying to state in general
how those flags should behave otherwise.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-15 22:36:24 +01:00
|
|
|
git rebase --skip &&
|
2020-09-26 23:04:21 +02:00
|
|
|
verbose test "$(commit_message HEAD~2)" = "topic_4" &&
|
|
|
|
verbose test "$(commit_message HEAD~)" = "files_subtree/topic_5" &&
|
2019-07-31 17:18:49 +02:00
|
|
|
verbose test "$(commit_message HEAD)" = "Empty commit"
|
|
|
|
'
|
|
|
|
|
2016-06-28 12:54:02 +02:00
|
|
|
test_done
|