sourcecode

기본 재배치를 수행한 후 동일한 분기에서 Git 커밋이 중복됩니다.

codebag 2023. 6. 22. 21:49
반응형

기본 재배치를 수행한 후 동일한 분기에서 Git 커밋이 중복됩니다.

는 리베이스화의 위험에 대한 Pro Git에 제시된 시나리오를 이해합니다.작성자는 기본적으로 중복된 커밋을 방지하는 방법에 대해 설명합니다.

공용 리포지토리에 푸시한 커밋을 기본값으로 변경하지 마십시오.

나는 그것이 ProGit 시나리오에 정확히 맞지 않고 여전히 중복된 커밋으로 끝나기 때문에 나의 특별한 상황을 당신에게 말하려고 합니다.

두 개의 원격 지점이 로컬 지점과 함께 있다고 가정해 보겠습니다.

origin/master    origin/dev
|                |
master           dev

의 브랜치 모두 한 커밋을 는 4개의 브랜치에서 입니다.dev:

origin/master : C1 C2 C3 C4
master        : C1 C2 C3 C4

origin/dev    : C1 C2 C3 C4
dev           : C1 C2 C3 C4

몇 번의 커밋 후 변경 사항을 에 적용합니다.origin/dev:

origin/master : C1 C2 C3 C4
master        : C1 C2 C3 C4

origin/dev    : C1 C2 C3 C4 C5 C6  # (2) git push
dev           : C1 C2 C3 C4 C5 C6  # (1) git checkout dev, git commit

는 나는돌합니다야가로 돌아가야 .master: 파일:

origin/master : C1 C2 C3 C4 C7  # (2) git push
master        : C1 C2 C3 C4 C7  # (1) git checkout master, git commit

origin/dev    : C1 C2 C3 C4 C5 C6
dev           : C1 C2 C3 C4 C5 C6

다시 시작합니다.dev변경 사항을 바탕으로 실제 개발에 빠른 수정 사항을 포함합니다.

origin/master : C1 C2 C3 C4 C7
master        : C1 C2 C3 C4 C7

origin/dev    : C1 C2 C3 C4 C5 C6
dev           : C1 C2 C3 C4 C7 C5' C6'  # git checkout dev, git rebase master

하면 GitX/gitk의 커밋 기록이 됩니다.origin/dev 두 한 커밋 이두 개의동커포밋다니함합이 되어 있습니다.C5'그리고.C6'Git와 다른 것들. 이제 사적용면하을항경변으로 .origin/dev결과는 다음과 같습니다.

origin/master : C1 C2 C3 C4 C7
master        : C1 C2 C3 C4 C7

origin/dev    : C1 C2 C3 C4 C5 C6 C7 C5' C6'  # git push
dev           : C1 C2 C3 C4 C7 C5' C6'

Pro Git의 설명을 완전히 이해하지 못해서 두 가지를 알고 싶습니다.

  1. 왜 Git는 리베이스를 하는 동안 이러한 커밋을 복제합니까?그냥 신청하는 대신에 그렇게 해야 하는 특별한 이유가 있습니까?C5그리고.C6나고끝 C7?
  2. 어떻게 하면 피할 수 있을까요?그것을 하는 것이 현명할까요?

단답형

당신은 당신이 도망쳤다는 사실을 빠뜨렸습니다.git push같은 후, 해서 다음오확계실속니다습했행을고인하류를다▁to▁run▁got를 실행했습니다.git pull:

To git@bitbucket.org:username/test1.git
 ! [rejected]        dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:username/test1.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Git이 도움이 되려고 노력하고 있음에도 불구하고, Git의 'git pull' 조언은 여러분이 하고 싶은 것이 아닐 가능성이 높습니다.

다음과 같은 경우:

  • "기능 분기" 또는 "개발자 분기"에서만 작업하면 다음을 실행할 수 있습니다.git push --force(사용자 5677의 답변에 따라) 기본 재배치 후 커밋으로 원격을 업데이트합니다.
  • 여러 개발자가 있는 지점에서 동시에 작업할 경우, 처음부터 사용하지 않는 이 좋습니다.업데이트하기dev로부터의 변화에 따라master▁of▁running합을 실행하는 에 해야 합니다.git rebase master dev, 친구들아.git merge master가 있는 동안에dev(Justin의 대답대로)

조금 더 긴 설명

Git의 각 커밋 해시는 여러 요인을 기반으로 하며, 그 중 하나는 앞에 오는 커밋 해시입니다.

커밋을 다시 정렬하면 커밋 해시가 변경되고, 커밋 해시를 다시 정렬하면 커밋 해시가 변경됩니다. 그으로결, 의과는기를 한 결과입니다.git rebase master dev서, 디에어dev .master의 커밋과 동일한 내용으로 새 커밋(및 해시)을 만듭니다.dev은 커있상서에태는이지하밋만▁on.master그들 앞에 삽입되었습니다.

당신은 여러 가지 방법으로 이런 상황에 빠질 수 있습니다.내가 생각할 수 있는 두 가지 방법:

  • 할밋수있다니에 을 했을 .master당신이 기초하기를 원하는 것.dev의 일.
  • 할밋수있다니에 을 했을 .dev이미 원격으로 푸시된 후 계속 변경합니다(커밋 메시지 재작성, 커밋 다시 정렬, 스쿼시 커밋 등).

무슨 일이 일어났는지 더 잘 이해해 보겠습니다. 다음은 예입니다.

리포지토리가 있습니다.

2a2e220 (HEAD, master) C5
ab1bda4 C4
3cb46a9 C3
85f59ab C2
4516164 C1
0e783a3 C0

Initial set of linear commits in a repository

그런 다음 커밋을 변경합니다.

git rebase --interactive HEAD~3 # Three commits before where HEAD is pointing

제 할입니다. 할 수 은 여러 가 있습니다 Git에서 커밋을 변경하는 방법은 여러 가지가 있습니다.는 이예서나시변경다니습했을간의 했습니다.C3그러나 새 커밋 삽입, 커밋 메시지 변경, 커밋 재정렬, 커밋을 함께 분쇄하는 등)

ba7688a (HEAD, master) C5
44085d5 C4
961390d C3
85f59ab C2
4516164 C1
0e783a3 C0

The same commits with new hashes

여기서 커밋 해시가 다르다는 것을 알아야 합니다.이는 사용자가 이들에 대해 무언가를 변경했기 때문에 예상되는 동작입니다.이것은 괜찮지만, 다음과 같습니다.

A graph log showing that master is out-of-sync with the remote

도 표시됩니다).git pull).

$ git push origin master
To git@bitbucket.org:username/test1.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:username/test1.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

우리가 뛰면,git pull다음 로그가 표시됩니다.

7df65f2 (HEAD, master) Merge branch 'master' of bitbucket.org:username/test1
ba7688a C5
44085d5 C4
961390d C3
2a2e220 (origin/master) C5
85f59ab C2
ab1bda4 C4
4516164 C1
3cb46a9 C3
0e783a3 C0

또는 다른 방법을 보여줍니다.

A graph log showing a merge commit

이제 로컬에서 커밋이 중복됩니다.만약 우리가 도망친다면,git push우리는 그것들을 서버로 보낼 것입니다.

이 단계에 도달하는 것을 피하기 위해, 우리는 도망칠 수 있었습니다.git push --force(가 도망친 git pull이렇게 하면 새 해시가 포함된 커밋을 문제 없이 서버로 전송할 수 있습니다.단계에서 이 다시 .git pull:

.git reflog실행하기 전에 커밋 해시가 무엇인지 확인합니다.git pull.

070e71d HEAD@{1}: pull: Merge made by the 'recursive' strategy.
ba7688a HEAD@{2}: rebase -i (finish): returning to refs/heads/master
ba7688a HEAD@{3}: rebase -i (pick): C5
44085d5 HEAD@{4}: rebase -i (pick): C4
961390d HEAD@{5}: commit (amend): C3
3cb46a9 HEAD@{6}: cherry-pick: fast-forward
85f59ab HEAD@{7}: rebase -i (start): checkout HEAD~~~
2a2e220 HEAD@{8}: rebase -i (finish): returning to refs/heads/master
2a2e220 HEAD@{9}: rebase -i (start): checkout refs/remotes/origin/master
2a2e220 HEAD@{10}: commit: C5
ab1bda4 HEAD@{11}: commit: C4
3cb46a9 HEAD@{12}: commit: C3
85f59ab HEAD@{13}: commit: C2
4516164 HEAD@{14}: commit: C1
0e783a3 HEAD@{15}: commit (initial): C0

위에서 우리는 그것을 봅니다.ba7688a우리가 실행하기 전에 했던 약속이었습니다.git pull할 수 .git reset --hard ba7688a합니다.git push --force.

그리고 우리는 끝났다.

하지만 잠깐만요, 저는 계속해서 중복된 커밋을 기반으로 작업을 했습니다.

만약 당신이 커밋이 중복되었다는 것을 알아차리지 못하고 중복 커밋 위에서 작업을 계속한다면, 당신은 정말 엉망이 된 것입니다.엉망진창의 크기는 중복된 커밋의 수에 비례합니다.

다음과 같이 표시됩니다.

3b959b4 (HEAD, master) C10
8f84379 C9
0110e93 C8
6c4a525 C7
630e7b4 C6
070e71d (origin/master) Merge branch 'master' of bitbucket.org:username/test1
ba7688a C5
44085d5 C4
961390d C3
2a2e220 C5
85f59ab C2
ab1bda4 C4
4516164 C1
3cb46a9 C3
0e783a3 C0

Git log showing linear commits atop duplicated commits

또는 다른 방법을 보여줍니다.

A log graph showing linear commits atop duplicated commits

이 시나리오에서는 중복된 커밋을 제거하지만 이 커밋을 기반으로 한 커밋은 유지합니다. 즉, C6에서 C10까지 유지합니다.대부분의 경우와 마찬가지로 여러 가지 방법이 있습니다.

다음 중 하나:

  • 마지막으로 복제된1 커밋에서 새 분기를 생성하고 각 분기(C6 ~ C10 포함)를 해당 새 분기에 커밋한 후 해당 새 분기를 표준으로 처리합니다.
  • 또는 실행git rebase --interactive $commit서, 디에어$commit중복된2 두 커밋 이전의 커밋입니다.여기서 중복된 행을 완전히 삭제할 수 있습니다.

1 둘 중 어느 것을 선택하는지도 중요하지 않습니다.ba7688a또는2a2e220잘 작동합니다

2 이 예에서는 다음과 같습니다.85f59ab.

TL;DR

다음으로 설정false:

git config --global advice.pushNonFastForward false

여기서 rebase를 사용하면 안 됩니다. 간단한 병합으로 충분합니다.당신이 링크한 Pro Git 책은 기본적으로 이 정확한 상황을 설명합니다.내부 작동 방식은 약간 다를 수 있지만 시각화 방법은 다음과 같습니다.

  • C5그리고.C6으로 에서 됩니다.dev
  • C7 됩니다.dev
  • C5그리고.C6위에서 재생됩니다.C7새로운 합니다.

그래서, 당신의dev 점분,C5그리고.C6사실상 더 이상 존재하지 않습니다: 그들은 지금 존재합니다.C5'그리고.C6'다음을 수행할 때origin/dev기트시즈C5'그리고.C6'새로운 약속을 하고 역사의 끝까지 그들을 공격합니다.정말로, 만약 당신이 사이의 차이점을 본다면.C5그리고.C5'origin/dev내용이 동일하더라도 행 번호가 다를 수 있으므로 커밋의 해시가 다를 수 있습니다.

ProGit 규칙을 다시 설명하겠습니다. 로컬 리포지토리 이외의 다른 곳에 존재했던 커밋을 다시 사용하지 마십시오.대신 병합을 사용합니다.

단계를 설명할 때 중요한 세부 사항을 건너뛰었다고 생각합니다. 더 구체적으로,단계인 더구적로말하면으단, 마막계는지의당신체▁more.git push일반적으로 빠르게 진행되지 않는 변경 사항을 푸시할 수 없기 때문에 dev에서 실제로 오류를 발생시켰을 것입니다.

은 ㅠㅠㅠㅠㅠgit pull마지막 푸시 이전에 C6 및 C6'을 부모로 하는 병합 커밋이 발생했기 때문에 둘 다 로그에 나열됩니다.로그 형식이 더 예쁘면 중복된 커밋의 병합된 분기임이 더 분명해질 수 있습니다.

아니면 당신이 만든.git pull --rebase이지 않음)--rebase대신 구성에 의해 암시되는 경우), 즉 원래 C5 및 C6을 로컬 개발로 되돌립니다(그리고 추가로 다음의 것들을 새 해시, C7'C5'C6'로 리베이스했습니다).

이 일에서 벗어나는 한 가지 방법은git push -f오류가 발생했을 때 강제로 밀어내고 C5 C6를 원래 위치에서 지웁니다. 하지만 만약 당신이 그것들을 지우기 전에 다른 누군가가 그것들을 뽑았다면, 당신은 훨씬 더 많은 문제를 겪게 될 것입니다.기본적으로 C5 C6를 가진 모든 사람들은 그것들을 없애기 위해 특별한 단계를 수행해야 할 것입니다.그래서 그들은 이미 출판된 것을 절대로 다시 기초해서는 안 된다고 말합니다.그러나 "출판"이 소규모 팀 내에 있다고 해도 여전히 가능합니다.

저의 경우 Git 구성 문제로 인해 이 문제가 발생한다는 것을 알게 되었습니다.(끌기 및 병합 포함)

문제 설명:

증상: 기본 재배치 후 하위 분기에서 중복되는 커밋으로, 기본 재배치 중 및 이후에 많은 병합이 발생합니다.

워크플로우:수행 중인 워크플로우의 단계는 다음과 같습니다.

  • "Features-branch" 작업("Develop-branch"의 하위 항목)
  • "Features-branch"에서 변경 사항 커밋 및 푸시
  • "Develop-branch"(기능의 마더 브랜치)를 선택하고 작업합니다.
  • "Develop-Branch"에 대한 변경 사항 커밋 및 푸시
  • "Features-branch" 체크아웃 후 저장소에서 변경사항 가져오기(다른 사용자가 작업을 커밋한 경우)
  • "Features-branch"를 "Develop-branch"로 다시 붙입니다.
  • "Feature-branch"에 대한 변경 사항의 푸시 포스

이 워크플로우의 결과로 이전 기본 재배치 이후 "기능 분기"의 모든 커밋 복제...:-(

이 문제는 기본 재배치 전 하위 분기의 변경 내용을 끌어오기 때문입니다.Git의 기본 풀 구성은 "머지"입니다.하위 분기에서 수행된 커밋 인덱스를 변경합니다.

해결책: Git 구성 파일에서 rebase 모드에서 작동하도록 pull을 구성합니다.

...
[pull]
    rebase = preserve
...

JN Grx에 도움이 되길 바랍니다.

현재와 다른 원격 분기에서 연결했을 수 있습니다.예를 들어 지점에서 추적 개발을 진행할 때 마스터에서 작업을 완료했을 수 있습니다.추적되지 않는 분기에서 끌어온 경우 Git는 중복된 커밋을 의무적으로 가져옵니다.

이 경우 다음을 수행할 수 있습니다.

git reset --hard HEAD~n

n == <number of duplicate commits that shouldn't be there.>

그런 다음 올바른 분기에서 끌어 올린 다음 다음을 실행합니다.

git pull upstream <correct remote branch> --rebase

--rebase커밋 기록을 흐리게 할 수 있는 외부 커밋을 추가하지 않도록 보장합니다.

여기 깃브 베이스를 위한 약간의 손잡기가 있습니다.

언급URL : https://stackoverflow.com/questions/9264314/git-commits-are-duplicated-in-the-same-branch-after-doing-a-rebase

반응형