diff options
Diffstat (limited to 'git-apply-patch-script')
| -rwxr-xr-x | git-apply-patch-script | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/git-apply-patch-script b/git-apply-patch-script new file mode 100755 index 0000000000..6261fd85f2 --- /dev/null +++ b/git-apply-patch-script @@ -0,0 +1,144 @@ +#!/bin/sh +# Copyright (C) 2005 Junio C Hamano +# +# Applying diff between two trees to the work tree can be +# done with the following single command: +# +# GIT_EXTERNAL_DIFF=git-apply-patch-script git-diff-tree -p $tree1 $tree2 +# + +case "$#" in +1) + echo >&2 "cannot handle unmerged diff on path $1." + exit 1 ;; +8 | 9) + echo >&2 "cannot handle rename diff between $1 and $8 yet." + exit 1 ;; +esac +name="$1" tmp1="$2" hex1="$3" mode1="$4" tmp2="$5" hex2="$6" mode2="$7" + +type1=f +case "$mode1" in +*120???) type1=l ;; +*1007??) mode1=+x ;; +*1006??) mode1=-x ;; +.) type1=- ;; +esac + +type2=f +case "$mode2" in +*120???) type2=l ;; +*1007??) mode2=+x ;; +*1006??) mode2=-x ;; +.) type2=- ;; +esac + +case "$type1,$type2" in + +-,?) + dir=$(dirname "$name") + case "$dir" in '' | .) ;; *) mkdir -p "$dir" ;; esac || { + echo >&2 "cannot create leading path for $name." + exit 1 + } + if test -e "$name" + then + echo >&2 "path $name to be created already exists." + exit 1 + fi + case "$type2" in + f) + # creating a regular file + cat "$tmp2" >"$name" || { + echo >&2 "cannot create a regular file $name." + exit 1 + } + case "$mode2" in + +x) + echo >&2 "created a regular file $name with mode +x." + chmod "$mode2" "$name" + ;; + -x) + echo >&2 "created a regular file $name." + ;; + esac + ;; + l) + # creating a symlink + ln -s "$(cat "$tmp2")" "$name" || { + echo >&2 "cannot create a symbolic link $name." + exit 1 + } + echo >&2 "created a symbolic link $name." + ;; + *) + echo >&2 "do not know how to create $name of type $type2." + exit 1 + esac + git-update-cache --add -- "$name" ;; + +?,-) + rm -f "$name" || { + echo >&2 "cannot remove $name" + exit 1 + } + echo >&2 "deleted $name." + git-update-cache --remove -- "$name" ;; + +l,f|f,l) + echo >&2 "cannot change a regular file $name and a symbolic link $name." + exit 1 ;; + +l,l) + # symlink to symlink + current=$(readlink "$name") || { + echo >&2 "cannot read the target of the symbolic link $name." + exit 1 + } + original=$(cat "$tmp1") + next=$(cat "$tmp2") + test "$original" != "$current" || { + echo >&2 "cannot apply symbolic link target change ($original->$next) to $name which points to $current." + exit 1 + } + if test "$next" != "$current" + then + rm -f "$name" && ln -s "$next" "$name" || { + echo >&2 "cannot create symbolic link $name." + exit 1 + } + echo >&2 "changed symbolic target of $name." + git-update-cache -- "$name" + fi ;; + +f,f) + # changed + test -e "$name" || { + echo >&2 "regular file $name to be patched does not exist." + exit 1 + } + dir=$(dirname "$name") + case "$dir" in '' | .) ;; *) mkdir -p "$dir";; esac || { + echo >&2 "cannot create leading path for $name." + exit 1 + } + tmp=.git-apply-patch-$$ + trap "rm -f $tmp-*" 0 1 2 3 15 + + # Be careful, in case "$tmp2" is borrowed path from the work tree + # we are looking at... + diff -u -L "a/$name" -L "b/$name" "$tmp1" "$tmp2" >$tmp-patch + + # This will say "patching ..." so we do not say anything outselves. + patch -p1 <$tmp-patch || exit + rm -f $tmp-patch + case "$mode1,$mode2" in + "$mode2,$mode1") ;; + *) + chmod "$mode2" "$name" + echo >&2 "changed mode from $mode1 to $mode2." + ;; + esac + git-update-cache -- "$name" + +esac |
