5주차: GIT

김민지·2024년 6월 22일

Git?

3가지 작업영역

  • working directory: 작업을 진행하는 프로젝트 디렉토리(폴더)
  • staging area: add만 된 공간
    커밋을 해도 staging area에는 아무런 변화가 없음
    나중에 git add를 또 했을 때 staging area 안에 새로운 파일이 추가되거나, 기존 파일이 더 새로운 파일로 교체될 뿐임
  • repository: .git 디렉토리 = 레포지토리. 커밋들이 저장되는 공간

Commit?

  • commit을 하기 전, 반드시 git에게 누가 한 commit인지를 알리기
    git config user.name "내이름"
    git config user.email "내이메일"
  • add하기
    git add 파일이름
  • 현재 프로젝트 디렉토리에서 수정된 모든 파일들 한번에 add하기
    git add .
  • git reset: git add 취소해서 staging area에서 파일을 제거하기 (단, 작업중인 파일이 바뀌지는 않음)
    git reset 파일이름
  • commit하기
    git commit -m "커밋메시지"
  • commit 기록 확인하기: git log --pretty=oneline
    단, 해당 명령어는 지나치게 기므로 사용자가 임의로 단축어를 생성할 수 있음 git config alias.history 'log --pretty=oneline'
    가장 오래된 기록이 아래에 있음, 위에 있을 수록 최신의 기록임
  • commit 내용 확인하기: git show 커밋아이디(대충앞4자리)

    -가 이전파일, +가 현재파일
  • 최신 commit 내용 수정하기: git commit --amend
    commit 메시지도 수정하고 싶다면 i 누르고 수정, :wq를 통해서 나가기
  • 두 commit 사이의 차이 비교하기: git diff 커밋아이디(4자리) 커밋아이디(4자리)
  • HEAD: 가장 최근에 한 commit을 가리킴

    working directory의 모양은 HEAD가 가리키는 commit의 모양대로 바뀜
  • HEAD 위치 바꾸기: git reset --hard 커밋아이디

    --hard: 해당커밋 이후로 한 작업들이 전부 사라짐
    즉, 리셋 정도를 체크할 수 있음
  • 직전 commit(HEAD^)으로 돌아가기: git reset --hard HEAD^
  • 현재 HEAD가 가리키는 commit보다 x단계 이전의 commit(HEAD~x)으로 돌아가기: git reset --hard HEAD~x
  • commit에 tag(즐겨찾기 느낌) 달기: git tag [태그 이름] [커밋 아이디]
  • tag들만 모아서 조회하기: git tag
  • tag의 commit 확인하기: git show [태그 이름]

파일 상태

  • git 현재 상태 확인하기: git status
  1. Untracked 상태: 파일을 새로 생성하고 그 파일을 한 번도 git add 해주지 않은 상태
  2. Tracked 상태 (Staged 상태, Unmodified 상태, Modified 상태)
  • Add the file : Untracked 상태의 파일을 처음으로 git add 해주면 Staged 상태가 됩니다.
  • Edit the file : 최신 커밋과 비교했을 때 차이가 없는 Unmodified 상태의 파일의 내용을 수정하면 Modified 상태가 됩니다.
  • Stage the file : Modified 상태의 파일을 git add 해주면 Staged 상태가 됩니다.
  • Remove the file : 파일을 삭제하면 당연히 Git에서 더이상 인식하지 않겠죠?
  • Commit : 커밋을 하면 staging area에 있던 파일들이 커밋에 반영되고, 이제 모든 파일들은 최신 커밋과 차이가 없게 되니까 Unmodified 상태가 됩니다.

git 명령어

git init : 현재 디렉토리를 Git이 관리하는 프로젝트 디렉토리(=working directory)로 설정하고 그 안에 레포지토리(.git 디렉토리) 생성
git config user.name 'codeit' : 현재 사용자의 아이디를 'codeit'으로 설정(커밋할 때 필요한 정보)
git config user.email 'teacher@codeit.kr' : 현재 사용자의 이메일 주소를 'teacher@codeit.kr'로 설정(커밋할 때 필요한 정보)
git add [파일 이름] : 수정사항이 있는 특정 파일을 staging area에 올리기
git add [디렉토리명] : 해당 디렉토리 내에서 수정사항이 있는 모든 파일들을 staging area에 올리기
git add . : working directory 내의 수정사항이 있는 모든 파일들을 staging area에 올리기
git reset [파일 이름] : staging area에 올렸던 파일 다시 내리기
git status : Git이 현재 인식하고 있는 프로젝트 관련 내용들 출력(문제 상황이 발생했을 때 현재 상태를 파악하기 위해 활용하면 좋음)
git commit -m "커밋 메시지" : 현재 staging area에 있는 것들 커밋으로 남기기
git help [커맨드 이름] : 사용법이 궁금한 Git 커맨드의 공식 메뉴얼 내용 출력
git push -u origin master : 로컬 레포지토리의 내용을 처음으로 리모트 레포지토리에 올릴 때 사용합니다.(-u origin master가 무슨 뜻인지는 'Git에서 브랜치 사용하기' 챕터에서 배울 거니까 걱정마세요!)
git push : 로컬 레포지토리의 내용을 리모트 레포지토리에 보내기
git pull : 리모트 레포지토리의 내용을 로컬 레포지토리로 가져오기
git clone [프로젝트의 GitHub 상 주소] : GitHub에 있는 프로젝트를 내 컴퓨터로 가져오기
git log : 커밋 히스토리를 출력
git log --pretty=oneline : --pretty 옵션을 사용하면 커밋 히스토리를 다양한 방식으로 출력할 수 있습니다. --pretty 옵션에 oneline이라는 값을 주면 커밋 하나당 한 줄씩 출력해줍니다. --pretty 옵션에 대해 더 자세히 알고싶으면 이 링크를 참고하세요.
git show [커밋 아이디] : 특정 커밋에서 어떤 변경사항이 있었는지 확인
git commit --amend : 최신 커밋을 다시 수정해서 새로운 커밋으로 만듦
git config alias.[별명] [커맨드] : 길이가 긴 커맨드에 별명을 붙여서 이후로 별명으로 해당 커맨드를 실행할 수 있도록 설정
git diff [커밋 A의 아이디] [커밋 B의 아이디] : 두 커밋 간의 차이 비교
git reset [옵션] [커밋 아이디] : 옵션에 따라 하는 작업이 달라짐(옵션을 생략하면 --mixed 옵션이 적용됨)
(1) HEAD가 특정 커밋을 가리키도록 이동시킴(--soft는 여기까지 수행)
(2) staging area도 특정 커밋처럼 리셋(--mixed는 여기까지 수행)
(3) working directory도 특정 커밋처럼 리셋(--hard는 여기까지 수행)
그리고 이때 커밋 아이디 대신 HEAD의 위치를 기준으로 한 표기법(예 : HEAD^, HEAD~3)을 사용해도 됨
과거의 커밋으로 git reset을 한다고 절대 그 이후의 커밋들이 삭제되지 않음
git reset은 과거의 커밋뿐만 아니라 현재 HEAD가 가리키는 커밋 이후의 커밋으로도 가능함
git tag [태그 이름] [커밋 아이디] : 특정 커밋에 태그를 붙임
git remote add origin [GitHub 상 프로젝트 주소] : [GitHub 상 프로젝트 주소]가 가리키는 리모트 레포지토리를 origin이라는 이름으로 내 컴퓨터에 등록하겠다는 뜻. origin 키워드는 관례상 사용되며, 다른 키워드로 변경도 가능함
git branch [새 브랜치 이름]: 새로운 브랜치를 생성
git checkout -b [새 브랜치 이름]: 새로운 브랜치를 생성하고 그 브랜치로 바로 이동
git branch -d [기존 브랜치 이름]: 브랜치 삭제
git checkout [기존 브랜치 이름]: 그 브랜치로 이동
git merge [기존 브랜치 이름]: 현재 브랜치에 다른 브랜치를 머지
git merge --abort: 머지를 하다가 conflict가 발생했을 때, 일단은 머지 작업을 취소하고 이전 상태로 돌아감
git fetch: 로컬 레포지토리에서 현재 HEAD가 가리키는 브랜치의 업스트림(upstream) 브랜치로부터 최신 커밋들을 가져옴(가져오기만 한다는 점에서, 가져와서 머지까지 하는 git pull과는 차이가 있음)
git blame: 특정 파일의 내용 한줄한줄이 어떤 커밋에 의해 생긴 것인지 출력
git revert: 특정 커밋에서 이루어진 작업을 되돌리는(취소하는) 커밋을 새로 생성

GitHub?


  • git push : local 리포지토리의 commit 내용을 remote 리포지토리(github)로 보내줌
  • git pull : remote 리포지토리의 commit 내용을 local 리포지토리로 가져옴
    cat 파일이름으로 잘 읽어왔는지 확인 가능!
  • 협업시, 팀원도 git push를 할 수 있도록 collaborator로 인정해서 권한을 허용하는 방법: https://www.codeit.kr/topics/git/lessons/2901
  • git clone 깃허브링크(https://github.com/리포지토리.git): 다른 프로젝트 가져오기
  • 마크다운: https://gist.github.com/ihoneymon/652be052a0727ad59601
  • commit vs. push
    commit: 로컬 저장소에 변경 내역을 저장하는 동작
    push: 위의 변경 내역을 원격 저장소에 업로드하는 동작

Branch?

  • branch 생성: git branch 브랜치이름
  • branch로 이동: git checkout 브랜치이름
    git status로 확인 가능
  • branch 생성 + 이동; git checkout -b 브랜치이름
  • branch 종류 확인: git branch
    내가 작업중인 브랜치에는 * 표시가 있음
  • branch 삭제: git branch -d 브랜치이름
  • branch merge하기: 브랜치 A에 브랜치 B의 commit사항들을 가져오고 싶을 때, A로 이동하고 git merge [가져오고자하는브랜치이름(B)] 를 실행함
    만약 같은 함수 이름이 다르거나 같은 변수 이름이 다른 등 같은 부분에 차이가 있을 때, 어느 branch의 내용을 반영해야 할지를 모르므로 conflict 발생
    ✨해결책1: 파일로 들어가서 conflict가 일어난 부분을 통일하는 방식으로 수정하고 다시 commit하면 성공적으로 merge됨
    ✨해결책2: merge 취소하기 git merge --abort

    merge를 한다고 반드시 새로운 commit이 발생하는 것은 아님
    merge의 종류:
  1. Fast-forward merge: 같은 선 상에 있는 브랜치를 merge할 때 이루어지며, 추가적인 commit을 생성하지는 않음
  2. 3-way merge: 서로 분리된 2개의 선에 존재하는 두 브랜치를 merge해서 merge commit이라는 추가적인 commit을 생성함. 이름이 3-way인 이유는 두 갈래로 갈라지기 전 공통 조상이 되는 commit, 한 브랜치가 가리키는 commit, 다른 브랜치가 가리키는 commit의 3가지를 고려하기 때문임.
  • upstream branch: 로컬 레포지토리의 브랜치에 대응되는, 즉 tracking connection을 갖고 있는 리모트 레포지토리의 브랜치
  • 자주 발생하는 오류: 현재 master 브랜치가 원격 저장소의 브랜치를 추적하고 있지 않을 때 발생
fatal: The current branch master has no upstream branch.

To push the current branch and set the remote as upstream, use

git push --set-upstream origin master

Git 협업하기

  • 협업을 할 때 기준이 되는 레포지토리는 늘 리모트 레포지토리이다
  • 만약 내가 로컬리포지토리를 수정하는 동안 리모트리포지토리에 변화가 있었다면? 바로 git push를 해서는 안됨, git pull을 먼저 해야 함.
    git pull - conflict 발생 파일을 열어서 확인하고 수정함 - git push
  • git fetch를 이용해서 branch로 불러오고, git diff 로컬리포지토리의브랜치 리모트리포지토리의브랜치를 실행해서 차이점을 체크한 후 git merge를 활용해서 merge하기
    즉, git fetch + merge == git pull
  • 가져올 브랜치의 내용을 한번 더 검토해야 할 때, fetch를 사용!
  • 코드를 작성한 사람을 확인하기 위해서는 git blame 파일명, git show를 사용해서 확인할 수 있음
  • git revert 되돌리고싶은커밋의아이디: 이미 remote repository에 올라간 commit을 취소하기 위해서 사용
    여러 commit을 취소하기 위해서 범위로도 지정 가능

    git reset은 remote repository와 local repository를 연결한 경우, 지양해야 함
  • 단, 혼자 진행중인 프로젝트의 경우 pull해서 검토하는 과정을 건너뛰고 git push -f옵션을 사용해서 강제로 push해버릴 수도 있음

Git 활용하기

  • conflict 해결하는 방법: 항상 sublime text로 돌아가서 (혹은 작업중인 코드 에디터로) 충돌이 일어난 부분을 하나로 통일한 후 commit하기!(git add . , git commit -m "커밋메시지")
  • git reflog: 지금까지 HEAD가 가리켜온 commit들의 기록. 이를 통해 직전에 HEAD가 가리키던 commit의 아이디를 얻어서 git reset --hard 아이디로 돌아갈 수 있음.
  • git log --pretty=oneline --all을 이용하면 모든 branch의 commit history를 확인할 수 있음. 이 때 더 가시적으로 효과적이게 표현하려면 git log --pretty=oneline --all --graph을 활용할 수 있음. 이 때 * 표시가 commit 하나이다.
  • sourceTree 사용법: https://www.codeit.kr/topics/git/lessons/2943
  • git rebase 브랜치 : 실행 결과는 merge와 동일함
    merge와 rebase의 차이:
  1. rebase는 새로운 commit을 만들지 않음
  2. rebase로 만들어진 커밋히스토리는 비교적 깔끔함

  • 작업내용 임시저장하기: 내가 브랜치 A에서 수정하던걸 마무리해서 commit하지 못하고 급히 브랜치 B로 이동해서 다른 작업을 수행해야 하는 경우, 작업내용이 날라갈 수 있음 ➡️ 이를 방지하기 위해 임시저장을 해야 함!
    git stash로 저장
    git stash list로 확인 가능: 최근 commit 이후 작업했던 내용은 모두 stack에 옮겨지고 working directory 내부는 다시 최근 commit의 상태로 초기화됨
    git stash apply 를 사용해서 다시 working directory로 불러올 수 있음!
  • 만약 잘못된 브랜치에서 작업하고 있었다면? 브랜치 A에서 작업해야 할 내용을 실수로 브랜치 B에서 작업해버렸다고 가정하자. 역시 git slash로 해결 가능!
  1. git stash로 stack에 작업 내용 저장하기
  2. 올바른 브랜치로 이동한 후, git stash apply로 불러오기 (이 때, 정확도를 위해 stash@{0} 등의 아이디를 apply 뒤에 붙여주기!
  • stack에 작업 내용이 계속 쌓이면 나중에 아이디를 일일이 확인해서 적용하는 번거로움이 생길 수 있음
    ➡️ 사용한 작업내용은 git stash drop 아이디을 통해 지워주자! (가장 최근에 저장된 작업내용의 아이디: stash@{0}
    ➡️ 아예 작업내용 적용 + stack에서 삭제를 동시에 실행해주는 커맨드인 git stash pop [작업 내용의 아이디]를 사용하자! (가장 최근에 작업해서 맨 위에 위치한 작업내용의 경우 아이디 생략 가능!)
  • git cherry-pick: 자신이 원하는 작업들이 들어있는 commit들만 가져와서 현재 브랜치에 추가하기 (merge등과 달리 전체 브랜치를 다 가져올 필요가 없어짐)
  • 여러 commit을 하나의 commit으로 만들어서 정리하기: git reset --mixed (or --soft)로 commit은 취소하되 working directory의 내용은 그대로 유지하고, git add ., git commit -m "커밋메시지" 순으로 commit해주기
  • 총정리: https://www.codeit.kr/topics/git/lessons/2954

Git의 일반적인 작업 흐름

웹 사이트를 만드는 프로젝트에서 새로운 기능인 "사용자 프로필 페이지"를 추가하는 상황:

git pull: 먼저 원격 저장소에서 최신 코드를 받아와서 현재 로컬 코드가 최신 상태인지 확인하고, 다른 사람이 진행한 작업을 로컬 리포지토리에 포함시킴
git checkout -b add_profile_page: 새로운 기능을 위한 브랜치를 생성하고 적절히 명명하기
git add -A: 새로운 프로필 페이지에 필요한 모든 파일과 변경 사항을 staging area에 추가하기 (새로운 HTML, CSS, JavaScript 파일 등)
git commit -m "feat: add user profile page": staging area에 있는 변경사항을 커밋
git push: 커밋한 변경 사항을 원격 저장소에 푸시합니다. 이를 통해 다른 팀원들이 이 변경 사항을 볼 수 있게 됩니다.

Pull Request

  • 생성 방법
    프로젝트 생성 (리포지터리 생성) → 프로젝트 클론(git clone https://github.com/<username>/<repository-name>.git )
    ORRRR
    기존의 프로젝트 내용 가져오기(git pull)
    → 브랜치 생성 (git checkout -b) → 변경 사항 커밋 (git add & git commit) → git push → PR 생성
  • 상태
    open: 아직 검토가 끝나지 않았거나 추가적인 작업이 필요한 상태
    merged: 소스코드의 기본브랜치로 병합된 상태
    closed: 거부되었거나 더 이상 유효하지 않은 상태
  • merge pull request
  1. merge commit을 만들며 합치기: 두 브랜치의 변경사항을 모두 유지하면서 병합 → 각 브랜치의 변경사항이 과거의 commit으로 보존되고 새로운 commit이 추가되어 최종 병합이 완료됨
  2. Squash and merge: 브랜치에서의 모든 변경 사항을 하나의 커밋으로 압축하여 병합
  3. Rebase and merge: 현재 브랜치를 target 브랜치에 재위치(rebase)시킨 후 병합

충돌 방지 방법 (결론: 작은 단계별 push를 해라)

  1. 개발 기간이 길어질수록 메인 브랜치와 개발 중인 브랜치 간의 차이가 커지며 충돌 가능성도 증가함
    ➡️ 해결책: 주기적으로 git merge main를 통해서 원본 브랜치의 최신 변경 이력을 main 브랜치로 가져오는 것
    잊기 쉽기 때문에 매일 아침에 동기화하기 등 정기적인 루틴을 만들어두는 것이 중요함!

    위의 그림처럼 중간중간 동기화가 진행되어야 한번에 지나치게 많은 충돌로 인해 문제가 되지 않음
  2. 작은 Pull Request 만들기
    항상 가능하지는 않음
    3.파일을 작게 만들기
  3. 동료들과 소통하기

Fork

  • Fork: 이미 존재하는 원격 Git repository를 사용자의 계정으로 복사하는 기능
    사용자는 자신의 repository로 fork해온 프로젝트를 자유롭게 변경할 수 있음
  • 작업이 끝난 후에는 Pull Request 기능으로 원본 repository에 기여할 수 있음

기타 Tip ✨

  • 자동으로 코드 작성 스타일을 formal하게 맞춰주는 툴: Linting, Formatter

0개의 댓글