Skip to content
This page has been auto-translated and may contain errors.View in English

파일 무시하기 및 좋은 습관

docs.scrimba.com

weather-app이라는 프로젝트를 클론하고 npm install을 실행한 다음 새 저장소의 상태를 확인합니다.

bash
$ git status
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	node_modules/
	dist/
	.env

추적되지 않은 세 개의 폴더와 파일이 나타나며, 이 중 어느 것도 커밋에 포함되어서는 안 됩니다. node_modules/package.json에서 npm install이 몇 초 만에 다시 생성하는 수천 개의 파일입니다. dist/는 소스에서 매번 다시 빌드되는 빌드 출력입니다. 그리고 .env는 API 키를 포함합니다. 이 중 어느 것도 프로젝트의 히스토리에 남아서는 안 되며, 생각 없이 git add .를 입력하는 것이 어떻게 이런 일이 발생하는지입니다.

Git에게 무시할 항목 알려주기

.gitignore 파일은 Git이 절대 추적하지 않아야 할 파일과 폴더의 패턴을 나열합니다. 첫 저장소에서 저장소를 설정할 때 git init을 실행한 프로젝트의 루트에 한 번 만들면, 그 이후로 git statusgit add .는 일치하는 항목을 조용히 건너뜁니다.

bash
# .gitignore
node_modules/
dist/
.env

각 줄은 패턴입니다. dist/와 같은 일반 폴더 이름은 프로젝트의 어디에 나타나든 해당 폴더 전체를 무시합니다. .gitignore 파일 자체를 커밋합니다. 파일이 작고, 프로젝트를 클론한 모든 사람에게 유용하며, 소스 코드와 같은 방식으로 히스토리에 속합니다.

bash
$ git status
On branch main
nothing to commit, working tree clean

패턴이 준비되면 git status는 조용합니다. 이것이 바로 요점입니다. 커밋하지 않으려는 폴더와 파일이 더 이상 노이즈로 표시되지 않으므로 실제로 중요한 항목들만 표시됩니다.

패턴은 글로브를 지원하므로 *.log는 이름에 관계없이 .log로 끝나는 모든 파일을 무시합니다. 후행 슬래시는 패턴을 디렉터리로만 제한하므로 dist/dist라는 폴더만 일치하고 같은 이름의 파일은 그대로 둡니다. 더 광범위한 패턴에 의해 그렇지 않으면 포함될 항목을 무시 해제하려면 줄 앞에 !를 붙입니다. 무시된 폴더 내의 한 파일만 추적해야 할 때 유용합니다.

bash
# .gitignore
logs/
!logs/keep-this.log

Git은 또한 머신별 전역 무시 파일을 읽으며, 프로젝트와 관계없이 모든 저장소에 원하는 패턴을 적용합니다. .DS_Store 또는 *.swp와 같은 편집기 파일입니다. git config --global core.excludesfile ~/.gitignore_global로 한 번 설정하면 이러한 패턴을 프로젝트별로 추가할 필요가 없습니다.

무시 패턴은 쉘 글로브와 동일한 방식으로 일치합니다. 모든 문자 집합에는 *, 하나에는 ?, 디렉터리 전체에는 **를 사용합니다. 슬래시가 없는 패턴은 프로젝트의 모든 깊이에서 일치하지만, 슬래시를 포함하는 패턴은 해당 경로에 고정됩니다. 이러한 패턴의 일치는 순전히 로컬 동작입니다. Git은 git statusgit add가 표시할 항목을 결정할 때만 .gitignore를 참조합니다. Git이 이미 파일을 추적한 후에는 파일이 추적되는 것을 중지하지 않으며, 이는 다음 섹션에서 중요합니다.

JunoGit에게 무시할 항목 알려주기.gitignore 파일은 Git이 추적하지 않아야 할 항목을 나열합니다. node_modules/, dist/, .env는 거의 모든 프로젝트에서 일반적입니다. .gitignore 파일 자체를 커밋하여 프로젝트를 클론한 모든 사람이 동일한 깔끔한 상태를 얻도록 합니다. 나는 이것을 배우기 전에 실수로 수천 개의 의존성 파일을 스테이징하면서 한 번 오후 전체를 낭비했습니다.
JunoGit에게 무시할 항목 알려주기 패턴은 *.log와 같은 글로브를 지원하며, 후행 슬래시는 "디렉터리만"을 의미하고, 선행 !는 더 광범위한 일치 내의 항목을 무시 해제합니다. core.excludesfile로 설정한 전역 무시 파일은 편집기 및 OS 파일이 있는 곳이므로 모든 프로젝트의 .gitignore.DS_Store를 수동으로 추가하지 않아도 됩니다.
JunoGit에게 무시할 항목 알려주기 무시 규칙은 셸 스타일의 글로브 일치이며, 클라이언트 측에서 적용되며, Git이 추적되지 않은 항목으로 표시하는 것만 변경합니다. Git이 이미 알고 있는 파일은 규칙이 영향을 미칠 수 없다는 점을 명심하세요. 이 구분은 종이에서는 작지만 실제로는 비용이 많이 듭니다.

절대 비밀을 커밋하지 마세요

API 키, 데이터베이스 암호 또는 서명 인증서는 절대 커밋에 나타나면 안 됩니다. 이는 개인 저장소에서 공개 저장소만큼 엄격하게 적용되며, 첫 커밋부터 계속 적용됩니다. 비밀을 .env와 같은 파일에 넣고, 첫째 날부터 해당 파일을 .gitignore에 추가하고, 소스 파일에 작성하는 대신 거기에서 앱에 값을 로드합니다.

bash
# .env
WEATHER_API_KEY=sk_live_9f8e7d6c5b4a
bash
# .gitignore
.env

이 규칙을 자동으로, 매번, 예외 없이 따르세요. 커밋에 있는 키는 저장소에 대한 액세스 권한이 있는 모든 사람이 도달할 수 있으며, 공개 저장소에서는 누구나 도달할 수 있습니다.

실제 프로젝트에서 비밀은 일반적으로 한 곳 이상에 있습니다. 자신의 머신용 .env 파일과 배포된 모든 것에 대한 비밀 관리자 또는 호스트의 환경 변수 설정입니다. 실제로 둘 다 동일한 방식으로 작동합니다. 값은 소스 파일 외부 및 Git 외부에 있으며, 코드는 런타임에 환경에서 읽습니다. 대신 .env.example 파일을 배포하되, 변수 이름만 포함하고 실제 값은 포함하지 않아서 팀원들이 실제 키를 보지 않고도 설정해야 할 항목을 알 수 있도록 합니다.

다음은 이 규칙을 협상할 수 없게 만드는 사실입니다. 비밀을 삭제한 **커밋**은 히스토리에서 제거되지 않습니다. 키를 가진 이전의 모든 커밋은 여전히 그것을 가지고 있으며, 저장소의 히스토리에 영원히 저장되어 있으며, 누군가 만든 모든 클론은 해당 이전 커밋과 함께 제공됩니다. 새 커밋에서 파일을 삭제하는 것은 최신 스냅샷에 더 이상 파일이 없다는 의미일 뿐입니다. 이전 값을 보유한 객체는 여전히 .git에 있으며, 이전 커밋을 확인하거나 로그를 살펴보는 모든 사람이 도달할 수 있습니다.

"파일을 삭제하고 다시 커밋하기"는 이미 유출된 비밀을 절대 고치지 못합니다. 실제 비밀이 커밋에 있게 되면, 공급자에게서 회전하거나 취소하세요(새 키를 발급하고, 이전 키를 무효화함). 그러면 유출된 값이 저장소에 대해 이후에 수행하는 작업과 관계없이 더 이상 유용하지 않습니다. 비밀을 제거하기 위해 히스토리를 다시 작성하는 것은 가능하지만, 키가 노출되는 동안 이미 사용된 것을 취소하지 못합니다. 회전을 실제 해결 방법으로 취급하고 히스토리 정리를 그 위의 선택적 추가 항목으로 취급하세요.

Juno절대 비밀을 커밋하지 마세요 실제 API 키, 암호 또는 인증서를 커밋에 넣지 마세요. 비밀을 .env와 같은 파일에 보관하고 git add를 실행하기 전에 .env.gitignore에 추가하세요. 이것이 이 장에서 절대로 취급할 가치가 있는 한 가지 규칙입니다.
Juno절대 비밀을 커밋하지 마세요 로컬 비밀은 .env로, 배포된 비밀은 호스트의 환경 변수 또는 비밀 관리자로, 그 어느 것도 커밋되지 않습니다. 변수 이름만 포함된 .env.example을 배포하여 팀원이 실제 값을 보지 않고도 설정할 항목을 알 수 있도록 합니다.
Juno절대 비밀을 커밋하지 마세요 새 커밋에서 비밀을 삭제해도 히스토리에서 제거되지 않습니다. 모든 이전 커밋과 모든 기존 클론은 여전히 비밀을 가지고 있습니다. 비밀이 유출되는 순간 공급자에게서 키를 회전하세요. 그 회전이 실제로 중요한 해결 방법입니다.

추적된 후 파일을 .gitignore에 추가하기

이것은 거의 모든 사람을 최소한 한 번은 함정에 빠뜨리는 문제입니다. 파일을 실수로 커밋하고, 실수를 깨닫고, .gitignore에 추가하고(아래 echo 줄은 경로를 해당 파일에 추가함), Git이 이를 잊을 것으로 예상합니다. 그렇지 않습니다.

bash
$ git add config/settings.json
$ git commit -m "Add app settings"

# 나중에, 이것이 실수였음을 깨닫습니다
$ echo "config/settings.json" >> .gitignore
$ git status
On branch main
nothing to commit, working tree clean

git status는 깔끔한 트리를 표시하지만, config/settings.json은 여전히 추적되고 있으며 향후 모든 git log와 모든 클론에 여전히 표시됩니다. 무시 규칙은 Git이 아직 알지 못하는 파일에만 적용됩니다. 파일이 추가되고 커밋되면 히스토리의 일부이며, .gitignore는 해당 히스토리에 이미 있는 파일에 대해서는 의견이 없습니다.

실제로 앞으로 추적을 중지하려면, Git에게 디스크의 파일을 그대로 두고 추적 중인 파일을 제거하도록 지시합니다.

bash
$ git rm --cached config/settings.json
$ git commit -m "Stop tracking config/settings.json"

git rm --cached <file>은 작업 디렉터리에서 삭제하지 않고 Git의 추적에서 파일을 제거합니다. 해당 제거를 커밋하면, 그 시점부터 .gitignore 패턴이 처음부터 원했던 작업을 수행합니다.

동일한 수정은 git rm -r --cached <folder>를 사용하여 전체 폴더에서 작동하며, 이는 프로젝트의 초기에 .gitignore를 전혀 추가하기 전에 node_modules/ 또는 dist/가 커밋되었음을 깨달은 후의 일반적인 이동입니다. 한 번 실행하고, 제거를 커밋하고, 폴더는 향후 커밋에서 사라지며 모든 팀원의 디스크에 있는 파일의 로컬 복사본은 건드리지 않습니다.

이 동작은 스테이징 영역이 실제로 무엇인지에서 직접 따릅니다. Git은 **인덱스**를 통해 파일을 추적합니다. 다음 커밋에 정확히 무엇이 들어갈지에 대한 기록입니다. 파일을 추가하고 커밋하면 인덱스에 항목을 작성하고 커밋의 스냅샷에 작성합니다. .gitignore는 아직 인덱스 항목이 없는 파일을 Git이 무엇을 해야 할지 결정할 때만 참조됩니다.

항목이 존재하면, 무시 패턴은 관련이 없습니다. git rm --cached는 인덱스 항목을 삭제하면서 디스크의 파일을 유지하므로, 무시 패턴 편집만으로는 아무 작동하지 않는 이 문제를 실제로 고치는 명령입니다.

Juno추적된 후 파일을 .gitignore에 추가하기 Git이 이미 추적하는 파일을 .gitignore에 추가해도 해당 파일에는 아무 영향도 미치지 않습니다. 무시 규칙은 Git이 아직 추가하지 않은 파일에만 적용됩니다. 실수로 스며들어온 파일 추적을 중지하려면 git rm --cached <file>을 실행하고 해당 변경을 커밋합니다.
Juno추적된 후 파일을 .gitignore에 추가하기.gitignore는 추적되지 않은 파일에만 영향을 미칩니다. 이미 커밋된 항목의 경우, git rm --cached <file>로 제거하거나, 전체 디렉터리의 경우 git rm -r --cached <folder>로 제거한 다음 커밋합니다. 모든 사람의 로컬 파일은 그대로 있고, Git의 추적만 변경됩니다.
Juno추적된 후 파일을 .gitignore에 추가하기 인덱스는 추적된 모든 파일에 대한 항목을 보유하며, .gitignore는 아직 항목이 없을 때만 참조됩니다. git rm --cached는 디스크의 파일을 건드리지 않고 인덱스 항목을 삭제하므로, 여기서 실제 해결책입니다. 파일이 다시 들어오지 않도록 좋은 조치로 무시 패턴을 추가합니다.

좋은 습관: 작은 커밋과 깔끔한 저장소

깔끔한 .gitignore는 저장소를 가치 있게 만드는 한 가지 절반입니다. 다른 절반은 커밋을 형성하는 방법입니다. 각 커밋을 하나의 집중된 변경으로 만드세요. 버그 수정, 작은 기능 하나, 단일 리팩터링입니다. 오후의 작업이 여러 관련 없는 항목에 닿으면, 하루 끝에 모두 한 번에 떨어뜨리는 대신 여러 커밋으로 나눕니다.

bash
$ git add src/weather-widget.js
$ git commit -m "Fix temperature rounding in weather widget"

작은 커밋은 검토하기 더 쉽고, 문제가 발생하면 되돌리기 더 쉽고, 6개월 후에 코드 줄이 왜 존재하는지 기억하려고 할 때 다시 읽기 더 쉽습니다. 커밋 루프는 커밋 메시지를 유용하게 만드는 것을 다룹니다. 이 습관은 변경 자체를 좋은 메시지를 쓸 수 있을 정도로 충분히 작게 유지하는 것에 관한 것입니다.

그 습관을 깔끔한 .gitignore와 결합하면 이득이 복합됩니다. 작고 목적 있는 커밋으로 만들어진 히스토리이며, 생성된 폴더나 추가 구성 파일이 diff를 어지럽히지 않습니다. 누군가 편집한 두 실제 줄 외에 dist/ 변동으로 가득 찬 변경을 검토하는 것은 관련된 모든 사람에게 불쾌하며, 첫째 날부터 .gitignore가 설정되어 있으면 완전히 피할 수 있습니다.

규모에서 이것은 가독성 이상의 방식으로 보상합니다. 생성된 파일과 의존성 폴더가 없는 저장소는 빠르게 클론하고 깔끔하게 검색할 수 있을 정도로 충분히 작게 유지되며, 집중된 커밋의 히스토리는 git log --oneline을 만들고 시간 사이에 git diff를 만들어 실제로 유용하도록 합니다. 무슨 일이 일어났고 왜 일어났는지 이해할 수 있습니다. 커밋의 절반이 node_modules/ 변동이고 다른 절반이 다섯 개의 관련 없는 변경을 혼합한 히스토리에 대해서는 그 중 어느 것도 잘 작동하지 않습니다.

Juno좋은 습관: 작은 커밋과 깔끔한 저장소 각 커밋을 하나의 집중된 변경으로 유지하고, .gitignore를 추적하지 않아야 할 폴더와 비밀로 커버하세요. 이 두 가지 습관이 저장소를 즐거워하는 것의 대부분입니다. 초기에 형성된 작은 습관은 나중에 많은 정리를 절약합니다.
Juno좋은 습관: 작은 커밋과 깔끔한 저장소 작고 집중된 커밋과 깔끔한 .gitignore는 검토와 diff를 생성된 노이즈에 묻히는 대신 실제로 가독성 있게 만듭니다. 첫 커밋 전에 .gitignore를 설정합니다. 다섯 번째 풀 요청에서 node_modules/가 표시될 때까지 기다리는 것은 절약하는 것보다 더 많은 정리 비용이 듭니다.
Juno좋은 습관: 작은 커밋과 깔끔한 저장소 간결한 저장소와 집중된 커밋의 히스토리는 클론을 빠르게 유지하고 히스토리를 통해 들어갈 때 히스토리를 읽을 수 있게 유지하는 것입니다. 히스토리로 들어가는 생성된 파일이나 의존성 폴더는 모든 향후 클론과 검색이 작은 세금을 내게 합니다. 무시 규칙을 미리 설정하면 다시 생각할 가치가 있는 문제가 됩니다.