git

[Git과 GitHub 입문] 7~11 Pull, 충돌해결, 커밋 되돌리기

EunaSon 2023. 10. 8. 18:28

7. Pull 및 충돌 해결하기

- 오늘 할 내용 요약

* 충돌은 자동병합 실패 시 발생

* 겁먹지 말고 걱정하지 말고 충돌 해결하자

* 실패하면 다시하면 된다

 

안쓰는 브랜치 삭제하기

현재 브랜치(헤드)가 아닌 경우 간단하게 삭제 가능

브랜치를 삭제했을 경우 사라지는 커밋이 있는지 없는지 확인하자

머지한 후에는 브랜치를 안전하게 삭제할 수 있다 

git pull

서버의 내용이 내 PC보다 최신일 경우 pull을 적용한다

충돌이 날 수 있지만 놀라지 말자

pull = fetch + merge

 

소스트리에서 'Pull' 에 불이 들어옴 = 내 로컬PC 보다 앞선 커밋이 서버(깃허브, 원격저장소)에 저장되어있다는 뜻

여러명과 작업할때는 자주 발생하는 상황임.

'Pull' 을 누르면 원격저장소의 내용이 내 PC에 적용됨

pull에서도 충돌이 발생할 수 있음!

 

충돌의 발생 원인

자동병합을 실패했을 경우 발생

주로 두 커밋이 같은 파일을 편집했을 경우 발생

*** 충돌을 방지하기 위해 main(master)에서는 작업하지 않는 것이 좋음 

 

일반적인 해결 방법

병합 시 충돌이 발생하면 '커밋하지 않은 변경사항' 이 표시됨

세모 안에 느낌표가 있는 아이콘으로 충돌이 발생한 파일을 알려줌

해결하기 위해

1. 에디터(ATOM, VS Code 등)를 이용해서 직접 수정 후 커밋

현재 변경사항(main)과 수신 변경사항(병합할 브랜치)이 서로 다른 색깔로 표시되고, 브랜치 이름도 표시됨

두 내용 다 추가하고 싶다면 shift+delete로 필요없는 줄('<<<<HEAD' 등)을 삭제하고,

저장하고 싶은 형태로 수정을 완료한 후 저장함 (텍스트파일이 아닌 소스코드라면 상당히 불편할 것... 충돌 해결 툴을 사용할 수 있음)

이를 스테이지에 올린 후 커밋하면 커밋메시지가 자동으로 표시되고

("Merge branch '브랜치이름'

 

# Conflicts:

#    '충돌일어난 파일이름')

 수정하거나, 혹은 그대로 다시 커밋, 푸쉬하면 해결! (실패하면 '되돌리기' 하면 됨)

 

2. 소스트리에서 " '내것'을 이용해 해결" / " '저장소' 것을 사용하여 해결" 중 하나를 선택하여 해결

소스트리에서 '커밋하지 않은 변경사항' 에서 충돌이 발생한 파일을 우클릭 > '충돌해결' 클릭,

충돌이 발생한 부분 중 main의 것을 사용할 지, 머지한 브랜치의 것을 사용할 지 선택할 수 있음 (둘다 사용할 수는 없음)

충돌 해결 후 커밋, 푸쉬하면 됨 


8. reset을 이용한 커밋 되돌리기

이전 커밋으로 되돌리기 기능은 git을 사용하는 큰 이유 중 하나임

 

1) reset 사용해보기 (비추)

* git reset --hard 옵션으로 커밋을 되돌리기

* reset 이후 push는 '강제' 옵션을 선택해야 함

* 이전 커밋은 사라짐

* 장점 : 쉽다

* 단점 : 커밋이 날아간다, 강제 push가 필요하다

 

소스트리 - 되돌아갈 커밋을 우클릭 > '이 커밋까지 현재 브랜치를 초기화'

reset에는 여러가지 모드가 있음

soft - 모든 로컬 변경사항을 유지

mixed - 작업 상태는 그대로 두지만 인덱스는 리셋

hard - 모든 작업 상태 내 변경 사항을 버림

 

모드 설명은 CLI에서 하도록 하고, 일단 reset - hard 가 되돌리기임

다만, 원격 저장소에 push 해두었기때문에 아예 내용이 날아가진 않았음

되돌리기 후 다시 원상태로 돌아가려면 원래 데이터가 남아있는 상태의 커밋을 병합시키면 됨

 

파일 변경 후 커밋, 푸쉬 후 내용을 다시 되돌려서 내용 추가 후 커밋하게 되는 경우,

Push와 Pull 모두에 불이 들어오게 됨

Pull은 되돌리기 이전에 push한 내용임

이때에 Push하려고 하면 오류가 발생하게 됨 - push하려는 원본이 원격 저장소보다 과거의 것이기 때문임

=> 강제 Push 하면 됨 (*** 소스트리는 강제 푸시 기능을 지원하지 않음) 

CLI - git push --force 로 강제푸쉬 가능

BUT ) 원래의 기록은 다 사라지게 됨

 

강제Push 하지 않고 해결하려면 좀 더 복잡해지게 됨

1. 되돌리기한 시점 이후의 커밋(Push했던 커밋) 을 현재 분기에 병합시킴 -> 충돌 발생

2. 충돌해결 - 내것을 이용해 해결

3. 커밋하면 자동으로 해결되어 머지됨 => 강제Push 아닌 자동Push 가능

 

*** rebase를 이용하면 좀더 이쁘게 할수도 있음

*** 제일 나쁜 방식의 커밋 되돌리는 방법임


9. 브랜치를 만들어서 커밋 되돌리기

- 이전 시간 복습

* 이전 커밋으로 되돌리기

1) reset (hard reset) 이용하기

: 되돌아갈 시점의 커밋에 대고 '이 커밋까지 현재 브랜치를 초기화' > Hard 선택하면 되돌아감

단, 이 경우 강제 Push를 하거나 병합하는 방법이 있음

강제푸시의 경우 커밋이 사라질 수 있으므로 좋지 않은 방법임 (원격저장소에 내용이 없다면 커밋이 사라짐)

2) 새로운 브랜치를 만들어서 체크아웃하기 (추천)

* 되돌릴 커밋 대상으로 브랜치 생성

* 체크아웃

* 작업 후 master(main)에 머지

* 장점 : 쉽다, 기록이 다 남아있다, Push 할 때 문제가 발생하지 않는다

* 단점 : 트리가 지저분해진다(별거아닌 단점임)

 

*** 브랜치 이름은 개발할 기능 이름으로 하는 것이 좋음

 

1. 되돌아갈 커밋에서 브랜치를 생성하면 됨,

2. 내용을 변경/추가/수정 후 기능이 잘 돌아가는 상태로 작성을 완료하면

3. master 브랜치로 돌아가서 기능을 추가한 브랜치를 병합함 ('fast-forward가 가능해도 새 커밋으로 생성' 은 체크하지않음)

-> 충돌 발생함

4. 수정/추가한 기능을 master에 반영할 것이기 때문에 '충돌해결' > ' '저장소' 것을 사용하여 해결' 을 클릭함,

5. 커밋하면 됨

 

혼자 작업할 때 추천하는 방식임

 


10. revert를 사용해 커밋 되돌리기

- 이전 내용 복습

* 커밋 되돌리기

1) reset을 이용해 되돌리기 : '이 커밋까지 현재 브랜치를 초기화' + 'Hard' 옵션 -> 강제푸시해야함, 소스트리에는 강제푸시 기능이 없으므로 CLI에서 git push --force 를 입력함

2) 브랜치를 생성해서 되돌리기 : 되돌아갈 커밋에서 새 브랜치 생성하여 체크아웃 후 작업이 끝나면 main으로 돌아가서 병합, 충돌 발생하므로 '충돌해결' > '저장소' 것을 이용하여 해결

3) revert 사용해보기

* 대상 커밋을 HEAD 커밋의 자식으로 새로 생성한다

* 장점 : 이전 커밋 기록이 다 남아있다

* 단점 :  충돌 날 가능성이 매우 높다, 다소 어렵다

 

*** 마크다운 문서 - 마지막 한줄 비워둬야함

 

'커밋 되돌리기' 를 사용하면 해당 커밋의 이전 커밋(수정 전 버전)이 새 커밋으로 생성됨

되돌아간 것처럼 보이지만 이전 커밋이 남아있음 + 모양도 깔끔함

요약하자면, revert는 커밋을 보존하면서 내용만 되돌릴 수 있는 방법임

이는 reset과 달리 커밋 기록이 남아있게 됨 (reset 했을 때는 커밋 기록이 사라져서 reset 후에는 다시 이전으로 돌아갈 수 없게 됨)

 

다만 충돌이 발생하기 쉬움


11. Revert로 여러 커밋 되돌리기

- 복습

revert로 쉽게 커밋을 되돌릴 수 있음

이전 커밋이 남기 때문에 좋음

SourceTree에서 되돌리고 싶은 상태의 커밋을 우클릭(* 돌아가고 싶은 상태의 커밋 아님!!!) > '커밋 되돌리기' 

 

revert로 여러 커밋을 되돌리는 방법

최신부터 순서대로 revert를 반복 적용하면 됨

commit 1 : 새 파일 생성, commit 1 기록

commit 2 : commit 2 기록

commit 3 : commit 3 기록

=>

commit 3 - 커밋 되돌리기하면 커밋 메시지는 'Revert Commit 3' 이 되고, 새 커밋이 생김 : commit 2와 내용 동일함

 

reset은 되돌아가고싶은 커밋을 선택해서 '이 커밋까지 현재 브랜치를 초기화' 해서 한꺼번에 커밋 여러개를 싹 지워버렸지만 revert는 그렇게 하면 안됨

revert는 항상 쌍을 이루게 됨

commit 3 --- Revert commit 3(commit3을 되돌리므로 commit2 내용) 두 커밋이 쌍을 이룸

  

*** 잘못된 방법 

commit 1로 revert로 되돌아가고 싶은 경우,

commit 2 에서 '커밋 되돌리기' > 충돌 발생 > 수신 변경사항 수락(commit 1의 내용) 하는 방식

 

=> 두 단계로 revert 하는 것이 맞음

Revert commit 3 을 만든 후

Revert commit 2 를 만들어줌

 

터미널로 적용해보자

 (현재 commit 3 상태)

git revert HEAD HEAD~1 // git revert HEAD = 가장 최신 상태로 되돌려라, HEAD~1 = HEAD의 아빠

=> HEAD와 HEAD의 아빠를 순서대로 되돌리라는 뜻 (Revert "commit 3")

빠져나올 때는 :wq 입력하면됨 (Revert "commit 2")

한번 더 :wq 입력하면 끝남

소스트리로 돌아가보면 Revert commit 3, Revert commit 2 생성된 것 확인할 수 있음

 

*** 장난치고 싶을 때는 test 브랜치를 생성해서 이것저것 해보다가 다 하고나면 test 브랜치만 삭제하면 깔끔해짐