Skip to content

Commit

Permalink
git-submodule: add support for --rebase.
Browse files Browse the repository at this point in the history
'git submodule update --rebase' rebases your local branch on top of what
would have been checked out to a detached HEAD otherwise.

In some cases, detaching the HEAD when updating a submodule complicates
the workflow to commit to this submodule (checkout master, rebase, then
commit).  For submodules that require frequent updates but infrequent
(if any) commits, a rebase can be executed directly by the git-submodule
command, ensuring that the submodules stay on their respective branches.

git-config key: submodule.$name.rebase (bool)

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Peter Hutterer authored and Junio C Hamano committed Apr 24, 2009
1 parent ea0b767 commit ca2cedb
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 6 deletions.
14 changes: 12 additions & 2 deletions Documentation/git-submodule.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ SYNOPSIS
'git submodule' [--quiet] add [-b branch] [--] <repository> <path>
'git submodule' [--quiet] status [--cached] [--] [<path>...]
'git submodule' [--quiet] init [--] [<path>...]
'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--] [<path>...]
'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--] [<path>...]
'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
'git submodule' [--quiet] foreach <command>
'git submodule' [--quiet] sync [--] [<path>...]
Expand Down Expand Up @@ -113,7 +113,8 @@ init::
update::
Update the registered submodules, i.e. clone missing submodules and
checkout the commit specified in the index of the containing repository.
This will make the submodules HEAD be detached.
This will make the submodules HEAD be detached unless '--rebase' is
specified or the key `submodule.$name.rebase` is set to `true`.
+
If the submodule is not yet initialized, and you just want to use the
setting as stored in .gitmodules, you can automatically initialize the
Expand Down Expand Up @@ -177,6 +178,15 @@ OPTIONS
This option is only valid for the update command.
Don't fetch new objects from the remote site.

--rebase::
This option is only valid for the update command.
Rebase the current branch onto the commit recorded in the
superproject. If this option is given, the submodule's HEAD will not
be detached. If a a merge failure prevents this process, you will have
to resolve these failures with linkgit:git-rebase[1].
If the key `submodule.$name.rebase` is set to `true`, this option is
implicit.

<path>...::
Paths to submodule(s). When specified this will restrict the command
to only operate on the submodules found at the specified paths.
Expand Down
3 changes: 3 additions & 0 deletions Documentation/gitmodules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ submodule.<name>.path::
submodule.<name>.url::
Defines an url from where the submodule repository can be cloned.

submodule.<name>.rebase::
Defines that the submodule should be rebased by default.


EXAMPLES
--------
Expand Down
33 changes: 29 additions & 4 deletions git-submodule.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ branch=
quiet=
cached=
nofetch=
rebase=

#
# print stuff on stdout unless -q was specified
Expand Down Expand Up @@ -294,6 +295,11 @@ cmd_init()
git config submodule."$name".url "$url" ||
die "Failed to register url for submodule path '$path'"

test true != "$(git config -f .gitmodules --bool \
submodule."$name".rebase)" ||
git config submodule."$name".rebase true ||
die "Failed to register submodule path '$path' as rebasing"

say "Submodule '$name' ($url) registered for path '$path'"
done
}
Expand Down Expand Up @@ -321,6 +327,10 @@ cmd_update()
shift
nofetch=1
;;
-r|--rebase)
shift
rebase=true
;;
--)
shift
break
Expand All @@ -339,6 +349,7 @@ cmd_update()
do
name=$(module_name "$path") || exit
url=$(git config submodule."$name".url)
rebase_module=$(git config --bool submodule."$name".rebase)
if test -z "$url"
then
# Only mention uninitialized submodules when its
Expand All @@ -359,6 +370,11 @@ cmd_update()
die "Unable to find current revision in submodule path '$path'"
fi

if test true = "$rebase"
then
rebase_module=true
fi

if test "$subsha1" != "$sha1"
then
force=
Expand All @@ -374,11 +390,20 @@ cmd_update()
die "Unable to fetch in submodule path '$path'"
fi

(unset GIT_DIR; cd "$path" &&
git-checkout $force -q "$sha1") ||
die "Unable to checkout '$sha1' in submodule path '$path'"
if test true = "$rebase_module"
then
command="git-rebase"
action="rebase"
msg="rebased onto"
else
command="git-checkout $force -q"
action="checkout"
msg="checked out"
fi

say "Submodule path '$path': checked out '$sha1'"
(unset GIT_DIR; cd "$path" && $command "$sha1") ||
die "Unable to $action '$sha1' in submodule path '$path'"
say "Submodule path '$path': $msg '$sha1'"
fi
done
}
Expand Down
140 changes: 140 additions & 0 deletions t/t7406-submodule-update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/bin/sh
#
# Copyright (c) 2009 Red Hat, Inc.
#

test_description='Test updating submodules
This test verifies that "git submodule update" detaches the HEAD of the
submodule and "git submodule update --rebase" does not detach the HEAD.
'

. ./test-lib.sh


compare_head()
{
sha_master=`git-rev-list --max-count=1 master`
sha_head=`git-rev-list --max-count=1 HEAD`

test "$sha_master" = "$sha_head"
}


test_expect_success 'setup a submodule tree' '
echo file > file &&
git add file &&
test_tick &&
git commit -m upstream
git clone . super &&
git clone super submodule &&
(cd super &&
git submodule add ../submodule submodule &&
test_tick &&
git commit -m "submodule" &&
git submodule init submodule
) &&
(cd submodule &&
echo "line2" > file &&
git add file &&
git commit -m "Commit 2"
) &&
(cd super &&
(cd submodule &&
git pull --rebase origin
) &&
git add submodule &&
git commit -m "submodule update"
)
'

test_expect_success 'submodule update detaching the HEAD ' '
(cd super/submodule &&
git reset --hard HEAD~1
) &&
(cd super &&
(cd submodule &&
compare_head
) &&
git submodule update submodule &&
cd submodule &&
! compare_head
)
'

test_expect_success 'submodule update --rebase staying on master' '
(cd super/submodule &&
git checkout master
) &&
(cd super &&
(cd submodule &&
compare_head
) &&
git submodule update --rebase submodule &&
cd submodule &&
compare_head
)
'

test_expect_success 'submodule update - rebase true in .git/config' '
(cd super &&
git config submodule.submodule.rebase true
) &&
(cd super/submodule &&
git reset --hard HEAD~1
) &&
(cd super &&
(cd submodule &&
compare_head
) &&
git submodule update submodule &&
cd submodule &&
compare_head
)
'

test_expect_success 'submodule update - rebase false in .git/config but --rebase given' '
(cd super &&
git config submodule.submodule.rebase false
) &&
(cd super/submodule &&
git reset --hard HEAD~1
) &&
(cd super &&
(cd submodule &&
compare_head
) &&
git submodule update --rebase submodule &&
cd submodule &&
compare_head
)
'

test_expect_success 'submodule update - rebase false in .git/config' '
(cd super &&
git config submodule.submodule.rebase false
) &&
(cd super/submodule &&
git reset --hard HEAD^
) &&
(cd super &&
(cd submodule &&
compare_head
) &&
git submodule update submodule &&
cd submodule &&
! compare_head
)
'

test_expect_success 'submodule init picks up rebase' '
(cd super &&
git config submodule.rebasing.url git://non-existing/git &&
git config submodule.rebasing.path does-not-matter &&
git config submodule.rebasing.rebase true &&
git submodule init rebasing &&
test true = $(git config --bool submodule.rebasing.rebase)
)
'

test_done

0 comments on commit ca2cedb

Please sign in to comment.