#!/bin/sh # # Copyright (c) 2005 Junio C Hamano # # Fetch one or more remote refs and merge it/them into the current HEAD. setvar SUBDIRECTORY_OK = 'Yes' setvar OPTIONS_KEEPDASHDASH = '' setvar OPTIONS_STUCKLONG = 'Yes' setvar OPTIONS_SPEC = ""\ git pull [options] [ [...]] Fetch one or more remote refs and integrate it/them with the current HEAD. -- v,verbose be more verbose q,quiet be more quiet progress force progress reporting Options related to merging r,rebase?false|true|preserve incorporate changes by rebasing rather than merging n! do not show a diffstat at the end of the merge stat show a diffstat at the end of the merge summary (synonym to --stat) log?n add (at most ) entries from shortlog to merge commit message squash create a single commit instead of doing a merge commit perform a commit if the merge succeeds (default) e,edit edit message before committing ff allow fast-forward ff-only! abort if fast-forward is not possible verify-signatures verify that the named commit has a valid GPG signature s,strategy=strategy merge strategy to use X,strategy-option=option option for selected merge strategy S,gpg-sign?key-id GPG sign commit Options related to fetching all fetch from all remotes a,append append to .git/FETCH_HEAD instead of overwriting upload-pack=path path to upload pack on remote end f,force force overwrite of local branch t,tags fetch all tags and associated objects p,prune prune remote-tracking branches no longer on remote recurse-submodules?on-demand control recursive fetching of submodules dry-run dry run k,keep keep downloaded pack depth=depth deepen history of shallow clone unshallow convert to a complete repository update-shallow accept refs that update .git/shallow refmap=refmap specify fetch refmap "" test $Argc -gt 0 && setvar args = ""$[join(ARGV)]"" source git-sh-setup source git-sh-i18n set_reflog_action "pull${args+ $args}" require_work_tree_exists cd_to_toplevel proc die_conflict { git diff-index --cached --name-status -r --ignore-submodules HEAD -- if test $(git config --bool --get advice.resolveConflict || echo true) = "true" { die $(gettext "Pull is not possible because you have unmerged files. Please, fix them up in the work tree, and then use 'git add/rm ' as appropriate to mark resolution and make a commit.") } else { die $(gettext "Pull is not possible because you have unmerged files.") } } proc die_merge { if test $(git config --bool --get advice.resolveConflict || echo true) = "true" { die $(gettext "You have not concluded your merge (MERGE_HEAD exists). Please, commit your changes before merging.") } else { die $(gettext "You have not concluded your merge (MERGE_HEAD exists).") } } test -z $(git ls-files -u) || die_conflict test -f "$GIT_DIR/MERGE_HEAD" && die_merge proc bool_or_string_config { git config --bool $1 2>/dev/null || git config $1 } setvar strategy_args = '', diffstat = '', no_commit = '', squash = '', no_ff = '', ff_only = '' setvar log_arg = '', verbosity = '', progress = '', recurse_submodules = '', verify_signatures = '' setvar merge_args = '', edit = '', rebase_args = '', all = '', append = '', upload_pack = '', force = '', tags = '', prune = '' setvar keep = '', depth = '', unshallow = '', update_shallow = '', refmap = '' setvar curr_branch = $(git symbolic-ref -q HEAD) setvar curr_branch_short = "${curr_branch#refs/heads/}" setvar rebase = $(bool_or_string_config branch.$curr_branch_short.rebase) if test -z $rebase { setvar rebase = $(bool_or_string_config pull.rebase) } # Setup default fast-forward options via `pull.ff` setvar pull_ff = $(bool_or_string_config pull.ff) case (pull_ff) { true { setvar no_ff = '--ff' } false { setvar no_ff = '--no-ff' } only { setvar ff_only = '--ff-only' } } setvar dry_run = '' while : { case (1) { -q|--quiet { setvar verbosity = ""$verbosity -q"" } -v|--verbose { setvar verbosity = ""$verbosity -v"" } --progress { setvar progress = '--progress' } --no-progress { setvar progress = '--no-progress' } -n|--no-stat|--no-summary { setvar diffstat = '--no-stat' } --stat|--summary { setvar diffstat = '--stat' } --log|--log=*|--no-log { setvar log_arg = "$1" } --no-commit { setvar no_commit = '--no-commit' } --commit { setvar no_commit = '--commit' } -e|--edit { setvar edit = '--edit' } --no-edit { setvar edit = '--no-edit' } --squash { setvar squash = '--squash' } --no-squash { setvar squash = '--no-squash' } --ff { setvar no_ff = '--ff' } --no-ff { setvar no_ff = '--no-ff' } --ff-only { setvar ff_only = '--ff-only' } -s*|--strategy=* { setvar strategy_args = ""$strategy_args $1"" } -X*|--strategy-option=* { setvar merge_args = ""$merge_args $(git rev-parse --sq-quote "$1")"" } -r*|--rebase=* { setvar rebase = "${1#*=}" } --rebase { setvar rebase = 'true' } --no-rebase { setvar rebase = 'false' } --recurse-submodules { setvar recurse_submodules = '--recurse-submodules' } --recurse-submodules=* { setvar recurse_submodules = "$1" } --no-recurse-submodules { setvar recurse_submodules = '--no-recurse-submodules' } --verify-signatures { setvar verify_signatures = '--verify-signatures' } --no-verify-signatures { setvar verify_signatures = '--no-verify-signatures' } --gpg-sign|-S { setvar gpg_sign_args = '-S' } --gpg-sign=* { setvar gpg_sign_args = $(git rev-parse --sq-quote "-S${1#--gpg-sign=}") } -S* { setvar gpg_sign_args = $(git rev-parse --sq-quote "$1") } --dry-run { setvar dry_run = '--dry-run' } --all|--no-all { setvar all = "$1" } -a|--append|--no-append { setvar append = "$1" } --upload-pack=*|--no-upload-pack { setvar upload_pack = "$1" } -f|--force|--no-force { setvar force = ""$force $1"" } -t|--tags|--no-tags { setvar tags = "$1" } -p|--prune|--no-prune { setvar prune = "$1" } -k|--keep|--no-keep { setvar keep = "$1" } --depth=*|--no-depth { setvar depth = "$1" } --unshallow|--no-unshallow { setvar unshallow = "$1" } --update-shallow|--no-update-shallow { setvar update_shallow = "$1" } --refmap=*|--no-refmap { setvar refmap = "$1" } -h|--help-all { usage } -- { shift break } * { usage } } shift } case (rebase) { preserve { setvar rebase = 'true' setvar rebase_args = '--preserve-merges' } true|false|'' { } * { echo "Invalid value for --rebase, should be true, false, or preserve" usage exit 1 } } proc error_on_no_merge_candidates { exec >&2 if test true = $rebase { setvar op_type = 'rebase' setvar op_prep = 'against' } else { setvar op_type = 'merge' setvar op_prep = 'with' } setvar upstream = $(git config "branch.$curr_branch_short.merge") setvar remote = $(git config "branch.$curr_branch_short.remote") if test $Argc -gt 1 { if test $rebase = true { printf "There is no candidate for rebasing against " } else { printf "There are no candidates for merging " } echo "among the refs that you just fetched." echo "Generally this means that you provided a wildcard refspec which had no" echo "matches on the remote end." } elif test $Argc -gt 0 && test $1 != $remote { echo "You asked to pull from the remote '$1', but did not specify" echo "a branch. Because this is not the default configured remote" echo "for your current branch, you must specify a branch on the command line." } elif test -z $curr_branch -o -z $upstream { source git-parse-remote error_on_missing_default_upstream "pull" $op_type $op_prep \ "git pull " } else { echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'" echo "from the remote, but no such ref was fetched." } exit 1 } test true = $rebase && do { if ! git rev-parse -q --verify HEAD >/dev/null { # On an unborn branch if test -f $(git rev-parse --git-path index) { die $(gettext "updating an unborn branch with changes added to the index") } } else { require_clean_work_tree "pull with rebase" "Please commit or stash them." } setvar oldremoteref = '' && test -n $curr_branch && source git-parse-remote && setvar remoteref = "$(get_remote_merge_branch "$@" 2>/dev/null)" && setvar oldremoteref = $(git merge-base --fork-point "$remoteref" $curr_branch 2>/dev/null) } setvar orig_head = $(git rev-parse -q --verify HEAD) git fetch $verbosity $progress $dry_run $recurse_submodules $all $append \ ${upload_pack:+"$upload_pack"} $force $tags $prune $keep $depth $unshallow $update_shallow \ $refmap --update-head-ok @ARGV || exit 1 test -z $dry_run || exit 0 setvar curr_head = $(git rev-parse -q --verify HEAD) if test -n $orig_head && test $curr_head != $orig_head { # The fetch involved updating the current branch. # The working tree and the index file is still based on the # $orig_head commit, but we are merging into $curr_head. # First update the working tree to match $curr_head. eval_gettextln "Warning: fetch updated the current branch head. Warning: fast-forwarding your working tree from Warning: commit \$orig_head." >&2 git update-index -q --refresh git read-tree -u -m $orig_head $curr_head || die $(eval_gettext "Cannot fast-forward your working tree. After making sure that you saved anything precious from $ git diff \$orig_head output, run $ git reset --hard to recover.") } setvar merge_head = $(sed -e '/ not-for-merge /d' \ -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD | \ tr '\012' ' ') case (merge_head) { '' { error_on_no_merge_candidates @ARGV } ?*' '?* { if test -z $orig_head { die $(gettext "Cannot merge multiple branches into empty head") } if test true = $rebase { die $(gettext "Cannot rebase onto multiple branches") } } } # Pulling into unborn branch: a shorthand for branching off # FETCH_HEAD, for lazy typers. if test -z $orig_head { # Two-way merge: we claim the index is based on an empty tree, # and try to fast-forward to HEAD. This ensures we will not # lose index/worktree changes that the user already made on # the unborn branch. setvar empty_tree = '4b825dc642cb6eb9a060e54bf8d69288fbee4904' git read-tree -m -u $empty_tree $merge_head && git update-ref -m "initial pull" HEAD $merge_head $curr_head exit } if test true = $rebase { setvar o = $(git show-branch --merge-base $curr_branch $merge_head $oldremoteref) if test $oldremoteref = $o { unset oldremoteref } } case (rebase) { true { setvar eval = ""git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity"" setvar eval = ""$eval $gpg_sign_args"" setvar eval = ""$eval --onto $merge_head ${oldremoteref:-$merge_head}"" } * { setvar eval = ""git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only"" setvar eval = ""$eval $log_arg $strategy_args $merge_args $verbosity $progress"" setvar eval = ""$eval $gpg_sign_args"" setvar eval = ""$eval FETCH_HEAD"" } } eval "exec $eval"