//1. master 브랜치로 이동
$git checkout master
//2. 병합할 브랜치를 master브랜치에 merge
$git merge [master에 병합할 브랜치 명]
//위 1,2를 한번에 표현 가능
$git merge [master에 병합할 브랜치 명] master
병합을 하면합쳐진 브랜치의 커밋 메시지가 중복으로 쌓이게 됩니다.
커밋 순서를 바꾸지 않습니다.
존재하는 브랜치가 변경되지 않습니다.
새로운 merge commit을 생성합니다.
git merge --abort:병합을 취소하는 명령어
위 이미지는Main 브랜치에 Feature 브랜치를 병합하는 과정을 나타냅니다.
커밋 순서가 변경되지 않고, 기존 분기는 유지되는 모습을 확인할 수 있습니다.
1-2. git conflict
충돌 상황 발생
//merge 실행
$git merge [master에 병합할 브랜치 명]
//conflict 발생
CONFLICT (content): Merge conflict in [수정한 파일]
Automatic merge failed; fix conflicts and then commit the results.
자동 merge가 실패했으니,충돌 부분을 수정하고 결과를 다시 커밋 하라는 경고문이 노출됩니다.
충돌이 발생한 이유는두 브랜치에서 [수정한 파일]의 내용이 서로 다르기 때문입니다.
이와 같이같은 부분에 서로 다른 부분이 있을 경우,merge conflict가 발생할 수 있습니다.
이를 해결하기 위해충돌이 발생한 부분을 수정이 필요합니다.
//[수정한 파일] 내용 출력
//사용하는 툴이 있다면 툴을 사용하여 conflict가 발생한 부분 수정하여도 됨
//ex : intelliJ, eclipse, vscode 등
$ cat [수정한 파일]
1. 안녕하세요.
2. git merge 중
3. conflict 상황 입니다.
<<<<<<< HEAD
4. 오전에 작성하였습니다.
=======
4. 오후에 작성하였습니다.
>>>>>>>> [병합할 브랜치 명]
위처럼 충돌이 일어난 부분은<<<<<<<<과=======혹은,=======과<<<<<<<<사이에 표시됩니다.
<<<<<<<< 과 ======= 사이에 표시된 내용은merge를 실행한 브랜치에 있는 내용을 나타냅니다.(HEAD가 가리키고 있는 내용)
반대로 ======= 과 <<<<<<<< 사이에 표시된 내용은merge 하고자 하는 브랜치(즉, 병합할 브랜치 명)의 내용을 나타냅니다.
이 표시들을 기반으로원하는 것을 선택하여 수정을 마친 후충돌이 일어난 파일을 커밋해주면merge가 완성됩니다.(위에 표시된 기호들을 없앤 후 커밋)
$ cat [수정한 파일]
1. 안녕하세요.
2. git merge 중
3. conflict 상황 입니다.
4. 오후에 작성하였습니다.
위 그림처럼 Feature 브랜치의 커밋은 Main 브랜치가 가지고 있던기존의 커밋 뒤에 위치하게 됩니다.
//master에 rebase 할 브랜치로 이동
$git checkout [rebase 할 브랜치]
$git rebase master
//rebase 할 브랜치를 master 브랜치에 merge
$git checkout master
$git merge [rebase한 브랜치]
병합을 하면 브랜치의 커밋 메시지가시간 순서대로합쳐집니다.
히스토리를 깔끔하게 유지하기 위해사용합니다.
전체 브랜치를마스터 브랜치 끝에 위치시킵니다, 그렇기 때문에master 브랜치의 기존의 마지막 커밋 뒤에 병합할 브랜치의 커밋들이 합쳐지게 하여master 브랜치에 재배치(rebase) 하는 것을 말합니다.
rebase 하기 전
rebase 된 후
즉, 위 그림처럼 master 브랜치의 m2 상태에서 다른 브랜치의 f1, f2 커밋을 재배치(rebase) 하면, 두 번째 사진과 같이m2 이후에 f1, f2 이 재배치됩니다.
2-1. rebase 진행 과정
//feature 브랜치로 체크아웃한 상태
$git checkout feature
feature 브랜치로 체크아웃한 상태, head는 feature를 가리키고 있음
$git rebase master
master와 feature의 공통 조상이 되는 base 커밋부터 현재 브랜치까지의 변경 사항(▵1, ▵2)을 구해서 patch로 저장해 둠
head를 master로 변경
Applying f1 : head가 현재 가리키고 있는 m2에 변경사항 ▵1 을 적용하여 새로운 커밋 f1'을 생성
Applying f2 : f1'에 변경사항 ▵2 을 적용하여 새로운 커밋 f2'을 생성
feature가 f2'를 가리키도록 함
$git merge feature
feature를 master로 fast-forward merge 하여 완료
2-2. rebase 사용법
//수정할 커밋들의 리스트 출력
//git rebase -i [수정을 시작할 커밋의 이전 커밋] 형식으로 입력
$git rebase -i HEAD~4
//4개의 커밋 리스트 노출
hint: Waiting for your editor to close the file...
pick 907c451 commit1
pick 1a7c765 commit2
pick v07c952 commit3
pick 40jc438 commit4
//사용할수있는 명령어 리스트
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
pick
-커밋을 사용하겠다는 의미, 이를 이용해 커밋의 순서를 바꿀 수 있고, 커밋의 해시값을 이용해 특정 커밋을 가져올 수 있습니다.
-rebase 명령어를 실행하면 기본적으로 pick으로 설정돼있기 때문에 아무것도 변경하지 않고 종료한다면, 커밋에 대하여 어떠한 변경도 일어나지 않게 됩니다.
- 위 코드에서 commit2와 commit3의 순서를 바꾼다면,커밋 순서와 커밋 해시값까지 변경됩니다.
reword
- 커밋 메시지를 변경하는 명령어
- 커밋 메시지를 변경할 커밋 앞에reword명령으로 수정하고, 저장하면 해당 커밋의 메시지를 다시 작성하는 에디터 창이 열리게 됩니다.
- 커밋메시지와 커밋의해시값또한 변경됩니다.
edit
- reword 명령어는 커밋 메시지만 변경하는 명령이라면, edit 명령어는 커밋 메시지뿐만 아니라 커밋의 작업 내용까지 변경할 수 있습니다.
- commit4라는 커밋을 edit으로 바꾸고 저장 후 종료하면, 변경할 커밋으로 checkout됨, 그 상태에서 변경 작업을 수행하면 됩니다.
- 그 후 변경사항을 저장하기 위해 아래와 같은 명령어 입력
//staged 상태 변경
$git add .
//변경할 커밋메시지 입력
$git commit --amend -m "commit4-amend"
//rebase처리
$git rebase --continue
최근에 git clone 후 npm install을 했을 때 package-lock.json가 변경되는 문제를 겪었고 npm ci 명령어를 통해 해결하게 되었던 일이 있었다.
이 문제를 통해 package-lock.json이 존재한다고 하더라고 npm 버전에 따라 npm install이 다르게 구동되어 package-lock.json을 기존과 다른 내용으로 덮어쓸 수 있게 된다는 것을 알게 되었다.
그럼 npm ci는 무엇이기에 이런 문제를 해결해 준 걸까? 그리고 모듈을 설치할 때 무조건 npm ci를 사용하면 되는 걸까?
위의 궁금증 해결을 위해 npm install과 npm ci가 무엇이고, 둘의 차이는 어떤 것인지 그리고 언제 사용하면 좋을지에 대해 정리를 해봤다.
npm install
소개
먼저 npm install은패키지와 패키지가 의존하는 모듈을 설치하는 명령어이며, npm i 혹은 npm add로 쓰기도 한다.
사용 방법
npm install는 다음과 같이 명령어를 이용할 수 있다.
개별적으로 패키지를 설치할 때위와 같은 방법으로 사용하면 package.json과 package-lock.json이 없는 경우에는 이 2개의 파일이 생성되고, package.json과 package-lock.json이 존재한다면 dependencies에 패키지가 추가된다.
npm install 패키지_이름
pacakge.json의 dependencies에 나열되어 있는 패키지를 설치할 때이때 package.json의 요구 사항(dependencies)을 만족해야 package-lock.json을 적용된다. 만약 요구 사항을 만족하지 않는다면 pacakge를 업데이트하고 package-lock.json 파일의 내용이 변경된다.
npm install
이 외에도 npm install 사용 방법은 다양하다. 이 글에서는 npm install과 npm ci 차이 설명이 주목적이기 때문에 가볍게 정리하고 넘어가지만 더 자세히 알고 싶다면여기(npm-install 공식 문서)를 참고하면 된다.
npm ci
소개
npm ci는 npm install 과 유사하지만, npm install과 달리같은 개발 환경을 구축해 줄 수 있기 때문에테스트 플랫폼, 지속적인 통합 및 배포(CI와 CD)와 같은 자동화된 환경이나 dependencies를 새로 설치해야 하는 모든 상황에서 사용할 수 있는 명령어이다.
참고로 5.7.0 버전부터 지원한 명령어이며, npm 공식 블로그에 따르면, 이름에서 알 수 있듯이 CI(Continuous Integration) 환경에 큰 이점이 될 것이라고 생각하고 있다.
사용 방법
사용 방법은 단순히 npm ci 명령어를 입력만 해주면 된다.
npm ci
주의 사항
npm ci는 pacakge-lock.json 기반으로 설치가 진행되기 때문에 package-lock.json이나 npm-shrinkwrap.json 파일이 꼭 존재해야 한다. 만약 package-lock.json이 없다면 아래와 같은 결과를 출력하고 패키지 설치가 진행되지 않는다.
added 1 packages in 4.892s
npm ci는 아래와 같이 사용할 수 없다.npm ci는 한 번에 전체 프로젝트만 설치할 수 있기 때문에개별적으로 패키지를 설치하는 것이 불가능하다.
npm ci 패키지_이름
이미 node_modules 폴더가 존재하는 경우에 npm ci를 실행시키면 기존 node_modules 폴더를 삭제하고 다시 설치한다.
package-lock.json의 dependencies가 package.json의 dependecies와 일치하지 않는다면, npm ci는 package-lock.json을 업데이트 하는 대신에 오류와 함께 종료한다.
npm install 과 npm ci의 속도 비교
npm install로 설치했을 때
added 1032 packages from 651 contributors and audited 1039 packages in 236.795s
npm ci로 설치했을 때
added 1033 packages in 135.108s
npm install을 사용해서 1032개의 패키지를 설치했을 때 236.795초가 걸렸고, npm ci를 사용해서 1033개의 패키지를 설치했을 때 135.108초가 걸렸다.
위의 결과를 통해npm ci가 npm install 보다 더 빠르다는 것을 알 수 있다.
npm ci가npm install 보다빠른 이유는 지정된 버전의 패키지만 설치하면 돼서최신 호환 버전을 확인하는 과정이 필요 없기 때문이다.
참고로, npm ci는 다음과 같은 경우에 훨씬 더 빠를 것이다.
package-lock.json 혹은 npm-shrinkwrap.json 파일이 있을 때
node_modules 폴더가 없거나 비었을 때
참고 - npm-shrinkwrap.json 이란?dependencies에 설치된 패키지의 버전을 고정시키는 명령어인 npm shrinkwrap를 실행시켰을 때 생성되는 파일로서, 패키지가 의존하고 있는 모듈의 버전과 정보를 갖고 있다.