본문 바로가기
빌드노트 검색

빌드노트

하위 폴더에서 git ls-files가 비면 경로 기준을 확인한다

저장소 루트에서 복사한 경로를 하위 폴더의 git ls-files나 diff에 주면 결과가 빌 수 있다. 현재 위치 기준 경로와 :(top)의 차이를 실제 출력으로 비교하고, --와 --full-name이 경로 선택 기준을 고쳐 주지 않는 이유를 설명한다.

저장소 루트에서 복사한 docs/guide.txt를 하위 폴더의 git ls-files나 git diff에 넘겼는데 아무것도 나오지 않을 수 있다. 이 두 명령에 주는 일반 경로는 현재 디렉터리를 기준으로 해석된다. 루트 기준 경로를 그대로 쓰려면 ':(top)docs/guide.txt'처럼 앞에 :(top)을 붙인다.

Git은 조회할 경로를 고르는 입력을 pathspec이라고 부른다. 공식 문서의 top magic은 명령을 하위 폴더에서 실행하더라도 작업 트리의 루트에서 패턴을 찾게 한다. 여기서 루트는 디스크의 루트가 아니라 현재 Git 저장소 작업 트리의 최상위 디렉터리다. pathspec과 top의 공식 설명 (새 탭에서 열림)

docs 폴더 안에서는 경로가 한 단계 어긋난다

자기 저장소에서 먼저 현재 Git 저장소와 그 안의 위치를 확인한다. 아래 명령은 Git이 설치된 PowerShell 7에서 실행한다.

git rev-parse --show-toplevel
git rev-parse --show-prefix

첫 명령은 저장소 루트의 절대 경로를 보여 준다. 의도한 저장소인지 확인한다. 둘째 명령은 현재 위치를 루트 기준으로 보여 준다. 루트에서 실행하면 빈 줄이고, docs 폴더 안에서는 docs/였다. 명령이 오류를 내면 그 오류부터 확인한다. rev-parse의 위치 조회 옵션 (새 탭에서 열림)

이번 비교에는 새 독립 저장소의 추적 파일 docs/guide.txt 하나를 사용했다. 루트에서 git ls-files -- docs/guide.txt를 실행하면 docs/guide.txt가 나왔다. 그 파일을 그대로 두고 현재 위치만 docs로 바꾼 뒤 세 입력을 비교했다. 자기 파일에 적용할 때는 예제 이름을 실제 경로로 바꾼다.

git ls-files -- docs/guide.txt
git ls-files -- guide.txt
git ls-files -- ':(top)docs/guide.txt'

첫 명령은 출력이 없었다. 둘째와 셋째 명령에서 각각 한 줄씩 나왔다.

guide.txt
guide.txt

현재 위치가 docs이므로 첫 입력은 루트 기준으로 docs/docs/guide.txt를 찾는 셈이다. 이 예제에는 그 경로가 없다. guide.txt는 현재 폴더의 파일을 가리키고, :(top)docs/guide.txt는 루트에서부터 같은 파일을 가리킨다. 세 명령 모두 종료 코드는 0이었다. 빈 출력만으로 추적 파일이 없다고 판단할 수 없는 이유다.

여기서 --는 경로 기준을 루트로 바꾸지 않는다. ls-files 문서에서 설명하는 역할은 이후 인자를 옵션으로 해석하지 않게 하는 것이다. 실제로 하위 폴더의 git ls-files docs/guide.txt와 git ls-files -- docs/guide.txt는 모두 비었다. --는 그대로 두고, 경로를 현재 위치에 맞추거나 :(top)을 붙여야 한다. ls-files의 -- 설명 (새 탭에서 열림)

diff에서도 파일을 고르는 기준은 같다

변경이 있는 파일로도 같은 차이를 확인했다. 예제 파일의 guide-v1을 인덱스에 추가한 뒤 작업 파일만 guide-v2로 수정했다. 수정 후에는 다시 추가하지 않았다. 일반 git diff가 인덱스와 작업 파일의 차이를 보여 줄 조건이다. git diff의 비교 대상 (새 탭에서 열림)

루트에서는 git diff --name-only -- docs/guide.txt에 docs/guide.txt가 나왔다. 같은 변경을 둔 채 docs 안에서 다음 명령을 실행했다.

git diff --name-only -- docs/guide.txt
git diff --name-only -- guide.txt
git diff --name-only -- ':(top)docs/guide.txt'

첫 명령은 다시 비었고, 나머지 두 명령의 출력은 각각 다음 한 줄이었다.

docs/guide.txt

루트에서 일반 경로로 읽은 전체 diff와 하위 폴더에서 :(top)으로 읽은 전체 diff도 같았다. 두 출력 모두 -guide-v1, +guide-v2를 담고 있었다. 파일 내용이나 스테이징 상태를 바꾸지 않고 조회 입력만 고쳐서 변경을 찾았다.

이때 ls-files는 guide.txt, 기본 diff --name-only는 docs/guide.txt를 출력했다. 이 비교에서는 diff의 상대 경로 출력 설정을 사용하지 않았다. 화면에 표시하는 경로와 입력 경로를 해석하는 기준은 구별해야 한다. diff 출력에서 루트 기준 경로를 복사했다고 해서, 하위 폴더의 다음 명령도 그 경로를 루트 기준으로 받는 것은 아니다.

--full-name은 출력 경로를 바꾼다

ls-files의 출력도 루트 기준으로 통일하고 싶다면 --full-name을 사용한다. docs 안에서 다음 두 명령을 비교했다.

git ls-files --full-name -- ':(top)docs/guide.txt'
git ls-files --full-name -- docs/guide.txt

첫 명령은 docs/guide.txt를 출력했고 둘째는 비었다. :(top)은 입력에서 찾을 기준을, --full-name은 찾은 경로를 출력하는 방식을 정한다. --full-name만 붙여서는 잘못된 입력 경로가 고쳐지지 않는다. ls-files의 --full-name 설명 (새 탭에서 열림)

현재 폴더에서 보이는 파일을 조회하려면 그 위치에 맞는 상대 경로를 쓴다. 저장소 루트 기준으로 받은 경로를 유지하려면 :(top)을 붙인다. 경로를 고친 뒤에도 ls-files가 비면 첫 조회의 저장소 루트와 인덱스에 추적된 정확한 경로를 다시 확인한다. 기본 ls-files는 인덱스의 추적 파일을 조회한다. ls-files의 기본 조회 범위 (새 탭에서 열림)

ls-files에는 나오지만 일반 diff가 빈 경우에는 변경이 없거나 이미 스테이징됐는지도 구별해야 한다. :(top)은 비교할 두 상태를 바꾸지 않는다. 직접 실행한 환경은 Windows의 Git 2.45.1.windows.1, PowerShell 7.6.6이며, 일반 텍스트 파일의 인덱스와 미스테이징 변경을 비교했다. 서브모듈·bare 저장소·와일드카드 패턴에서의 동작은 이번에 시험하지 않았다.

← 전체 글 보기