Created
April 22, 2017 18:32
-
-
Save Arakade/237079d9290e0d5c208e17481a7ac0bd to your computer and use it in GitHub Desktop.
BASH script to port a Git commit from one Git repo to another unrelated Git repo (can run with BASH on Windows)
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
$ GitPortPatch.sh 22b7f80c22ac1861e945ddf30e30671c46b53d6e | |
Getting commit message | |
Getting patch | |
Getting affected filenames | |
Getting current status of those files... | |
Checking them... | |
Ensuring affected files are ready for patching... | |
Preparing Assets/TerraVolPack/TerraVol/Scripts/Data/MeshData.cs | |
Preparing Assets/TerraVolPack/TerraVol/Scripts/Map/Chunk.cs | |
Apply patch? y/n : y | |
Patching... | |
patching file Assets/TerraVolPack/TerraVol/Scripts/Data/MeshData.cs | |
patching file Assets/TerraVolPack/TerraVol/Scripts/Map/Chunk.cs | |
Adding affected files to staged group... | |
Assets/TerraVolPack/TerraVol/Scripts/Data/MeshData.cs | |
Assets/TerraVolPack/TerraVol/Scripts/Map/Chunk.cs | |
Commit patch? y/n : y | |
Committing... | |
[voxels-generations 2842944] MeshData: validation working (maybe doing extraneous calculations?) (from 22b7f80c22ac1861e945ddf30e30671c46b53d6e) | |
2 files changed, 80 insertions(+), 25 deletions(-) | |
Done. |
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
#!/bin/bash | |
# Process a Git commit from one Git repository into another (unrelated) repository. | |
# (there are definitely better ways if they are related, e.g. cherry-pick) | |
# Currently leaves tmp files in /tmp (since it's sometimes handy to check). | |
# v1.0 2017/04/22 Rupert Key / @Arakade | |
showHelp() { | |
echo -e "\n${CmdName} [-h -? -g -a -G -A -1 <DirFrom> -2 <DirTo> ] <SHA1>" | |
echo -e "\t-h -? : this help" | |
echo -e "\t-g and -G : -g get patch (default), -G do not get patch" | |
echo -e "\t-a and -A : -a apply patch (default), -A do not apply patch" | |
echo -e "\t-1 : set 'from' repository" | |
echo -e "\t-2 : set 'to' repository" | |
echo -e "\tSHA1 : commit to port\n" | |
echo -e "\tYou will be asked before anything is changed." | |
echo -e "\tIf you wish to tweak a patch before applying," | |
echo -e "\t- answer 'n' to not apply," | |
echo -e "\t- tweak the files in /tmp/<SHA1>* as needed," | |
echo -e "\t- resume without redoing the 'get' with $CmdName -G <SHA1>" | |
echo -e "\n" | |
} | |
checkRepo() { | |
if [ "XX" == "X${1}X" ] ; then | |
showHelp | |
echo -e "ERROR: No Git repository specified as $2\n" | |
exit 1 | |
fi | |
if [ ! -d "$1" ] ; then | |
showHelp | |
echo -e "ERROR: \"$1\" does not exist (or is not a directory)\n" | |
exit 1 | |
fi | |
if [ ! -d "$1/.git" ] ; then | |
showHelp | |
echo -e "ERROR: \"$1\" is not a Git repository\n" | |
exit 1 | |
fi | |
} | |
GetPatch() { | |
cd "$D1" | |
# Get log for committing at end | |
echo "Getting commit message" | |
git log --pretty=%B "${commit}^..${commit}" | awk "NR==1 {printf(\"%s (from %s)\n\", \$0, \"${commit}\")} NR>1" > "$LogFile" | |
if [ 0 -ne $? ] ; then | |
echo "Failed to get log" | |
exit 1 | |
fi | |
# Get the actual patch | |
echo "Getting patch" | |
git diff "${commit}^" "${commit}" > "$PatchFile" | |
if [ 0 -ne $? ] ; then | |
echo "Failed to get diff" | |
exit 1 | |
fi | |
# Process filenames affected from the patch | |
echo "Getting affected filenames" | |
# --- a/Assets/TerraVolPack/TerraVol/Scripts/Data/ActionData.cs | |
sed -n 's%^--- a/\(.*\)$%\1%p' "$PatchFile" > "$FilenamesFile" | |
cd "$D2" | |
# See whether any already modified | |
echo "Getting current status of those files..." | |
git status > "$StatusFileBefore" | |
echo "Checking them..." | |
AlreadyModified="" | |
cat "$FilenamesFile" | while read f ; do | |
if grep -q "$f" "$StatusFileBefore" ; then | |
# Really changed (not just whitespace) | |
linesDiff=$(git diff -w "$f" | wc -l) | |
if [ $linesDiff -ne 0 ] ; then | |
AlreadyModified="\t$f\n${AlreadyModified}" | |
fi | |
fi | |
done | |
if [ "XX" != "X${AlreadyModified}X" ] ; then | |
echo -e "Some affected files already modified. They'll need commiting first:\n$AlreadyModified" | |
exit 1 | |
fi | |
# Start actually changing things | |
echo "Ensuring affected files are ready for patching..." | |
cat "$FilenamesFile" | while read f ; do | |
if [ -f "$f" ] ; then | |
echo -e "\tPreparing $f" | |
dos2unix -q "$f" | |
fi | |
done | |
} | |
ApplyPatch() { | |
read -n 1 -p "Apply patch? y/n : " response | |
if [ "X${response}X" != "XyX" ] ; then | |
echo "" | |
exit 0 | |
fi | |
cd "$D2" | |
# Actually apply the patch | |
echo -e "\nPatching..." | |
patch -i "$PatchFile" -p 1 -F 10 -N | |
echo "Adding affected files to staged group..." | |
cat "$FilenamesFile" | while read f ; do | |
if [ -f "$f" ] ; then | |
echo -e "\t$f" | |
git add "$f" | |
fi | |
done | |
read -n 1 -p "Commit patch? y/n : " response | |
if [ "X${response}X" != "XyX" ] ; then | |
echo ". OK, not committing." | |
echo "Commit with git commit --file \"$LogFile\"" | |
exit 0 | |
fi | |
echo -e "\nCommitting..." | |
git commit --file "$LogFile" | |
echo "Done." | |
} | |
## | |
## MAIN | |
## | |
CmdName="$(basename $0)" | |
D1="" | |
D2="" | |
doGetPatch=1 | |
doApplyPatch=1 | |
commit="" | |
OPTIND=1 | |
while getopts "h?-gaGA1:2:" opt ; do | |
case "$opt" in | |
h|\?|-) | |
showHelp | |
exit 0 | |
;; | |
g) | |
doGetPatch=1 | |
;; | |
G) | |
doGetPatch=0 | |
;; | |
a) | |
doApplyPatch=1 | |
;; | |
A) | |
doApplyPatch=0 | |
;; | |
1) | |
D1="$(readlink -m ${OPTARG})" | |
;; | |
2) | |
D2="$(readlink -m ${OPTARG})" | |
;; | |
esac | |
done | |
shift $((OPTIND-1)) | |
[ "X${1}X" == "X--X" ] && shift | |
commit="$1" | |
if [ "X${commit}X" == "XX" ] ; then | |
showHelp | |
echo -e "ERROR: No commit supplied\n" | |
exit 1 | |
fi | |
checkRepo "$D1" "source" | |
checkRepo "$D2" "destination" | |
PatchFile="/tmp/${commit}.patch" | |
LogFile="/tmp/${commit}.log" | |
FilenamesFile="/tmp/${commit}.filenames" | |
StatusFileBefore="/tmp/${commit}-before-status.txt" | |
[ $doGetPatch -eq 1 ] && GetPatch | |
[ $doApplyPatch -eq 1 ] && ApplyPatch |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment