~ubuntu-branches/ubuntu/intrepid/git-core/intrepid-updates

« back to all changes in this revision

Viewing changes to git-applypatch.sh

  • Committer: Package Import Robot
  • Author(s): Gerrit Pape
  • Date: 2007-10-04 08:27:01 UTC
  • mfrom: (1.1.23)
  • Revision ID: package-import@ubuntu.com-20071004082701-rsd058ontoqz4i30
Tags: 1:1.5.3.4-1
new upstream point release (closes: #445188).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/bin/sh
2
 
##
3
 
## applypatch takes four file arguments, and uses those to
4
 
## apply the unpacked patch (surprise surprise) that they
5
 
## represent to the current tree.
6
 
##
7
 
## The arguments are:
8
 
##      $1 - file with commit message
9
 
##      $2 - file with the actual patch
10
 
##      $3 - "info" file with Author, email and subject
11
 
##      $4 - optional file containing signoff to add
12
 
##
13
 
 
14
 
USAGE='<msg> <patch> <info> [<signoff>]'
15
 
. git-sh-setup
16
 
 
17
 
case "$#" in 3|4) ;; *) usage ;; esac
18
 
 
19
 
final=.dotest/final-commit
20
 
##
21
 
## If this file exists, we ask before applying
22
 
##
23
 
query_apply=.dotest/.query_apply
24
 
 
25
 
## We do not munge the first line of the commit message too much
26
 
## if this file exists.
27
 
keep_subject=.dotest/.keep_subject
28
 
 
29
 
## We do not attempt the 3-way merge fallback unless this file exists.
30
 
fall_back_3way=.dotest/.3way
31
 
 
32
 
MSGFILE=$1
33
 
PATCHFILE=$2
34
 
INFO=$3
35
 
SIGNOFF=$4
36
 
EDIT=${VISUAL:-${EDITOR:-vi}}
37
 
 
38
 
export GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$INFO")"
39
 
export GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$INFO")"
40
 
export GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$INFO")"
41
 
export SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$INFO")"
42
 
 
43
 
if test '' != "$SIGNOFF"
44
 
then
45
 
        if test -f "$SIGNOFF"
46
 
        then
47
 
                SIGNOFF=`cat "$SIGNOFF"` || exit
48
 
        elif case "$SIGNOFF" in yes | true | me | please) : ;; *) false ;; esac
49
 
        then
50
 
                SIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e '
51
 
                                s/>.*/>/
52
 
                                s/^/Signed-off-by: /'
53
 
                `
54
 
        else
55
 
                SIGNOFF=
56
 
        fi
57
 
        if test '' != "$SIGNOFF"
58
 
        then
59
 
                LAST_SIGNED_OFF_BY=`
60
 
                        sed -ne '/^Signed-off-by: /p' "$MSGFILE" |
61
 
                        tail -n 1
62
 
                `
63
 
                test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
64
 
                    test '' = "$LAST_SIGNED_OFF_BY" && echo
65
 
                    echo "$SIGNOFF"
66
 
                } >>"$MSGFILE"
67
 
        fi
68
 
fi
69
 
 
70
 
patch_header=
71
 
test -f "$keep_subject" || patch_header='[PATCH] '
72
 
 
73
 
{
74
 
        echo "$patch_header$SUBJECT"
75
 
        if test -s "$MSGFILE"
76
 
        then
77
 
                echo
78
 
                cat "$MSGFILE"
79
 
        fi
80
 
} >"$final"
81
 
 
82
 
interactive=yes
83
 
test -f "$query_apply" || interactive=no
84
 
 
85
 
while [ "$interactive" = yes ]; do
86
 
        echo "Commit Body is:"
87
 
        echo "--------------------------"
88
 
        cat "$final"
89
 
        echo "--------------------------"
90
 
        printf "Apply? [y]es/[n]o/[e]dit/[a]ccept all "
91
 
        read reply
92
 
        case "$reply" in
93
 
                y|Y) interactive=no;;
94
 
                n|N) exit 2;;   # special value to tell dotest to keep going
95
 
                e|E) "$EDIT" "$final";;
96
 
                a|A) rm -f "$query_apply"
97
 
                     interactive=no ;;
98
 
        esac
99
 
done
100
 
 
101
 
if test -x "$GIT_DIR"/hooks/applypatch-msg
102
 
then
103
 
        "$GIT_DIR"/hooks/applypatch-msg "$final" || exit
104
 
fi
105
 
 
106
 
echo
107
 
echo Applying "'$SUBJECT'"
108
 
echo
109
 
 
110
 
git-apply --index "$PATCHFILE" || {
111
 
 
112
 
        # git-apply exits with status 1 when the patch does not apply,
113
 
        # but it die()s with other failures, most notably upon corrupt
114
 
        # patch.  In the latter case, there is no point to try applying
115
 
        # it to another tree and do 3-way merge.
116
 
        test $? = 1 || exit 1
117
 
 
118
 
        test -f "$fall_back_3way" || exit 1
119
 
 
120
 
        # Here if we know which revision the patch applies to,
121
 
        # we create a temporary working tree and index, apply the
122
 
        # patch, and attempt 3-way merge with the resulting tree.
123
 
 
124
 
        O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
125
 
        rm -fr .patch-merge-*
126
 
 
127
 
        if git-apply -z --index-info "$PATCHFILE" \
128
 
                >.patch-merge-index-info 2>/dev/null &&
129
 
                GIT_INDEX_FILE=.patch-merge-tmp-index \
130
 
                git-update-index -z --index-info <.patch-merge-index-info &&
131
 
                GIT_INDEX_FILE=.patch-merge-tmp-index \
132
 
                git-write-tree >.patch-merge-tmp-base &&
133
 
                (
134
 
                        mkdir .patch-merge-tmp-dir &&
135
 
                        cd .patch-merge-tmp-dir &&
136
 
                        GIT_INDEX_FILE="../.patch-merge-tmp-index" \
137
 
                        GIT_OBJECT_DIRECTORY="$O_OBJECT" \
138
 
                        git-apply $binary --index
139
 
                ) <"$PATCHFILE"
140
 
        then
141
 
                echo Using index info to reconstruct a base tree...
142
 
                mv .patch-merge-tmp-base .patch-merge-base
143
 
                mv .patch-merge-tmp-index .patch-merge-index
144
 
        else
145
 
        (
146
 
                N=10
147
 
 
148
 
                # Otherwise, try nearby trees that can be used to apply the
149
 
                # patch.
150
 
                git-rev-list --max-count=$N HEAD
151
 
 
152
 
                # or hoping the patch is against known tags...
153
 
                git-ls-remote --tags .
154
 
        ) |
155
 
            while read base junk
156
 
            do
157
 
                # Try it if we have it as a tree.
158
 
                git-cat-file tree "$base" >/dev/null 2>&1 || continue
159
 
 
160
 
                rm -fr .patch-merge-tmp-* &&
161
 
                mkdir .patch-merge-tmp-dir || break
162
 
                (
163
 
                        cd .patch-merge-tmp-dir &&
164
 
                        GIT_INDEX_FILE=../.patch-merge-tmp-index &&
165
 
                        GIT_OBJECT_DIRECTORY="$O_OBJECT" &&
166
 
                        export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY &&
167
 
                        git-read-tree "$base" &&
168
 
                        git-apply --index &&
169
 
                        mv ../.patch-merge-tmp-index ../.patch-merge-index &&
170
 
                        echo "$base" >../.patch-merge-base
171
 
                ) <"$PATCHFILE"  2>/dev/null && break
172
 
            done
173
 
        fi
174
 
 
175
 
        test -f .patch-merge-index &&
176
 
        his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&
177
 
        orig_tree=$(cat .patch-merge-base) &&
178
 
        rm -fr .patch-merge-* || exit 1
179
 
 
180
 
        echo Falling back to patching base and 3-way merge using $orig_tree...
181
 
 
182
 
        # This is not so wrong.  Depending on which base we picked,
183
 
        # orig_tree may be wildly different from ours, but his_tree
184
 
        # has the same set of wildly different changes in parts the
185
 
        # patch did not touch, so resolve ends up canceling them,
186
 
        # saying that we reverted all those changes.
187
 
 
188
 
        if git-merge-resolve $orig_tree -- HEAD $his_tree
189
 
        then
190
 
                echo Done.
191
 
        else
192
 
                echo Failed to merge in the changes.
193
 
                exit 1
194
 
        fi
195
 
}
196
 
 
197
 
if test -x "$GIT_DIR"/hooks/pre-applypatch
198
 
then
199
 
        "$GIT_DIR"/hooks/pre-applypatch || exit
200
 
fi
201
 
 
202
 
tree=$(git-write-tree) || exit 1
203
 
echo Wrote tree $tree
204
 
parent=$(git-rev-parse --verify HEAD) &&
205
 
commit=$(git-commit-tree $tree -p $parent <"$final") || exit 1
206
 
echo Committed: $commit
207
 
git-update-ref -m "applypatch: $SUBJECT" HEAD $commit $parent || exit
208
 
 
209
 
if test -x "$GIT_DIR"/hooks/post-applypatch
210
 
then
211
 
        "$GIT_DIR"/hooks/post-applypatch
212
 
fi