Watch at Ease세상을 읽고, 일상의 답을 찾다.

기술 · 실용 가이드

Git 하위 모듈 경로에 URL이 없나요? 삭제 전에 gitlink와 .gitmodules 확인

실패한 커밋, 현재 인덱스, 버전 관리된 매핑, 로컬 체크아웃을 비교한 뒤 복구·동기화·deinit·저장소 제거를 선택하세요.

원본 일러스트: 선택한 커밋의 gitlink·매핑과 현재 인덱스·로컬 체크아웃을 비교합니다. 디스크 파일만으로 커밋된 스냅샷이 수정되지는 않습니다.
원본 일러스트: 선택한 커밋의 gitlink·매핑과 현재 인덱스·로컬 체크아웃을 비교합니다. 디스크 파일만으로 커밋된 스냅샷이 수정되지는 않습니다. Watch at Ease

“No url found for submodule path”가 나오면 Git 메타데이터를 삭제하기 전에 경로와 URL의 매핑을 확인해야 합니다. 하위 커밋을 기록하는 gitlink와 .gitmodules 설정은 별개의 상태입니다. 현재 인덱스, 디스크의 작업 파일, 실패한 커밋은 서로 다를 수 있습니다.

원래 오류, 실패한 상위 저장소 커밋, 경로와 로컬 작업을 보존하세요. 커밋된 gitlink와 매핑을 확인하고 로컬 설정을 살핀 뒤 저장소가 의도한 작업을 선택합니다. 아래의 격리된 Git 2.51.1 실험은 디스크 파일이 올바르다고 실패한 커밋까지 수정된 것은 아님을 보여줍니다.

실패한 커밋과 현재 인덱스를 따로 입증

오류 전문을 저장하고 실패한 체크아웃 또는 CI가 실제 사용한 상위 커밋을 확인하세요. 상위 저장소 루트에서 작업하고 쓰기 전에 커밋되지 않은 작업을 보존합니다. git ls-files --stage -- path/to/item으로 현재 인덱스를 확인하세요. 모드 160000은 gitlink와 객체 ID를 나타냅니다. 중첩된 .git 디렉터리만으로 하위 모듈을 판단하지 마세요.

다음으로 git ls-tree --full-tree COMMIT -- path/to/item을 실행하되 COMMIT을 확인한 실패 커밋 ID로 바꿉니다. 이 명령은 현재 인덱스가 같다고 가정하지 않고 지정된 커밋 트리를 읽습니다. 그곳에 gitlink가 없다면 다른 체크아웃, 중첩된 상위 저장소, 스테이징된 변경 또는 오류에 나온 경로부터 조사한 뒤 매핑 복구를 적용하세요.

같은 커밋에서 매핑 읽기

git show COMMIT:.gitmodules로 실패한 커밋의 버전 관리 파일을 확인합니다. 파일이 없다는 사실도 증거이므로 다른 브랜치 파일을 몰래 대신 사용하면 안 됩니다. 대소문자까지 gitlink와 정확히 맞는 path 절을 찾으세요. Git은 고유한 루트 상대 경로, 끝 슬래시 없음, URL을 요구합니다. 절 이름이 경로와 같을 필요는 없습니다.

현재 작업 파일은 호환되는 git config -f .gitmodules --get-regexp '^submodule\..*\.(path|url)$'로 살필 수 있습니다. 정규식을 따옴표로 감싸 셸이 |를 파이프로 해석하지 않게 하세요. 커밋의 파일과 비교합니다. 디스크에 커밋하지 않은 파일만 복원해도 실패한 커밋을 깨끗하게 체크아웃할 때 받는 내용은 바뀌지 않습니다.

로컬 설정을 분리하고 의도한 URL만 동기화

git config --local --get-regexp '^submodule\..*\.(url|active)$'로 초기화된 로컬 설정을 별도로 확인합니다. 키는 하위 모듈 이름을 사용하므로 .gitmodules의 path와 연결해야 합니다. 초기화는 버전 관리된 템플릿에서 설정을 채울 수 있지만 이후 로컬 재정의는 다를 수 있습니다. deinit된 모듈은 기록된 정의를 남기고 체크아웃 파일만 없을 수 있습니다.

저장소가 기존 URL을 의도적으로 바꿨다면 승인된 원격 주소를 확인하고 .gitmodules를 수정한 뒤, 대상 초기화 모듈에 git submodule sync --recursive -- path/to/item을 실행합니다. update 전에 실제 URL을 확인하세요. sync는 등록된 URL 설정을 맞출 뿐 누락 매핑 복구, 기록된 하위 커밋 변경, 비공개 원격 접근 승인을 하지 않습니다.

유지·로컬 제거·저장소 제거를 구별

모듈을 유지하려면 정확한 경로와 승인된 URL을 복원하고 매핑을 스테이징한 뒤 차이를 검토해 의도한 수정 커밋을 만듭니다. 이후 초기화·업데이트하고 그 커밋의 깨끗한 체크아웃으로 검증하세요. URL만 변경한다면 하위 커밋 변경도 의도한 경우가 아닌 한 gitlink를 유지하며 영향을 받는 초기화된 체크아웃을 동기화합니다.

로컬 체크아웃만 없애려면 작업을 보존한 뒤 git submodule deinit -- path/to/item을 사용하고 변경을 버리는 --force를 추가하지 마세요. 버전 관리에서 제거하려면 git rm -- path/to/item 후 gitlink 삭제와 .gitmodules 절 변경을 검토해 커밋합니다. 결과가 다른 작업입니다. git rm --cached는 인덱스만 다루며 일반 git rm과 같은 자동 매핑 정리를 하지 않습니다.

캐시를 의심하기 전에 새 클론으로 검증

격리된 Git 2.51.1 저장소에서 매핑 없는 gitlink를 커밋하자 새 로컬 클론에서 같은 fatal 오류가 재현됐습니다. 인덱스와 커밋 트리 모두 160000을 표시했습니다. .gitmodules를 디스크에만 되돌리자 작업 파일 검사는 통과했지만 실패 커밋의 git show는 계속 실패했습니다. 복원한 매핑을 커밋한 뒤 새 로컬 클론 초기화가 성공했고, 이후 deinit해도 커밋된 gitlink와 매핑은 그대로였습니다.

실험은 로컬 하위 저장소만 사용했으며 해당 실험 명령마다 file 전송을 허용했습니다. 실제 CI, 네트워크 또는 비공개 권한을 재현하지 않았으며 이 전송 재정의는 운영 복구책이 아닙니다. 커밋된 메타데이터가 올바른 뒤에만 폐기 가능한 체크아웃의 오래된 상태를 의심하세요. 로그와 작업을 보존하고 필요할 때 폐기 가능한 체크아웃만 다시 만들며 실패·수정 커밋과 새 클론 결과를 기록합니다. .git/modules, 중첩 .git 데이터, 개발자 작업 트리부터 삭제하지 마세요.

원본 일러스트: 모듈 유지, URL 변경, 로컬 deinit, 저장소 제거는 서로 다른 상태 변경입니다. 작업을 보존하고 수정 커밋을 새로 체크아웃해 검증하세요.
원본 일러스트: 모듈 유지, URL 변경, 로컬 deinit, 저장소 제거는 서로 다른 상태 변경입니다. 작업을 보존하고 수정 커밋을 새로 체크아웃해 검증하세요. Watch at Ease