# JGF (Jira Git Flow) π
> Jiraμ Gitμ μ°λνλ μν¬νλ‘μ° μλν CLI λꡬ
## π λ¬Έμ μν©
κ°λ°νμμ λ°λ³΅μ μΌλ‘ κ²ͺλ λ¬Έμ λ€:
- PMμ΄ Jira ν°μΌ ν λΉ β κ°λ°μκ° μλμΌλ‘ ν°μΌ νμΈ
- ν°μΌ λ²νΈλ‘ λΈλμΉ μμ± β μλμΌλ‘ Jira μν λ³κ²½
- PR μμ± μ Jira λ§ν¬ 볡μ¬/λΆμ¬λ£κΈ°
- PR λ¨Έμ§ ν Jira μν μλ μ
λ°μ΄νΈ
- λ‘컬 λΈλμΉ μ 리
**μ΄ λͺ¨λ κ³Όμ μ΄ μκ°μ΄ λ§μ΄ μμλ©λλ€.**
## β¨ JGFκ° ν΄κ²°νλ κ²
1. **μλ λΈλμΉ μμ±**: Jira ν°μΌ λ²νΈλ‘ μλ λΈλμΉ μμ±
2. **μλ μν λκΈ°ν**: μμ
μμ/PR/λ¨Έμ§ μ Jira μν μλ μ
λ°μ΄νΈ
3. **PR ν
νλ¦Ώ μλν**: Jira λ§ν¬μ ν°μΌ μ 보 μλ ν¬ν¨
4. **λΈλμΉ μλ μ 리**: λ¨Έμ§λ λΈλμΉ μλ κ°μ§ λ° μμ
## π μν¬νλ‘μ°
### μ 체 νλ‘μ°
```
1. PM/κ°λ°μ Jira ν°μΌ ν λΉ
β
2. κ°λ°μ: jgf tickets (ν°μΌ μ‘°ν)
β
3. κ°λ°μ: jgf start EM-XXX (λΈλμΉ μμ±)
β μλ: Git λΈλμΉ μμ±
β μλ: Jira μν "In Progress"λ‘ λ³κ²½
β
4. κ°λ°μ: μ½λ© μμ
β
5. κ°λ°μ: jgf pr (PR μμ±)
β μλ: PR μ λͺ©μ ν°μΌ λ²νΈ ν¬ν¨
β μλ: PR λ³Έλ¬Έμ Jira λ§ν¬ μΆκ°
β
6. ν: μ½λ 리뷰 & λ¨Έμ§
β
7. κ°λ°μ: jgf sync (λκΈ°ν)
β μλ: λ¨Έμ§λ λΈλμΉ κ°μ§
β μλ: Jira μν "Done"μΌλ‘ λ³κ²½
β μλ: λ‘컬 λΈλμΉ μμ
```
### μν λ³ν
```
Jira μν: To Do β In Progress β Done
Git λΈλμΉ: μμ β EM-XXX μμ± β PR β λ¨Έμ§ β μμ
```
## π μ€μΉ λ°©λ²
### Prerequisites
- Git
- Jira κ³μ λ° API ν ν°
- GitHub κ³μ λ° Personal Access Token
### μ€μΉ μ΅μ
#### Option 1: Cargoλ₯Ό ν΅ν μ€μΉ (Rust νμ)
```bash
# crates.ioμμ μ€μΉ
cargo install jgf
# λλ μμ€μμ λΉλ
git clone https://github.com/jaehafe/jgf.git
cd jgf
cargo install --path .
```
#### Option 2: λ°μ΄λ리 μ§μ λ€μ΄λ‘λ (Rust λΆνμ)
```bash
# macOS (Apple Silicon)
curl -L https://github.com/jaehafe/jgf/releases/latest/download/jgf-darwin-aarch64 -o jgf
chmod +x jgf
sudo mv jgf /usr/local/bin/
# macOS (Intel)
curl -L https://github.com/jaehafe/jgf/releases/latest/download/jgf-darwin-x64 -o jgf
chmod +x jgf
sudo mv jgf /usr/local/bin/
# Linux
curl -L https://github.com/jaehafe/jgf/releases/latest/download/jgf-linux-x64 -o jgf
chmod +x jgf
sudo mv jgf /usr/local/bin/
```
## βοΈ μ΄κΈ° μ€μ
### νλ‘μ νΈλ³ μ€μ (κΆμ₯)
κ° νλ‘μ νΈ λ£¨νΈμμ μ€ν:
```bash
jgf init
```
μ΄ λͺ
λ Ήμ λ κ°μ νμΌμ μμ±ν©λλ€:
#### 1. `jgf.json` - νλ‘μ νΈ μ€μ (Gitμ μ»€λ° κ°λ₯)
```json
{
"project": "your-project-name",
"jira": {
"url": "https://your-company.atlassian.net",
"project": "EM",
"username": "your-email@company.com" // Optional
},
"github": {
"owner": "YourOrg",
"repo": "your-repo"
},
"defaultBranch": "develop",
"prTemplate": { // Optional
"path": "custom/pr_template.md" // λλ
// "content": "μ§μ ν
νλ¦Ώ λ΄μ©..."
}
}
```
#### 2. `.env` - ν ν° μ 보
```env
JIRA_TOKEN=your-jira-api-token
GITHUB_TOKEN=ghp_your_github_token
```
### API ν ν° λ°κΈ λ°©λ²
**Jira API Token:**
1. [Atlassian Account Settings](https://id.atlassian.com/manage-profile/security/api-tokens) μ μ
2. "Create API token" ν΄λ¦
3. ν ν° μ΄λ¦ μ
λ ₯ ν μμ±
4. ν ν° λ³΅μ¬νμ¬ `.env`μ μ μ₯
**GitHub Personal Access Token:**
1. GitHub Settings β Developer settings β Personal access tokens
2. "Generate new token (classic)" ν΄λ¦
3. κΆν μ ν: `repo` (μ 체)
4. ν ν° μμ± λ° λ³΅μ¬
## π μ¬μ©λ²
### 1. ν λΉλ ν°μΌ μ‘°ν λ° μμ
μμ
```bash
# ν λΉλ λͺ¨λ ν°μΌ μ‘°ν
jgf tickets
# μνλ³ νν°λ§
jgf tickets --status "In Progress"
# μ΅λ κ°μ μ ν
jgf tickets --limit 10
```
**μΈν°λν°λΈ λͺ¨λ:**
- ν°μΌ λͺ©λ‘μμ μ ν
- "λΈλμΉ μμ± λ° In Progressλ‘ λ³κ²½" μ ν
- μλμΌλ‘ λΈλμΉ μμ± λ° Jira μν μ
λ°μ΄νΈ
### 2. νΉμ ν°μΌμΌλ‘ μμ
μμ
```bash
jgf start EM-100
```
**μλ μν μμ
:**
- β
develop λΈλμΉμμ μ΅μ λ³κ²½μ¬ν pull
- β
`EM-100` λΈλμΉ μμ± λ° μ²΄ν¬μμ
- β
Jira ν°μΌμ "In Progress"λ‘ λ³κ²½
### 3. PR μμ±
```bash
jgf pr
```
**μλ μν μμ
:**
- β
νμ¬ λΈλμΉμμ developμΌλ‘ PR μμ±
- β
PR μ λͺ©: `[EM-100] ν°μΌ μ λͺ©`
- β
νλ‘μ νΈμ PR ν
νλ¦Ώ μλ νμ λ° μ μ©
- β
PR λ³Έλ¬Έμ Jira λ§ν¬ λ° ν°μΌ μ 보 μλ μ½μ
- β
PRμ΄ μ΄λ―Έ μ‘΄μ¬νλ©΄ λ§ν¬ μλ΄
### 4. λ¨Έμ§ ν λκΈ°ν
```bash
jgf sync
```
**μλ μν μμ
:**
- β
develop λΈλμΉλ‘ μ ν λ° μ΅μ pull
- β
λ¨Έμ§λ λΈλμΉ κ°μ§
- β
ν΄λΉ Jira ν°μΌμ "Done"μΌλ‘ λ³κ²½
- β
λ‘컬 λΈλμΉ μμ
## π― μ€μ μ¬μ© μλ리μ€
### μλλ¦¬μ€ 1: μ κΈ°λ₯ κ°λ°
```bash
# 1. ν λΉλ ν°μΌ νμΈ
$ jgf tickets
π« [1] EM-120 μ¬μ©μ νλ‘ν κΈ°λ₯ μΆκ°
# 2. μμ
μμ (μΈν°λν°λΈ μ ν λλ μ§μ λͺ
λ Ή)
$ jgf start EM-120
π ν°μΌ EM-120 μμ
μ μμν©λλ€
πΏ λΈλμΉ 'EM-120'κ° μμ±λκ³ μ²΄ν¬μμλμμ΅λλ€
β
ν°μΌ μνκ° 'In Progress'λ‘ λ³κ²½λμμ΅λλ€
# 3. μ½λ© μμ
...
# 4. PR μμ±
$ jgf pr
π λΈλμΉ 'EM-120'μμ 'develop'μΌλ‘ PR μμ±
β
PRμ΄ μ±κ³΅μ μΌλ‘ μμ±λμμ΅λλ€! #123
π‘ PR λ§ν¬: https://github.com/YourOrg/your-repo/pull/123
# 5. 리뷰 & λ¨Έμ§ ν
$ jgf sync
π λ¨Έμ§λ λΈλμΉ λκΈ°ν μμ
β
ν°μΌ EM-120 μνκ° 'Done'μΌλ‘ λ³κ²½λμμ΅λλ€
β
λΈλμΉ 'EM-120'κ° μμ λμμ΅λλ€
β¨ λΈλμΉ λκΈ°ν μλ£!
```
### μλλ¦¬μ€ 2: μ¬λ¬ ν°μΌ λμ μμ
```bash
# μ¬λ¬ λΈλμΉμμ μμ
ν νλ²μ μ 리
$ jgf sync
π 3κ°μ ν°μΌ λΈλμΉλ₯Ό λ°κ²¬νμ΅λλ€
πΏ λΈλμΉ 'EM-118' νμΈ μ€...
β
λΈλμΉ 'EM-118'κ° λ¨Έμ§λμμ΅λλ€
> ν°μΌ EM-118λ₯Ό 'Done' μνλ‘ λ³κ²½νμκ² μ΅λκΉ? Yes
> λ‘컬 λΈλμΉ 'EM-118'λ₯Ό μμ νμκ² μ΅λκΉ? Yes
πΏ λΈλμΉ 'EM-119' νμΈ μ€...
π‘ λΈλμΉ 'EM-119'λ μμ§ λ¨Έμ§λμ§ μμμ΅λλ€
πΏ λΈλμΉ 'EM-120' νμΈ μ€...
β
λΈλμΉ 'EM-120'κ° λ¨Έμ§λμμ΅λλ€
...
```
## π’ νμ¬λ³ 컀μ€ν°λ§μ΄μ§
### Jira μν λ§€ν
κΈ°λ³Έμ μΌλ‘ λ€μ μνλ₯Ό μ§μν©λλ€:
- `To Do` / `ν΄μΌ ν μΌ`
- `In Progress` / `μ§ν μ€`
- `Done` / `μλ£`
νμ¬μ "In Review" μνκ° μλ κ²½μ°, PR μμ± μ μνλ₯Ό λ³κ²½νμ§ μκ³ λ¨Έμ§ ν DoneμΌλ‘λ§ λ³κ²½ν©λλ€.
### λΈλμΉ λ€μ΄λ°
- κΈ°λ³Έ: `{JIRA_TICKET_NUMBER}` (μ: `EM-100`)
- μμ νμμ `src/config.rs`μ `format_branch_name()` ν¨μ μμ
### PR ν
νλ¦Ώ κΈ°λ₯
#### ν
νλ¦Ώ μ°μ μμ
1. **νλ‘μ νΈμ PR ν
νλ¦Ώ νμΌ** (μλ νμ)
- `.github/pull_request_template.md`
- `.github/PULL_REQUEST_TEMPLATE.md`
- `pull_request_template.md`
- `docs/pull_request_template.md`
- `.gitlab/merge_request_templates/default.md`
2. **jgf.jsonμ μ μλ ν
νλ¦Ώ**
- `prTemplate.path`: 컀μ€ν
κ²½λ‘ μ§μ
- `prTemplate.content`: μ§μ ν
νλ¦Ώ λ΄μ© μμ±
3. **κΈ°λ³Έ λ΄μ₯ ν
νλ¦Ώ**
#### ν
νλ¦Ώ λ³μ
jgfλ PR ν
νλ¦Ώμμ λ€μ λ³μλ₯Ό μλ μΉνν©λλ€:
- `{{TICKET_KEY}}` - Jira ν°μΌ λ²νΈ (μ: EM-100)
- `{{TICKET_URL}}` - Jira ν°μΌ URL
- `{{TICKET_TITLE}}` - Jira ν°μΌ μ λͺ©
- `{{BRANCH_NAME}}` - νμ¬ λΈλμΉλͺ
#### ν
νλ¦Ώ μμ
```markdown
## π« ν°μΌ
{{TICKET_URL}}
## π μμ
λ΄μ©
-
## β
체ν¬λ¦¬μ€νΈ
- [ ] ν
μ€νΈ μμ±
- [ ] λ¬Έμ μ
λ°μ΄νΈ
- [ ] μ½λ 리뷰 μμ²
```
### μ¬λ¬ νλ‘μ νΈ κ΄λ¦¬
κ° νλ‘μ νΈμ λ
립μ μΈ `jgf.json`μ μμ±νμ¬ κ΄λ¦¬:
```bash
# Frontend νλ‘μ νΈ
cd ~/projects/frontend
jgf init # frontendμ© jgf.json μμ±
# Backend νλ‘μ νΈ
cd ~/projects/backend
jgf init # backendμ© jgf.json μμ±
# κ° νλ‘μ νΈμμ λ
립μ μΌλ‘ μλ
cd ~/projects/frontend && jgf tickets # frontend μ€μ μ¬μ©
cd ~/projects/backend && jgf tickets # backend μ€μ μ¬μ©
```
### μ€μ νμΌ μ°μ μμ
1. νμ¬ λλ ν 리λΆν° μμλ‘ νμνμ¬ `jgf.json` μ°ΎκΈ°
2. `jgf.json`μ΄ μμΌλ©΄ ν΄λΉ μ€μ + κ°μ μμΉμ `.env` μ¬μ©
3. μμΌλ©΄ μ μ `.env` νμΌ μ¬μ© (λ κ±°μ λͺ¨λ)
## π μμ νμΌ
νλ‘μ νΈμ ν¬ν¨λ μμ νμΌ:
- `jgf.json.example` - νλ‘μ νΈ μ€μ μμ
- `.env.example` - ν ν° μ€μ μμ
## π§ λ¬Έμ ν΄κ²°
### SSH μΈμ¦ μ€λ₯
```bash
# SSH μμ΄μ νΈ νμΈ
ssh-add -l
# SSH ν€ μΆκ°
ssh-add ~/.ssh/id_ed25519
```
### Jira API μ€λ₯
- API ν ν°μ΄ μ¬λ°λ₯Έμ§ νμΈ
- Jira URLμ΄ `https://`λ‘ μμνλμ§ νμΈ
- νλ‘μ νΈ ν€(μ: EM)κ° μ ννμ§ νμΈ
### GitHub API μ€λ₯
- Personal Access Token κΆν νμΈ (repo κΆν νμ)
- Repository ownerμ nameμ΄ μ ννμ§ νμΈ