paint-brush
Git 기록을 자신 있게 다시 작성하기: 가이드~에 의해@omerosenbaum
2,019 판독값
2,019 판독값

Git 기록을 자신 있게 다시 작성하기: 가이드

~에 의해 Omer Rosenbaum18m2023/04/27
Read on Terminal Reader
Read this story w/o Javascript

너무 오래; 읽다

Git은 파일 시스템의 스냅샷을 적시에 기록하는 시스템입니다. Git 저장소에는 인덱스, 준비 영역, 작업 트리라는 세 가지 "상태" 또는 "트리"가 있습니다. 작업 디렉토리(ectrory)는 Git 저장소가 연결된 파일 시스템의 모든 디렉토리입니다.
featured image - Git 기록을 자신 있게 다시 작성하기: 가이드
Omer Rosenbaum HackerNoon profile picture

개발자는 항상 Git을 사용하여 작업합니다.


“아, 내가 방금 무슨 짓을 한 거야?”라고 말하는 지점에 도달한 적이 있습니까?

Git에 문제가 생기면 많은 엔지니어가 무력감을 느낍니다(출처: XKCD)


이 게시물은 자신있게 역사를 다시 쓸 수 있는 도구를 제공합니다.

시작하기 전 참고 사항

  1. 이 게시물의 내용을 다루는 라이브 토크도 진행했습니다. 비디오를 선호하거나 독서와 함께 시청하고 싶다면 찾을 수 있습니다. 여기 .


  2. 저는 Git에 관한 책을 집필 중입니다! 초기 버전을 읽고 피드백을 제공하는 데 관심이 있으십니까? 이메일을 보내주세요: [email protected]

Git에 변경 사항 기록

Git에서 작업을 취소하는 방법을 이해하기 전에 먼저 Git에서 변경 사항을 기록하는 방법을 이해해야 합니다. 이미 모든 용어를 알고 있다면 이 부분을 건너뛰셔도 됩니다.


Git을 시간에 맞춰 파일 시스템의 스냅샷을 기록하는 시스템으로 생각하는 것은 매우 유용합니다. Git 저장소를 고려하면 세 가지 "상태" 또는 "트리"가 있습니다.

Git 저장소의 세 가지 '트리'(출처: https://youtu.be/ozA1V00GIT8)


일반적으로 소스 코드 작업을 할 때 작업 디렉토리 에서 작업합니다. 작업 디렉토리(ectrory) (또는 작업 트리 )는 연관된 저장소 가 있는 파일 시스템의 디렉토리입니다.


여기에는 프로젝트의 폴더와 파일과 .git 이라는 디렉터리도 포함되어 있습니다. .git 폴더의 내용에 대해 더 자세히 설명했습니다. 이전 게시물 .


일부 변경 사항을 적용한 후 해당 내용을 저장소 에 기록할 수 있습니다. 저장소 (간단히 repo )는 커밋 모음으로, 각 커밋은 자신의 컴퓨터에서든 다른 사람의 컴퓨터에서든 과거 날짜에 프로젝트의 작업 트리가 어땠는지에 대한 아카이브입니다.


저장소에는 HEAD , 분기 등과 같은 코드 파일 이외의 항목도 포함됩니다.


그 사이에는 인덱스 또는 준비 영역이 있습니다. 이 두 용어는 서로 바꿔 사용할 수 있습니다. 브랜치를 checkout 하면 Git은 작업 디렉터리 에서 마지막으로 체크아웃한 모든 파일 내용과 원래 체크아웃했을 때의 모습으로 인덱스를 채웁니다.


git commit 사용하면 인덱스 상태에 따라 커밋이 생성됩니다.


따라서 인덱스 또는 준비 영역은 다음 커밋을 위한 놀이터입니다. 인덱스를 사용하여 원하는 모든 작업을 수행하고, 인덱스 에 파일을 추가하고, 인덱스에서 항목을 제거한 다음 준비가 되었을 때만 저장소에 커밋할 수 있습니다.


직접 체험해볼 시간 🙌🏻


git init 사용하여 새 저장소를 초기화합니다. 1.txt 라는 파일에 텍스트를 작성합니다.

새 저장소를 시작하고 그 안에 첫 번째 파일 만들기(출처: https://youtu.be/ozA1V00GIT8)


위에서 설명한 세 가지 트리 상태 중 1.txt 현재 어디에 있습니까?


작업 트리에서는 아직 인덱스에 도입되지 않았습니다.

'1.txt' 파일은 이제 작업 디렉터리에만 포함됩니다(출처: https://youtu.be/ozA1V00GIT8).


이를 준비 하고 인덱스에 추가하려면 git add 1.txt 사용하세요.

`git add`를 사용하면 파일이 이제 색인에도 포함되도록 준비됩니다(출처: https://youtu.be/ozA1V00GIT8).


이제 git commit 사용하여 변경 사항을 저장소에 커밋할 수 있습니다.

`git commit`을 사용하면 저장소에 커밋 개체가 생성됩니다(출처: https://youtu.be/ozA1V00GIT8).


전체 작업 트리를 설명하는 트리에 대한 포인터를 포함하는 새 커밋 개체를 만들었습니다. 이 경우 루트 폴더 내에는 1.txt 만 있을 것입니다. 커밋 개체에는 트리에 대한 포인터 외에도 타임스탬프 및 작성자 정보와 같은 메타데이터가 포함됩니다.


Git의 개체(예: 커밋 및 트리)에 대한 자세한 내용을 보려면 내 이전 게시물을 확인해 보세요 .


(예, "체크아웃", 말장난 의도 😇)


Git은 또한 이 커밋 개체의 SHA-1 값을 알려줍니다. 제 경우에는 c49f4ba 였습니다(공간을 절약하기 위해 SHA-1 값의 처음 7자만 포함).


컴퓨터에서 이 명령을 실행하면 작성자가 다르기 때문에 다른 SHA-1 값을 얻게 됩니다. 또한 다른 타임스탬프에 커밋을 생성하게 됩니다.


repo를 초기화하면 Git은 새 브랜치를 생성합니다(기본적으로 main 이라는 이름). 그리고 Git의 브랜치는 커밋에 대한 명명된 참조일 뿐입니다. . 따라서 기본적으로 main 분기만 있습니다. 지점이 여러 개 있으면 어떻게 되나요? Git은 어떤 브랜치가 활성 브랜치인지 어떻게 알 수 있나요?


Git에는 HEAD 라는 또 다른 포인터가 있는데, 이 포인터는 (보통) 브랜치를 가리킨 다음 커밋을 가리킵니다. 그런데, 후드, HEAD 그냥 파일이에요. 여기에는 일부 접두사와 함께 지점 이름이 포함됩니다.


저장소에 더 많은 변경 사항을 도입할 시간입니다!


이제 또 다른 것을 만들고 싶습니다. 이제 이전과 같이 새 파일을 만들고 이를 인덱스에 추가해 보겠습니다.

`2.txt` 파일은 작업 디렉토리에 있으며 `git add`를 사용하여 스테이징한 후 색인에 있습니다(출처: https://youtu.be/ozA1V00GIT8).


이제 git commit 사용할 차례입니다. 중요한 것은 git commit 두 가지 작업을 수행한다는 것입니다.


먼저 커밋 객체를 생성하므로 Git의 내부 객체 데이터베이스 내에 해당 SHA-1 값을 가진 객체가 있습니다. 이 새로운 커밋 개체는 상위 커밋도 가리킵니다. 이것이 git commit 명령을 작성할 때 HEAD 가 가리키는 커밋입니다.

처음에는 새로운 커밋 개체가 생성되었습니다. 'main'은 여전히 이전 커밋을 가리킵니다(출처: https://youtu.be/ozA1V00GIT8).


둘째, git commit 새로 생성된 커밋 개체를 가리키도록 활성 분기(우리의 경우 main 의 포인터를 이동합니다.

`git commit`은 또한 새로 생성된 커밋 객체를 가리키도록 활성 분기를 업데이트합니다(출처: https://youtu.be/ozA1V00GIT8).


변경 사항 취소

기록을 다시 작성하려면 커밋 도입 프로세스를 실행 취소하는 것부터 시작하겠습니다. 이를 위해 우리는 매우 강력한 도구인 git reset 명령을 알게 될 것입니다.

git reset --soft

따라서 이전에 수행한 마지막 단계는 git commit 이었습니다. 이는 실제로 두 가지를 의미합니다. Git이 커밋 개체를 생성하고 활성 분기인 main 이동했습니다. 이 단계를 실행 취소하려면 git reset --soft HEAD~1 명령을 사용하세요.


HEAD~1 구문은 HEAD 의 첫 번째 부모를 나타냅니다. 커밋 그래프에 커밋이 두 개 이상 있는 경우 "커밋 2"를 가리키는 "커밋 3"이라고 말합니다. 이는 차례로 "커밋 1"을 가리킵니다.


그리고 HEAD "Commit 3"을 가리키고 있다고 가정해 보겠습니다. HEAD~1 사용하여 "커밋 2"를 참조할 수 있고 HEAD~2 "커밋 1"을 참조할 수 있습니다.


이제 다음 명령으로 돌아갑니다: git reset --soft HEAD~1


이 명령은 Git에게 HEAD 가 가리키는 내용을 변경하도록 요청합니다. (참고: 아래 다이어그램에서는 " HEAD 가 가리키는 모든 것"을 의미하는 *HEAD 사용합니다.) 이 예에서 HEAD main 가리키고 있습니다. 따라서 Git은 main 포인터가 HEAD~1 을 가리키도록 변경합니다. 즉, main "Commit 1"을 가리킵니다.


그러나 이 명령은 인덱스나 작업 트리의 상태에 영향을 미치지 않습니다 . 따라서 git status 사용하면 git commit 실행하기 전과 마찬가지로 2.txt 가 준비되는 것을 볼 수 있습니다.

`main`을 'Commit 1'로 재설정(출처: https://youtu.be/ozA1V00GIT8)


git log? HEAD 에서 시작하여 main 으로 이동한 다음 “Commit 1”로 이동합니다. 이는 기록에서 더 이상 “Commit 2”에 접근할 수 없음을 의미합니다.


이는 "Commit 2"의 커밋 개체가 삭제된다는 의미입니까? 🤔


아니요, 삭제되지 않았습니다. 이는 여전히 Git의 내부 개체 데이터베이스 내에 있습니다.


지금 git push 사용하여 현재 기록을 푸시하면 Git은 "Commit 2"를 원격 서버에 푸시하지 않지만 커밋 개체는 여전히 저장소의 로컬 복사본에 존재합니다.


이제 다시 커밋하고 "Commit 2.1"의 커밋 메시지를 사용하여 이 새 객체를 원래 "Commit 2"와 구별합니다.

새 커밋 만들기(출처: https://youtu.be/ozA1V00GIT8)


"커밋 2"와 "커밋 2.1"이 다른 이유는 무엇입니까? 동일한 커밋 메시지를 사용하고, 같은 나무 개체 ( 1.txt2.txt 로 구성된 루트 폴더) 서로 다른 시간에 생성되었으므로 여전히 서로 다른 타임스탬프를 갖습니다.


위 그림에서는 Git의 내부 개체 데이터베이스에 여전히 존재한다는 점을 상기시키기 위해 “Commit 2”를 유지했습니다. 이제 "Commit 2"와 "Commit 2.1"은 모두 "Commit 1"을 가리키지만 HEAD 에서는 "Commit 2.1"만 연결할 수 있습니다.

힘내 재설정 - 혼합

이제는 뒤로 돌아가서 더 멀리 실행 취소해야 할 때입니다. 이번에는 git reset --mixed HEAD~1 사용하세요(참고: --mixedgit reset 의 기본 스위치입니다).


이 명령은 git reset --soft HEAD~1 과 동일하게 시작됩니다. 즉, HEAD 현재 가리키는 포인터( main 브랜치)를 가져와 HEAD~1 로 설정한다는 의미입니다(예: "Commit 1").

`git Reset --mixed`의 첫 번째 단계는 `git Reset --soft`와 동일합니다(출처: https://youtu.be/ozA1V00GIT8).


다음으로 Git은 더 나아가 인덱스에 대한 변경 사항을 효과적으로 취소합니다. 즉, 첫 번째 단계에서 설정한 후 새 HEAD 현재 HEAD 와 일치하도록 인덱스를 변경하는 것입니다.


git reset --mixed HEAD~1 실행하면 HEAD HEAD~1 (“Commit 1”)로 설정되고 Git이 인덱스를 “Commit 1” 상태와 일치시킨다는 뜻입니다. 이 경우에는 이는 2.txt 더 이상 색인의 일부가 아니라는 의미입니다.

`git Reset --mixed`의 두 번째 단계는 색인을 새로운 `HEAD`와 일치시키는 것입니다(출처: https://youtu.be/ozA1V00GIT8).


이제 원래 “Commit 2” 상태로 새 커밋을 생성할 차례입니다. 이번에는 2.txt 를 생성하기 전에 다시 스테이지해야 합니다.

'Commit 2.2' 생성(출처: https://youtu.be/ozA1V00GIT8)


Git 재설정 --하드

계속해서 더 많은 작업을 취소하세요!


계속해서 git reset --hard HEAD~1 실행하세요.


다시 Git은 --soft 단계로 시작하여 HEAD 가 가리키는 모든 항목( main )을 HEAD~1 (“Commit 1”)로 설정합니다.

`git Reset --hard`의 첫 번째 단계는 `git Reset --soft`와 동일합니다. (출처: https://youtu.be/ozA1V00GIT8)


여태까지는 그런대로 잘됐다.


다음으로 --mixed 단계로 이동하여 인덱스를 HEAD 와 일치시킵니다. 즉, Git은 2.txt 의 준비를 취소합니다.

`git Reset --hard`의 두 번째 단계는 `git Reset --mixed`와 동일합니다(출처: https://youtu.be/ozA1V00GIT8).


이제 Git이 더 나아가 작업 디렉토리를 인덱스 단계와 일치시키는 --hard 단계를 수행할 시간입니다. 이 경우 작업 디렉토리에서도 2.txt 제거한다는 의미입니다.

`git Reset --hard`의 세 번째 단계는 작업 디렉토리의 상태를 인덱스의 상태와 일치시킵니다(출처: https://youtu.be/ozA1V00GIT8).


(**참고: 이 특정 경우에는 파일이 추적되지 않으므로 파일 시스템에서 삭제되지 않습니다. 하지만 git reset 이해하는 데는 그다지 중요하지 않습니다.)


따라서 Git에 변경 사항을 적용하려면 세 단계를 거쳐야 합니다. 작업 디렉토리, 인덱스 또는 스테이징 영역을 변경한 다음 해당 변경 사항이 포함된 새 스냅샷을 커밋합니다. 이러한 변경 사항을 실행 취소 하려면 다음을 수행하세요.


  • git reset --soft 사용하면 커밋 단계가 실행 취소됩니다.


  • git reset --mixed 사용하면 스테이징 단계도 실행 취소됩니다.


  • git reset --hard 사용하면 작업 디렉토리에 대한 변경 사항이 취소됩니다.

실제 시나리오!

시나리오 #1

따라서 실제 시나리오에서는 우리 모두 Git을 좋아하므로 "I love Git"을 파일( love.txt )에 작성하세요. 다음도 준비하고 커밋하세요.

'Commit 2.3' 생성(출처: https://youtu.be/ozA1V00GIT8)


아, 이런!


사실 나는 당신이 그런 일을 저지르기를 바라지 않았습니다.


내가 실제로 당신에게 바라는 것은 이 파일을 커밋하기 전에 이 파일에 사랑의 말을 더 적어주는 것입니다.

당신은 무엇을 할 수 있나요?


이 문제를 극복하는 한 가지 방법은 git reset --mixed HEAD~1 사용하여 수행한 커밋 및 스테이징 작업을 효과적으로 실행 취소하는 것입니다.

스테이징 및 커밋 단계 실행 취소(출처: https://youtu.be/ozA1V00GIT8)


따라서 main 다시 “Commit 1”을 가리키며 love.txt 더 이상 인덱스의 일부가 아닙니다. 그러나 파일은 작업 디렉토리에 남아 있습니다. 이제 더 많은 콘텐츠를 추가할 수 있습니다.

사랑 가사 더 추가하기(출처: https://youtu.be/ozA1V00GIT8)


계속해서 파일을 스테이징하고 커밋하세요.

원하는 상태로 새 커밋 만들기(출처: https://youtu.be/ozA1V00GIT8)


잘했어요 👏🏻


"Commit 1"을 가리키는 "Commit 2.4"의 명확하고 멋진 기록을 얻었습니다.


이제 도구 상자에 git reset 새로운 도구가 생겼습니다 💪🏻

git Reset은 이제 도구 상자에 있습니다(출처: https://youtu.be/ozA1V00GIT8).


이 도구는 매우 매우 유용하며 이 도구를 사용하면 거의 모든 작업을 수행할 수 있습니다. 항상 사용하기 가장 편리한 도구는 아니지만 주의 깊게 사용하면 거의 모든 기록 다시 쓰기 시나리오를 해결할 수 있습니다.


초보자의 경우 Git에서 실행 취소하려는 거의 모든 시간에 git reset 만 사용하는 것이 좋습니다. 익숙해지면 다른 도구로 넘어갈 차례입니다.

시나리오 #2

또 다른 경우를 고려해 보겠습니다.


new.txt 라는 새 파일을 만듭니다. 스테이지 및 커밋:

`new.txt` 및 'Commit 3' 생성(출처: https://youtu.be/ozA1V00GIT8)


이런. 사실 그것은 실수입니다. 당신은 main 에 있었고 기능 브랜치에서 이 커밋을 생성하길 원했습니다. 안됐어 😇


이 게시물에서 가장 중요한 두 가지 도구를 활용하시기 바랍니다. 두 번째는 git reset 입니다. 첫 번째이자 훨씬 더 중요한 것은 현재 상태와 원하는 상태를 화이트보드로 작성하는 것 입니다.


이 시나리오의 경우 현재 상태와 원하는 상태는 다음과 같습니다.

시나리오 #2: 현재 상태와 원하는 상태(출처: https://youtu.be/ozA1V00GIT8)


세 가지 변경 사항을 확인할 수 있습니다.


  1. main 포인트는 현재 상태에서는 "Commit 3"(파란색)이지만 원하는 상태에서는 "Commit 2.4"입니다.


  2. feature 브랜치는 현재 상태에는 존재하지 않지만 존재하며 원하는 상태의 "Commit 3"을 가리킵니다.


  3. HEAD 현재 상태의 main 과 원하는 상태의 feature 가리킵니다.


이것을 그릴 수 있고 git reset 사용법을 안다면 확실히 이 상황에서 벗어날 수 있습니다.


그러니 다시 한 번 말씀드리지만, 가장 중요한 것은 숨을 들이쉬고 이를 뽑아내는 것입니다.


위의 그림을 관찰하면서, 현재 상태에서 원하는 상태로 어떻게 갈 수 있을까요?


물론 몇 가지 다른 방법이 있지만 각 시나리오에 대해 하나의 옵션만 제시하겠습니다. 다른 옵션도 자유롭게 사용해 보세요.


git reset --soft HEAD~1 사용하여 시작할 수 있습니다. 이렇게 하면 main 이전 커밋인 “Commit 2.4”를 가리키도록 설정됩니다.

`메인` 변경; “커밋 3은 아직 거기에 있지만 연결할 수 없기 때문에 흐릿합니다(출처: https://youtu.be/ozA1V00GIT8).


현재-원하는 다이어그램을 다시 보면 새로운 브랜치가 필요하다는 것을 알 수 있죠? git switch -c feature 사용하거나 git checkout -b feature (동일한 기능을 수행함)을 사용할 수 있습니다.

'feature' 브랜치 생성(출처: https://youtu.be/ozA1V00GIT8)


이 명령은 또한 HEAD 업데이트하여 새 분기를 가리키도록 합니다.


git reset --soft 사용했기 때문에 인덱스를 변경하지 않았으므로 현재 커밋하려는 상태가 정확하게 유지됩니다. 정말 편리합니다! 간단히 feature 브랜치에 커밋할 수 있습니다.

'feature' 브랜치에 커밋(출처: https://youtu.be/ozA1V00GIT8)


그리고 원하는 상태에 도달했습니다 🎉

시나리오 #3

추가 사례에 지식을 적용할 준비가 되셨나요?


love.txt 에 몇 가지 변경 사항을 추가하고, cool.txt 라는 새 파일도 만듭니다. 준비하고 커밋합니다.

'커밋 4' 생성(출처: https://youtu.be/ozA1V00GIT8)


아, 이런, 사실 저는 각 변경 사항마다 하나씩 두 개의 별도 커밋을 생성하길 원했습니다 🤦🏻

직접 시도해 보고 싶으신가요?


커밋 및 스테이징 단계를 실행 취소할 수 있습니다.

`git Reset --mixed HEAD~1`을 사용하여 커밋 및 스테이징 실행 취소(출처: https://youtu.be/ozA1V00GIT8)


이 명령을 따르면 인덱스에는 더 이상 두 가지 변경 사항이 포함되지 않지만 둘 다 여전히 파일 시스템에 있습니다. 이제 love.txt 만 스테이징하는 경우 별도로 커밋할 수 있으며, cool.txt 에도 동일한 작업을 수행할 수 있습니다.

별도로 커밋(출처: https://youtu.be/ozA1V00GIT8)


좋아요 😋

시나리오 #4

일부 텍스트가 포함된 새 파일( new_file.txt )을 만들고 love.txt 에 일부 텍스트를 추가합니다. 두 가지 변경 사항을 모두 준비하고 커밋합니다.

새로운 커밋(출처: https://youtu.be/ozA1V00GIT8)


이런 🙈🙈


그래서 이번에는 새로운 브랜치가 아닌 이미 존재하는 브랜치에 있기를 원했습니다.


그럼 당신은 무엇을 할 수 있나요?


힌트를 드리겠습니다. 대답은 정말 짧고 정말 쉽습니다. 우리는 무엇을 먼저 해야 할까요?


아니요, reset 하지 않습니다. 우리는 그립니다. 그것이 가장 먼저 해야 할 일입니다. 그렇게 하면 다른 모든 일이 훨씬 쉬워질 것입니다. 따라서 현재 상태는 다음과 같습니다.

`main`에 대한 새 커밋이 파란색으로 표시됩니다(출처: https://youtu.be/ozA1V00GIT8)


그리고 원하는 상태는?

우리는 '블루' 커밋이 다른 '기존' 브랜치에 있기를 원합니다(출처: https://youtu.be/ozA1V00GIT8).


현재 상태에서 원하는 상태로 어떻게 이동합니까? 가장 쉬운 방법은 무엇입니까?


따라서 한 가지 방법은 이전처럼 git reset 사용하는 것이지만, 여러분이 시도해 보셨으면 하는 또 다른 방법이 있습니다.


먼저 existing 분기를 가리키도록 HEAD 이동합니다.

'기존' 분기로 전환합니다(출처: https://youtu.be/ozA1V00GIT8)


직관적으로 원하는 작업은 파란색 커밋에 도입된 변경 사항을 적용하고 이러한 변경 사항("복사-붙여넣기")을 existing 분기 위에 적용하는 것입니다. 그리고 Git에는 이를 위한 도구가 있습니다.


Git에게 이 커밋과 상위 커밋 사이에 도입된 변경 사항을 적용하고 이러한 변경 사항을 활성 브랜치에만 적용하도록 요청하려면 git cherry-pick 사용할 수 있습니다. 이 명령은 지정된 개정에 도입된 변경 사항을 가져와 활성 커밋에 적용합니다.


또한 새 커밋 개체를 만들고 이 새 개체를 가리키도록 활성 분기를 업데이트합니다.

`git Cherry-pick` 사용(출처: https://youtu.be/ozA1V00GIT8)


위의 예에서는 생성된 커밋의 SHA-1 식별자를 지정했지만 git cherry-pick main 사용할 수도 있습니다. 변경 사항을 적용하는 커밋이 main 이 가리키는 커밋이기 때문입니다.


하지만 우리는 이러한 변경 사항이 main 브랜치에 존재하는 것을 원하지 않습니다. git cherry-pick existing 브랜치에만 변경 사항을 적용했습니다. main 에서 어떻게 제거할 수 있나요?


한 가지 방법은 다시 main 으로 switch 다음 git reset --hard HEAD~1 사용하는 것입니다.

`main` 재설정(출처: https://youtu.be/ozA1V00GIT8)


훌륭해! 💪🏻


git cherry-pick 실제로 지정된 커밋과 상위 커밋 간의 차이를 계산한 다음 이를 활성 커밋에 적용합니다. 이는 때때로 충돌이 발생할 수 있기 때문에 Git이 이러한 변경 사항을 적용할 수 없다는 것을 의미하지만 이는 다른 게시물의 주제입니다.


또한 브랜치에서 참조하는 커밋뿐만 아니라 모든 커밋에 도입된 변경 사항을 cherry-pick Git에 요청할 수 있습니다.


우리는 새로운 도구를 얻었으므로 git resetgit cherry-pick 우리 벨트 아래에 있습니다.

시나리오 #5

좋아요, 또 다른 날, 또 다른 저장소, 또 다른 문제입니다.


커밋을 만듭니다.

또 다른 커밋(출처: https://youtu.be/ozA1V00GIT8)


그리고 이를 원격 서버로 push .

(출처: https://youtu.be/ozA1V00GIT8)


음, 이런 😓…


방금 뭔가를 발견했습니다. 거기에 오타가 있습니다. 나는 This is more tezt This is more text tezt라고 썼습니다. 앗. 그렇다면 지금 가장 큰 문제는 무엇입니까? 나는 ed를 push . 이는 다른 사람이 이미 해당 변경 사항을 pull ed했을 수도 있음을 의미합니다.


지금까지 해왔던 것처럼 git reset 사용하여 이러한 변경 사항을 무시하면 다른 기록이 생기고 모든 것이 풀릴 수 있습니다. push 할 때까지 원하는 만큼 저장소 복사본을 다시 작성할 수 있습니다.


변경 사항을 push 후 기록을 다시 작성하려면 다른 사람이 해당 변경 사항을 가져오지 않았는지 확인 해야 합니다.


또는 git revert 라는 다른 도구를 사용할 수도 있습니다. 이 명령은 git cherry-pick 과 마찬가지로 제공하는 커밋을 가져와 상위 커밋에서 Diff를 계산하지만 이번에는 역 변경 사항을 계산합니다.


따라서 지정된 커밋에 줄을 추가하면 그 반대의 경우 해당 줄이 삭제되고 그 반대의 경우도 마찬가지입니다.

`git revert`를 사용하여 변경 사항을 취소합니다(출처: https://youtu.be/ozA1V00GIT8)


git revert 새로운 커밋 객체를 생성했는데, 이는 기록에 추가되었음을 의미합니다. git revert 사용하면 기록을 다시 쓰지 않았습니다. 당신은 과거의 실수를 인정했고, 이 커밋은 당신이 실수를 했고 이제 그것을 고쳤다는 것을 인정하는 것입니다.


어떤 사람들은 그것이 더 성숙한 방법이라고 말할 것입니다. 어떤 사람들은 git reset 사용하여 이전 커밋을 다시 작성했을 때처럼 기록이 깨끗하지 않다고 말합니다. 그러나 이는 역사를 다시 쓰는 것을 방지하는 방법입니다.


이제 오타를 수정하고 다시 커밋할 수 있습니다.

변경사항 다시 실행(출처: https://youtu.be/ozA1V00GIT8)


이제 도구 상자에 새로운 빛나는 도구인 revert 로드되었습니다.

도구 상자(출처: https://youtu.be/ozA1V00GIT8)


시나리오 #6

작업을 완료하고, 코드를 작성하고, love.txt 에 추가하세요. 이 변경 사항을 준비하고 커밋합니다.

또 다른 커밋(출처: https://youtu.be/ozA1V00GIT8)


내 컴퓨터에서도 동일한 작업을 수행했으며 키보드의 Up 화살표 키를 사용하여 이전 명령으로 다시 스크롤한 다음 Enter 를 쳤습니다. 와우.


앗.

방금 `git Reset --hard`를 수행했나요? (출처: https://youtu.be/ozA1V00GIT8)


방금 git reset --hard 사용했나요? 😨


실제로 무슨 일이 일어났나요? Git은 포인터를 HEAD~1 로 옮겼으므로 나의 소중한 작업이 포함된 마지막 커밋은 현재 기록에서 도달할 수 없습니다. Git은 또한 스테이징 영역의 모든 변경 사항을 언스테이징한 다음 작업 디렉토리를 스테이징 영역의 상태와 일치시켰습니다.


즉, 모든 것이 내 작업이… 사라진 이 상태와 일치합니다.


정신없는 시간. 정말 놀랍다.

그런데 정말, 겁을 먹을 이유가 있나요? 그렇지 않아요… 우리는 편안한 사람들이에요. 우리는 무엇을해야합니까? 글쎄요, 직관적으로 커밋이 정말로 사라졌나요? 아니요. 왜 안 되나요? Git의 내부 데이터베이스에는 여전히 존재합니다.


그것이 어디에 있는지 알고 있다면 이 커밋을 식별하는 SHA-1 값을 알고 복원할 수 있습니다. 실행 취소를 취소하고 이 커밋으로 다시 reset 할 수도 있습니다.


따라서 여기서 정말로 필요한 것은 "삭제된" 커밋의 SHA-1입니다.


그래서 질문은 어떻게 찾을 수 있느냐는 것입니다. git log 유용할까요?


글쎄,별로. git log 우리가 찾고 있는 커밋의 상위 커밋을 가리키는 main 가리키는 HEAD 로 이동합니다. 그런 다음 git log 내 소중한 작업에 대한 커밋을 포함하지 않는 상위 체인을 통해 다시 추적합니다.

이 경우 `git log`는 도움이 되지 않습니다(출처: https://youtu.be/ozA1V00GIT8).


감사하게도 Git을 만든 매우 똑똑한 사람들이 우리를 위해 백업 계획도 만들었고, 이를 reflog 라고 합니다.


Git으로 작업하는 동안 HEAD 변경할 때마다( git reset 사용하여 수행할 수 있지만 git switch 또는 git checkout 과 같은 다른 명령도 사용할 수 있음) Git은 reflog 에 항목을 추가합니다.


`git reflog`는 `HEAD`가 어디에 있는지 보여줍니다(출처: https://youtu.be/ozA1V00GIT8).


커밋을 찾았습니다! 0fb929e 로 시작하는 것입니다.


"닉네임"( HEAD@{1} 으로도 관련시킬 수 있습니다. 따라서 Git은 HEAD~1 사용하여 HEAD 의 첫 번째 상위 항목을 참조하고 HEAD~2 사용하여 HEAD 의 두 번째 상위 항목을 참조하는 등 Git은 HEAD@{1} 사용하여 HEAD 의 첫 번째 reflog 상위 항목을 참조합니다. 여기서 HEAD 이전 단계에서 가리켰습니다.


git rev-parse 값을 표시하도록 요청할 수도 있습니다.

(출처: https://youtu.be/ozA1V00GIT8)


reflog 보는 또 다른 방법은 git log -g 사용하는 것입니다. 이 명령은 git log 에 실제로 reflog 고려하도록 요청합니다.

`git log -g`의 출력(출처: https://youtu.be/ozA1V00GIT8)


위에서 HEAD 와 마찬가지로 reflog 도 “Commit 2”를 가리키는 main 가리킨다는 것을 알 수 있습니다. 그러나 reflog 에 있는 해당 항목의 상위 항목은 "Commit 3"을 가리킵니다.


따라서 "Commit 3"으로 돌아가려면 git reset --hard HEAD@{1} (또는 "Commit 3"의 SHA-1 값)을 사용하면 됩니다.

(출처: https://youtu.be/ozA1V00GIT8)


이제 git log 실행하면 다음과 같습니다.

우리의 역사가 돌아왔다!!! (출처: https://youtu.be/ozA1V00GIT8)


우리는 그날을 구했습니다! 🎉👏🏻


이 명령을 다시 사용하면 어떻게 되나요? 그리고 git commit --reset HEAD@{1} 실행했습니까? Git은 HEAD 마지막 reset 이전에 HEAD 가 가리키는 위치, 즉 "Commit 2"로 설정합니다. 우리는 하루 종일 계속할 수 있습니다:

(출처: https://youtu.be/ozA1V00GIT8)


지금 도구 상자를 살펴보면 Git에서 문제가 발생하는 여러 가지 사례를 해결하는 데 도움이 되는 도구가 포함되어 있습니다.

우리의 도구 상자는 매우 광범위합니다! (출처: https://youtu.be/ozA1V00GIT8)


이러한 도구를 사용하면 이제 Git 작동 방식을 더 잘 이해할 수 있습니다. 구체적으로 기록을 다시 작성할 수 있는 더 많은 도구( git rebase )가 있지만 이 게시물에서 이미 많은 것을 배웠습니다. 다음 포스팅에서는 git rebase 에 대해서도 알아보겠습니다.


이 도구 상자에 나열된 다섯 가지 도구보다 훨씬 더 중요한 가장 중요한 도구는 현재 상황과 원하는 상황을 화이트보드에 표시하는 것입니다. 저를 믿으십시오. 그러면 모든 상황이 덜 어려워지고 해결책이 더 명확해지게 될 것입니다.

Git에 대해 자세히 알아보기

이 게시물의 내용을 다루는 라이브 토크도 진행했습니다. 비디오를 선호하거나 독서와 함께 시청하고 싶다면 찾을 수 있습니다. .


일반적으로, 내 YouTube 채널 Git과 그 내부의 여러 측면을 다룹니다. 당신을 환영합니다 확인 해봐 (말장난 의도 😇)

저자 소개

오메르 로젠바움 의 CTO이자 공동 창립자입니다. 수영 , 개발자와 팀이 최신 내부 문서를 통해 코드베이스에 대한 지식을 관리하는 데 도움이 되는 개발 도구입니다. Omer는 Check Point Security Academy의 설립자이자 재능 있는 전문가를 양성하여 기술 분야에서 경력을 개발하는 교육 기관인 ITC의 사이버 보안 책임자였습니다.


Omer는 Tel Aviv University에서 언어학 석사를 취득했으며 간략한 YouTube 채널 .


여기에 처음 게시됨