…For those not using RHEL8 (or similar) - you may be interested in this script.
It uses RCS; being a simple versions control system which exists on many distros/repos.
apt-get install rcs
which is a tiny package!
I have scripted the basic use-cases, which could be used to version control any file you may have. While RCS relies on subdirectories (./RCS) the below uses a central directory and creates a symlink instead - this way all of the version data is kept in 1 place (opposed to scattered around your drive).
I include the below for anybody who may be interested in version controlling their files, but doesn’t want the bother of installing something like GIT (you lucky things!
) - but I don’t intent to maintain this any further, and I’ve therefore added a few extra comments to aid those who may find it useful.
NB: I’m not suggesting it’s 100%, but based on my own basic tests it showed promise…
examples:
brian000s_vc_script.sh add /etc/fstab
This will create a new directory within ${rcsdir} called “etc” which is symlinked to “/etc/RCS” - adding this initial version to it.
After making changes, run:
brian000s_vc_script.sh lock /etc/fstab
brian000s_vc_script.sh update /etc/fstab
Which will apply the new changes (perhaps you’d consider merging those two into one statement!).
To view the revision history:
brian000s_vc_script.sh version /etc/fstab
If you find yourself changing multiple files at the same time:
brian000s_vc_script.sh bulk
this will version control (creating new revisions, or updating existing ones) for any thing changed “today”
For more info please refer to the script below…
Hope this helps somebody…
#!/bin/sh
##X-ref: http://linuxforums.org.uk/index.php?topic=14199.0
CI=`which ci`
CO=`which co`
RCS=`which rcs`
RCSDIFF=`which rcsdiff`
RLOG=`which rlog`
DIRNAME=`which dirname`
dollar=$
success=0
today=$(date +"%Y-%m-%d")
##update as required!
user=`whoami`.`hostname -s`
rcsdir=/shared/RCS
rcsdirtmp=${rscdir}/tmp
_HELP() {
echo "#########################################################"
echo "File: ${0}"
echo "$Id:$"
echo "$Source:$"
echo "#########################################################"
echo "Purpose: Use RCS for version control"
echo " This uses symlinks saving revisions to 'rcsdir'"
echo "#########################################################"
echo "Known Issue or Risk:"
echo " Limited testing - may contain errors"
echo " RCS removes the file after it's created, so this performs a 'get' after"
echo " 'Bulk' may encounter issues where the revision is locked"
echo " During development, I lost a few test file, so a copy of the original script is saved to 'rcsdirtmp'"
echo " RCS doesn't seem to permit un/lock with a specific user - so 'user' may not be fully functional"
echo "#########################################################"
echo ""
echo "checkout - Bookout and lock the latest revision"
echo " ${0} checkout <file>"
echo ""
echo "bulk - Batch add/update all changes made <today>"
echo " ${0} bulk"
echo ""
echo "diff - Get differences between the file and latest revision"
echo " ${0} diff <file>"
echo ""
echo "get - Bookout and unlock the latest revision"
echo " ${0} get <file>"
echo ""
echo "header - Check file for inclusion of the version detail parameters"
echo " ${0} header <file>"
echo ""
echo "help - View this text"
echo ""
echo "lock - Lock a file for changes (will leave the file unchanged)"
echo " ${0} lock <file>"
echo ""
echo "new - add a new file; which includes the 'get' and 'header' actions"
echo " ${0} new <file>"
echo ""
echo "unlock - Release a Lock from a file (will leave the file unchanged)"
echo " ${0} unlock <file>"
echo ""
echo "update - Push changes to version control"
echo " ${0} update <file>"
echo ""
echo "version - view revision history for a specific file"
echo "ver - synonym for 'version'"
echo " ${0} version <file>"
echo " ${0} ver <file>"
echo ""
echo "#########################################################"
}
_LOG() {
##Consider logging instead of just "echo"!
if [ ! "${1}" = "" ]; then
echo ${1}
fi
}
_Success() {
##Log and report failures.
##${success} holds the greatest of any errors.
if [ ${1} -eq 0 ]; then
_LOG "${2} - ${3} Successful."
else
_LOG "${2} - Unexpected Error(${1}): ${3}."
if [ ${success} -lt ${1} ]; then
success=${1}
fi
fi
}
_Bulk() {
##Add/Update all files in the current directory into RCS.
### not 100% - issues around when the file is locked.
message="Bulk update ${today}"
description="Created via Bulk"
for file in `find . -maxdepth 1 -newermt "${today}"`; do
##disrgared old errors
success=0
##Does the file needs to added or (locked and) updated?
if [ -f "${file}" ]; then
_TestInputFile "${file}"
if [ ${success} -eq 0 ]; then
##Use LOG to establish if the file already exists (and therefore needs to updated)
${RCS} log "${dirname}/${basename}" >> /dev/nul 2>>/dev/nul
if [ ${?} -eq 0 ]; then
_LOG "Processing: '${dirname}/${basename}' (update)"
## remember to lock the file before an update
lock=-l
_LOCK
_UPDATE
else
##If it's not an update, it needs to be added.
_LOG "Processing: '${dirname}/${basename}' (new)"
_NEW
if [ ${success} -eq 0 ]; then
lock=-u
_CHECKOUT
fi
fi
fi
else
##RCS does not handle directories...
_LOG "${file} is not a file (or was not found)."
fi
done
}
_CheckHeader() {
##Capture those files which shoud have variables but don't
if [ ! "`grep \#\!/bin/ ${dirname}/${basename}`" ]; then
_LOG "Consider adding '#!/bin/sh'"
fi
##use ${dolar} to stop RCS from expanding them, mistaking them for it's own parameters!
if [ ! "`grep \${dollar}Id ${dirname}/${basename}`" ]; then
_LOG "Consider adding '${dollar}Id:${dollar}' and ${dollar}Source:${dollar}'"
fi
}
_TestInputFile() {
##build the target directory based on in the input filename
cd `${DIRNAME} ${1}`
basename=`basename ${1}`
dirname=${PWD}
if [ ! -f "${dirname}/${basename}" ]; then
_Success 9 "${dirname}/${basename}" "Input file not found"
fi
}
_MKRCSDIR() {
##Create symlink for the RCS directory.
##Nb: to bypass this, simply manually create the RCS directory as required.
if [ -d "${dirname}/RCS" ]; then
_LOG "RCS subdirectory already exists."
else
##Create the "tmp" direcory too
if [ ! -d "${rcsdirtmp}" ]; then
mkdir -p "${rcsdirtmp}"
fi
##to use a local RCS direcory, simply create the directory first
##translate characters because the path will become the directory name
rcsloc=`echo "${dirname}" | tr "/ " __`
_LOG "Making RCS subdirectory - ${rcsloc}"
mkdir -p "${rcsdir}/${rcsloc}"
if [ ${?} -ne 0 ]; then
_Success 9 "${rcsdir}/${rcsloc}" "Unable to create RCS directory"
fi
##Create the symlink.
ln -s "${rcsdir}/${rcsloc}" "${dirname}/RCS"
if [ ${?} -ne 0 ]; then
_Success 9 "${dirname}/RCS" "Failed to create SymLink"
fi
fi
}
_BackupSource() {
#take a copy of the file before we start.
#these are not required, but will save the file in the event of errors
if [ "${backup}" = "" ]; then
cp -f "${dirname}/${basename}" "${rcsdirtmp}/${basename}"
_Success ${?} "${basename}" "Copied to 'tmp'"
backup=no
fi
}
_NEW() {
##Check that the RSC directory exists (or create it)
_MKRCSDIR
if [ ${success} -ne 0 ]; then
_LOG "Failed to make RCS directory."
exit 9
fi
##Take a backup of the source file
_BackupSource
##Add a new file (also called from _Bulk - which passes the message and description)
if [ "${message}" = "" ]; then
${CI} -T -i -w${user} ${dirname}/${basename}
else
${CI} -T -i -w${user} -m"${message}" -t-"${description}" ${dirname}/${basename}
fi
_Success ${?} ${basename} "Add to version control"
}
_LOCK() {
##Lock the file - required before updating the revision
${RCS} ${lock} ${dirname}/${basename}
_Success ${?} ${basename} "Lock"
}
_UPDATE() {
##Take a backup of the source file
_BackupSource
##Add a new file (also called from _Bulk - which passes the message and description)
if [ "${message}" = "" ]; then
${CI} -T -u -w${user} ${dirname}/${basename}
else
${CI} -T -u -w${user} -m"${message}" -t-"${description}" ${dirname}/${basename}
fi
_Success ${?} ${basename} "Update"
}
_CHECKOUT() {
##Get the latest revision.
_BackupSource
${CO} -T -w${user} ${lock} ${dirname}/${basename}
_Success ${?} ${basename} "Check out"
}
_VERSION() {
##display the revision details
${RLOG} -b ${dirname}/${basename}
}
_DIFF() {
##Display a difference between the file and latest revision
${RCSDIFF} ${dirname}/${basename}
}
#############################################
if [ "${RCS}" = "" ]; then
echo "RCS doesn't appear to exist on this system!"
exit 9
elif [ "${1}" = "help" ]; then
_HELP
elif [ "${1}" = "bulk" ]; then
_LOG ""
else
_TestInputFile "${2}"
if [ ${success} -ne 0 ]; then
_LOG "Unable to process file '${2}'."
exit 9
fi
fi
#############################################
if [ "${1}" = "bulk" ]; then
_Bulk
elif [ "${1}" = "header" ]; then
_CheckHeader
elif [ "${1}" = "checkout" ]; then
lock=-l
_CHECKOUT
elif [ "${1}" = "diff" ]; then
_DIFF
elif [ "${1}" = "get" ]; then
lock=-u
_CHECKOUT
elif [ "${1}" = "lock" ]; then
lock=-l
_LOCK
elif [ "${1}" = "new" ]; then
_NEW
if [ ${success} -eq 0 ]; then
lock=-u
_CHECKOUT
_CheckHeader
fi
elif [ "${1}" = "unlock" ]; then
lock=-u
_LOCK
elif [ "${1}" = "update" ]; then
_UPDATE
elif [ "${1}" = "ver" ] || [ "${1}" = "version" ]; then
_VERSION
fi