This new configuration variable executes 'git stash' before attempting to merge/rebase, and 'git stash pop' after a successful merge/rebase. It makes it convenient for people to pull with dirty worktrees. Signed-off-by: Ramkumar Ramachandra <artagnon@xxxxxxxxx> --- Documentation/config.txt | 5 ++++ Documentation/git-pull.txt | 7 ++++++ git-pull.sh | 26 ++++++++++++++++++-- t/t5521-pull-options.sh | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index c1f435f..0becafe 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1786,6 +1786,11 @@ pull.rebase:: of merging the default branch from the default remote when "git pull" is run. See "branch.<name>.rebase" for setting this on a per-branch basis. + +pull.autostash:: + When true, automatically stash all changes before attempting to + merge/rebase, and pop the stash after a successful + merge/rebase. + *NOTE*: this is a possibly dangerous operation; do *not* use it unless you understand the implications (see linkgit:git-rebase[1] diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index c975743..bb57c86 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -94,6 +94,13 @@ must be given before the options meant for 'git fetch'. has to be called afterwards to bring the work tree up to date with the merge result. +--[no-]autostash:: + When turned on, automatically stash all changes before + attempting to merge/rebase, and pop the stash after a + successful merge/rebase. Useful for people who want to pull + with a dirty worktree. This option can also be set via the + `pull.autostash` configuration variable. + Options related to merging ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/git-pull.sh b/git-pull.sh index 37e1cd4..ad8e494 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -48,6 +48,7 @@ if test -z "$rebase" then rebase=$(git config --bool pull.rebase) fi +autostash=$(git config --bool pull.autostash) dry_run= while : do @@ -116,6 +117,12 @@ do --no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase) rebase=false ;; + --autostash) + autostash=true + ;; + --no-autostash) + autostash=false + ;; --recurse-submodules) recurse_submodules=--recurse-submodules ;; @@ -196,7 +203,8 @@ test true = "$rebase" && { then die "$(gettext "updating an unborn branch with changes added to the index")" fi - else + elif test "$autostash" = false + then require_clean_work_tree "pull with rebase" "Please commit or stash them." fi oldremoteref= && @@ -213,6 +221,12 @@ test true = "$rebase" && { fi done } + +stash_required () { + ! (git diff-files --quiet --ignore-submodules && + git diff-index --quiet --cached HEAD --ignore-submodules) +} + 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 @@ -288,4 +302,12 @@ true) eval="$eval \"\$merge_name\" HEAD $merge_head" ;; esac -eval "exec $eval" + +if test "$autostash" = true && stash_required +then + git stash + eval "$eval" + test $? = 0 && git stash pop +else + eval "exec $eval" +fi diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh index 4a804f0..cecacbc 100755 --- a/t/t5521-pull-options.sh +++ b/t/t5521-pull-options.sh @@ -90,4 +90,63 @@ test_expect_success 'git pull --all' ' ) ' +test_expect_success 'pull --autostash with clean worktree' ' + mkdir clonedautostash && + (cd clonedautostash && + git init && + git pull --autostash ../parent && + test_must_fail test_path_is_file .git/refs/stash + test_commit one + ) && + rm -rf clonedautostash +' + +test_expect_success 'pull.autostash with clean worktree' ' + mkdir clonedautostash && + (cd clonedautostash && + git init && + test_config pull.autostash true && + git pull ../parent && + test_must_fail test_path_is_file .git/refs/stash + test_commit one + ) && + rm -rf clonedautostash +' + +test_expect_success 'pull.autostash without conflict' ' + mkdir clonedautostash && + (cd clonedautostash && + git init && + test_commit "root_commit" && + cat >quux <<-\EOF && + this is a non-conflicting file + EOF + git add quux && + test_config pull.autostash true && + git pull ../parent && + test_must_fail test_path_is_file .git/refs/stash && + test_path_is_file quux && + test_commit one + ) && + rm -rf clonedautostash +' + +test_expect_success 'pull.autostash with conflict' ' + mkdir clonedautostash && + (cd clonedautostash && + git init && + test_commit "will_conflict" file "this is a conflicting file" && + cat >quux <<-\EOF && + this is a non-conflicting file + EOF + git add quux && + test_config pull.autostash true && + test_must_fail git pull ../parent && + test_must_fail test_commit one && + test_path_is_file .git/refs/stash && + test_must_fail test_path_is_file quux + ) && + rm -rf clonedautostash +' + test_done -- 1.8.2.141.gad203c2.dirty -- 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