이 글은 GIT의 기초를 설명하기 보다는 흔히 현장에서 발생할 수 있는 상황에 대처할 수 있는 실용적인 방법들을 설명하기 위한 첫번째 글이다.
소스 공유 툴을 사용할 때, 모든 참여자들이 정확히 방법을 숙지하고, 정상적인 경우만 있다면 아무 문제가 없지만, 대부분은 누군가 이상한 작업을 해서 뒤죽박죽 뭔가 섞였을 때... 해결을 못하고 아마도 소스를 백업받고 아예 엎어치는 경우가 종종 있다. 이럴 때면 이걸 왜 쓰지 하는 생각이 들기도 한다.
게다가 SVN보다 GIT이 사용하기 어렵다. 솔직히 너무 어렵게 만든 것 같고 무엇보다도 명령어들이 나에게는 직관적이지 않아서 더욱 어렵다. 언젠가 확실히 이해할 필요가 있다고 생각하던 중, 시간이 되서 정리를 시작해 본다.
1. GIT 클론 저장소와 원격저장소간 차이 확인
어떤 문제가 어렵게 느껴질 때는 상황이 제대로 파악되지 못해서인 경우가 많다. 따라서 우리의 GIT 저장소에 대해 정확히 볼 수 있는 방법들을 숙지한다면, 문제는 한결 쉬워질 것이다.
git fetch 명령어를 늘 사용하자.
소스 관리자가 아니라면, 보통 원격저장소 브랜치의 클론 저장소를 생성, 사용할 것이다.이 경우 fetch 명령은 절대로 원격의 소스상태를 망치지도 않고, 내가 작업한 것들도 망치지 않는다. 그러나 원격저장소의 정보를 내 클론 저장소로 연동시켜 주기 때문에, 정확한 상태 파악을 위해서는 수시로 사용해줘야 한다.
한번에 pull명령으로 동기화 하려다 보니 원격저장소의 상태를 알아야 하는 부담이 생긴다. 그래서 원격저장소의 정보를 알기 위한 여러 어려운 방법들이 인터넷에 소개되지만 그럴 필요가 없다. 그냥 자주 아무 이유없이 fetch명령어를 쓰면 모든 것이 편해진다.
git log <revision range> : 원격과 나와의 차이 확인
예를 들면 'git log HEAD..origin' 처럼 사용할 수 있다. 의미는 HEAD에는 없고 origin에는 있는 커밋들을 보여준다. 여기서 origin은 origin/<branch-name>을 쓸 수 있다. 앞서 fetch가 왜 중요한지 데모로 조성된 환경하에서 실행된 log명령어의 차이를 보면 알 수 있다. 데모 환경은 하나의 원격저장소에서 파생된 두개의 클론저장소에서 한 곳에서 몇개의 커밋/push작업을 했을 때, 다른 한 쪽에서 어떻게 보이는지 보여준다.
=== 하나의 클론 저장소에서 모든 커밋을 push한 후 조회한 커밋로그
prompt$ git log origin/master --oneline
4d685a3 hope to conflict
e2e8f16 commit missing files
43bae9a Other clone 3rd commit
6a8da57 Test commit while there is untracked files
69d7aba Other clone has modified readme.txt
6846f6d add some files
325b548 initialize repository
위의 로그 정보는 절대로 원격저장소에소 조회한 정보가 아니다. 바로 자신(클론)의 정보를 이용한 것이다. 이 때 다른 클론 저장소에서 'fetch'명령을 사용하지 않고 조회를 하면 자신이 갖고 있던 옛날 정보만을 보여주게 된다. 따라서 원격에 이미 커밋된 내용을 확인하지 못한다.
=== fetch 명령을 실행하지 않은 다른 클론저장소에서 ===
prompt$ git log HEAD..origin/master --oneline
prompt$
prompt$ git log origin/master --oneline
6846f6d add some files
325b548 initialize repository
만약 이 경우 'pull'명령어를 실행하게 되면 예상치 못한 커밋들로 인해 당황하게 된다. 항상 'fetch'를 수행하고 있었다면 아래의 로그명령을 통해 내가 반영해야될 커밋들을 정확히 파악 할 수 있다. 앞서 조회되지 않은 커밋들이 조회된다.
=== 아래 명령어에서 'FETCH_HEAD'는 'origin' 혹은 'origin/<branch name>'으로 변경가능하다. ===
prompt$ git log HEAD..FETCH_HEAD --oneline
4d685a3 hope to conflict
e2e8f16 commit missing files
43bae9a Other clone 3rd commit
6a8da57 Test commit while there is untracked files
69d7aba Other clone has modified readme.txt
prompt$
prompt$ git log HEAD..origin/master --oneline
4d685a3 hope to conflict
e2e8f16 commit missing files
43bae9a Other clone 3rd commit
6a8da57 Test commit while there is untracked files
69d7aba Other clone has modified readme.txt
2. 파일충돌 해결방법
파일에서 충돌 발생.
어떤 파일이 두군데 이상의 곳에서 변경되었고, 잘 합쳐지지 않게 되면 충돌이 난다. GIT에서는 'fetch'명령어를 실행했는지 여부와 아무 상관없이 항상 'commit'을 할 수 있다. 그러나 결국 'fetch'된 정보는 'merge'명령을 통해 자신의 클론 저장소에 반영해야 된다. 아래는 다른 곳에서 커밋된 것이 'fetch'되고 자신이 수정한 것이 커밋된 것이 공존하는 경우를 보여준다.
=== 나에게는 반영안된 커밋들 ===
prompt$ git log HEAD..FETCH_HEAD --oneline
4d685a3 hope to conflict
e2e8f16 commit missing files
43bae9a Other clone 3rd commit
6a8da57 Test commit while there is untracked files
69d7aba Other clone has modified readme.txt
=== 내가 커밋했지만 원격으로 push안한 것들 ===
prompt$
prompt$ git log FETCH_HEAD..HEAD --oneline
f190b1a try to commit while there is a unmerged fatch
충돌난 파일 조회 및 처리방법
prompt$ git status -s
A dir2/dir2-other.txt
A dir2/dir2.txt
UU readme.txt
prompt$
prompt$ git ls-files -u
100644 633cb9b8d004e779c4ddc13be0a13016ed502ef3 1 readme.txt
100644 afe66fea12a7cf0e62eff1eee061391af1e49c15 2 readme.txt
100644 16643f3ad2efbcb106fa2a3a9c510c2df666608d 3 readme.txt
prompt$ git ls-files --stage -- readme.txt
100644 633cb9b8d004e779c4ddc13be0a13016ed502ef3 1 readme.txt
100644 afe66fea12a7cf0e62eff1eee061391af1e49c15 2 readme.txt
100644 16643f3ad2efbcb106fa2a3a9c510c2df666608d 3 readme.txt
- 1 : 자신과 상대방이 서로 수정하기 전 공통으로 받은 파일(내용이 같았던) 내용
- 2 : 자신이 수정한 내용
- 3 : 다른 곳에서 수정한 내용
prompt$ git checkout-index --stage=2 -f -- readme.txt
'--stage'옵션의 숫자를 1~3사이의 값을 사용해서 원본으로 되돌릴 수도 자신의 것 혹은 다른 곳에서 수정한 것으로 덮어쓸 수도 있다. 또한 work-tree에 있는 파일 자체를 수정하거나 다른 파일로 대체할 수 있다. 모든 작업이 끝나면 'add'명령어를 사용해서 충돌사항이 처리되었음을 알린다.
충돌난 파일을 처리한 후 상대방은?
상대방이 처리된 내용을 'fetch'해서 'merge'하게 되면 상대방 또한 처리된 내용으로 덮어 써지게 된다. 그런데 상대방이 그 사이에 또 수정했다. 그 때 상대방은 이 것을 어떻게 처리할 수 있을까... 이런 복잡한 경우 아래 명령어를 사용하면 상황을 파악하는데 도움이 된다. 여전히 우리는 항상 'fetch'명령을 수행한 상태이다.
prompt$ git log --graph --oneline --all
* d7c47fd merge OKmore readme.txt
|\
| * dde8191 Other change readme.txt once more
* | 55030ae change readme.txt once more
|/
* 44b1a6d OK overwrite
|\
| * b76dcd7 insert line into readme.txt
* | 52b2e3b change readme.txt
|/
* 046ad98 merge other clone's changes
|\
| * 4d685a3 hope to conflict
| * e2e8f16 commit missing files
| * 43bae9a Other clone 3rd commit
| * 6a8da57 Test commit while there is untracked files
| * 69d7aba Other clone has modified readme.txt
* | f190b1a try to commit while there is a unmerged fatch
|/
* 6846f6d add some files
* 325b548 initialize repository
'-n 10' 같은 옵션을 추가해서 내용이 많은 경우, 보여지는 갯수를 제한할 수 있다.예는 10개로 제한한 경우이다. 현재 상황을 보면 최종 커밋인 'd7c47fd'는 아래 두개의 서로 분기된 커밋의 충돌을 해소하고 병합된 커밋이다.
이 커밋을 받는 곳에서 또 수정을 했을 때는 아래처럼 또 분기된다.
prompt$ git log --graph --oneline --all
* e100f0b fix merge too
| * d7c47fd merge OKmore readme.txt
| |\
| |/
|/|
* | dde8191 Other change readme.txt once more
| * 55030ae change readme.txt once more
|/
* 44b1a6d OK overwrite
|\
| * b76dcd7 insert line into readme.txt
* | 52b2e3b change readme.txt
|/
* 046ad98 merge other clone's changes
|\
| * 4d685a3 hope to conflict
| * e2e8f16 commit missing files
| * 43bae9a Other clone 3rd commit
| * 6a8da57 Test commit while there is untracked files
| * 69d7aba Other clone has modified readme.txt
* | f190b1a try to commit while there is a unmerged fatch
|/
* 6846f6d add some files
* 325b548 initialize repository
'--graph'옵션은 많은 도움이 된다. 출력된 내용을 보면 커밋의 흐름이 한 눈에 많이 들어온다. 이 출력들은 OSX에서 돌린 결과이다. 다른 플랫폼에서는 어떤지 모르곘다.
마치며
'Trouble Shooting' 카테고리의 다른 글
안드로이드 EditText 항목 쓰기방지(read-only)로 만들기 (0) | 2017.09.27 |
---|---|
[GIT 정리] 이미 commit/push된 파일을 .gitignore에 등록하기 (0) | 2017.08.30 |
안드로이드 시뮬레이터, root권한 없이 SQLite DB 파일 접근 (0) | 2017.08.14 |
안드로이드 기기를 사용하는 단위테스트 첫발 (0) | 2017.07.26 |
git 레포지토리에서 변경된 파일들중에서 원하는 파일들만 추리기 (0) | 2017.05.31 |