[개발 환경] Git
Git이란?
Git은 내 컴퓨터에서 코드의 모든 변경 사항을 기록하고 관리하는 버전 관리 소프트웨어이다.
Git vs GitHub
Git은 컴퓨터에 설치하는 소프트웨어다.
즉, 내 컴퓨터 (로컬)에서 작동하는 프로그램이기 때문에, 인터넷이 끊겨도 문제 없이 코드를 수정하고, 버전을 저장할 수 있다.
GitHub는 온라인에 존재하는 웹 서비스로, 원격 저장소를 제공하는 클라우드 서비스이다.
즉, 로컬에서 Git으로 작업한 내용을 안전하게 백업하거나, 다른 팀원들과 협업하기 위해 인터넷 상에 올려놓을 수 있다.
따라서 Git을 이용해 다른 사람들과 협업할 때는, 먼저 내 컴퓨터에서 Git으로 코드를 작업하고 그 결과를 GitHub에 올려서 공유하는 방식으로 개발한다.
Git 기능
Git에는 여러 기능이 있으며, 이를 이용하면 프로젝트의 추적과 분업 및 협업이 수월해진다.
기본적으로 History 기록, Branch 작업, Merge 기능은 네트워크 연결 없이 로컬에서만 독립적으로 이루어진다.
반면, Remote 기능은 로컬에서 완성된 작업 내역을 깃허브 같은 원격 저장소와 동기화할 때만 사용된다.
History
코드의 변경 사항을 시간 순으로 기록하는 기능이며, 단순히 파일을 저장하는 것이 아니라 ‘누가, 언제, 어떤 이유로’ 코드를 수정했는지 상세히 기록한다.
이 덕분에 실수가 발생했을 때 언제든 과거의 특정 시점으로 되돌릴 수 있다.
기록을 남기는 최소 단위를 commit이라고 하며, History는 이 commit들이 모여 만들어진다.
| 명령어 | 설명 | 사용 예시 |
|---|---|---|
git status | 현재 수정된 파일이나 Staging Area의 상태를 확인 | - |
git add <파일명> | 수정된 파일을 스냅샷을 찍기 위한 Staging Area에 올림 (모든 수정 파일을 올리려면 git add .) | git add script.py |
git commit -m "<commit 메시지>" | Staging Area에 있는 파일들을 하나의 스냅샷으로 기록 | git commit -m "initial commit" |
git log --oneline | 지금까지의 commit 이력을 한 줄씩 간결하게 출력 | - |
Branch
하나의 프로젝트에서 Main Branch를 바탕으로 독립적인 작업 공간을 분리하는 기능이다.
메인 코드에 영향을 주지 않고 새로운 기능을 실험하거나 버그를 수정할 수 있는 일종의 평행 세계를 제공하며, 이 덕분에 하나의 프로젝트 안에서 여러 가지 실험을 독립적으로 진행할 수 있다.
| 명령어 | 설명 | 사용 예시 |
|---|---|---|
git branch | 로컬에 존재하는 브랜치 목록 출력 (원격 저장소의 branch까지 모두 출력하려면 git branch -a) | - |
git branch <브랜치명> | 로컬에서 새로운 브랜치 생성 | git branch dev |
git switch <브랜치명> | 해당 브랜치로 작업 공간 이동 | git switch dev |
git branch -d <브랜치명> | 작업이 끝난 브랜치 삭제 | git branch -d dev |
git branch -a 명령어를 실행하면 아래와 같은 화면이 출력될 것이다.
출력에 대한 의미는 다음과 같다.
- 빨간색 텍스트는 원격 저장소에 존재하는 브랜치, 흰색 텍스트는 로컬에 존재하는 브랜치,
*초록색 텍스트는 현재 내가 위치해 있는 브랜치를 의미한다. origin은 코드가 저장된 원격 저장소 (깃허브 서버)의 별명이다.원래 원격 저장소의 URL
https://github.com/...을 매번 입력하기는 번거롭기 때문에, Git에서 자동으로origin이라는 별명을 붙여준 것이다.remotes/origin/HEAD -> origin/main은 원격 저장소를 대표하는 기본 브랜치 (HEAD)가 원격 저장소의main브랜치라는 뜻이다.우리가
git clone으로 레포지토리를 복제할 때, Git은 화살표->가 가리키는 곳 (원격 저장소의 HEAD)을 확인하고 자동으로 해당 브랜치를 기준으로 로컬 환경을 초기 세팅한다.*기호는 현재 내가 위치해 있는 브랜치, 즉 내 로컬의 HEAD를 의미한다.우리가
git branch로 로컬에서 새로운 브랜치를 생성할 때, Git은*가 표시된 곳 (로컬의 HEAD)을 확인하고 현재 작업 중인 코드를 기준으로 새로운 브랜치를 생성한다.main(또는master)은 기본 브랜치, 그 외의dev나test1등의 브랜치는 사용자가 직접 생성한 브랜치이다.현재
dev는 원격 저장소에,test1과test2는 로컬에 존재하는 것을 확인할 수 있다.
Merge
각기 다른 브랜치에서 작업한 결과물을 다시 하나의 메인 코드로 합치는 기능이다.
| 명령어 | 설명 | 사용 예시 |
|---|---|---|
git merge <브랜치명> | 현재 내가 위치한 브랜치로 <브랜치명>의 작업을 가져와 통합 | git merge test1 |
Merge 오류
git merge를 실행했을 때, 상황에 따라 나타나는 경고 또는 에러 메시지에는 크게 3가지가 있다.
Merge Conflict (병합 충돌)
원인: 두 브랜치에서 같은 파일의 같은 line을 각각 다르게 수정했을 때, Git이 스스로 어떤 코드를 선택해야 할지 몰라서 사용자에게 도움을 요청하는 상태이다.
1 2
CONFLICT (content): Merge conflict in <파일명> Automatic merge failed; fix conflicts and then commit the result.
해결 방법: 충돌이 난 파일을 열어보면
=======를 기준으로,<<<<<<< HEAD와>>>>>>>기호로 두 코드가 나뉘어 있다.
남길 코드만 선택하고 제거할 코드와 기호들을 지운 뒤, 다시git add와git commit을 하면 병합이 완료된다.Uncommitted Changes (커밋하지 않은 변경 사항 존재)
원인: 현재 내가 작업 중인 브랜치에 아직 커밋하지 않은 수정 사항이 남아있는데 병합을 시도할 때 나타나는 경고다.
기존 작업물이 날아가는 것을 방지하기 위한 Git의 안전장치다.1 2
error: Your local changes to the following files would be overwritten by merge: Please commit your changes or stash them before you merge.해결 방법: 현재 진행중인 작업을
git commit으로 완전히 저장한 뒤, 다시 병합을 시도하면 된다.Unrelated Histories (관련 없는 기록 병합 거부)
원인: 서로 출발점이 다른 두 프로젝트를 강제로 합치려고 할 때 나타나는 경고다.
보통 로컬에서 프로젝트를 새로 만들고, 원격 저장소에서도 새 레포지토리를 만들어서 둘을 연결하려 할 때 자주 발생한다.1
fatal: refusing to merge unrelated histories
해결 방법: 만약 두 프로젝트를 억지로라도 하나로 합쳐야 한다면, 강제 옵션을 붙인 명령어
git merge <브랜치명> --allow-unrelated-histories를 실행한다.
Remote
내 컴퓨터에서 기록한 History와 Branch들을 원격 저장소에 올려서 팀원들과 공유하고, 반대로 팀원들이 올린 새로운 업데이트를 내 컴퓨터로 가져와 동기화하는 기능이다.
| 명령어 | 설명 | |
|---|---|---|
git fetch | 원격 저장소의 최신 업데이트를 로컬에 다운로드 (작업 코드에는 영향 X) | - |
git pull | 원격 저장소의 최신 업데이트를 로컬에 다운로드한 뒤 병합 | |
git push | 내 컴퓨터의 commit들을 깃허브로 업로드 |
git pull은fetch와merge가 순차적으로 일어난다고 생각하면 된다.
Upstream 브랜치
로컬 브랜치와 원격 저장소의 특정 브랜치를 연결 (기본 도착지로 설정)하고 싶을 때, git push -u origin <브랜치명>을 사용하면 된다.
이 명령은 사실 git push -u origin <로컬브랜치명>:<원격브랜치명>의 축약형이며, 두 이름이 같을 때 한쪽을 생략할 수 있다.
따라서 로컬과 원격의 브랜치 이름이 달라도 git push -u origin dev:develop처럼 명시해주면 서로 다른 이름의 브랜치끼리도 연결할 수 있다.
또는 로컬에서 dev라는 브랜치를 생성했는데 원격 저장소에는 dev라는 브랜치가 없는 경우에도, git push -u origin dev를 사용해서 원격 저장소에 브랜치를 생성하고 연결까지 한 번에 끝낼 수 있다.
이때 연결된 원격 저장소의 브랜치를 Upstream 브랜치라고 한다.
이렇게 한 번 연결하면, 다음부터는 목적지를 생략하고 git pull이나 git push만 입력해도 자동으로 Upstream 브랜치와 동기화된다.
만약 Upstream 브랜치를 설정하지 않는다면, 매번 git pull origin <원격 저장소 브랜치명> , git push origin <원격 저장소 브랜치명>처럼 목적지를 끝까지 타이핑해야 한다는 번거로움이 생긴다.
Push 오류
git push를 실행했을 때, 상황에 따라 나타나는 경고 또는 에러 메시지에는 크게 3가지가 있다.
원격 저장소에 나보다 최신 코드가 있는 경우
원인: 내가
push하려는 코드보다 원격 저장소의 코드가 더 최신 상태일 때 발생한다. (예: 팀원이 먼저 해당 브랜치에push를 했거나, 내가 깃허브 웹에서 파일을 직접 수정한 경우)
이때 Git은 내 코드가 덮어씌워지는 것을 막기 위해push를 거부한다.1 2 3
! [rejected] main -> main (fetch first) error: failed to push some refs to 'https://github.com/... hint: Updates were rejected because the remote contains work that you do not have locally.
해결 방법: 먼저
git pull을 해서 원격 저장소의 최신 변경 사항을 내 컴퓨터로 가져와 병합한 뒤에, 다시git push를 해야 한다.권한이 없거나 인증에 실패한 경우
원인: 해당 원격 저장소에 코드를 밀어 넣을 쓰기 (Write) 권한이 없거나, 로컬 리눅스/터미널 환경에서 계정 인증이 제대로 설정되지 않았을 때 발생한다.
1 2 3
remote: Permission to user/repo.git denied to user. fatal: unable to access '...': The requested URL returned error: 403 (또는) Permission denied (publickey).
해결 방법: 협업 중이라면 깃허브 레포지토리의 Collaborator로 등록되어 있는지 확인해야 한다.
터미널 환경이라면 로컬에 등록된 SSH 키가 깃허브 계정에 잘 등록되어 있는지, 혹은 Personal Access Token (PAT)이 만료되지 않았는지 확인해야 한다.푸시하려는 브랜치가 존재하지 않는 경우
원인: 존재하지 않는 브랜치 이름을
push하려고 했거나 (오타), 프로젝트를 처음 만들고 아직git commit을 한 번도 하지 않은 빈 깡통 상태에서push를 시도할 때 발생한다.1 2
error: src refspec main does not match any error: failed to push some refs to '...'해결 방법:
git branch를 입력해 현재 브랜치 이름이 맞는지 확인하고, 초기 세팅 중이라면 커밋 기록이 하나 이상 존재하는지 확인한다.
Pull 오류
git pull은 다운로드는 잘 되더라도, 주로 병합하는 과정에서 오류가 잦다.
이 때문에 git merge에서 발생하는 오류와 유형이 거의 동일하다.
충돌이 발생한 경우
원인: 팀원이 원격 저장소에 올려둔 코드와 내가 로컬에서 수정한 코드가 같은 줄을 건드렸을 때 발생한다.
1 2
CONFLICT (content): Merge conflict in {파일명} Automatic merge failed; fix conflicts and then commit the result.
해결 방법: 충돌난 파일을 열어 코드를 직접 수정한 뒤,
git add와git commit을 진행하여 병합을 마무리한다.커밋하지 않은 내 작업물이 덮어씌워질 위험이 있는 경우
원인: 원격 저장소에서 가져온 코드가 ‘내가 현재 로컬에서 수정 중이지만 아직 커밋하지 않은 파일’과 겹칠 때 발생한다.
기존 작업물이 날아가는 것을 방지하기 위한 Git의 안전장치다.1 2
error: Your local changes to the following files would be overwritten by merge: Please commit your changes or stash them before you merge.해결 방법: 현재 진행중인 작업을
git commit으로 완전히 저장한 뒤, 다시pull을 받으면 된다.


