사전 Perforce
구현체

Perforce

gabury1고친 사람 github-actions[bot]

Perforce 는 팀이 함께 고치는 파일의 이력을 서버 한 곳에 모아 관리해 주는 도구입니다. 파일을 고치기 전에 서버에 먼저 알립니다. 고친 파일은 묶음 하나로 서버에 올립니다. 코드와 함께 큰 그림 파일을 다루는 게임 회사가 많이 씁니다.

쉽고 빠른 이해

Perforce 는 팀의 파일과 그 변경 기록을 서버 하나에 모아 두는 도구입니다. 게임 팀이라면 소스 코드와 캐릭터 그림 파일을 한 서버에 두고 모두가 거기서 받아 고칩니다.

이게 없으면 수백 명이 수십 기가바이트짜리 폴더를 저마다 복사해 씁니다. 누가 무엇을 고치는 중인지도 알 수 없습니다. 그림 파일은 둘이 동시에 고치면 합칠 방법이 없어서 한 사람의 작업이 버려집니다.

어떻게 도나:

  1. 서버에서 내가 맡은 폴더만 골라 최신 파일을 받습니다
  2. 고치기 전에 서버에 「이 파일을 고치겠다」고 알립니다. 서버는 누가 무엇을 고치는 중인지 압니다
  3. 고친 파일을 묶음 하나로 올립니다. 묶음에는 서버 전체에서 하나뿐인 번호가 붙습니다

서버에 닿지 않으면 고치겠다는 알림도, 지난 기록 보기도, 올리기도 못 합니다. 고치기 전에 알리는 단계를 잊으면 서버가 내 변경을 모릅니다.

상세

Perforce 는 버전관리 도구입니다. 버전관리는 파일을 언제 누가 어떻게 바꿨는지 남겨 두는 일입니다. 필요하면 예전 모습으로 되돌립니다. 이런 도구가 없으면 날짜를 붙인 폴더 복사본만 쌓입니다.

이 절은 이력을 서버에 두는 구조부터 봅니다. 이어서 서버와 내 컴퓨터가 파일을 나눠 갖는 법, 고치고 올리는 하루 흐름을 명령과 그림으로 봅니다. 끝으로 파일 잠금과 브랜치, 이 도구를 고르는 때와 안 고르는 때를 봅니다.

서버 한 곳에 이력을 두는 방식

버전관리 도구는 이력을 어디에 두느냐로 갈립니다. 이력 전체를 서버 한 곳에만 두는 방식이 중앙집중식 버전관리입니다. Perforce 는 이 방식입니다. Subversion 도 같은 방식입니다.

반대편에는 분산 버전관리가 있습니다. 사람마다 이력 전체를 한 벌씩 가지는 방식입니다. Git 과 Mercurial 이 그렇습니다.

Perforce 에서는 서버 프로그램 p4d 가 파일과 이력을 전부 쥡니다. 쓰는 사람은 각자 컴퓨터에서 명령줄 도구 p4 로 그 서버에 붙습니다. p4 는 Perforce 를 소리 나는 대로 줄인 이름입니다.

이 도구를 만든 회사 이름도 Perforce 입니다. 서버 제품은 한동안 Helix Core 라는 이름으로 팔렸습니다. 지금은 P4 라는 이름으로 팔립니다. 실무에서는 Perforce, Helix Core, P4 를 섞어 부릅니다.

디포와 워크스페이스

서버 안에서 파일과 이력을 담아 두는 보관소를 디포라고 부릅니다. 영어로 depot 입니다. 디포 안의 파일은 //depot/game/main.c 처럼 슬래시 둘로 시작하는 경로로 가리킵니다.

내 컴퓨터에서 파일을 받아 고치는 폴더는 워크스페이스라고 부릅니다. 명령 안에서는 클라이언트라고도 부릅니다. 워크스페이스에는 파일마다 내가 받아 간 판 하나만 있습니다. 지난 이력은 서버에만 있습니다.

flowchart TD
    subgraph 서버["서버 · p4d"]
        D["디포 · 파일과 이력 전체"]
    end
    D --> W1["내 워크스페이스 · 받은 파일만"]
    D --> W2["동료 워크스페이스 · 받은 파일만"]

그림의 두 워크스페이스는 같은 디포에서 받습니다. 그래도 받는 폴더는 서로 다를 수 있습니다. 어느 폴더를 받을지는 워크스페이스마다 따로 정합니다.

워크스페이스를 만들 때는 디포의 어느 경로를 내 컴퓨터의 어느 폴더로 받을지 적습니다. 이 대응표를 뷰라고 부릅니다. 받을 경로를 고를 수 있어서 거대한 디포에서도 내가 맡은 폴더만 받습니다.

//depot/game/...       //my-ws/game/...
-//depot/game/movie/... //my-ws/game/movie/...

왼쪽은 디포 경로입니다. 오른쪽은 내 워크스페이스 안의 경로입니다. ... 는 그 아래 모든 파일과 폴더를 뜻합니다.

둘째 줄처럼 앞에 - 를 붙이면 그 경로를 받지 않습니다. 이 뷰는 game 폴더를 받되 영상이 든 movie 폴더는 빼고 받습니다.

서버가 기억하는 내 파일 상태

Perforce 서버는 워크스페이스마다 어떤 파일의 몇 번째 판을 받아 갔는지 기록해 둡니다. 그래서 최신 파일을 다시 받을 때 서버는 내게 없는 판만 보냅니다. 내 폴더를 뒤져 비교하지 않아도 됩니다.

이 기록이 맞으려면 내가 파일을 건드릴 때마다 서버가 알아야 합니다. 그래서 받은 파일은 처음에 읽기 전용입니다. 고치려면 먼저 p4 edit 로 서버에 알립니다. 그러면 쓰기가 풀립니다. 서버는 그 파일을 내가 열어 둔 파일로 적습니다.

열어 둔 파일은 다른 사람에게도 보입니다. 동료가 같은 파일을 열면 누가 이미 고치는 중인지 알려 줍니다. 서버가 모든 사람의 작업 상태를 알고 있기 때문입니다.

알리지 않고 쓰기를 풀어 고친 파일은 서버가 모릅니다. 이럴 때는 p4 reconcile 을 칩니다. 이 명령은 워크스페이스를 훑어 서버 기록과 다른 파일을 찾습니다. 찾은 파일은 뒤늦게 열어 둔 파일로 적습니다.

체인지리스트와 번호

열어 둔 파일들은 체인지리스트 하나에 묶입니다. 체인지리스트는 한 번에 올릴 변경을 담는 묶음입니다. 올리기 전의 체인지리스트는 대기 중(pending)이라고 부릅니다.

체인지리스트를 서버에 올리는 일을 제출이라고 합니다. 명령은 p4 submit 입니다.

제출은 원자적입니다. 묶음 안의 파일이 전부 들어가거나 하나도 안 들어갑니다. 파일 열 개 중 일곱 개만 올라가 빌드가 깨지는 일이 없습니다.

제출된 체인지리스트에는 번호가 붙습니다. 이 번호는 파일마다가 아니라 서버 전체에서 하나씩 늘어납니다. 그래서 번호 하나가 「그 제출 직후 서버 전체의 모습」을 가리킵니다.

파일 하나에도 따로 판 번호가 붙습니다. 그 파일이 몇 번째로 제출됐는지를 셉니다. 두 번호는 아래처럼 파일 이름 뒤에 붙여 씁니다.

터미널
p4 print main.c#3   # main.c 의 3번째 판
p4 sync ...@1234    # 1234번 제출 직후 모습

# 뒤는 파일의 판 번호입니다. @ 뒤는 체인지리스트 번호입니다. 둘째 줄은 지금 폴더 아래 모든 파일을 1234번 제출 직후의 모습으로 맞춥니다.

하루 작업 흐름

하루 작업은 받기, 열기, 제출의 세 단계로 돕니다. 아래 명령 세 줄이 그 순서입니다.

터미널
p4 sync           # 최신 판을 받는다
p4 edit main.c    # 고치겠다고 알린다
p4 submit -d fix  # Change 1235 submitted.

첫 줄은 서버에서 최신 파일을 받습니다. 둘째 줄은 main.c 를 열어 대기 중 체인지리스트에 넣습니다. 셋째 줄은 -d 뒤의 설명을 붙여 제출합니다. 서버는 이 제출에 붙인 체인지리스트 번호를 돌려줍니다.

새 파일을 넣을 때는 p4 add, 지울 때는 p4 delete 로 엽니다. 어느 쪽이든 제출하기 전까지는 서버의 파일이 바뀌지 않습니다.

sequenceDiagram
    participant 나
    participant 서버
    나->>서버: p4 sync · 최신 판을 달라
    서버-->>나: 내게 없는 판만 보낸다
    나->>서버: p4 edit · 이 파일을 고치겠다
    Note over 서버: 내가 연 파일로 적는다
    나->>서버: p4 submit · 체인지리스트를 올린다
    서버-->>나: 서버 전체에서 하나뿐인 번호

그림에서 모든 화살표가 서버를 오갑니다. 받기, 열기, 제출이 전부 서버와 주고받는 일이라는 뜻입니다.

제출 거절과 합치기

내가 파일을 받은 뒤에 동료가 같은 파일을 먼저 제출했을 수 있습니다. 그러면 내 제출은 거절됩니다. 내가 고친 판이 서버의 최신 판보다 뒤처졌기 때문입니다.

이때는 p4 sync 로 동료의 판을 먼저 받습니다. 받은 파일은 합쳐야 할 파일로 표시됩니다. 이어서 p4 resolve 가 동료의 변경과 내 변경을 하나로 합칩니다. 이 일을 병합이라고 합니다.

둘이 서로 다른 줄을 고쳤으면 도구가 알아서 합칩니다. 같은 줄을 다르게 고쳤으면 사람이 골라야 합니다. 이 일을 충돌 해소라고 합니다. 합친 뒤 다시 p4 submit 을 치면 들어갑니다.

한 사람만 열게 하는 파일 잠금

그림이나 음원 같은 이진 파일은 줄 단위로 합칠 수 없습니다. 둘이 같은 그림을 동시에 고치면 한 사람의 작업을 버려야 합니다. 그래서 이런 파일은 애초에 한 사람만 고치게 막습니다.

Perforce 는 파일마다 형식을 붙여 둡니다. 형식은 그 파일을 텍스트로 다룰지 이진으로 다룰지 같은 성질을 적은 꼬리표입니다.

형식에 +l 을 붙이면 그 파일은 한 번에 한 사람만 열 수 있습니다. 먼저 연 사람이 제출하거나 열기를 취소할 때까지 다른 사람의 p4 edit 는 거절됩니다. 열기를 취소하는 명령은 p4 revert 입니다. 고치던 내용은 버려집니다.

sequenceDiagram
    participant 나
    participant 서버
    participant 동료
    나->>서버: p4 edit hero.png
    서버-->>나: 연다 · 이제 나만 고친다
    동료->>서버: p4 edit hero.png
    서버-->>동료: 거절 · 이미 누가 열었다
    나->>서버: p4 submit
    Note over 서버: 이제 동료가 열 수 있다

먼저 잡고 고치는 이 방식은 비관적 잠금과 같은 생각입니다. 누가 잡고 있는지 서버 한 곳이 알기 때문에 가능합니다. 이력을 사람마다 따로 가지는 분산 버전관리에서는 이런 잠금을 걸 곳이 마땅치 않습니다.

브랜치와 스트림

브랜치는 이력을 갈래로 나눠 두는 것입니다. 출시 판을 고치는 동안 다음 판 개발을 따로 이어 가려면 갈래가 둘 필요합니다.

Perforce 에서 브랜치는 디포 안의 다른 경로입니다. //depot/main/... 을 //depot/rel1/... 로 복사하면 갈래가 하나 생깁니다. 서버는 파일 내용을 새로 쓰지 않고 원본을 가리키기만 하므로 복사가 가볍습니다.

갈래 사이에 변경을 옮기는 명령은 p4 integrate 입니다. 출시 판에서 고친 버그를 다음 판 갈래에도 넣을 때 이 명령을 씁니다.

스트림은 이 경로 복사에 규칙을 더한 브랜치입니다. 규칙은 갈래끼리의 관계와 변경을 옮기는 방향을 정합니다.

스트림마다 부모가 하나 있습니다. 서버는 이 부모 자식 관계를 기록해 둡니다. 맨 위 스트림 하나만 부모가 없습니다.

변경은 정해진 방향으로 흐릅니다. 부모의 변경은 자식에게 병합해 내려 보냅니다. 자식에서 끝낸 일은 부모로 복사해 올립니다. 방향이 정해져 있어서 어느 갈래에 무엇을 옮겨야 할지 헷갈리는 일이 줄어듭니다.

자식은 올리기 전에 부모의 변경을 먼저 병합해 받아 둡니다. 그래서 올릴 무렵의 자식에는 부모의 변경과 자식의 일이 함께 들어 있습니다. 올릴 때는 합칠 것이 없어서 부모에 복사하기만 하면 됩니다.

제출 없이 서버에 맡기는 셸브

대기 중 체인지리스트는 내 워크스페이스에만 있습니다. 동료에게 보여 주려면 제출해야 합니다. 그런데 제출하면 모두의 파일이 바뀝니다.

p4 shelve 는 대기 중 체인지리스트의 파일을 제출하지 않고 서버에 맡겨 둡니다. 이것을 셸브라고 부릅니다. 동료는 p4 unshelve 로 그 파일을 자기 워크스페이스에 받아 볼 수 있습니다. 코드 리뷰를 받을 때 이렇게 씁니다.

고르는 때와 안 고르는 때

이 소절은 파일의 크기, 권한, 서버 의존 세 가지로 가립니다.

Perforce 가 잘 맞는 곳은 디포가 거대하고 이진 파일이 많은 팀입니다. 워크스페이스에는 이력 없이 받아 간 판만 옵니다. 뷰로 필요한 폴더만 받을 수도 있습니다. 그래서 디포가 아주 커도 각자 받는 양은 작습니다.

게임 회사가 많이 쓰는 까닭이 여기 있습니다. Unreal Engine 편집기도 Perforce 를 버전관리 도구로 붙여 쓸 수 있습니다.

경로마다 권한을 나눌 때도 맞습니다. 서버 관리자는 p4 protect 로 누가 어느 경로를 읽고 쓸 수 있는지 정합니다. 외주 팀에게 그림 폴더만 열어 주는 식입니다. 이력이 서버 한 곳에 있어서 가능한 일입니다.

서버에 닿지 않으면 파일을 열 수도, 지난 이력을 볼 수도, 제출할 수도 없습니다. 비행기 안이나 사내망 밖에서는 일이 막힙니다. 서버 한 대가 멈추면 팀 전체가 멈추기도 합니다.

코드만 다루는 팀이라면 대개 Git 을 고릅니다. 코드를 맡아 주는 GitHub 와 GitLab 이 Git 저장소를 받습니다. 대부분의 개발자가 이미 Git 에 익어 있습니다.

Perforce 는 상용 제품입니다. 서버는 팀이 직접 띄우거나 따로 계약해야 합니다. 사람 수가 늘면 값도 늘어납니다.

관련 항목

Perforce 가 속하는 상위 분류

버전관리 · 중앙집중식 버전관리 · 형상 관리 · 소스 관리

같은 역할을 두고 겨루는 버전관리 도구

Git · Subversion · Mercurial · CVS · Plastic SCM · 분산 버전관리 · Git LFS

Perforce 를 이루는 구성 요소

디포 · 워크스페이스 · 뷰 매핑 · p4d · 체인지리스트 · 리비전

Perforce 로 하는 작업

체크아웃 · 커밋 · 셸브 · 브랜치 · Perforce 스트림 · 병합 · 코드 리뷰

Perforce 가 동시 수정을 다루는 방식

비관적 잠금 · 낙관적 잠금 · 이진 파일 · 충돌 해소 · 원자성

Perforce 를 많이 쓰는 개발 분야와 도구

게임 개발 · Unreal Engine · 모노레포 · 접근 제어

다른 이름: 퍼포스 · P4 · p4 · Helix Core · Perforce Helix