Last active
August 9, 2024 13:47
-
-
Save Dyrcona/4629200 to your computer and use it in GitHub Desktop.
A bash script to batch git cherry-pick of many commits from a single source branch. It can become a new git command if you save it in your path with a name like git-quickpick. Then, you can run it like so `git quickpick foo/bar'. Very handy, that.
This file contains 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
#!/bin/bash | |
# Author: Thomas Berezansky <[email protected]> | |
# Author: Jason Stephenson <[email protected]> | |
# | |
# Feel free to use and to share this script in anyway you like. | |
# This script is intended as a shortcut for the git cherry-pick | |
# command when you have several commits that you want to cherry-pick | |
# into your local branch from another branch. It often results in a | |
# cleaner commit history than simply doing a git merge. | |
# It can be run in two ways and either method takes an optional | |
# parameter, -s. If provided the -s parameter will add your git | |
# signature to each incoming commit as they are cherry-picked. This | |
# is a handy way to sign off on someone else's commits in bulk when | |
# your project has a policy of requiring sign offs on anything going | |
# into the main git repository. If you supply the -s parameter, it | |
# should come before any branch or commit arguments on the command | |
# line. | |
# The simpler way to run this script is to simply supply the branch | |
# name whose commits you want to cherry-pick into your current branch. | |
# For instance, if you want to cherry-pick the commits from branch | |
# `bar' of remote `foo' that do not exist in your current branch you | |
# would use the following: | |
# | |
# quickpick foo/bar | |
# | |
# or | |
# | |
# quickpick -s foo/bar | |
# | |
# to include your sign off. | |
# The second way to use this script is to specify two branches: the | |
# base and the feature. In this case the base is the branch, other | |
# than the current branch, to compare with the feature branch. This | |
# mode will use git cherry to pull out those commit in feature branch | |
# that do not exist in base. This is useful if you're trying to merge | |
# commits into a branch that does not share a common history with | |
# feature branch. Let's say that our branch, local, is based on a | |
# fork of the master at some point in the past, and feature branch is | |
# based on the current master branch. We want to pull the new commits | |
# from feature into our local branch without getting the commits | |
# common to the master and feature branch that are not in our local | |
# branch. We do that by running this command in a checkout of our | |
# local branch: | |
# | |
# quickpick master feature | |
# Should you run into a conflict while cherry-picking, you would | |
# resolve in the usual way. Should you still have outstanding commits | |
# left to pull in, you may pickup where you left off by using the | |
# special argument `--continue.' Even if you believe that your | |
# conflict occurred in the final cherry-pick, it won't hurt to use the | |
# --continue argument as a precaution against missing any commits. | |
# The script keeps track of the commits that have been cherry-picked | |
# as it runs, and so it would be safe to run --continue when there are | |
# none left. | |
if [ "$1" == "-s" ]; then | |
SIGN="-s" | |
shift | |
else | |
SIGN="" | |
fi | |
START=${1:-'FAIL'} | |
END=${2:-'CHERRY'} | |
if [ "$1" == 'FAIL' ]; then | |
echo "NEED SOURCE BRANCH" | |
exit 1; | |
fi | |
if [ "$START" == '--continue' ]; then | |
COMMITS=`cat ~/.git-cherrypick-resume-commits` | |
SIGN=`cat ~/.git-cherrypick-resume-sign` | |
else | |
if [ "$END" == 'CHERRY' ]; then | |
END=$START | |
START='HEAD' | |
fi | |
COMMITS=`git cherry $START $END | grep ^+ | cut -f2 -d' '` | |
fi | |
if [ "$SIGN" != "-s" ]; then | |
SIGN='' | |
fi | |
for commit in $COMMITS | |
do | |
COMMITS=`echo $COMMITS | sed -e "s/.*$commit\s*//"` | |
git cherry-pick $SIGN $commit | |
if [ $? -ne 0 ]; then | |
echo $COMMITS > ~/.git-cherrypick-resume-commits | |
echo "$SIGN" > ~/.git-cherrypick-resume-sign | |
exit 1 | |
fi | |
done | |
rm -f ~/.git-cherrypick-resume-commits ~/.git-cherrypick-resume-sign | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment