Created
December 22, 2023 13:34
-
-
Save coderxin/c5b341cd41e1d0ab52e5365ee270ad05 to your computer and use it in GitHub Desktop.
git-split: Script to duplicate a file while preserving git line history
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/sh | |
# Script to duplicate a file while preserving git line history | |
# | |
# This could be useful if you want two copies of a file, | |
# say, one where you are doing a bunch of disruptive work, | |
# and another that remains largely unchanged. The project continues to use the old, | |
# stable version, but there’s a feature flag to switch to the new one. | |
# Eventually, you’ll make the new one the default version. | |
# | |
# NOTE: Based on https://devblogs.microsoft.com/oldnewthing/20190919-00/?p=102904 | |
set -euo pipefail | |
usage() { | |
echo "Usage: git-split <originalFile> <copyName> [customCommitMessage]" | |
echo "Duplicate a file while preserving git line history" | |
echo "Optionally, provide custom commit message as explanation." | |
exit 1 | |
} | |
if [[ "$#" -lt 2 ]] || [[ "$#" -gt 3 ]]; then | |
usage | |
fi | |
originalFile=$1 | |
copyName=$2 | |
defaultCommitMsg="to preserve original file history (see: script/git-split)." | |
explanationCommitMsg=${3:-$defaultCommitMsg} | |
branchName=copy-with-history-$1 | |
# Method: Create a branch where the desired new file appears | |
# to have been created via a rename of the original file. | |
# And then restore the original file. | |
commit_message() { | |
if [ "$1" ]; then | |
echo "${1} $2" | |
else | |
echo "$2" | |
fi | |
} | |
# Extract XX-##### tag for commit messages | |
BRANCH_TAG=$(git rev-parse --abbrev-ref HEAD | grep -Eo '[A-Z]+-[0-9]+' || true) | |
# Create and switch to a branch | |
git checkout -b $branchName | |
# Make the duplicate of the original file | |
git mv $originalFile $copyName | |
summaryCommitMsg=$(commit_message "$BRANCH_TAG" "Duplicate $originalFile to $copyName") | |
git commit -m "$summaryCommitMsg" -m "$explanationCommitMsg" | |
# Bring back the original file | |
git checkout HEAD~ $originalFile | |
summaryCommitMsg=$(commit_message "$BRANCH_TAG" "Restore duplicated $originalFile") | |
git commit -m "$summaryCommitMsg" -m "$explanationCommitMsg" | |
# Switch back to the previous branch | |
# `-` (dash) is a special symbol that Git interprets | |
# as a reference to the previous branch you were working on. | |
git checkout - | |
# Merge created branch back into source | |
summaryCommitMsg=$(commit_message "$BRANCH_TAG" "Merge branch $branchName") | |
git merge --no-ff $branchName \ | |
-m "$summaryCommitMsg" -m "$explanationCommitMsg" | |
# Delete the branch | |
git branch -D $branchName |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment