diff options
author | Junio C Hamano <gitster@pobox.com> | 2013-06-27 12:40:24 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2013-07-19 15:20:21 -0700 |
commit | 949e0d8e380639091043ab19be4f15d7e670c832 (patch) | |
tree | 3095884bb5bb91390facbc0759e9ec760aefa475 | |
parent | 85318f521f6c0b9843d6da12abf67f2de7608431 (diff) | |
download | git-jc/pull-training-wheel.tar.gz |
pull: require choice between rebase/merge on non-fast-forward pulljc/pull-training-wheel
Because it is so easy to let Git handle automatically a trivial
merge with "git pull", a person who is new to Git may not realize
that the project s/he is interacting with may prefer a "rebase"
workflow.
Add a safety valve to fail "git pull" that does not explicitly
specify what branch from which repository to integrate your history
with, when it is neither a fast-forward or "already up-to-date",
until/unless the user expressed her preference between the two ways
of integration.
This can be an irritating backward incompatible change for old
timers, but it can be a one time irritation by doing:
git config --global pull.rebase false
once to say "I will always --merge", and they'd not even notice.
http://thread.gmane.org/gmane.comp.version-control.git/225146/focus=225326
for a full discussion.
Helped-by: John Keeping <john@keeping.me.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | Documentation/git-pull.txt | 9 | ||||
-rwxr-xr-x | git-pull.sh | 40 | ||||
-rwxr-xr-x | t/t5520-pull.sh | 51 | ||||
-rwxr-xr-x | t/t5524-pull-msg.sh | 2 |
4 files changed, 100 insertions, 2 deletions
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index 24ab07a3f8..8b3acf5b11 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -97,6 +97,14 @@ must be given before the options meant for 'git fetch'. Options related to merging ~~~~~~~~~~~~~~~~~~~~~~~~~~ +With no repository or branch on the command line, `git pull` needs +to be told how to integrate the changes with your history. + +This can be done via either `--merge` or `--rebase` option, but most +people would want to decide which method matches the workflow of the +project once, and set the configuration variable `pull.rebase` or +`branch.<name>.rebase` to stick to it; see linkgit:git-config[1]. + include::merge-options.txt[] :git-pull: 1 @@ -119,6 +127,7 @@ It rewrites history, which does not bode well when you published that history already. Do *not* use this option unless you have read linkgit:git-rebase[1] carefully. +--merge:: --no-rebase:: Override earlier --rebase. diff --git a/git-pull.sh b/git-pull.sh index 638aabb7b3..88c198fa66 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -41,13 +41,21 @@ test -f "$GIT_DIR/MERGE_HEAD" && die_merge strategy_args= diffstat= no_commit= squash= no_ff= ff_only= log_arg= verbosity= progress= recurse_submodules= verify_signatures= merge_args= edit= + curr_branch=$(git symbolic-ref -q HEAD) curr_branch_short="${curr_branch#refs/heads/}" + +# See if we are configured to rebase by default. +# The value $rebase is, throughout the main part of the code: +# (empty) - the user did not have any preference +# true - the user told us to integrate by rebasing +# false - the user told us to integrate by merging rebase=$(git config --bool branch.$curr_branch_short.rebase) if test -z "$rebase" then rebase=$(git config --bool pull.rebase) fi + dry_run= while : do @@ -113,7 +121,8 @@ do -r|--r|--re|--reb|--reba|--rebas|--rebase) rebase=true ;; - --no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase) + --no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase|\ + -m|--m|--me|--mer|--merg|--merge) rebase=false ;; --recurse-submodules) @@ -219,6 +228,7 @@ test true = "$rebase" && { fi done } + orig_head=$(git rev-parse -q --verify HEAD) git fetch $verbosity $progress $dry_run $recurse_submodules --update-head-ok "$@" || exit 1 test -z "$dry_run" || exit 0 @@ -264,6 +274,34 @@ case "$merge_head" in die "$(gettext "Cannot rebase onto multiple branches")" fi ;; +*) + # integrating with a single other history; be careful not to + # trigger this check when we will say "fast-forward" or "already + # up-to-date". + merge_head=${merge_head% } + if test -z "$rebase$no_ff$ff_only${squash#--no-squash}" && + test -n "$orig_head" && + test $# = 0 && + ! git merge-base --is-ancestor "$orig_head" "$merge_head" && + ! git merge-base --is-ancestor "$merge_head" "$orig_head" + then +echo >&2 "orig-head was $orig_head" +echo >&2 "merge-head is $merge_head" +git show >&2 --oneline -s "$orig_head" "$merge_head" + + die "The pull does not fast-forward; please specify +if you want to merge or rebase. + +Use either + + git pull --rebase + git pull --merge + +You can also use 'git config pull.rebase true' (if you want --rebase) or +'git config pull.rebase false' (if you want --merge) to set this once for +this project and forget about it." + fi + ;; esac if test -z "$orig_head" diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 6af6c63350..1e91ecae7e 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -255,4 +255,55 @@ test_expect_success 'git pull --rebase against local branch' ' test file = "$(cat file2)" ' +test_expect_success 'git pull that does not say how to integrate' ' + git checkout -b other master^1 && + >new && + git add new && + git commit -m "add new file" && + + git checkout -b test-to-integrate master && + + test_config branch.test-to-integrate.remote . && + test_config branch.test-to-integrate.merge other && + + # need real integration + test_must_fail git pull && + git reset --hard master && + + + # configuration is explicit enough + for how in false true + do + test_config pull.rebase $how && + git pull && + git reset --hard master || break + done && + + # per branch configuration is explicit enough + test_unconfig pull.rebase && + for how in false true + do + test_config branch.test-to-integrate.rebase $how && + git pull && + git reset --hard master || break + done && + + test_unconfig pull.rebase && + test_unconfig branch.test-to-integrate && + + # already up to date + git reset --hard master && + git branch -f other master^1 + git pull && + + # fast forward + git reset --hard master && + git checkout -B other master && + >new && + git add new && + git commit -m "add new file" && + git checkout -B test-to-integrate master && + git pull +' + test_done diff --git a/t/t5524-pull-msg.sh b/t/t5524-pull-msg.sh index 8cccecc2fc..660714b1ad 100755 --- a/t/t5524-pull-msg.sh +++ b/t/t5524-pull-msg.sh @@ -25,7 +25,7 @@ test_expect_success setup ' test_expect_success pull ' ( cd cloned && - git pull --log && + git pull --log --merge && git log -2 && git cat-file commit HEAD >result && grep Dollar result |