| #!/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 |