이슈와 PR 은 별개 테이블
번호 순번과 댓글 흐름을 공유해서 합치고 싶어집니다. 그런데 PR 에는 head·base 브랜치, 초안 플래그, 병합 시각, 리뷰가 붙고, 이슈에는 그런 것이 없는 대신 마일스톤과 담당자가 있습니다. 한 테이블이면 모든 행의 절반이 null 이고 모든 질의가 종류를 걸러야 합니다. 나눈 대가는 공유 번호를 스키마 밖에서 발급해야 한다는 것, 그리고 댓글이 둘 중 하나를 가리켜야 한다는 것입니다.
사용자 계정, 조직, 저장소, 브랜치, 커밋, 풀 리퀘스트, 코드 리뷰, 이슈, 라벨, 마일스톤, 릴리스, 스타, 포크 및 Actions 워크플로우를 포함하는 깃허브 스타일의 코드 호스팅 플랫폼을 위한 종합적인 데이터베이스 스키마입니다.
저장소는 사람에게 속할 수도 조직에 속할 수도 있고, 이 스키마는 두 포인터 — owner_id 와 org_id — 를 같은 행에 두고 하나만 채웁니다. 거의 모든 코드 호스팅이 도달하는 모양입니다. 사용자에서 조직으로 옮긴 저장소가 정체성과 스타와 이슈를 그대로 가져가야 하기 때문입니다.
이슈와 풀 리퀘스트는 저장소 단위 번호를 각각 들고 있는 별개 테이블입니다. 합칠 수 있어 보이지만, PR 에는 브랜치와 병합 상태와 리뷰가 있고 이슈에는 담당자와 마일스톤이 있습니다. 번호 순번을 둘이 공유하는 부분만은 스키마 바깥에서 지켜 줘야 합니다.
Git 자체는 모델링하지 않습니다. commits·branches·releases 는 호스팅이 보여 줘야 하는 것 — 누가, 언제, 몇 줄 — 만 기록하고 객체 그래프는 디스크의 저장소에 남습니다. 의도한 경계입니다. 모든 커밋의 트리를 담으려는 데이터베이스는 Git 이 이미 잘하는 일의 느린 사본이 됩니다.
번호 순번과 댓글 흐름을 공유해서 합치고 싶어집니다. 그런데 PR 에는 head·base 브랜치, 초안 플래그, 병합 시각, 리뷰가 붙고, 이슈에는 그런 것이 없는 대신 마일스톤과 담당자가 있습니다. 한 테이블이면 모든 행의 절반이 null 이고 모든 질의가 종류를 걸러야 합니다. 나눈 대가는 공유 번호를 스키마 밖에서 발급해야 한다는 것, 그리고 댓글이 둘 중 하나를 가리켜야 한다는 것입니다.
owner_id 와 org_id 중 정확히 하나만 채우는 방식은 가장 단정한 모델은 아닙니다 — 다형 소유자 테이블이 더 엄격합니다. 이렇게 두는 이유는 둘 사이의 소유권 이전이 흔하고 그때 저장소의 정체성이 바뀌면 안 되기 때문이며, 거의 모든 질의가 추상적 소유자가 아니라 둘 중 하나로 거르기 때문입니다.
commits 는 sha·message·additions·deletions·files_changed 를 담습니다. 목록 화면이 보여 주는 것들입니다. 트리나 블롭이나 부모는 담지 않습니다. 관계형 테이블에서 히스토리를 복원하는 것이 Git 에 묻는 것보다 느리고, 그 데이터는 저장소와 어긋날 수 있는 두 번째 사본이기 때문입니다.
branches.commit_sha 는 Git 에서 꺼내 온 브랜치 헤드입니다. 저장소 페이지가 브랜치와 마지막 커밋을 ref 를 훑지 않고 나열할 수 있게 해 줍니다. 캐시라서 푸시보다 늦을 수 있고, 진실은 저장소에 있습니다.