I have got a central SVN repository I must commit to, but I've got a passion for git (like any other developer I know). The case is well known.
Then I read about git-svn and gave it a try. Since I don't need the full history, just from two months or so, I did like this:
git svn clone -r 34000 -s https://svn.ourdomain.com/svn/repos/Project/SubProject
SubProject had, as usual, the subdirectories trunk
, tags
and branches
. Great.
Then, in order to get the last revision, I did
git svn rebase
Some downloads later, great. Last revision, logs, etc. Ok, now I'll switch to my feature branch.
$ git branch
* master
$ git branch -r
trunk
$ git branch -a
* master
remotes/trunk
The questions are: Where are my branches? Have I done something wrong? How should I do in order to get my branches in the new git repo?
git-svn, wherever I have read about it, dealt wis开发者_StackOverflowely with branches and tags, but the behaviour is not what I expected. Thanks!
EDIT: I have just found out that git svn fetch
will do it. But it will get all revisions, which is something I wouldn't like.
You'll need several steps.
supply proper trunk, branches and tags folder names and fetch svn repo:
git svn init -t tags -b branches -T trunk https://mysvn.com/svnrepo git svn fetch
Since tags in svn are real branches, create git tags from tag branches:
git for-each-ref --format="%(refname:short) %(objectname)" refs/remotes/tags | cut -d / -f 3- | while read ref do echo git tag -a $ref -m 'import tag from svn' done
Delete tag branches
git for-each-ref --format="%(refname:short)" refs/remotes/tags | cut -d / -f 2- | while read ref do echo git branch -rd $ref done
Since tags marked in the previous step point to a commit "create tag", we need to derive "real" tags, i.e. parents of "create tag" commits.
git for-each-ref --format="%(refname:short)" refs/tags | while read ref do tag=`echo $ref | sed 's/_/./g'` # give tags a new name echo $ref -\> $tag git tag -a $tag `git rev-list -2 $ref | tail -1` -m "proper svn tag" done
All we have to do now is to remove old tags.
This draws on Vanuan's answer above, but it preserves the message of the original svn
tag in the new git
tag.
$ git for-each-ref --format="%(refname:short) %(objectname)" refs/remotes/tags \
| while read BRANCH REF
do
TAG_NAME=${BRANCH#*/}
BODY="$(git log -1 --format=format:%B $REF)"
echo "ref=$REF parent=$(git rev-parse $REF^) tagname=$TAG_NAME body=$BODY" >&2
git tag -a -m "$BODY" $TAG_NAME $REF^ &&\
git branch -r -d $BRANCH
done
This is the same as nicolai.rostov's answer above, but i just change the refs path
I replaced refs/remotes/tags
by refs/remotes/origin/tags
I'm using git version 2.1.1
into cygwin
terminal.
$ git for-each-ref --format="%(refname:short) %(objectname)" refs/remotes/origin/tags \
| while read BRANCH REF
do
TAG_NAME=${BRANCH#*/}
BODY="$(git log -1 --format=format:%B $REF)"
echo "ref=$REF parent=$(git rev-parse $REF^) tagname=$TAG_NAME body=$BODY" >&2
git tag -a -m "$BODY" $TAG_NAME $REF^ &&\
git branch -r -d $BRANCH
done
You say that you haven't gotten your branches in your checkout.
This is likely a problem with the layout of your svn repo.
The 'standard layout' is:
branches/
tags/
trunk/
If you have your layout like this:
branches/user1/
branches/user2/
Then, you will lose your branches when you do git svn fetch / clone.
To fix this, you should give the argument
--branches=branches/*/*
to git clone.
I wrote a script to help migrate as you want. The script is not perfect, but I hope this could help you:
For more information, you can visit: https://github.com/MPDFT/svn-to-git
#!/bin/bash
####### Project name
PROJECT_NAME="myproject"
EMAIL="mycompany.com"
###########################
####### SVN
# SVN repository to be migrated
BASE_SVN="http://svn.mycompany.com/svn/repo/sistemas/myproject"
# Organization inside BASE_SVN
BRANCHES="branches"
TAGS="tags"
TRUNK="trunk"
###########################
####### GIT
# Git repository to migrate
GIT_URL="https://git.mycompany.com/git/repo/sistemas/myproject.git"
###########################
#### Don't need to change from here
###########################
# Geral Configuration
ABSOLUTE_PATH=$(pwd)
TMP=$ABSOLUTE_PATH/"migration-"$PROJECT_NAME
# Branchs Configuration
SVN_BRANCHES=$BASE_SVN/$BRANCHES
SVN_TAGS=$BASE_SVN/$TAGS
SVN_TRUNK=$BASE_SVN/$TRUNK
AUTHORS=$PROJECT_NAME"-authors.txt"
echo '[LOG] Starting migration of '$SVN_TRUNK
echo '[LOG] Using: '$(git --version)
echo '[LOG] Using: '$(svn --version | grep svn,)
mkdir $TMP
cd $TMP
echo
echo '[LOG] Getting authors'
svn log -q $BASE_SVN | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2"@"$EMAIL">"}' | sort -u >> $AUTHORS
echo
echo '[RUN] git svn clone --authors-file='$AUTHORS' --trunk='$TRUNK' --branches='$BRANCHES' --tags='$TAGS $BASE_SVN $TMP
git svn clone --authors-file=$AUTHORS --trunk=$TRUNK --branches=$BRANCHES --tags=$TAGS $BASE_SVN $TMP
echo
echo '[LOG] Getting first revision'
FIRST_REVISION=$( svn log -r 1:HEAD --limit 1 $BASE_SVN | awk -F '|' '/^r/ {sub("^ ", "", $1); sub(" $", "", $1); print $1}' )
echo
echo '[RUN] git svn fetch -'$FIRST_REVISION':HEAD'
git svn fetch -$FIRST_REVISION:HEAD
echo
echo '[RUN] git remote add origin '$GIT_URL
git remote add origin $GIT_URL
echo
echo '[RUN] svn ls '$SVN_BRANCHES
for BRANCH in $(svn ls $SVN_BRANCHES); do
echo git branch ${BRANCH%/} remotes/svn/${BRANCH%/}
git branch ${BRANCH%/} remotes/svn/${BRANCH%/}
done
git for-each-ref --format="%(refname:short) %(objectname)" refs/remotes/origin/tags | grep -v "@" | cut -d / -f 3- |
while read ref
do
echo git tag -a $ref -m 'import tag from svn'
git tag -a $ref -m 'import tag from svn'
done
git for-each-ref --format="%(refname:short)" refs/remotes/origin/tags | cut -d / -f 1- |
while read ref
do
git branch -rd $ref
done
echo
echo '[RUN] git push'
git push origin --all --force
git push origin --tags
echo 'Sucessufull.'
If you want to see your branches when doing a git branch after a import from svn, you should use the ruby script svn2git (and git2svn)
It is better than git svn clone because if you have this code in svn:
trunk
...
branches
1.x
2.x
tags
1.0.0
1.0.1
1.0.2
1.1.0
2.0.0
git-svn
will go through the commit history to build a new git repo.
It will import all branches and tags as remote SVN branches, whereas what you really want is git-native local branches and git tag objects. So after importing this project, you would get:
$ git branch
* master
$ git branch -a
* master
1.x
2.x
tags/1.0.0
tags/1.0.1
tags/1.0.2
tags/1.1.0
tags/2.0.0
trunk
$ git tag -l
[ empty ]
After svn2git
is done with your project, you'll get this instead:
$ git branch
* master
1.x
2.x
$ git tag -l
1.0.0
1.0.1
1.0.2
1.1.0
2.0.0
For those who have to work on Windws at work, here is a solution up-to-date with git version 2.17.0 (and theoretically also works for versions before)
git svn init -t tags -b branches -T trunk https://mysvn.com/svnrepo
git svn fetch
for /f "tokens=1-2 delims= " %a in ('git for-each-ref --format="%(refname:lstrip=-1) %(objectname)" refs/remotes/origin/tags') do git tag -a %a %b -m "import tag from svn"
I had the same problem - tags and branches were missing when I specified the revision:
$ git svn clone -r 34000 -s https://...
The fix was to specifiy a range of revisions, -r 34000:HEAD
:
$ git svn clone -r 34000:HEAD -s https://...
The git mailing list gave me the hint.
To pull a new SVN branch into your local Git-SVN repository, I've found an easy method, which does not require editing any config files or so.
You only need the revision number of the last commit in the branch that you want to add to your local git-svn repository.
If you have an up-to-date SVN checkout of the new branch and TortoiseSVN installed, you can right-click on this folder and use "TortoiseSVN / Show Log".
Make a note of the topmost commit (e.g. 45065).
Now use in Git Bash the following command:
git svn fetch -r45065
NOTE: You need to replace the number 45065
against your commit number.
git will now pull the new remote branch into your local repository.
You can then check it out with creating a local Branch. I'm using Git Extension for checking out the new branch, using "Remote-Branch" and the option "Create local branch with name: ...".
Hint: You can remove the "origin/" prefix from your local branch name, as this avoids the warning "refname 'origin/V8.0' is ambiguous.".
精彩评论