summaryrefslogtreecommitdiff
path: root/bin/git-merge-ff
blob: e772041d7584fb9b878f677a934bb0bd63c7f5ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env bash

# source: Jefromi on Stack Overflow -- https://stackoverflow.com/a/4157435

# modified by spwhitton to default to $branch@{u} at the suggestion of
# orip on Stack Overflow

# modified by spwhitton not to output a diff when the fast-forward
# didn't change anything

# modified by spwhitton to add trailing '--' to call to git-diff(1),
# which avoids an error when there is a filename and branch with the
# same name

# modified by spwhitton to handle branches checked out in other worktrees

_usage() {
    echo "Usage: git merge-ff <branch> [<committish-to-merge>]" 1>&2
    exit 1
}

_merge_ff() {
    branch="$1"
    commit="$2"

    branch_orig_hash="$(git show-ref -s --verify refs/heads/$branch 2> /dev/null)"
    if [ $? -ne 0 ]; then
        echo "Error: unknown branch $branch" 1>&2
        _usage
    fi

    commit_orig_hash="$(git rev-parse --verify $commit 2> /dev/null)"
    if [ $? -ne 0 ]; then
        echo "Error: unknown revision $commit" 1>&2
        _usage
    fi

    worktree=$(git worktree list --porcelain | perl -000 -wn \
        -e'm#^branch refs/heads/'"$branch"'$#m && m#^worktree (.+)$#m && print $1')

    if [ -n "$worktree" ]; then
        git -C "$worktree" merge $quiet --ff-only "$commit"
    else
        if [ "$(git merge-base $branch_orig_hash $commit_orig_hash)" != "$branch_orig_hash" ]; then
            echo "Error: merging $commit into $branch would not be a fast-forward" 1>&2
            exit 1
        fi
        if [ "$commit_orig_hash" = "$branch_orig_hash" ]; then
            if [ -z $quiet ]; then
                echo "Already up-to-date."
            fi
            exit 0
        fi
        echo "Updating ${branch_orig_hash:0:7}..${commit_orig_hash:0:7}"
        if git update-ref -m "merge $commit: Fast forward" "refs/heads/$branch" "$commit_orig_hash" "$branch_orig_hash"; then
            if [ -z $quiet ]; then
                echo "Fast forward"
                git diff --stat "$branch@{1}" "$branch" --
            fi
        else
            echo "Error: fast forward using update-ref failed" 1>&2
        fi
    fi
}

while getopts "q" opt; do
    case $opt in
        q ) quiet="-q";;
        * ) ;;
    esac
done
shift $((OPTIND-1))

case $# in
    2 ) _merge_ff "$1" "$2";;
    1 ) _merge_ff "$1" "${1}@{upstream}";;
    * ) _usage
esac