2011-04-12 5 views
3

우리 회사에서 새로운 일을하고 Subversion의 git에 들어갔다. 주말에는 우리가하지 않은 지점의 공개 버전에 대한 커밋이있는 저장소의 상황에 처하게되었다. 거기있어.git에서 "닫힌"브랜치를 오염시키는 커밋을 더 잘 처리하려면 어떻게해야합니까?

A -> B 

을 그리고있는 지점을 넣어 나쁜 커밋을 가지고 : 우리는 있었다

A -> B -> C -> D 

C와 D는 해당 분기에 없었을 것이다. 문제는이 지점이 "닫혔다"는 것입니다. 이것은 우리 소프트웨어의 출시 된 버전이었으며이 지점에 대한 새로운 커밋이 없어야했습니다. ! 서브 버전에서

상황이 이런 종류의 밖으로 유일한 방법은 커밋 D이었고, 그래서 당신은 끝낼 C : B에 날 다시 얻을 수 있지만, 타임 라인에 전진 나를 계속

A -> B -> C -> D -> !D -> !C 

!을 브랜치의 경우 마스터 저장소와 동기화되는 지점의 원격 사용자는 C와 D를 가져 와서 논리적으로 비슷한 버전의 B (B가 아닌 B -)로 끝내도록 실행 취소해야합니다.

this solution for reverting commits in git이 이상적으로 보였습니다. 공개 저장소를 다시 A -> B에 넣었습니다. 그러나 그것은 누군가의 작업 컴퓨터에서이 분기의 복제본이 매우 부정확하고 모든 사람이 다시 복제해야한다는 것을 의미했습니다. 내 수정에 달했다 :

git checkout thebranch 
git reset --hard <<commit # associated with commit B>> 
git push --force 
내가 위의 링크의 길을가는 결국

그것은 꽤 파문을 일으킨 :

가) 당신은 멀리 던져이 같은 자식과 대중 저장소에서 역사를 커밋 할 수 , 문자 그대로 현실을 다시 쓰라.

b) 모두를 다시 복제해야 분기 (또는 우리가 만들고자하는 지점의 새 분기)에 C -> D을 다시 주입 할 위험이 없습니다.

git revert HEAD~2 
git commit 
git push 

을하지만이 A -> B -> C -> D -> E로 분기를 떠난 것과는 폐쇄해야하는데 있기 때문에 정말에 C -> D -> E을하지 말았어야 :

나는 내가 해야 완료했다 생각합니다.

나는 세 가지 질문을 가지고 :

  • 가 어떻게 더 잘 깨끗한 처리 수 있었다
      ? reset 대신 revert을 사용 하시겠습니까? 가지 오염에 대한 가장 좋은 방법은 무엇입니까?
    1. 되돌리기 지점 push --force이 실제로 공개 저장소에서 기록을 삭제 했습니까? 아니면 git를 B로 되 돌렸지 만 C -> D이라는 기록을 유지하고 나에 의해 어느 시점에서 되돌리기가 B로 돌아 갔는가? 커밋 로그에서 되돌리기를 확실히 표시하지는 않지만 어쩌면 내 작업의 기록을 다른 곳에서 보관할 수 있습니까?
    2. git에서 "닫힌"브랜치를 어떻게 다룰 것인가?우리는 커밋 B에서 저장소에 태그를 적용했고 사람들은 분기 + 태그를 사용하여 릴리스의 소스를 가져야한다고 생각했지만, 이것은 가지지 않아야하는 가지 줄에 변경 사항을 표시하는 것은 여전히 ​​무서운 일입니다 패치를 릴리스하기 위해 지점에서 분기 한 사람이 쉽게 태그를 놓칠 수 있었고 C -> D을 새로운 지점으로 가져올 수있었습니다.
  • +0

    , 당신은 자식 태그에 대해 이야기하고, 맞죠? – idbrii

    +0

    @pydave : 죄송합니다. 예, 태그를 의미했습니다. 내 말의 기술 교차 오염. :) –

    답변

    5

    릴리스 ("폐쇄 된 분기") 및 개발을위한 분기 ("열린 분기")에 태그를 사용해야합니다. 이 방법은 문제를 해결할 수있는 대안 (현재 출시 된 코드의 태그 만 사용 가능)과 향후이 문제를 방지 할 수있는 방법입니다.

    v3.1을 개발하는 동안 v3.1을 사용할 수 있습니다. v3.1이 완료되면 마지막 커밋에 태그를 지정하고 분기의 이름을 다음 개발 분기 (v3.2)로 바꿉니다. 기억하십시오 : 힘내는 Svn이 아닙니다! 분기는 커밋에 대한 포인터 일뿐입니다. 분기를 삭제해도 커밋은 삭제되지 않습니다 (하지만 커밋이 다른 분기에 포함되어 있지 않으면 커밋되지 않아 분기를 삭제하기 전에 태그를 만들어야합니다).

    당신은 버전 3.1 (V3.1.1)에 패치를 개발하고자하는 경우에, 당신은 태그 버전 3.1에서 지점 작성 :

    git checkout -b v3.1.1 v3.1 
    

    이것은 개발자에게 명확하게됩니다 (가지가 있습니다 개발 및 태그는 릴리스 용입니다.)이 문제가 다시 발생하지 않도록하십시오.


    는 되돌아 가지의 푸시 --force 정말 대중 저장소에서 역사를 파괴 했습니까?

    아니요. 커밋 D에 대해 태그 또는 분기를 만들었 으면 해당 분기는 여전히 문제가되지 않습니다. 최근 변경 사항을 보려면 git reflog을 사용하십시오. 저 커밋이 거기에 있어야합니다. (또는 git fsck.) 이해를 기초로 다른 버전 제어 시스템을 사용하지 않는 자식의 좋은 토론을위한


    , PeepCode's Git Internals을 시도합니다.무료는 아니지만 중앙 집중식 버전 관리와 별개로 이해하는 것이 더 낫다고 생각합니다. 합니다 (Git Community Book 좋은 무료 대안처럼 보인다.) 당신이 레이블을 말할 때

    +0

    감사합니다. 이것은 즉시 명확하지 않은 (지점에 태그를 붙인 다음, 개발을 계속하기 위해 이름을 바꾸는) 것입니다. 아주 잘 알고 있습니다. –

    1

    점 2 : 아니오; 지사 (로컬 또는 서버)를 재설정하면 기록이 삭제되지 않습니다. git에서 브랜치는 특정 커밋을 가리키는 레이블과 비슷하다. (브랜치가 체크 아웃되고 새로운 커밋이 만들어지면 레이블은 자동으로 앞으로 움직인다.) 브랜치를 리셋하는 것은 레이블이 뒤로 이동한다는 것을 의미합니다. 커밋 자체는 그대로 있지만 다른 지점이 없다면 "보이지 않게"됩니다. 이 경우 git reflog을 사용하여 복구 할 수 있습니다. 그러면 분기가없는 경우에도 모든 커밋의 해시가 표시됩니다. 그런 다음 "삭제 된"커밋이 아직 있음을 알 수 있습니다. 그 (것)들을 파괴 할 수있는 유일한 것은 git gc (또한 git 자체에 의해 산발적으로 실행된다)이다. 이것은 참조되지 않은 커밋을 제거한다.

    지점을 이전 지점으로 재설정하고 강제로 밀어 넣으면 다른 개발자가 git fetch -f origin branchname:branchname을 사용하여 지점을 재설정 할 수 있습니다. 다시 복제 할 필요가 없습니다 (그러나 강제로 가져 오는 인덱스가 엉망이되지 않도록 먼저 다른 분기를 체크 아웃해야합니다). 그러나 실수로 푸시 한 브랜치를 커밋 한 경우 커밋을 "잃게"됩니다 (다시 git reflog). 이것은 브랜치가 어쨌든 닫히기로되어 있었기 때문에 아마도 당신에게는 문제가 아니지만 만약 그것이 발생한다면, 그들은 강제적 인 페칭 전에 새로운 브랜치를 생성 할 수 있습니다. 새로운 브랜치는 여전히 가장 최신의 커밋을 가리키고, git rebase은 커밋을 적절한 브랜치에 이식 할 수 있습니다.

    +0

    나는 두 개의 대답을 받아 들일 수 있으면 좋겠다. 대답의 후반부는 훌륭합니다. 고맙습니다. –

    +0

    @Ian C .: 도움이 된 것을 기쁘게 생각합니다. (어떻게 든 전반부를 개선 할 수 있습니까?)) –

    +0

    @Aasumnd - no. @ pydave는 나를 위해 1과 3을 대답했고, 2를 답했습니다. 3가 내게 가장 중요했습니다. –

    관련 문제