contrib / examples / git-pull.shon commit log-tree: respect diffopt's configured output file stream (4d7b0ef)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005 Junio C Hamano
   4#
   5# Fetch one or more remote refs and merge it/them into the current HEAD.
   6
   7SUBDIRECTORY_OK=Yes
   8OPTIONS_KEEPDASHDASH=
   9OPTIONS_STUCKLONG=Yes
  10OPTIONS_SPEC="\
  11git pull [options] [<repository> [<refspec>...]]
  12
  13Fetch one or more remote refs and integrate it/them with the current HEAD.
  14--
  15v,verbose                  be more verbose
  16q,quiet                    be more quiet
  17progress                   force progress reporting
  18
  19  Options related to merging
  20r,rebase?false|true|preserve incorporate changes by rebasing rather than merging
  21n!                         do not show a diffstat at the end of the merge
  22stat                       show a diffstat at the end of the merge
  23summary                    (synonym to --stat)
  24log?n                      add (at most <n>) entries from shortlog to merge commit message
  25squash                     create a single commit instead of doing a merge
  26commit                     perform a commit if the merge succeeds (default)
  27e,edit                       edit message before committing
  28ff                         allow fast-forward
  29ff-only!                   abort if fast-forward is not possible
  30verify-signatures          verify that the named commit has a valid GPG signature
  31s,strategy=strategy        merge strategy to use
  32X,strategy-option=option   option for selected merge strategy
  33S,gpg-sign?key-id          GPG sign commit
  34
  35  Options related to fetching
  36all                        fetch from all remotes
  37a,append                   append to .git/FETCH_HEAD instead of overwriting
  38upload-pack=path           path to upload pack on remote end
  39f,force                    force overwrite of local branch
  40t,tags                     fetch all tags and associated objects
  41p,prune                    prune remote-tracking branches no longer on remote
  42recurse-submodules?on-demand control recursive fetching of submodules
  43dry-run                    dry run
  44k,keep                     keep downloaded pack
  45depth=depth                deepen history of shallow clone
  46unshallow                  convert to a complete repository
  47update-shallow             accept refs that update .git/shallow
  48refmap=refmap              specify fetch refmap
  49"
  50test $# -gt 0 && args="$*"
  51. git-sh-setup
  52. git-sh-i18n
  53set_reflog_action "pull${args+ $args}"
  54require_work_tree_exists
  55cd_to_toplevel
  56
  57
  58die_conflict () {
  59    git diff-index --cached --name-status -r --ignore-submodules HEAD --
  60    if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then
  61        die "$(gettext "Pull is not possible because you have unmerged files.
  62Please, fix them up in the work tree, and then use 'git add/rm <file>'
  63as appropriate to mark resolution and make a commit.")"
  64    else
  65        die "$(gettext "Pull is not possible because you have unmerged files.")"
  66    fi
  67}
  68
  69die_merge () {
  70    if [ $(git config --bool --get advice.resolveConflict || echo true) = "true" ]; then
  71        die "$(gettext "You have not concluded your merge (MERGE_HEAD exists).
  72Please, commit your changes before merging.")"
  73    else
  74        die "$(gettext "You have not concluded your merge (MERGE_HEAD exists).")"
  75    fi
  76}
  77
  78test -z "$(git ls-files -u)" || die_conflict
  79test -f "$GIT_DIR/MERGE_HEAD" && die_merge
  80
  81bool_or_string_config () {
  82        git config --bool "$1" 2>/dev/null || git config "$1"
  83}
  84
  85strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
  86log_arg= verbosity= progress= recurse_submodules= verify_signatures=
  87merge_args= edit= rebase_args= all= append= upload_pack= force= tags= prune=
  88keep= depth= unshallow= update_shallow= refmap=
  89curr_branch=$(git symbolic-ref -q HEAD)
  90curr_branch_short="${curr_branch#refs/heads/}"
  91rebase=$(bool_or_string_config branch.$curr_branch_short.rebase)
  92if test -z "$rebase"
  93then
  94        rebase=$(bool_or_string_config pull.rebase)
  95fi
  96
  97# Setup default fast-forward options via `pull.ff`
  98pull_ff=$(bool_or_string_config pull.ff)
  99case "$pull_ff" in
 100true)
 101        no_ff=--ff
 102        ;;
 103false)
 104        no_ff=--no-ff
 105        ;;
 106only)
 107        ff_only=--ff-only
 108        ;;
 109esac
 110
 111
 112dry_run=
 113while :
 114do
 115        case "$1" in
 116        -q|--quiet)
 117                verbosity="$verbosity -q" ;;
 118        -v|--verbose)
 119                verbosity="$verbosity -v" ;;
 120        --progress)
 121                progress=--progress ;;
 122        --no-progress)
 123                progress=--no-progress ;;
 124        -n|--no-stat|--no-summary)
 125                diffstat=--no-stat ;;
 126        --stat|--summary)
 127                diffstat=--stat ;;
 128        --log|--log=*|--no-log)
 129                log_arg="$1" ;;
 130        --no-commit)
 131                no_commit=--no-commit ;;
 132        --commit)
 133                no_commit=--commit ;;
 134        -e|--edit)
 135                edit=--edit ;;
 136        --no-edit)
 137                edit=--no-edit ;;
 138        --squash)
 139                squash=--squash ;;
 140        --no-squash)
 141                squash=--no-squash ;;
 142        --ff)
 143                no_ff=--ff ;;
 144        --no-ff)
 145                no_ff=--no-ff ;;
 146        --ff-only)
 147                ff_only=--ff-only ;;
 148        -s*|--strategy=*)
 149                strategy_args="$strategy_args $1"
 150                ;;
 151        -X*|--strategy-option=*)
 152                merge_args="$merge_args $(git rev-parse --sq-quote "$1")"
 153                ;;
 154        -r*|--rebase=*)
 155                rebase="${1#*=}"
 156                ;;
 157        --rebase)
 158                rebase=true
 159                ;;
 160        --no-rebase)
 161                rebase=false
 162                ;;
 163        --recurse-submodules)
 164                recurse_submodules=--recurse-submodules
 165                ;;
 166        --recurse-submodules=*)
 167                recurse_submodules="$1"
 168                ;;
 169        --no-recurse-submodules)
 170                recurse_submodules=--no-recurse-submodules
 171                ;;
 172        --verify-signatures)
 173                verify_signatures=--verify-signatures
 174                ;;
 175        --no-verify-signatures)
 176                verify_signatures=--no-verify-signatures
 177                ;;
 178        --gpg-sign|-S)
 179                gpg_sign_args=-S
 180                ;;
 181        --gpg-sign=*)
 182                gpg_sign_args=$(git rev-parse --sq-quote "-S${1#--gpg-sign=}")
 183                ;;
 184        -S*)
 185                gpg_sign_args=$(git rev-parse --sq-quote "$1")
 186                ;;
 187        --dry-run)
 188                dry_run=--dry-run
 189                ;;
 190        --all|--no-all)
 191                all=$1 ;;
 192        -a|--append|--no-append)
 193                append=$1 ;;
 194        --upload-pack=*|--no-upload-pack)
 195                upload_pack=$1 ;;
 196        -f|--force|--no-force)
 197                force="$force $1" ;;
 198        -t|--tags|--no-tags)
 199                tags=$1 ;;
 200        -p|--prune|--no-prune)
 201                prune=$1 ;;
 202        -k|--keep|--no-keep)
 203                keep=$1 ;;
 204        --depth=*|--no-depth)
 205                depth=$1 ;;
 206        --unshallow|--no-unshallow)
 207                unshallow=$1 ;;
 208        --update-shallow|--no-update-shallow)
 209                update_shallow=$1 ;;
 210        --refmap=*|--no-refmap)
 211                refmap=$1 ;;
 212        -h|--help-all)
 213                usage
 214                ;;
 215        --)
 216                shift
 217                break
 218                ;;
 219        *)
 220                usage
 221                ;;
 222        esac
 223        shift
 224done
 225
 226case "$rebase" in
 227preserve)
 228        rebase=true
 229        rebase_args=--preserve-merges
 230        ;;
 231true|false|'')
 232        ;;
 233*)
 234        echo "Invalid value for --rebase, should be true, false, or preserve"
 235        usage
 236        exit 1
 237        ;;
 238esac
 239
 240error_on_no_merge_candidates () {
 241        exec >&2
 242
 243        if test true = "$rebase"
 244        then
 245                op_type=rebase
 246                op_prep=against
 247        else
 248                op_type=merge
 249                op_prep=with
 250        fi
 251
 252        upstream=$(git config "branch.$curr_branch_short.merge")
 253        remote=$(git config "branch.$curr_branch_short.remote")
 254
 255        if [ $# -gt 1 ]; then
 256                if [ "$rebase" = true ]; then
 257                        printf "There is no candidate for rebasing against "
 258                else
 259                        printf "There are no candidates for merging "
 260                fi
 261                echo "among the refs that you just fetched."
 262                echo "Generally this means that you provided a wildcard refspec which had no"
 263                echo "matches on the remote end."
 264        elif [ $# -gt 0 ] && [ "$1" != "$remote" ]; then
 265                echo "You asked to pull from the remote '$1', but did not specify"
 266                echo "a branch. Because this is not the default configured remote"
 267                echo "for your current branch, you must specify a branch on the command line."
 268        elif [ -z "$curr_branch" -o -z "$upstream" ]; then
 269                . git-parse-remote
 270                error_on_missing_default_upstream "pull" $op_type $op_prep \
 271                        "git pull <remote> <branch>"
 272        else
 273                echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'"
 274                echo "from the remote, but no such ref was fetched."
 275        fi
 276        exit 1
 277}
 278
 279test true = "$rebase" && {
 280        if ! git rev-parse -q --verify HEAD >/dev/null
 281        then
 282                # On an unborn branch
 283                if test -f "$(git rev-parse --git-path index)"
 284                then
 285                        die "$(gettext "updating an unborn branch with changes added to the index")"
 286                fi
 287        else
 288                require_clean_work_tree "pull with rebase" "Please commit or stash them."
 289        fi
 290        oldremoteref= &&
 291        test -n "$curr_branch" &&
 292        . git-parse-remote &&
 293        remoteref="$(get_remote_merge_branch "$@" 2>/dev/null)" &&
 294        oldremoteref=$(git merge-base --fork-point "$remoteref" $curr_branch 2>/dev/null)
 295}
 296orig_head=$(git rev-parse -q --verify HEAD)
 297git fetch $verbosity $progress $dry_run $recurse_submodules $all $append \
 298${upload_pack:+"$upload_pack"} $force $tags $prune $keep $depth $unshallow $update_shallow \
 299$refmap --update-head-ok "$@" || exit 1
 300test -z "$dry_run" || exit 0
 301
 302curr_head=$(git rev-parse -q --verify HEAD)
 303if test -n "$orig_head" && test "$curr_head" != "$orig_head"
 304then
 305        # The fetch involved updating the current branch.
 306
 307        # The working tree and the index file is still based on the
 308        # $orig_head commit, but we are merging into $curr_head.
 309        # First update the working tree to match $curr_head.
 310
 311        eval_gettextln "Warning: fetch updated the current branch head.
 312Warning: fast-forwarding your working tree from
 313Warning: commit \$orig_head." >&2
 314        git update-index -q --refresh
 315        git read-tree -u -m "$orig_head" "$curr_head" ||
 316                die "$(eval_gettext "Cannot fast-forward your working tree.
 317After making sure that you saved anything precious from
 318$ git diff \$orig_head
 319output, run
 320$ git reset --hard
 321to recover.")"
 322
 323fi
 324
 325merge_head=$(sed -e '/  not-for-merge   /d' \
 326        -e 's/  .*//' "$GIT_DIR"/FETCH_HEAD | \
 327        tr '\012' ' ')
 328
 329case "$merge_head" in
 330'')
 331        error_on_no_merge_candidates "$@"
 332        ;;
 333?*' '?*)
 334        if test -z "$orig_head"
 335        then
 336                die "$(gettext "Cannot merge multiple branches into empty head")"
 337        fi
 338        if test true = "$rebase"
 339        then
 340                die "$(gettext "Cannot rebase onto multiple branches")"
 341        fi
 342        ;;
 343esac
 344
 345# Pulling into unborn branch: a shorthand for branching off
 346# FETCH_HEAD, for lazy typers.
 347if test -z "$orig_head"
 348then
 349        # Two-way merge: we claim the index is based on an empty tree,
 350        # and try to fast-forward to HEAD.  This ensures we will not
 351        # lose index/worktree changes that the user already made on
 352        # the unborn branch.
 353        empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
 354        git read-tree -m -u $empty_tree $merge_head &&
 355        git update-ref -m "initial pull" HEAD $merge_head "$curr_head"
 356        exit
 357fi
 358
 359if test true = "$rebase"
 360then
 361        o=$(git show-branch --merge-base $curr_branch $merge_head $oldremoteref)
 362        if test "$oldremoteref" = "$o"
 363        then
 364                unset oldremoteref
 365        fi
 366fi
 367
 368case "$rebase" in
 369true)
 370        eval="git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity"
 371        eval="$eval $gpg_sign_args"
 372        eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
 373        ;;
 374*)
 375        eval="git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only"
 376        eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress"
 377        eval="$eval $gpg_sign_args"
 378        eval="$eval FETCH_HEAD"
 379        ;;
 380esac
 381eval "exec $eval"