# If they are introducing non-merge commits /and/ merge commits, it could
# look like one of two ways. This way:
#
-# * --- B --- * --- oldrev
-# \ \
-# new --- new --- newrev
+# A -- B <-- origin/topic
+# \ \
+# c -- d <-- topic
#
# They basically had an un-shared local dev branch (probably by making a
# merge) and instead should have done a rebase. Also, if they did:
#
-# * --- B --- * --- oldrev
-# \ \
-# new --- new --- new -- newrev
+# A -- B <-- origin/topic
+# \ \
+# c -- d -- e <-- topic
#
# We should try and catch them--where the merge happened previously to
# them doing more work in the newrev commit.
#
# But if it looks like:
#
-# * --- B --- * --- oldrev
-# \ \
-# old --- new --- newrev
+# A -- B <-- origin/foo
+# \ \
+# C \ <-- origin/topic
+# \ \
+# d -- e <-- topic
#
# Then they had a pre-shared branch that cannot be rebased and so they
# were correct in doing a merge to tie "old" and "oldrev" together.
#
# Also, we obviously have to be okay with:
#
-# * --- * --- * --- oldrev --- new --- new --- newrev
+# A -- B <-- origin/topic
+# \
+# c -- d <-- topic
refname="$1"
oldrev="$2"
git merge-base --all $parents | while read baserev ; do
# For each parent
git rev-list -n 1 --parents $commit | sed 's/ /\n/g' | grep -v $commit | while read parent ; do
- parent_is_old=$(git branch --contains $parent | wc -l)
all_commits=$(git rev-list --first-parent $baserev..$parent | wc -l)
new_commits=$(git rev-parse --not --branches | git rev-list --stdin $baserev..$parent | wc -l)
- if [ $parent_is_old -gt 0 -a $all_commits -eq $new_commits ] ; then
+ if [ $all_commits -eq $new_commits ] ; then
# echo "parent=$parent"
# echo "all_commits=$all_commits"
# echo "new_commits=$new_commits"
install_update_hook 'update-prefer-rebase'
-test_expect_success 'all local changes do not need a merge' '
- # server is on "setup"
-
+test_expect_success 'merge local changes is caught' '
# make an outstanding change for us--but do not push
echo "$test_name" >a.client1 &&
git add a.client1 &&
git reset --hard origin/master
'
-test_expect_success 'all local changes do not need a merge even with more commits after' '
- # server is on "setup"
-
+test_expect_success 'merge local changes followed by more commits is caught' '
# make an outstanding change for us--but do not push
echo "$test_name" >a.client1 &&
git add a.client1 &&
git reset --hard origin/master
'
-test_expect_success 'already shared topic changes do warrant a merge' '
- # server is on "setup"
-
+test_expect_success 'merge shared changes from another topic is okay' '
# make a change on topic for us and share it
git checkout -b topic master &&
echo "$test_name" >a.client1 &&
git commit -m "$test_name on client1 and topic" &&
git push origin topic &&
- # make an outstanding change that we will have to merge later
+ # make an outstanding on topic that is not pushed
echo "$test_name again" >>a.client1 &&
git commit -a -m "$test_name on client1 and topic again" &&
# go back to our client and it will merge in our changes
cd .. &&
git checkout master &&
+ # this should fast fwd
git pull &&
+ # this pulls in the shared branch+its new tip
git merge topic &&
git push
git push origin stable
'
-install_server_hook 'update-prefer-rebase' 'update'
+install_update_hook 'update-prefer-rebase'
+#
+# A -- B <-- origin/stable
+# \ |
+# C -- D <-- origin/topic1
+# \ | \
+# e - f <-- topic1
+#
+# Nope: should rebase e ontop of D
+#
test_expect_success 'merging in stable does not fool the script' '
# start our branch, and share it
git checkout -b topic1 stable &&
git commit -m "topic1 changed by client2" &&
cd .. &&
- # now locally try and merge in stable (even though we are out of date)
+ # now locally try and merge in stable (even though topic1 is out of date)
git checkout topic1 &&
git merge stable &&
# Make a new merge commit
git pull &&
! git push 2>push.err &&
- cat push.err | grep "It looks like you should rebase instead of merging"
+ cat push.err | grep "It looks like you should rebase instead of merging" &&
+
+ # Now fix it
+ git reset --hard ORIG_HEAD &&
+ GIT_EDITOR=: git rebase -i -p origin/topic1 &&
+ git push &&
+ git branch -r --contains stable | grep origin/topic
'
#
-# A --C------ stable
+# A --C------ <-- origin/stable
# \ | \
-# B -- D -- E -- F topic2
+# B -- D -- E -- F <-- origin/topic2
# \| \
-# G -- H ------- I attempted push
+# g -- h ------- i <-- topic2
#
-# Trying to push F..I
+# Trying to push F..i
#
-# merge-base(F, H) has two options: B and C
+# merge-base(F, h) has two options: B and C
#
test_expect_success 'merging in stable with tricky double baserev does not fool the script' '
- # start our branch, and share it--commit B
+ # B: start our branch, and share it
git checkout -b topic2 stable &&
git config --add branch.topic2.remote origin &&
git config --add branch.topic2.merge refs/heads/topic2 &&
git commit -m "commit B created topic2" &&
git push origin topic2 &&
- # now, separately, move ahead stable, and share it--commit C
+ # C: now, separately, move ahead stable, and share it
git checkout stable
echo "commit C" >a &&
git commit -a -m "commit C moved stable" &&
git push origin stable &&
- # have another client commit (in this case, it is the server, but close enough) moves topic2
+ # D: have another client commit (in this case, it is the server, but close enough) moves topic2
cd server &&
git checkout topic2 &&
+ # We might have cruft from the previous test
+ git reset --hard &&
echo "commit D continuing topic2" >a.client2 &&
git add a.client2 &&
git commit -m "commit D by client2" &&
- # Go ahead and merge in stable by the other client--commit E
+ # E: another client merges stable
git merge stable &&
- # Then move topic2 put to--commit F
+ # F: another client moves topic2 again
echo "commit F" >a.client2 &&
git commit -a -m "commit F by client2" &&
cd .. &&
- # now locally try and merge in stable (even though we are out of date)--commit G
+ # g: now locally try and merge in stable (even though topic2 is out of date)
git checkout topic2 &&
git merge stable &&
- # Go ahead and move our local topic2
+ # h: advance local topic2
echo "commit H" >a.topic2 &&
git commit -a -m "commit H continues local fork" &&
- # Make a new merge commit
+ # i: make a new merge commit
git pull &&
- ! git push origin topic2
+ ! git push origin topic2 2>push.err &&
cat push.err | grep "It looks like you should rebase instead of merging"
+
+ # Now fix it
+ # git reset --hard ORIG_HEAD &&
+ # GIT_EDITOR=: git rebase -i -p origin/topic2 &&
+ # git push &&
+ # git branch -r --contains stable | grep origin/topic2
'
test_done
--- /dev/null
+#!/bin/sh
+
+test_description='server update prefer rebase'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ echo "setup" >a &&
+ git add a &&
+ git commit -m "setup" &&
+ git clone ./. server &&
+ rm -fr server/.git/hooks &&
+ git remote add origin ./server &&
+ git config --add branch.master.remote origin &&
+ git config --add branch.master.merge refs/heads/master &&
+ git fetch
+'
+
+install_update_hook 'update-prefer-rebase'
+
+test_expect_success 'one new, one old parent is okay' '
+ # server is on "setup"
+
+ # make an outstanding change for us--but do not push
+ echo "$test_name" >a.client1 &&
+ git add a.client1 &&
+ git commit -m "$test_name on client1" &&
+
+ # have another client commit (in this case, it is the server, but close enough)
+ cd server &&
+ echo "$test_name" >a.client2 &&
+ git add a.client2 &&
+ git commit -m "$test_name on client2" &&
+ cd .. &&
+
+ # go back to our client and it will merge in our changes
+ git pull &&
+ merge=$(git rev-parse HEAD) &&
+
+ ! git push 2>push.err &&
+ cat push.err | grep "It looks like you should rebase instead of merging $merge" &&
+ git reset --hard origin/master
+'
+
+test_done
+
+test_expect_success 'all local changes do not need a merge even with more commits after' '
+ # server is on "setup"
+
+ # make an outstanding change for us--but do not push
+ echo "$test_name" >a.client1 &&
+ git add a.client1 &&
+ git commit -m "$test_name on client1" &&
+
+ # have another client commit (in this case, it is the server, but close enough)
+ cd server &&
+ echo "$test_name" >a.client2 &&
+ git add a.client2 &&
+ git commit -m "$test_name on client2" &&
+
+ # go back to our client and it will merge in our changes
+ cd .. &&
+ git pull &&
+ merge=$(git rev-parse HEAD) &&
+
+ # To complicate things, have them add another change
+ echo "$test_name again" >a.client1 &&
+ git commit -a -m "$test_name on client1 again" &&
+
+ ! git push 2>push.err &&
+ cat push.err | grep "It looks like you should rebase instead of merging $merge" &&
+ git reset --hard origin/master
+'
+
+test_expect_success 'already shared topic changes do warrant a merge' '
+ # server is on "setup"
+
+ # make a change on topic for us and share it
+ git checkout -b topic master &&
+ echo "$test_name" >a.client1 &&
+ git add a.client1 &&
+ git commit -m "$test_name on client1 and topic" &&
+ git push origin topic &&
+
+ # make an outstanding change that we will have to merge later
+ echo "$test_name again" >>a.client1 &&
+ git commit -a -m "$test_name on client1 and topic again" &&
+
+ # have another client commit to master (in this case, it is the server, but close enough)
+ cd server &&
+ echo "$test_name" >a.client2 &&
+ git add a.client2 &&
+ git commit -m "$test_name on client2" &&
+
+ # go back to our client and it will merge in our changes
+ cd .. &&
+ git checkout master &&
+ git pull &&
+ git merge topic &&
+
+ git push
+'
+
+test_expect_success 'simple commit' '
+ # go back to topic and make a simple commit/push as a sanity check
+ git checkout topic &&
+ echo "$test_name" >>a.client1 &&
+ git commit -a -m "$test_name on client1 and topic" &&
+ git push
+'
+
+test_done
+