jj 시작하기
원문은 Ellie Huxtable님이 에 게재했습니다. 이 블로그 구독하기
지난 몇 주 동안 jj를 써 왔다! 처음 써보는 건 아니지만, 이번에야 비로소 정착했다.
수년 동안 내 git 워크플로우는 브랜치에서 무언가를 고친 뒤 git commit --amend --no-edit && git push --force-with-lease를 실행하는 방식이었다. 이렇게 하면 변경 사항이 거의 지연 없이 원격에 바로 반영됐다. PR은 보통 커밋이 1개, 많아도 몇 개를 넘지 않았고, 최대한 작게 유지하려 했다.
에이전트와 함께 작업하면서부터는 브랜치를 훨씬 더 자주 옮겨 다니게 됐다. 그러다 보니 git stash를 쓰거나, 변경 사항이 서로 겹치지 않게 하려고 별 의미 없는 WIP 커밋을 만들어야 했다.
그때 등장한 새로운 주인공이 바로 jj다! 여기서는 모델이 조금 다르다. 내가 대충 끄적인 노트보다 훨씬 잘 쓰인 훌륭한 매뉴얼이 이미 많으니, 장황한 매뉴얼을 직접 쓸 생각은 없다.
간단히 말해, 가장 마음에 드는 점은 내 변경 사항이 항상 커밋된다는 것이다. 모든 편집이 가장 최근 커밋을 자동으로 amend하고, push하면 원격을 덮어쓴다(혹은 jj 식으로 말하면 "옆으로" 이동시킨다).
change를 수정하는 것도 쉽다. checkout이나 rebase 같은 번거로운 과정이 필요 없다. 마치 내가 선호하던 git 워크플로우를 그대로 가져다 도구로 만들어 놓은 것 같다. 왜 진작 깨닫지 못했는지 모르겠다.
그냥 떠오르는 대로 적어본 글이다. 더 배우게 되면 노트를 더 정리해 올릴 생각이다.
워크플로우
무언가를 변경할 때 내 워크플로우는 이렇다
jj new main
<do some coding>
jj describe -m 'feat: something really cool'
jj git push -c @끝. PR을 머지하고 반복하면 된다.
jj에서는 커밋보다 change라는 말을 더 많이 쓴다. change는 끊임없이 진화하는 커밋이다. 그리고 "@"는 현재 change를 가리킨다
새로운 change 시작하기
작업을 시작하기 전에 change를 하나 만들어야 한다. 앞으로 하게 될 모든 편집은 여기에 담긴다
jj new main이렇게 하면 main(북마크 main이 붙은 커밋) 위에 커밋이 만들어진다(change와 commit의 구분은 실제로 존재하고, 처음에는 헷갈린다). 현재 change의 자식으로 새로운 change를 만들고 싶다면 그냥 jj new를 실행하면 된다.
change에 설명 붙이기
아마 스테이징 영역에 변경 사항을 추가한 뒤 메시지와 함께 커밋하는 방식에 익숙할 것이다. jj에서는 변경 사항이 이미 추가되어 있다. 다만 change에 설명(커밋 메시지 같은 것)이 없을 뿐이다!
jj describe -m 'hello i am a message'change를 만들 때 바로 설명을 붙일 수도 있다
jj new -m "hello i am a message"커밋을 새 브랜치로 푸시하기
어떤 change 위에 있고, 마음에 들어서 GitHub에 올려 에이전트가 당신의 (사실은 Claude의) 코드를 신랄하게 비판하게 하고 싶다면?
간단하다.
jj git push -c @즉 "git을 이용해 현재 커밋을 푸시하라"는 뜻이다. 자동으로 브랜치를 만들고 원격으로 푸시한다. 변경을 하면서 이 명령을 계속 반복해도 되고, jj의 마법이 자동으로 git amend와 force push로 변환된다.
그래도 jj가 자체 프로토콜과 호스트를 갖게 될 날이 기대된다.
커밋 수정하기
기존 change로 돌아가 수정하고 싶다면? 쉽다
jj edit <change-id>이쯤부터 진짜 강력하다는 느낌이 들기 시작하는데, 동시에 내가 기존에 갖고 있던 멘탈 모델이 깨지기 시작하는 지점이기도 하다. checkout이나 rebase 같은 걸로 삽질할 필요가 전혀 없다.
jj에는 change와 commit이 모두 있다. 스테이징 영역을 두는 대신 커밋을 계속 진화시킨다는 점을 떠올리면, change를 안정적인 ID로, commit ID를 편집할 때마다 바뀌는 ID로 생각할 수 있다
되돌리기
jj에서 하는 거의 모든 작업은 op log에 저장된다. 뭔가를 하다가 망쳤다고? jj undo가 구해줄 것이다.
그 밖의 git 관련 기능
jj는 아직 대부분 git 위에서 동작한다. 기존 레포를 변환하기도 쉽고, GitHub과의 연동도 잘 된다
# Create a jj repo inside of a git repo
jj git init
# Fetch from the remote (github etc)
jj git fetch
# Push
jj git push
# Clone
jj git clone그럼 브랜치는 어디에?
없다! 적어도 당신이 익숙한 그런 브랜치는 없다. jj는 "북마크"를 사용한다. 커밋에 붙일 수 있는 문자열이다. change를 푸시하면 자동으로 북마크를 만들어 준다 - 예를 들면 push-refrefref 같은 식이다
# bookmark the current change with a name
jj bookmark create <name>
# move a bookmark to a new commit
jj bookmark set <name> -r <commit>
# other things exist just use --help내가 가장 답답하게 느끼는 점은 새 change를 만들어도 북마크가 따라 움직이지 않는다는 것이다.
용어집에 따르면
Git과 달리 "현재 북마크"라는 개념은 없다. 새 커밋을 만들어도 북마크는 이동하지 않는다. 다만 커밋이 재작성되면 북마크는 자동으로 그 커밋을 따라간다.
리베이스나 수정 같은 재밌는 것들에 대해서는 나중에 따로 정리하겠다
참고: 이 글을 Vim에서 쓰는 게 엄청 짜증났다. jj를 <esc>에 바인딩해 놨기 때문이다.
글을 무작위로 읽기
댓글
로그인하고 댓글 남기기