요약. Git Bash 에서 ln -s 를 실행했는데 링크가 아니라 파일 복사본이 생긴 적이 있으실 겁니다. 리눅스에서 잘 쓰던 dotfiles 를 Windows 로 가져왔더니 링크가 전부 텍스트 파일로 바뀌어 있는 경우도 같은 원인입니다. 설정 네 곳을 맞추면 해결됩니다. 이 글은 그 네 단계와, 설정을 빠뜨렸을 때 나타나는 증상을 다룹니다.
심볼릭 링크는 대상 경로를 적어 둔 이정표입니다
심볼릭 링크는 파일의 사본이 아니라 "실제 파일은 저기에 있다" 는 경로 문자열을 담은 특수 파일입니다. 원본을 한 곳에만 두고 여러 위치에서 같은 파일처럼 참조할 때 씁니다. 원본을 고치면 링크로 접근한 쪽에도 즉시 반영됩니다.
Git 도 심볼릭 링크를 그대로 저장합니다. 일반 파일이 100644 모드로 기록되는 것과 달리 링크는 120000 모드로 들어가고, 내용은 대상 경로 문자열 하나입니다.
$ git ls-files -s
120000 c9c61fe1fb4b3b... 0 alias.txt
100644 10622902e19e73... 0 real.txt
문제는 Windows 쪽입니다. Windows 에도 심볼릭 링크가 있지만 생성하려면 SeCreateSymbolicLinkPrivilege 권한이 필요하고, 이 권한은 기본적으로 관리자에게만 부여됩니다. 아래 설정들은 전부 이 제약을 우회하기 위한 것입니다.
네 단계를 모두 맞춰야 링크가 만들어집니다
- Git 설치 시, 맨 마지막 화면에서
Enable symbolic links를 체크합니다. - Git Bash 를 관리자 권한으로 실행합니다.
export MSYS=winsymlinks:nativestrict를 셸 환경에 넣습니다.~/.gitconfig의[core]에symlinks = true를 추가합니다.
3번과 4번은 명령 두 줄로 끝납니다.
echo 'export MSYS=winsymlinks:nativestrict' >> ~/.bashrc
git config --global core.symlinks true
MSYS 변수가 핵심입니다. 기본값은 deepcopy 라서 링크를 만들지 못하면 조용히 파일을 복사합니다. nativestrict 는 네이티브 링크만 만들고, 권한이 없으면 오류를 냅니다. 실패를 감추지 않기 때문에 원인을 바로 알 수 있습니다. 새 터미널을 연 뒤 아래처럼 확인합니다.
$ ln -s real.txt alias.txt
$ ls -l alias.txt
lrwxrwxrwx 1 dualk 197609 8 8월 27 16:59 alias.txt -> real.txt
맨 앞 글자가 l 이고 화살표가 보이면 성공입니다. -rw-r--r-- 로 나오면 복사본입니다.
바로가기 대신 원본 exe 속성을 바꿉니다
매번 우클릭해서 관리자로 실행하는 것은 번거롭습니다. Git Bash 바로가기를 따라가 원래 실행 파일을 찾은 뒤, 그 파일에 상시 관리자 권한을 걸어 둡니다.
- Git Bash 바로가기에서 원본
.exe를 추적한 뒤 우클릭하고속성을 선택합니다. 호환성탭에서관리자 권한으로 실행을 체크합니다.
관리자 권한 셸을 상시 띄우는 것이 부담스럽다면 대안이 있습니다. Windows 10 Creators Update(1703) 부터는 개발자 모드를 켜면 일반 사용자 계정도 심볼릭 링크를 만들 수 있습니다. 설정 > 개인 정보 및 보안 > 개발자용 에서 켠 뒤 재부팅하면 3번 항목만으로 동작합니다.
설정이 빠지면 링크가 조용히 텍스트 파일이 됩니다
가장 곤란한 상황은 오류가 나지 않는 경우입니다. core.symlinks 가 꺼진 상태로 저장소를 클론하면, 링크 자리에 경로 문자열이 내용인 일반 파일이 놓입니다.
| 상태 | ls -l 앞부분 | cat alias.txt 결과 |
|---|---|---|
| 정상 링크 | lrwxrwxrwx ... -> real.txt | 원본 파일의 내용 |
| 깨진 링크 | -rw-r--r-- (8바이트) | real.txt (경로 문자열) |
더 나쁜 점은 git status 가 깨끗하게 나온다는 것입니다. Git 은 이것을 변경으로 보지 않기 때문에 그대로 커밋되어도 알아채기 어렵습니다. 그리고 클론 시점의 core.symlinks=false 값은 그 저장소의 .git/config 에 박제됩니다. 나중에 전역 설정을 켜도 로컬 설정이 우선하므로 그 저장소만 계속 깨진 상태로 남습니다.
git config --local --get core.symlinks # false 가 나오면 이것이 원인입니다
git config --local --unset core.symlinks # 로컬 설정을 지웁니다
git checkout -- . # 작업 트리를 다시 펼칩니다
정리
심볼릭 링크는 대상 경로를 담은 파일이고, Windows 에서는 생성에 별도 권한이 필요합니다. 설치 옵션, 관리자 권한, MSYS=winsymlinks:nativestrict, core.symlinks=true 네 가지가 모두 맞아야 합니다. 하나라도 빠지면 오류 대신 복사본이 생기고 git status 도 조용합니다.
지금 Git Bash 를 열어 echo $MSYS 와 git config --get core.symlinks 를 실행해 보시기 바랍니다. 두 값이 비어 있다면 위 두 줄부터 실행하면 됩니다.
