Jujutsu(jj) 사용법: Git 위에 얹는 차세대 버전 관리

이번 포스팅에서는 Jujutsu(jj)에 대해서 정리하고자 한다. Jujutsu는 기존 Git 저장소를 그대로 둔 채 그 위에 얹어 쓰는 차세대 버전 관리 도구다. Git을 버리는 게 아니라 Git을 백엔드로 쓰면서, 매번 이름 붙이던 브랜치와 staging area 같은 번거로운 개념을 걷어낸다. 작업 중인 파일이 항상 자동으로 커밋으로 기록되고, 저장소에 가한 모든 조작이 operation log에 남아 jj undo 한 번으로 되돌려진다. GitHub에 그대로 push할 수 있어서 팀 전체를 바꾸지 않고 나 혼자만 먼저 도입해 볼 수 있다는 점이 가장 큰 매력이다. 이 글에서는 설치와 초기 설정, working copy가 커밋이라는 핵심 개념, bookmark와 Git 브랜치의 차이, undo, 그리고 GitHub 연동까지 실무 순서대로 짚는다.

Jujutsu가 대체 뭐길래 Git 유저들이 갈아타나

Jujutsu(jj)는 Git과 완전히 호환되는 차세대 버전 관리 시스템이다. 공식 저장소의 한 줄 소개는 “A Git-compatible VCS that is both simple and powerful”이다. 즉 저장소 데이터는 여전히 Git 포맷으로 저장되고 GitHub에 그대로 올라가지만, 사용자가 만지는 명령어 체계와 워크플로우가 완전히 새롭다. Git을 감싸는 껍데기가 아니라, Git 저장소를 백엔드로 사용하는 독립 VCS다.

Jujutsu는 Google의 Martin von Zweigbergk이 시작해 지금은 jj-vcs 조직에서 개발하는 오픈소스 프로젝트다. 2026년 8월 기준 GitHub 스타는 30.9k를 넘겼고, 최신 버전은 v0.44.0(2026년 8월 6일 릴리스)로 거의 매달 새 버전이 나올 만큼 개발이 활발하다. Git 백엔드는 순수 Rust로 작성된 gitoxide 라이브러리를 사용한다.

핵심은 “Git을 안 버려도 된다”는 점이다. 기존 .git 저장소에 jj를 얹으면 .jj 디렉터리가 추가로 생기고, 두 도구가 같은 working copy를 공유한다. 그래서 팀원들은 여전히 git을 쓰고 나만 jj로 작업해도 아무 문제가 없다. Git의 무엇이 불편했는지 이미 겪어본 사람일수록 Jujutsu의 설계가 반갑다. staging area(git add)가 없고, 브랜치에 매번 이름을 붙일 필요가 없으며, 잘못 만진 히스토리를 두려움 없이 되돌릴 수 있다. 왜 이게 가능한지는 아래에서 하나씩 풀어본다. 공식 문서는 docs.jj-vcs.dev에서 볼 수 있다.

5분 만에 끝내는 Jujutsu 설치와 첫 설정

Jujutsu 설치는 패키지 매니저 한 줄이면 끝난다. macOS·Linux는 Homebrew, Windows는 winget, 어느 플랫폼이든 Rust의 cargo로 설치할 수 있다. 설치 후에는 커밋에 남길 이름과 이메일만 등록하면 바로 쓸 수 있다. Git 2.41.0 이상이 함께 설치돼 있어야 Git 저장소와 연동된다.

# macOS / Linux (Homebrew)
brew install jj

# Windows (winget)
winget install jj-vcs.jj

# Arch Linux
sudo pacman -S jujutsu

# 모든 플랫폼 (Rust cargo, 소스 빌드)
cargo install --locked --bin jj jj-cli
ShellScript

위 명령 중 자신의 환경에 맞는 하나만 실행하면 된다. Homebrew가 가장 간편하고, cargo는 최신 소스를 직접 빌드하고 싶을 때 쓴다. 설치가 끝나면 jj --version으로 버전을 확인한다. 설치 방법은 버전마다 조금씩 바뀌므로 정확한 목록은 공식 설치 문서를 참고하는 게 안전하다.

# 커밋 저자 정보 등록 (전역 설정)
jj config set --user user.name "Hong Gildong"
jj config set --user user.email "gildong@example.com"
ShellScript

jj config set --user는 사용자 홈 디렉터리의 전역 설정 파일에 값을 기록한다. Git의 git config --global에 대응한다. 이 한 번의 설정으로 이후 만드는 모든 커밋에 저자 정보가 자동으로 붙는다. 여기까지 하면 Jujutsu를 쓸 준비가 끝난다.

Git 저장소에 jj를 얹는 두 가지 방법 (colocated가 핵심)

기존 프로젝트에 Jujutsu를 도입하는 가장 안전한 방법은 colocated 모드다. jj git init --colocate를 실행하면 기존 .git은 그대로 두고 .jj 디렉터리만 추가로 만들어져, git 명령과 jj 명령을 같은 저장소에서 섞어 쓸 수 있다. 새 저장소를 복제할 때는 jj git clone을 쓴다.

# 이미 있는 Git 저장소에 jj 얹기 (colocated)
cd my-existing-project
jj git init --colocate
# 이제 .git 과 .jj 가 공존한다

# 원격 저장소를 새로 복제하면서 시작하기
jj git clone https://github.com/jj-vcs/jj.git
cd jj
ShellScript

--colocate 옵션이 붙으면 Git과 Jujutsu가 하나의 working copy를 공유하는 하이브리드 작업 공간이 된다. 공식 문서에 따르면 colocated 저장소에서는 모든 jj 명령이 실행될 때마다 자동으로 Git과 상태를 동기화한다. 덕분에 빌드 도구처럼 .git이 있어야 동작하는 외부 도구들과도 충돌 없이 함께 쓸 수 있다.

colocated 모드의 실전 팁은 “쓰기는 jj로, 읽기는 git으로”다. 두 도구를 아무 순서로 섞어도 되지만, 저장소를 바꾸는 조작(커밋·리베이스)은 jj로 하고 git log, git status 같은 조회성 명령만 git으로 쓰면 상태 추적이 훨씬 명확해진다. 이 점진적 도입 방식 덕분에 Git 브랜치를 다루는 기존 습관을 아직 완전히 못 버린 상태에서도 Jujutsu를 실전에 투입할 수 있다. Git worktree로 병렬 작업을 관리하던 사람이라면 Git worktree 실전 가이드와 비교해 보면 접근 방식의 차이가 잘 보인다.

working copy가 곧 커밋이다: staging area가 사라진 이유

Jujutsu의 가장 근본적인 차이는 working copy 자체가 하나의 실제 커밋이라는 점이다. 파일을 수정하면 그 변경이 다음 jj 명령 실행 시점에 자동으로 현재 커밋에 반영(amend)된다. 그래서 Git의 git add(staging)와 git commit이라는 2단계가 통째로 사라진다. 작업 디렉터리와 커밋 사이의 경계가 없다.

# 새 작업(빈 커밋) 시작
jj new

# 파일을 아무렇게나 수정한다
echo "hello jujutsu" > README.md

# 상태 확인 — 이미 현재 커밋(@)에 반영돼 있다
jj status
# Working copy changes:
# M README.md
# Working copy : qpvuntsm 4f2a...  (no description set)
ShellScript

위 예시에서 echo로 파일을 바꾼 뒤 git add를 하지 않았는데도 jj status가 변경을 잡아낸다. Jujutsu는 working copy를 실제 커밋으로 표현하기 때문에, 파일을 저장하는 순간 그 내용이 현재 커밋(@ 기호로 표시된다)에 자동으로 담긴다. 커밋을 “만드는” 행위가 아니라 커밋을 “채워 넣는” 행위에 가깝다.

작업이 끝나 다음 단계로 넘어갈 때는 jj describe로 설명을 달고 jj new로 새 커밋을 연다. 이 흐름이 몸에 익으면 “아직 커밋 안 한 변경을 실수로 날렸다” 같은 사고가 구조적으로 일어나지 않는다. 모든 변경은 이미 커밋 안에 안전하게 들어 있기 때문이다.

# 현재 커밋에 설명 달기
jj describe -m "README에 소개 문구 추가"

# 이 커밋을 마무리하고 새 작업 시작
jj new
ShellScript

jj describe -m은 현재 커밋(@)의 메시지를 설정하거나 수정한다. Git의 git commit -m과 달리, 이미 존재하는 커밋의 메시지를 언제든 다시 고칠 수 있다. jj new는 현재 커밋을 부모로 삼는 새 빈 커밋을 만들고 그리로 이동한다. 이 두 명령의 조합이 Jujutsu 워크플로우의 뼈대다.

change ID와 commit ID, 두 개의 정체성

Jujutsu의 모든 커밋은 두 개의 식별자를 가진다. 하나는 리베이스나 수정을 해도 변하지 않는 안정적인 change ID이고, 다른 하나는 커밋 내용이 바뀔 때마다 새로 계산되는 commit ID(Git 해시)다. jj log를 보면 이 둘이 나란히 표시된다. change ID 덕분에 “같은 논리적 변경”을 계속 추적할 수 있다.

jj log
# @  qpvuntsm gildong@example.com 2026-08-08 14:30:12 4f2a9c1e
# │  README에 소개 문구 추가
# ○  mzvwutvl gildong@example.com 2026-08-08 14:12:03 8b3d5f00
# │  초기 커밋
# ◆  zzzzzzzz root() 00000000
ShellScript

jj log 출력에서 각 줄 맨 앞의 @는 현재 working copy 커밋을 뜻한다. 그 옆 qpvuntsm처럼 생긴 것이 change ID, 줄 끝의 4f2a9c1e가 commit ID다. Jujutsu는 change ID를 사람이 구별하기 쉽게 앞 글자만으로도 지정할 수 있게 해준다.

change ID가 왜 중요한지는 리베이스할 때 드러난다. Git에서는 커밋을 리베이스하면 해시가 전부 바뀌어 “이 커밋이 원래 그 커밋”이라는 연결이 끊긴다. Jujutsu에서는 commit ID가 바뀌어도 change ID가 유지되므로, jj rebase로 커밋을 옮겨도 동일한 change ID로 계속 참조할 수 있다. 이 설계가 뒤에서 설명할 자동 리베이스와 first-class conflict를 가능하게 하는 토대다.

커밋을 자유자재로 재조립하기: squash, split, edit

Jujutsu는 이미 만든 커밋을 나중에 쪼개고 합치는 작업이 극도로 편하다. jj squash는 현재 변경을 부모 커밋에 밀어 넣고, jj split은 하나의 커밋을 여러 개로 나누며, jj edit은 과거 커밋으로 돌아가 직접 수정한다. Git의 rebase -i로 씨름하던 히스토리 정리가 개별 명령 하나로 끝난다.

# 현재 커밋의 변경을 부모 커밋에 합치기
jj squash

# 변경 일부만 골라서 부모에 합치기 (대화형)
jj squash -i

# 하나의 커밋을 둘로 쪼개기 (대화형으로 파일 선택)
jj split

# 과거의 특정 커밋으로 돌아가 직접 수정
jj edit mzvwutvl
ShellScript

jj squash는 현재 커밋(@)의 내용을 부모로 흡수시킨다. 여러 파일을 고쳤는데 그중 일부만 이전 커밋에 넣고 싶다면 jj squash -i로 대화형 화면에서 라인 단위로 선택한다. jj split은 반대로 너무 커진 커밋을 논리 단위로 나눌 때 쓴다.

여기서 Jujutsu의 진짜 강점이 나온다. jj edit으로 과거 커밋을 수정하면, 그 위에 쌓여 있던 후손 커밋들이 자동으로 리베이스된다. Git이라면 git rebase로 손수 재정렬하고 충돌을 하나씩 처리해야 할 일을, Jujutsu는 알아서 처리한다. 앞서 말한 change ID가 유지되기 때문에 가능한 동작이다. 실수로 잘못 건드려도 다음 절의 jj undo로 되돌리면 되니 부담이 없다.

실제 jujutsu 저장소에서 만든 세 커밋의 jj log 출력 — @ 표시와 change ID·commit ID가 나란히 보인다
실제 jujutsu 저장소에서 만든 세 커밋의 jj log 출력 — @ 표시와 change ID·commit ID가 나란히 보인다

위 캡처는 실제로 jj로 커밋 세 개를 만든 뒤 jj log를 찍은 결과다. 각 커밋 앞의 vokuyvvw·uskrooul·tsrkutyq가 change ID이고, jj edit uskrooul처럼 이 change ID로 수정할 커밋을 지정한다. 맨 위 @가 현재 working copy이며, 커밋을 리베이스해도 이 change ID는 그대로라 참조가 끊기지 않는다.

jj undo: 저장소를 통째로 되감는 안전벨트

Jujutsu는 모든 조작을 operation log에 기록하므로 jj undo로 직전 조작을, jj op restore로 특정 시점 상태를 되돌린다
Jujutsu는 모든 조작을 operation log에 기록하므로 jj undo로 직전 조작을, jj op restore로 특정 시점 상태를 되돌린다

Jujutsu가 초보자에게도 안전한 이유는 operation log와 jj undo 덕분이다. Jujutsu는 저장소에 가한 모든 조작(커밋, 리베이스, squash, bookmark 이동 등)을 operation log에 기록한다. 그래서 무엇을 하다 망쳐도 jj undo 한 번이면 직전 조작 이전 상태로 정확히 되돌아간다. Git의 reflog보다 훨씬 직관적이고 강력하다.

# 지금까지의 모든 조작 이력 보기
jj op log
# @  a1b2c3d4  gildong@ 2026-08-08 14:35:00
# │  squash commit into parent
# ○  e5f6a7b8  gildong@ 2026-08-08 14:30:12
# │  describe commit

# 직전 조작 하나 되돌리기
jj undo

# 특정 시점의 저장소 상태로 통째로 복원
jj op restore e5f6a7b8
ShellScript

jj op log는 커밋 히스토리가 아니라 “저장소에 무슨 조작을 했는가”의 이력을 보여준다. 각 조작에는 고유 ID가 붙는다. jj undo는 가장 최근 조작 하나를 취소하고, jj op restore는 특정 operation ID 시점의 저장소 상태 전체를 그대로 복원한다.

이 기능의 실전 가치는 “겁 없이 실험할 수 있다”는 데 있다. 복잡한 리베이스나 대규모 squash를 시도하다 꼬여도, jj undo로 아무 일 없던 것처럼 되돌린다. Git에서 git reset --hard나 reflog를 뒤지며 식은땀 흘리던 상황이 Jujutsu에서는 명령 한 줄로 끝난다. 공식 저장소도 이 점을 “you can undo that mistake you just made with ease”라고 강조한다.

bookmark vs Git 브랜치: 가장 많이 헷갈리는 지점

Git 브랜치는 새 커밋을 자동으로 따라가지만 Jujutsu의 bookmark는 그 자리에 고정돼 jj bookmark move로 직접 옮겨야 한다
Git 브랜치는 새 커밋을 자동으로 따라가지만 Jujutsu의 bookmark는 그 자리에 고정돼 jj bookmark move로 직접 옮겨야 한다

Jujutsu에서 Git 브랜치에 해당하는 개념은 bookmark다. 하지만 결정적 차이가 있다. Git 브랜치는 커밋할 때마다 자동으로 따라 움직이지만, Jujutsu의 bookmark는 자동으로 따라오지 않는다. 새 커밋을 만들어도 bookmark는 그 자리에 그대로 있어서, 필요할 때 jj bookmark move로 직접 옮겨줘야 한다. 이 차이를 모르면 “push했는데 왜 옛날 커밋만 올라갔지?”라며 혼란에 빠진다.

# 현재 커밋에 bookmark 생성
jj bookmark create feature-login -r @

# 작업을 몇 번 더 한 뒤, bookmark를 최신 커밋으로 이동
jj new
# ... 작업 ...
jj bookmark move feature-login --to @-

# bookmark 목록 확인
jj bookmark list
ShellScript

jj bookmark create -r @는 현재 커밋에 이름표를 붙인다. 문제는 그 다음이다. jj new로 새 커밋을 만들어도 feature-login bookmark는 이전 위치에 남아 있으므로, jj bookmark move --to @-처럼 명시적으로 옮겨야 한다(@-는 현재 커밋의 부모를 뜻한다).

이 동작은 처음엔 불편해 보이지만 의도된 설계다. Jujutsu는 이름 없는 익명 브랜치를 기본으로 삼기 때문에, 사소한 변경마다 브랜치 이름을 지어낼 필요가 없다. 이름이 정말 필요한 순간(원격에 push할 때)에만 bookmark를 만들면 된다. 이 개념 차이가 Jujutsu 학습에서 가장 큰 허들이라는 점은 커뮤니티에서도 자주 지적된다. 브랜치가 자동으로 안 따라온다는 사실 하나만 기억하면 대부분의 혼란은 사라진다.

충돌이 무섭지 않은 이유: first-class conflict

Jujutsu는 충돌(conflict)을 1급 시민으로 다룬다. Git에서는 리베이스나 병합 중 충돌이 나면 작업이 멈추고 그 자리에서 해결할 때까지 다음으로 못 넘어간다. Jujutsu는 충돌을 커밋 안에 그대로 저장한 채로 작업을 계속 진행시킨다. 충돌은 나중에 편한 시점에 해결하면 된다. 리베이스가 중간에 막히는 일이 없다.

# 리베이스 중 충돌이 나도 멈추지 않는다
jj rebase -d main
# 충돌이 있는 커밋은 로그에 conflict로 표시된다

jj log
# @  kntqzsrv (conflict) 기능 구현
# │
# ○  main

# 충돌 커밋으로 가서 파일을 직접 수정해 해결
jj edit kntqzsrv
# ... 충돌 마커를 편집 ...
# 저장하면 자동으로 해결 상태가 반영된다
ShellScript

jj rebase -d main을 실행하면 대상 커밋을 main 위로 옮긴다. 이때 충돌이 생겨도 Jujutsu는 멈추지 않고, 충돌을 품은 커밋을 로그에 (conflict)로 표시한 뒤 리베이스를 끝까지 완료한다. 공식 튜토리얼의 표현대로 “commits remain in the repo marked as conflicted” 상태가 된다.

해결은 급할 게 없다. 충돌 표시된 커밋으로 jj edit해서 파일을 고치면 그 커밋의 충돌이 풀리고, 그 위에 쌓인 후손 커밋들도 자동으로 다시 리베이스된다. 여러 커밋을 한꺼번에 리베이스했다가 충돌이 여기저기 났을 때, Git처럼 “한 커밋 해결 → continue → 또 충돌”을 반복하지 않아도 된다는 게 실무에서 체감되는 가장 큰 편의다.

원격 따라잡기와 변경 되돌리기: fetch·diff·abandon

Jujutsu에서 원격 변경을 받아오려면 jj git fetch로 가져온 뒤 내 작업을 최신 커밋 위로 리베이스한다. 변경 내용은 jj diff로 확인하고, 만들다 만 커밋을 통째로 버릴 때는 jj abandon, 파일 수정만 되돌릴 때는 jj restore를 쓴다. push만 알고 이 명령들을 모르면 일상 작업에서 금방 막힌다.

# 원격(origin)의 최신 변경 가져오기
jj git fetch

# 내 작업을 갱신된 원격 main 위로 리베이스
jj rebase -d main@origin

# 현재 변경 내용 확인 / 특정 커밋 내용 보기
jj diff
jj show uskrooul
ShellScript

jj git fetch는 원격의 커밋을 로컬로 내려받는다. Git의 git fetch와 같지만, 이어서 jj rebase -d main@origin으로 내 커밋들을 갱신된 원격 main 위로 옮기면 된다(main@origin은 “원격 origin의 main”을 가리키는 revset 표기다). 리베이스 중 충돌이 나도 앞서 본 first-class conflict 덕분에 멈추지 않는다.

# 지금 작업 중인 변경 전체를 버리기 (커밋째 삭제)
jj abandon

# 특정 파일의 수정만 직전 상태로 되돌리기 (커밋은 유지)
jj restore app.py
ShellScript

위 캡처는 임시로 만든 scratch.txt 변경을 jj diff로 확인한 뒤 jj abandon으로 커밋째 버리고, jj log로 사라진 걸 확인한 실제 결과다. jj abandon은 현재 커밋을 통째로 없애고 그 부모로 이동하며, jj restore <파일>은 커밋은 남긴 채 지정한 파일의 수정만 되돌린다. Git의 git restoregit reset이 하던 일을 목적별로 두 명령이 나눠 맡는다. 그리고 abandon처럼 파괴적인 조작도 결국 operation log에 남으므로, 잘못 버렸다면 jj undo로 즉시 되살릴 수 있다.

한 가지 주의할 함정이 있다. Jujutsu는 이미 원격에 push했거나 main에 올라간 커밋을 기본적으로 immutable(변경 불가)로 취급한다. 그런 커밋을 jj edit이나 jj squash로 고치려 하면 Commit ... is immutable 오류가 난다. 협업 중인 히스토리를 실수로 갈아엎지 못하게 막는 안전장치다. 정말 고쳐야 한다면 새 커밋을 그 위에 쌓는 방식으로 우회하거나, 설정에서 immutable 판단 기준을 조정한다.

GitHub와 함께 쓰기: push와 PR의 현실

Jujutsu는 GitHub에 그대로 push할 수 있지만, PR 워크플로우에는 알아둘 제약이 있다. 원격에 올리려면 먼저 커밋에 bookmark를 붙이고 jj git push로 밀어 올린다. 다만 Jujutsu 단독으로는 GitHub의 특정 Pull Request를 체크아웃할 수 없어서, 이 경우엔 colocated 저장소에서 git을 병행해야 한다.

# 방법 1: bookmark를 만들고 push
jj bookmark create feature-login -r @
jj git push --bookmark feature-login

# 방법 2: 이름을 자동 생성해서 push (임시 bookmark)
jj git push --change @
# push-xxxxxxxx 형태의 bookmark가 자동 생성돼 올라간다
ShellScript

jj git push --bookmark는 지정한 bookmark를 원격에 올린다. 이름을 미리 짓기 귀찮으면 jj git push --change @(단축 -c)를 쓴다. 이러면 Jujutsu가 push- 접두어의 bookmark를 자동으로 만들어 push하므로, PR 하나 올리자고 브랜치 이름을 고민할 필요가 없다. 참고로 원격에 없던 새 bookmark를 처음 올릴 때는 --allow-new 플래그를 함께 붙여야 한다. 기존 bookmark를 실수로 새로 만드는 사고를 막기 위한 안전장치다.

주의할 제약도 분명하다. 공식 문서와 커뮤니티 논의에 따르면 Jujutsu는 원격의 refs/heads/*에서만 fetch하기 때문에, GitHub PR을 jj만으로 체크아웃하는 방법은 아직 없다. 남의 PR을 받아 확인해야 한다면 colocated 저장소에서 git fetch로 PR을 가져온 뒤 jj로 이어서 작업하는 우회가 필요하다. 이런 GitHub 연동 세부 사항은 공식 GitHub 가이드에 정리돼 있다. 팀이 GitHub PR 중심으로 돌아간다면 이 제약을 미리 인지하고 도입하는 게 좋다.

Git 명령어를 jj로 옮기면: 한눈에 보는 대응표

Git에 익숙한 사람이라면 명령어 대응표부터 보는 게 가장 빠르다. 아래 표는 자주 쓰는 Git 명령이 Jujutsu에서 어떻게 바뀌는지 정리한 것이다. 개념이 1:1로 딱 맞지 않는 경우도 있는데, 그 자체가 Jujutsu의 설계 철학을 보여준다.

작업GitJujutsu(jj)
저장소 복제git clone <url>jj git clone <url>
변경 스테이징git add <file>(불필요 — 자동 반영)
커밋 생성git commit -m "msg"jj describe -m "msg" + jj new
새 작업 시작git checkout -b featurejj new (이름 불필요)
커밋 메시지 수정git commit --amendjj describe
브랜치/북마크 생성git branch featurejj bookmark create feature -r @
히스토리 보기git logjj log
리베이스git rebase -ijj rebase / jj squash / jj split
되돌리기git reset / reflogjj undo / jj op restore
변경 버리기git restore / git resetjj abandon(커밋째) / jj restore <file>(파일)
원격 변경 받기git fetch + git rebasejj git fetch + jj rebase -d main@origin
원격에 올리기git push origin featurejj git push --bookmark feature
상태 확인git statusjj status

표에서 보듯 git add에 대응하는 명령이 아예 없다. staging이라는 개념 자체가 사라졌기 때문이다. 또한 커밋을 만들 때 브랜치 이름을 짓는 checkout -b 단계가 jj new 하나로 대체된다. 이름은 push 직전에만 붙이면 된다.

이 대응표는 처음 며칠 참고용으로만 쓰고, 곧 잊어버리는 게 좋다. Jujutsu를 “Git 명령의 번역”으로만 이해하면 오히려 헷갈린다. working copy가 커밋이고, 브랜치는 익명이 기본이며, 모든 조작은 되돌릴 수 있다는 세 가지 전제를 받아들이면 명령어는 자연스럽게 손에 붙는다. 다른 현대적 CLI 도구들과 함께 개발 환경을 꾸리고 싶다면 2026년 모던 CLI 도구 모음도 참고할 만하다.

언제 도입할 만하고, 어떤 한계가 있나

Jujutsu는 “혼자 쓰는 로컬 워크플로우”에서 가장 큰 이득을 준다. 복잡한 커밋 재정리, 잦은 실험, 리베이스가 많은 개인 작업이라면 지금 도입해도 충분히 실용적이다. 반면 팀 협업에서 GitHub PR을 촘촘히 주고받는 환경이라면 앞서 본 PR 체크아웃 제약 때문에 git을 병행하게 되므로, 완전 대체보다는 병용으로 시작하는 게 현실적이다.

도입을 권할 만한 경우는 대략 세 부류다. 커밋을 자주 쪼개고 합치며 히스토리 정리에 시간을 쏟는 사람이라면 jj squashjj split, 자동 리베이스만으로도 도입할 이유가 충분하다. 리베이스 도중 충돌로 자꾸 막혀 흐름이 끊기는 사람에게는 first-class conflict가 답이 된다. 그리고 Git 명령 한 줄에 식은땀 흘려본 적이 있다면, jj undo의 안심감이 생각보다 크게 다가온다.

한계도 솔직히 알아둬야 한다. Jujutsu는 아직 1.0 이전(v0.44.0)이라 명령어 체계가 버전 간에 바뀔 수 있다. GitHub PR 체크아웃을 jj 단독으로 못 하고, 팀원들에게 새 개념(bookmark, working copy 커밋)을 설명해야 하는 학습 비용도 있다. 그래서 가장 안전한 출발점은 colocated 모드다. 기존 Git 저장소를 그대로 둔 채 jj를 얹어, 나 혼자만 먼저 써보며 감을 잡은 뒤 판단하면 된다. 실제로 이 방식으로 도입을 시작한 개발자들의 후기가 Hacker News 토론에도 다수 올라와 있다.

FAQ

Jujutsu를 쓰면 기존 Git 저장소나 팀원들에게 문제가 생기나요?

문제가 생기지 않는다. Jujutsu는 Git 저장소를 백엔드로 그대로 사용하고, 만들어진 커밋도 일반 Git 커밋과 동일하다. colocated 모드(jj git init --colocate)로 얹으면 .git은 손상 없이 유지되고 .jj만 추가된다. 팀원들은 계속 git을 쓰고 나만 jj를 써도 원격 저장소에는 똑같은 Git 히스토리가 올라가므로 협업에 지장이 없다.

Jujutsu의 bookmark는 Git 브랜치와 뭐가 다른가요?

가장 큰 차이는 자동으로 따라 움직이지 않는다는 점이다. Git 브랜치는 커밋할 때마다 최신 커밋을 자동으로 가리키지만, Jujutsu의 bookmark는 생성된 위치에 고정돼 있어 새 커밋을 만들어도 그 자리에 남는다. 최신 커밋을 가리키게 하려면 jj bookmark move --to @처럼 직접 옮겨야 한다. Jujutsu가 익명 브랜치를 기본으로 삼기 때문에 생기는 설계상의 차이다.

staging area(git add)가 없으면 일부 변경만 커밋하려면 어떻게 하나요?

jj squash -ijj split으로 라인 단위 선택을 하면 된다. Jujutsu는 모든 변경을 현재 커밋에 자동으로 담지만, 대화형 명령으로 그중 일부만 골라 다른 커밋으로 옮길 수 있다. jj squash -i는 선택한 변경만 부모 커밋에 합치고, jj split은 현재 커밋을 골라낸 변경과 나머지로 쪼갠다. Git이라면 커밋 전에 git add -p로 하던 선별 작업을, Jujutsu에서는 커밋을 만든 뒤에 한다는 점만 다르다.

Jujutsu에서 실수한 작업을 되돌리려면?

jj undo로 직전 조작을 취소하거나 jj op restore로 특정 시점 상태로 복원한다. Jujutsu는 커밋뿐 아니라 리베이스·squash·bookmark 이동 같은 모든 저장소 조작을 operation log에 기록한다. jj op log로 이력을 확인한 뒤 jj undo를 실행하면 가장 최근 조작 하나가 취소되고, 특정 operation ID를 jj op restore에 넘기면 그 시점의 저장소 전체 상태로 되돌아간다. Git의 reflog보다 복원 범위가 넓고 사용법이 직관적이다.

GitHub Pull Request는 Jujutsu만으로 처리할 수 있나요?

PR을 새로 올리는 것은 가능하지만, 남의 PR을 체크아웃하는 것은 jj 단독으로는 아직 안 된다. jj git push --change @ 또는 bookmark를 만들어 push하면 PR용 브랜치를 원격에 올릴 수 있다. 다만 Jujutsu는 원격의 refs/heads/*에서만 fetch하므로 GitHub PR 브랜치를 직접 가져오지 못한다. 이 경우 colocated 저장소에서 git fetch로 PR을 받아온 뒤 jj로 이어 작업하는 우회가 필요하다.

마치며

지금까지 Jujutsu(jj)에 대해서 정리해 보았다. 개인적으로 Jujutsu에서 가장 크게 체감한 건 “겁 없이 히스토리를 만진다”는 감각이었다. Git을 오래 쓰면서 리베이스 직전엔 늘 브랜치를 하나 백업해 두는 습관이 있었는데, jj undo를 몇 번 써보고 나서는 그 백업 습관 자체가 사라졌다. 커밋을 쪼개고 합치고 순서를 바꾸는 실험을 부담 없이 하게 되니, 오히려 커밋 하나하나를 더 정성껏 다듬게 됐다.

물론 아직 완성형 도구는 아니다. bookmark가 자동으로 안 따라오는 첫 며칠은 분명 헷갈리고, 팀이 GitHub PR로 굴러간다면 git을 완전히 놓기도 어렵다. 그래서 나는 새 프로젝트를 통째로 옮기기보다, 기존 저장소에 colocated로 얹어 개인 작업에만 먼저 써보는 방식을 권한다. Git을 버리는 게 아니라 그 위에 더 편한 레이어를 하나 올려보는 것뿐이니, 마음에 안 들면 .jj 디렉터리만 지우면 원래 Git 저장소로 되돌아간다. 그 정도 부담이면 한 번 써볼 만하다.