Last active
June 28, 2018 14:46
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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