Merge branch 'sh/pull-rebase-preserve'
"git pull --rebase" always flattened the history; pull.rebase can now be set to "preserve" to invoke "rebase --preserve-merges". * sh/pull-rebase-preserve: pull: allow pull to preserve merges when rebasing
This commit is contained in:
@ -765,6 +765,10 @@ branch.<name>.rebase::
|
|||||||
instead of merging the default branch from the default remote when
|
instead of merging the default branch from the default remote when
|
||||||
"git pull" is run. See "pull.rebase" for doing this in a non
|
"git pull" is run. See "pull.rebase" for doing this in a non
|
||||||
branch-specific manner.
|
branch-specific manner.
|
||||||
|
+
|
||||||
|
When preserve, also pass `--preserve-merges` along to 'git rebase'
|
||||||
|
so that locally committed merge commits will not be flattened
|
||||||
|
by running 'git pull'.
|
||||||
+
|
+
|
||||||
*NOTE*: this is a possibly dangerous operation; do *not* use
|
*NOTE*: this is a possibly dangerous operation; do *not* use
|
||||||
it unless you understand the implications (see linkgit:git-rebase[1]
|
it unless you understand the implications (see linkgit:git-rebase[1]
|
||||||
@ -1878,6 +1882,10 @@ pull.rebase::
|
|||||||
of merging the default branch from the default remote when "git
|
of merging the default branch from the default remote when "git
|
||||||
pull" is run. See "branch.<name>.rebase" for setting this on a
|
pull" is run. See "branch.<name>.rebase" for setting this on a
|
||||||
per-branch basis.
|
per-branch basis.
|
||||||
|
+
|
||||||
|
When preserve, also pass `--preserve-merges` along to 'git rebase'
|
||||||
|
so that locally committed merge commits will not be flattened
|
||||||
|
by running 'git pull'.
|
||||||
+
|
+
|
||||||
*NOTE*: this is a possibly dangerous operation; do *not* use
|
*NOTE*: this is a possibly dangerous operation; do *not* use
|
||||||
it unless you understand the implications (see linkgit:git-rebase[1]
|
it unless you understand the implications (see linkgit:git-rebase[1]
|
||||||
|
@ -102,12 +102,18 @@ include::merge-options.txt[]
|
|||||||
:git-pull: 1
|
:git-pull: 1
|
||||||
|
|
||||||
-r::
|
-r::
|
||||||
--rebase::
|
--rebase[=false|true|preserve]::
|
||||||
Rebase the current branch on top of the upstream branch after
|
When true, rebase the current branch on top of the upstream
|
||||||
fetching. If there is a remote-tracking branch corresponding to
|
branch after fetching. If there is a remote-tracking branch
|
||||||
the upstream branch and the upstream branch was rebased since last
|
corresponding to the upstream branch and the upstream branch
|
||||||
fetched, the rebase uses that information to avoid rebasing
|
was rebased since last fetched, the rebase uses that information
|
||||||
non-local changes.
|
to avoid rebasing non-local changes.
|
||||||
|
+
|
||||||
|
When preserve, also rebase the current branch on top of the upstream
|
||||||
|
branch, but pass `--preserve-merges` along to `git rebase` so that
|
||||||
|
locally created merge commits will not be flattened.
|
||||||
|
+
|
||||||
|
When false, merge the current branch into the upstream branch.
|
||||||
+
|
+
|
||||||
See `pull.rebase`, `branch.<name>.rebase` and `branch.autosetuprebase` in
|
See `pull.rebase`, `branch.<name>.rebase` and `branch.autosetuprebase` in
|
||||||
linkgit:git-config[1] if you want to make `git pull` always use
|
linkgit:git-config[1] if you want to make `git pull` always use
|
||||||
|
31
git-pull.sh
31
git-pull.sh
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# Fetch one or more remote refs and merge it/them into the current HEAD.
|
# Fetch one or more remote refs and merge it/them into the current HEAD.
|
||||||
|
|
||||||
USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s strategy]... [<fetch-options>] <repo> <head>...'
|
USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [--[no-]rebase|--rebase=preserve] [-s strategy]... [<fetch-options>] <repo> <head>...'
|
||||||
LONG_USAGE='Fetch one or more remote refs and integrate it/them with the current HEAD.'
|
LONG_USAGE='Fetch one or more remote refs and integrate it/them with the current HEAD.'
|
||||||
SUBDIRECTORY_OK=Yes
|
SUBDIRECTORY_OK=Yes
|
||||||
OPTIONS_SPEC=
|
OPTIONS_SPEC=
|
||||||
@ -38,15 +38,19 @@ Please, commit your changes before you can merge.")"
|
|||||||
test -z "$(git ls-files -u)" || die_conflict
|
test -z "$(git ls-files -u)" || die_conflict
|
||||||
test -f "$GIT_DIR/MERGE_HEAD" && die_merge
|
test -f "$GIT_DIR/MERGE_HEAD" && die_merge
|
||||||
|
|
||||||
|
bool_or_string_config () {
|
||||||
|
git config --bool "$1" 2>/dev/null || git config "$1"
|
||||||
|
}
|
||||||
|
|
||||||
strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
|
strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
|
||||||
log_arg= verbosity= progress= recurse_submodules= verify_signatures=
|
log_arg= verbosity= progress= recurse_submodules= verify_signatures=
|
||||||
merge_args= edit=
|
merge_args= edit= rebase_args=
|
||||||
curr_branch=$(git symbolic-ref -q HEAD)
|
curr_branch=$(git symbolic-ref -q HEAD)
|
||||||
curr_branch_short="${curr_branch#refs/heads/}"
|
curr_branch_short="${curr_branch#refs/heads/}"
|
||||||
rebase=$(git config --bool branch.$curr_branch_short.rebase)
|
rebase=$(bool_or_string_config branch.$curr_branch_short.rebase)
|
||||||
if test -z "$rebase"
|
if test -z "$rebase"
|
||||||
then
|
then
|
||||||
rebase=$(git config --bool pull.rebase)
|
rebase=$(bool_or_string_config pull.rebase)
|
||||||
fi
|
fi
|
||||||
dry_run=
|
dry_run=
|
||||||
while :
|
while :
|
||||||
@ -110,6 +114,9 @@ do
|
|||||||
esac
|
esac
|
||||||
merge_args="$merge_args$xx "
|
merge_args="$merge_args$xx "
|
||||||
;;
|
;;
|
||||||
|
-r=*|--r=*|--re=*|--reb=*|--reba=*|--rebas=*|--rebase=*)
|
||||||
|
rebase="${1#*=}"
|
||||||
|
;;
|
||||||
-r|--r|--re|--reb|--reba|--rebas|--rebase)
|
-r|--r|--re|--reb|--reba|--rebas|--rebase)
|
||||||
rebase=true
|
rebase=true
|
||||||
;;
|
;;
|
||||||
@ -145,6 +152,20 @@ do
|
|||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
|
case "$rebase" in
|
||||||
|
preserve)
|
||||||
|
rebase=true
|
||||||
|
rebase_args=--preserve-merges
|
||||||
|
;;
|
||||||
|
true|false|'')
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Invalid value for --rebase, should be true, false, or preserve"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
error_on_no_merge_candidates () {
|
error_on_no_merge_candidates () {
|
||||||
exec >&2
|
exec >&2
|
||||||
for opt
|
for opt
|
||||||
@ -292,7 +313,7 @@ fi
|
|||||||
merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
|
merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
|
||||||
case "$rebase" in
|
case "$rebase" in
|
||||||
true)
|
true)
|
||||||
eval="git-rebase $diffstat $strategy_args $merge_args $verbosity"
|
eval="git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity"
|
||||||
eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
|
eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
@ -148,6 +148,95 @@ test_expect_success 'branch.to-rebase.rebase should override pull.rebase' '
|
|||||||
test new = $(git show HEAD:file2)
|
test new = $(git show HEAD:file2)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
# add a feature branch, keep-merge, that is merged into master, so the
|
||||||
|
# test can try preserving the merge commit (or not) with various
|
||||||
|
# --rebase flags/pull.rebase settings.
|
||||||
|
test_expect_success 'preserve merge setup' '
|
||||||
|
git reset --hard before-rebase &&
|
||||||
|
git checkout -b keep-merge second^ &&
|
||||||
|
test_commit file3 &&
|
||||||
|
git checkout to-rebase &&
|
||||||
|
git merge keep-merge &&
|
||||||
|
git tag before-preserve-rebase
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pull.rebase=false create a new merge commit' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
test_config pull.rebase false &&
|
||||||
|
git pull . copy &&
|
||||||
|
test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) &&
|
||||||
|
test $(git rev-parse HEAD^2) = $(git rev-parse copy) &&
|
||||||
|
test file3 = $(git show HEAD:file3.t)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pull.rebase=true flattens keep-merge' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
test_config pull.rebase true &&
|
||||||
|
git pull . copy &&
|
||||||
|
test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
|
||||||
|
test file3 = $(git show HEAD:file3.t)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pull.rebase=1 is treated as true and flattens keep-merge' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
test_config pull.rebase 1 &&
|
||||||
|
git pull . copy &&
|
||||||
|
test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
|
||||||
|
test file3 = $(git show HEAD:file3.t)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pull.rebase=preserve rebases and merges keep-merge' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
test_config pull.rebase preserve &&
|
||||||
|
git pull . copy &&
|
||||||
|
test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
|
||||||
|
test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pull.rebase=invalid fails' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
test_config pull.rebase invalid &&
|
||||||
|
! git pull . copy
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--rebase=false create a new merge commit' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
test_config pull.rebase true &&
|
||||||
|
git pull --rebase=false . copy &&
|
||||||
|
test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) &&
|
||||||
|
test $(git rev-parse HEAD^2) = $(git rev-parse copy) &&
|
||||||
|
test file3 = $(git show HEAD:file3.t)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--rebase=true rebases and flattens keep-merge' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
test_config pull.rebase preserve &&
|
||||||
|
git pull --rebase=true . copy &&
|
||||||
|
test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
|
||||||
|
test file3 = $(git show HEAD:file3.t)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--rebase=preserve rebases and merges keep-merge' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
test_config pull.rebase true &&
|
||||||
|
git pull --rebase=preserve . copy &&
|
||||||
|
test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
|
||||||
|
test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--rebase=invalid fails' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
! git pull --rebase=invalid . copy
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-merge' '
|
||||||
|
git reset --hard before-preserve-rebase &&
|
||||||
|
test_config pull.rebase preserve &&
|
||||||
|
git pull --rebase . copy &&
|
||||||
|
test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
|
||||||
|
test file3 = $(git show HEAD:file3.t)
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success '--rebase with rebased upstream' '
|
test_expect_success '--rebase with rebased upstream' '
|
||||||
|
|
||||||
git remote add -f me . &&
|
git remote add -f me . &&
|
||||||
|
Reference in New Issue
Block a user