blog.dopana

Back

Khi làm việc với stacked pull requests trên GitHub, đôi khi bạn cần thay đổi cấu trúc của stack - sắp xếp lại các nhánh, kết hợp chúng, hoặc đổi tên. GitHub CLI extension gh stack cung cấp công cụ mạnh mẽ để xử lý việc này một cách dễ dàng.

Vấn đề#

Khi phát triển tính năng theo kiểu stacked PRs, bạn thường gặp các tình huống:

  • Cần di chuyển một nhánh lên vị trí cao hơn hoặc thấp hơn trong stack
  • Muốn gộp hai nhánh lại với nhau
  • Cần xóa một nhánh khỏi stack nhưng vẫn giữ lại PR
  • Muốn chèn một nhánh mới vào giữa stack
  • Cần đổi tên nhánh để phản ánh đúng nội dung

Thay vì thực hiện thủ công với git rebase và force push phức tạp, gh stack cung cấp các lệnh chuyên biệt.

Giải pháp#

GitHub CLI cung cấp hai cách chính để tái cấu trúc stack:

1. Sử dụng gh stack modify (Khuyên dùng)#

Lệnh này mở giao diện terminal UI tương tác cho phép bạn thực hiện các thay đổi cấu trúc và áp dụng tất cả cùng lúc.

gh stack modify
bash

Giao diện TUI hỗ trợ các phím tắt:

PhímHành độngMô tả
xDropXóa nhánh và commit khỏi stack
dFold downGộp nhánh vào nhánh bên dưới (hướng về trunk)
uFold upGộp nhánh vào nhánh bên trên (xa trunk)
iInsert belowChèn nhánh mới trống bên dưới (hướng về trunk)
IInsert aboveChèn nhánh mới trống bên trên (xa trunk)
Shift+↓Move downDi chuyển nhánh xuống (hướng về trunk)
Shift+↑Move upDi chuyển nhánh lên (xa trunk)
rRenameĐổi tên nhánh
zUndoHoàn tác hành động đã staged
Ctrl+SApplyÁp dụng tất cả thay đổi

2. Sử dụng gh stack unstack + gh stack init#

Cách tiếp cận thủ công hơn nhưng linh hoạt cho các thay đổi phức tạp:

# 1. Xóa stack hiện tại
gh stack unstack

# 2. Thực hiện thay đổi cấu trúc thủ công
git branch -m api-routes api-endpoints
git branch -d feature-removed

# 3. Tạo lại stack với cấu trúc mới
gh stack init db-migrations api-endpoints frontend
bash

Quy trình tái cấu trúc#

Dưới đây là quy trình tái cấu trúc một stack:

flowchart TD
    A[Stack hiện tại] --> B{Phương pháp?}
    B -->|Tương tác| C[gh stack modify]
    B -->|Thủ công| D[gh stack unstack]
    
    C --> E[Mở TUI]
    E --> F[Chọn hành động]
    F --> G[Stage thay đổi]
    G --> H{Đã xong?}
    H -->|Chưa| F
    H -->|Xong| I[Ctrl+S Apply]
    
    D --> J[Thay đổi thủ công]
    J --> K[git branch -m/-d]
    K --> L[gh stack init]
    
    I --> M[Cascading rebase]
    L --> M
    M --> N[gh stack push]
    N --> O[Stack đã tái cấu trúc]

Ví dụ thực tế#

Ví dụ 1: Di chuyển nhánh lên vị trí cao hơn#

Giả sử bạn có stack từ dưới lên trên:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[frontend]
    D --> E[testing]

Bạn muốn di chuyển testing lên trên api-routes:

gh stack modify
# Sử dụng Shift+↑ để di chuyển testing lên
# Ctrl+S để áp dụng
bash

Kết quả:

graph TD
    A[main] --> B[db-migrations]
    B --> C[testing]
    C --> D[api-routes]
    D --> E[frontend]

Ví dụ 2: Gộp hai nhánh#

Khi bạn nhận ra hai nhánh nên được gộp thành một:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[api-validation]
    D --> E[frontend]

Gộp api-validation vào api-routes:

gh stack modify
# Chọn api-validation, nhấn d (fold down)
# Ctrl+S để áp dụng
bash

Kết quả:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes + validation]
    C --> D[frontend]

Ví dụ 3: Chèn nhánh mới#

Khi bạn cần thêm một layer vào giữa stack:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[frontend]

Chèn nhánh auth-middleware giữa api-routesfrontend:

gh stack modify
# Đặt con trỏ ở api-routes
# Nhấn I (insert above)
# Đặt tên cho nhánh mới
# Ctrl+S để áp dụng
bash

Kết quả:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[auth-middleware]
    D --> E[frontend]

Quy trình cascading rebase#

Khi bạn áp dụng thay đổi với gh stack modify, quá trình sau sẽ diễn ra:

sequenceDiagram
    participant User as Bạn
    participant CLI as gh stack modify
    participant Git as Git
    participant Remote as GitHub Remote

    User->>CLI: gh stack modify
    User->>CLI: Stage thay đổi (di chuyển/gộp/chèn)
    User->>CLI: Nhấn Ctrl-S để Apply
    
    CLI->>Git: Đổi tên nhánh nếu cần
    CLI->>Git: Chèn nhánh mới nếu cần
    CLI->>Git: Cascading rebase
    loop Qua từng nhánh
        CLI->>Git: Rebase nhánh hiện tại lên nhánh dưới
        Git-->>CLI: Rebase hoàn tất
    end
    
    CLI->>User: Thông báo thành công
    User->>CLI: gh stack push
    CLI->>Remote: Force push với `\-\-force-with-lease`
    Remote-->>CLI: Push thành công
    CLI-->>User: Stack đã cập nhật trên GitHub

Lưu ý quan trọng#

[!WARNING]

  • Không thể sửa đổi nhánh từ PR đã merged
  • Các thay đổi cấu trúc (drop, fold, insert, rename) không thể trộn trong cùng một session
  • Luôn sử dụng gh stack push với --force-with-lease để an toàn
  • Backup branch quan trọng trước khi tái cấu trúc lớn

Best practices#

  • Kiểm tra stack hiện tại: Luôn chạy gh stack view trước khi thay đổi
  • Sử dụng TUI: gh stack modify an toàn hơn vì preview thay đổi trước khi apply
  • Test cục bộ: Đảm bảo rebase thành công trước khi push
  • Communicate: Thông báo team về thay đổi cấu trúc stack lớn
  • Backup: Đánh tag hoặc branch backup cho stack quan trọng

Tài liệu tham khảo#