git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[SCRIPT/RFC 2/3] git-merge-one-file--cached

From
IDIgor 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
	fi
	if 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
	fi
	if 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
Previous: Igor DjordjevicNext: Johannes Sixt
Message 4 of 26 in “[SCRIPT/RFC 0/3] git-commit --onto-parent (three-way merge, no working tree file changes)”
  1. Igor DjordjevicNov 26, 2017
  2. 1/3 setup.shIgor Djordjevic, Nov 26, 2017
  3. 3/3 git-commit--onto-parent.shIgor Djordjevic, Nov 26, 2017
  4. 2/3 git-merge-one-file--cachedIgor Djordjevic, Nov 26, 2017
  5. Johannes SixtNov 27, 2017
  6. Igor DjordjevicNov 28, 2017
  7. Johannes SixtNov 29, 2017
  8. Igor DjordjevicNov 29, 2017
  9. Johannes SixtDec 1, 2017
  10. Igor DjordjevicDec 4, 2017
  11. Johannes SixtDec 6, 2017
  12. Junio C HamanoDec 6, 2017
  13. Igor DjordjevicDec 8, 2017
  14. Junio C HamanoDec 8, 2017
  15. Igor DjordjevicDec 8, 2017
  16. Alexei LozovskyDec 9, 2017
  17. Igor DjordjevicDec 9, 2017
  18. Phillip WoodDec 9, 2017
  19. Igor DjordjevicDec 10, 2017
  20. Phillip WoodDec 10, 2017
  21. Igor DjordjevicDec 10, 2017
  22. Alexei LozovskyDec 11, 2017
  23. Alexei LozovskyDec 11, 2017
  24. Phillip WoodDec 9, 2017
  25. Chris NerwertNov 30, 2017
  26. Igor DjordjevicDec 3, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.