[git] 누군가가 게시 된 브랜치에 리베이스 또는 재설정을 푸시 한 후 복구 / 재 동기화하려면 어떻게해야합니까?

우리는 게시 된 작업을 절대로 리베이스해서는 안된다고, 위험하다는 등의 말을 들었습니다. 그러나 나는 리베이스 게시 된 경우 상황을 처리하는 방법에 대한 레시피가 게시 된 것을 보지 못했습니다 .

이제 저장소가 알려진 (가급적 작은) 그룹에 의해서만 복제되는 경우에만 실제로 가능하다는 점에 유의하십시오. 따라서 리베이스 또는 재설정을 푸시하는 사람은 다른 모든 사람에게 다음에주의를 기울여야한다고 알릴 수 있습니다. 술책(!).

내가 본 한 가지 분명한 솔루션은 로컬 커밋이없고 foo리베이스 되는 경우 작동합니다 .

git fetch
git checkout foo
git reset --hard origin/foo

이것은 단순히 foo원격 저장소에 따라 히스토리에 찬성하여의 로컬 상태를 버립니다 .

하지만 그 지점에서 상당한 지역적 변화를 일으킨다면 상황을 어떻게 다룰까요?



답변

푸시 된 리베이스 후에 다시 동기화하는 것은 대부분의 경우 그렇게 복잡하지 않습니다.

git checkout foo
git branch old-foo origin/foo # BEFORE fetching!!
git fetch
git rebase --onto origin/foo old-foo foo
git branch -D old-foo

즉. 먼저 원격 브랜치가 원래 있던 위치에 대한 북마크를 설정 한 다음이를 사용하여 해당 지점에서 리 기반 원격 브랜치로 로컬 커밋을 재생합니다.

Rebasing은 폭력과 같습니다. 문제가 해결되지 않으면 더 많이 필요합니다. ☺

물론 pre-rebase origin/foo커밋 ID 를 찾아서 사용한다면 북마크 없이도 가능합니다 .

또한 가져 오기 전에 북마크를 만드는 것을 잊은 상황을 처리하는 방법이기도합니다 . 손실되는 것은 없습니다. 원격 분기에 대한 리플 로그를 확인하기 만하면됩니다.

git reflog show origin/foo | awk '
    PRINT_NEXT==1 { print $1; exit }
    /fetch: forced-update/ { PRINT_NEXT=1 }'

이것은 origin/foo기록을 변경 한 가장 최근의 가져 오기 전에 가리키는 커밋 ID를 인쇄합니다 .

그런 다음 간단히

git rebase --onto origin/foo $commit foo


답변

내가 말하고 싶지만 상류 REBASE의 복구 힘내 – REBASE 매뉴얼 페이지 커버 섹션 거의 모든의를.

자신의 리베이스에서 복구하는 것과 실제로 다르지 않습니다. 하나의 브랜치를 이동하고 기록에있는 모든 브랜치를 새로운 위치로 리베이스합니다.


답변

자식과 함께 시작하는 것은 2014 년 1 분기 1.9 / 2.0, 당신은에 설명 된대로 다시 상류 지점에 그것을 리베이스하기 전에 이전 분기 원을 표시 할 필요가 없습니다 아리스토텔레스 Pagaltzis대답 :
참조가 07d406b 커밋d96855f 커밋 :

topic만든 브랜치 에서 작업 한 후 git checkout -b topic origin/master원격 추적 브랜치의 기록을 origin/master되 감고 다시 빌드하여 다음과 같은 형태의 기록을 만들 수 있습니다.

                   o---B1
                  /
  ---o---o---B2--o---o---o---B (origin/master)
          \
           B3
            \
             Derived (topic)

여기서 origin/master커밋에 포인트로 사용 B3, B2, B1지금은에 점 B, 그리고 topic때 백업의 지점은 정상에 시작되었다 origin/master이었다 B3.

이 모드는의 reflog를 사용하여 분기점 origin/master으로 찾기 B3때문에 다음 topic을 통해 업데이트 된 항목origin/master기반으로 할 수 있습니다 .

$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic

이것이 git merge-base명령에 새로운 옵션이있는 이유입니다 .

--fork-point::

분기 (또는 이로 이어지는 모든 기록 <commit>)가 다른 분기 (또는 참조)에서 분기 된 지점을 찾습니다 <ref>.
이것은 두 커밋의 공통 조상을 찾을뿐만 아니라 분기의 이전 화신에서 분기 된 <ref>역사를 확인하기 위해 의 리플 로그를 고려합니다<commit><ref> .


git pull --rebase“명령은 ” base“가있는 경우에 대처하기 위해 분기 작업의 기반이 된 ” “분기 (일반적으로 원격 추적 분기)의 reflog 항목을 사용하여 리베이스되는 분기의 분기점을 계산합니다. 가지가 되 감고 재건되었습니다.

예를 들어, 기록이 다음과 같은 경우 :

  • 현재의 끝은 ” base“지점에 있습니다 B만, 이전의 팁 예전 관찰을 불러오는 B3다음과 B2다음 B1
    , 커밋 현재에 도착하기 전에
  • 최신 “base”위에 리베이스되는 브랜치는 commit을 기반으로합니다 B3.

이 찾습니다 B3“의 출력을 통해 이동하여 git rev-list --reflog base“(즉 B, B1, B2, B3) 그것은 그 현재의 팁의 조상 커밋 찾을 때까지 ” Derived (topic)“.

내부적으로 get_merge_bases_many()는 일회성으로 이것을 계산할 수 있습니다. ” ” 의 모든 역사적 팁을 병합하여 결과가되는 가상의 병합 커밋
사이의 병합 기반을 원할 Derivedbase (origin/master)입니다.
그러한 커밋이 존재하면 ” base” 의 reflog 항목 중 하나와 정확히 일치하는 단일 결과를 얻어야합니다 .


힘내 2.1 (2014 년 3 분기)이이 기능이 더 강력하게 추가 할 것입니다 : 참조 1e0dacd 커밋 에 의해 존 키핑 ( johnkeeping)

다음 토폴로지가있는 시나리오를 올바르게 처리하십시오.

    C --- D --- E  <- dev
   /
  B  <- master@{1}
 /
o --- B' --- C* --- D*  <- master

어디:

  • B'B패치와 동일하지 않은 수정 된 버전입니다 B.
  • C*D*패치와 동일한다 CD각각 잘못된 순서로 적용될 경우, 텍스트로 충돌;
  • E텍스트는 D.

정확한 결과 git rebase master devIS B의 포크 포인트로 식별 dev하고 master, 그래서 C, D, E필요에이 재생 될 것을 커밋이다 master; 하지만, CD패치와 동일하다 C*D*최종 결과가되도록, 따라서 감소 될 수있다 :

o --- B' --- C* --- D* --- E  <- dev

분기점이 식별되지 않은 경우 B포함 된 분기 를 선택 B'하면 충돌이 발생하고 패치와 동일한 커밋이 올바르게 식별되지 않은 경우 C포함 D(또는 동등하게 D*)을 포함하는 분기 를 선택 하면 충돌이 발생합니다.


--fork-point“모드는 git rebaseGit 2.27 (2020 년 2 분기)에서 수정 된 2.20 시대에 C에서 명령을 다시 작성했을 때 퇴보했습니다.

참조는 f08132f 커밋 에 의해 (2019 12월 9일)를 Junio C 하마노 ( gitster)을 .
(Merged by Junio ​​C gitsterHamano in commit fb4175b , 27 Mar 2020)

rebase: --fork-point회귀 수정

서명자 : Alex Torok
[jc : 수정 사항 수정 및 Alex의 테스트 사용]
서명자 : Junio ​​C Hamano

git rebase --fork-point master“은 (는) 잘 작동했습니다. 내부적으로 ” git merge-base --fork-point” 라는 이름으로 짧은 참조 이름을 처리하는 방법을 알고 기본 get_fork_point()함수 를 호출하기 전에 전체 참조 이름으로 변경했습니다 .

명령이 C로 다시 작성된 후에는 더 이상 해당되지 않습니다. 직접 내부 호출이 get_fork_point()짧은 참조를 dwim하지 않기 때문입니다.

“git merge-base”에서 사용되는 “refname 인수를 전체 참조 이름으로 변경”논리를 기본 get_fork_point()함수로 이동하여 “git rebase”구현에서 함수의 다른 호출자가 동일한 방식으로 수정하도록합니다. 이 회귀.


답변