기억의 실마리
2023. 5. 24. 17:31

git filter-branch란?

브랜치를 재작성할 수 있는 기능이며 간략하게 소개하자면 필터를 제공해서

필터에 적용된 파일만 가지고 히스토리를 재구축하는 기능이다. 

이번에 다룰 내용은 특정 파일에 대한 기록을 제외하고 재구축 하는 것에

대한 내용이다.

 

어떤 경우에 쓰면 좋을까?

개발을 진행하면서 깃허브 레포지토리에 push할때 간혹 실수를 하게 될 때가 있다.

예를 들면 절대로 공유되어선 안될 민감한 정보들이 담겨있는 env파일이

푸쉬되어버린 경우에는 아무리 이후에 gitignore파일을 수정하고 깃허브에서 푸쉬된

env파일을 삭제해도 해당 레포지토리의 공개범위가 public인 경우라면 히스토리를

확인하면 env파일의 내용을 누구나 볼 수가있다. 그렇기 때문에 Git의 히스토리 자체를

필터링하여 특정 히스토리를 삭제하고 깃허브에 적용해주어야 할 경우에 많이 사용한다.

 

filter-branch를 사용하게 된 계기

과거 개발 입문당시에 env파일을 실수로 push했던 일이 있었고 레포지토리에서 삭제하면

나에게만 보여지고 다른 유저는 볼 수 없을 것이라고 생각했었던 것 같다. 그렇게 둘러보다

2가지 프로젝트에서  env파일을 삭제했던 기록이 남아있었고 삭제처리가 필요했다. 때문에

git에서 제공하는 filter-branch라는 기능을 알게되었고 이 기능을 사용하여 env에 대한

기록을 모두 제거하고 재구축했다.

 

사용예시

1. 기능사용 환경

내가 filter-branch를 사용한 환경은 백엔드와 프론트엔드를 동시 개발을 진행하고 있었기 때문에

project라는 디렉토리 안에 fontend, backend 두가지 디렉토리로 나누어 개발했다. project디렉토리

내부에 존재하는 frontend와 backend디렉토리를 스테이징 시켜 버전을 관리하고 있었기 때문에

깃허브 레포지토리에는 fontend, backend 두가지 디렉토리가 존재하고 있는 환경이였다.

 

2. 기능사용이 가능한 위치

반드시 해당 기능은 최상위 트리에서만 실행해야 한다. 나의 경우는 fontend디렉토리가 아닌

backend디렉토리에서 env파일에 대한 기록을 삭제해야하기 때문에 처음에는 backend디렉토리 에서

파워쉘을 열어 filter-branch 명령어를 사용했었다. 하지만 실행되지 않았다.

그 이유는 최상위 디렉토리는 backend디렉토리가 아닌 project디렉토리이기 때문이다.

반드시 최상위 트리인 project디렉토리에서 명령어를 실행시켜야 하며 명령어를 작성할때

경로만 backend/... 이렇게 지정해주면 되는 것이다.

 

 

3.  예시코드

# 코드의 두번째 줄에서 backend/.env 는 필터링해줄 경로+파일
git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch 
backend/.env' --prune-empty -- --all

# 이 후에 강제 push 해준다.
git push origin main --force

위에 명령어는 지정된 경로에서 지정된 파일과 일치하지 않는 히스토리만을 남긴채로

재구축하는 명령어다. " Ref 'backend/.env' was rewritten " 명령어가 나오면 재구축이 완료된 것이다.

이후에 강제푸쉬를 해주고 깃허브 레포지토리를 확인해보면 원하는 히스토리가 사라져 있는 것을

볼 수 있다.

 

마치며...

나의 경우는 특별히 문제없이 기능이 잘 수행되었고 문제를 해결할 수 있었지만 타 기술블로그를 찾아 보니 불가피하게 문제해결을 의도하지 못한 방향으로 해결해야하는 상황도 종종있는 것 같았다. 아무리 문제를 해결할 수 있는 좋은 기능들이 있다고 하여도 너무 맹신하는 것 보다는 미리 문제를 방지할 수 있는 기반을 구축한 후에 개발을 진행하는 것이 가장 중요하다고 생각했다.

'Git > Github' 카테고리의 다른 글

[ GitHub ] 깃허브 사용해보기  (0) 2023.03.19
2023. 3. 19. 15:29

Git & GitHub

Git은 개발자 리누스 토르발스에 의해서 개발되었고

분산 버전관리 시스템(DVCS : Distributed Version Control Systems)이다.

이는 컴퓨터파일의 변경사항을 추적할 수 있으며 주로 여려사람들이 하나의

프로젝트를 개발할때 작업을 조율하는데 사용한다.

 

GitHub는 Git을 지원하는 웹 호스팅 서비스 시스템(Cloud)이다.

작업중인 컴퓨터에 Git History를 GitHub-Cloud에공유할 수 있다.

공유된 파일은 fetch하여 clone파일을 만들 수도 있고 clone파일을 수정하여

기존 클라우드에 공유된 파일에 덮어쓰거나 새로운 파일을 추가로 공유할 수도 있다.

이러한 서비스는  GitHub뿐만 아니라 GitLab, BitBucket 등 다수 존재한다.

웹 호스팅 서비스 시스템에선 GitHub가 가장 대중화 되어있고 많은 오픈소스를

공유하고 있는 것이 가장 큰 장점이다.

 

 

GitHub에 대한 견해

처음 깃허브를 접했을때는 단순 클라우드가 아닌가? 굳이 써야하나 싶었던 생각을 0.1초나마 했던 것 같다. 하지만 지금의 나로서 깃허브를 바라보는 시점은 "깃허브가 없었다면... 지금의 나도 없다..." 라고 생각할 정도로 많은 도움을 받고 있다. 깃허브는 개발자의 대다수가 경험해보았을 것이고 대게 나와 같이 긍정적인 의견을 가지고 있을 것 같다.

 

 

GitHub 사용준비

1. Install

깃허브 홈페이지로가서 install을 먼저 해주어야한다.

OS환경이 window인 경우 공식홈에서 install을 하면 되지만

Mac인경우 Homebrew를 설치하여 brew install git 명령어를 입력하여

인스톨 해야 한다.

 

2. 깃허브에 레포지토리(저장소) 생성

깃허브 홈페이지에 회원가입한 후 로그인 하고 Repository -> New 를 눌러서

새로운 레포지토리를 생성한다. 가능하면 처음에 README는 제외하고 만든 후

프로젝트가 진행되면서 이후에 작성하는 것이 바람직하다.

 

3. 사용자정보 입력

깃허브에 공유하고자 하는 프로젝트 경로에서 파워쉘을 열거나

프로젝트를 개발툴로 열어서 터미널에 사용자 정보를 입력해준다.

git config --global user.name "내이름"  // 사용자이름

git config --global user.email "내메일@example.com"  // 이메일

 

4. Git Init

깃이 프로젝트를 감지할 수 있도록 만들어주는 명령어다.

프로젝트를 개발툴을 사용하여 열고 터미널에 git init 을 입력하면

프로젝트내부에 .git 파일이 생기면서 컴퓨터에 Git History를 남기며

깃허브에 레포지토리를 지정하면 해당 레포지토리로 공유할 수 있게된다.

 

5. 깃허브 레포지토리와 연결

깃허브에 공유하기 위해서는 저장소와의 연결이 필수적이다.

이를 위해서 깃허브 레포지토리의 주소가 필요한데 깃허브에 로그인해서

공유하고자 하는 레포지토리에 접속하여 녹색버튼으로 되어있는

  <> Code  버튼을 눌러서 주소를 복사하여 터미널에 아래와 같이 입력한다.

git remote add origin 레포지토리주소
// remote를 origin이라는 변수명으로 추가해주고 레포지토리주소와 연결

주의해야할 점 :  url에서 복사하면 연결에 실패할 가능성이 있다. 이때 주소끝에 .git을 추가하면 된다.

 

 

Staging

깃허브에 파일을 공유하기 전에 반드시 선행되어야할 작업이 스테이징이다.

스테이징은 공유할 파일을 Git이 감지할 수 있도록 만드는 것이다.

// terminal
git add 내파일.js  // 반드시 확장자명을 명시해야 한다. space를 넣어서 복수 스테이징 가능

git add .  // 모든 파일을 listen

git commit -a  // 수정된 파일 모두 스테이징

 

Commit

깃허브의 가장 기본이며 핵심인 커밋은 버전을 생성하는 명령어다.

커밋 또는 버전생성이라 하며 프로젝트를 공유를하거나 깃허브에서

가져온 파일을 수정한상태로 덮어쓸 때 모두 반드시 커밋이 선행되어야한다.

// terminal
git commit -m '버전생성 메모'  // -m 수정내용을 메모한다.

git commit -am '메모'  // 수정된 모든 파일을 커밋(버전생성)한다.

 

Push

푸시는 스테이징 이후에 커밋된 파일을 깃허브에 공유하는 명령어다.

반드시 스테이징 ->  커밋 이후에만 가능하며 기존에 깃허브에 공유되던 파일에

덮어쓴다. 푸시하기전에 레포지토리와 브랜치가 필요하다. master가 default이며

브랜치명을 main으로 바꿔주는게 의례적이지만 요근례에는 다시 master 그대로

쓰는 경우도 적지않으니 협업을 하는 경우 팀원들과 브랜치명을 먼저 결정 후에

개발을 진행해야 한다.

git branch -m main  // 브랜치이름 변경. 필요시 적용

git push 리모트변수명  // 레포지토리에 적용시킨 remote의 변수명을 써야한다.

 

 

GitHub 공동작업

혼자 깃허브를 버전저장소로 사용할때는 스테이징, 커밋, 푸쉬만 사용하면 되지만

프로젝트를 누군가와 공유하며 공동작업을 하는 경우에는 이 외에도 Clone, Pull, Merge

등을 사용한다. 그리고 Pull이지만 깃허브에서 요청하여 팀원들과 변경사항을 공유하여

merge할 코드를 선택하는 PR(Pull Request)라는 기능도 사용을 하게 된다. merge방식 또한

정하여 개발을 진행해야 한다. merge방식은 크게 3-way-merge, fast-forward-merge

두가지로 나눌 수 있다.

 

Git Merge & Pull

1. Merge

병합이라는 뜻으로 서로 다른 코드를 하나로 합치는 명령어다.

변경점이 일치하지 않아 충돌하는 코드를 명시해주고 이를 수작업을 통해서

어떤 코드를 사용하여 합칠 것인지 정한 후 병합한다.

<<<<<<< HEAD
main에서 짠 코드
=======
feature에서 짠 코드
>>>>>>> feature

// 두 코드중 하나를 지운 후(====, >>>이런 것들 모두 제거) commit하면 브랜치가 합쳐진다.

 

2. Pull

지정한 브랜치의 코드를 가져온다. 단순히 가져오는 것이 아닌

fetch + merge하기 때문에 해당 브랜치의 코드를 fetch하여 가져온 후

pull을 요청한 코드와 충돌하는 코드를 현재 코드에 merge까지 

해주는 것이 pull이다. 때문에 공동작업해서 dev브랜치에 올린다고 가정하면

dev에 다른사람이 코드를 merge해서 최신화를 시켜두면 나는 pull을 사용해서

나의 브랜치 히스토리에 dev의 최신화된 코드를 포함시켜 [dev + 내브랜치코드]를

dev로 push해서 업데이트 시키는 것이다. 때문에 실질적으로 협업을 하게되면

merge명령어보다 많이 사용하게 된다.

git pull origin dev

// 작업중이던 브랜치에서 git pull 리모트변수 메인브랜치명

 

fast-forward

< 예시 브랜치 >

origin / feature = 작업용 브랜치

origin / main = 배포브랜치(메인브랜치)

 

fast-forward 관계

이 관계는 기존 배포용브랜치 main 작업용브랜치 feature의 관계가 기준이며

feature의 커밋 히스토리 메인브랜치 main의 커밋 히스토리를 포함하고

있으면 fast-forward관계가 형성된다.

 

fast-forward merge

fast-forward관계인 상태에서 메인브랜치인 main에서 git merge feature하면 된다.

 

3-way-merge

3-way-merge는 작업중인 각 브랜치에 커밋이 1회이상 있어 코드가 일치하지 않는

두 브랜치를 합쳐서 새로운 커밋을 만들어주는 것이다. 이는 가장 기본적인 동작방식이다.

 

Git Clone

이름 그대로 프로젝트를 그대로 복사하여 클론을 만드는 명령어다.

개인이 오픈소스를 코드분해하여 학습할때도 쓰이겠지만 협업에서는 공동작업자가 있는

프로젝트에 합류하여 처음개발을 진행할때 많이 쓰인다. 작업할 폴더경로에서

파워쉘 또는 깃베스를 사용하여 git clone 명령어를 사용하여 최신화된 코드를 가져와서

작업을 진행한다.

git clone 레포지토리주소

 

브랜치 전략 Git-flow & Trunk-based

Git-flow

브랜치를 기능, 혹은 따로 기준을 만들어 나눈 후 최종배포 main브랜치 이전에 dev와 같은

임시배포브랜치를 만들어 개발을 진행하는 것이다. 예를 들어 feature에 신기능을 개발하고

auth브랜치에서 인증기능을 개발한다고 가정하면 이를 바로 main브랜치에 합치는 것이 아니라

dev브랜치에 합쳐서 QA 즉, 여러 테스트를 거친 후 최종적으로 main브랜치에 merge해서

배포하는 방식이다. 안정적인 운영이 필요한 경우 Git-flow전략을 많이 사용한다.

 

Trunk-based

Git-flow전략과 다르게 브랜치를 많이 만들어두지 않고 개발해야하는 기능에 맞는 브랜치명

지어주고 해당기능을 개발완료 후 main브랜치에 합친다.이후엔 해당기능의 브랜치는 삭제한다.

Trunk-based전략은 바로바로 공유배포해도 상관없고 큰 업데이트를 하지않는 안정적인

프로그램인 경우 많이 사용하고 브랜치는 크게 main과 feature정도만 운영해도 좋다.

 

PR(Pull Request)

개발툴에서 pull을 하게 될 경우 코드 자체에 충돌하는 내역이 그대로 fetch되어 적혀버리고 공동작업자가 있는 경우 변경된 커밋을 공유할 수도 없기때문에 이를 보완하기 위해 깃허브에서 만든 기능이 PR이다. PR을 하기 위해서는 깃허브에서 해당 레포지토리에 접속하여 Pull Requests를 눌러서 PR을 진행하면 된다.

  1.   New pull request   를 누른 후 base와 compare를 선택한다.
  2.   Create pull request  를 누르고 코멘트를 남긴 후   Create pull request  를 누른다.
  3. 충돌하는 코드가 없다면  Marge pull request  를 누르면 완료되고 있다면 선택하여 채택해주어야한다.

 

마치며...

깃허브는 모두가 대중적으로 쓰는 만큼 나 역시 개발자로서 공부를 시작하고 코딩을 시작할때 프로젝트를 저장하기 위해서 GitHub를 사용하기 시작했다. 사실상 현재 개발의 트렌드와 개발시장의 확장 중심에는 GitHub가 있기 때문이라고 생각한다. 포스팅을 하면서 생각보다 정리하여 쓸 내용이 많아서 포스팅에 꽤 많은 시간이 들어갔던 것 같다. 그 만큼 포스팅하면서 생각을 다시 한번 정리할 수 있어 좋았다.

'Git > Github' 카테고리의 다른 글

[ git filter-branch ] 깃허브 저장소 히스토리 필터링  (0) 2023.05.24