Created
March 8, 2024 09:43
-
-
Save jwarkentin/0cd53beda345afde53cf1464237f7f32 to your computer and use it in GitHub Desktop.
Migrate stashes and branches from an old git repo to a new clone
This file contains 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
#!/usr/bin/env bash | |
TMP_SRC_REMOTE="git-stash-copy-source" | |
TMP_TARGET_REMOTE="git-stash-copy-target" | |
FROMDIR="$( cd "$1" && pwd )" | |
TODIR="$( cd "$2" && pwd )" | |
if ! cd "$FROMDIR" && git rev-parse --git-dir 2> /dev/null ; then | |
echo "Error: \"$FROMDIR\" is not a git repository" | |
exit 1 | |
fi | |
if ! cd "$TODIR" && git rev-parse --git-dir 2> /dev/null ; then | |
echo "Error: \"$TODIR\" is not a git repository" | |
exit 1 | |
fi | |
UNTRACKED_FILES="$(git -C "$TODIR" ls-files --others --exclude-standard | wc -l)" | |
UNSTAGED_FILES="$(git -C "$TODIR" diff --name-only | wc -l)" | |
STAGED_FILES="$(git -C "$TODIR" diff --cached --name-only | wc -l)" | |
if [ $UNTRACKED_FILES -gt 0 ] || [ $UNSTAGED_FILES -gt 0 ] || [ $STAGED_FILES -gt 0 ]; then | |
echo "Error: \"$TODIR\" has uncommitted changes" | |
exit 1 | |
fi | |
printf "From Dir: $FROMDIR\nTo Dir: $TODIR\n" | |
read -p "Continue? [Y/n] " -n 1 -r | |
printf "\n" | |
if [[ ! $REPLY =~ ^[Yy]$ ]]; then | |
exit 1 | |
fi | |
printf "\n" | |
echo "Adding old repository as temporary remote \"$TMP_SRC_REMOTE\"" | |
git -C "$TODIR" remote add $TMP_SRC_REMOTE "$FROMDIR" > /dev/null 2>&1 | |
CURRENT_BRANCH="$(git -C "$TODIR" branch --show-current)" | |
CURRENT_HASH="$(git -C "$TODIR" rev-parse HEAD)" | |
CURRENT_REF=$([[ -z "$CURRENT_BRANCH" ]] && echo "$CURRENT_HASH" || echo "$CURRENT_BRANCH") | |
NUM_STASHES="$(git -C "$FROMDIR" stash list | wc -l)" | |
for i in $(seq $(($NUM_STASHES - 1)) 0); do | |
printf "\n" | |
echo "Copying stash@{$i}" | |
STASH_MSG="$(git -C "$FROMDIR" log --format=%B -n 1 stash@{$i})" | |
PARENT_COMMIT="$(git -C "$FROMDIR" rev-parse stash@{$i}^)" | |
PATCH="$(git -C "$FROMDIR" stash show -p stash@{$i})" | |
# git -C "$TODIR" checkout "$PARENT_COMMIT" > /dev/null 2>&1 | |
if ! git -C "$TODIR" checkout "$PARENT_COMMIT" > /dev/null 2>&1 ; then | |
echo "Could not find parent commit in local copy. Fetching from remote." | |
if ! git -C "$TODIR" -c uploadpack.allowReachableSHA1InWant fetch --depth=1 $TMP_SRC_REMOTE "$PARENT_COMMIT" ; then | |
echo "Error: Could not fetch from remote. Skipping stash." | |
else | |
git -C "$TODIR" checkout "$PARENT_COMMIT" > /dev/null 2>&1 || exit 1 | |
fi | |
fi | |
echo "$PATCH" | git -C "$TODIR" apply | |
git -C "$TODIR" add . | |
git -C "$TODIR" stash save -m "$STASH_MSG" | |
done | |
git -C "$TODIR" checkout "$CURRENT_REF" > /dev/null 2>&1 | |
printf "\n" | |
echo "Deleting temporary remote \"$TMP_SRC_REMOTE\"" | |
git -C "$TODIR" remote remove $TMP_SRC_REMOTE | |
printf "\n" | |
read -p "Would you like to copy your branches? [Y/n] " -n 1 -r | |
printf "\n" | |
if [[ $REPLY =~ ^[Yy]$ ]]; then | |
echo "Adding new repository as temporary remote \"$TMP_TARGET_REMOTE\"" | |
git -C "$FROMDIR" remote add $TMP_TARGET_REMOTE "$TODIR" > /dev/null 2>&1 | |
BRANCHES="$(git -C "$FROMDIR" for-each-ref --format='%(refname:short)' refs/heads/)" | |
echo "$BRANCHES" | |
for BRANCH in $BRANCHES; do | |
if [[ $BRANCH != "main" && $BRANCH != "master" ]]; then | |
printf "\n" | |
echo "Copying branch \"$BRANCH\"" | |
git -C "$FROMDIR" push $TMP_TARGET_REMOTE "$BRANCH" | |
fi | |
done | |
echo "Deleting temporary remote \"$TMP_TARGET_REMOTE\"" | |
git -C "$FROMDIR" remote remove $TMP_TARGET_REMOTE | |
fi | |
printf "\n" | |
echo "Done." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
After downloading the file, usage is simple:
Relative paths are fine. It will prompt to confirm before starting and ask whether you want to copy branches or just copy stashes.