기존 Git 저장소를 SVN으로 푸시


384

나는 Git에서 모든 작업을 수행하고 GitHub로 추진했다. 소프트웨어와 사이트 모두에 매우 만족했으며이 시점에서 작업 방식을 바꾸고 싶지 않습니다.

저의 PhD 고문은 모든 학생들에게 대학에서 주최하는 SVN 저장소에서 작업을 유지하도록 요청하고 있습니다. 기존 SVN 저장소를 Git으로 가져 오는 것에 대한 수많은 문서와 자습서를 찾았지만 Git 저장소를 새로운 SVN 저장소로 푸시하는 것에 대해서는 아무것도 없습니다. 나는 git-svn과 신선한 브랜치 및 rebasing 및 모든 훌륭한 용어를 조합 하여이 작업을 수행 할 수있는 방법이 있어야한다고 생각하지만, Git 초보자이며 그 중 어느 것에도 자신감이 없습니다.

그런 다음 선택할 때 SVN 저장소에 커밋을 푸시하는 몇 가지 명령을 실행하고 싶습니다. Git을 계속 사용하고 SVN 저장소에 Git의 내용을 반영하고 싶습니다.

이것이 SVN에 헌신하는 유일한 사람이 될 것입니다.


1
참고 : 이렇게하면 원래 날짜-스탬프가 손실 될 수 있습니다. 새로운 날짜는 Subversion으로 가져 오기 한 시간을 기준으로합니다.
nobar

일부 자동화에 대한 그들의 검색하는 동안 다음과 같은 포스트 도움을 찾을 수 있습니다 최신 정보를 찾는 사람들을 위해 : deliciousbrains.com/deploying-wordpress-plugins-travis
조쉬 Habdas

답변:


402

나는 이것도 필요했고 Bombe의 대답과 주변의 도움으로 도움이되었습니다. 레시피는 다음과 같습니다.

가져 오기 힘내-> Subversion

1. cd /path/to/git/localrepo
2. svn mkdir --parents protocol:///path/to/repo/PROJECT/trunk -m "Importing git repo"
3. git svn init protocol:///path/to/repo/PROJECT -s
4. git svn fetch
5. git rebase origin/trunk
5.1.  git status
5.2.  git add (conflicted-files)
5.3.  git rebase --continue
5.4.  (repeat 5.1.)
6. git svn dcommit

# 3 후에 다음과 같은 암호 메시지가 나타납니다.

더 높은 수준의 URL 사용 : protocol:///path/to/repo/PROJECT => protocol:///path/to/repo

그냥 무시해

# 5를 실행 하면 충돌 이 발생할 수 있습니다. 상태가 "병합되지 않음"인 파일을 추가하고 rebase를 다시 시작하여이를 해결하십시오. 결국, 당신은 끝날 것입니다; 을 사용하여 SVN 저장소로 다시 동기화하십시오 dcommit. 그게 다야.

리포지토리 동기화

다음 명령을 사용하여 SVN에서 Git으로 동기화 할 수 있습니다.

git svn fetch
git rebase trunk

Git에서 SVN으로 동기화하려면 다음을 사용하십시오.

git svn dcommit

최종 메모

라이브 저장소에 적용하기 전에 로컬 사본에서이를 시도 할 수 있습니다. Git 저장소의 사본을 임시 위치에 만들 수 있습니다. cp -r모든 데이터가 저장소 자체에 있으므로 간단히 사용 하십시오. 그런 다음 다음을 사용하여 파일 기반 테스트 저장소를 설정할 수 있습니다.

svnadmin create /home/name/tmp/test-repo

다음을 사용하여 작업 복사본을 확인하십시오.

svn co file:///home/name/tmp/test-repo svn-working-copy

그것은 당신이 지속적인 변화를하기 전에 사물을 가지고 놀 수있게 해줍니다.

부록 : 엉망인 경우 git svn init

실수로 git svn init잘못된 URL 로 실행 하고 작업을 백업 할만큼 똑똑하지 않은 경우 (요청하지 않음) 동일한 명령을 다시 실행할 수 없습니다. 그러나 다음을 발행하여 변경 사항을 취소 할 수 있습니다.

rm -rf .git/svn
edit .git/config

섹션 [svn-remote "svn"]섹션을 제거 하십시오.

그런 다음 git svn init새로 실행할 수 있습니다 .


2
좋은 대답입니다. 커밋 날짜도 엉망입니까?
Drew Noakes

4
좋은 질문-불행히도, 나도 그 답을 모른다. 이것은 내가 찾은 것에 대한 실용적인 지침입니다. 모든 세부 사항을 완전히 이해하지 못했습니다. 커밋 날짜와 관련하여 테스트를하고 찾을 수 있다고 생각합니다. 테스트를 위해 로컬 (fs 기반) svn 저장소를 초기화 할 수 있습니다.
troelskn

10
5 단계 대신 "git rebase --onto trunk --root"를 사용하여 동일한 단계를 수행했으며 훨씬 더 많은 성공을 거두었습니다. 톤 대신 소수의 병합 충돌 만 해결할 수 있습니다.
kubi

5
제 경우에는이 시퀀스가 ​​작동하지 않았습니다. "HEAD 히스토리에서 업스트림 SVN 정보를 판별 할 수 없습니다"라는 메시지가 항상 표시되었습니다. 따라서 dcommit이 불가능합니다.
Fedir RYKHTIK

2
SVN 표준 설정 (트렁크 / 브랜치 / 태그 /)을 따르고 싶지 않기 때문에 똑똑해지기 위해 -s를 생략하려고했습니다. 그것 없이는 전혀 작동하지 못했습니다.
James McMahon

33

작동 방식은 다음과 같습니다.

머신의 어딘가에 Git 저장소를 복제하십시오.

.git / config를 열고 Git 저장소의 읽기 전용 SVN 미러 유지 보수 에서 다음을 추가하십시오 .

[svn-remote "svn"]
    url = https://your.svn.repo
    fetch = :refs/remotes/git-svn

이제 콘솔 창에서 다음을 입력하십시오.

git svn fetch svn
git checkout -b svn git-svn
git merge master

어떤 이유로 든 여기에서 끊어지면 다음 세 줄을 입력하십시오.

git checkout --theirs .
git add .
git commit -m "some message"

그리고 마지막으로 SVN에 커밋 할 수 있습니다.

git svn dcommit

참고 : 나는 항상 그 폴더를 스크랩합니다.


6
일이 실제로 나를 위해 일한 (하지 뭐든지 트렁크 /베이스), 다른 답변 달리 제공에 보관Unable to determine upstream SVN information from HEAD history.
스테인


2
이 기술을 사용해 보았지만 기록을 가져 오지 않았습니다. BTW, "자식 병합 마스터는"지금 "자식 병합 --allow-관련이없는-역사 마스터는"
의 Berend 드 보어

1
SVN의 내용을 git의 내용으로 덮어 쓰려면을 사용하십시오 git merge -s recursive -Xtheirs --allow-unrelated-histories master.
user1475814

28

git rebase직접 사용 하면 첫 번째 커밋이 손실됩니다. 힘내는 그것을 다르게 취급하고 rebase 할 수 없습니다.

전체 기록을 보존하는 절차가 있습니다 : http://kerneltrap.org/mailarchive/git/2008/10/26/3815034

여기에 해결책을 제시하지만 Björn의 크레딧입니다.

git-svn을 초기화하십시오 :

git svn init -s --prefix=svn/ https://svn/svn/SANDBOX/warren/test2

--prefix는 "svn / trunk"와 같은 원격 추적 분기를 제공합니다. 로컬 분기를 "trunk"라고 부르면 모호한 이름을 얻지 못하기 때문에 좋습니다. 과-s 표준 트렁크 / 태그 / 지점 레이아웃에 대한 바로 가기입니다.

SVN에서 초기 내용을 가져옵니다.

git svn fetch

이제 루트 커밋의 해시를 찾으십시오 (단일 커밋을 표시해야 함).

git rev-list --parents master | grep '^.\{40\}$'

그런 다음 빈 트렁크 커밋의 해시를 가져옵니다.

git rev-parse svn/trunk

이식편을 만듭니다.

echo <root-commit-hash> <svn-trunk-commit-hash> >> .git/info/grafts

이제 "gitk"는 svn/trunk마스터 브랜치를 기반으로하는 첫 번째 커밋으로 표시되어야합니다 .

이식편을 영구적으로 만듭니다.

git filter-branch -- ^svn/trunk --all

이식편을 삭제하십시오 :

rm .git/info/grafts

gitk는 여전히 svn/trunk마스터의 조상에 보여 져야합니다 .

트렁크 위에서 역사를 선형화하십시오.

git svn rebase

이제 "git svn dcommit -n"은 트렁크에 커밋 할 것임을 알려줍니다.

git svn dcommit

이 기술이 위와 어떻게 다른지 더 명확하게 설명 할 수 있습니까?
cmcginty 2016 년

3
"git rev-parse svn / trunk"를 시도하면 작업 트리에없는 알 수없는 개정 또는 경로 가보고됩니다.
Adam Ness

이것은 git filter-branch 및 drop graft가 필요하지 않은 단계를 제외하고는 나를 위해 일한 유일한 대답입니다 .graft를 만든 후 rebase를 한 다음 git svn dcommit을 수행했습니다.
fc7

8

프로젝트의 Subversion 저장소에 새 디렉토리를 작성하십시오.

# svn mkdir --parents svn://ip/path/project/trunk

Git 관리 프로젝트로 변경하고 git-svn을 초기화하십시오.

# git svn init svn://ip/path/project -s
# git svn fetch

SVN 프로젝트 디렉토리가 여전히 비어 있기 때문에 단일 커밋이 생성됩니다. 이제 커밋의 모든 것을 리베이스 git svn dcommit하고 완료해야합니다. 그러나 커밋 날짜를 심각하게 망칠 것입니다.


이 답변을 hassox.blogspot.com/2007/12/using-git-with-svn.html 의 지침과 함께 사용 하여 트렁크 이름을 확인하기 위해 "#git branch -a"명령을 따랐습니다. # git checkout -b local-svn trunk # git merge master # git svn dcommit .svn 디렉토리를 .gitignore로 기억하십시오!
cflewis 2016 년

방금 동일한 작업을 수행 했으므로 지금은 얼마 동안 (1 월 '09) git이 루트 커밋에서 리베이스 작업을 수행 할 수 있음을 분명히하고 싶었습니다. 이것은 많은 오래된 기사가 나타내는 것보다 프로세스를 훨씬 간단하게 만듭니다. 자세한 내용은 its.arubything.com/2009/1/4/…를
Louis Jacomet

"-s"git svn init 옵션은 무엇을합니까? git svn에 대한 매뉴얼 페이지에서 이것을 볼 수 없습니다.
Nathan

매뉴얼 페이지를 다시 읽고“-s”를 검색하십시오. “--stdlayout”의 별칭입니다.
Bombe

7

완전한 커밋 히스토리를 가진 Git-> SVN

나는 Git 프로젝트를 가지고 있었고 SVN으로 옮겨야했다. 이것이 내가 저지른 전체 커밋 기록을 유지하는 방법입니다. libSVN이 우리가 할 때 로컬 시간을 설정하므로 원래 커밋 시간이 유실됩니다 git svn dcommit.

어떻게:

  1. SVN 저장소에 물건을 가져오고 git-svn으로 복제하십시오.

    git svn clone https://path.to/svn/repository repo.git-svn`
    
  2. 저기로가:

    cd repo.git-svn
    
  3. Git 저장소의 원격을 추가하십시오 (이 예에서는 C : /Projects/repo.git 사용하고 있습니다 ). SVN으로 푸시하고 old-git 이름을 지정하려고합니다.

    git remote add old-git file:///C/Projects/repo.git/
    
  4. 이전 분기 저장소에서 현재 저장소로 마스터 브랜치에서 정보를 가져옵니다.

    git fetch old-git master
    
  5. old-git remote의 master 브랜치를 현재 저장소에서 old라는 새로운 브랜치로 체크 아웃하십시오.

    git checkout -b old old-git/master`
    
  6. HEAD를 낡은 git / master 위에 놓도록 리베이스하십시오. 이것은 모든 커밋을 유지합니다. 이것이 기본적으로하는 일은 Git에서 수행 한 모든 작업을 SVN에서 액세스하는 작업 위에 두는 것입니다.

    git rebase master
    
  7. 이제 마스터 지점으로 돌아갑니다.

    git checkout master
    

    그리고 커밋 기록이 깨끗하다는 것을 알 수 있습니다. 이것이 SVN으로 푸시하려는 것입니다.

  8. 작업을 SVN으로 푸시하십시오.

    git svn dcommit
    

그게 다야. 매우 깨끗하고 해킹이 없으며 모든 것이 완벽하게 작동합니다. 즐겨.


유사 프로세스는에서 설명 chani.wordpress.com/2012/01/25/...
TWiStErRob

같은데 그러나 나는 그녀의 방법이 꽤 혼란스럽고 내 것이 훨씬 짧습니다 (19/23보다 8 단계). 어쩌면 나는 그녀를 올바르게 얻지 못했지만 svn과 git 명령을 두 번째 글 머리 기호에 섞은 것 같습니다.
codingdave

아, 네, 차이점은 프로세스가 git을 SVN 저장소의 루트로 가져오고 하위 폴더로 가져 오는 것이므로 몇 가지 git svn준비가 필요합니다.
TWiStErRob

7 단계에서 git merge old가 없어야합니까? 나를 위해 당신은 당신이 변경하지 않은 마스터의 dcommit을 만드는 것 같습니다!
Alexander

@git rebase master를 사용하는 @Alexander는 빨리 감기 병합, 즉 부모 커밋이 두 개인 병합 커밋이없는 선형 병합입니다. 우리는 여기서 선형적인 역사를 원합니다.
codingdave


3

기존 Git 리포지토리를 빈 SVN 리포지토리에 커밋해야했습니다.

이것이 내가 관리하는 방법입니다.

$ git checkout master
$ git branch svn
$ git svn init -s --prefix=svn/ --username <user> https://path.to.repo.com/svn/project/
$ git checkout svn
$ git svn fetch
$ git reset --hard remotes/svn/trunk
$ git merge master
$ git svn dcommit

문제없이 작동했습니다. 나는 이것이 누군가를 돕기를 바랍니다.

SVN 저장소와 다른 사용자 이름으로 내 권한을 부여해야했기 때문에 ( origin개인 / 공개 키 인증을 사용합니다) --username속성 을 사용해야 했습니다.


git-svn가능하기 전에 설치해야 할 수도 있습니다. stackoverflow.com/questions/527037/git-svn-not-a-git-command
flexponsive

2

메인 리포지토리로 Git을 계속 사용하고 가끔 수정본을 SVN으로 "내보내기"만하면 Tailor 를 사용 하여 SVN 리포지토리를 동기화 상태로 유지할 수 있습니다 . 다른 소스 제어 시스템간에 수정본을 복사 할 수 있으며 Git에서 변경 한 내용으로 SVN을 업데이트합니다.

Git-to-SVN 변환을 시도하지 않았지만 SVN-> SVN 예제의 경우이 답변을 참조하십시오 .


2

또 다른 시퀀스가 ​​작동했습니다 (각 단계에 대한 주석 포함).

  1. 설치 git-svnsubversion툴킷 :

    sudo apt-get install git-svn subversion
    
  2. 내부 스위치 PROJECT_FOLDER

    cd PROJECT_FOLDER
    
  3. Subversion 서버에서 프로젝트 경로를 만듭니다 (불행히도 현재 git-svn플러그인에 TortoiseSVN과 비교하여 결함이 있음). 에 소스 코드를 직접 저장할 수 없습니다 PROJECT_FOLDER. 대신 기본적으로 모든 코드를에 업로드합니다 PROJECT_FOLDER/trunk.

    svn mkdir --parents protocol : /// path / to / repo / PROJECT_FOLDER / trunk -m "git repo 플레이스 홀더 작성"

이것은 trunk경로의 끝에서 필수 장소입니다

  1. 폴더 git-svn내 에서 플러그인 컨텍스트를 초기화하십시오..git

    git svn init -s protocol:///path/to/repo/PROJECT_FOLDER
    

    이곳은 trunk 경로의 끝에 불필요한 곳입니다

  2. 빈을 가져옵니다 Subversion 저장소 정보를

    git svn fetch
    

    이 단계는 Subversion 서버를 git-svn플러그인 과 동기화하는 데 도움이됩니다 . 이 순간은git-svn플러그인이 remotes/origin경로를 설정 trunk하고 서버 측 의 하위 폴더 와 연결 입니다.

  3. git-svn플러그인이 프로세스에 참여 하기 전에 이전 Git 커밋을 Rebase했습니다 (이 단계는 선택 사항입니다) )

    git rebase origin/trunk
    
  4. 커밋 할 새 / 수정 된 파일 추가 (이 단계는 Git 활동에 정기적이며 선택 사항입니다. )

    git add .
    
  5. 새로 추가 한 파일을 로컬 Git 저장소에 커밋 (이 단계는 선택 사항 임) 이며 7 단계를 사용한 경우에만 적용 가능) :

    git commit -m "Importing Git repository"
    
  6. 모든 프로젝트 변경 내역을 Subversion 서버로 푸시 :

    git svn dcommit
    

1

새로운 SVN 저장소를 만들 수 있습니다. Git 프로젝트를 내 보냅니다 (.git 파일 포함). SVN 저장소에 추가하십시오 (Git에서 지금까지 가지고있는 저장소를 초기화하십시오). 그런 다음 새로운 Git 프로젝트에서 SVN 저장소 가져 오기에 대한 지시 사항을 사용하십시오.

그러나 이것은 이전 Git 기록을 잃을 것입니다.



1

Scatter라는 WordPress 커뮤니티에서 사용되는 훌륭한 도구를 공유하고 싶습니다.

힘내 워드 프레스 플러그인과 약간의 정신 분산

이를 통해 사용자는 Git 저장소를 wordpress.org SVN으로 자동 전송할 수 있습니다. 이론적으로이 코드는 모든 SVN 저장소에 적용 할 수 있습니다.


링크가 효과적으로 끊어진 것 같습니다 ( "evansolomon.me의 서버가 응답하는 데 시간이 너무 오래 걸립니다" ).
Peter Mortensen

1

나는 최근에 여러 개의 Git 저장소를 SVN으로 마이그레이션해야했으며, 내가 찾은 모든 솔루션을 시도한 후에 마침내 나를 위해 일한 것은 Mercurial 이었습니다 (예, 세 번째 VCS 사용). 이 안내서를 사용 하여 다음 프로세스를 수행했습니다 (Linux에서는 기본 아이디어는 Windows에서도 작동합니다).

  1. 필요한 패키지 :

    $ sudo apt-get install git subversion mercurial python-subversion
    
  2. Mercurial은 다음을 추가하여 구성해야합니다 ~/.hgrc.

    [extensions]
    hgext.convert=
    
  3. 임시 작업 디렉토리를 만듭니다 (마이그레이션 할 여러 저장소가 있었으므로 SVN 및 Git 버전의 디렉토리를 별도로 유지했습니다).

    $ mkdir svn
    $ mkdir git
    
  4. 빈 로컬 SVN 저장소를 만듭니다.

    $ svnadmin create svn/project
    
  5. 기존 Git 저장소를 복제하십시오.

    $ git clone server/path/project.git git/project
    
  6. Mercurial이 그 일을하도록하십시오 :

    $ hg convert --dest-type svn git/project svn/project
    
  7. 이제 SVN 저장소에는 전체 커밋 히스토리가 포함되어야하지만 원래 타임 스탬프는 포함되지 않아야합니다. 이것이 문제가되지 않으면 다음 단계를 11 단계로 건너 뜁니다.

  8. 약간의 작업 으로 각 커밋의 날짜와 시간을 변경할 수 있습니다 . 내 리포지토리가 상당히 작기 때문에 수동으로 수행하는 것이 가능했습니다. 먼저 pre-revprop-changeSVN 저장소에 다음 내용 으로 후크를 작성 하여 필요한 특성을 수정하십시오.

    #!/bin/bash
    exit 0;
    

    이 스크립트는 실행 가능해야합니다.

    $ chmod +x svn/project/hooks/pre-revprop-change
    
  9. Mercurial은 이름이 project -wc 인 SVN 저장소의 작업 사본을 작성 했으므로이를 전환하고 커미트 시간을 편집하십시오.

    $ cd project-wc
    $ svn propedit svn:date --revprop -r 1
    

    정확한 날짜와 시간을 입력하고 (시간대에주의하십시오!) 저장하십시오. "버전 1의 속성 svn : date에 새 값 설정"이라는 메시지가 나타납니다.
    이제 다른 모든 개정에 대해 헹구고 반복하십시오.

  10. 선택적으로 커밋 기록을 확인하여 모든 것이 정상으로 보이는지 확인하십시오.

    $ svn log -r 1:HEAD
    

    그런 다음 한 레벨 위로 돌아가십시오.

    $ cd ..
    
  11. 저장소를 덤프하십시오.

    $ svnadmin dump svn/project > project.dump
    
  12. 그리고 Subversion 서버에 덤프를로드하십시오. 끝난!

이 프로세스는 아마도 원격 리포지토리간에 직접 작동 할 수도 있지만 로컬 리포지토리를 사용하는 것이 더 쉽다는 것을 알았습니다. 커밋 시간을 수정하는 것은 많은 작업 이었지만 전반적인 프로세스는 내가 찾은 다른 방법보다 훨씬 간단했습니다.


1

세 가지 방법이 있습니다.

  1. rebase : 다른 답변으로

  2. 먼저 ID를 커밋 ID를 커밋 첫번째 이눔 아 SVN 찾을 .git / 정보 / 이식에 자신의 반향 : ID를 커밋 echo "git_id svn_id}" > .git/info/grafts다음git svn dcommit

  3. 모든 자식 커밋을 체크 아웃하고 파일을 svn_repo, svn commit으로 복사하십시오.

배쉬 데모 : github 데모

v1.x : rebase 사용 및 커밋 id

v2.x : 복사 파일을 사용하고 svn commit


0

내 경우에는 SVN에서 깨끗한 프로젝트를 시작해야했습니다.

$ Project> git svn init protocol://path/to/repo -s
$ Project> git svn fetch

모든 프로젝트 소스를 추가하십시오 ...

$ Project> git add .
$ Project> git commit -m "Importing project sources"
$ Project> git svn dcommit

0

나는 단지 내 경험의 일부를 받아 들여진 대답과 공유하고 싶다. 마지막 단계를 실행하기 전에 모든 단계를 수행했으며 모두 정상이었습니다.

git svn dcommit

$ 자식 svn dcommit

/usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm 줄 101에서 대체 (s ///)에 초기화되지 않은 값 $ u 사용.

/usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm 라인 101에서 연결 (.) 또는 문자열에 초기화되지 않은 값 $ u 사용. refs / remotes / origin / HEAD : ' https://192.168.2.101/ svn / PROJECT_NAME '이 (가)'에 없습니다.

스레드 https://github.com/nirvdrum/svn2git/issues/50을 찾았고 마지막으로 101 /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm 파일에서 다음 솔루션에 적용 한 솔루션을 찾았습니다.

나는 바꿨다

$u =~ s!^\Q$url\E(/|$)!! or die

if (!$u) {
    $u = $pathname;
} 
else {
       $u =~ s!^\Q$url\E(/|$)!! or die
      "$refname: '$url' not found in '$u'\n";
}

이것은 내 문제를 해결했습니다.


-1

Git에서 모든 커밋을 SVN 저장소 에 커밋하지 않으려면 어떻게해야 합니까? 파이프 커밋을 선택적으로 보내려면 어떻게해야합니까? 더 나은 해결책이 있습니다.

SVN에서 가져 와서 병합하는 모든 로컬 Git 저장소를 유지합니다. 그렇게하면 SVN과 동일한 변경 사항을 모두 포함시킬 수 있지만 커밋 기록은 SVN과 완전히 분리됩니다.

그런 다음 별도의 폴더에있는 별도의 SVN 로컬 작업 복사본을 유지합니다. 그것이 SVN으로 다시 커밋하는 것이므로 SVN 명령 줄 유틸리티를 사용합니다.

로컬 Git 저장소의 상태를 SVN으로 커밋 할 준비가되면 파일의 전체 엉망을 로컬 SVN 작업 복사본에 복사하고 Git 대신 SVN을 사용하여 커밋합니다.

이렇게하면 재베이스 작업은 프리베이스 작업과 같기 때문에 재베이스 작업을 수행 할 필요가 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.