Skip to content

Instantly share code, notes, and snippets.

@leophys
Last active June 28, 2018 14:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leophys/5ac7113866af58fc8e0568e191b282d1 to your computer and use it in GitHub Desktop.
Save leophys/5ac7113866af58fc8e0568e191b282d1 to your computer and use it in GitHub Desktop.
An extension for git to git-merge a single specified file from another revision
#!/usr/bin/env bash
usage () {
cat << EOH
git merge-pick [flags] <tree-ish> path/to/file
being <tree-ish> a commit-like object (a commit sha1,
a branch name or a tag).
[flags]
-s, --strategy: merge strategy (see man git-merge)
EOH
}
main() {
GITMP_GATHERER=()
while [[ $# -gt 0 ]]; do
key=$1
case $key in
-h|--help)
usage
exit 0
;;
-v|--verbose)
GITMP_DEBUG="true"
shift
;;
*)
if [[ $GITMP_DEBUG = "true" ]]; then
print_debug "level_1: $1"
fi
GITMP_GATHERER+=($1)
shift
;;
esac
done
print_debug "level_2: ${GITMP_GATHERER[@]}"
merge_pick_wrapper ${GITMP_GATHERER[@]}
}
merge_pick_wrapper() {
if [[ $# -lt 2 ]]; then
usage
exit 2
fi
GITMP_FLAGS=()
while [[ $# -gt 0 ]]; do
key="$1"
case $1 in
-*)
interpret_flag $1 $2
shift
shift
;;
*)
parse_tree_info $1
parse_file_info $1 $2
shift
shift
;;
esac
done
print_debug "GITMP_DEBUG=$GITMP_DEBUG"
print_debug "GITMP_STRATEGY=$GITMP_STRATEGY"
print_debug "GITMP_TARGET_REV=$GITMP_TARGET_REV"
print_debug "GITMP_TARGET_FILE=$GITMP_TARGET_FILE"
# merge_pick $GITMP_FLAGS $GITMP_TARGET_REV $GITMP_TARGET_FILE
merge_pick
}
print_debug() {
if [[ $GITMP_DEBUG = "true" ]]; then
echo "[DEBUG] $@"
fi
}
interpret_flag() {
case $1 in
-h|--help)
usage
exit 0
;;
-s|--strategy)
shift
GITMP_STRATEGY=$1
GITMP_FLAGS+=("-s $GITMP_STRATEGY")
shift
;;
*)
continue
;;
esac
}
parse_tree_info() {
GITMP_CURRENT_REV=$(git rev-parse HEAD)
if [ ! $(git rev-parse --quiet --verify $1) ]; then
echo "$1 is not a valid reference"
exit 3
fi
GITMP_ORIG_REV=$(git symbolic-ref --short HEAD)
GITMP_TARGET_REV=$(git rev-parse $1)
}
parse_file_info() {
if [[ ! -f $2 ]]; then
if [[ $(comm -23 <(echo $2) <(git diff --names-only --diff-filter=AM $1)) != "" ]]; then
print_debug "GITMP_TARGET_FILE=$2"
print_debug "GITMP_TARGET_REV=$1"
print_debug "Diff from target tree point"
print_debug "---------------------------"
print_debug ""
print_debug "$(git diff --names-only --diff-filter=AM HEAD $1)"
exit 4
fi
fi
GITMP_TARGET_FILE=$2
}
merge_pick() {
GITMP_TMP_BRANCH="git-merge-pick-$RANDOM"
git stash push
git checkout -b $GITMP_TMP_BRANCH
git checkout $GITMP_TARGET_REV $GITMP_TARGET_FILE
git add $GITMP_TARGET_FILE
git commit -m "Merge $GITMP_TARGET_FILE from \
$GITMP_TARGET_REV into $GITMP_ORIG_REV"
git checkout $GITMP_ORIG_REV
git merge -m "$GITMP_TARGET_FILE merged from $GITMP_TARGET_REV" \
${GITMP_FLAGS[@]} $GITMP_TMP_BRANCH
git branch -D $GITMP_TMP_BRANCH
git stash pop
}
main $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment