[내 로컬의 커밋 내역 , 즉 프로젝트의 변화를 연결된 원격 저장소의 특정 브랜치에 업로드 하기]
(먼저 로컬 프로젝트에 변화를 준 후 , commit 완료 후)
- git push
-> 우리의 경우 앞서 git push -u origin main 을 통해 ,
-> 로컬의 메인 브랜치를, 원격저장소 origin의 main브랜치와 연결 시켜놓았기 때문에
-> 이후 push할 때는 , 그냥 git push 만 적어주어도
-> 알아서 연결된 origin의 main 브랜치로 커밋이 업로드 된다.
[반대로 원격에 반영된 변화를 내 로컬에 적용하기]
- git pull
- 이 또한 앞선 git push -u origin main 에 의해 한번 연결된 origin의 main 브랜치의 커밋 중, 로컬에 반영되지 않은 커밋을 알아서 다운받게 된다.
- 만약 push에 의해 원격저장소의 어느 브랜치와 연결될지 설정되지 않은 상태라면
-> git pull origin main 등을 통해 , "어느 저장소의 어느 브랜치에서 pull 받을것인가" 를 pull 뒤에 명시적으로 설정하면
-> 연결된 해당 저장소 (여기서는 origin) 에서 해당 브랜치의 내용이 pull 받아진다.
-> EX ) (만약 upstream이라는 새로운 repo와 연결되어 있다면)
-> git pull upstream main
이렇게 단순하게 내 로컬의 변화는 원격으로 push 하고, 원격의 변화는 로컬로 pull 하면 될 것 같지만, 협업은 그렇게 단순하지 않다.
예를 들어 나와 팀원이 함께 협업을 하면서,
내 로컬에도 변화가 생겼고 팀원의 로컬에도 변화가 생겼는데
팀원만 로컬의 변화를 원격에 push한 상황이라면
내 로컬 변화와 원격의 변화가 서로 다른데 무작정 내 변화만을 push 할 수 있을까?
답은 No 이다. 내 로컬과 원격의 변화가 다를 경우, Git은 반드시 원격의 변화를 먼저 내 로컬에 반영한 후 , 내 로컬의 변화를 원격에 반영하도록 교통정리를 하고 있기 때문이다
[정리하면 ,
내 로컬의 변화를 원격으로 push도 해야 하지만 && 동시에 원격의 변화를 로컬로 pull 해야하는 상황]
- 이런상황에서 내 로컬의 변화 먼저 push 하면 -> 오류가 뜬다
- 이는 원격 저장소와의 push , pull 매카니즘의 근본이 다음과 같기 때문이다
: 로컬의 변화를 원격으로 push 할 수 있으려면, 반드시 먼저 원격의 변화를 pull한 이후여야 한다.
그런데 이때 원격의 변화를 받아서 내 로컬에 반영할 때,
원격의 변화(커밋 내역)와 - 내 로컬의 변화(커밋 내역)을
어떻게 합쳐서 반영 시킬것인가에 대해 2가지 전력이 존재한다
[전략 1. merge]
- git pull --no-rebase
- commit 메세지가 적힌 vim창이 나오면 -> :wq로 저장
-> 이 경우 아래와 같이 origin의 변화와 / 내로컬의 변화가
-> 각각의 브랜치로 분기된 후에 하나로 merge 되면서
-> 새 commit이 생기므로써
-> 원격의변화와 로컬의 변화가 합쳐진다.
[전략 2. rebase]
- git pull --rebase
- (vim 창이 나오지 않고 알아서 커밋 완료됨)
-> 이 경우 아래와 같이 origin의 변화와 / 로컬의 변화가 브랜치로 분기되지 않고
-> 기존의 하나의 브랜치 안에서
-> 원격의 변화가 먼저 적용된 후 (커밋) - 로컬의 변화가 적용된다 (커밋)
어쨌든 두 전략중 한 전략을 써서, 로컬에서 원격의 변화와 로컬만의 변화를 모두 적용시킨후, 다시 push를 해줘야 원격의 변화와 로컬의 변화가 모두 반영된 로컬의 프로젝트가 원격에도 업로드 된다.
[다시 push]
- git push 로 로컬에서 합쳐진 변화를 원격에 반영시켜주어야 ,
로컬과 원격이 모두 최신 프로젝트가 된다.
이제는 나아가 내가 로컬에서 수정한 프로젝트와 ,
팀원이 로컬에서 수정한 프로젝트 사이에 충돌이 일어난 경우를 살펴보자.
팀원이 먼저 로컬에서 수정한 프로젝트를 원격에 올려서
내가 로컬에 먼저 pull 받은 후 - 내 로컬 변화까지 함께 push 하려고 하는데 ,
당연히 내 로컬에서 pull 받을 때 충돌이 일어난다!
일단 팀원이 push한 원격과 , 내 로컬 상황이 다른 것을 아래와 같이 확인할 수 있다.
[이때 merge 전략으로 pull 받을때 충돌이 발생한다면]
- git pull --no-rebase
- 충돌 발생
- 충돌 해결
- git add .
- git commit
- 커밋 메세지가 적힌 vim 창이 나오고 , 그대로 :wq로 저장하여 commit완료
(충돌이 발생한 화면)
(충돌 해결 후, commit 까지 완료한 화면)
[rebase 전략으로 pull 받을 때 충돌이 발생한다면]
- git pull --rebase
- 충돌 발생
- 충돌 해결
- git add .
- git rebase --continue
- 커밋 메세지가 적힌 vim 창이 나오고 , 그대로 :wq로 저장하여 commit완료
이 rebase 전략으로 충돌을 해결한 경우, 어떻게 해결하냐에 따라 내 로컬 변화에 의한 커밋이 추가가 안될 수도 있다.
ex 로컬 변화 : A 추가 / 원격 변화 : B 추가 인 경우
-> rebase로 pull 받았을 때
-> 충돌시 B추가만 하게 수정한다면
-> 애초에 내 로컬에서의 A추가가 안된 것이니 - 로컬에서의 커밋도 사라진다-> 반면 충돌시 A추가만 하거나 A,B 둘다 추가할 경우
-> 어쨌든 A가 남아있게 된 것이니 - 로컬에서의 A추가 커밋도 유지가 된다
-> 이때의 커밋은 pull 한 원격 먼저 적용 후 - 내 커밋이 나중에 적용된다.
[강제 push]
- 언급한 것 처럼, 로컬 내역이 원격보다 뒤쳐진 경우는 push가 바로 안되고
- 먼저 pull 받아서 로컬에서 합친 이후
- push를 할 수 있었다.
그렇지 않고 서로 합의가 된 상황하에, 원격에 있는 프로젝트가 잘못되어서,
한 로컬에서 전부 수정한 걸로 원격껄 맞춰야 할때
- git push --force로 강제 push 할 수 있고,
-> 이 경우 원격은 로컬의 내용으로 전부 맞춰진다
(단 원격의 일부가 날아갈 수 O)- 실제로 강제 push 할 경우 원격의 일부 커밋이 날아갈 수 있다는 점 주의
- 그렇지만 그만큼 원격의 커밋이 로컬의 커밋에 깔끔하게 맞춰진다!!