Skip to content

Instantly share code, notes, and snippets.

@ric-evans
Last active December 20, 2023 17:14
Show Gist options
  • Save ric-evans/aa55b6d054ef1fae9464b992631aa90d to your computer and use it in GitHub Desktop.
Save ric-evans/aa55b6d054ef1fae9464b992631aa90d to your computer and use it in GitHub Desktop.
Copy a file or directory while preserving git line history
#!/bin/bash
# set -x # turn on debugging
set -e # exit on fail
########################################################################
#
# Copy a file or directory while preserving git line history
# Manually trim the files after to accomplish a split!
#
# Note: This script makes several commits to the current branch.
# If you squash-merge these commits, line history will not be
# preserved.
#
########################################################################
if [ -z "$1" ] || [ -z "$2" ]; then
echo "Usage: $(basename "$0") ORIGNAL_FILE NEW_FILE"
exit 1
fi
orig="$1"
copy="$2"
temp="temp"
# append "/" if these are dirs -- really, just needed for commit message(s)
if [ -d "$1" ]; then
if [[ $orig != */ ]]; then
orig="$orig/"
fi
if [[ $copy != */ ]]; then
copy="$copy/"
fi
temp="temp/"
fi
git mv $orig $copy
git commit -m "[duplicating \`$orig\` (1/4)]"
echo "---"
SAVED=`git rev-parse HEAD`
git reset --hard HEAD^
git mv $orig $temp
git commit -m "[duplicating \`$orig\` (2/4)]"
echo "---"
# this will show:
# CONFLICT (rename/rename): <FILE1> renamed to <pkg>/temp in HEAD and to <FILE2> in <commit-sha>.
# Automatic merge failed; fix conflicts and then commit the result.
# this is okay.
git merge $SAVED &> /dev/null || true
git commit -a -m "[duplicating \`$orig\` (3/4)]"
echo "---"
git mv $temp $orig
git commit -m "Duplicated \`$orig\` to \`$copy\` with git line history" # last commit gets nice msg
echo "---"
echo "ready for manual trimming!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment