t4200: test the out-of-date checking code
[topgit/pro.git] / tg--index-merge-one-file.sh
blob5d80b132a2efaa4f642bac9f523a09537c44e3bb
1 #!/bin/sh
3 # tg--index-merge-one-file -- auto merge a file without touching working tree
4 # Copyright (C) 2017 Kyle J. McKay
5 # All rights reserved.
6 # License GPLv2+
8 # $TG_TMP_DIR => location to store temporary files
9 # $tg_index_mergetop_behavior => "" (ours), "theirs", "merge", "remove"
10 # $1 => stage 1 hash or empty
11 # $2 => stage 2 hash or empty
12 # $3 => stage 3 hash or empty
13 # $4 => full pathname in index
14 # $5 => stage 1 mode (6 octal digits) or empty
15 # $6 => stage 2 mode
16 # $7 => stage 3 mode
18 nullsha="0000000000000000000000000000000000000000"
19 tab=' '
21 if [ "$1" = "-h" ] && [ $# -eq 1 ]; then
22 echo "\
23 usage: ${tgname:-tg} index-merge-one-file [--<mergetop>] <s1_hash> <s2_hash> <s3_hash> <path> <s1_mode> <s2_mode> <s3_mode>"
24 exit 0
26 if [ -z "$tg_index_mergetop_behavior" ]; then case "$1" in
27 --merge|--theirs|--remove|--ours)
28 tg_index_mergetop_behavior="${1#--}"
29 shift
30 esac; fi
32 [ $# -eq 7 ] || exit 1
34 # The read-tree --aggressive option handles three cases that may end up in
35 # here:
37 # 1. One side removes a file but the other leaves it unchanged (remove)
38 # 2. Both sides remove a file (remove)
39 # 3. Both sides add a path identically (use it)
41 # The problem is (1). When resolving .topdeps and .topmsg files using either
42 # --ours or --theirs the normal resolution of (1) to remove may be incorrect.
44 # But that means in order to get that case to come to us all three cases must
45 # be handled properly for non-topfile files since they will therefore end up
46 # in here as well.
48 newhash=
49 newmode="${6:-0}"
51 if [ "$tg_index_mergetop_behavior" != "merge" ] &&
52 { [ "$4" = ".topdeps" ] || [ "$4" = ".topmsg" ]; }
53 then
54 # Handle --ours, --theirs and --remove for .topdeps and .topmsg
56 if [ "$tg_index_mergetop_behavior" = "remove" ]; then
57 newhash="$nullsha"
58 elif [ "$tg_index_mergetop_behavior" = "theirs" ]; then
59 newhash="${3:-$nullsha}"
60 newmode="${7:-0}"
61 else
62 # --ours is the default mode
63 newhash="${2:-$nullsha}"
66 # .topmsg and .topdeps are never executable
67 [ "$newmode" != "100755" ] || newmode="100644"
69 if [ "$newmode" != "100644" ] && [ "$newhash" != "$nullsha" ]; then
70 # .topmsg and .topdeps are only allowed to be blobs
71 newhash="$nullsha"
72 newmode="0"
76 if [ -z "$newhash" ]; then
77 # Check for the "--aggressive" and "--trivial" things:
79 # a) all three hashes are the same (handled same as next case)
80 # b) $2 and $3 are the same (and their modes)
81 # c) $1 and $2 are the same (and their modes)
82 # d) $1 and $3 are the same (and their modes)
84 if [ "$2" = "$3" ] && [ "$6" = "$7" ] ; then
85 newhash="${2:-$nullsha}"
86 elif [ "$1" = "$2" ] && [ "$5" = "$6" ]; then
87 newhash="${3:-$nullsha}" newmode="${7:-0}"
88 elif [ "$1" = "$3" ] && [ "$5" = "$7" ]; then
89 newhash="${2:-$nullsha}"
93 if [ -z "$newhash" ]; then
94 # We only handle auto merging existing files with the same mode
95 case "${1:-:}${2:-:}${3:-:}${4:-:}${5:-:}${6:-:}${7:-:}" in *":"*) exit 1; esac
96 [ "$5" = "$6" ] && [ "$6" = "$7" ] || exit 1
98 # mode must match 100\o\o\o
99 case "$6" in 100[0-7][0-7][0-7]);;*) exit 1; esac
101 # perform a "simple" 3-way merge
102 tg_tmp_dir="${TG_TMP_DIR:-/tmp}"
103 basef="$tg_tmp_dir/tgmerge_$$_base"
104 oursf="$tg_tmp_dir/tgmerge_$$_ours"
105 thrsf="$tg_tmp_dir/tgmerge_$$_thrs"
106 trap 'rm -f "$basef" "$oursf" "$thrsf"' EXIT
107 trap 'exit' HUP INT QUIT ABRT PIPE TERM
108 git cat-file blob "$1" >"$basef" 2>/dev/null || exit 1
109 git cat-file blob "$2" >"$oursf" 2>/dev/null || exit 1
110 git cat-file blob "$3" >"$thrsf" 2>/dev/null || exit 1
111 git merge-file --quiet "$oursf" "$basef" "$thrsf" >/dev/null 2>&1 || exit 1
112 printf '%s\n' "Auto-merging $4"
113 newhash="$(git hash-object -w --stdin <"$oursf" 2>/dev/null)" || exit 1
116 [ -n "$newhash" ] && [ -n "$newmode" ] || exit 1
117 [ "$newhash" != "$nullsha" ] || newmode="0"
118 git update-index --index-info >/dev/null 2>&1 <<EOT
119 0 $nullsha$tab$4
120 $newmode $newhash$tab$4