OMC 심볼릭 링크 스킬을 깃이그노어로 관리하도록 정리
목차
심볼릭 링크를 git에서 어떻게 다룰 것인지, 생각보다 선택지가 몇 가지 있다. 그냥 트래킹해도 되고, ignore 처리해도 되고, 아예 링크 대신 복사본을 repo에 두는 방법도 있다. OMC 쪽 스킬 디렉토리가 심볼릭 링크로 구성돼 있었는데, 이 상태로 계속 가면 환경마다 링크가 끊기거나 경로가 달라지는 문제가 생길 수 있어서 이번에 gitignore 쪽으로 깔끔하게 정리했다.
심볼릭 링크와 git이 만날 때 생기는 문제
git은 심볼릭 링크를 "파일 내용이 링크 경로인 특수 파일"로 취급한다. git status를 찍어보면 symlink -> /some/absolute/path 식으로 나오고, 커밋에도 그대로 들어간다. 문제는 링크 타겟이 절대 경로인 경우다. 로컬에서 /Users/me/shared/skills/deploy.sh로 잘 붙던 게 CI 서버나 다른 개발자 환경에선 그 경로가 없어서 dead link가 된다. 체크아웃 직후 스크립트 실행이 안 된다는 연락이 오는 건 시간문제.
OMC 스킬 파일들이 딱 이 케이스였다. 공유 스크립트 디렉토리를 각 환경마다 다른 위치에 두고, 거기서 심볼릭 링크를 만들어 프로젝트 내에서 쓰는 구조. 링크를 그대로 repo에 올리면 다른 환경에서 체크아웃했을 때 깨진 링크가 들어온다. 그렇다고 스크립트 본체를 repo에 복사해 넣으면 소스가 두 벌이 되고, 한 쪽 수정할 때 다른 쪽을 빠뜨리는 실수가 나온다.
해결책이 몇 가지 있었다.
- 심볼릭 링크를 gitignore 처리하고, 환경 설정 스크립트에서 링크를 생성
- 링크 대신 상대 경로로 스크립트 직접 추가
- git submodule로 공유 스킬 디렉토리를 별도 관리
결국 gitignore + setup 스크립트 방식을 골랐다. 환경 초기화 스크립트를 이미 관리하고 있었고, 링크 생성 로직을 거기 넣는 게 제일 자연스러웠음. submodule은 관리 오버헤드가 있고, 공유 디렉토리 자체가 별도 repo로 관리되고 있는 상황이 아니었다.
실제 처리 방식
.gitignore에 스킬 파일들을 명시하는 건 간단하다.
# OMC skill symlinks - env-specific, created by setup.sh
skills/
*.skill.sh
여기서 끝내면 "이 파일들 어디서 나와요?" 질문이 반드시 생긴다. gitignore만 있고 생성 방법이 없으면 나중에 환경 세팅하는 사람이 막힌다. 그래서 setup 스크립트에 링크 생성 부분을 정리해 넣었다.
#!/bin/bash
# setup.sh - OMC 환경 초기 세팅
SKILL_SRC="${OMC_SKILL_DIR:-/opt/shared/omc-skills}"
SKILL_DST="$(pwd)/skills"
if [ ! -d "$SKILL_SRC" ]; then
echo "[ERROR] 스킬 소스 디렉토리를 찾을 수 없음: $SKILL_SRC"
echo " OMC_SKILL_DIR 환경변수를 확인하거나 /opt/shared/omc-skills 를 확인하세요."
exit 1
fi
mkdir -p "$SKILL_DST"
for skill_file in "$SKILL_SRC"/*.sh; do
[ -f "$skill_file" ] || continue
skill_name="$(basename "$skill_file")"
ln -sf "$skill_file" "$SKILL_DST/$skill_name"
echo " linked: $skill_name"
done
echo "Done. Skills linked from $SKILL_SRC"
-sf 옵션으로 기존 링크가 있어도 덮어쓰게 했다. 환경변수 OMC_SKILL_DIR가 없으면 /opt/shared/omc-skills가 기본값. 소스 디렉토리 자체가 없으면 에러 메시지와 함께 exit 1 내고, 어디를 확인해야 하는지 출력하도록 했다. 새벽에 누군가 이 스크립트를 돌릴 때 그냥 조용히 실패하는 것보다 낫다.
이 구조의 트레이드오프
gitignore + setup.sh 방식과 링크를 직접 커밋하는 방식의 차이를 정리하면 이렇다.
| 구분 | gitignore + setup.sh | 링크 직접 커밋 |
|---|---|---|
| 체크아웃 후 실행 | setup.sh 한 번 실행 필요 | 링크 타겟 경로가 맞으면 바로 가능 |
| 환경별 경로 차이 | 환경변수로 유연하게 처리 | 절대 경로 하드코딩 위험 |
| 링크 깨짐 복구 | setup.sh 재실행으로 해결 | git이 깨진 링크를 정상으로 인식 |
| 신규 스킬 추가 | 소스 디렉토리에 추가하면 자동 반영 | repo에도 링크 추가 필요 |
| 온보딩 복잡도 | setup.sh 실행 단계 추가됨 | 별도 작업 없음 |
링크를 직접 커밋하는 방식이 맞을 때도 있다. 링크 타겟이 repo 내부 상대 경로거나, 팀 전체가 동일한 환경 구성을 쓴다면 그쪽이 더 단순하다. 이번 케이스는 공유 스크립트 디렉토리 위치가 환경마다 달랐기 때문에 gitignore 방식이 맞았음.
주의할 점은, setup.sh 실행을 강제할 방법이 없다는 것. README에 명시하고, .env.example에 OMC_SKILL_DIR 항목도 추가해서 "이런 환경변수가 있다"는 걸 눈에 띄게 해뒀다. Makefile이 있는 프로젝트라면 make setup 타겟에 링크 생성을 넣어두는 것도 좋은 방법이다.
작업 회고
diff만 보면 거의 없는 작업이다. .gitignore 몇 줄, setup.sh 수정, .env.example 항목 추가가 전부. 코드 리뷰에서 "이게 다예요?" 소리 들을 법한 PR이기도 하다.
근데 이런 정리가 나중에 신규 합류자나 서버 이전 작업할 때 체감이 갈린다. gitignore 처리 없이 깨진 심볼릭 링크가 repo에 그대로 있으면, 체크아웃한 사람이 스크립트 실행 안 된다고 하고, 원인 파악하는 데 시간 쓰고, 결국 "원래 이런 거 아닌가요?" 물어보러 오는 루프가 생긴다. 처음 마주치는 사람 입장에선 링크가 왜 깨져있는지, 어디서 만들어지는 건지 알 방법이 없다.
이번 작업을 하면서 다시 생각한 건, 파일이 어디서 왔고 어떻게 만들어지는지를 코드로 표현해두는 것. 주석도 좋고, setup 스크립트도 좋고, .env.example도 좋다. 중요한 건 "나는 알고 있다"가 아니라 "코드 보면 알 수 있다"인가 여부다.
코드를 읽는 주체를 항상 세 가지 관점으로 생각하게 된다.
- 6개월 후의 나: 이 구조를 왜 이렇게 했는지 읽으면 나오는가
- 처음 보는 팀원: 질문 없이 환경 세팅이 가능한가
- 새벽 장애 상황: 슬랙 뒤지거나 사람 깨우지 않고 setup.sh만 보면 복구 경로가 보이는가
세 질문 다 "그렇다"가 나오면 충분하다고 본다. 이번 작업은 그 기준으로 정리했고, 당장 눈에 안 띄는 작업이 나중에 조용히 시간을 아껴준다는 걸 다시 확인했다.
댓글 0
첫 댓글 달아줘.