[SCRIPT/RFC 2/3] git-merge-one-file--cached
- From
- Igor Djordjevic <igor.d.djordjevic@gmail.com>
- Date
- Nov 26, 2017, 22:36 UTC
- Message-ID
- <d60812ab-a4d9-6d39-9624-3280ef1ccd21@gmail.com>
- In-Reply-To
- <8998e832-f49f-4de4-eb8d-a7934fba97b5@gmail.com>
Original "git-merge-one-file" script is slightly tweaked here into "git-merge-one-file--cached"[*1*] to allow (still trivial) _index-only_ three-way file merge, not touching files inside working tree.
Proof of concept, not thoroughly tested, original content left in, commented out. Feel free to comment/polish.
To make it available, I guess it would be best placed beside existing "git-merge-one-file" script...?
Regards, Buga
[*1*] "git-merge-one-file--cached" --- 8< --- #!/bin/sh # # Copyright (c) Linus Torvalds, 2005 # # --- # Original "git-merge-one-file" script slightly tweaked into # "git-merge-one-file--cached" to allow (still trivial) index-only # three-way file merge, not touching files inside working tree. # # Proof of concept, not thoroughly tested, original content left in, # commented out. # --- # # 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 $# != 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 { test -z "$6" && test "$5" != "$7"; } ||
{ test -z "$7" && test "$5" != "$6"; }
then
echo "ERROR: File $4 deleted on one branch but had its" >&2
echo "ERROR: permissions changed on the other." >&2
exit 1
fiif test -n "$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 --cacheinfo "$6","$2","$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." >&2 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 test "$6" != "$7" then echo "ERROR: File $4 added identically in both branches," >&2 echo "ERROR: but permissions conflict $6->$7." >&2 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." >&2 exit 1 ;; *,160000,*) echo "ERROR: $4: Not merging conflicting submodule changes." >&2 exit 1 ;; esac
src1=$(git unpack-file $2) src2=$(git unpack-file $3) case "$1" in '') echo "Added $4 in both, but differently." orig=$(git unpack-file e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) ;; *) echo "Auto-merging $4" orig=$(git unpack-file $1) ;; esac
git merge-file "$src1" "$orig" "$src2" ret=$? msg= if test $ret != 0 || test -z "$1" then msg='content conflict' ret=1 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 test "$6" != "$7"
then
if test -n "$msg"
then
msg="$msg, "
fi
msg="${msg}permissions conflict: $5->$6,$7"
ret=1
fiif test $ret = 0 then merge_blob=$(git hash-object -w --path="$4" -- "$src1") fi rm -f -- "$orig" "$src1" "$src2"
if test $ret != 0 then echo "ERROR: $msg in $4" >&2 exit 1 fi # exec git update-index -- "$4" exec git update-index --cacheinfo "$6","$merge_blob","$4" ;;
*) echo "ERROR: $4: Not handling case $1 -> $2 -> $3" >&2 ;; esac exit 1