Last active
January 7, 2019 06:44
-
-
Save borgand/5441827 to your computer and use it in GitHub Desktop.
A helper script to set *svn:mergeinfo* property when using `git svn dcommit` on merged git branches.This makes it possible to merge two SVN branches using **git-svn**.NB! the merged-from branch **MUST** be pushed to SVN.USAGE: git merge-svn <branch name>EDIT: added exit condition when mergeinfo calculation fails to avoid pushing incomplete merge…
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
#!/bin/bash | |
function usage { | |
echo "USAGE: git merge-svn <from> [<to>]" | |
echo "" | |
echo " from The branch name to be merged FROM" | |
echo " to Optional branch name to be merged onto. Default: HEAD" | |
echo "" | |
} | |
# CHANGE THIS: change this to match the SVN remote name | |
SVN_REMOTE_NAME=svn | |
# get svn base URL and remove username from it (if it's there) | |
SVN_BASE=$(git config svn-remote.$SVN_REMOTE_NAME.url | sed -e "s#//.*@#//#") | |
# Set FROM and TO from arguments | |
FROM=$1 | |
TO=$2 | |
# If FROM is not given, we can't really do anything | |
if [[ -z $FROM ]]; then | |
echo "ERROR: From branch not given" | |
usage | |
exit 1 | |
fi | |
# If TO is not given, calculate if from HEAD | |
if [[ -z $TO ]]; then | |
TO=$(git rev-parse --abbrev-ref HEAD) | |
fi | |
# ensure we are on TO | |
git checkout $TO > /dev/null 2>&1 | |
# Get current commit on FROM | |
LAST=$(git rev-parse $FROM) | |
# Get common ancestor | |
ANCESTOR=$(git merge-base $FROM $TO) | |
# if ancestor is last commit on FROM these two branches are already merged | |
# get previous ancestor to calculate MERGEINFO | |
if [[ $ANCESTOR == $LAST ]]; then | |
GIT_MERGED="true" | |
ANCESTOR=$(git merge-base $FROM "$TO~1") | |
fi | |
# Get some info to show | |
ANCESTOR_SVN_REV=$(git svn find-rev $ANCESTOR) | |
ANCESTOR_SHORT_REV=$(git rev-parse --short $ANCESTOR) | |
TO_SHORT_REV=$(git rev-parse --short $TO) | |
TO_SVN_REV=$(git svn find-rev $TO) | |
FROM_SHORT_REV=$(git rev-parse --short $FROM) | |
FROM_SVN_REV=$(git svn find-rev $FROM) | |
# Verify that FROM is dcommitted to SVN | |
if [[ -z $FROM_SVN_REV ]]; then | |
echo "Branch $FROM is not pushed (dcommitted) to SVN!" | |
echo "Aborting!" | |
exit | |
fi | |
# Nothing to do if git-merged and svn dcommitted | |
if [[ $GIT_MERGED == "true" && ! -z $TO_SVN_REV ]]; then | |
echo "Already up to date" | |
exit | |
fi | |
############### | |
# The real work | |
############### | |
# Parse merged commit messages for SVN revision number | |
NEWMERGEINFO=$(git log --reverse $ANCESTOR..$FROM | grep "git-svn-id" | tr -s ' ' | cut -f3 -d' ' | sed -e "s#$SVN_BASE##" | sed -e "s/@/:/") || exit 1 | |
# Get previous mergeinfo | |
OLDMERGEINFO=$(git svn propget svn:mergeinfo) | |
# Build new mergeinfo | |
if [[ $? == 0 ]]; then | |
MERGEINFO="$OLDMERGEINFO | |
$NEWMERGEINFO" | |
else | |
MERGEINFO="$NEWMERGEINFO" | |
fi | |
echo "About to do an SVN merge: $FROM -> $TO" | |
# Tweak graph depending on merge status | |
if [[ $GIT_MERGED == "true" ]]; then | |
echo " | |
* $TO [$TO_SHORT_REV] | |
|\\ | |
| * $FROM [$FROM_SHORT_REV] (r$FROM_SVN_REV)" | |
else | |
echo " | |
* NEW MERGE COMMIT | |
|\\ | |
| * $FROM [$FROM_SHORT_REV] (r$FROM_SVN_REV) | |
* | $TO [$TO_SHORT_REV] (r$TO_SVN_REV)" | |
fi | |
echo " \\| | |
* [$ANCESTOR_SHORT_REV] (r$ANCESTOR_SVN_REV) | |
" | |
echo -n "STEP 1: GIT merge " | |
if [[ -z $GIT_MERGED ]]; then | |
echo "" | |
echo "Executing: | |
git merge --no-ff $FROM" | |
echo | |
echo -n "Continue? (y/n) [n]: " | |
read ANSWER | |
if [[ $ANSWER == 'y' ]]; then | |
git merge --no-ff $FROM | |
echo "" | |
else | |
echo "Aborting!" | |
exit | |
fi | |
else | |
echo "(already up to date)" | |
fi | |
echo "STEP 2: SVN dcommit" | |
echo "" | |
echo "executing: | |
git svn dcommit --mergeinfo" | |
echo $MERGEINFO | |
echo "" | |
echo -n "Continue? (y/n) [n]: " | |
read ANSWER | |
if [[ $ANSWER == 'y' ]]; then | |
git svn dcommit --mergeinfo "$MERGEINFO" | |
else | |
echo "Aborting!" | |
exit | |
fi |
Another issue I found (which might be specific to just me): when the process is successful (no conflicts were produced), after the dcommit
, I'm not longer on any branch. Running git status
returns "Not currently on any branch."
I verified that the commit
and dcommit
were applied to the proper local and remote branches. Checking out the branch also shows the correct file updates. Any ideas why this would happen?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This looks like a great solution, but does not handle the case of merge conflicts. Is there any way to restart the process after merge conflicts are resolved?