Odd rebase behavior
- From
David A. Greene <greened@obbligato.org>
- Date
- Dec 16, 2015, 03:17 UTC
- Message-ID
- <877fkf9j5h.fsf@waller.obbligato.org>
Hi,
The attached tests do not do what I expected them to do. I commented out the tests involving the new rebase empty commit behavior I just sent. The uncommented tests show the strange behavior.
According to the rebase man page, rebase gathers commits as in "git log <upstream>..HEAD." However, that is not what happens in the tests below. Some of the commits disappear.
The test basically does this:
- Setup a master project and a subproject, merged via a subtree-like merge (this is how git-subtree does it).
- Add some commits to the subproject directory after the subtree merge, to create some history not in the original subproject.
- filter-branch --subdirectory-filter to extract commits from the subproject directory.
- Rebase those commits back on to the original subproject repository.
The above loses all commits made after the subproject is merged into the main project.
Note that the rebase is a little wonky. filter-branch creates a disconnected graph and the rebase is invoked with <upstream>=master. I'm not sure how rebase is supposed to operate in this case (if it is supported at all) but it definitely is not doing the master..HEAD thing.
Replacing "master" with "--root" causes rebase to do the right thing.
This seems like a bug to me, even with the strange <upstream> on a disconnected graph. At the very least git should not silently lose commits.
I can think of two ways this could be resolved:
- Forbid this kind of operation and error our with a message (when <upstream> and HEAD do not share ancestry)
- Make it work as if --root were specified
Thoughts?
-David
--->8---
#!/bin/sh
test_description='git rebase tests for empty commits
This test runs git rebase and tests handling of empty commits. ' . ./test-lib.sh
addfile() {
name=$1
echo $(basename ${name}) > ${name}
${git} add ${name}
${git} commit -m "Add $(basename ${name})"
}check_equal()
{
test_debug 'echo'
test_debug "echo \"check a:\" \"{$1}\""
test_debug "echo \" b:\" \"{$2}\""
if [ "$1" = "$2" ]; then
return 0
else
return 1
fi
}last_commit_message()
{
git log --pretty=format:%s -1
}test_expect_success 'setup' '
test_commit README &&
mkdir files &&
cd files &&
git init &&
test_commit master1 &&
test_commit master2 &&
test_commit master3 &&
cd .. &&
test_debug "echo Add project master to master" &&
git fetch files master &&
git branch files-master FETCH_HEAD &&
test_debug "echo Add subtree master to master via subtree" &&
git read-tree --prefix=files_subtree files-master &&
git checkout -- files_subtree &&
tree=$(git write-tree) &&
head=$(git rev-parse HEAD) &&
rev=$(git rev-parse --verify files-master^0) &&
commit=$(git commit-tree -p ${head} -p ${rev} -m "Add subproject master" ${tree}) &&
git reset ${commit} &&
cd files_subtree &&
test_commit master4 &&
cd .. &&
test_commit files_subtree/master5
'# Does not preserve master4 and master5. test_expect_success 'Rebase default' ' git checkout -b rebase-default master && git filter-branch --prune-empty -f --subdirectory-filter files_subtree && git commit -m "Empty commit" --allow-empty && git rebase -Xsubtree=files_subtree --preserve-merges --onto files-master master && check_equal "$(last_commit_message)" "files_subtree/master5" '
# Does not preserve master4, master5 and empty. test_expect_success 'Rebase --keep-empty' ' git checkout -b rebase-keep-empty master && git filter-branch --prune-empty -f --subdirectory-filter files_subtree && git commit -m "Empty commit" --allow-empty && git rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-master master && check_equal "$(last_commit_message)" "Empty commit" '
# Does not preserve master4 and master5. #test_expect_success 'Rebase --keep-redundant' ' # git checkout -b rebase-keep-redundant master && # git filter-branch --prune-empty -f --subdirectory-filter files_subtree && # git commit -m "Empty commit" --allow-empty && # git rebase -Xsubtree=files_subtree --keep-redundant --preserve-merges --onto files-master master && # check_equal "$(last_commit_message)" "files_subtree/master5" #'
# Does not preserve master4, master5 and empty. #test_expect_success 'Rebase --keep-empty --keep-redundant' ' # git checkout -b rebase-keep-empty-keep-redundant master && # git filter-branch --prune-empty -f --subdirectory-filter files_subtree && # git commit -m "Empty commit" --allow-empty && # git rebase -Xsubtree=files_subtree --keep-empty --keep-redundant --preserve-merges --onto files-master master && # check_equal "$(last_commit_message)" "Empty commit" #'
test_done