Minter
이민지Cloud Engineer
GitHubadf5858@naver.com포트폴리오 PDF

© 2026 Minter · MINJI LEE

Minter
🏠전체 보기최근 기록 · 연결 지도 · 활동📝학습 기록작업과 공부 과정을 정리한 글📖IT 용어 사전용어와 개념 정리Git 명령어명령어, 옵션, 예시🛠️트러블슈팅문제 상황, 원인, 해결💼커리어 노트취업 준비와 커리어 기록
🧠학습법망각곡선 기반 복습 방식
👋About이민지 · Cloud Engineer📄포트폴리오 PDFv2026.10

Blog

🏠전체 보기최근 기록 · 연결 지도 · 활동📝학습 기록작업과 공부 과정을 정리한 글📖IT 용어 사전용어와 개념 정리Git 명령어명령어, 옵션, 예시🛠️트러블슈팅문제 상황, 원인, 해결💼커리어 노트취업 준비와 커리어 기록🧠학습법망각곡선 기반 복습 방식

Portfolio

👋About이민지 · Cloud Engineer📄포트폴리오 PDFv2026.10
트러블슈팅GitHTTPWeb

GitHub PR 본문의 상대경로 링크가 깨지는 이유

PR 본문의 상대 URL은 저장소 루트가 아닌 현재 PR 페이지 URL을 기준으로 해석되므로, 저장소 파일은 blob 경로를 포함한 절대 URL로 연결해야 한다.

2026년 10월 18일


상황

열심히 취업 지원 트래커를 디벨롭 하던 중....(supabase 스키마 마이그레이션이 필요한 작업이었다)

image.png

https://github.com/Minter-v1/Minters-job-tracker/pull/28

 

그냥 인라인 코드 블록 말고, 링크 네비게이션을 걸고 싶어 마크다운 문법을 적용해서 작성해뒀으나,..

# Markdown 링크 참조 문법 (참고하시라)
[`20261018_add_job_platforms.sql`](docs/supabase/migrations/20261018_add_job_platforms.sql)

 


증상과 에러

image.png

놀랍게도 왜 대체 이 페이지로 리다이렉트 되는가..

심지어 다른 PR 게시글은 Not Found가 뜨시더라는 이말..

 

image.png

개발자도구로 뜯어봤다. 링크 텍스트는 정상적으로 렌더링 되지만, 클릭하면 대상 SQL 파일로 이동하지 않는다.

앵커 태그를 보니 href="/docs/supabase/migrations/<파일명>" 으로 되어있는 것을 확인했다.

 

저 경로는 내가 루트저장소(레포지토리)를 기준으로 작성해둔 경로이다.

하지만, 브라우저는 이 링크를 저장소 루트가 아닌 현재 PR URL 기준으로 해석할 가능성이 있다..

  • 한줄 결론

    GitHub는 PR 본문의 상대경로를 저장소 파일 URL로 변환 안하고 href에 걍 그대로 넣은 것임

 

# 현재 PR 링크 URL
https://github.com/Minter-v1/Minters-job-tracker/pull/28

# PR 본문에 작성한 상대 URL
/docs/supabase/migrations/<파일명>

# 브라우저가 현재 문서 URL을 기준으로 계산하는 URL -> "(PR 링크 URL/상대경로)"의 형태
https://github.com/Minter-v1/Minters-job-tracker/pull/28/docs/supabase/migrations/<파일명>

# 실제 클릭 후 이동된 URL
https://github.com/Minter-v1/Minters-job-tracker/compare/docs/supabase/migrations/20261018_add_job_platforms.sql?expand=1

 

 

주의할 점이 하나 있다.

처음에는 아래처럼 단순히 PR URL 뒤에 상대경로(docs/migrations/~)가 붙을 것이라고 생각했다.

/pull/28/docs/....

 

그런데? 기준 URL인 /pull/28 의 마지막 28은 디렉터리가 아니라 현재 문서의 마지막 경로로 취급된다.

그래서.... 일반적인 상대 URL 해석 결과는 28을 교체한 다음 경로가 될 것이다.

/pull/docs/...

 

 

이후 GitHub 라우터가 유효하지 않은 /pull/docs/... 경로를 처리하면서 /compare/docs/... 혹은 Pull Request 생성 화면으로 리다이렉트한 것으로 볼 수 있다.

 

 


원인

처음 세운 가설을 살펴보자.

  1. Markdown 링크 문법 오류 : 마크다운 문법 정상임(링크 텍스트 렌더링도 잘 되고)
  2. 파일 경로 or 파일명 잘못됨 : 파일 경로도 제대로 있음
  3. 파일이 main 브랜치에 없음 : PR 병합 이후에도 링크가 안되기대문에, 해당 없음
  4. PR 본문에서 상대경로를 해석하는 기준이 저장소 Markdown 파일과 다름

: 이 친구가 실제 원인이다.

 

저장소 안에 있는 README.md 등의 Markdown 파일은 특정 브랜치와 디렉터리 안에서 렌더링 된다.

따라서 그 안에서 작성한 상대경로는 현재 Markdown 파일이 위치한 저장소 경로를 기준으로 다른 파일을 찾아갈 수 있다.

 

반면 PR 본문은 저장소 안의 Markdown 파일이 아니다.

PR 본문은 다음과 같은 웹페이지에서 렌더링 된다

https://github.com/Minter-v1/Minters-job-tracker/pull/28

 

브라우저는 docs/... 라는 문자열을 저장소 루트부터 시작하는 파일 경로라고 알 수 없다.

# 브라우저가 아는 정보는 다음 두 가지 뿐이겠지
현재 문서 URL: https://github.com/Minter-v1/Minters-job-tracker/pull/28
링크 href: docs/supabase/migrations/20261018_add_job_platforms.sql

# 브라우저는 표준 URL 해석 규칙에 따라 두 값을 결합함
node -e '
const base = "https://github.com/Minter-v1/Minters-job-tracker/pull/28";
const href = "docs/supabase/migrations/20261018_add_job_platforms.sql";

console.log(new URL(href, base).href);
'

# 그래서 이딴 실행 결과가 나오는 것임
https://github.com/Minter-v1/Minters-job-tracker/pull/docs/supabase/migrations/20261018_add_job_platforms.sql 

 

하지만, 우리가 실제 원했던 GitHub 파일 URL에는 브랜치 정보를 나타내는 blob/main이 포함되어야 한다.

 

 


해결

Sol 1) 절대경로

상대경로로는 URL 해석 기준이 다를 것 같아, 안전하게 해당 파일의 절대경로로 바꿔 링크하였다.
보이는가? 절대경로에서 정확히 blob/main 이 명시되어있다. (브랜치 정보를 나타냄)

image.png

image.png

정상 이동 됨을 확인함

 

Sol2 ) 커밋 SHA 이용(해시값 이용하기)

혹시나 가장 최신 파일이 아닌, 특정 시점의 파일을 고정해서 보여주고 싶다면 브랜치 대신 커밋 SHA를 사용할 수 있다.

[`20261018_add_job_platforms.sql`](https://github.com/Minter-v1/Minters-job-tracker/blob/51f4a589f770d2c2ee9362bbdb4ec962e39c2448/docs/supabase/migrations/20261018_add_job_platforms.sql)

 

위 코드에서 Sol 1) 에선 blob/<브랜치명> 으로 기재되어 있었으나, 여기선 blob/<커밋 해시> 로 명시되어있는 것을 확인할 수있다.

 

재발 방지

PR or Issue 저장소 파일 링크를 작성할 때 다음 항목을 확인해보자. (개발자모드로 href 도 필히 확인해보자)

  • docs/...과 같은 단순 상대경로를 사용하지 않았는가?
  • URL에 저장소 소유자와 저장소(레포지토리) 이름이 포함되어이쓴가?
  • URL에 커밋 해시 혹은 브랜치명이 명시 되어있는가? (ex. blob/<브랜치명 | SHA> )

배운 점

  • 상대경로는 언제나 현재 문서의 URL을 기준으로 해석된다.
  • 개발자가 생각하는 “저장소 루트”와 브라우저가 알고 있는 “현재 URL”은 다를 수 있다.
  • README와 PR 본문은 같은 Markdown을 사용하지만 렌더링 컨텍스트가 다르다.
  • 브라우저가 요청을 보내기 전에 URL 해석 과정이 먼저 일어난다.
  • 리다이렉트 문제는 HTTP 상태 코드뿐만 아니라 최종 URL도 확인해야 한다.

: 잘못된 링크의 리다이렉트도 HTTP 200으로 나올 수 있으니까

  • GitHub 파일 링크에는 브랜치 또는 커밋 정보가 필요하다.
← 트러블슈팅GitHub에서 보기