2P by GN⁺ 2일전 | ★ favorite | 댓글 1개
  • Jujutsu(jj)는 Git보다 단순한 개념과 명령어, 그러나 강력한 기능을 제공하는 버전 관리 시스템
  • Git을 백엔드로 사용하므로 동시에 사용하거나 Git으로 쉽게 복귀할 수 있는 장점이 있음
  • 스택형 diff, 쉬운 rebase, 임시 리비전과 같은 기능이 자연스럽게 제공됨
  • 분기(Branch) 대신 북마크(Bookmarks) 개념을 활용하며, 현업 작업 흐름에 더 직관적임
  • 충돌(Conflict) 처리 방식이 유연하고, 일상적인 버전 관리 작업을 훨씬 간단하게 해줌

Elevator Pitch

Jujutsu(jj)는 Git과 비교해 훨씬 단순한 정신 모델과 명령줄 인터페이스를 제공하는 버전 관리 시스템임.
기능을 희생하지 않으면서도, 실은 더 강력하다고 볼 수도 있음
스택형 diff, 손쉬운 rebase, 임시 리비전과 같은 기능이 자연스럽게 동작함
백엔드로 Git을 사용하므로, 단 한 줄로 Git 저장소와 나란히 사용을 시작할 수 있으며 언제든지 Git으로 돌아갈 수 있음
다른 사용자가 저장소를 다루는 방식에도 영향을 주지 않음

Getting Started

  • jj 명령줄 도구를 설치한 뒤, 사용자 정보와 쉘 자동완성 설정을 권장함
  • 기존 저장소에 적용 시 새로 클론하거나, 변경 없는 상태에서 사용 시작이 유리함
  • 기존 저장소에서 jj git init --colocate . 명령으로 Git과 Jujutsu 저장소를 병행 생성할 수 있음
  • jj 저장소 데이터는 Git의 .git과 별도의 .jj/ 폴더에 보관됨
  • Git과 Jujutsu 간의 데이터 동기화는 기본적으로 문제 없이 운영됨
  • 단, git clean -fdx 명령은 .jj/ 폴더를 삭제하므로 주의해야 함
  • remote branch 트래킹도 해당 명령으로 한 번에 설정 가능함

How To Use It

Jujutsu의 명령줄 인터페이스는 Git보다 좁고 간결함
기본 개념이 단순하지만 작업 흐름에는 약간의 적응이 필요함
간단한 절차와 예시로 주요 사용 방법을 설명함

Starting A New Revision

  • Git에서의 새 작업은 보통 브랜치 생성으로 시작하지만, Jujutsu는 리비전을 새로 만드는 방식
  • 최신 리모트 저장소 상태 반영: jj git fetch
  • 저장소 히스토리 확인: jj log
  • 히스토리 내 리비전은 고유한 Jujutsu별 리비전 IDGit 커밋 해시로 구분됨
  • 신작업 시작은 jj new main으로 현재 main 위에 새 리비전 생성
  • 현재 편집 중인 리비전은 @ 기호로 구분됨
  • 동일한 접두사가 사라지면 리비전 ID의 짧은 접두사도 따라 변동됨

Making Changes

  • 파일을 수정하면 즉시 해당 리비전에 포함됨(별도의 staging area 없음)
  • 수정이 완료되면 jj describe -m "메시지"로 리비전에 메시지 추가
  • 새 리비전을 만들 때는 jj new (또는 이전 리비전 지정)
  • jj commitjj describe + jj new의 조합 연산임

Navigating

  • jj new로 생성한 빈 리비전은 이동 시 자동 폐기됨
  • 명시적으로 리비전 삭제: jj abandon <rev ID>
  • 삭제 취소: jj op undo
  • 기존 리비전으로 돌아가기는 jj edit <rev ID>
  • 리비전 참조시 revset expressions도 사용 가능:
    • @: 현재 리비전
    • x-: 부모 리비전
    • y+: 자식 리비전
    • z::: z의 모든 자손

Branches (Bookmarks)

  • Jujutsu는 Git처럼 "브랜치에 머무르는 상태"가 없음
  • 대신, 북마크(Bookmarks)는 단지 특정 리비전을 가리키는 포인터임
  • 새 북마크 생성: jj bookmark create <이름> -r <리비전>
  • 커밋해도 자동으로 북마크가 이동하지 않으므로, 필요시 jj bookmark move <이름> --to <리비전>으로 별도 이동 필요
  • push 시에는 --allow-new 플래그로 원격 새 브랜치 생성 인정
  • 북마크가 원격과 다르면 *로 표시되며 jj git push로 동기화 가능

Conflicts

  • Jujutsu의 충돌 처리 방식은 Git보다 유연
  • 충돌 시 ‘conflicted’ 표식이 리비전 및 자손 리비전에 표시됨
  • 충돌 파일은 충돌 마커가 삽입되고, 해당 마커를 제거하는 것으로 해결함
  • 직접 수정 또는 새 리비전에서 변경 이후 jj squash로 합칠 수 있음

결론

이상으로 Git에서 가장 많이 쓰이는 80%의 작업을 Jujutsu로 더욱 간단하게 처리하는 방법을 안내함
추후 일반적/고급 활용은 참조 핸드북(Quick Reference) 형태로 제공 예정임
Git처럼 jj status 명령 지원함
문의나 피드백은 본문 이메일로 가능함

Hacker News 의견
  • jj를 배울 가치가 있는지 고민하는 분들께 강조하고 싶은 점이 있음
    Hacker News에서 jj에 대해 얘기하면, 두 부류로 나뉨: 아직 시도해보지 않은 사람들과 강력 추천하는 사람들임
    일주일간 jj를 써본 뒤 다시 git으로 돌아가는 경우는 거의 본 적이 없음
    정말 진지하게 써본 사람들은 거의 다 jj에 정착했음
    오늘이 바로 jj를 써보는 계기가 되길 바람
    생각보다 전환이 훨씬 간단하고, 나는 당일에도 바로 생산성을 유지했고, 일주일 안에 git 커맨드로 돌아갈 일이 전혀 없었음
    짧은 시간 안에 더 생산적으로 변했고, 이전에 어떻게 git을 썼는지 신기할 따름임

    • 나는 git이 생산성 측면에서 전혀 불편하지 않음
      git 커맨드를 매일 오래 쓰는 것도 아니고, 대부분의 경우 작업에 무리가 없음
      레포를 git으로 많이 조작해야 한다면 jj가 더 나을 수 있지만, 내 상황엔 해당되지 않음
      예를 들어, vim과 매우 비슷하면서 다른 기능이 추가된 bim을 무조건 써보라는 제안과도 유사함
      하지만 "i"를 몇 번 더 치는 게 궁금하지 않고, julia 자동완성도 필요하지 않음
      jj가 더 좋은 분들은 즐기시길 바람

    • jj는 VCS UI에서 확실히 발전이긴 하지만, git 고급 사용자라면 몇 가지 한계점이 있음
      gitattributes 미지원으로 git-crypt, git-lfs 등 필터가 필요하면 불편함
      줄 끝 처리 등 Windows에서의 호환성도 떨어질 수 있음
      또, git-annex, git-bug 같은 외부 툴은 oplog 통합 안 되고 히스토리 어지럽힐 수도 있음

    • 나는 실제로 일주일 넘게 써보고 다시 git으로 돌아간 경험이 있음
      개인적으로 staging area의 워크플로우가 더 좋아서, 대부분은 git staging을 싫어하지만 나는 오히려 그게 jj에서 버릴 만큼 이득이 크지 않았음
      습관은 바꿀 수 있겠지만, 아직 jj에 굳이 안 얽매임
      언젠가 다시 시도할 마음은 열려있음

    • 몇 달간 jj를 썼다가 다시 git으로 돌아갔던 이유는 성능 문제였음
      jj 조작은 수 초가 걸렸고, git은 프로젝트 크기와 관계없이 즉각적이었음
      또 jj를 쓰면 약간 더 정신적으로 복잡해지는 느낌을 받았고, 다시 git으로 오니 한결 가벼워짐
      이건 나만의 장기간 git 사용 경험 때문일 수도 있음

    • “어차피 두 부류뿐”이라 말하는 자체가 jj 전도사들의 전형적 멘트 같음

  • jj에서 미치는 점은 변경사항이 무조건 자동 staging되었다는 점임
    SVN 체계가 예전에 그랬고, git은 명시적으로 staging해서 훨씬 개선되었다고 느낌
    레포에는 늘 더 많은 변경이 남아 있고, 다음 커밋에 넣고 싶은 것만 선택하는 게 git에선 당연한데
    jj(SVN 포함)는 커밋 전 변경을 임시로 밖으로 옮기는 등 번거로운 수작업이 필요함

    • 이 이슈는 나도 딜레마임
      staging이 항상 귀찮아서 Mercurial 쓸 때도 힘들었음
      자동 추가가 90% 이상 필요한 경우엔 오히려 편한데, .gitignore에 못 넣는 파일들이 문제임
      auto add를 꺼도 불편해지고, 켜도 애매함
      어느 쪽도 완전히 깔끔하지 않음

    • JJ의 워크플로우는 약간 다르니, 예를 들어 베이스 커밋을 먼저 만들고, 그 위에 익명 커밋을 쌓아서 작업
      준비가 되면 jj squashjj split으로 정리하게 됨

    • 나는 jj commit -i나 여러 명령의 -i 옵션, 그리고 config의 snapshot.auto-track="none()"을 씀
      Mercurial 쓸 때도 비슷했음
      실제론 absorb 기능을 많이 쓰면 불필요한 파일이나 청크는 자동으로 무시됨

    • “jj new” 명령어가 원하는 워크플로우에 적합한 것 아님?

    • jj는 트리 상에서 head가 아닌 브랜치도 제대로 추적하기 때문에, 리베이스와 머지가 stash 필요 없이 매끄럽게 작동함

  • 자동 변경 추가에 적응하기가 쉽지 않음
    로컬에서 특정 파일은 커밋할 생각 없이 개발 과정에서 잠깐 변경할 때가 있는데
    git에선 staging하지 않으면 절대 커밋/푸시 안 되니 안심되지만
    jj에선 뭔가 unstage하거나 조심해야 할 것 같음
    습관 문제일 수 있겠으나, 나는 내가 커밋할 것만 명확히 지정하는 게 더 편함
    혹시 내가 jj를 잘못 이해한 것인지 궁금함

    • jj에선 jj split으로 변경점을 나눌 수 있음
      선택하면 첫 번째 리비전, 나머지는 두 번째 리비전으로 정리됨
      여러 작업을 한 번에 하고 bite-sized 리비전으로 나눴을 때 git보다 훨씬 수월함
      git처럼 새 리비전(jj new) 만들고 바꾼 후, jj squash -i로 딱 원하는 부분만 옮길 수 있음
      개념적으로 “@”가 현재 리비전, “@-”가 한 단계 전이니 git의 워킹 카피/스테이지처럼 생각하면 됨

    • jj의 자동 스테이징이 항상 좋은 게 아님
      jj 공식문서와 입문자들이 기본값을 쉽게 끌 수 있다는 점을 더 명확히 알렸으면 함
      ~/.jjconfig에
      [snapshot]
      auto-track = "none()"
      이렇게 적으면 됨

    • 나는 주로 작업 후 jj split으로 커밋할 부분을 리뷰해서 정리함
      이 워크플로우는 git의 add -p랑 비슷하게 움직임
      맨 위 커밋은 보통 push하지 않는 워킹 카피처럼 쓸 수 있음
      스태시 없이 브랜치 전환해도 진행중인 내용은 잘 보존됨

    • 네, 그 습관이 나도 쉽지 않게 바뀜
      바꿔야 한다는 주장의 합리적 근거는, untracked 상태로 코드를 돌리면 안 된다는 것임
      의미 있는 변경은 커밋에 남기고, 나머지는 기록하지 않는 게 더 안전함
      문제는 레포 전체의 설정과 로컬 설정이 분리되지 않을 때인데, VSCode가 대표적임
      이럴 땐 환경별로 커밋해선 안 되는 변경이 필요해져서 더 복잡해짐

    • 이런 워크플로우를 원하면, jj의 “@”를 git index처럼, 커밋 타임에 “@-”로 squash 하면 git add --patch와 비슷한 효과를 얻을 수 있음

  • 팀을 jj로 바꾸려다 실패 중임
    git에서 복잡한 작업을 jj로 얼마나 쉽게 할 수 있는지 한눈에 보여주는 페이지가 있으면 좋겠음
    엘리베이터 피치 마냥 간단히
    내가 직접 데모해서 보여주는 것도 필요하겠다는 생각임

    • 많은 사람들이 흔히 쓰는 git 작업이 jujutsu에서 더 쉬운 건 아닌 듯함
      오히려 git에선 불가능하거나 번거로운 새로운 워크플로우가 jujutsu에 있음
      이건 기존 git에 익숙한 개발자들에겐 잘 와닿지 않을 수 있음

    • 나 역시 git을 특별히 좋아하는 건 아님
      과거엔 mercurial만 썼었는데, 지금은 git이 이미 머릿속에 박혀있음
      Jujutsu가 뭔가 확실한 장점이 있어도, 초기 셋업(복잡한 컬러 세팅, 익숙한 스크립트 세팅 등)까지 신경 쓸만큼의 매력은 아직 못 느낌

    • 나는 jj와 git의 한 가지 대표 작업 비교가 큰 이해를 도왔음
      https://lottia.net/notes/0013-git-jujutsu-miniature.html

    • 도움이 될만한 좋은 링크들도 추천함
      https://v5.chriskrycho.com/essays/jj-init/
      https://v5.chriskrycho.com/journal/jujutsu-megamerges-and-jj-absorb/
      https://ofcr.se/jujutsu-merge-workflow

    • 내가 이 포스트에 곧 추가할 다음 내용이 아마 마음에 들 것임
      조만간 페이지 하단과 별도 포스트로 올릴 예정임

  • 몇 주 jj를 쓰다가 자동 커밋 메시지 스크립트도 제작함
    오늘 오랜 git 레포에서 같은 스크립트를 포팅하려고 했는데, git에선 커밋/어멘드 시점을 자동 판별할 코드가 필요하다는 걸 깨달았음
    jj는 immutable 커밋 구조 덕분에 스크립트가 매우 간단했음
    그냥 jj로 레포를 새로 클론함
    커밋과 어멘드 헷갈림에서 순식간에 해방되었음
    https://codeberg.org/jcdickinson/nix/…

    • 꼭 re-clone 할 필요 없이, 기존 git 레포에 jj를 추가로 쓰면 됨
  • git이 충분히 잘 작동함
    학습 곡선이 조금 있을 뿐, 일단 익히면 모든게 이해됨
    솔직히 95%의 상황에서 pull, add, reset, branch, commit 정도만 알면 충분함

    • 내 워크플로우에선 stacked diff가 필수임
      리뷰 기다리느라 막히지 않고 미래 작업까지 쌓아두기 좋음
      git에서 세팅은 안 어렵지만, 스택 아래쪽에 변경 추가하고 전체 restack 하는 건 정말 헬임

    • 협업하는 경우엔 rebase/squash 숙지가 필수임
      팀 전체가 안 쓰도록 설득하기 전엔 피할 수 없음
      특히 여러 명이 한 브랜치에서 급하게 개발할 땐 git 습관이 불편함으로 다가옴
      기본적으론 편하지만, 복잡한 상황에선 문제가 많음

    • 특이한 상황만 경험해봐도 git의 단점이 보임

  • jj를 쓴 지 2주 정도 됐고, 처음으로 커맨드라인만으로 버전 관리를 편하게 쓰고 있음
    git을 쓸 땐 항상 GUI(Git Graph in VSCode)에서 우클릭 위주였는데
    jj는 튜토리얼 만 읽고도 바로 일관된 커맨드라인으로 진입이 가능했음
    다만 jj 로그에서 id를 계속 복붙하는 걸 방지하려면 revset 언어를 배워야 할 듯함

    • 나도 비슷한 상황임
      git을 오래 썼지만 복잡한 건 항상 UI로 처리했었음
      한 달 가까이 jj CLI만 사용 중이고 꽤 만족스러움
      다만 jj 공식 문서가 기본 지식이 있다는 전제로 쓰여 있어서 초보에겐 헷갈릴 때가 있음
      블로그, 튜토리얼이 더 많아지길 바람
      나도 revset 언어랑 rebase 좀 더 배워보고 싶음
      간결한 cli, 충돌 해결, oplog 다 맘에 듦

    • 나도 id 복사 붙여넣기 불편했었는데, jjui(https://github.com/idursun/jjui) 쓰고나선 훨씬 부드러워졌음
      마치 로그를 훑듯이 빠르게 작업하게 됨

  • jj 최고의 기능은 undo라고 생각함
    git에서 undo는 실수 종류에 따라 커맨드가 따로 있어서 어려움
    jj는 jj undo 한 번이면 끝남
    백엔드 시스템에도 얽매이지 않아 로컬에서 혼자 jj 써도 동료에게 영향 없음

  • jj가 뭔지 혼란스러움
    git 헷갈리는 사람을 위한 프론트엔드인지 궁금함
    백엔드 추상화한다고 하지만 git에 너무 영향을 받아 Perforce, Piper처럼 순차 넘버 커밋이 강제되는 시스템에선 잘 상상이 안 됨
    작업카피=커밋 설계는 퀄리티 컨트롤이 불가하다고 생각함
    커밋의 본래 의미는 꼭 의도된 것만 올리는 것인데, 이런 구조면 "쓰레기 커밋" 구분이 더 어려워짐
    git이나 jj 모두 대형 프로젝트에는 취약하고, 커밋 난립을 방지하지 못하는 점은 고쳐지지 않은 듯함
    jj가 실제로 어떤 문제를 푸는지 궁금함, 단순히 저자 취향의 프론트엔드인지 모르겠음

    • Piper 백엔드는 오히려 Git 백엔드보다 더 자연스럽게 돌아감
      jj 커밋은 git 커밋과 완벽하게 대응하지 않으니, 오해할 필요 없음
      실제로 “커밋”이라 하면 “이름 붙은 diff” 개념이고, 푸시 전 변경은 언제든 쉽게 갈아엎어 정리할 수 있음
      git에서 리베이스, 히스토리 편집보다 훨씬 편함
      나는 실험, 문서 등 여러 커밋을 작업 중간에 만들고, git이었다면 stash나 임시 브랜치에 억지로 넣었어야 했음

    • jj는 git 프론트엔드 이상임
      버전 컨트롤 시스템이고, backend-agnostic함
      대표 backend가 git이라 바로 기존 repo에서 전환 가능함
      나는 git을 github 나오기 전부터 썼던 유저지만, jj 쓰다 다시 git으로 못 돌아가겠음
      jj는 더 단순하면서도 강력함
      working copy=commit은 실제로 “index도 하나의 커밋이다” 식으로 이해해야 함
      예를 들어 feature x 작업 시작시 jj new -m "working on feature x" trunk로 새 커밋 만들고, 그 위에 비어있는 커밋 하나 더 얹음
      작업물은 워킹 카피(@)에 들어가고, 이전 커밋(@-)으로 “옮기기(squash)”해서 git의 add-p, reset 등 복잡한 옵션 대신 커밋 간 diff로 모든 걸 처리함
      이 구조 덕에 git index보다 유연하고 강력하게 커밋을 분할·정리할 수 있음
      커밋 난립 문제는 pull request 문화에 더 가깝고, jj도 일정 부분만 해결해줄 수 있음

    • working copy가 깃허브에 무작정 푸시되는 건 아니고, 커밋 설명 붙일 때 리뷰/정리하면 됨

  • jj를 며칠 써봤지만, 기존 lazygit 및 내 워크플로우, 스크립트 셋업에 충분히 만족하고 있음
    jj가 참신하고 괜찮긴 한데, 이제 막 버전 관리 시작하는 입장 아니면 굳이 바꿀 동기가 부족함

    • GitButler처럼 다른 도구 쓰면 프론트엔드가 덜 중요한데, 며칠 전 Jujutsu 도입해서 Claude에게 주요 동작(커밋, 브랜치 이동, 깃허브 푸시/풀) 묻고 10분 만에 숙달됨
      여전히 Lazygit의 diff는 쓰지만 detached HEAD 상태로 있어도 전혀 문제 없음
      JJ는 git과 잘 호환되고, 복잡한 커맨드를 외울 필요 없이 훨씬 쉽게 모든 걸 처리해줌
      브랜치 간 이동 때 미커밋 파일이 자동으로 같이 움직이는 건 최고의 기능임
      개발, 버그 수정, 카피 변경 등 오가며 작업하기 매우 수월함
      AI 에이전트가 변경 작업하면 worktree 분리해 쓰면 됨
      작업 완료 전에 변경 설명(=커밋 메시지) 붙여서 트리에서 미리 볼 수 있는 것도 정말 좋음
      JJ는 전반적으로 상당히 훌륭함