git-svn을 시험해보기위한 나의 동기는 쉬운 병합 및 분기입니다. 그런 다음 남자 git-svn (1)이 말합니다.
커밋하려는 분기에서는 git-merge 또는 git-pull을 실행하지 않는 것이 좋습니다. Subversion은 합리적이거나 유용한 방식으로 병합을 나타내지 않습니다. Subversion을 사용하는 사용자는 병합 한 내용을 볼 수 없습니다. 또한 SVN 분기의 미러 인 자식 분기를 병합하거나 가져 오면 dcommit이 잘못된 분기를 커밋 할 수 있습니다.
이것은 svn / trunk (또는 브랜치)에서 로컬 브랜치를 생성하고 해킹하고 svn / trunk로 다시 병합 한 다음 dcommit 할 수 없다는 것을 의미합니까? svn 사용자는 svn pre 1.5.x에서 병합 한 것과 같은 엉망이 항상 있었음을 알지만 다른 단점이 있습니까? 그 마지막 문장도 저를 걱정합니다. 사람들은 일상적으로 이런 종류의 일을합니까?
답변
사실, --no-ff
git merge 옵션으로 더 나은 방법을 찾았습니다 . 내가 사용한이 스쿼시 기술은 더 이상 필요하지 않습니다.
나의 새로운 워크 플로우는 다음과 같습니다 :
-
나는에서 dcommit있는 유일한 지점과 그 클론 SVN 저장소 인 “마스터”지점을 가지고 (
-s
당신이 저장소의 표준 SVN 레이아웃을 가지고 가정trunk/
,branches/
그리고tags/
) :git svn clone [-s] <svn-url>
-
로컬 지점 “작업”에서 작업합니다 (
-b
“작업”분기 작성).git checkout -b work
-
“작업”분기에 로컬로 커밋합니다 (
-s
커밋 메시지를 사인 오프합니다). 속편에서는 3 번의 로컬 커밋을했다고 가정합니다.... (work)$> git commit -s -m "msg 1" ... (work)$> git commit -s -m "msg 2" ... (work)$> git commit -s -m "msg 3"
이제 SVN 서버에 커밋하려고합니다.
-
[결국] SVN 서버에서 커밋하고 싶지 않은 수정 사항을 숨기십시오 (주로 컴파일을 가속화하고 주어진 기능에 집중하기 위해 메인 파일에서 일부 코드에 주석을 달았습니다)
(work)$> git stash
-
SVN 저장소로 마스터 브랜치 리베이스 (SVN 서버에서 업데이트)
(work)$> git checkout master (master)$> git svn rebase
-
작업 지점으로 돌아가서 마스터와 리베이스
(master)$> git checkout work (work)$> git rebase master
-
예를 들어 다음을 사용하여 모든 것이 올바르게 작동하는지 확인하십시오.
(work)$> git log --graph --oneline --decorate
-
이제이 훌륭한
--no-ff
옵션을 사용하여 “작업”브랜치에서 “마스터”로 세 커밋을 모두 병합해야합니다.(work)$> git checkout master (master)$> git merge --no-ff work
-
로그 상태를 확인할 수 있습니다.
(master)$> git log --graph --oneline --decorate * 56a779b (work, master) Merge branch 'work' |\ | * af6f7ae msg 3 | * 8750643 msg 2 | * 08464ae msg 1 |/ * 21e20fa (git-svn) last svn commit
-
이제
amend
SVN 친구들의 마지막 커밋 을 편집 ( )하고 싶을 수도 있습니다 (그렇지 않으면 “Merge branch ‘work'”메시지와 함께 단일 커밋 만 표시됩니다)(master)$> git commit --amend
-
마지막으로 SVN 서버에서 커밋
(master)$> git svn dcommit
-
작업으로 돌아가서 숨김 파일을 복구하십시오.
(master)$> git checkout work (work)$> git stash pop
답변
git-svn으로 로컬 브랜치를 만들 수 있습니다. 로컬 브랜치를 사용하고 업스트림 svn 브랜치를 병합하기 위해 git을 사용하지 않는 한 괜찮습니다.
svn 서버를 추적하는 데 사용하는 “마스터”분기가 있습니다. 이것은 내가 위임 한 유일한 지점입니다. 내가 일을하고 있다면, 토픽 브랜치를 만들고 해결합니다. 커밋하고 싶을 때 다음을 수행합니다.
- 토픽 브랜치에 모든 것을 커밋
- 자식 svn rebase (작업과 svn 사이의 충돌을 해결하십시오)
- 자식 체크 아웃 마스터
- 자식 svn rebase (다음 단계는 빨리 진행되는 병합입니다. 아래의 Aaron 의견 참조)
- 자식 병합 topic_branch
- 병합 충돌 해결 (이 시점에는 없어야 함)
- 자식 svn dcommit
또한 svn으로 푸시해서는 안되는 로컬 변경 사항 (디버깅 용)을 유지 해야하는 또 다른 상황이 있습니다. 이를 위해 위의 마스터 지점뿐만 아니라 일반적으로 작업하는 “work”라는 지점도 있습니다. 주제 분기는 작업에서 분기됩니다. 거기에서 작업을 커밋하려면 master를 체크 아웃하고 cherry-pick을 사용하여 svn에 커밋하려는 작업 분기에서 커밋을 선택하십시오. 세 가지 로컬 변경 커밋을 커밋하지 않기를 원하기 때문입니다. 그런 다음 마스터 브랜치에서 커밋하고 모든 것을 리베이스합니다.
가치있는 달리기 git svn dcommit -n
커밋하려는 것을 정확히 커밋하려고 먼저 . 자식과 달리 svn에서 기록을 다시 쓰는 것은 어렵습니다!
cherry-pick을 사용하는 것보다 로컬 변경 커밋을 건너 뛰면서 토픽 브랜치에서 변경 사항을 병합하는 더 좋은 방법이 있어야한다고 생각합니다.
답변
간단한 해결책 : 병합 후 ‘작업’분기 제거
짧은 대답 : 병합을 포함하여 원하는대로 git을 사용할 수 있습니다 (간단한 워크 플로우는 아래 참조). 임시 작업 분기를 삭제 하려면 각 ‘ git merge work ‘와 ‘ git branch -d work ‘를 따르십시오 .
배경 설명 :
병합 / dcommit 문제는 분기를 ‘git svn dcommit’할 때마다 해당 분기의 병합 기록이 ‘평평하게’됩니다 .git은 분기에 들어간 모든 병합 작업을 잊어 버립니다. 파일 내용 만 보존됩니다. 그러나이 내용이 (부분적으로) 특정 다른 지점에서 나온 사실은 손실됩니다. 참조 : 왜 git svn dcommit이 로컬 브랜치에 대한 병합 커밋 기록을 잃습니까?
(참고 : git-svn이 할 수있는 일은 많지 않습니다 : svn은 훨씬 더 강력한 git merge를 이해하지 못합니다. 따라서 svn 저장소 내 에서이 병합 정보는 어떤 식으로도 나타낼 수 없습니다.)
그러나 이것은 전체입니다 문제입니다. ‘작업’브랜치를 ‘마스터 브랜치’에 병합 한 후 ‘작업’브랜치를 삭제하면 git 저장소가 100 % 깨끗하며 svn 저장소와 똑같이 보입니다.
내 워크 플로우 :
물론 원격 svn 저장소를 로컬 자식 저장소에 복제했습니다 (시간이 걸릴 수 있음).
$> git svn clone <svn-repository-url> <local-directory>
그런 다음 모든 작업은 “local-directory”내부에서 발생합니다. 서버에서 ‘svn update’와 같은 업데이트를 받아야 할 때마다 다음을 수행합니다.
$> git checkout master
$> git svn rebase
나는 모든 개발 작업을 다음과 같이 생성되는 별도의 분기 ‘작업’에서 수행합니다.
$> git checkout -b work
물론 원하는만큼 작업에 대해 많은 브랜치를 생성하고 원하는대로 병합 및 리베이스 할 수 있습니다 (아래에서 논의한 것처럼 작업을 마치면 삭제). 정상적인 작업에서 나는 매우 자주 커밋합니다.
$> git commit -am '-- finished a little piece of work'
다음 단계 (git rebase -i)는 선택 사항입니다 — svn에 보관하기 전에 역사를 정리하고 있습니다. 커밋 메시지를 분기하고 정리하십시오 (다른 개발자는 내가 겪은 작은 단계와 실수를 모두 볼 필요가 없습니다-결과 만). 이를 위해 나는
$> git log
svn 저장소에있는 마지막 커밋의 sha-1 해시를 복사하십시오 (git-svn-id로 표시). 그런 다음 전화
$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb
내 대신 마지막 svn 커밋의 sha-1 해시를 붙여 넣으십시오. 자세한 내용은 ‘git help rebase’와 함께 설명서를 읽으십시오. 한마디로 :이 명령은 먼저 커밋을 표시하는 편집기를 엽니 다 —- 이전 커밋으로 스쿼시하려는 모든 커밋에 대해 ‘pick’을 ‘squash’로 변경하십시오. 물론 첫 번째 줄은 ‘픽’으로 유지해야합니다. 이런 식으로 많은 작은 커밋을 하나 이상의 의미있는 단위로 압축 할 수 있습니다. 편집기를 저장하고 종료하십시오. 커밋 로그 메시지를 다시 작성하도록 요청하는 다른 편집기가 표시됩니다.
간단히 말해서 : ‘코드 해킹’을 마친 후 다른 프로그래머에게 제시하고 싶을 때까지 (또는 역사를 탐색 할 때 몇 주 안에 작업을보고 싶을 때까지) ‘작업’분기를 마사지합니다. .
svn 저장소에 변경 사항을 푸시하기 위해 다음을 수행합니다.
$> git checkout master
$> git svn rebase
이제 우리는 svn 저장소에서 그 동안 발생한 모든 변경 사항으로 업데이트 된 이전 ‘마스터’분기로 돌아 왔습니다 (새로운 변경 사항은 ‘작업’분기에 숨겨져 있습니다).
새로운 ‘작업’변경 사항과 충돌 할 수있는 변경 사항이있는 경우 새 작업을 푸시하기 전에 로컬로 변경해야합니다 (자세한 내용은 아래 참조). 그런 다음 변경 사항을 svn으로 푸시 할 수 있습니다.
$> git checkout master
$> git merge work # (1) merge your 'work' into 'master'
$> git branch -d work # (2) remove the work branch immediately after merging
$> git svn dcommit # (3) push your changes to the svn repository
참고 1 : ‘git branch -d work’명령은 매우 안전합니다. 더 이상 필요하지 않은 브랜치를 삭제할 수 있습니다 (이미 현재 브랜치에 병합되어 있기 때문에). ‘master’분기와 작업을 병합하기 전에 실수로이 명령을 실행하면 오류 메시지가 표시됩니다.
참고 2 : 병합과 dcommit 사이에 ‘git branch -d work’ 를 사용하여 분기를 삭제하십시오. dcommit 후 분기를 삭제하려고하면 오류 메시지가 표시됩니다. ‘git svn dcommit’을 수행하면 git은 지점이 ‘마스터’와 병합되었습니다. 안전 검사를 수행하지 않는 ‘git branch -D work’로 제거해야합니다.
이제 ‘마스터’브랜치를 실수로 해킹하는 것을 피하기 위해 새로운 ‘워크’브랜치를 즉시 만듭니다.
$> git checkout -b work
$> git branch # show my branches:
master
* work
SVN의 변경으로 ‘작업’을 통합 :
다음은 내 ‘일’지점에 근무하는 동안 그 다른 사람이 SVN 저장소를 변경할 때 ‘자식 svn의 REBASE’알 내가 할 것입니다 :
$> git checkout master
$> git svn rebase # 'svn pull' changes
$> git checkout work # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed
$> git checkout master # try again to push my changes
$> git svn rebase # hopefully no further changes to merge
$> git merge integration # (1) merge your work with theirs
$> git branch -d work # (2) remove branches that are merged
$> git branch -d integration # (2) remove branches that are merged
$> git svn dcommit # (3) push your changes to the svn repository
더 강력한 솔루션이 존재합니다 :
제시된 워크 플로우는 단순합니다. ‘update / hack / dcommit’의 각 라운드 내에서만 git의 기능을 사용하지만 장기 프로젝트 히스토리는 svn 저장소와 마찬가지로 선형입니다. 레거시 svn 프로젝트에서 작은 첫 단계로 git merge 사용을 시작하려는 경우에도 괜찮습니다.
git merging에 익숙해지면 다른 워크 플로우를 자유롭게 탐색하십시오.하고있는 것을 알고 있다면 svn merge와 git merge를 혼합 할 수 있습니다 ( git-svn (또는 비슷한 것을 사용하여 svn merge)? )
답변
그렉 휴길의 답변은 안전하지 않습니다! 두 개의 “git svn rebase”사이의 트렁크에 새로운 커밋이 나타나면 병합이 빨리 진행되지 않습니다.
git-merge에 “–ff-only”플래그를 사용하여 보장 할 수 있지만 일반적으로 분기에서 “git svn rebase”를 실행하지 않고 “git rebase master”만 실행합니다 (로컬 만 가정 할 경우). 분기). 그런 다음 “git merge thebranch”가 빨리 감 깁니다.
답변
git에서 svn 브랜치를 병합하는 안전한 방법은 git merge –squash를 사용하는 것입니다. 이렇게하면 단일 커밋이 만들어지고 메시지를 추가 할 수 없게됩니다.
svn-branch라는 주제 svn 분기가 있다고 가정 해 봅시다.
git svn fetch
git checkout remotes/trunk -b big-merge
git merge --squash svn-branch
이 시점에서 svn-branch의 모든 변경 사항이 인덱스에서 대기하는 하나의 커밋으로 스쿼시되었습니다.
git commit
답변
로컬 git 브랜치를 마스터 git 브랜치에 리베이스 한 다음 dcommit하면 svn 사람들이 익숙한대로 선형으로 볼 수 있도록 모든 커밋을 순서대로 수행 한 것처럼 보입니다. 토픽이라는 로컬 브랜치가 있다고 가정하면
git rebase master topic
그러면 마스터 커밋을 통해 커밋을 수행하여 커밋 할 수 있습니다.