programing

현재 분기에 커밋되지 않은 변경사항이 있을 때 다른 분기 체크아웃

abcjava 2023. 5. 1. 19:47
반응형

현재 분기에 커밋되지 않은 변경사항이 있을 때 다른 분기 체크아웃

제가 다른 기존 지점을 확인하려고 할 때 대부분 Git는 현재 지점에 커밋되지 않은 변경 사항이 있을 경우 이를 허용하지 않습니다.그래서 저는 먼저 그 변화들을 저지르거나 숨겨야 할 것입니다.

그러나 때때로 Git는 변경 사항을 커밋하거나 저장하지 않고 다른 지점을 체크아웃할 수 있도록 허용하며, 이러한 변경 사항은 내가 체크아웃하는 지점으로 전달됩니다.

여기 규칙은 무엇입니까?변경사항이 단계적인지 아니면 단계적이지 않은지가 중요합니까?변경 사항을 다른 지점으로 옮기는 것은 말이 안 되는데, 왜 가끔은 git에서 허용하는 걸까요?즉, 어떤 상황에서 도움이 됩니까?

준비사항

이 대답은 Git가 왜 그렇게 행동하는지 설명하려는 시도입니다.특정 워크플로우에 참여하는 것은 권장되지 않습니다.(제가 선호하는 것은 어쨌든 약속하는 것이고, 피하는 것입니다.git stash너무 까다롭게 굴려고 하는 것이 아니라 다른 방법들을 좋아합니다.)

여기서 관찰되는 것은, 당신이 일을 시작한 후에branch1(다른 지점으로 전환하는 것이 좋을 것이라고 생각하거나 깨닫지 못함)branch2먼저), 다음을 실행합니다.

git checkout branch2

때때로 Git는 "좋아요, 당신은 지금 2번 지점에 있어요!"라고 말합니다.가끔, Git는 "저는 그렇게 할 수 없어요, 저는 당신의 변화 중 일부를 잃게 될 거예요."라고 말합니다.

Git이 허락하지 않으면 변경사항을 커밋하여 영구적인 어딘가에 저장해야 합니다.이를 사용하여 저장할 수도 있습니다. 이것이 바로 이러한 용도로 설계된 것 중 하나입니다.참고:git stash save또는git stash push실제로는 "모든 변경 사항을 커밋하지만 분기가 전혀 없는 상태에서 현재 위치에서 제거하십시오."를 의미합니다.이를 통해 전환이 가능합니다. 이제 진행 중인 변경 사항이 없습니다.그러면 됩니다.git stash apply전환 후 그들.

사드바:git stash save구문입니다.git stash push 2에 도입되어 Git에 하기 위해 2.13에 도입되었습니다.git stash그리고 새로운 옵션을 허용합니다.둘 다 기본적인 방법으로 사용할 때 동일한 작업을 수행합니다.

원한다면 여기서 그만 읽어도 돼요!

Git이 당신이 전환하지 못하게 한다면, 당신은 이미 해결책이 있습니다: 사용.git stash또는git commit 만드는 것이 에는 또는변항다만것경사우이소를 사용합니다.git checkout -f강제로.이 대답은 Git이 언제 당신에게 허락할 것인가에 관한 것입니다.git checkout branch2당신이 약간의 변화를 시작했음에도 불구하고.왜 가끔은 작동하고 다른 때는 작동하지 않습니까?

여기서의 규칙은 한 가지 방법으로 단순하며 다른 방법으로 설명하기는 어렵습니다.

작업 트리에서 커밋되지 않은 변경 사항이 있는 분기는 해당 변경 사항을 클로버할 필요가 없는 경우에만 전환할 수 있습니다.

즉, 이는 여전히 단순화되어 있습니다. 단계별로 매우 어려운 코너 사례가 있습니다.git adds,git rm기타—당신이 타고 있는 모든 것branch1.a.git checkout branch2 할 것 같습니다.

  • 모든 파일에 대해branch1 없는branch2파일을1 제거합니다.
  • 모든 파일에 대해branch2 없는branch1해당 파일을 만듭니다(해당 내용 포함).
  • , 만약 두분에모파대해일에, 의이버전에 이라면.branch2다릅니다. 작업 트리 버전을 업데이트하십시오.

이러한 각 단계는 작업 트리에서 무언가를 분해할 수 있습니다.

  • 의 버전이 업트리버의버커같합전경파제은거 "일전"의 .branch1당신이 변화를 했다면 그것은 "이상한" 것입니다.
  • 파이표시방는파만일들에 표시되는 으로 파일 branch2지금 2존재하지 않는 경우 "안전"합니다.만약 그것이 지금 존재하지만 "잘못된" 내용을 가지고 있다면 그것은 "안전하지 않습니다.
  • 그리고 물론 작업 트리 버전이 이미 다음과 같이 커밋된 경우 파일의 작업 트리 버전을 다른 버전으로 교체하는 것이 "안전"합니다.branch1.

분기 생성(새분만들기기(기만들git checkout -b newbranch)는 항상 "안전"한 것으로 간주됩니다. 이 프로세스의 일부로 작업 트리에서 파일이 추가, 제거 또는 변경되지 않으며 인덱스/스테이지 영역도 변경되지 않습니다. (Caveat: 새 분기의 시작점을 변경하지 않고 새 분기를 만들 때 안전합니다. 그러나 다른 인수를 추가하면 다음과 같습니다.git checkout -b newbranch different-start-point이것은 상황을 바꿔야 할 수도 있고, 이동하기 위해.different-start-point그런 다음 Git는 체크아웃 안전 규칙을 평소와 같이 적용합니다.)


1이를 위해서는 파일이 분기에 있는 것이 무엇을 의미하는지 정의해야 하며, 이를 위해서는 branch라는 단어를 올바르게 정의해야 합니다. ("branch"란 정확히 무엇을 의미합니까?여기서 제가 정말 의미하는 것은 지점 이름이 확인하는 커밋입니다. 경로가 있는 파일은branch1한다면git rev-parse branch1:P해시를 생성합니다.해당 파일이 없습니다.branch1오류 메시지가 표시되는 경우.인덱스 또는 작업 트리에 경로가 있는지 여부는 이 특정 질문에 대답할 때 관련이 없습니다.따라서, 여기서 비밀은 결과를 검토하는 것입니다.git rev-parse각각의 branch-name:path파일이 최대 하나의 분기에 "들어가" 있기 때문에 실패하거나 두 개의 해시 ID를 제공합니다.두 해시 ID가 같은 경우 파일은 두 분기에서 동일합니다.변경할 필요가 없습니다.해시 ID가 다른 경우 파일은 두 분기에서 다르므로 분기를 전환하려면 변경해야 합니다.

여기서 핵심 개념커밋파일 영구적으로 고정된다는 입니다. 편집할 파일은 분명히 고정되지 않았습니다. 우리는 적어도 처음에는 두 개의 동결된 커밋 사이의 불일치만을 보고 있습니다.안타깝게도 전환할 커밋에 포함되지 않거나 전환할 커밋에 포함된 파일도 처리해야 합니다.따라서 인덱스 및/또는 작업 트리에도 파일이 존재할 수 있으므로 작업 중인 이 두 가지 특정 동결된 커밋이 존재할 필요가 없기 때문에 복잡성이 남아 있습니다.

이미 "올바른 콘텐츠"와 함께 존재하는 경우 "안전한 종류"로 간주될 수 있으므로 Git는 결국 이를 생성할 필요가 2없습니다.나는 이것을 허용하는 Git의 적어도 일부 버전을 기억하지만, 방금 테스트한 결과 Git 1.8.5.4에서 "안전하지 않은" 것으로 간주되었습니다.To-Be-Switch-to 분기와 일치하도록 수정된 수정된 파일에도 동일한 인수가 적용됩니다.그러나 1.8.5.4는 "덮어쓰기"라고만 말합니다.기술 노트의 끝도 참조하십시오. 버전 1.5. 무언가에서 Git를 처음 사용하기 시작한 이후로 읽기 트리 규칙이 변경되지 않았기 때문에 메모리에 결함이 있을 수 있습니다.


변경사항이 단계적인지 아니면 단계적이지 않은지가 중요합니까?

네, 어떤 면에서는요.특히, 작업 트리 파일을 "수정 해제"할 수 있습니다.두 이 파일은 ▁in▁in▁here.branch1그리고.branch2:

$ git show branch1:inboth
this file is in both branches
$ git show branch2:inboth
this file is in both branches
but it has more stuff in branch2 now
$ git checkout branch1
Switched to branch 'branch1'
$ echo 'but it has more stuff in branch2 now' >> inboth

에서 작업 파일은 다음과 같습니다.inboth의것일니다합에 있는 합니다.branch2방송 중인데도branch1이 변경 사항은 커밋을 위해 준비되지 않았습니다.git status --short여기에 표시됩니다.

$ git status --short
 M inboth

Space-then-M은 "수정되었지만 스테이징되지 않음"을 의미합니다(더 정확히 말하면, 작업 트리 복사본은 스테이징된/인덱스 복사본과 다릅니다).

$ git checkout branch2
error: Your local changes ...

있는 아요좋, 이제트복준의 합니다. 이미 알고 있는 복사본과 일치합니다.branch2.

$ git add inboth
$ git status --short
M  inboth
$ git checkout branch2
Switched to branch 'branch2'

여기서 준비된 복사본과 작업 복사본은 둘 다 일치합니다.branch2그래서 체크아웃이 허용되었습니다.

다른 단계를 시도해 보겠습니다.

$ git checkout branch1
Switched to branch 'branch1'
$ cat inboth
this file is in both branches

체크아웃이 준비 영역에 기록되기 때문에 변경한 내용은 준비 영역에서 손실됩니다.이것은 약간 궁지에 몰린 사례입니다.변화가 사라진 것이 아니라, 제가 그것을 무대에 올렸다는 사실이 사라졌습니다.

분기 복사본과 다른 세 번째 변형 파일을 준비한 다음 현재 분기 버전과 일치하도록 작업 복사본을 설정합니다.

$ echo 'staged version different from all' > inboth
$ git add inboth
$ git show branch1:inboth > inboth
$ git status --short
MM inboth

사람M서 의미:이 "" " " " " "와 다릅니다.HEAD파일 및 작업 트리 파일이 준비된 파일과 다릅니다.작업 트리 버전이 다음과 일치합니다.branch1 (일명)HEAD 전버:

$ git diff HEAD
$

그렇지만git checkout체크아웃을 허용하지 않습니다.

$ git checkout branch2
error: Your local changes ...

설정합니다.branch2작업 버전으로서의 버전:

$ git show branch2:inboth > inboth
$ git status --short
MM inboth
$ git diff HEAD
diff --git a/inboth b/inboth
index ecb07f7..aee20fb 100644
--- a/inboth
+++ b/inboth
@@ -1 +1,2 @@
 this file is in both branches
+but it has more stuff in branch2 now
$ git diff branch2 -- inboth
$ git checkout branch2
error: Your local changes ...

이 현재작 의복이일과도의 branch2준비된 파일은 그렇지 않습니다, 그래서.git checkout 되고, 그사복을것고이잃고그리, 본을고▁would▁lose,그리▁that.git checkout거부되었습니다.

기술 노트—미치도록 호기심 많은 사람들만을 위한 노트 :-)

이 모든 것의 기본 구현 메커니즘은 Git's 인덱스입니다."준비 영역"이라고도 하는 인덱스는 다음 커밋을 작성하는 곳입니다. 현재 커밋과 일치하기 시작합니다. 즉, 지금 체크아웃한 것이 무엇이든, 그리고 매번git add파일을 사용하면 인덱스 버전을 작업 트리에 있는 것으로 바꿉니다.

작업 트리는 파일 작업을 수행하는 곳입니다.여기서, 그들은 커밋이나 인덱스에서 하는 것처럼 특별한 유용한 Git-to-Git 형식이 아닌, 그들의 정상적인 형태를 가지고 있습니다.따라서 커밋에서 인덱스를 통해 파일을 추출한 다음 작업 트리로 이동합니다.바꾼 후에, 당신은git add그것을 색인에 붙입니다.실제로 각 파일에는 현재 커밋, 인덱스 및 작업 트리의 세 가지 위치가 있습니다.

을 할 때git checkout branch2Git가 커버 아래에서 하는 것은 팁 커밋을 비교하는 것입니다.branch2현재 커밋과 인덱스 모두에 있는 모든 것.지금 있는 것과 일치하는 파일이면 Git은 그냥 둘 수 있습니다.손도 대지 않았어요. 커밋 모두 동일한 파일이면 Git를 그대로 둘 수도 있습니다. 이러한 파일을 사용하면 분기를 전환할 수 있습니다.

커밋 전환을 포함한 Git의 대부분은 이 지수 때문에 상대적으로 빠릅니다.실제로 인덱스에 있는 것은 각 파일 자체가 아니라 각 파일의 해시입니다.파일의 복사본 자체는 Git가 BLOB 개체라고 부르는 저장소에 저장됩니다.이것은 파일이 커밋에 저장되는 방식과도 유사합니다. 커밋은 실제로 파일을 포함하지 않고 Git을 각 파일의 해시 ID로 이끌 뿐입니다.따라서 Git는 해시 ID(현재 160비트 길이 문자열)를 비교하여 커밋 X와 Y의 파일이 동일한지 여부를 결정할 수 있습니다.그런 다음 이러한 해시 ID를 인덱스의 해시 ID와 비교할 수도 있습니다.

이것이 위의 모든 홀수볼 코너 케이스로 이어지는 것입니다.둘 다 파일이 있는 커밋 X와 Y가 있습니다.path/to/name.txt그리고 우리는 다음을 위한 색인 항목을 가지고 있습니다.path/to/name.txt아마도 세 해시가 모두 일치할 것입니다.아마 둘은 일치하고 하나는 일치하지 않을 것입니다.어쩌면 세 가지 모두 다를 수도 있습니다.는 그고또, 우는한리도 수 .another/file.txt이 값은 X 또는 Y에만 있으며 현재 인덱스에 있거나 없습니다.이러한 다양한 사례들은 각각 별도로 고려해야 합니다. GitX에서 Y로 전환하기 위해 파일을 커밋에서 인덱스로 복사하거나 인덱스에서 제거해야 합니까?이 경우 파일을 작업 트리에 복사하거나 작업 트리에서 제거해야 합니다.그렇다면 인덱스 및 작업 트리 버전은 커밋된 버전 중 하나 이상과 일치하는 것이 좋습니다. 그렇지 않으면 Git가 일부 데이터를 클로빙하게 됩니다.

전체 규칙은 (이모든것대전규있에설다습니어명되칙은체한에▁the,▁for▁not▁(▁()가 아니라 에 되어 있습니다.git checkout예상한 대로의 문서가 아니라 "두의 트리 병합" 섹션에 있는 문서입니다.)

두 가지 선택지가 있습니다. 변경 내용을 저장합니다.

git stash

그들을 되찾기 위해 나중에:

git stash apply

또는 변경사항을 분기에 배치하여 원격 분기를 가져온 다음 변경사항을 분기에 병합할 수 있습니다.이것이 git의 가장 큰 장점 중 하나입니다. 분기를 만들고, 분기에 커밋한 다음, 이전 분기에 다른 변경사항을 가져올 수 있습니다.

말도 안 된다고 하시면서 당기기를 하고 나면 마음대로 병합할 수 있도록 하는 것뿐입니다.분명히 당신의 다른 선택은 당신의 브랜치 복사본을 커밋한 다음 풀을 하는 것입니다.당신이 그렇게 하고 싶지 않거나(이 경우 당신이 지점을 원하지 않는다는 것에 대해 나는 어리둥절합니다) 또는 당신은 갈등을 두려워한다는 가정입니다.

새 분기에 변경된 특정 파일에 대한 현재 분기와 다른 편집 내용이 포함된 경우 변경 내용을 커밋하거나 숨길 때까지 분기를 전환할 수 없습니다.변경된 파일이 두 분기에서 동일한 경우(즉, 해당 파일의 커밋된 버전) 자유롭게 전환할 수 있습니다.

예:

$ echo 'hello world' > file.txt
$ git add file.txt
$ git commit -m "adding file.txt"

$ git checkout -b experiment
$ echo 'goodbye world' >> file.txt
$ git add file.txt
$ git commit -m "added text"
     # experiment now contains changes that master doesn't have
     # any future changes to this file will keep you from changing branches
     # until the changes are stashed or committed

$ echo "and we're back" >> file.txt  # making additional changes
$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
    file.txt
Please, commit your changes or stash them before you can switch branches.
Aborting

이는 추적되지 않은 파일과 추적된 파일에 적용됩니다.다음은 추적되지 않은 파일의 예입니다.

예:

$ git checkout -b experimental  # creates new branch 'experimental'
$ echo 'hello world' > file.txt
$ git add file.txt
$ git commit -m "added file.txt"

$ git checkout master # master does not have file.txt
$ echo 'goodbye world' > file.txt
$ git checkout experimental
error: The following untracked working tree files would be overwritten by checkout:
    file.txt
Please move or remove them before you can switch branches.
Aborting

변경 작업을 수행하면서 분기 간을 이동하려는 이유의 좋은 예는 마스터에 대해 몇 가지 실험을 수행하고 마스터를 커밋하려고 하지만 아직 마스터를 수행하지 않은 경우입니다.

$ echo 'experimental change' >> file.txt # change to existing tracked file
   # I want to save these, but not on master

$ git checkout -b experiment
M       file.txt
Switched to branch 'experiment'
$ git add file.txt
$ git commit -m "possible modification for file.txt"

정답은.

git checkout -m origin/master

원본 마스터 분기의 변경 사항을 커밋되지 않은 로컬 변경 사항과 병합합니다.

  1. 분기 전환은 두 분기 간에 차이가 없는 파일을 변경하는 경우에만 수행됩니다.이 경우 Git는 두 파일 모두에 대해 변경 사항을 공통적으로 처리합니다.
  2. 두 분기 사이에 차이가 있는 파일을 변경하면 이 문제가 방지됩니다.이 경우 ABORT 신호가 수신됩니다.

현지 테스트를 통해 몇 시간 동안 조사한 끝에 이러한 결론에 도달했습니다.

저는 최근에 같은 질문에 직면했습니다.제가 이해하는 것은 체크인 중인 지점에 당신이 수정한 파일이 있고 해당 지점에서도 수정 및 커밋이 가능하다는 것입니다.그런 다음 Git을 사용하면 커밋하거나 보관하기 전에 변경 사항을 안전하게 유지하기 위해 분기로 전환하는 것을 방지할 수 있습니다.

저도 한동안 이것 때문에 어려움을 겪었고 저는 그 답에 2센트를 주고 싶습니다.우선, 이 문제에 대한 저의 이해는 여기서 나왔습니다: https://medium.com/swimm/a-visualized-intro-to-git-internals-objects-and-branches-68df85864037 .

질문은 다음과 같습니다.

그러나 때때로 Git는 변경 사항을 커밋하거나 저장하지 않고 다른 지점을 체크아웃할 수 있도록 허용하며, 이러한 변경 사항은 내가 체크아웃하는 지점으로 전달됩니다.

여기 규칙은 무엇입니까?변경사항이 단계적인지 아니면 단계적이지 않은지가 중요합니까?변경 사항을 다른 지점으로 옮기는 것은 말이 안 되는데, 왜 가끔은 git에서 허용하는 걸까요?즉, 어떤 상황에서 도움이 됩니까?

다른 분기에서 분기를 생성할 때는 동일한 커밋에 대한 포인터만 생성하므로 작업을 시작한 변경 사항이 없는 한 동일한 커밋을 가리키게 되므로 Git을 사용하여 분기를 변경할 수 있습니다.새 분기에 대한 변경 사항을 커밋할 때만 분기마다 커밋이 달라지기 시작하며 커밋되지 않은 변경 사항이 있는 경우 해당 분기를 체크아웃하려고 할 때 Git가 불만을 제기합니다.

에는 을 수행합니다.git reset --hard.

다음으로 원하는 지점으로 체크아웃할 수 있지만 커밋되지 않은 변경사항은 손실됩니다.

언급URL : https://stackoverflow.com/questions/22053757/checkout-another-branch-when-there-are-uncommitted-changes-on-the-current-branch

반응형