4P by GN⁺ | ★ favorite | 댓글 2개
  • Jujutsu는 소프트웨어 프로젝트의 코드 복사, 변경 추적, 변경 공개에 사용하는 버전 관리 시스템이며, 신규 사용자와 경험자, 개인 신규 프로젝트와 대규모 이력·팀을 모두 고려해 사용하기 쉽게 설계됨
  • 사용자 인터페이스와 버전 관리 알고리듬을 콘텐츠를 제공하는 저장 시스템과 내부적으로 분리하며, 현재는 Git 저장소를 저장 계층으로 사용해 Git 기반 도구와 호환됨
  • Git에는 커밋과 파일만 저장되고, bookmark(branch)와 기타 상위 메타데이터는 Git 외부의 커스텀 저장소에 저장됨
  • 기본 Git 백엔드는 gitoxide Rust 라이브러리를 사용하며, Git 원격 저장소에서 branch를 가져오고 원격으로 push할 수 있고, 일반 Git 커밋처럼 보이는 커밋을 생성함
  • 작업 복사본을 실제 커밋으로 표현하는 working-copy-as-a-commit 모델을 사용하며, 파일 변경은 일반 커밋으로 자동 기록되고 이후 변경마다 amend됨
    • dirty working copy 때문에 명령이 실패하지 않음
    • git stash가 필요하지 않음
    • 작업이 끝나기 전에도 작업 복사본 커밋에 커밋 메시지를 설정할 수 있음
  • 저장소의 모든 작업은 작업 이후 저장소 상태 스냅샷과 함께 기록되며, 이전 저장소 상태 복원, 작업 단위 undo, 최신 작업이 아닌 특정 작업의 revert가 가능함
  • 충돌을 커밋과 같은 일급 객체로 기록하며, 충돌이 발생한 작업도 성공하고 이후 단일 충돌 해결 워크플로로 처리 가능함
  • 커밋을 수정하면 기존 커밋의 모든 descendant가 새 커밋 위로 자동 rebase되며, 충돌 해결 결과도 descendant로 전파되고 rebased 커밋을 가리키는 bookmark와 작업 복사본도 업데이트됨
  • 명시적 index나 staging area가 없고, commit 선택에는 revset 언어를 사용하며, 출력 포맷은 사용자가 설정 가능한 template 언어로 처리함
  • 이력 재작성 기능으로 임의 커밋의 메시지를 편집하는 jj describe, 체크아웃 없이 커밋 변경을 편집하는 jj diffedit, 커밋 분할용 jj split, 변경 일부를 다른 커밋으로 옮기는 jj squash -i --from X --into Y를 제공함
  • 안전한 동시 복제 기능은 실험적 기능이며, Dropbox·rsync 같은 분산 파일 시스템 또는 백업 도구 사용 시 저장소가 손상 상태가 되지 않도록 설계되고, 최악의 경우 로컬·원격 상태 간 충돌 노출을 목표로 함
  • jj는 실험적 버전 관리 시스템이며, Git 호환성은 안정적이지만 작업 중인 기능, 최적이 아닌 UX, 특정 사용 방식에서의 워크플로 공백이 있을 수 있음
  • 기능은 상당히 완성된 상태지만 Git submodule 지원은 아직 완료되지 않았고, 여러 성능 버그가 있으며, 이메일 기반 워크플로의 네이티브 지원은 없음
  • 1.0.0 이전에는 워크플로 변경과 온디스크 형식의 하위 호환되지 않는 변경이 있을 예정이며, 형식 변경에는 투명 업그레이드나 요청 시 업그레이드 명령·스크립트 제공을 시도함
  • Apache 2.0 라이선스의 오픈소스 소프트웨어이며, Google의 지원 제품은 아니고 지원은 커뮤니티에서 제공됨

댓글과 토론

Jujutsu - 간단하고 강력한 Git 호환 DVCS

제가 1년 반전에 올렸는데, 다시 HN에서 이슈로 올라왔네요.

Hacker News 의견들
  • 여기 올라와서 반가움. 2~3주 전쯤 jj로 갈아탔고, 다시 돌아갈 생각이 안 듦. 머릿속 작업 방식은 많이 바꿔야 했지만 jj가 제공하는 흐름이 꽤 마음에 듦
    무엇을 커밋할지 따로 생각하는 시간이 사라지고, 모든 파일 변경이 자동으로 작업 사본 커밋에 반영됨. 물론 원치 않을 때도 있어서 커밋을 둘로 나누거나 옮기는 기능이 있고, 모든 작업이 커밋을 대상으로 동작한다는 점이 좋음
    jj log는 여러 브랜치의 전체 지도를 보기에 훌륭하고, 충돌은 일부만 해결한 뒤 다른 브랜치로 이동할 수 있으며, 축약된 changeset ID도 편함. 예를 들어 jj log에서 리베이스할 changeset을 보고 jj rebase -s qr -d master처럼 실행할 수 있어 브랜치 이름을 다 치는 것보다 빠름

    • 실수로 비밀값이 들어간 파일을 저장해서 자동으로 빨려 들어가면 어떻게 되는지 궁금함
    • 그냥 GitHub 저장소와 함께 쓰는 건지 궁금함
      Dropbox 같은 백엔드와 쓸 수 있다고 되어 있는데, IPFS와 쉽게 쓸 수 있는 시스템이 나오면 좋겠음. 대용량 데이터에서는 GitHub에 1TB를 저장할 수 없고, LFS는 유료라 제외하고 봄
      데이터셋을 쓰려는 사람은 어차피 로컬에 갖고 있으니, 다운로드 원천이 하나가 아니라 수천 개가 되는 IPFS가 자연스러운 해법임. 데이터 저장소에 IPFS를 쓴다면 바로 갈아타겠지만, 아니면 살펴볼 가치가 적다고 봄
    • 팀에서 성공적으로 쓰고 있는 사례가 있는지 궁금함. 두 사람이 같은 브랜치에서 작업하면 어떤 느낌인지 알고 싶음
  • Jujutsu는 작성자의 개인 프로젝트로 시작했고, 지금은 Google에서 작성자의 전업 프로젝트가 됨. Git Merge 2022에서 발표된 적 있음
    Jujutsu: A Git-Compatible VCS - Git Merge 2022:
    Video:
    https://youtu.be/bx_LGilOuE4
    Slides:
    https://docs.google.com/presentation/d/1F8j9_UOOSGUN9MvHxPZX...

    • 개인 프로젝트가 Google에서 전업 프로젝트가 됐다니 꽤 뿌듯할 듯함
  • 거의 1년 동안 jj를 매일 써왔고, Git 사용자 경험보다 확실히 훨씬 낫다고 봄. 변경을 원자적 커밋으로 나누는 데 예민한 편이라, 자동 리베이스가 핵심 기능임
    충돌을 커밋에 기록할 수 있어서 Git이나 Mercurial처럼 리베이스 중간에 멈춰 충돌을 고칠 필요가 없음. 커밋을 수정하거나 삭제해도 jj가 모든 후손 커밋을 자동으로 리베이스해 주고, Git rebase와 달리 Mercurial evolve처럼 여러 자식도 처리함
    커밋 이력을 다루는 기본 명령도 좋음. jj move|restore로 한 커밋의 변경을 다른 커밋으로 옮기거나 복사하고, jj split으로 커밋을 쪼개고, jj rebase로 커밋을 이동함. 작업 트리나 인덱스 없이 모든 것이 커밋 이력 안에 있어서 같은 명령과 플래그로 처리 가능함
    작업 로그도 훌륭해서 대부분의 작업을 문제없이 되돌릴 수 있음. Git에서 나쁜 rebase나 commit --amend를 고치려면 reflog에서 맞는 커밋을 뒤지고 ref를 수동으로 고쳐야 하는 것과 대비됨
    가장 불편한 점은 자동 작업 사본 커밋이 원치 않는 파일까지 커밋하려 할 때가 있다는 것과, 이름 변경 감지가 없어서 병합을 Git만큼 우아하게 처리하지 못한다는 것임. 그래도 깨진 커밋은 jj split|restore로 비교적 쉽게 고칠 수 있고, jj 개발자들도 이름 변경 문제를 고민 중임

  • 작업 결과 충돌이 나도 그 정보를 커밋에 기록하고 작업은 성공시키며, 나중에 충돌을 해결할 수 있다는 점이 반가움. 지난 10년 정도 협업 편집 알고리즘을 다뤄왔고, 이상적으로는 Git 같은 도구가 결국 CRDT 기반 접근으로 대체되면 좋겠음
    CRDT를 쓰면 같은 도구로 페어 프로그래밍을 할 수 있고, Git에서 생길 수 있는 자기 충돌 같은 복잡한 병합도 더 잘 다룸. 더 강력한 모델이기도 함
    다만 현대 텍스트 CRDT는 동시 편집을 자동으로 충돌 없이 해결하는데, 오프라인으로 코드 협업을 할 때는 보통 충돌이 드러나서 사람이 직접 해결하길 원함. CRDT는 Git보다 편집 이력 정보를 더 많이 갖고 있으니 이론상 가능하지만, 제대로 하려면 충돌 자체를 텍스트 파일의 데이터 모델에 넣어야 할 듯하고, 현대 편집기와 어떻게 맞물릴지는 잘 모르겠음
    jj가 같은 요령을 찾아낸 것처럼 들려서 실제로 얼마나 잘 동작할지 기대됨. CRDT 기반 코드 저장소라는 꿈에 한 걸음 가까워진 느낌임

    • Pijul을 살펴보면 좋겠음. 여기서 말한 대부분을 사실상 구현하고 있음. Pijul은 CRDT인 패치 위에서 동작하고, 충돌을 1급 개념으로 다룸
    • git bisect에서 가치를 느껴본 적이 없는지 궁금함
      재현 가능한 버그가 있고 원인이 복잡하다면, 어떤 커밋이 버그를 도입했는지 찾아서 어떤 변경이 원인인지 보는 게 유용하지 않나 싶음. 적어도 무엇을 고쳐야 할지 첫 감을 잡는 데 좋음
      현재 git bisect는 모든 커밋이 빌드 및 실행 가능할 때 가장 잘 동작함. 충돌 표시가 들어 있어 빌드나 실행이 안 되는 커밋이 있으면 훨씬 많은 수동 개입이 필요해짐
      이런 시나리오에서 git bisect에 해당하는 기능을 어떻게 적응시킬 수 있을지 궁금함. 단순히 충돌 표시 문자열을 스캔하는 것은 적절하지 않을 수 있음. 문서에서 충돌 표시를 설명하거나, 어떤 마크업 언어에서는 =======가 밑줄로 합법적으로 쓰일 수 있기 때문임
    • 실제로는 어떻게 전개될지 궁금함
      소스 관리 이력이 의미 있는 산출물이고, 패치 묶음이 개발 머신을 떠나기 전에 점진적이고 원자적인 변경의 연속으로 정리돼야 한다는 생각과 충돌하는 것처럼 보임
      다만 주변 개발자 대부분은 이미 Git 이력을 무한 편집기 실행 취소 이력처럼 다루고 있어서, 이 접근은 그 사실을 굳혀버릴 것 같기도 함
      장기적인 이력이 어떻게 동작한다고 보는지, 지금보다 더 유용할지 덜 유용할지 궁금함
  • 작업 사본이 자동 커밋된다는 건 처음에는 좋아 보이지만, 좋지 않은 상황이 많음
    새 산출물 파일이 생겼는데 아직 .gitignore에 넣기 전이면 자동 커밋되고, 한 브랜치에서 무시 파일을 추가한 뒤 다른 브랜치로 전환하면 작업 사본에는 남아 있지만 .gitignore에는 없어서 자동 커밋될 수 있음
    또 나중에 커밋을 쪼개는 것보다, 일부 파일만 스테이징해서 커밋하는 편이 훨씬 쉬움

    • 일부 파일만 스테이징해서 커밋하는 게 나중에 커밋을 쪼개는 것보다 쉽다는 통념에 이 프로젝트가 도전하는 것으로 봄
      나도 그 생각이 머릿속에 박혀 있지만, 정말 맞는지는 모르겠음. 실제로는 인덱스를 고치고 사후에 커밋을 amend하는 일이 꽤 잦고, 사전에 할 수도 있음
      어차피 사후 편집을 완전히 피할 수 없다면, 이런 편집을 위한 단일 작업 흐름이 더 낫지 않을까 싶음. 아직 써보진 않았지만, 당연시하던 관습이 실제로 도움이 안 될 수도 있다는 점을 꽤 그럴듯하게 찌르는 접근으로 보임
    • 같은 생각임. 보통 프로젝트 디렉터리에 출력 파일, 메모, 일회성 스크립트 같은 추가 파일이 10개 이상 있음. 커밋에 파일을 넣을 때는 항상 파일명으로 고르지, 새로 생기거나 바뀐 모든 것을 넣지는 않음
      모든 생성·수정 파일이 항상 커밋에 들어가는 사용 사례는 내게 없음
      다른 브랜치로 바꿨을 때 파일이 작업 사본에 남지만 .gitignore에는 없는 건 Git의 실패라고 봄. .gitignore에 더해지는 .local.gitignore 같은 게 있어야 함. 나한테만 필요한 무시 파일은 매우 흔하고 프로젝트의 .gitignore에 들어갈 성격이 아님. 방법은 있지만 다 어색하니, 기본으로 간단히 제공돼야 함
    • 첫 번째 문제는 이미 추적 중인 파일과 새 파일을 쉽게 비교하면 되지 않나 싶음
      그래도 흥미로움. Git의 스테이징을 좋아한 적은 없지만 여기서 말한 경우는 겪어보지 않아서, 파일 시스템과 커밋 사이에 중간 단계가 필요하다는 걸 이제야 이해함
    • README만 읽어본 바로는, 그런 파일을 .gitignore에 추가하면 다음 자동 커밋 때 익명 작업 사본 커밋에서 다시 빠지는 구조로 이해함
      파일이 애초에 추가되지 않는 대신 익명 작업 사본 커밋에 들어갔다가 빠지는 흐름은 직관적이지 않지만, 그 익명 커밋이 대부분 사용자에게 보이지 않는다면 차이는 없을 듯함
    • 이런 것들이 jj 설계에서 왜 문제가 되는지 잘 모르겠고, 일부 파일을 스테이징하는 게 나중에 커밋을 쪼개는 것보다 왜 쉬운지도 잘 모르겠음
      문서를 보면 걱정하는 여러 경우가 명시적으로 다뤄져 있음:
      https://github.com/martinvonz/jj/blob/main/docs/git-comparis...
  • 몇몇 특수한 경우를 빼면 몇 년째 명령줄에서 Git을 거의 쓰지 않음. 일상적으로는 IntelliJ 같은 IDE 내장 통합에 의존하고, 왜 굳이 수동으로 감수하는지 이해하기 어려움
    에디터 안에서 줄 단위로 골라 부분 커밋을 할 수 있고, 모든 브랜치를 보고 병합하고 cherry-pick하고, 커밋하거나 amend하고, 업데이트를 pull하고, 태그를 편집하는 걸 단축키로 한 번에 처리함
    다만 여기서는 내가 소수인 듯함. Git이 필수 기술이라 진짜 프로그래머는 눈 감고 명령을 칠 수 있어야 한다는 식의 분위기까지 고려하면 더 그렇고, 왜 그런지 궁금함

    • 언제나 버전 관리 시스템은 명령줄로 다루는 걸 선호했고 앞으로도 그럴 것임
      이 기술은 환경을 가리지 않아 원격 머신에 접속해 저장소를 보는 것도 로컬과 같고, 편집기마다 VCS 연동 방식을 새로 배울 필요도 없으며, 익숙한 도구를 그대로 쓸 수 있음
      예로 든 작업들은 명령줄에서도 똑같이 쉽게 가능해서 편집기 통합이 특별하다고 보지 않음. reflog를 만지는 식의 이상하고 고급 작업이 필요하면 결국 명령줄을 꺼내야 할 가능성이 큼
      물론 GUI를 쓰는 사람에게 불만은 없음. 도구로 생산적이면 판단할 일은 아니지만, 왜 그런지 물었으니 답한 것뿐이고 내 방식이 더 낫다고 주장하는 건 아님
    • IDE 통합은 보통 Git CLI의 전체 기능을 구현하지 않는다는 경험이 있음. 나아졌을 수는 있지만, 기본 clone/branch/commit/merge를 넘어 개발자와 브랜치가 조금만 늘어나도 결국 문제 해결에는 Git CLI로 돌아가게 됐음
    • 진짜 프로그래머인지는 모르겠지만, Git GUI가 잘못된 일을 할지도 모른다는 비합리적인 두려움이 있음. IntelliJ에서도 Git은 내장 CLI를 열어 다룸. 오래된 습관은 잘 안 죽음
    • Git을 막 쓰기 시작한 많은 사람은 Git이 어떻게 동작하는지, 즉 커밋과 브랜치가 무엇이고 무엇을 할 수 있는지 이해하지 못함. 그러고는 CLI 도구 탓을 하며 GitHub Desktop을 쓰면 모든 게 이해될 거라 기대함
      사람들이 “Git CLI를 배워야 한다”고 말하는 가장 흔한 맥락이 이 경우임
      며칠 전에도 Git 명령을 배우지 않으려고 GitHub Desktop을 쓰자는 예가 있었음: https://www.reddit.com/r/learnprogramming/comments/15b7pra/s...
    • 팀에서 Git을 이해하는 사람은 두 부류뿐임. CLI를 쓰는 사람과, Git을 이해하지 못한 채 버튼만 누르기 시작하는 사람임
  • Git 호환성을 먼저 내세우는 접근 덕분에 Jujutsu가 지금까지 본 것들 중 Git 대체 후보로 더 강해 보임
    Git 호환성 설명을 읽고 궁금했던 건, Jujutsu 사용자가 GitHub 등에 호스팅된 Git 저장소를 jj로 접근하는 사용 사례에 주로 초점을 맞춘 듯하다는 점임. 반대로 네이티브 Jujutsu 저장소를 Git으로 접근하는 방식도 지원하는지 궁금함
    대부분의 개발자는 이미 Git CLI에 익숙하니, 실제 운영에서는 같은 코드베이스에서 jj와 Git을 함께 쓰는 개발자가 나올 것 같음. 아니면 현실적인 운영 시나리오는 양쪽 CLI 접근을 위해 항상 네이티브 Jujutsu 데이터베이스가 아니라 Git을 백엔드 저장소로 쓰는 것인지 궁금함

    • README 각주에 따르면, 현재는 네이티브 백엔드를 쓸 실질적인 이유가 거의 없음
      이 백엔드는 주로 나중에 Git 백엔드에 쉽게 추가할 수 없는 기능을 넣을 수 있음을 보장하기 위해 존재함
    • 항상 Jujutsu를 Git 저장소의 프런트엔드로 쓰거나, 완전한 Jujutsu 기반 원격 저장소를 쓰는 기대가 있을 것 같음
      이미 Jujutsu를 쓰는 프로젝트에서 작업하고 기여하려면, 프로젝트가 내 작업 흐름에 맞추는 게 아니라 내가 프로젝트에 맞추는 게 합리적임
  • Git 호환성 우선 접근 덕분에 Jujutsu가 지금까지 본 Git 대체 후보 중 더 강해 보임
    충돌 관리가 궁금함. pmeunier가 Pijul을 위해 패치 이론을 형식적으로 정리하는 데 많은 신경을 쓴 걸 알고 있고, 건전하지 않거나 문제가 있는 패치·충돌 개념은 큰 문제로 이어질 수 있음. Darcs의 성능 문제가 그렇게 생겼다고 하지 않나 싶음
    저장소 위키의 비교 페이지가 Pijul의 충돌 처리가 “비슷하다”는 수준보다 조금 더 자세히 설명해 주면 좋겠음

    • 여기 조금 더 자세한 설명이 있음: https://github.com/martinvonz/jj/blob/main/docs/technical/co...
      이런 방식으로 충돌을 기호적으로 저장하면 나중에 충돌을 재현하고 특정 충돌은 자동 해결할 수도 있지만, 실제 충돌 내용 자체를 해결하는 문제까지 다루지는 않음
      누군가 구현한다면 Pijul을 jj 백엔드로 써서 양쪽 장점을 모두 얻을 수도 있을 것 같음
  • rsync, Dropbox, 분산 파일 시스템을 통한 안전한 복제라니 좋음. 요즘은 점점 단순 동기화 친화적인 시스템 쪽으로 기울고 있음
    어디에든 아무 도구로나 던져놔도 그냥 동작하기 때문임. 새 도구가 이런 방향을 취하는 건 언제나 반가움

    • 이 부분을 더 설명해 줄 수 있으면 좋겠음
      이런 문제가 있다는 건 들어봤지만 직접 겪어보지는 못함. Git과 rsync/Dropbox 같은 도구 사이에 어떤 경쟁 조건이 생겨 문제가 되는지 궁금함
  • 작업 사본이 자동으로 커밋된다니 다행임. 오래전부터 필요했던 기능임
    우아한 도구를 만들기 위해 힘을 쏟은 Martin에게 박수를 보냄