Last active
August 16, 2024 07:07
-
-
Save dd32/8b38750e1c1b80b3a00663be00f62058 to your computer and use it in GitHub Desktop.
svn-ci-partial, Commit a partial SVN tree.
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 | |
# SVN ci partial support | |
# | |
# See https://gist.github.com/dd32/8b38750e1c1b80b3a00663be00f62058 | |
# | |
# This script can be enabled with a `svn()` wrapper defined in your profile. | |
# | |
# Props need to go to authors who have attempted this in the past, particularly to | |
# Karljohan Lundin Palmerius for his work with using kompare: | |
# https://www.itn.liu.se/~karlu20/div/blog/2013-05-31_SVNPartialCommit.php | |
# | |
# This script is based on the same idea, but uses a CLI staging function, similar to git. | |
# This has been written from scratch, with the aid of VSCode AI auto-complete. | |
# | |
########## | |
# WARNING: Use at your own risk. This may cause data loss. Always backup your work. | |
########## | |
verbose="1" | |
while getopts v flag; do | |
case "${flag}" in | |
v) verbose=1; | |
esac | |
done | |
shift $(($OPTIND - 1)) | |
paths="$@" | |
function error() { | |
echo "$1" >&2 | |
exit 1 | |
} | |
function debug() { | |
if [[ -n "$verbose" ]]; then | |
echo "DEBUG: $1" >&2 | |
fi | |
} | |
function early_exit() { | |
echo -n "Caught signal, files in $TMP_FOLDER left alone, restoring working copy, ... " | |
restore_working_copy "keep" | |
error "Done." | |
} | |
function restore_working_copy() { | |
cp -r $TMP_FOLDER/* . || error "Couldn't restore unstaged changes. You'll find your files in $TMP_FOLDER" | |
if [[ "$1" == "delete" ]]; then | |
rm -r $TMP_FOLDER || error "Couldn't remove temporary directory." | |
fi | |
} | |
function do_compare_and_patch { | |
CHANGES=$1 | |
CLEAN=$2 | |
IFS=$'\n' DIFF_LINES=( $(diff -U3 $CLEAN $CHANGES) ) | |
chunks=() | |
chunk=-1 | |
for line in "${DIFF_LINES[@]}"; do | |
if [[ $line =~ ^@@ ]]; then | |
chunk=$((chunk+1)) | |
chunks[$chunk]="" | |
fi; | |
if [[ $chunk == "-1" ]]; then | |
# Headers. | |
echo $line | colordiff --color=always | |
else : | |
chunks[$chunk]+="$line"$'\n' | |
fi | |
done | |
diff_to_apply="" | |
for chunk in "${chunks[@]}"; do | |
echo "$chunk" | colordiff | |
# Do we want to stage this chunk? | |
stage="" | |
while [[ "$stage" != "y" && "$stage" != "n" ]]; do | |
read -p "Stage this chunk? (y/n) " stage | |
done | |
if [[ "$stage" == "y" ]]; then | |
echo "Staging chunk" | |
diff_to_apply+="$chunk" | |
fi | |
done | |
if [[ -n "$diff_to_apply" ]]; then | |
echo "Applying diff to $CLEAN" | |
patch $CLEAN <<< "$diff_to_apply" || error "Couldn't apply patch!!!!" | |
fi | |
} | |
debug "Pre-check; Checking for svn working copy" | |
svn info $paths > /dev/null 2>&1 || error "SVN Working Copy not detected." | |
debug "Pre-check; Is paths relative?" | |
[[ "$paths" = *..* ]] && error "Paths must be relative to the working copy." | |
debug "Finding modified files." | |
MODIFIED_FILES=`svn st $paths -qu 2>/dev/null | grep "^M" --color=none | sed -E "s/^M\s+[0-9]+\s+//g"` | |
NEW_FILES=`svn st $paths -qu 2>/dev/null | grep "^A" --color=none | sed -E "s/^A\s+-\s+//g"` | |
if [ -z "$MODIFIED_FILES" ]; then | |
error "No modified files detected." | |
elif [[ "$MODIFIED_FILES" =~ '*' ]]; then | |
echo "Out of date files detected. Please check these files:" | |
grep -E "^M\s*" --color=none <<< "$MODIFIED_FILES" | sed -E 's/^M\s+\*\s+[0-9]+\s+/ - /g' | |
error; | |
fi | |
debug "Create a backup folder, and copy modified files to it." | |
TMP_FOLDER=`mktemp -d svn-ci-partial-XXXXX` | |
debug "Temporary folder: $TMP_FOLDER" | |
trap early_exit INT TERM | |
cp --parents $MODIFIED_FILES $TMP_FOLDER || error "Couldn't move files" | |
debug "Cleaning svn working copy." | |
svn revert $MODIFIED_FILES > /dev/null 2> /dev/null || error "Couldn't revert files" | |
debug "Comparing files..." | |
for path in $MODIFIED_FILES; do | |
do_compare_and_patch "$TMP_FOLDER/$path" "./$path" | |
done | |
svn st $paths | |
view_diff="" | |
while [[ "$view_diff" != "y" && "$view_diff" != "n" ]]; do | |
read -p "Review the Diff before commit? (y/n) " view_diff | |
done | |
if [[ "$view_diff" == "y" ]]; then | |
svn diff $MODIFIED_FILES $NEW_FILES | colordiff --color=always | less -RS | |
read -p "Enter to proceed with commit. Control+C otherwise." | |
fi | |
debug "svn ci..." | |
svn ci $MODIFIED_FILES $NEW_FILES || error "Commit Aborted." | |
debug "Restoring working copy." | |
restore_working_copy "delete" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment