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@xxxxxxxxxxxxx> Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx> --- * This time with updates to the documentation and the test suite. Documentation/git-pull.txt | 9 ++++++++ git-pull.sh | 40 +++++++++++++++++++++++++++++++++++- t/t5520-pull.sh | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 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 24ab07a..86f5170 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~ +When `git pull` that does not explicitly specify what branch from +which repository is to be integrated with your history on the +command line, recent Git will refuse to work until you specify how +that integration should happen, either with a command line option +(`--merge` or `--rebase`) or a configuration variable (`pull.rebase` +or `branch.<name>.rebase`, which is the same as `--merge` +(`--rebase`) when set to `false` (`true`) respectively. + 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 638aabb..88c198f 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 6af6c63..1e91eca 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 8cccecc..660714b 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 -- 1.8.3.3-992-gf0e5e44 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html