- clonecoding-agentforkpisession-branchtree
pi coding agent: fork, clone, tree 명령어 가이드
- 1. Fork vs Clone: 두 명령어의 차이
- - 한눈에 비교
- - Fork: "그 질문을 그 시점에서 다시 해보자"
- - Clone: "지금까지 결과를 복제해서 다른 방향으로"
- - Fork vs Clone 결정 가이드
- 2. Tree: 세션 파일 안에서 분기 탐색하기
- - Tree 개요
- - Leaf 개념
- - Tree 노드 선택 동작: user vs assistant의 차이
- - Branch Summary: 브랜치 요약
- - Compaction과 Tree
- - Tree 요약
- 3. 세 명령어 종합 비교
- 4. fork, clone, tree 활용 전략
- - 여러 접근법 시도: 직렬 vs 분기
- - 추천: 하이브리드 전략
- 5. 마치며
pi를 사용하다 보면 "이전에 했던 질문을 다시 해보고 싶다"거나 "지금까지 한 작업을 유지한 채 다른 방향으로 실험해보고 싶다"는 상황이 생깁니다. pi coding agent는 터미널 기반 코딩 에이전트로, 이럴 때 사용하는 명령어가 /fork, /clone, /tree입니다.
이 세 명령어는 이름은 비슷해 보이지만, 동작 방식과 복사 범위가 완전히 다릅니다. 이 글에서 각각의 차이점을 정리합니다.
1. Fork vs Clone: 두 명령어의 차이
한눈에 비교
| 항목 | /fork | /clone |
|---|---|---|
| 실행 방식 | 사용자 메시지(프롬프트) 선택기가 열림 | 즉시 실행 (선택 과정 없음) |
| 복사 범위 | 선택한 프롬프트의 parent까지 | 현재 leaf까지 전체 경로 |
| 실행 결과 포함? | ❌ 미포함 (프롬프트 실행 전 상태로 복사) | ✅ 포함 (모든 assistant 응답, 도구 결과 등) |
| 편집기 상태 | 선택한 프롬프트가 입력됨 (수정/재실행 준비) | 비어있음 (새로 입력) |
| 출력 | 새 세션 파일 | 새 세션 파일 |
| 의도 | "예전 그 질문을 다시 할게" | "지금까지 결과를 복제해서 새 출발" |
Fork: "그 질문을 그 시점에서 다시 해보자"
/fork는 과거에 보냈던 프롬프트(사용자 메시지)를 선택하면, 그 프롬프트를 실행하기 직전 상태까지의 세션 히스토리를 새 파일로 복사합니다.
원본 세션:
[root] "로그인 구현해줘"
assistant: (코드 작성)
user: "테스트 추가해줘" ← 이 프롬프트를 선택
assistant: (테스트 코드 작성) ← ❌ 복사 안 됨
user: "좀 더 수정해줘" ← ❌ 복사 안 됨
/fork 실행 후 새 세션:
[root] "로그인 구현해줘" ✅ 복사됨
assistant: (코드 작성) ✅ 복사됨
──────────────────────────────
"테스트 추가해줘" ← 편집기에 입력만 (실행 전)즉, 선택한 프롬프트 이후의 모든 대화(assistant 응답, 도구 실행 결과 등)는 버려지고, 프롬프트 내용만 편집기에 넣어줍니다. 사용자가 내용을 수정하거나 그대로 Enter를 누르면 실행됩니다.
Clone: "지금까지 결과를 복제해서 다른 방향으로"
/clone은 현재 세션의 전체 활성 경로(root에서 현재 leaf까지)를 그대로 새 파일에 복사합니다.
원본 세션 (현재 leaf 위치):
[root] "로그인 구현해줘"
assistant: (코드 작성)
user: "테스트 추가해줘"
assistant: (테스트 코드 작성) ← 현재 leaf
user: "좀 더 수정해줘" ← 아직 입력 안 함
/clone 실행 후 새 세션:
[root] "로그인 구현해줘" ✅ 복사됨
assistant: (코드 작성) ✅ 복사됨
user: "테스트 추가해줘" ✅ 복사됨
assistant: (테스트 코드 작성) ✅ 복사됨 (leaf까지 전체)
──────────────────────────────
(빈 편집기) ← 새로 입력 시작실행 결과(assistant 응답, 도구 호출 출력 등)까지 모두 포함되며, 편집기는 빈 상태로 새 프롬프트를 기다립니다.
Fork vs Clone 결정 가이드
| 상황 | 사용할 명령어 |
|---|---|
| "아까 그 질문을 다른 방식으로 다시 해보고 싶어" | /fork |
| "저번에 시도했던 접근법을 약간 바꿔서 재시도" | /fork |
| "지금까지 작업을 백업하고 새로운 방향 실험" | /clone |
| "결과는 좋았는데, 여기서부터 다른 기능 추가" | /clone |
| "opencode의 --fork 같은 기능이 필요해" | /clone (pi의 fork는 opencode fork와 달라요) |
중요: pi의
/fork와 opencode의--fork는 이름만 같고 동작이 완전히 다릅니다. pi의/fork는 "프롬프트 재실행" 개념이고, opencode의--fork는 pi의/clone에 가깝습니다.
2. Tree: 세션 파일 안에서 분기 탐색하기
/tree는 fork나 clone처럼 새 파일을 만들지 않고, 같은 세션 파일 안에서 leaf 포인터만 이동합니다.
Tree 개요
| 항목 | 내용 |
|---|---|
| 실행 방식 | /tree 입력 → 트리 뷰 열림 → 노드 선택 |
| 파일 영향 | 같은 세션 파일 (새 파일 생성 ❌) |
| 변경되는 것 | leaf 포인터만 이동 (현재 위치 변경) |
| LLM 컨텍스트 | 오직 leaf → root 경로의 메시지만 LLM에 전달 |
| 브랜치 요약 | 브랜치 이동 시 BranchSummary를 남길 수 있음 |
| 사용 의도 | 같은 파일 안에서 여러 대안을 트리 구조로 탐색 |
Leaf 개념
Leaf는 세션 트리에서 현재 활성화된 노드(포인터)입니다. 언제나 하나만 존재합니다.
각 노드는 ID(역할) 형식으로 표시됩니다. a1, a2 등은 세션 파일 내 8자리 헥스 ID의 앞부분을 간략히 표현한 것입니다.
/tree로 선택한 노드로 leaf가 이동getLeafId()로 현재 leaf 조회 가능
Tree 노드 선택 동작: user vs assistant의 차이
/tree에서 어떤 타입의 노드를 선택하느냐에 따라 동작이 달라집니다.
| 선택한 대상 | leaf 이동 | 편집기 상태 | 선택한 메시지가 컨텍스트에 포함? |
|---|---|---|---|
| user 메시지 | 해당 user의 parent로 이동 | 선택한 내용이 입력됨 (실행 전) | ❌ 미포함 (Enter로 전송해야 포함) |
| assistant 메시지 | 해당 assistant로 이동 | 비어있음 | ✅ 포함 (leaf 경로에 속함) |
| compaction entry | 해당 compaction으로 이동 | 비어있음 | ✅ 포함 (compaction 요약) |
| 도구 호출/결과 | 해당 entry로 이동 | 비어있음 | ✅ 포함 |
| branch_summary | 해당 summary로 이동 | 비어있음 | ✅ 포함 (요약된 정보) |
User 메시지 선택 예시
선택 전:
a1(user) ─ a2(assistant) ─ a3(user) ─ a4(assistant) ← 현재 leaf
/tree에서 a3(user) 선택:
1. leaf가 a2(assistant)로 이동 (a3의 parent)
2. a3의 내용이 편집기에 입력됨
3. 아직 LLM에 전송 안 됨 (편집기에만 있음)
현재 LLM 컨텍스트: a1, a2 ← leaf(a2)까지의 경로
Enter 전송 후:
a1 ─ a2 ─ a3(user) ─ a7(새 응답) ← 새 브랜치Assistant 메시지 선택 예시
선택 전:
a1(user) ─ a2(assistant) ─ a3(user) ─ a4(assistant) ← 현재 leaf
/tree에서 a2(assistant) 선택:
1. leaf가 a2로 이동
2. 편집기는 비어있음
3. 사용자가 새 프롬프트 입력 가능
현재 LLM 컨텍스트: a1, a2 ← leaf(a2)까지의 경로 (a3, a4는 경로에서 제외)
Enter 전송 후:
a1 ─ a2 ─ a5(새 user) ← 새 브랜치 (a3, a4는 다른 브랜치가 됨)의미:
- user 메시지 선택 = "그 질문을 다시 할게" (결과는 버리고 프롬프트만 재사용)
- assistant 메시지 선택 = "여기까지는 좋았으니, 이 시점에서 계속 진행할게" (기존 진행 상황 유지)
Branch Summary: 브랜치 요약
/tree로 다른 브랜치로 이동할 때, 떠나는 브랜치의 내용을 LLM이 요약해서 BranchSummaryMessage로 남길 수 있습니다.
/tree 실행 → 브랜치 B 선택
선택하세요:
1. 요약 없음
2. 기본 프롬프트로 요약
3. 사용자 정의 요약 (집중할 내용 지정)
2번 선택 시:
LLM이 브랜치 A의 전체 대화를 요약
→ 세션 파일에 branch_summary entry로 저장
→ 이후 컨텍스트에 요약문이 포함됨브랜치 요약은 다음과 같은 형식으로 저장됩니다:
## Goal
[사용자가 달성하려는 목표]
## Progress
### Done
- [x] 완료된 작업
### In Progress
- [ ] 진행 중인 작업
## Key Decisions
- [결정 사항]: [근거]
## Next Steps
1. 다음에 할 일주의: Branch Summary는 압축된 요약이므로, 원본 코드나 실행 결과의 세부 내용은 유실됩니다. 정확한 코드 비교가 필요하면 파일로 저장 후
@로 참조하는 방법이 더 좋습니다.
Compaction과 Tree
세션이 길어져서 컨텍스트가 모델의 제한에 가까워지면 auto-compaction이 실행됩니다. Compaction은 오래된 메시지를 요약해서 컨텍스트를 확보합니다.
세션 트리 (compaction 포함):
a1 ─ a2 ─ a3 ─ a4 ─ c1(compaction) ─ a5 ─ a6 ← 현재 leaf
LLM 컨텍스트: c1(요약) + a5 + a6/tree에서 Ctrl+O로 필터 모드를 all로 전환하면 compaction entry도 노드로 표시됩니다.
| 모드 | compaction 표시 |
|---|---|
| default | ❌ 숨김 |
| no-tools | ❌ 숨김 |
| user-only | ❌ 숨김 |
| labeled-only | ❌ (라벨링된 경우만) |
| all | ✅ 표시됨 |
compaction 이전 메시지를 선택하면 compaction을 완전히 우회할 수 있습니다:
/tree에서 a1(user) 선택:
→ leaf가 a1의 parent(null)로 이동 → 사실상 leaf = null
→ 편집기에 a1 입력됨
→ Enter 전송 시 a1만 root이자 leaf가 됨
→ compaction 및 이후 모든 메시지 무시, 원본 a1만 컨텍스트에 전달Tree 요약
/tree는 동일한 세션 파일 내에서 leaf 포인터만 이동합니다.- user 메시지 선택 = 프롬프트를 편집기에 넣고 재실행 대기 상태
- assistant/compaction 등 선택 = 그 위치로 leaf를 이동하고 계속 진행
- compaction 이전 메시지 선택 = compaction을 우회하고 원본 컨텍스트로 복원
- Branch Summary를 남기면 다른 브랜치의 요약된 정보를 컨텍스트에 포함 가능
3. 세 명령어 종합 비교
| 항목 | /fork | /clone | /tree |
|---|---|---|---|
| 출력 대상 | 새 세션 파일 | 새 세션 파일 | 현재 세션 파일 (in-place) |
| 복사 범위 | 선택한 프롬프트의 parent까지 (결과 ❌ 미포함) | 현재 leaf까지 전체 경로 (결과 ✅ 포함) | 복사 없음 (이동만) |
| 편집기 상태 | 프롬프트 입력됨 | 비어있음 | user 선택 시 입력됨 (그 외 선택 시 비어있음) |
| 원본 세션 영향 | 없음 (새 파일) | 없음 (새 파일) | leaf 포인터만 이동 |
| 핵심 의도 | "예전 질문 다시 할게" | "여기까지 복제해서 새 출발" | "같은 파일 안에서 분기 탐색" |
4. fork, clone, tree 활용 전략
여러 접근법 시도: 직렬 vs 분기
직렬 방식 (tree 미사용):
msg1: "JWT로 구현" → assistant: 코드
msg2: "Session으로도" → assistant: 코드
msg3: "OAuth로도" → assistant: 코드
msg4: "비교해줘" → LLM이 3개 코드 모두 참조 가능 ✅| 장점 | 단점 |
|---|---|
| 모든 코드가 컨텍스트에 보존되어 정확한 비교 가능 | 컨텍스트 많이 소모 |
| 별도 조작 불필요 | 이전 접근법으로 복귀 불가 |
분기 방식 (tree 사용):
| 장점 | 단점 |
|---|---|
| 컨텍스트 절약 | 다른 브랜치 상세 코드는 LLM이 볼 수 없음 |
| 각 브랜치 독립적 유지 | BranchSummary는 요약이라 정보 손실 |
/tree로 자유 이동 가능 |
추천: 하이브리드 전략
직렬의 장점(정보 보존)과 파일 저장의 이점을 결합:
1. JWT 구현 완료 → .approach-jwt.md 에 주요 코드와 설명 저장
2. Session 구현 완료 → .approach-session.md 에 저장
3. OAuth 구현 완료 → .approach-oauth.md 에 저장
4. pi @.approach-*.md "이 세 가지 비교해서 최선 추천해줘"이렇게 하면:
- 직렬로 진행 → 모든 코드가 파일로 보존됨 (정보 손실 0)
- 파일을
@로 참조 → LLM이 정확한 코드로 비교 가능 - 파일은 세션 컨텍스트 밖에서 관리 → 컨텍스트 절약
5. 마치며
| 명령어 | 원라이너 |
|---|---|
/fork | "저 질문 다시 할게" — 프롬프트만 재사용, 결과는 버림 |
/clone | "여기까지 복제해서 새로 시작" — 결과 포함 복제 |
/tree | "같은 파일 내에서 자유롭게 이동" — leaf 포인터 변경 |
세 가지 명령어는 pi의 트리 구조 세션이라는 인프라 위에서 각각 다른 목적으로 설계되었습니다. 상황에 맞게 적절히 사용하면 세션 관리가 훨씬 편리해집니다.
Tip: fork와 clone 모두 원본 세션의 다른 브랜치는 복사되지 않습니다. 오직 현재 leaf 에서 루트까지 경로인 활성 경로만 복사됩니다.
(끝)