Last active
February 13, 2024 03:54
-
-
Save dd32/9035a8ce5197735ff681cd73c456ddd2 to your computer and use it in GitHub Desktop.
svn ci --partial
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 | |
# | |
# 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 | |
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