*유튜브의 Git & GitHub Tutorial for Beginners를 참고하였습니다.
*https://victorydntmd.tistory.com/ 를 참고하였습니다.
Git은 분산형 버전 컨트롤 시스템이다.
이것은 기본적으로 의미한다.
-시간에 따른 파일의 변화를 기록해주는 시스템이다.
-우리는 작성된 시간대의 파일의 특정한 버전을 기억할 수 있다.
-많은 사람들이 손쉽게 협업할 수 있다. 또한 프로젝트에 자신만의 버전을 가질 수 있다.
react-node-fullstack-last v1
react-node-fullstack-last v2
react-node-fullstack-last v3
... WTF
git을 사용하게 되면 하나의 디렉토리로 모든 버전을 관리할 수 있다.
react-node-fullstack
또한
프로젝트에서 내가 원하는 버전으로 되감을 수도 있다.
메인 코드베이스를 더럽히지 않아도 된다.(브런치)
다른 프로그래머와 협업할 수 있다.
그래서 GITHUB이 뭐라구?
1.우리의 프로젝트를 올릴 수 있는 온라인 서비스이다.
2.우리의 코드를 다른 개발자와 공유한다.
3.개발자는 다른 개발자의 프로젝트를 다운로드 할 수 있다.
4.다른 개발자가 프로젝트를 수정하거나 해당 프로젝트와 자신의 코드를 합칠 수 있다.
1.리포지토리는 내가 깃으로 추적하고자 하는 프로젝트의 컨테이너다.
2.많은 리포지토리에 많은 프로젝트를 가질 수 있다.
git은 루트 폴더 아래 모든 파일을 추적한다.
일종의 게임 세이브와 같은 역할을 한다.
이 커밋으로 인해 우리는 원하는 지점으로 돌아갈 수 있다.
Modified: 아직 커밋되지 않은 상태이다.
Staging: 커밋하고자 하는 수정된 파일을 staging에 올린다.
Commited: staging area의 파일들이 commit에 추가된다.
되돌리기는 기본적으로 커밋을 취소할 수 있게 해준다.
checkout commit
Modified 상태의 파일을 Unmodified로 되돌릴 수 있다.
주로 수정을 잘못해서 파일을 원상태로 되돌리고 싶을 때 사용한다.
git checkout git.html
git reset
add를 해서 Modifed가 아닌 Staged 상태라면 checkout이 아닌 reset을 해야한다.
reset을 하게되면 Staged 상태에서 Modified 상태로 되돌아간다.
이 때 checkout을 하게 되면 Modified에서 Unmodified로 되돌아 갈 수 있다.
git reset git.html
commit을 한 후 되돌릴 때도 reset을 사용한다.
옵션은 세 가지가 있다.
--soft
commit 후의 Unmodified에서 commit 전의 Staged 상태로 만든다.(add)
--mixed(기본 옵션)
Unmodified에서 commit 전의 Modified 상태로 만든다.(add 전)
--hard
Unmodified에서 commit 전의 Unmodified로 만든다.(모두 날려버린다.)
git reset HEAD~1
HEAD는 현재 commit의 위치이다. ~1은 commit 1개 전으로 되돌아가라는 것이다.
git revert
revert는 이전 commit을 새 commit으로 만들어 저장한다.
git revert HEAD
reset은 이전 commit으로 직접 되돌아 갔다면
revert는 현재 commit 위에 이전 commit을 덮어씌웠기 때문에
새로운 commit이 하나 추가된다.
revert는 주로 commit을 push해버린 경우 자주 사용한다.
서버에 한 번 저장된 commit은 다시 되돌리지 못한다.
그래서 commit을 덮어씌우는 revert를 사용하는 것이다.
참고-https://www.zerocho.com/category/Git/post/581b7122809622001722fc0b
git branch feature-1
같은 프로젝트에서 동시에 작업할 때 우리는 브랜치를 만들 수 있다. 브랜치를 만들게되면
우리는 마스터 브랜치를 전혀 건드리지 않고 작업할 수 있다.
작업이 성공적으로 완성되면 해당 브랜치를 마스터 브랜치에 Merge하면 된다.
만약 작업이 마음에 들지 않는다면 단지 Merge하지 않으면 된다.
git add .
git commit -m "first commit"
git remote add origin "github remote 주소"
git push origin master
merge를 하는 도중에 충돌( conflicts )이 발생할 수 있다.
현재 브랜치와 병합 하고자 하는 브랜치에서 같은 파일의 같은 위치를 수정했을 경우,
사용자가 어느 것을 선택할 것인지 Git은 알 수가 없다.
그래서 사용자에게 충돌난 부분을 직접 수정해서 충돌을 해결하라고 하는 것이다.
1.명령어
git merge
{대상브랜치} : 현재브랜치에서 대상브랜치를 병합시킴
--squash
대상브랜치를 병합할 때, 커밋 이력을 모두 제거하고 작업된 내용만 병합
이 옵션은 대상 브랜치의 모든 커밋을 하나의 커밋으로 합쳐서 merge 하는 방식이다.
즉, 대상 브랜치에서 작업했던 히스토리를 하나의 메시지로 압축시키는 것이다.
이 옵션은 테스트 브랜치에서 원래 브랜치에 병합할 때 유용한 방식이다.
처음부터 하나였던 브랜치가 임시로 빠져나왔을 때 그것을 다시 통합할 경우 사용하는 것이 좋습니다.
예를 들어, master 브랜치가 있고, 이를 그대로 복사한 child 브랜치가 있다고 가정한다.
.
그리고 child 브랜치에서 커밋을 5번을 했다고 했을 때, 당연히 master branch보다 커밋 수가 앞서 있다.
이 때 master 브랜치에서 --squash 옵션을 이용해서 child 브랜치를 병합하면,
child 브랜치의 5번의 커밋 내역은 무시되고 파일 수정 이력만 받게 된다.
따라서 깔끔한 히스토리와 함께 merge를 할 수 있게 된다.
--no-ff
fast-forward 방식으로 병합할 때, 병합된 것임을 알리는 커밋 메시지를 생성한다.
fast-forward 관계에서 merge를 하면 merge 커밋이 생략되는데,
--no-ff 옵션을 주면 merge할 때 커밋을 생성한다.
전자의 경우는 --ff 옵션과 같다.
fast-forward 관계일 때 옵션 없이 그냥 merge 할 때는 아래와 같이 브랜치가 갈라지지 않지만,
--no-ff 옵션을 추가하면 다음과 같이, "Merge branch 'child2'"라는 커밋 이력이 추가되는 것을 확인할 수 있다.
2.Fast-forward 방식으로 병합
1)master 브랜치 작업
# git checkout master
# git add .
# git commit -m "메시지"
새로운 브랜치 생성해서 작업
다음으로 master 브랜치에서 새로운 브랜치인 test1 브랜치를 생성합니다.
그러면 master 브랜치의 파일들과 커밋 이력을 그대로 복사되고, 독립적인 작업공간이 생성됩니다.
# git add .
# git commit -m "test1 메시지"
git merge
지금까지 내용을 요약하면 다음과 같습니다.
master 브랜치는 <span> 요소의 내용이 없지만, test1 브랜치에는 존재하는 상황입니다.
test1 브랜치가 master 브랜치보다 한 번 더 commit을 했습니다.
이제 master 브랜치에 test1 브랜치를 merge하도록 하겠습니다.
그러기 위해서는 먼저 master branch로 이동을 해야 합니다
# git checkout master
# git merge test1
Fast-forward란 merge 할 브랜치( 대상 브랜치, test1 브랜치 )의 commit이
현재 branch( 기준 브랜치, master 브랜치 )의 commit 보다 앞서가 있기 때문에,
기준 브랜치의 커밋을 대상 브랜치 commit으로 이동하겠다는 의미입니다
즉, "master 브랜치의 HEAD를 test1 브랜치의 HEAD로 이동하겠다 "는 뜻입니다.
실제로 master 브랜치의 파일을 열어보면, test1 브랜치에서 작성된 내용이 저장되어 있습니다.
가장 최근의 커밋 메시지도 test1 브랜치에서 작성한 커밋 메시지가 표시되구요.
이것이 fast-forward 방식의 merge입니다.
즉, 테스트를 진행할 브랜치를 만들어서 테스트가 성공적으로 끝나면 원래 브랜치에 통합하는 방식으로 사용하면 좋겠네요.
충돌발생
그런데 기준 브랜치와 대상 브랜치가 같은 파일의 같은 부분을 수정하면 충돌이 발생합니다.
1) master 브랜치 작업
이전 예제에 이어서 master 브랜치로 이동( git checkout master )한 후의 파일에 다음과 같이 작성합니다.
<div> 요소에 class 속성에 foo를 추가했고, </div>와 <span> 사이에 공백을 줬습니다.
그리고 나서 commit을 합니다.
# git add .
# git commit -m "master message"
그러면 현재 test1 브랜치보다 master 브랜치의 버전이 더 높은 상황이 됩니다.
2) test1 브랜치 작업
다음으로 test1 branch로 브랜치를 이동( git checkout test1 )한 후,
아래와 같이 <div> 요소의 class 속성에 goo를 추가하고, </div>와 <span> 사이의 공백을 없애겠습니다.
마찬가지로 commit을 합니다.
# git add .
# git commit -m "master message"
그러면 master 브랜치와 test1 브랜치의 commit 수가 같습니다.
즉, fast-forward 방식으로 병합이 되지 않을 것입니다.
3) git merge
이제 똑같이 master branch로 이동해서 test1 브랜치를 merge한다.
# git checkout master
# git merge test1
merge 명령어를 실행하면 충돌이 발생했다면서, merge를 진행하지 않는다.
상황은 다음과 같다.
1.master 브랜치와 test1 브랜치의 커밋횟수가 같다.
2/master 브랜치와 test1 브랜치는 <div> 요소의 class 속성 값을 각각 다른 값으로 동시에 수정
따라서 Git은 사용자에게 어떤 branch의 내용을 선택할 것인지 제시합니다.
merge를 진행했던 기준 브랜치는 master 이므로 <<<< HEAD 영역이 master 브랜치의 내용을 의미합니다.
<<<<< HEAD
=========
만약 협업 과정에서 이러한 충돌이 발생했을 경우에는 동료들과 함께 충돌을 해결해야 한다.
코드를 비교해 가면서 필요 없는 코드를 일일이 지우는 작업이다.
이는 귀찮은 작업이기 때문에 최대한 작업 내용이 겹치지 않도록 하는 것이 좋다.
이렇게 충돌이 발생한 후, 해결이 됐으면 commit을 하면 된다.
참고-https://victorydntmd.tistory.com/78
1. A는 환경 설정을 마친 프로젝트 파일을 Github에 올린다.
A는 Github에 repository를 생성하여 B, C를 collaborator로 추가한다.
B,C를 Collaborator로 추가해야 B,C가 해당 프로젝트에 pull, push 할 권한이 생깁니다.
# git init
# git add .
# git commit -m "프로젝트 시작"
# git remote add origin 깃헙주소
# git push origin master
2. B, C는 프로젝트 파일을 자신의 PC로 가져온다.
B, C는 A가 작업한 프로젝트 파일을 clone해서 가져온다.
git clone을 하면 자동으로 remote repository가 등록된다.
# git clone 깃헙주소
3. A, B, C는 각각 브랜치를 생성하여 작업을 진행합니다.
A, B, C는 각각 자신의 PC에서 brchA, brchB, brchC 이름의 branch를 생성한다.
# git branch branchA
# git branch branchB
# git branch branchC
이제 A, B, C는 깃헙을 공유하고 있는 상황이며, 독립적인 local repository를 갖고 있다
A, B, C는 각자 구현할 기능이 정해져 있으며,
각 기능을 끝낼 때 마다 깃헙에 자신의 브랜치 작업본을 push 한다.
이 때 주기적으로 mater branch에 merge 하는 것이 merge conflict에 대처하는 좋은 방법이다.
4. B가 기능 구현을 마치고 이 파일을 master branch에 병합한다.
제일 먼저 B가 기능 구현을 마쳤다고 가정하겠습니다.
이제 B는 master 브랜치에 자신의 파일을 올릴 것입니다.
// 현재 브랜치는 branchB
# git add .
# git commit -m "기능 구현 완료"
# git checkout master
# git merge branchB
# git push origin master
B는 깃헙의 master 브랜치에 push를 하기 전에
먼저 자신의 local repository에 있는 master 브랜치에
branchB 브랜치를 merge해야 한다.
그리고 local master 브랜치에서 깃헙 master 브랜치로 push한다.
자신의 local master 브랜치는 최신 코드를 push 하고 pull하는 용도로만 사용한다.
즉, master 브랜치는 local이든 remote이든 관리만 한다는 것이 핵심이다.
5. A, C는 작업 진행 중에 B가 올린 최신 버전을 갖고 와서 이어서 작업을 진행한다.
A, C는 B가 push한 최신 작업본을 사용하기 위해 깃헙에서 master 브랜치를 pull한다.
A, C는 pull할 때 master 브랜치로 이동한 후 pull해야 한다.
브랜치를 이동할 때, 작업을 마무리 짓고 commit을 한 후 이동해야 한다.
( working directory에 작업내용이 있다면 브랜치 이동이 안된다. )
# git checkout master
# git pull origin master
최신 버전을 가져왔으면, 자신의 작업본에 반영해야 한다.
A를 기준으로 branchA 브랜치로 이동 후 master 브랜치를 merge하면 된다.
# git checkout branchA
# git merge master
이 때, 같은 곳을 수정했다면 충돌이 발생할 수 있다.
6. C의 코드에서 버그가 발생하여 이전 버전으로 돌아가야 하는 경우
Github을 통해 A, B, C가 push, pull을 수행하면서 작업이 원할하게 진행되고 있다.
하지만 C가 테스트 도중 버그가 발생해서 한참 전의 상태로 돌아가야 하는 상황이 발생했다.
C가 버전을 local repository에서만 관리했다면 reset, revert 명령어
둘 중 하나를 사용할 수 있지만,
push를 하여 깃헙에도 올라간 상황이라면, revert 명령어만 사용할 수 있다.
여기서는 push를 한 상황이라 가정을 하고,
버그가 발생하기까지 총 5번의 commit을 했다고 가정한다.
현재 마지막 커밋 내용은 "C에서 5번째 기능 구현" 버전 ( 6d5ed94 )이다.
버그가 발생했기 때문에 안전하다 생각되는 곳은 "C에서 2번째 기능 구현" 버전이라 생각되어,
f37a6b7 버전으로 돌아가려 한다.
그러면 "C에서 3번째 기능 구현" 버전의 commit 번호( 1d9184f )로 revert를 하면 된다.
해당 버전의 commit 번호를 복사해서 revert 명령어를 실행한다.
# git revert commit번호
기능 2까지 완료된 버전으로 돌아가고 싶었던 것이므로 아래의 부분을 제거한다.
<<<<<<< HEAD
<span>기능 3 완료</span>
<span>기능 3 완료</span>
<span>기능 3 완료</span>
===========
다음으로, 이전 버전으로 돌아갔으니 커밋을 해서 이력을 남기는 것이 좋다.
# git add .
# git commit -m "기능2로 백업"
# git push origin branchC
revert는 이력을 남기고 버전을 되돌리는 명령어이므로
기능3, 4, 5에 대한 커밋 이력은 남아있을 것이다.
참고-https://victorydntmd.tistory.com/91
git --version
git config --global user.name yeonsoo
git config --global user.email m60kys@gmail.com
git config user.name //yeonsoogit config user.email //m60kys@gmail.com
git init
git status
git diff
git branch -a
git checkout 브랜치명
git branch -D 브랜치명