시작으로


버전관리를 하기 위해 Git, Github, Gitea, Svn 등 툴을 사용하는 방법에 대해서만 관심이 있었는데 정작 버전관리를 하기 위한 규칙에 대해서는 관심이 없었다.

소프트웨어 할당하는 버전은 기본적으로 유의적 버전 2.0.0-ko2을 따른다고 한다. 나도 이 글을 보면서 지식을 남기기 위해 포스팅을 시작한다.

흔히 애플리케이션 버전정보를 보면 아래와 같이 x.x.x 3자리의 정수로 되어있다.

image

image

이런 형태의 버전 할당은 Semantic versioning의 규칙을 따른 방식이라고 한다.


Versioning


소프트웨어 개발 생태계는 수많은 사람들이 서로의 기술과 성과를 이어받아 오며 믿을 수 없는 수준의 협력 체제를 구축해오고 있다. 의존성은 이러한 협력체제에서 나오게 된 요소로, 다른 사람들이 만들어온 기능을 다시 만들 필요 없이 손쉽게 가져와서 재활용하는 방식으로 빠르게 소프트웨어를 만들 수 있게 되었다.

하지만 이렇게 여러 사람에게 이용되는 패키지가 새롭게 업데이트될 때, 생각보다 다양한 문제에 직면하게 된다. 기능의 사용법을 바꾸어버리거나 동작 방식의 변경 같은 변화들은 그에 의존하는 다른 소프트웨어를 의도대로 동작하지 못하게 하므로, 새로운 변화와 기존의 것을 구분할 필요가 생겼다. 버전이라는 개념은 이러한 패키지의 변화를 구분하기 위해 사용하기 시작하였다.


Semantic versioning


Semantic Versioning은 Github의 공동창업자인 Tom Preston-Werner가 Versioning의 문제를 해결하기 위해 기존의 현안을 모아 만든 제안이다.

번호 할당은 Major.Minor.Patch 으로 할당한다고 한다. 밑에서 자세히 알아보자.


유의적 버전 명세


공개 API 선언

  • 유의적 버전을 쓰는 소프트웨어는 반드시 공개 API를 선언한다. 이 API는 코드 자체로 선언하거나 문서로 엄격히 명시해야 한다. 어떤 방식으로든, 정확하고 이해하기 쉬워야 한다.

버전 번호 형식

  • 보통 버전 번호는 반드시 X.Y.Z의 형태로 한다. X, Y, Z는 각각 자연수(음이 아닌 정수)이고, 절대로 0이 앞에 붙어서는 안 된다.
  • X는 주(主, Major)버전 번호이고, Y는 부(部, Minor)버전 번호이며, Z는 수(修, Patch)버전 번호이다.
  • 각각은 반드시 증가하는 수여야 한다. 예: 1.9.0 -> 1.10.0 -> 1.11.0.

금지 사항

  • 특정 버전으로 패키지를 배포하고 나면, 그 버전의 내용은 절대 변경하지 말아야 한다.
  • 변경분이 있다면 반드시 새로운 버전으로 배포하도록 한다.

초기개발 버전

  • 주버전 0(0.y.z)은 초기 개발을 위해서 쓴다. 아무 때나 마음대로 바꿀 수 있다.
  • 이 공개 API는 안정판으로 보지 않는 게 좋다.

최초 배포 버전

  • 1.0.0 버전은 공개 API를 정의한다.
  • 이후의 버전 번호는 이때 배포한 공개 API에서 어떻게 바뀌는지에 따라 올린다.

수(Patch)버전 증가 조건

* 수(Patch)버전 Z (x.y.Z | x > 0)는 반드시 그 전 버전 API와 호환되는 버그 수정의 경우에만 올린다.

  • 버그 수정은 잘못된 내부 기능을 고치는 것이라 정의한다.

부(Minor)버전 증가 조건

* 공개 API에 기존과 호환되는 새로운 기능을 추가할 때는 반드시 부(Minor)버전 Y(x.Y.z | x > 0)를 올린다.

  • 공개 API의 일부를 앞으로 제거할 것(deprecate)으로 표시한 경우에도 반드시 올리도록 한다.
  • 내부 비공개 코드에 새로운 기능이 대폭 추가되거나 개선사항이 있을 때도 올릴 수 있다.
  • 부(Minor)버전을 올릴 때 수(Patch)버전을 올릴 때만큼의 변화를 포함할 수도 있다.
  • 부(Minor)버전이 올라가면 수(Patch)버전은 반드시 0에서 다시 시작한다.

주(Major)버전 증가 조건

* 공개 API에 기존과 호환되지 않는 변화가 있을 때는 반드시 주(Major)버전 X(X.y.z | X > 0)를 올린다.

  • 부(Minor)버전이나 수(Patch)버전급 변화를 포함할 수 있다.
  • 주(Major)버전 번호를 올릴 때는 반드시 부(Minor)버전과 수(Patch)버전을 0으로 초기화 한다.

버전 우선순위

  • 우선순위는 버전의 순서를 정렬할 때 서로를 어떻게 비교할지를 나타낸다.
  • 우선순위는 반드시 주, 부, 수 버전, 그리고 정식배포 전 버전의 식별자를 나누어 계산하도록 한다 (빌드 메타데이터는 우선순위에 영향을 주지 않는다).
  • 우선순위는 다음의 순서로 차례로 비교하면서, 차이가 나는 부분이 나타나면 결정된다
    • 주, 부, 수는 숫자로 비교한다. 예: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1.
    • 주, 부, 수버전이 같을 경우, 정식배포 전 버전이 표기된 경우의 우선순위가 더 낮다. 예: 1.0.0-alphaa1 < 1.0.0.
    • 주, 부, 수버전이 같은 두 배포 전 버전 간의 우선순위는 식별자 숫자가 클수록 높다. 예: a1 < a2.


요약(Major.Minor.Patch)

  1. 기존 버전과 호환되지 않게 API가 바뀌면 “주(Major) 버전”을 올리고,
  2. 기존 버전과 호환되면서 새로운 기능을 추가할 때는 “부(Minor) 버전”을 올리고,
  3. 기존 버전과 호환되면서 버그를 수정한 것이라면 “수(Patch) 버전”을 올린다. 주.부.수 형식에 정식배포 전 버전이나 빌드 메타데이터를 위한 라벨을 덧붙이는 방법도 있다.
  4. 각 번호의 수는 항상 증가해야 한다.
  5. 버전 번호는 Major, Minor, Patch 의 형태로 배포하고, Major, Minor, Patch 는 각각 자연수이고 절대 앞에 0이 붙어서는 안된다.
  6. 특정 버전으로 패키지를 배포하고 나면, 그 버전의 내용은 절대 변경하지 말아야한다. 변경분이 있다면 반드시 새로운 버전으로 배포하도록 한다.
  7. Major 버전이 변경될 때, Minor, Patch 는 0으로 초기화 된다.
  8. Minor 버전이 변경될 때, Patch 는 0으로 초기화 된다.


이를 좀더 쉽게 정리해보자면

주(Major) : 기존이랑 다름, 싹 바뀜 => 싹다 바꼈으니 주(Major) +1 해주고 나머지는 0부터 시작~ (ex 1.5.2 -> 2.0.0)
부(Minor) : 기존이랑 같지만 거기서 새로운기능을 추가하거나 삭제할 떄 => 후 새로운 기능 버그도 없고 완성했으니 부(Minor)+1 해주고 수(Patch)는 0으로 시작 (ex 1.5.2 -> 1.6.0)
수(Patch) : 그 전버전 버그 수정만했을 때(다른거 안됨 무조건 기능 고치는 것) => 기능

이렇게 생각하고 버전 관리 규칙을 적용해서 할당하면 될 것 같다.