aboutsummaryrefslogtreecommitdiff
path: root/git-merge-one-file.sh
blob: 7aeb96952f668baef2fd18383806e13a20415f19 (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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/bin/sh
#
# Copyright (c) Linus Torvalds, 2005
#
# This is the git per-file merge script, called with
#
#   $1 - original file SHA1 (or empty)
#   $2 - file in branch1 SHA1 (or empty)
#   $3 - file in branch2 SHA1 (or empty)
#   $4 - pathname in repository
#   $5 - original file mode (or empty)
#   $6 - file in branch1 mode (or empty)
#   $7 - file in branch2 mode (or empty)
#
# Handle some trivial cases.. The _really_ trivial cases have
# been handled already by git read-tree, but that one doesn't
# do any merges that might change the tree layout.

USAGE='<orig blob> <our blob> <their blob> <path>'
USAGE="$USAGE <orig mode> <our mode> <their mode>"
LONG_USAGE="Usage: git merge-one-file $USAGE

Blob ids and modes should be empty for missing files."

SUBDIRECTORY_OK=Yes
. git-sh-setup
cd_to_toplevel
require_work_tree

if ! test "$#" -eq 7
then
	echo "$LONG_USAGE"
	exit 1
fi

case "${1:-.}${2:-.}${3:-.}" in
#
# Deleted in both or deleted in one and unchanged in the other
#
"$1.." | "$1.$1" | "$1$1.")
	if [ "$2" ]; then
		echo "Removing $4"
	else
		# read-tree checked that index matches HEAD already,
		# so we know we do not have this path tracked.
		# there may be an unrelated working tree file here,
		# which we should just leave unmolested.  Make sure
		# we do not have it in the index, though.
		exec git update-index --remove -- "$4"
	fi
	if test -f "$4"; then
		rm -f -- "$4" &&
		rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || :
	fi &&
		exec git update-index --remove -- "$4"
	;;

#
# Added in one.
#
".$2.")
	# the other side did not add and we added so there is nothing
	# to be done, except making the path merged.
	exec git update-index --add --cacheinfo "$6" "$2" "$4"
	;;
"..$3")
	echo "Adding $4"
	if test -f "$4"
	then
		echo "ERROR: untracked $4 is overwritten by the merge."
		exit 1
	fi
	git update-index --add --cacheinfo "$7" "$3" "$4" &&
		exec git checkout-index -u -f -- "$4"
	;;

#
# Added in both, identically (check for same permissions).
#
".$3$2")
	if [ "$6" != "$7" ]; then
		echo "ERROR: File $4 added identically in both branches,"
		echo "ERROR: but permissions conflict $6->$7."
		exit 1
	fi
	echo "Adding $4"
	git update-index --add --cacheinfo "$6" "$2" "$4" &&
		exec git checkout-index -u -f -- "$4"
	;;

#
# Modified in both, but differently.
#
"$1$2$3" | ".$2$3")

	case ",$6,$7," in
	*,120000,*)
		echo "ERROR: $4: Not merging symbolic link changes."
		exit 1
		;;
	*,160000,*)
		echo "ERROR: $4: Not merging conflicting submodule changes."
		exit 1
		;;
	esac

	src2=`git-unpack-file $3`
	case "$1" in
	'')
		echo "Added $4 in both, but differently."
		# This extracts OUR file in $orig, and uses git apply to
		# remove lines that are unique to ours.
		orig=`git-unpack-file $2`
		sz0=`wc -c <"$orig"`
		@@DIFF@@ -u -La/$orig -Lb/$orig $orig $src2 | git apply --no-add
		sz1=`wc -c <"$orig"`

		# If we do not have enough common material, it is not
		# worth trying two-file merge using common subsections.
		expr "$sz0" \< "$sz1" \* 2 >/dev/null || : >$orig
		;;
	*)
		echo "Auto-merging $4"
		orig=`git-unpack-file $1`
		;;
	esac

	# Be careful for funny filename such as "-L" in "$4", which
	# would confuse "merge" greatly.
	src1=`git-unpack-file $2`
	git merge-file "$src1" "$orig" "$src2"
	ret=$?
	msg=
	if [ $ret -ne 0 ]; then
		msg='content conflict'
	fi

	# Create the working tree file, using "our tree" version from the
	# index, and then store the result of the merge.
	git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1
	rm -f -- "$orig" "$src1" "$src2"

	if [ "$6" != "$7" ]; then
		if [ -n "$msg" ]; then
			msg="$msg, "
		fi
		msg="${msg}permissions conflict: $5->$6,$7"
		ret=1
	fi
	if [ "$1" = '' ]; then
		ret=1
	fi

	if [ $ret -ne 0 ]; then
		echo "ERROR: $msg in $4"
		exit 1
	fi
	exec git update-index -- "$4"
	;;

*)
	echo "ERROR: $4: Not handling case $1 -> $2 -> $3"
	;;
esac
exit 1