Skip to content

Instantly share code, notes, and snippets.

@bholloway
Last active May 1, 2024 06:11
Show Gist options
  • Save bholloway/a72081a0bae7ca62c20afea1eb4e020d to your computer and use it in GitHub Desktop.
Save bholloway/a72081a0bae7ca62c20afea1eb4e020d to your computer and use it in GitHub Desktop.
Split a single file into multiple files in the directory

Git-spit

Split a single file into multiple files under a directory name based on the original.

Maintain git history.

Usage

prerequisites

Create a file names.txt that contains one line for each of the files that are the targets of the split.

  • Ensure there is a blank line at the end of file or the last entry will be ignored.
  • An index file is not automatically created, you will need to explicitly list it.

This is useful to retain. The merge commits produced by this script will not survive rebase and need to be recreated, meaning you will need to run the same command again in future.

command

git-split.sh some/file/path/name.ext "my commit message" < names.txt

The first argument is the file to split.

The second argument is the commit message.

The stdin stream is expected to be the names of the files that you wish to split into.

rebasing

Maintain a copy of your original branch.

  1. Reset your branch to the point preceding where the script commits begin.
  2. Rerun the script. This is where it is important to retain your names.txt.
  3. Cherry-pick any remaining commits from the original branch.
#!/usr/bin/env bash
set -e
Branch=`git rev-parse --abbrev-ref HEAD`
if [ "$Branch" = "main" ]; then
echo "Expected to be on a branch, cannot operate on \"main\"";
exit 1
fi
OriginalFilename=$1
if [ -f "${OriginalFilename}" ]; then
echo "Original: \"$OriginalFilename\""
else
echo "Expected an original filename"
exit 1
fi
RemFilename=$2
if [ -f "${RemFilename}" ]; then
echo "Removed: \"$RemFilename\""
else
echo "Expected an original filename"
exit 1
fi
CommitMessage=$3
if [ "${#CommitMessage}" -gt 1 ]; then
echo "Commit msg: \"$CommitMessage\""
else
echo "Expected a commit message"
exit 1
fi
Basename=`basename -- "$OriginalFilename"`
Directory=`dirname -- "$OriginalFilename"`
ShortName="${Basename%.*}"
Ext="${Basename##*.}"
if [ "${ShortName}" = "index" ]; then
NewDirectory="$Directory"
else
NewDirectory="$Directory/$ShortName"
fi
# last chance for user abort
echo "ShortName: \"$ShortName\""
echo "Extension: \".$Ext\""
echo "Directory: \"$NewDirectory\""
sleep 3
# make a temporary copy of the original file
TempFilename="$Directory/$ShortName-copy.$Ext"
git mv $OriginalFilename $TempFilename
git commit -m "$CommitMessage"
# now move the file back
git mv $TempFilename $OriginalFilename
git commit -m "$CommitMessage"
# save git ref that has this original state and reset to head
SavedGitRef=`git rev-parse HEAD`
git reset --hard HEAD^
# make the move
git mv $RemFilename $OriginalFilename
git commit -m "$CommitMessage"
# merge with the saved ref
# beware this systematically exists 1
git merge $SavedGitRef -m "$CommitMessage" || true
echo "!! manually resolve conflicts and amended the commit !!"
#!/usr/bin/env bash
set -e
Branch=`git rev-parse --abbrev-ref HEAD`
if [ "$Branch" = "main" ]; then
echo "Expected to be on a branch, cannot operate on \"main\"";
exit 1
fi
OriginalFilename=$1
if [ -f "${OriginalFilename}" ]; then
echo "Original: \"$OriginalFilename\""
else
echo "Expected an original filename"
exit 1
fi
CommitMessage=$2
if [ "${#CommitMessage}" -gt 1 ]; then
echo "Commit msg: \"$CommitMessage\""
else
echo "Expected a commit message"
exit 1
fi
Basename=`basename -- "$OriginalFilename"`
Directory=`dirname -- "$OriginalFilename"`
ShortName="${Basename%.*}"
Ext="${Basename##*.}"
if [ "${ShortName}" = "index" ]; then
NewDirectory="$Directory"
else
NewDirectory="$Directory/$ShortName"
fi
# last chance for user abort
echo "ShortName: \"$ShortName\""
echo "Extension: \".$Ext\""
echo "Directory: \"$NewDirectory\""
sleep 3
# Setup
{
mkdir -p $NewDirectory
} > /dev/null
echo "-------"
# Each line in the input
while IFS= read -r name; do
NewBasename=$name.$Ext
NewFilename="$NewDirectory/$NewBasename"
if [ -f "${NewFilename}" ]; then
echo "$NewFilename EXISTS"
continue
else
echo "$NewFilename"
fi
{
# make a temporary copy of the original file
TempFilename="$Directory/$ShortName-copy.$Ext"
git mv $OriginalFilename $TempFilename
git commit -m "$CommitMessage ($NewBasename)"
# save git ref that has this copy and reset to head
SavedGitRef=`git rev-parse HEAD`
git reset --hard HEAD^
# make the move
git mv $OriginalFilename $NewFilename
git commit -m "$CommitMessage ($NewBasename)"
# merge with the saved ref and resolve the conflicts with amended commit
# beware this systematically exists 1
git merge $SavedGitRef -m "$CommitMessage ($NewBasename)" || true
git commit -a -m "$CommitMessage ($NewBasename)" || true
# reinstate the original file from the temporary copy
git mv $TempFilename $OriginalFilename
git commit -m "$CommitMessage ($NewBasename)"
} > /dev/null
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment