stakk
stakk는 Jujutsu의 북마크를 GitHub 또는 Forgejo의 스택형(stacked) 풀 리퀘스트로 변환합니다.
북마크가 필요한 스택을 선택하고, stakk는 각 북마크당 하나의 PR을 푸시하고 유지 관리합니다:
- 올바른 베이스 브랜치 설정
- 모든 PR에 대한 스택 개요 제공
- 재실행 시 중복 방지
이는 GitHub의 네이티브 스택형 풀 리퀘스트와 함께 작동합니다: --native-stacks auto 옵션을 사용하면 GitHub가 스택 자체를 렌더링하고 스택 병합 시 PR을 재대상화(retargets)합니다.
jj는 커밋과 북마크 관리를 담당하며, stakk는 해당 상태가 포지(forge)에 존재해야 할 때만 작동합니다. 따라서 git을 호출하지 않으며, 모든 작업은 jj를 통해 이루어지므로 워크스페이스와 비연속적인 리포지토리도 문제없이 작동합니다.
Interactive stakk submission flow
설치 (Installation)
PATH에 jj CLI가 설치되어 있어야 하며, 버전은 0.39.0 이상이어야 합니다.
mise use -g 'github:glennib/stakk' # 권장 방식
mise use -g 'cargo:stakk' # crates.io에서
cargo binstall stakk
...
또는 최신 릴리스에서 바이너리를 다운로드할 수 있습니다.
빠른 시작 (Quick start)
stakk # TUI(터미널 사용자 인터페이스)에서 스택을 선택하고 북마크를 할당합니다.
stakk graph # 스택과 해당 변경 ID를 보여줍니다 (오프라인).
...
--dry-run은 계획만 출력하고 중단하며, 어떤 북마크도 생성되지 않고, 아무것도 푸시되지 않으며, GitHub에 아무것도 기록되지 않습니다.
stakk --help와 stakk <하위 명령어> --help는 플래그 참조 가이드입니다.
stakk docs는 docs/ 디렉토리에 있는 문서를 바이너리에 번들링하여 출력합니다.
스태킹 작동 방식 (How stacking works)
선형 체인을 형성하는 북마크가 하나의 스택을 이룹니다:
○ feat-ui ← leaf
○ feat-api
○ feat-auth
...
세 가지 모두를 제출하면 (TUI에서 또는 stakk submit --keep feat-auth --keep feat-api --keep feat-ui와 같이), stakk는 각 북마크를 푸시하고, 그 아래에 있는 북마크를 기반으로 각 북마크당 하나의 PR을 생성하거나 업데이트합니다: feat-auth → main, feat-api → feat-auth, feat-ui → feat-api. 각 PR은 자신의 diff만 보여줍니다.
북마크되지 않은 커밋도 PR이 될 수 있습니다.
TUI에서는 각 커밋이 기존 북마크 [x], 커밋에서 파생된 이름 (TF-IDF)의 [~], 유형화된 [>], 생성된 stakk-<change_id>의 [+], --bookmark-command로부터 온 [*] 및 건너뛰기([ ])를 순환합니다.
--auto-prefix는 파생된 이름에 접두사(예: gb-caching-database)를 붙입니다.
GitHub 네이티브 스택 (GitHub native stacks)
--native-stacks는 제출된 스택을 GitHub의 네이티브 스택형 풀 리퀘스트(public preview)에 등록합니다. 따라서 GitHub는 모든 PR에서 스택을 그리고, 나머지 PR들을 스택이 바닥부터 병합될 때 재대상화합니다.
모드: on(기능을 사용할 수 없을 경우 실패), auto(사용 가능한 곳에 등록하고, 그렇지 않은 곳은 건너뜀—예: GitHub Enterprise Server), none(아무것도 등록하지 않고 서버 측 스택을 제거함), 그리고 ignore(스택 API를 절대 건드리지 않음).
기본값은 이 기능이 public preview 상태이기 때문에 ignore이며, 나중에 마이너 릴리스에서 auto가 될 수 있습니다—이는 안정성 계약이 면제하는 유일한 기본값입니다.
네이티브 스택은 stakk가 어쨌든 유지하는 기반 브랜치 체인 위에 추가됩니다. 제출된 다른 부분은 변경되지 않습니다.
스택 정보 배치 (Stack info placement)
스택에 있는 모든 PR에는 stakk graph와 TUI처럼 stakk가 제공하는 스택 개요가 표시됩니다. 각 행은 순수한 PR 링크이며, GitHub는 여기에 PR의 실시간 제목과 병합 상태를 렌더링합니다:
Stack of 3 PRs merging into main
• Add the search UI #14 (top of stack)
...
--stack-placement는 이 정보가 어디에 위치할지 결정합니다: PR comment, PR body의 구분된 섹션, none(아무것도 작성하지 않고 있는 것을 제거함), ignore(아무것도 작성하지 않고 아무 것도 건드리지 않음), 또는 기본값인 auto-comment/auto-body. 이들은 comment/body처럼 작성되지만, 네이티브 스택이 적용되는 실행에서는 GitHub의 렌더링이 이를 대체합니다. 따라서 --native-stacks auto는 사용 가능한 곳에 네이티브 렌더링을 제공하고 다른 모든 곳에는 스택 코멘트를 제공하며, 둘 중 어느 것도 동시에 제공하지 않습니다.
comment와 body 간 전환은 자동으로 마이그레이션됩니다.
Mode 테이블 및 minijinja 템플링:
docs/template.md 또는 stakk docs template.
설정 (Configuration)
CLI 플래그가 STAKK_* 환경 변수를 덮어쓰고, 이는 저장소의 stakk.toml, 그리고 사용자 설정(~/.config/stakk/config.toml - Linux 기준)을 덮어씁니다.
remote = "origin"
pr_mode = "draft"
...
모든 키와 변수: docs/config.md 또는 stakk docs config.
GitHub Enterprise Server
github.com은 별도의 설정이 필요 없으며, 엔터프라이즈 호스트는 API 응답을 통해 첫 사용 시 인식됩니다.
이 확인 절차를 건너뛰려면 --host ghe.example.com=github, STAKK_HOSTS 또는 stakk.toml의 hosts에 한 번 매핑하거나 GitHub CLI의 GH_HOST를 사용할 수 있습니다. stakk는 https://<호스트>/api/v3와 통신합니다.
토큰은 GitHub CLI가 하는 것처럼 호스트별로 해결되므로, 엔터프라이즈 토큰이 github.com으로 전송되는 일은 없습니다.
설정 및 문제 해결: docs/auth.md 또는 stakk docs auth.
Forgejo
codeberg.org는 별도의 설정이 필요 없으며, 다른 모든 인스턴스는 API 응답을 통해 첫 사용 시 인식됩니다;
확인 절차를 건너뛰려면 --host git.example.com=forgejo, STAKK_HOSTS 또는 stakk.toml의 hosts에 한 번 매핑해야 합니다.
일반 http를 통한 host:port도 작동합니다: stakk는 원격 저장소 자체 스킴을 사용하여 <scheme>://<호스트>/api/v1와 통신합니다.
--forge forgejo (STAKK_FORGE, forge = "forgejo")는 한 번의 실행에 대해 검색(lookup) 과정을 건너뜁니다.
토큰은 FORGEJO_TOKEN에서 가져오며 다른 곳에서는 가져오지 않습니다.
--native-stacks는 GitHub 기능입니다: Forgejo에서는 auto와 none이 조용히 처리되며, 스택 댓글을 얻을 수 있습니다.
설정 및 문제 해결: docs/auth.md 또는 stakk docs auth.
비대화형 선택 (Non-interactive selection)
---keep, --new, --new-auto 및 --new-command
(-k, -n, -a, -c)는 TUI를 명시적인 선택으로 대체합니다: 모든 PR 경계가 커맨드 라인에서 이름 붙여지며, 모든 마크는 하나의 트렁크-투-팁(trunk-to-tip) 경로에 놓이고, 마크되지 않은 커밋은 그 위의 PR로 접히며, 가장 상위 마크 위에 있는 것은 제출되지 않습니다.
rev는 한 커밋을 지정하는 임의의 jj revset이며, 이는 @-, 북마크, 또는 stakk graph --format=json에서 가져온 변경 ID일 수 있습니다.
규칙 및 진단 코드(coding agents용): docs/agents.md 또는 stakk docs agents
(stakk docs agents >> AGENTS.md를 사용하면 귀하의 시스템으로 전달됩니다).
종료 코드 및 작동하는 Python 예제: docs/scripting.md 또는 stakk docs scripting.
JSON 스키마: docs/graph.md 또는 stakk docs graph.
PR 제목 및 본문
제목은 변경 설명의 첫 번째 줄이며, 본문은 나머지 부분입니다; 다중 커밋 세그먼트는 ---로 설명을 연결합니다.
하드-래핑된 산문(prose)은 단락으로 재배치되며, Markdown 구조는 있는 그대로 통과됩니다. 둘 다 PR 생성 시에만 작성되므로 GitHub에서 편집한 내용은 유지됩니다 — --sync-pr-content
(title, body, all) 옵션이 이를 업데이트하는 데 사용됩니다.
--trailers strip은 끝 부분의 Key: value 블록(Signed-off-by, Refs 등)을 제거합니다.
사용자 지정 북마크 이름
--bookmark-command는 표준 입력(stdin)에 세그먼트에 대한 JSON 설명을 가진 프로그램(sh -c, 또는 Windows에서는 cmd /C)을 실행하고 그 표준 출력(stdout)을 북마크 이름으로 사용합니다.
이는 [*] TUI 상태와 --new-command를 구동하며, JSON 스키마는 stakk submit --help에 있습니다.
불변 커밋
jj가 불변하다고 간주하는 커밋은 새로운 북마크를 가질 수 없습니다: 기본 북마크 revset은 immutable()을 제외하므로, stakk는 다시 볼 수 없는 PR을 생성할 것입니다.
TUI는 이러한 행(row)을 잠그고, --new <rev>는 stakk::selection::rev_immutable 오류와 함께 실패하며, stakk graph가 이를 표시합니다.
작업을 가변 커밋으로 옮기거나, 직접 북마크를 생성하고 --bookmarks-revset에서 ~ immutable()을 제거하십시오.
안정성
stakk는 Semantic Versioning을 따릅니다.
안정적인 부분(Stable): 서브 명령어, 별칭 및 플래그, STAKK_ 환경 변수, 설정 키 및 기본값, 두 개의 schema_version-처리된 JSON 문서(stakk graph와 --bookmark-command의 stdin), 그리고 종료 코드.
자유롭게 변경 가능한 부분(Free to change): --help 및 stakk docs 텍스트, 오류 문구, 진단 코드 세트, stakk graph의 보기 좋은 출력, stacks[]의 순서, TUI, 그리고 최소 jj 버전.
계약 사항: docs/stability.md 또는 stakk docs stability.
라이선스
MIT 또는 Apache-2.0