매3개 | Git 저장소의 구조와 흐름 & 파일 상태 변화

🌿 Git?

Git은 분산 버전 관리 시스템으로, 개발자가 코드를 효율적으로 관리하고 협업할 수 있도록 돕는다. 이런 Git 저장소는 총 4가지로 작업 디렉터리, 스테이징 영역, 지역 저장소, 원격 저장소가 있다.

이 중에서 주요 영역은 작업 디렉터리, 스테이징 영역, 지역 저장소 3가지로 Git의 데이터 흐름을 파악하기 위해 꼭 알아야 한다. 이 3가지 영역은 Git의 주요 데이터 관리 구조로 Git이 추적(관리)하는 파일과 추적하지 않는 파일을 구분하고, 추적하는 파일들의 상태를 구분짓는다.

일단 Git의 데이터 흐름을 알아보기 전에 Git의 저장소 4가지가 어떤 역할을 하는지 알아보자.

🗄️ Git 저장소의 구조

1. 작업 디렉터리(Working Directory)

작업 디렉터리(Working Directory)는 작업 중인 파일들이 실제로 있는 공간으로, 사용자가 직접 수정하고 편집하는 파일이 위치한다.

git init 명령어를 통해 현재 디렉터리(컴퓨터에서 작업 중인 폴더)를 Git 저장소로 초기화한다. 초기화가 완료되면 Git은 변경된 파일을 추적하기 시작한다.

작업 디렉터리는 Working Tree라고도 부르는데, 이 두 가지 용어는 동일한 의미로 사용된다. Git 공식 문서에서도 두 용어가 같은 의미로 사용되며 혼용된다.

working tree Git 공식문서 설명

working tree Git 공식문서 설명

이는 Git의 상태를 트래킹하고 파일 시스템의 특정 상태를 나타내는데 있어서 같은 역할을 하기 때문이다. 따라서, 작업 디렉터리와 작업 트리 모두 “사용자가 직접 편집하는 파일들이 위치한 영역”을 지칭한다.

Image

작업 내용이 없을 경우 git status 명령을 했을 때 띄워지는 문구

2. 스테이징 영역(Staging Area)

스테이징 영역은 커밋(commit)하기 전에 변경된 파일을 임시로 저장하는 공간이다.

git add 명령어를 사용하여 작업 디렉터리에서 변경된 파일을 스테이징 영역으로 추가할 수 있다. 이를 통해 커밋 시 어떤 변경 사항이 포함될지 선택적으로 관리할 수 있다.

3. 지역 저장소(Local Repository)

지역 저장소는 사용자의 컴퓨터에 위치하며, 모든 버전 히스토리를 저장한다.

git commit 명령어를 통해 스테이징 영역에 있는 변경 사항을 지역 저장소에 기록한다. 지역 저장소는 .git 디렉터리로 관리되며, 버전 기록을 안전하게 보관한다.

4. 원격 저장소(Remote Repository)

원격 저장소는 GitHub, GitLab과 같은 플랫폼에서 호스팅되며, 협업을 위해 사용된다.

git push 명령어를 사용하여 지역 저장소의 데이터를 원격 저장소로 업로드할 수 있다. 반대로, 원격 저장소에 있는 최신 데이터를 지역 저장소로 가져오려면 git pull 명령어를 사용한다. 새로운 저장소를 처음 복제할 때는 git clone 명령어를 사용하여 원격 저장소의 내용을 지역 저장소로 복사한다.

쉽게 기억하기

  • 작업 디렉토리: 내가 실제로 일하는 공간.
  • 스테이징 영역: 커밋하기 전에 임시로 저장하는 곳.
  • 지역 저장소: 내 작업을 안전하게 저장하는 곳.
  • 원격 저장소: 협업 및 백업을 하기 위해 작업을 저장하는 곳.

🌊 Git의 데이터 흐름

Git 저장소에 대해 설명하면서 Git의 데이터 흐름에 대해서도 설명을 했다. 그러나 이렇게 글로 설명해서는 잘 이해되지 않을 것이다. 아래 그림을 보면서 간략하게 Git의 데이터 흐름에 대해서 다시 한번 살펴보자.

git 저장소의 구조와 흐름

  1. git init을 통해 현재 디렉토리를 Git 저장소로 초기화하고 변경된 파일을 추적한다.
  2. 작업 디렉터리에서 코드를 수정하고 변경 사항을 생성한다.
  3. git add 명령어로 변경 사항을 스테이징 영역에 추가한다.
  4. git commit 명령어로 스테이징 영역의 변경 사항을 지역 저장소에 저장한다.
  5. git push 명령어를 사용해 지역 저장소의 변경 사항을 원격 저장소로 전송한다.
  6. 다른 작업자의 변경 사항을 통합하려면 git pull 명령어를 사용한다.

+) 만약 새로운 저장소를 작업 중인 컴퓨터로 복제하고 싶은 경우, git clone 명령어를 사용하여 원격 저장소의 내용을 지역 저장소로 복사한다.

Git의 저장소 구조와 데이터 흐름을 이해했다면, 이제 작업을 진행하며 파일의 상태가 어떻게 변화하는지 알아볼 차례다. 파일의 상태 변화는 Git이 파일을 관리하는 과정을 이해하는 핵심으로, 효율적인 버전 관리를 위해 반드시 알아야 할 개념이다.

🕊️ Git에서의 파일 상태 변화

Git에서 파일의 상태 변화는 파일이 Git에서 어떻게 관리되고 있는지를 보여주는 중요한 요소다. 이 과정은 파일이 작업 디렉터리(Working Directory)와 스테이징 영역(Staging Area) 사이를 이동하며 상태가 변화하는 방식으로 나타난다.

아래 그림을 참고하여 어떻게 파일 상태 변화가 나타나는지 알아보자.

git의 파일 상태 변화

1. Untracked 상태

작업 디렉터리에 새로 추가된 파일은 처음에는 Git에 의해 추적되지 않는 상태인 Untracked로 분류된다. 이 상태는 Git이 파일을 아직 버전 관리에 포함하지 않았음을 의미한다.

untracked file

  • git add 명령어

    git add 명령어를 실행하면 Untracked 상태의 파일이 스테이징 영역에 추가되고, Tracked 상태로 전환된다.

2. Tracked 상태

Tracked 상태는 Git이 해당 파일을 버전 관리하고 있음을 의미한다.

tracked file

Tracked 상태의 파일은 아래 세 가지 하위 상태로 나뉜다.

  • Unmodified: 마지막 커밋 이후 파일에 변경이 없는 상태. git add를 실행하지 않은 상태의 파일이 여기에 해당.
  • Modified: 파일이 수정되었으나 아직 스테이징 영역에 반영되지 않은 상태.
  • Staged: 수정된 파일이 git add 명령어로 스테이징 영역에 추가된 상태.

3. Unmodified → Modified

Tracked 상태의 파일이 수정되면, 파일은 Modified 상태로 변경된다. 이 상태는 파일이 변경되었으나 아직 스테이징 영역에 반영되지 않았음을 나타낸다.

modified file

4. → git add 명령어

수정된 파일에 대해 다시 git add 명령어를 실행하면, 파일은 다시 Staged 상태로 전환된다. Staged 상태의 파일은 이후 커밋(commit) 시 기록된다.

📝 정리

  • 작업 디렉터리 (Working Directory): 실제로 파일을 수정/편집하는 공간
  • 스테이징 영역 (Staging Area): 커밋 전 변경 사항을 임시 저장하는 공간
  • 지역 저장소 (Local Repository): 모든 버전 히스토리를 저장하는 공간
  • 원격 저장소 (Remote Repository): 협업 및 백업용 저장 공간 (GitHub, GitLab 등)
  • Git의 핵심 흐름: 작업 디렉터리 → 스테이징 영역 → 지역 저장소 → 원격 저장소
  • Untracked: Git이 추적하지 않는 새 파일
  • Tracked 상태
    • Unmodified: 마지막 커밋 이후 변경 없음
    • Modified: 파일 수정됨
    • Staged: 수정 파일이 git add로 스테이징 영역에 반영

📚 참고

매3개 | Git: HEAD와 detached HEAD

📩 HEAD?

HEAD는 Git에서 현재 작업 중인 브랜치를 가리키는 포인터이다. 일반적으로 HEAD는 특정 브랜치(예: main, develop)를 가리키며, 해당 브랜치의 마지막 커밋을 기준으로 작업을 진행한다.

💘 detached HEAD?

detached HEAD는 HEAD가 브랜치를 가리키는 대신, 특정 커밋을 직접 가리키는 상태를 말한다. 즉, 브랜치와 연결되지 않은 채 특정 커밋에서 작업을 시작한다.

어떻게 detached HEAD 상태가 될 수 있는지 예시를 통해 알아보자.

dtached HEAD 상태로 만들기

git checkout <commit-hash>

위 명령어를 실행하면 Git은 브랜치를 기준으로 작업하지 않고, <commit-hash>로 지정된 특정 커밋에서 작업을 시작한다. 이제 HEAD는 브랜치가 아닌 특정 커밋을 가리키게 된다.

그렇다면 detached HEAD 상태에서 작업을 하면 어떤 일이 일어나는 걸까?

detached HEAD 상태에서 작업의 특징

1. 임시 상태

새로운 커밋을 생성하면, 이 커밋은 기존 브랜치와 연결되지 않는다. 브랜치로 연결하지 않으면, 이후 Git 작업 중 이 커밋을 잃어버릴 위험이 있다.

2. 기본 브랜치로 돌아가면 변경 사항이 사라질 수 있음

git checkout main

detached HEAD 상태에서 다른 브랜치로 이동하면, 이전에 작업한 내용이 그대로 버려질 수 있다.

git checkout <commit-hash>
echo "Changes" > file.txt
git add file.txt
git commit -m "detached commit"

git checkout main

만약 detached HEAD 상태에서 작업한 내용을 커밋하고 기본 브랜치로 돌아왔다면, 해당 커밋은 보이지 않게 될 수 있지만, 완전히 사라지지는 않는다.

그렇다면 어떻게 detached HEAD에서 작업한 내용을 저장해둘 수 있을까?

detached HEAD 상태에서 작업 보존

detached HEAD 상태에서 작업을 유지하려면 브랜치를 생성하거나 변경 사항을 명시적으로 저장해야 한다.

방법 1: 새로운 브랜치 생성

git checkout -b <new-branch>

detached HEAD 상태에서 브랜치를 생성하면, 해당 브랜치에 현재 상태가 저장된다.

방법 2: stash로 저장

git stash

작업 내용을 stash로 저장한 후, 다시 브랜치로 돌아가서 pop을 통해 복원할 수 있다.

이렇게 detached HEAD에 대해서 알아보았다. 그렇다면 이건 도대체 언제 사용하는 걸까?

detached HEAD 상태가 필요한 경우

  • 특정 커밋 기반으로 새로운 작업을 시작하고 싶을 때
  • 과거 커밋의 상태를 확인하거나 임시로 작업하려 할 때
  • 특정 태그나 커밋을 기반으로 빌드하거나 디버깅하려 할 때

위와 같은 경우에 detached HEAD를 사용하게 된다. 자, 이제 detached HEAD가 뭔지 알아보았으니 어떻게 사용하는지 예시를 통해 알아보자.

예시로 이해하기

  1. 현재 브랜치 상태

    현재 HEAD는 main 브랜치를 가리킨다.

    git checkout main
    
  2. detached HEAD 상태로 전환

    HEAD가 특정 커밋(1234abcd)을 가리키고, main 브랜치와의 연결이 끊긴다.

    git checkout 1234abcd
    
  3. detached HEAD 상태에서 커밋 생성

    이 커밋은 브랜치와 연결되지 않아 나중에 잃어버릴 위험이 있다. 그러나 완전히 사라지는 것은 아니다.

    echo "Test" > file.txt
    git add file.txt
    git commit -m "Detached HEAD commit"
    
  4. 브랜치를 생성하여 커밋 보존

    커밋을 안전하게 새로운 브랜치에 저장할 수 있다.

    git checkout -b <new-branch>
    

여기서 만약? detached HEAD 상태에서 작업한 커밋을 브랜치를 생성하여 바로 저장하지 않고 그냥 기존 브랜치(main)로 변경해버렸다면? 어떻게 다시 detached HEAD 상태에서 작업한 커밋을 찾아서 저장할 수 있을까?

잃어버린 커밋 찾고 저장하기

절차는 다음과 같다.

  1. 잃어버린 커밋 해시 찾기
  2. 해당 커밋 해시를 기반으로 새로운 브랜치 생성

끝이다! 2번 절차는 위에서 이미 알아봤으니 우리는 1번 절차만 어떻게 하는지 알면 된다.

잃어버린 커밋 해시 찾기

git log

or

git reflog

git log 명령을 사용하여 최근 커밋들을 확인하거나, git reflog를 사용해 최근의 모든 작업을 확인할 수 있다.

  • git log의 경우에는 HEAD되어 있는 브랜치에서 작업했던 내용들만 확인할 수 있다.
  • git reflog는 최근에 작업했던 모든 내용들. 즉, 현재 HEAD된 브랜치가 무엇이던 간에 브랜치에 상관없이 작업했던 모든 내용(checkout하거나 commit 하거나 등)들과 hash 값을 확인할 수 있다.

이렇게 잃어버린 커밋의 hash 값을 찾았다면 이 것을 기반으로 새로운 브랜치를 생성하면 된다.

git switch -c <new-branch> <잃어버린 커밋의 hash>

📝 정리

상태 HEAD가 가리키는 위치 브랜치와의 연결 여부
일반 브랜치 상태 특정 브랜치 (main) 연결됨
detached HEAD 상태 특정 커밋 (1234abcd) 연결되지 않음

📚 참고

매3개 | Git: checkout, switch, restore (부제: 원격 브랜치를 로컬에 그대로 생성하기)

때는 행동대장 프로젝트를 진행하면서…
새로운 이슈를 처리하기 위해 원격에서 만들어둔 브랜치를 로컬로 가져오려고 시도했다. 그러나 만들어진 브랜치의 마지막 log를 확인해보니 원격 브랜치의 log와 달랐다! 나는 원격 브랜치를 그대로 로컬로 가져오는 방법을 검색했고.. git의 checkout을 통해 성공할 수 있었다.

도대체 이 checkout이 무엇을 수행하는 명령어이길래 원격 브랜치를 그대로 로컬에 생성할 수 있는지 알아보도록 하자. 그리고 checkout과 유사한 일을 수행하는 switch와 restore은 무엇인지도 같이 알아보자!

✅ checkout?

checkout 명령어는 브랜치 변경, 특정 커밋 체크아웃, 파일 복원 등 여러 작업에 사용된다.

checkout으로 할 수 있는 기능

1. 브랜치 변경

현재 작업 중인 브랜치를 다른 브랜치로 변경하는 데 사용된다.

git checkout <branch-name>
  • 현재 브랜치를 branch-name으로 변경한다.
  • 작업 디렉토리는 변경된 브랜치의 마지막 commit 상태로 업데이트된다.
  • 단, commit 혹은 stash하지 않은 작업이 존재할 경우(즉, working directory에 존재) 다른 브랜치로 변경할 수 없다.

2. 새 브랜치 생성 및 이동

브랜치를 생성하고 바로 이동할 때 사용한다.

git checkout -b <new-branch-name>
  • 새로운 브랜치를 생성하고 해당 브랜치로 이동한다.
  • 만약 원격 브랜치를 추적하는 로컬 브랜치를 생성하고 이동하고 싶을 경우 다음과 같다.

    git checkout -b <new-branch-name> <remote>/<remote-branch-name>
    
    or
    
    git checkout --track <remote>/<remote-branch-name>
    

    예로, origin에 있는 feature1이라는 브랜치를 로컬에 바로 생성하고 이동하고 싶다면 다음과 같다.

    git checkout -b feature1 origin/feature1
    
    or
    
    git checkout --track origin/feature1
    

    origin의 브랜치 이름과 다른 이름을 사용할 수 있다. feature1이 아니라 feat1로 만들고 싶다면

    git checkout -b feat1 origin/feature1
    

3. 특정 커밋 체크아웃

특정 커밋으로 working directory를 업데이트한다.

git checkout <commit-hash>
  • commit-hash로 지정된 커밋의 파일들을 작업 디렉토리에 반영한다.
  • 이 상태는 “detached HEAD” 상태라고 불리며, 이후 작업은 브랜치가 아닌 해당 커밋을 기준으로 진행된다.

4. 파일 복원

특정 파일을 이전 커밋의 상태로 복원한다.

git checkout <branch-name> -- <file-path>
  • <file-path>에 있는 파일을 지정된 브랜치 또는 커밋의 상태로 되돌린다.
  • 이 명령은 주로 잘못된 수정 내용을 되돌릴 때 유용하다.

checkout의 기능이 분리?

Git 2.23 이후, checkout의 일부 기능이 switch(브랜치 변경)와 restore(파일 복원)로 분리되었다. 각각의 명령은 특정 작업에 초점이 맞춰져 있어 더 직관적이고 명확하게 사용할 수 있다. 그렇지만 checkout은 여전히 사용 가능하다.

하지만 기능이 분리되었기 때문에, 이제는 switch와 restore를 사용하는 것을 더 권장한다. (아무래도 checkout은 책임 분리가 덜 된 구조였기 때문인 듯 하다.)

그렇다면 checkout에서 사용하던 기능을 switch와 restore로 어떻게 대체할 수 있는지 알아보자!

🕹️ switch

브랜치를 이동하거나 새로 생성하는 작업에만 사용된다. checkout이 한꺼번에 처리하던 다양한 작업 중 브랜치와 관련된 작업만 분리한 명령이다.

주요 기능

1. 브랜치 전환

현재 작업 중인 브랜치를 <branch-name>으로 변경한다.

git switch <branch-name>

2. 새 브랜치 생성 및 이동

새 브랜치를 생성하고 해당 브랜치로 이동한다.

git switch -c <new-branch-name>
  • 만약 원격 브랜치를 추적하는 로컬 브랜치를 생성하고 이동하고 싶을 경우 다음과 같다.

    git switch -c <new-branch-name> <remote>/<remote-branch-name>
    
    or
    
    git switch --track <remote>/<remote-branch-name>
    

3. 강제 전환

작업 중인 변경 사항을 무시하고 강제로 브랜치를 변경한다.

git switch -f <branch-name>

♻️ restore

특정 파일을 이전 상태로 복원하는 작업에 초점을 맞춘 명령이다. 이는 checkout의 파일 복원 기능을 대체한다.

주요 기능

1. 작업 디렉토리에서 파일 복원

스테이징된 변경 사항이나 working directory의 변경 사항을 마지막 커밋 상태로 되돌린다.

git restore <file-path>

2. 스테이징 영역에서 복원

스테이징 영역(Staging Area)에 있는 파일을 언스테이징한다.

git restore --staged <file-path>

3. 특정 커밋 기준으로 파일 복원

<commit-hash>에 해당하는 커밋 상태로 파일을 복원한다.

git restore --source=<commit-hash> <file-path>

🥊 checkout vs switch & restore

기능 checkout switch restore
브랜치 변경 O O X
새 브랜치 생성 및 이동 git checkout -b <branch> git switch -c <branch> X
파일 복원 git checkout <branch> -- <file-path> X git restore <file-path>
스테이징 영역 복원 git checkout -- <file-path> X git restore --staged <file-path>
특정 커밋 기반 파일 복원 git checkout <commit-hash> -- <file> X git restore --source=<commit-hash>

📝 정리

  • checkout: 브랜치 변경, 특정 커밋 체크아웃, 파일 복원 등 여러 작업에 사용.
  • switch: 브랜치를 전환하거나 생성하는 데만 사용.
  • restore: 파일 복원 및 스테이징 관련 작업에 사용.
  • switchrestore는 Git 2.23 이상에서만 사용할 수 있다. 구버전에서는 checkout을 사용해야 한다.
  • switchrestore를 사용하면 작업의 목적과 의도가 명확히 드러나므로, 사용을 권장한다.

📚 참고

Error | webpack < 5 used to include polyfills for node.js core modules by default

문제 발생 상황

때는, 행동대장 회원 탈퇴 기능 구현에서 google spreadsheets api를 사용하기 위해서 google-auth-library를 활용하여 코드를 작성하던 중.. 이런 어마무시한 에러의 늪에 빠져버렸다.

webpack_v5_error_1

이 에러가 무슨 에러인데?

webpack < 5 used to include polyfills for node.js core modules by default. This is no longer the case. Verify if you need this module and configure a polyfill for it.

위 에러를 해석하면 다음과 같다.

이 에러 메시지는 Webpack 5부터 Node.js의 코어 모듈(예: http, https, fs, 등)에 대한 폴리필(polyfill)이 기본적으로 제공되지 않는다는 것을 의미함.

Webpack 4까지는 브라우저 환경에서도 Node.js 코어 모듈이 동작할 수 있도록 자동으로 폴리필을 포함했다. 그러나 Webpack 5부터는 이를 자동으로 포함하지 않으며, 사용자가 필요한 폴리필을 직접 설정해야 하도록 바뀌었다. 우리 행동대장의 Webpack의 버전은 ^5.93.0… 그렇기에 폴리필을 직접 설정을 해줘야 해당 에러가 해결된다.

근데 폴리필이 뭐예요?

폴리필(Polyfill)은 최신 기술이나 특정 기능이 일부 환경에서 지원되지 않을 때, 그 기능을 대신 구현하여 호환성을 제공하는 코드나 라이브러리를 말한다.
쉽게 말해, 오래된 브라우저나 특정 환경에서도 새로운 기능을 사용할 수 있도록 도와주는 “백업” 코드이다.

그렇다면 폴리필이 왜 필요할까?

JavaScript는 빠르게 진화하지만, 모든 브라우저나 환경이 새로운 기능을 지원하는 것은 아니다.
예를 들어 Array.prototype.includes는 최신 브라우저에서는 지원되지만, 구형 브라우저(ex, IE)에서는 작동하지 않는다. 이 경우, 폴리필을 사용하면 Array.prototype.includes와 동일한 기능을 추가할 수 있다.

Webpack에서 폴리필은 어떻게 설정해야 하죠?

Webpack은 브라우저 환경에서 동작하도록 설계되었지만, 일부 Node.js 기능을 사용할 때 폴리필이 필요하다. 그렇기에 필요한 Node.js 코어 모듈(http, fs 등)을 직접 설치하고 설정해주면 되겠다!

에러 해결

아래 이미지 외에도 많은 폴리필 에러가 발생했다.. 에러 메세지를 확인하면 설치해야 할 라이브러리를 알려주고 있어 설치하라는 라이브러리를 모두 설치하고 설정해주었다.

webpack_v5_error_2

  • 에러 메시지의 라이브러리
    • url
    • crypto-browserify
    • stream-http
    • https-browserify
    • os-browserify
    • stream-browserify
    • path-browserify
    • querystring-es3
    • assert

위 라이브러리를 설치한 후 webpack 파일의 resolve.fallback에 값을 설정해줬다.

또한 추가로 reqire를 사용할 수 있도록 createRequire를 생성했다.

import {createRequire} from 'module';

const require = createRequire(import.meta.url);

export default {
	// ...
  resolve: {
    fallback: {
      url: require.resolve('url'),
      fs: false,
      crypto: require.resolve('crypto-browserify'),
      http: require.resolve('stream-http'),
      https: require.resolve('https-browserify'),
      os: require.resolve('os-browserify/browser'),
      stream: require.resolve('stream-browserify'),
      path: require.resolve('path-browserify'),
      querystring: require.resolve('querystring-es3'),
      assert: require.resolve('assert/'),
    },
  // ...
};

결과

아래 이미지를 통해 폴리필과 관련된 에러가 모두 사라졌음을 확인할 수 있다! (근데 난 다른 에러가 남았지!)

webpack_v5_error_3

참고

Error | Module not found: Can't resolve child_process

에러

폴리필 에러를 해결했지만 아직도 우리에겐 에러가 남았다.. 에러 내용은 다음과 같다.

error_child_process

에러 해석

Module not found: Error: Can't resolve 'child_process' in '/Users/soha/soha/wooteco/2024-haeng-dong/client/node_modules/google-auth-library/build/src/auth’

  1. Module not found: 특정 모듈을 찾지 못하겠다.
  2. Error: Can't resolve 'child_process': Node.js의 내장 모듈인 child_process를 찾을 수 없다는 뜻. 이 모듈은 일반적으로 서버 환경(Node.js)에서 사용되며, 브라우저 환경에서는 사용할 수 없음…..
  3. in '/Users/soha/soha/wooteco/2024-haeng-dong/client/node_modules/google-auth-library/build/src/auth': 에러가 발생한 위치는 google-auth-library 패키지 내부의 코드에서 child_process를 사용하려고 시도한 부분임.

종합하자면?

google-auth-library는 Google API 인증을 위해 사용되는 라이브러리이다. 이 라이브러리는 서버 환경(Node.js)을 위해 설계되었으므로, 브라우저 환경에서 사용하려고 하면 child_process와 같은 Node.js 전용 모듈을 찾지 못해 에러가 발생한다!

결론

너! Node.js에서 실행되어야 하는거 왜 브라우저에서 하셈? 그거 브라우저에서는 실행 못하니 돌아가.