git-merge-one-file.shon commit commit: allow associating auxiliary info on-demand (96c4f4a)
   1#!/bin/sh
   2#
   3# Copyright (c) Linus Torvalds, 2005
   4#
   5# This is the git per-file merge script, called with
   6#
   7#   $1 - original file SHA1 (or empty)
   8#   $2 - file in branch1 SHA1 (or empty)
   9#   $3 - file in branch2 SHA1 (or empty)
  10#   $4 - pathname in repository
  11#   $5 - original file mode (or empty)
  12#   $6 - file in branch1 mode (or empty)
  13#   $7 - file in branch2 mode (or empty)
  14#
  15# Handle some trivial cases.. The _really_ trivial cases have
  16# been handled already by git read-tree, but that one doesn't
  17# do any merges that might change the tree layout.
  18
  19USAGE='<orig blob> <our blob> <their blob> <path>'
  20USAGE="$USAGE <orig mode> <our mode> <their mode>"
  21LONG_USAGE="usage: git merge-one-file $USAGE
  22
  23Blob ids and modes should be empty for missing files."
  24
  25SUBDIRECTORY_OK=Yes
  26. git-sh-setup
  27cd_to_toplevel
  28require_work_tree
  29
  30if ! test "$#" -eq 7
  31then
  32        echo "$LONG_USAGE"
  33        exit 1
  34fi
  35
  36case "${1:-.}${2:-.}${3:-.}" in
  37#
  38# Deleted in both or deleted in one and unchanged in the other
  39#
  40"$1.." | "$1.$1" | "$1$1.")
  41        if [ "$2" ]; then
  42                echo "Removing $4"
  43        else
  44                # read-tree checked that index matches HEAD already,
  45                # so we know we do not have this path tracked.
  46                # there may be an unrelated working tree file here,
  47                # which we should just leave unmolested.  Make sure
  48                # we do not have it in the index, though.
  49                exec git update-index --remove -- "$4"
  50        fi
  51        if test -f "$4"; then
  52                rm -f -- "$4" &&
  53                rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || :
  54        fi &&
  55                exec git update-index --remove -- "$4"
  56        ;;
  57
  58#
  59# Added in one.
  60#
  61".$2.")
  62        # the other side did not add and we added so there is nothing
  63        # to be done, except making the path merged.
  64        exec git update-index --add --cacheinfo "$6" "$2" "$4"
  65        ;;
  66"..$3")
  67        echo "Adding $4"
  68        if test -f "$4"
  69        then
  70                echo "ERROR: untracked $4 is overwritten by the merge."
  71                exit 1
  72        fi
  73        git update-index --add --cacheinfo "$7" "$3" "$4" &&
  74                exec git checkout-index -u -f -- "$4"
  75        ;;
  76
  77#
  78# Added in both, identically (check for same permissions).
  79#
  80".$3$2")
  81        if [ "$6" != "$7" ]; then
  82                echo "ERROR: File $4 added identically in both branches,"
  83                echo "ERROR: but permissions conflict $6->$7."
  84                exit 1
  85        fi
  86        echo "Adding $4"
  87        git update-index --add --cacheinfo "$6" "$2" "$4" &&
  88                exec git checkout-index -u -f -- "$4"
  89        ;;
  90
  91#
  92# Modified in both, but differently.
  93#
  94"$1$2$3" | ".$2$3")
  95
  96        case ",$6,$7," in
  97        *,120000,*)
  98                echo "ERROR: $4: Not merging symbolic link changes."
  99                exit 1
 100                ;;
 101        *,160000,*)
 102                echo "ERROR: $4: Not merging conflicting submodule changes."
 103                exit 1
 104                ;;
 105        esac
 106
 107        src2=`git-unpack-file $3`
 108        case "$1" in
 109        '')
 110                echo "Added $4 in both, but differently."
 111                # This extracts OUR file in $orig, and uses git apply to
 112                # remove lines that are unique to ours.
 113                orig=`git-unpack-file $2`
 114                sz0=`wc -c <"$orig"`
 115                @@DIFF@@ -u -La/$orig -Lb/$orig $orig $src2 | git apply --no-add
 116                sz1=`wc -c <"$orig"`
 117
 118                # If we do not have enough common material, it is not
 119                # worth trying two-file merge using common subsections.
 120                expr $sz0 \< $sz1 \* 2 >/dev/null || : >$orig
 121                ;;
 122        *)
 123                echo "Auto-merging $4"
 124                orig=`git-unpack-file $1`
 125                ;;
 126        esac
 127
 128        # Be careful for funny filename such as "-L" in "$4", which
 129        # would confuse "merge" greatly.
 130        src1=`git-unpack-file $2`
 131        git merge-file "$src1" "$orig" "$src2"
 132        ret=$?
 133        msg=
 134        if [ $ret -ne 0 ]; then
 135                msg='content conflict'
 136        fi
 137
 138        # Create the working tree file, using "our tree" version from the
 139        # index, and then store the result of the merge.
 140        git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1
 141        rm -f -- "$orig" "$src1" "$src2"
 142
 143        if [ "$6" != "$7" ]; then
 144                if [ -n "$msg" ]; then
 145                        msg="$msg, "
 146                fi
 147                msg="${msg}permissions conflict: $5->$6,$7"
 148                ret=1
 149        fi
 150        if [ "$1" = '' ]; then
 151                ret=1
 152        fi
 153
 154        if [ $ret -ne 0 ]; then
 155                echo "ERROR: $msg in $4"
 156                exit 1
 157        fi
 158        exec git update-index -- "$4"
 159        ;;
 160
 161*)
 162        echo "ERROR: $4: Not handling case $1 -> $2 -> $3"
 163        ;;
 164esac
 165exit 1