xref: /aosp_15_r20/development/tools/mergetool/remerge3.sh (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1#!/bin/bash
2
3usage() {
4  cat <<EOF
5Usage:
6  ${0}                  Remerge all files with conflict markers in the git working tree
7  ${0} [FILE...]        Remerge the given files
8
9Options:
10  -t, --tool {bcompare,meld,vimdiff}
11    Use the specified merge tool.
12EOF
13}
14
15# shellcheck disable=SC2155
16readonly BIN_DIR=$(dirname "${BASH_SOURCE[0]}")
17readonly SPLIT3="${BIN_DIR}/split3.awk"
18readonly CONFLICT_MARKER_BEGIN='^<{7}( .+)?$'
19readonly CONFLICT_MARKER_BASE='^\|{7}( .+)?$'
20
21TEMP_FILES=()
22cleanup() {
23  rm -rf "${TEMP_FILES[@]}"
24}
25trap cleanup EXIT
26
27xtrace() {
28  (
29    set -x
30    "${@}"
31  )
32}
33
34mergetool() {
35  local file="${1}"
36  local MERGED="$file"
37  local BASE="${file}:BASE"
38  local LOCAL="${file}:LOCAL"
39  local REMOTE="${file}:REMOTE"
40  TEMP_FILES+=("$BASE" "$LOCAL" "$REMOTE")
41
42  local has_base=false
43  if grep -qE "${CONFLICT_MARKER_BASE}" "$file"; then
44    has_base=true
45  fi
46
47  $has_base && awk -f "$SPLIT3" -v TARGET=BASE <"$file" >"$BASE"
48  awk -f "$SPLIT3" -v TARGET=LOCAL <"$file" >"$LOCAL"
49  awk -f "$SPLIT3" -v TARGET=REMOTE <"$file" >"$REMOTE"
50
51  case "$MERGETOOL" in
52    bc*)
53      if $has_base; then
54        xtrace bcompare "$LOCAL" "$REMOTE" "$BASE" -mergeoutput="$MERGED"
55      else
56        xtrace bcompare "$LOCAL" "$REMOTE" -mergeoutput="$MERGED"
57      fi
58      ;;
59    meld)
60      if $has_base; then
61        xtrace meld "$LOCAL" "$BASE" "$REMOTE" -o "$MERGED"
62      else
63        xtrace meld "$LOCAL" "$MERGED" "$REMOTE"
64      fi
65      ;;
66    vim*)
67      if $has_base; then
68        xtrace vimdiff -c '4wincmd w | wincmd J' "$LOCAL" "$BASE" "$REMOTE" "$MERGED"
69      else
70        xtrace vimdiff -c 'wincmd l' "$LOCAL" "$MERGED" "$REMOTE"
71      fi
72      ;;
73  esac
74}
75
76#
77# BEGIN
78#
79
80MERGETOOL=vimdiff
81if [[ -n "$DISPLAY" ]]; then
82  if command -v bcompare; then
83    MERGETOOL=bcompare
84  elif command -v meld; then
85    MERGETOOL=meld
86  fi
87fi >/dev/null
88
89while [[ "$1" =~ ^- ]]; do
90  arg="${1}"
91  shift
92  case "$arg" in
93    --) break ;;
94    -t | --tool)
95      MERGETOOL="${1}"
96      shift
97      ;;
98    -h | --help | --usage)
99      usage
100      exit 0
101      ;;
102    *)
103      usage
104      exit 1
105      ;;
106  esac
107done
108
109TRUST_EXIT_CODE=false
110if git rev-parse >/dev/null 2>/dev/null; then
111  case "$MERGETOOL" in
112    bc* | vim*)
113      TRUST_EXIT_CODE=true
114      ;;
115  esac
116fi
117
118readonly MERGETOOL
119readonly TRUST_EXIT_CODE
120
121FILES_UNFILTERED=()
122if [[ "${#}" -eq 0 ]]; then
123  while IFS= read -r -d '' ARG; do
124    FILES_UNFILTERED+=("$ARG")
125  done < <(git -c grep.fallbackToNoIndex=true grep -zlE "$CONFLICT_MARKER_BEGIN" 2>/dev/null)
126else
127  FILES_UNFILTERED+=("${@}")
128fi
129
130FILES=()
131for file in "${FILES_UNFILTERED[@]}"; do
132  if ! [[ -f "$file" ]] || [[ -L "$file" ]]; then
133    echo "[SKIPPED] ${file}: not a regular file"
134  elif ! grep -qE "$CONFLICT_MARKER_BEGIN" "$file"; then
135    echo "[SKIPPED] ${file}: no conflict markers found"
136  else
137    FILES+=("$file")
138  fi
139done
140
141echo "Found files with conflict markers:"
142printf '    %s\n' "${FILES[@]}"
143
144for file in "${FILES[@]}"; do
145  echo
146  echo "Merging '${file}'"
147
148  mergetool "$file"
149  exit_code="$?"
150  if [[ "$exit_code" -ne 0 ]]; then
151    echo "Failed to merge '${file}'"
152  fi
153
154  if $TRUST_EXIT_CODE && [[ "$exit_code" -eq 0 ]]; then
155    if [[ -n "$(git ls-files "$file")" ]]; then
156      xtrace git add "$file"
157    fi
158    continue
159  fi
160  read -r -p "Continue merging other files? [Y/n]" -n 1 yn || exit
161  echo
162  [[ "$yn" == [nNqQ] ]] && exit "$exit_code"
163done
164
165exit 0
166