Nếu bạn đang có dở dang một phần việc chưa sẵn sàng để commit nhưng cần đổi ngữ cảnh ngay bây giờ, đừng tạo commit "WIP". Cũng đừng copy-paste thay đổi của bạn vào một tệp văn bản như năm 2005. git stash là tất cả những gì bạn cần.
Lệnh này là cách quen thuộc để bảo toàn các thay đổi chưa commit trong khi bạn chuyển ngữ cảnh. Nó cho phép bạn lưu tạm thời các thay đổi, xử lý tác vụ khẩn trên nhánh khác, và khôi phục mọi thứ đúng vị trí bạn đang dang dở.
Trong bài viết này, tôi sẽ hướng dẫn bạn cách git stash pop hoạt động, khi nào nên dùng thay vì git stash apply, và cách khắc phục khi xung đột không thể tránh khỏi xuất hiện.
Nếu bạn mới dùng Git và thấy khái niệm stash còn mơ hồ, hãy đảm bảo nắm vững các kiến thức nền tảng trước. Các khóa học Introduction to Git và Introduction to GitHub của chúng tôi sẽ giúp bạn bắt đầu nhanh chóng.
Hiểu về Git Stash
Git stash là nơi lưu trữ tạm thời cho các thay đổi chưa commit.
Hãy nghĩ nó như clipboard cho công việc của bạn. Bạn có những thay đổi trong thư mục làm việc chưa sẵn sàng để commit, nhưng cần chuyển nhánh hoặc pull cập nhật từ remote. Thay vì làm mất công việc hoặc tạo commit WIP, bạn stash chúng lại.
Lệnh sẽ lưu các chỉnh sửa của bạn và đưa thư mục làm việc trở về khớp với commit HEAD.
Ý tưởng về stashing trong Git
Stashing giải quyết một vấn đề đơn giản: Git không cho phép bạn chuyển nhánh khi có thay đổi chưa commit.
Giả sử bạn đang làm một tính năng thì nhận được báo cáo lỗi. Bạn cần chuyển sang nhánh khác ngay, nhưng bạn có mã đang viết dở và các tệp đã chỉnh sửa. Commit thì không hợp lý vì công việc chưa hoàn thiện. Cưỡng bức checkout sẽ làm mất thay đổi của bạn.
Đó là lúc bạn stash.
Dưới đây là những tình huống phổ biến mà stashing có thể giúp bạn:
Chuyển nhánh để xử lý việc khẩn: Bạn đang làm dở tính năng thì cần sửa lỗi production.
Pull thay đổi từ remote: Đồng đội đã đẩy cập nhật và bạn cần pull, nhưng bạn có sửa đổi cục bộ.
Tránh commit lộn xộn: Bạn chưa sẵn sàng commit, nhưng cần một thư mục làm việc sạch để rebase hoặc merge.
Lưu mã thử nghiệm: Bạn muốn thử cách tiếp cận khác mà không làm mất công việc hiện tại
Stashing nhanh và có thể đảo ngược - không cần nghĩ thông điệp commit hay tên nhánh.
Kiến trúc stack của stash
Git quản lý các stash theo một ngăn xếp LIFO (vào sau, ra trước).
Mỗi lần bạn stash, Git tạo một mục mới ở đỉnh ngăn xếp. Stash gần nhất là stash@{0}, và các stash cũ dịch xuống: stash@{1}, stash@{2}, v.v.
Bên dưới, mỗi stash thực chất là một commit - chính xác hơn là một tập hợp commit. Git tạo cấu trúc commit đa-parent lưu trữ:
Các thay đổi trong thư mục làm việc
Các thay đổi đã stage (index)
Các tệp chưa theo dõi (nếu bạn dùng cờ u)
Cấu trúc này có nghĩa stash không chỉ là snapshot. Chúng là các commit đầy đủ mà Git có thể merge trở lại vào thư mục làm việc của bạn sau này.
Bạn có thể tham chiếu stash theo hai cách - bằng chỉ số dùng cú pháp stash@{0}, hoặc dùng git stash list để tìm thông điệp bạn đã đặt và tham chiếu stash cụ thể đó. Chỉ số tiện cho stash gần đây, còn thông điệp hữu ích khi bạn có nhiều stash đã lưu.
Đây là ví dụ một ngăn xếp stash điển hình:
Tiền tố WIP on nghĩa là bạn dùng git stash không kèm thông điệp. Tiền tố On nghĩa là bạn đã cung cấp thông điệp tùy chỉnh với git stash push -m.
Stash chỉ tồn tại trong kho cục bộ của bạn - chúng không được push lên remote. Điều này giữ cho công việc tạm thời ở đúng nơi nó thuộc về: trên máy của bạn, sẵn sàng khôi phục khi cần.
Tạo, Quản lý và Kiểm tra Stash
Lệnh git stash cơ bản là đủ để bắt đầu, nhưng khá "lười". Bạn sẽ có một đống mục "WIP on branch-name" mà không nói lên được gì bên trong. Sáu tuần sau, bạn sẽ không nhớ stash nào chứa bản vá lỗi và stash nào chứa phần refactor dở dang.
Sự khác biệt là quá rõ. Một mục nói chính xác bạn đã làm gì, còn mục kia bắt bạn phải đoán.
Hãy viết thông điệp như đang để lại ghi chú cho chính mình trong tương lai. "Thêm logic auth", "Sửa lỗi navbar", hoặc "Thử nghiệm thiết kế API mới" luôn tốt hơn các thông điệp WIP chung chung.
Bao gồm tệp chưa theo dõi hoặc bị bỏ qua
Theo mặc định, git stash chỉ lưu các tệp đã được theo dõi - các tệp Git đã biết.
Các tệp chưa theo dõi vẫn ở trong thư mục làm việc. Điều này hay khiến mọi người bất ngờ khi stash, chuyển nhánh, và thấy các tệp mới vẫn còn đó.
Đây là điều xảy ra:
echo"new_feature.py"> new_feature.py
git stashĐược hỗ trợ bởi
Tệp không được stash vì Git chưa theo dõi nó:
Để xử lý, dùng cờ -u để stash cả tệp chưa theo dõi:
git stash push -u-m"Added a Python file for a new cool feature"Được hỗ trợ bởi
Lệnh này stash cả tệp đã theo dõi lẫn chưa theo dõi. Thư mục làm việc của bạn trở nên hoàn toàn sạch.
Mẹo: Bạn có thể thêm cờ -a để bao gồm cả các tệp bị .gitignore bỏ qua. Nó sẽ stash các tệp đã theo dõi, chưa theo dõi, và các tệp trong .gitignore. Bạn hiếm khi cần điều này, trừ khi đang debug vấn đề build hoặc muốn lưu lại snapshot hoàn toàn sạch của mọi thứ.
Đây là một cheat sheet để bạn biết khi nào dùng từng cờ:
Không có cờ: Bạn chỉ thay đổi các tệp đã tồn tại
u flag: Bạn đã thêm tệp mới chưa được theo dõi
a flag: Bạn cần lưu mọi thứ, bao gồm đầu ra build hoặc tệp tạm
Phần lớn thời gian, bạn sẽ dùng -u. Đây là lựa chọn an toàn nhất khi bạn tạo tệp mới trong quá trình phát triển.
Stash một phần hoặc có chọn lọc
Bạn không nhất thiết phải stash mọi thứ trong thư mục làm việc.
Giả sử bạn đã sửa hai lỗi, nhưng chỉ muốn stash một lỗi. Hoặc bạn có thay đổi ở năm tệp, nhưng chỉ ba tệp liên quan đến tính năng muốn lưu.
Bạn có thể stash các tệp cụ thể với pathspec:
git stash push -m"New files" new_file.txt new_file_2.txtĐược hỗ trợ bởi
Lệnh này chỉ stash new_file.txt và new_file_2.txt. Mọi thứ khác vẫn ở thư mục làm việc.
Lệnh này áp dụng stash@{1} và xóa nó, nhưng có một điểm - các stash còn lại sẽ dịch lên. Cái trước là stash@{2} sẽ thành stash@{1}, v.v.
Git xử lý một lần stash pop như thế nào
Khi bạn chạy git stash pop, Git thực hiện một lần merge ba chiều ở hậu trường.
Nó so sánh ba trạng thái:
Commit gốc (nơi bạn tạo stash)
Commit HEAD hiện tại
Các thay đổi trong stash
Nếu merge thành công không có xung đột, Git áp dụng thay đổi và xóa stash. Thư mục làm việc của bạn trông đúng như trước khi stash.
Đây là ví dụ quy trình làm việc đơn giản:
# You're working on a featureecho"new feature code">> feature.py
git stash push -m"Half-finished feature work"# Switch to new branch and make unrelated changesgit checkout bugfix
echo"bug fix">> bugfix.py
gitadd bugfix.py
git commit -m"Fix critical bug"# Go back to your other branchgit checkout main
# Pop your stashed workgit stash popĐược hỗ trợ bởi
Nếu Git không thể merge sạch, bạn sẽ gặp xung đột. Stash vẫn ở trong ngăn xếp vì pop chưa hoàn tất thành công. Bạn sẽ thấy ký hiệu xung đột trong các tệp, giống như khi merge conflict thông thường.
Khi có xung đột, bạn cần tự xử lý, stage các tệp đã sửa và commit. Stash không tự biến mất, nên bạn cần chạy git stash drop sau khi đã giải quyết xong.
Áp dụng stash giữa các nhánh
Stash không gắn với nhánh cụ thể nào.
Bạn có thể tạo stash trên bugfix, chuyển sang main, và pop stash đó tại đây. Git không quan tâm stash đến từ đâu - nó chỉ cố áp dụng thay đổi vào nhánh bạn đang đứng.
Điều này mở ra các quy trình hữu ích:
Di chuyển công việc giữa các nhánh: Giả sử bạn bắt đầu code trên nhánh sai. Thay vì reset và mất việc, bạn stash lại, chuyển sang nhánh đúng, và pop tại đó.
Tái tổ chức tác vụ: Bạn đã stash mã thử nghiệm một tuần trước. Giờ muốn thử nó trên nhánh khác xem có hợp hơn không.
Kiểm thử thay đổi trong các ngữ cảnh khác nhau: Bạn có một bản vá lỗi đã stash, và muốn thử trên nhiều nhánh trước khi commit. Hãy dùng git stash apply thay vì pop để giữ stash lại, thử trên các nhánh khác nhau, rồi pop ở nhánh bạn muốn commit. Sẽ nói thêm về apply ngay sau.
Miễn là các thay đổi không xung đột với nhánh hiện tại, stash sẽ áp dụng sạch - đó là ý chính bạn cần nhớ.
Git Stash Pop so với Git Stash Apply
Các lập trình viên thường băn khoăn nên dùng git stash pop hay git stash apply.
Khác biệt chính: tính tồn tại của stash
Khác biệt chủ yếu rất đơn giản: pop xóa stash sau khi áp dụng, còn apply giữ stash lại trong ngăn xếp.
Với pop, bạn nói "Tôi xong với stash này - áp dụng và bỏ đi." Với apply, bạn nói "Có thể tôi sẽ cần lại sau."
Điều này ảnh hưởng đến quy trình của bạn theo hai cách:
An toàn: Nếu có sự cố trong quá trình pop và bạn cần khôi phục, stash đã biến mất. Với apply, stash vẫn ở trong ngăn xếp như một bản dự phòng.
Dọn dẹp: Dùng pop giúp danh sách stash sạch tự động. Dùng apply nghĩa là bạn phải tự chạy git stash dropsau đó để xóa các stash không còn cần.
Đa số lập trình viên mặc định dùng pop vì sạch sẽ hơn. Nhưng apply tốt hơn khi bạn chưa chắc stash sẽ hoạt động sạch trên nhánh hiện tại, hoặc khi muốn thử cùng thay đổi trên nhiều nhánh.
Tính dự đoán, rủi ro, và dịch chuyển chỉ số
Đây là chỗ pop trở nên rắc rối - chỉ số stash dịch chuyển khi bạn pop từ giữa ngăn xếp.
Giả sử bạn có ba stash:
stash@{0}: Feature work
stash@{1}: Bug fix
stash@{2}: Experimental codeĐược hỗ trợ bởi
Nếu bạn pop stash@{1}, các stash còn lại dịch lên:
stash@{0}: Feature work
stash@{1}: Experimental codeĐược hỗ trợ bởi
Điều này có thể gây vấn đề nếu bạn viết script Git hoặc chạy nhiều lệnh pop liên tiếp. Bạn pop stash@{1}, rồi thử pop stash@{2}, nhưng chỉ số đó không còn tồn tại.
Lệnh apply không gặp vấn đề này. Chỉ số chỉ dịch chuyển khi bạn rõ ràng chạy git stash drop. Bạn có thể apply các stash theo bất kỳ thứ tự nào mà không lo ngăn xếp thay đổi ngoài ý muốn.
Xử lý xung đột giống hệt nhau
Cả hai lệnh xử lý xung đột theo cách giống hệt nhau.
Nếu Git không thể merge sạch các thay đổi trong stash, bạn sẽ thấy ký hiệu xung đột trong tệp. Khác biệt là điều gì xảy ra với stash:
Với pop: Stash vẫn ở trong ngăn xếp vì pop chưa hoàn tất
Với apply: Stash vẫn ở trong ngăn xếp (vốn dĩ là như vậy)
Trong cả hai trường hợp, bạn cần tự sửa xung đột, stage các tệp đã giải quyết bằng git add, và xóa stash bằng git stash drop (nếu dùng apply).
Quy trình xử lý xung đột là giống nhau - điểm khác biệt duy nhất là stash có được xóa tự động khi thành công hay không.
Khi nào chọn mỗi lệnh
Dùng git stash pop khi:
Bạn áp dụng một stash một lần và xong với nó
Bạn muốn danh sách stash được dọn tự động
Bạn làm việc trên một nhánh và không cần stash ở nơi khác
Dùng git stash apply khi:
Bạn muốn thử cùng thay đổi trên nhiều nhánh
Bạn chưa chắc stash sẽ áp dụng sạch
Bạn đang viết script Git và cần chỉ số ổn định, dự đoán được
Bạn muốn có lưới an toàn nếu có sự cố
Xử lý Xung đột khi Stash Pop
Xung đột xảy ra khi Git không thể merge sạch các thay đổi trong stash. Phần này, tôi sẽ chỉ bạn cách xử lý.
Khi nào có xung đột và vì sao
Xung đột xảy ra trong quá trình merge ba chiều mà Git thực hiện khi bạn pop một stash.
Git so sánh ba phiên bản mã của bạn:
Commit gốc nơi bạn tạo stash
Commit HEAD hiện tại
Các thay đổi trong stash
Nếu cùng dòng bị thay đổi ở nhánh hiện tại và trong stash, Git không biết giữ phiên bản nào. Đó là xung đột.
Nguyên nhân phổ biến của xung đột khi pop stash:
Bạn chỉnh sửa cùng một tệp ở cả hai nhánh: Bạn stash thay đổi vào một tệp, chuyển nhánh, rồi lại chỉnh tệp đó trước khi pop
Người khác đã push thay đổi: Bạn stash công việc, pull từ remote, và các cập nhật đó đụng vào cùng đoạn mã
Bạn rebase hoặc cherry-pick commit: Commit gốc mà Git kỳ vọng không còn nữa, dẫn tới lệch merge
Nói chung, stash để càng lâu thì khả năng gặp xung đột khi pop càng cao.
Quy trình xử lý xung đột
Khi xung đột xảy ra, Git tạm dừng pop và đánh dấu xung đột trong tệp:
Tệp của bạn giờ có các ký hiệu xung đột:
Mọi thứ giữa <<<<<<< Updated upstream và ======= là mã hiện tại của bạn. Mọi thứ giữa ======= và >>>>>>> Stashed changes là từ stash.
Bạn có thể làm như sau để sửa:
Mở tệp bị xung đột và quyết định giữ phiên bản nào (hoặc kết hợp cả hai)
Xóa các ký hiệu xung đột (<<<<<<<, =======, >>>>>>>)
Stage tệp đã giải quyết bằng git add
Xóa stash thủ công bằng git stash drop - nhớ rằng nó sẽ không biến mất tự động.
Chiến lược thay thế
Nếu bạn không muốn xử lý xung đột ở nhánh hiện tại, hãy dùng git stash branch.
Lệnh này tạo một nhánh mới từ commit nơi bạn tạo stash, rồi áp dụng stash tại đó:
Git tạo nhánh tên temp-feature, checkout nó, và pop stash của bạn lên đó. Vì nhánh bắt đầu từ đúng commit nơi bạn stash, sẽ không có xung đột. Tôi sẽ bàn kỹ hơn ở phần riêng.
Bạn cũng có thể hủy một lần pop thất bại với git reset --merge:
git stash pop
# Conflicts appeargit reset --mergeĐược hỗ trợ bởi
Lệnh này hoàn tác nỗ lực pop và đưa thư mục làm việc về trạng thái trước khi pop. Stash vẫn ở trong ngăn xếp.
Hủy bỏ các thao tác stash đang diễn ra
Nếu bạn đã bắt đầu pop hoặc apply và muốn quay lại hoàn toàn, bạn có vài lựa chọn.
Lệnh này loại bỏ toàn bộ thay đổi trong thư mục làm việc, gồm cả các sửa bạn đã làm. Dùng khi bạn đã làm rối và muốn bắt đầu lại.
Hãy nhớ lệnh này sẽ hủy vĩnh viễn công việc chưa commit. Đảm bảo bạn thực sự muốn bỏ hết trước khi chạy.
Sau khi hủy, stash của bạn vẫn ở trong ngăn xếp (trừ khi bạn dùng pop và nó đã thành công trước khi gặp xung đột). Bạn có thể thử lại sau, hoặc dùng git stash branch để tiếp cận sạch hơn.
Dọn Dẹp Stash
Stash tích tụ rất nhanh trong các dự án dài hạn. Bạn stash công việc để sửa lỗi, rồi quên nó. Bạn tạo các stash thử nghiệm mà không bao giờ pop. Sáu tháng sau, bạn có 20 stash và không biết nửa trong số đó chứa gì.
Điều này khiến việc tìm stash bạn cần trở nên khó hơn. Bạn sẽ phải chạy git stash show -p cho từng cái để biết bên trong có gì.
Rất tốn thời gian, nên hãy nhớ dọn dẹp stash thường xuyên.
Tạo nhánh từ stash rất phù hợp cho các tính năng thử nghiệm. Giả sử bạn đã stash một số mã thử nghiệm cách đây một tuần, và giờ muốn phát triển nó đàng hoàng mà không làm rối công việc hiện tại.
Bạn có một nhánh sạch để làm việc với thử nghiệm. Nếu hiệu quả, bạn merge lại. Nếu không, bạn xóa nhánh và tiếp tục.
Nó cũng tuyệt cho các lần rebase dài. Thay vì xử lý khả năng xung đột trong quá trình rebase, bạn có thể stash mọi thứ và tạo nhánh từ đó.
git stash push -m"WIP before rebase"git rebase main
git stash branch temp-workĐược hỗ trợ bởi
Giờ bạn có thể xem lại các thay đổi đã stash riêng biệt và quyết định cách tích hợp chúng sau khi rebase.
Tạo nhánh cũng hữu ích để tách biệt các thay đổi lớn hoặc lộn xộn. Hãy tưởng tượng bạn có một stash khổng lồ với thay đổi ở 15 tệp, một nửa xung đột với nhánh hiện tại. Chỉ cần tạo nhánh mới - không cần vật lộn.
Bạn có một nhánh riêng để xem lại mọi thứ một cách bình tĩnh, commit đúng chuẩn, rồi merge lại với lịch sử rõ ràng.
Kỹ thuật Nâng cao và Phương án Khôi phục
Đến giờ bạn đã quen với những điều cơ bản của git stash, nên tôi sẽ chỉ bạn vài khái niệm nâng cao hơn.
Làm việc với các mục stash cụ thể
Bạn có thể pop hoặc apply bất kỳ stash nào trong ngăn xếp, không chỉ cái gần nhất.
Chỉ cần tham chiếu stash bằng chỉ số để lấy đúng thứ bạn cần:
git stash pop stash@{3}git stash apply stash@{1}Được hỗ trợ bởi
Điều này cho phép bạn lấy stash cũ hơn mà không đụng tới những cái mới. Khi bạn pop một stash ở giữa, mọi chỉ số phía dưới sẽ dịch lên. Cái trước là stash@{4} sẽ thành stash@{3}, v.v. Nếu bạn đang viết script Git hoặc pop nhiều stash liên tiếp, việc dịch chỉ số này có thể làm hỏng lệnh của bạn.
Giải pháp là dùng apply thay vì pop khi bạn cần chỉ số dự đoán được:
git stash apply stash@{2}# Drop it manually when you're donegit stash drop stash@{2}Được hỗ trợ bởi
Cách này cho bạn toàn quyền kiểm soát khi nào ngăn xếp thay đổi. Bạn apply stash, xác nhận mọi thứ hoạt động đúng, rồi tự tay drop. Chỉ số chỉ dịch khi bạn yêu cầu rõ ràng.
Khôi phục trạng thái staged
Theo mặc định, git stash pop và git stash apply khôi phục thay đổi của bạn nhưng không giữ lại những gì đã stage.
Giả sử bạn sửa ba tệp, và đã stage hai tệp để commit trước khi stash. Khi pop stash đó, cả ba tệp quay lại dưới dạng thay đổi chưa stage. Git không còn biết bạn muốn commit tệp nào.
Giải pháp là dùng cờ --index để khôi phục trạng thái staging đúng như trước:
Lệnh này tái tạo chính xác working tree và index trước khi stash. Tệp nào đã stage sẽ vẫn stage. Tệp nào chưa stage vẫn chưa stage. Mọi thứ về đúng chỗ.
Bạn sẽ cần cờ này khi:
Bạn đang chuẩn bị một commit được stage cẩn thận và không thể để mất thông tin staging đó
Bạn làm việc với kịch bản staging phức tạp, như khi dùng git add -p để stage chỉ một số hunk
Bạn muốn thư mục làm việc trông đúng như trước khi stash, không ngoại lệ
Phần lớn thời gian, bạn sẽ không cần cờ này. Bạn pop stash, xem những gì trở lại, và stage những gì cần.
Khôi phục khi mắc lỗi với stash
Rồi sẽ có lúc bạn drop nhầm một stash cần thiết hoặc lỡ clear cả ngăn xếp.
Nếu điều đó xảy ra, reflog của git có thể cứu bạn.
Reflog theo dõi mọi thay đổi tham chiếu trong kho của bạn, bao gồm stash. Khi bạn tạo hoặc drop một stash, Git ghi lại trong reflog. Ngay cả sau khi drop, các commit đó vẫn tồn tại một thời gian như đối tượng không thể truy cập.
Bạn có thể tìm stash đã mất bằng cách tìm commit không thể truy cập:
Giờ bạn có thể kiểm tra từng commit để tìm stash của mình:
git show 066ded985342e585bc8e75c074add99ec1950f50Được hỗ trợ bởi
Xem diff và thông điệp commit để xác định đâu là stash đã mất. Khi tìm thấy, hãy khôi phục nó:
git stash apply 066ded985342e585bc8e75c074add99ec1950f50Được hỗ trợ bởi
Lệnh này áp dụng stash đã mất vào thư mục làm việc như thể nó chưa từng bị drop.
Tốt hơn nữa, hãy ngăn lỗi ngay từ đầu bằng cách làm theo các thực hành tốt sau:
Viết thông điệp stash có mô tả để bạn biết chính xác mình đang drop gì. "Sửa lỗi đăng nhập" tốt hơn "WIP" khi bạn nhìn vào danh sách năm stash.
Dùng git stash show -p trước khi drop để xác nhận đó là stash đúng. Mất năm giây để kiểm tra còn hơn năm phút để khôi phục.
Dọn ngăn xếp stash thường xuyên để nó không bừa bộn. Ngăn xếp với ba stash liên quan dễ điều hướng hơn nhiều so với 15 mục cũ.
Dùng apply thay vì pop khi bạn chưa 100% chắc muốn xóa stash. Bạn luôn có thể drop sau khi đã xác minh mọi thứ hoạt động.
Reflog có thể giúp khôi phục, nhưng khá mất công. Chỉ cần nhìn vào hình trên để thấy tôi sẽ phải kiểm tra thủ công bao nhiêu commit - và đây chỉ là một dự án nhỏ tạo ra cho bài viết này.
Thực hành Tốt và Hướng dẫn Quy trình
Dùng stash hiệu quả nghĩa là làm theo các mô thức giúp ngăn lỗi và giữ quy trình của bạn sạch sẽ. Tôi sẽ chỉ bạn cách tiếp cận ưa thích của mình.
Mô thức quy trình được khuyến nghị
Quy trình stash an toàn nhất theo mẫu đơn giản: stash kèm thông điệp, chuyển ngữ cảnh, rồi pop khi bạn sẵn sàng tiếp tục.
# Work on feature-branchgit stash push -m"Feature work in progress"git checkout main
# Do urgent work on main# Go backgit checkout feature-branch
git stash popĐược hỗ trợ bởi
Cách này phù hợp cho hầu hết tình huống. Bạn bảo toàn công việc, xử lý gián đoạn, và khôi phục mọi thứ sạch sẽ.
Một mô thức phổ biến khác là quy trình "kiểm tra trước khi pop". Bạn liệt kê các stash, xem bên trong có gì, rồi pop cái phù hợp.
git stash list
git stash show -p stash@{1}git stash pop stash@{1}Được hỗ trợ bởi
Bước xác minh bổ sung này ngăn bạn pop nhầm stash hoặc áp dụng công việc đã lỗi thời.
Một số lập trình viên thích lựa chọn "commit miễn cưỡng" thay cho stashing. Thay vì stash, họ tạo commit tạm với thông điệp như "WIP - not ready" rồi amend hoặc reset sau. Cách này hữu ích nếu bạn không thoải mái với stash hoặc muốn công việc được theo dõi trong lịch sử nhánh. Điểm trừ là bạn có thể để lại lịch sử commit lộn xộn nếu quên dọn.
Tích hợp với công cụ phát triển
Hầu hết GUI Git hiển thị stash trực quan và cho phép pop hoặc apply chỉ bằng một cú nhấp.
Các công cụ như GitKraken, Sourcetree, và GitHub Desktop liệt kê stash trong thanh bên. Bạn có thể xem thông điệp, xem diff, và apply hoặc drop stash mà không cần gõ lệnh. Điều này hữu ích khi bạn có nhiều stash và muốn so sánh chúng cạnh nhau.
Phần mở rộng Git của VS Code hiển thị stash trong bảng điều khiển source control. Bạn có thể nhấp phải để pop, apply, hoặc drop ngay trong trình soạn thảo.
Alias shell giúp stash nhanh hơn nếu bạn thích dòng lệnh. Thêm các lệnh này vào .bashrc hoặc .zshrc:
aliasgst='git stash'aliasgstp='git stash pop'aliasgstl='git stash list'aliasgsts='git stash show -p'Được hỗ trợ bởi
Giờ đây gst sẽ stash công việc của bạn, gstp pop nó, gstl liệt kê các stash, và gsts hiển thị diff. Bạn tiết kiệm được vài lần gõ mỗi lần.
Vệ sinh stash và cân nhắc cho nhóm
Stash là cục bộ trên máy bạn - chúng không bao giờ được push lên kho từ xa.
Điều này có nghĩa đồng đội không thể thấy stash của bạn, và bạn cũng không thể truy cập chúng từ máy khác. Nếu cần chia sẻ công việc đang làm, đừng stash. Hãy dùng patch hoặc nhánh tạm.
Để chia sẻ công việc qua patch, chạy:
git stash show -p> my-work.patch
# Send the patch file to your teammate# They apply it with: git apply my-work.patchĐược hỗ trợ bởi
Giờ hãy gửi tệp patch cho đồng đội, và họ sẽ áp dụng bằng cách chạy git apply my-work.patch.
Đồng đội có thể pull nhánh, xem xét công việc, và tiếp tục từ đó.
Dù bạn chọn cách nào làm mặc định, luôn duy trì vệ sinh stash tốt. Điều này sẽ tránh nhầm lẫn và giúp ngăn xếp cục bộ dễ quản lý. Dưới đây là vài thực hành tốt:
Dùng tên mô tả cho mỗi stash. "Thêm logic xác thực người dùng" cho biết bên trong có gì. "WIP on feature-branch" thì không.
Dọn stash hàng tuần. Chạy git stash list và drop mọi thứ cũ hơn một tuần. Nếu bảy ngày rồi bạn chưa cần, có lẽ sẽ không cần nữa.
Đừng để số lượng stash vượt quá năm. Nhiều hơn năm stash nghĩa là bạn đang dùng chúng như kho lưu trữ dài hạn thay vì tạm thời. Hãy pop, commit công việc, hoặc drop.
Nếu bạn làm việc theo nhóm và ai đó hỏi, "Đoạn mã bạn đang làm đâu?", đừng bao giờ trả lời, "Trong stash của tôi." Stash là riêng tư và tạm thời - không dùng để chia sẻ hay lưu trữ công việc quan trọng.
Kết luận
Giờ bạn đã biết git stash pop hoạt động thế nào và khi nào nên dùng.
Cốt lõi, stashing rất đơn giản: lưu công việc chưa commit, chuyển ngữ cảnh, và khôi phục sau. Nhưng chi tiết mới quan trọng. Biết khi nào dùng pop so với apply, cách xử lý xung đột, và khi nào tạo nhánh từ stash sẽ giúp bạn tiết kiệm hàng giờ bực bội.
Điều quan trọng nhất cần nhớ là stash là lưu trữ tạm thời, không phải sao lưu vĩnh viễn. Hãy dùng thông điệp mô tả, dọn dẹp thường xuyên, và đừng để ngăn xếp vượt quá năm mục. Nếu cần chia sẻ công việc hoặc giữ lâu dài, hãy commit lên một nhánh.
Chuyên gia Khoa học Dữ liệu Cấp cao, làm việc tại Croatia. Tác giả Công nghệ Hàng đầu với hơn 700 bài viết đã xuất bản, đạt trên 10 triệu lượt xem. Tác giả cuốn sách Tự động hóa Machine Learning với TPOT.
FAQs
Git stash pop là gì và khi nào nên dùng?⌄
git stash pop áp dụng các thay đổi đã stash gần nhất vào thư mục làm việc của bạn và xóa stash đó khỏi ngăn xếp. Dùng khi bạn đã tạm lưu công việc chưa commit để chuyển nhánh hoặc pull cập nhật, và giờ sẵn sàng khôi phục chúng. Rất phù hợp để xử lý gián đoạn mà không cần tạo commit "WIP" lộn xộn.
Sự khác nhau giữa git stash pop và git stash apply là gì?⌄
git stash pop áp dụng các thay đổi trong stash và xóa stash khỏi ngăn xếp, trong khi git stash apply giữ lại stash sau khi áp dụng. Dùng pop khi bạn đã xong với stash và muốn giữ ngăn xếp gọn gàng. Dùng apply khi bạn muốn thử cùng thay đổi trên nhiều nhánh hoặc giữ stash làm bản dự phòng.
Làm thế nào xử lý xung đột merge khi dùng git stash pop?⌄
Khi xảy ra xung đột trong lúc pop stash, Git đánh dấu các tệp xung đột bằng ký hiệu xung đột và tạm dừng thao tác. Mở các tệp xung đột, tự xử lý bằng cách chọn phần cần giữ, rồi stage tệp đã sửa bằng git add. Stash vẫn ở trong ngăn xếp sau khi xung đột xảy ra, nên bạn cần drop thủ công bằng git stash drop khi hoàn tất.
Tôi có thể khôi phục một stash đã lỡ xóa không?⌄
Có, bạn có thể khôi phục các stash đã xóa bằng reflog của Git. Chạy git fsck --unreachable | grep commit để tìm commit không thể truy cập, sau đó dùng git show với từng hash để xác định stash đã mất. Khi tìm thấy, chạy git stash apply <commit-hash> để khôi phục.
Tôi nên dùng git stash hay tạo commit tạm thời?⌄
Dùng git stash cho các lần chuyển ngữ cảnh nhanh khi bạn sẽ sớm quay lại công việc, như sửa lỗi khẩn trên nhánh khác. Tạo commit tạm nếu bạn muốn công việc được theo dõi trong lịch sử nhánh hoặc nếu bạn không thoải mái với stash. Stash là cục bộ và tạm thời, còn commit là vĩnh viễn và có thể push lên remote.
Nếu bạn đang có dở dang một phần việc chưa sẵn sàng để commit nhưng cần đổi ngữ cảnh ngay bây giờ, đừng tạo commit "WIP". Cũng đừng copy-paste thay đổi của bạn vào một tệp văn bản như năm 2005.
git stashlà tất cả những gì bạn cần.Lệnh này là cách quen thuộc để bảo toàn các thay đổi chưa commit trong khi bạn chuyển ngữ cảnh. Nó cho phép bạn lưu tạm thời các thay đổi, xử lý tác vụ khẩn trên nhánh khác, và khôi phục mọi thứ đúng vị trí bạn đang dang dở.
Trong bài viết này, tôi sẽ hướng dẫn bạn cách
git stash pophoạt động, khi nào nên dùng thay vìgit stash apply, và cách khắc phục khi xung đột không thể tránh khỏi xuất hiện.Nếu bạn mới dùng Git và thấy khái niệm stash còn mơ hồ, hãy đảm bảo nắm vững các kiến thức nền tảng trước. Các khóa học Introduction to Git và Introduction to GitHub của chúng tôi sẽ giúp bạn bắt đầu nhanh chóng.
Hiểu về Git Stash
Git stash là nơi lưu trữ tạm thời cho các thay đổi chưa commit.
Hãy nghĩ nó như clipboard cho công việc của bạn. Bạn có những thay đổi trong thư mục làm việc chưa sẵn sàng để commit, nhưng cần chuyển nhánh hoặc pull cập nhật từ remote. Thay vì làm mất công việc hoặc tạo commit WIP, bạn stash chúng lại.
Lệnh sẽ lưu các chỉnh sửa của bạn và đưa thư mục làm việc trở về khớp với commit HEAD.
Ý tưởng về stashing trong Git
Stashing giải quyết một vấn đề đơn giản: Git không cho phép bạn chuyển nhánh khi có thay đổi chưa commit.
Giả sử bạn đang làm một tính năng thì nhận được báo cáo lỗi. Bạn cần chuyển sang nhánh khác ngay, nhưng bạn có mã đang viết dở và các tệp đã chỉnh sửa. Commit thì không hợp lý vì công việc chưa hoàn thiện. Cưỡng bức checkout sẽ làm mất thay đổi của bạn.
Đó là lúc bạn stash.
Dưới đây là những tình huống phổ biến mà stashing có thể giúp bạn:
Stashing nhanh và có thể đảo ngược - không cần nghĩ thông điệp commit hay tên nhánh.
Kiến trúc stack của stash
Git quản lý các stash theo một ngăn xếp LIFO (vào sau, ra trước).
Mỗi lần bạn stash, Git tạo một mục mới ở đỉnh ngăn xếp. Stash gần nhất là
stash@{0}, và các stash cũ dịch xuống:stash@{1},stash@{2}, v.v.Bên dưới, mỗi stash thực chất là một commit - chính xác hơn là một tập hợp commit. Git tạo cấu trúc commit đa-parent lưu trữ:
Cấu trúc này có nghĩa stash không chỉ là snapshot. Chúng là các commit đầy đủ mà Git có thể merge trở lại vào thư mục làm việc của bạn sau này.
Bạn có thể tham chiếu stash theo hai cách - bằng chỉ số dùng cú pháp
stash@{0}, hoặc dùnggit stash listđể tìm thông điệp bạn đã đặt và tham chiếu stash cụ thể đó. Chỉ số tiện cho stash gần đây, còn thông điệp hữu ích khi bạn có nhiều stash đã lưu.Đây là ví dụ một ngăn xếp stash điển hình:
Tiền tố
WIP onnghĩa là bạn dùnggit stashkhông kèm thông điệp. Tiền tốOnnghĩa là bạn đã cung cấp thông điệp tùy chỉnh vớigit stash push -m.Stash chỉ tồn tại trong kho cục bộ của bạn - chúng không được push lên remote. Điều này giữ cho công việc tạm thời ở đúng nơi nó thuộc về: trên máy của bạn, sẵn sàng khôi phục khi cần.
Tạo, Quản lý và Kiểm tra Stash
Lệnh git stash cơ bản là đủ để bắt đầu, nhưng khá "lười". Bạn sẽ có một đống mục "WIP on branch-name" mà không nói lên được gì bên trong. Sáu tuần sau, bạn sẽ không nhớ stash nào chứa bản vá lỗi và stash nào chứa phần refactor dở dang.
Giờ tôi sẽ chỉ bạn cách làm đúng ngay từ đầu.
Tạo stash với metadata phù hợp
Cách đơn giản nhất để stash là gõ
git stash:Lệnh này lưu thay đổi của bạn, nhưng thông điệp "WIP on main" không mấy thông tin. Bạn không thể biết bên trong có gì nếu không kiểm tra.
Thay vào đó, chạy
git stash push -mkèm một thông điệp mô tả:Giờ danh sách stash của bạn thực sự có ý nghĩa:
Sự khác biệt là quá rõ. Một mục nói chính xác bạn đã làm gì, còn mục kia bắt bạn phải đoán.
Hãy viết thông điệp như đang để lại ghi chú cho chính mình trong tương lai. "Thêm logic auth", "Sửa lỗi navbar", hoặc "Thử nghiệm thiết kế API mới" luôn tốt hơn các thông điệp WIP chung chung.
Bao gồm tệp chưa theo dõi hoặc bị bỏ qua
Theo mặc định,
git stashchỉ lưu các tệp đã được theo dõi - các tệp Git đã biết.Các tệp chưa theo dõi vẫn ở trong thư mục làm việc. Điều này hay khiến mọi người bất ngờ khi stash, chuyển nhánh, và thấy các tệp mới vẫn còn đó.
Đây là điều xảy ra:
Tệp không được stash vì Git chưa theo dõi nó:
Để xử lý, dùng cờ
-uđể stash cả tệp chưa theo dõi:Lệnh này stash cả tệp đã theo dõi lẫn chưa theo dõi. Thư mục làm việc của bạn trở nên hoàn toàn sạch.
Mẹo: Bạn có thể thêm cờ
-ađể bao gồm cả các tệp bị .gitignore bỏ qua. Nó sẽ stash các tệp đã theo dõi, chưa theo dõi, và các tệp trong.gitignore. Bạn hiếm khi cần điều này, trừ khi đang debug vấn đề build hoặc muốn lưu lại snapshot hoàn toàn sạch của mọi thứ.Đây là một cheat sheet để bạn biết khi nào dùng từng cờ:
Không có cờ: Bạn chỉ thay đổi các tệp đã tồn tại
uflag: Bạn đã thêm tệp mới chưa được theo dõiaflag: Bạn cần lưu mọi thứ, bao gồm đầu ra build hoặc tệp tạmPhần lớn thời gian, bạn sẽ dùng
-u. Đây là lựa chọn an toàn nhất khi bạn tạo tệp mới trong quá trình phát triển.Stash một phần hoặc có chọn lọc
Bạn không nhất thiết phải stash mọi thứ trong thư mục làm việc.
Giả sử bạn đã sửa hai lỗi, nhưng chỉ muốn stash một lỗi. Hoặc bạn có thay đổi ở năm tệp, nhưng chỉ ba tệp liên quan đến tính năng muốn lưu.
Bạn có thể stash các tệp cụ thể với pathspec:
Lệnh này chỉ stash
new_file.txtvànew_file_2.txt. Mọi thứ khác vẫn ở thư mục làm việc.Bạn cũng có thể dùng wildcard:
Hoặc dùng
--patchđể stash tương tác:Git duyệt qua từng thay đổi và hỏi bạn có muốn stash không. Bạn trả lời
y(yes),n(no), hoặcs(tách hunk này thành phần nhỏ hơn).Hữu ích khi bạn có thay đổi liên quan và không liên quan trộn trong cùng một tệp. Bạn stash phần công việc tính năng và để lại mã debug.
Đây là giao diện nhắc tương tác:
Liệt kê và kiểm tra stash
Như bạn đã thấy, bạn có thể chạy
git stash listđể xem mọi thứ đã stash:Stash gần nhất luôn là
stash@{0}. Các stash cũ dịch xuống chỉ số.Nếu bạn đã viết thông điệp tốt, bạn có thể lướt danh sách và biết chính xác nội dung từng stash. Nếu không, bạn sẽ phải kiểm tra từng cái một.
Dùng
git stash showđể xem tóm tắt:Lệnh này hiển thị tệp nào thay đổi và bao nhiêu dòng được thêm hoặc xóa.
Ngoài ra, dùng
git stash show -pđể xem toàn bộ khác biệt:Cờ -p hiển thị thay đổi mã thực tế, giống như
git diff. Đây là cách bạn xác nhận mình sẽ pop đúng stash trước khi chạygit stash pop.Thực chất Git Stash Pop làm gì
Giờ hãy nói về
git stash popthực sự làm gì và vì sao bạn nên dùng.Hành vi cơ bản và cú pháp
Lệnh
git stash poplàm hai việc: áp dụng các thay đổi đã stash và sau đó xóa stash đó khỏi ngăn xếp.Cú pháp cơ bản:
Lệnh này pop stash gần nhất (
stash@{0}) và xóa nó khỏi danh sách.Bạn cũng có thể pop một stash cụ thể bằng cách tham chiếu chỉ số của nó:
Lệnh này áp dụng
stash@{1}và xóa nó, nhưng có một điểm - các stash còn lại sẽ dịch lên. Cái trước làstash@{2}sẽ thànhstash@{1}, v.v.Git xử lý một lần stash pop như thế nào
Khi bạn chạy
git stash pop, Git thực hiện một lần merge ba chiều ở hậu trường.Nó so sánh ba trạng thái:
Nếu merge thành công không có xung đột, Git áp dụng thay đổi và xóa stash. Thư mục làm việc của bạn trông đúng như trước khi stash.
Đây là ví dụ quy trình làm việc đơn giản:
Nếu Git không thể merge sạch, bạn sẽ gặp xung đột. Stash vẫn ở trong ngăn xếp vì pop chưa hoàn tất thành công. Bạn sẽ thấy ký hiệu xung đột trong các tệp, giống như khi merge conflict thông thường.
Khi có xung đột, bạn cần tự xử lý, stage các tệp đã sửa và commit. Stash không tự biến mất, nên bạn cần chạy
git stash dropsau khi đã giải quyết xong.Áp dụng stash giữa các nhánh
Stash không gắn với nhánh cụ thể nào.
Bạn có thể tạo stash trên
bugfix, chuyển sangmain, và pop stash đó tại đây. Git không quan tâm stash đến từ đâu - nó chỉ cố áp dụng thay đổi vào nhánh bạn đang đứng.Điều này mở ra các quy trình hữu ích:
Di chuyển công việc giữa các nhánh: Giả sử bạn bắt đầu code trên nhánh sai. Thay vì reset và mất việc, bạn stash lại, chuyển sang nhánh đúng, và pop tại đó.
Tái tổ chức tác vụ: Bạn đã stash mã thử nghiệm một tuần trước. Giờ muốn thử nó trên nhánh khác xem có hợp hơn không.
Kiểm thử thay đổi trong các ngữ cảnh khác nhau: Bạn có một bản vá lỗi đã stash, và muốn thử trên nhiều nhánh trước khi commit. Hãy dùng
git stash applythay vìpopđể giữ stash lại, thử trên các nhánh khác nhau, rồipopở nhánh bạn muốn commit. Sẽ nói thêm vềapplyngay sau.Miễn là các thay đổi không xung đột với nhánh hiện tại, stash sẽ áp dụng sạch - đó là ý chính bạn cần nhớ.
Git Stash Pop so với Git Stash Apply
Các lập trình viên thường băn khoăn nên dùng
git stash pophaygit stash apply.Khác biệt chính: tính tồn tại của stash
Khác biệt chủ yếu rất đơn giản:
popxóa stash sau khi áp dụng, cònapplygiữ stash lại trong ngăn xếp.Với
pop, bạn nói "Tôi xong với stash này - áp dụng và bỏ đi." Vớiapply, bạn nói "Có thể tôi sẽ cần lại sau."Điều này ảnh hưởng đến quy trình của bạn theo hai cách:
An toàn: Nếu có sự cố trong quá trình
popvà bạn cần khôi phục, stash đã biến mất. Vớiapply, stash vẫn ở trong ngăn xếp như một bản dự phòng.Dọn dẹp: Dùng pop giúp danh sách stash sạch tự động. Dùng
applynghĩa là bạn phải tự chạygit stash dropsau đó để xóa các stash không còn cần.Đa số lập trình viên mặc định dùng pop vì sạch sẽ hơn. Nhưng apply tốt hơn khi bạn chưa chắc stash sẽ hoạt động sạch trên nhánh hiện tại, hoặc khi muốn thử cùng thay đổi trên nhiều nhánh.
Tính dự đoán, rủi ro, và dịch chuyển chỉ số
Đây là chỗ
poptrở nên rắc rối - chỉ số stash dịch chuyển khi bạn pop từ giữa ngăn xếp.Giả sử bạn có ba stash:
Nếu bạn pop
stash@{1}, các stash còn lại dịch lên:Điều này có thể gây vấn đề nếu bạn viết script Git hoặc chạy nhiều lệnh pop liên tiếp. Bạn pop
stash@{1}, rồi thử popstash@{2}, nhưng chỉ số đó không còn tồn tại.Lệnh
applykhông gặp vấn đề này. Chỉ số chỉ dịch chuyển khi bạn rõ ràng chạygit stash drop. Bạn có thể apply các stash theo bất kỳ thứ tự nào mà không lo ngăn xếp thay đổi ngoài ý muốn.Xử lý xung đột giống hệt nhau
Cả hai lệnh xử lý xung đột theo cách giống hệt nhau.
Nếu Git không thể merge sạch các thay đổi trong stash, bạn sẽ thấy ký hiệu xung đột trong tệp. Khác biệt là điều gì xảy ra với stash:
Với
pop: Stash vẫn ở trong ngăn xếp vì pop chưa hoàn tấtVới
apply: Stash vẫn ở trong ngăn xếp (vốn dĩ là như vậy)Trong cả hai trường hợp, bạn cần tự sửa xung đột, stage các tệp đã giải quyết bằng
git add, và xóa stash bằnggit stash drop(nếu dùngapply).Quy trình xử lý xung đột là giống nhau - điểm khác biệt duy nhất là stash có được xóa tự động khi thành công hay không.
Khi nào chọn mỗi lệnh
Dùng
git stash popkhi:Dùng
git stash applykhi:Xử lý Xung đột khi Stash Pop
Xung đột xảy ra khi Git không thể merge sạch các thay đổi trong stash. Phần này, tôi sẽ chỉ bạn cách xử lý.
Khi nào có xung đột và vì sao
Xung đột xảy ra trong quá trình merge ba chiều mà Git thực hiện khi bạn pop một stash.
Git so sánh ba phiên bản mã của bạn:
Nếu cùng dòng bị thay đổi ở nhánh hiện tại và trong stash, Git không biết giữ phiên bản nào. Đó là xung đột.
Nguyên nhân phổ biến của xung đột khi pop stash:
Nói chung, stash để càng lâu thì khả năng gặp xung đột khi pop càng cao.
Quy trình xử lý xung đột
Khi xung đột xảy ra, Git tạm dừng pop và đánh dấu xung đột trong tệp:
Tệp của bạn giờ có các ký hiệu xung đột:
Mọi thứ giữa
<<<<<<< Updated upstreamvà=======là mã hiện tại của bạn. Mọi thứ giữa=======và>>>>>>> Stashed changeslà từ stash.Bạn có thể làm như sau để sửa:
Mở tệp bị xung đột và quyết định giữ phiên bản nào (hoặc kết hợp cả hai)
Xóa các ký hiệu xung đột (
<<<<<<<,=======,>>>>>>>)Stage tệp đã giải quyết bằng
git addXóa stash thủ công bằng
git stash drop- nhớ rằng nó sẽ không biến mất tự động.Chiến lược thay thế
Nếu bạn không muốn xử lý xung đột ở nhánh hiện tại, hãy dùng
git stash branch.Lệnh này tạo một nhánh mới từ commit nơi bạn tạo stash, rồi áp dụng stash tại đó:
Git tạo nhánh tên
temp-feature, checkout nó, và pop stash của bạn lên đó. Vì nhánh bắt đầu từ đúng commit nơi bạn stash, sẽ không có xung đột. Tôi sẽ bàn kỹ hơn ở phần riêng.Bạn cũng có thể hủy một lần pop thất bại với
git reset --merge:Lệnh này hoàn tác nỗ lực pop và đưa thư mục làm việc về trạng thái trước khi pop. Stash vẫn ở trong ngăn xếp.
Hủy bỏ các thao tác stash đang diễn ra
Nếu bạn đã bắt đầu pop hoặc apply và muốn quay lại hoàn toàn, bạn có vài lựa chọn.
Với xung đột bạn chưa bắt đầu sửa, chạy lệnh sau:
Lệnh này hủy merge và dọn dẹp thư mục làm việc. Mọi thứ trở về như trước khi bạn chạy lệnh stash.
Với xung đột bạn đã sửa một phần, chạy lệnh này:
Lệnh này loại bỏ toàn bộ thay đổi trong thư mục làm việc, gồm cả các sửa bạn đã làm. Dùng khi bạn đã làm rối và muốn bắt đầu lại.
Hãy nhớ lệnh này sẽ hủy vĩnh viễn công việc chưa commit. Đảm bảo bạn thực sự muốn bỏ hết trước khi chạy.
Sau khi hủy, stash của bạn vẫn ở trong ngăn xếp (trừ khi bạn dùng
popvà nó đã thành công trước khi gặp xung đột). Bạn có thể thử lại sau, hoặc dùnggit stash branchđể tiếp cận sạch hơn.Dọn Dẹp Stash
Stash tích tụ rất nhanh trong các dự án dài hạn. Bạn stash công việc để sửa lỗi, rồi quên nó. Bạn tạo các stash thử nghiệm mà không bao giờ pop. Sáu tháng sau, bạn có 20 stash và không biết nửa trong số đó chứa gì.
Điều này khiến việc tìm stash bạn cần trở nên khó hơn. Bạn sẽ phải chạy
git stash show -pcho từng cái để biết bên trong có gì.Rất tốn thời gian, nên hãy nhớ dọn dẹp stash thường xuyên.
Xóa từng stash riêng lẻ
Dùng
git stash dropđể xóa một stash cụ thể:Lệnh này xóa
stash@{2}khỏi ngăn xếp. Các stash còn lại dịch lên - cái trước làstash@{3}sẽ thànhstash@{2}.Bạn cũng có thể xóa stash gần nhất mà không cần chỉ số:
Lệnh này mặc định xóa
stash@{0}.Theo nhiều năm làm việc với Git, những lý do hàng đầu khiến tôi xóa stash là khi:
Nếu chưa chắc có nên xóa stash, hãy dùng
git stash show -pđể kiểm tra trước. Cẩn tắc vô ưu.Xóa toàn bộ ngăn xếp stash
Bạn có thể dùng
git stash clearđể xóa tất cả stash cùng lúc:Hãy nhớ rằng thao tác này là vĩnh viễn. Bạn không thể hoàn tác hoặc khôi phục stash sau đó.
Chỉ dùng
git stash clearkhi bạn hoàn toàn chắc chắn không cần bất kỳ công việc nào đã stash.Phần lớn thời gian, xóa từng stash riêng lẻ là tốt hơn để tránh xóa nhầm thứ bạn cần.
Tạo Nhánh từ Stash
Đôi khi giải pháp sạch nhất là biến một stash thành nhánh riêng. Điều này tránh xung đột merge và cho công việc đã stash một chỗ ở đúng nghĩa.
Dùng git stash branch
Lệnh
git stash branchtạo nhánh mới và áp dụng stash của bạn lên đó:Diễn ra như sau:
Git tạo nhánh mới tên
feature-experimenttừ commit nơi bạn tạo stashGit checkout nhánh mới đó
Git pop stash lên nhánh
Git xóa stash khỏi ngăn xếp (giống như
pop)Vì nhánh bắt đầu từ đúng commit với stash, sẽ không có xung đột. Các thay đổi luôn áp dụng sạch.
Bạn cũng có thể dùng một stash cụ thể thay vì cái gần nhất:
Các trường hợp sử dụng phổ biến
Tạo nhánh từ stash rất phù hợp cho các tính năng thử nghiệm. Giả sử bạn đã stash một số mã thử nghiệm cách đây một tuần, và giờ muốn phát triển nó đàng hoàng mà không làm rối công việc hiện tại.
Bạn có một nhánh sạch để làm việc với thử nghiệm. Nếu hiệu quả, bạn merge lại. Nếu không, bạn xóa nhánh và tiếp tục.
Nó cũng tuyệt cho các lần rebase dài. Thay vì xử lý khả năng xung đột trong quá trình rebase, bạn có thể stash mọi thứ và tạo nhánh từ đó.
Giờ bạn có thể xem lại các thay đổi đã stash riêng biệt và quyết định cách tích hợp chúng sau khi rebase.
Tạo nhánh cũng hữu ích để tách biệt các thay đổi lớn hoặc lộn xộn. Hãy tưởng tượng bạn có một stash khổng lồ với thay đổi ở 15 tệp, một nửa xung đột với nhánh hiện tại. Chỉ cần tạo nhánh mới - không cần vật lộn.
Bạn có một nhánh riêng để xem lại mọi thứ một cách bình tĩnh, commit đúng chuẩn, rồi merge lại với lịch sử rõ ràng.
Kỹ thuật Nâng cao và Phương án Khôi phục
Đến giờ bạn đã quen với những điều cơ bản của
git stash, nên tôi sẽ chỉ bạn vài khái niệm nâng cao hơn.Làm việc với các mục stash cụ thể
Bạn có thể pop hoặc apply bất kỳ stash nào trong ngăn xếp, không chỉ cái gần nhất.
Chỉ cần tham chiếu stash bằng chỉ số để lấy đúng thứ bạn cần:
Điều này cho phép bạn lấy stash cũ hơn mà không đụng tới những cái mới. Khi bạn pop một stash ở giữa, mọi chỉ số phía dưới sẽ dịch lên. Cái trước là
stash@{4}sẽ thànhstash@{3}, v.v. Nếu bạn đang viết script Git hoặc pop nhiều stash liên tiếp, việc dịch chỉ số này có thể làm hỏng lệnh của bạn.Giải pháp là dùng
applythay vìpopkhi bạn cần chỉ số dự đoán được:Cách này cho bạn toàn quyền kiểm soát khi nào ngăn xếp thay đổi. Bạn apply stash, xác nhận mọi thứ hoạt động đúng, rồi tự tay drop. Chỉ số chỉ dịch khi bạn yêu cầu rõ ràng.
Khôi phục trạng thái staged
Theo mặc định,
git stash popvàgit stash applykhôi phục thay đổi của bạn nhưng không giữ lại những gì đã stage.Giả sử bạn sửa ba tệp, và đã stage hai tệp để commit trước khi stash. Khi pop stash đó, cả ba tệp quay lại dưới dạng thay đổi chưa stage. Git không còn biết bạn muốn commit tệp nào.
Giải pháp là dùng cờ
--indexđể khôi phục trạng thái staging đúng như trước:Lệnh này tái tạo chính xác working tree và index trước khi stash. Tệp nào đã stage sẽ vẫn stage. Tệp nào chưa stage vẫn chưa stage. Mọi thứ về đúng chỗ.
Bạn sẽ cần cờ này khi:
Bạn đang chuẩn bị một commit được stage cẩn thận và không thể để mất thông tin staging đó
Bạn làm việc với kịch bản staging phức tạp, như khi dùng git add
-pđể stage chỉ một số hunkBạn muốn thư mục làm việc trông đúng như trước khi stash, không ngoại lệ
Phần lớn thời gian, bạn sẽ không cần cờ này. Bạn pop stash, xem những gì trở lại, và stage những gì cần.
Khôi phục khi mắc lỗi với stash
Rồi sẽ có lúc bạn drop nhầm một stash cần thiết hoặc lỡ clear cả ngăn xếp.
Nếu điều đó xảy ra, reflog của git có thể cứu bạn.
Reflog theo dõi mọi thay đổi tham chiếu trong kho của bạn, bao gồm stash. Khi bạn tạo hoặc drop một stash, Git ghi lại trong reflog. Ngay cả sau khi drop, các commit đó vẫn tồn tại một thời gian như đối tượng không thể truy cập.
Bạn có thể tìm stash đã mất bằng cách tìm commit không thể truy cập:
Giờ bạn có thể kiểm tra từng commit để tìm stash của mình:
Xem diff và thông điệp commit để xác định đâu là stash đã mất. Khi tìm thấy, hãy khôi phục nó:
Lệnh này áp dụng stash đã mất vào thư mục làm việc như thể nó chưa từng bị drop.
Tốt hơn nữa, hãy ngăn lỗi ngay từ đầu bằng cách làm theo các thực hành tốt sau:
Viết thông điệp stash có mô tả để bạn biết chính xác mình đang drop gì. "Sửa lỗi đăng nhập" tốt hơn "WIP" khi bạn nhìn vào danh sách năm stash.
Dùng
git stash show -ptrước khi drop để xác nhận đó là stash đúng. Mất năm giây để kiểm tra còn hơn năm phút để khôi phục.Dọn ngăn xếp stash thường xuyên để nó không bừa bộn. Ngăn xếp với ba stash liên quan dễ điều hướng hơn nhiều so với 15 mục cũ.
Dùng
applythay vìpopkhi bạn chưa 100% chắc muốn xóa stash. Bạn luôn có thể drop sau khi đã xác minh mọi thứ hoạt động.Reflog có thể giúp khôi phục, nhưng khá mất công. Chỉ cần nhìn vào hình trên để thấy tôi sẽ phải kiểm tra thủ công bao nhiêu commit - và đây chỉ là một dự án nhỏ tạo ra cho bài viết này.
Thực hành Tốt và Hướng dẫn Quy trình
Dùng stash hiệu quả nghĩa là làm theo các mô thức giúp ngăn lỗi và giữ quy trình của bạn sạch sẽ. Tôi sẽ chỉ bạn cách tiếp cận ưa thích của mình.
Mô thức quy trình được khuyến nghị
Quy trình stash an toàn nhất theo mẫu đơn giản: stash kèm thông điệp, chuyển ngữ cảnh, rồi pop khi bạn sẵn sàng tiếp tục.
Cách này phù hợp cho hầu hết tình huống. Bạn bảo toàn công việc, xử lý gián đoạn, và khôi phục mọi thứ sạch sẽ.
Một mô thức phổ biến khác là quy trình "kiểm tra trước khi pop". Bạn liệt kê các stash, xem bên trong có gì, rồi pop cái phù hợp.
Bước xác minh bổ sung này ngăn bạn pop nhầm stash hoặc áp dụng công việc đã lỗi thời.
Một số lập trình viên thích lựa chọn "commit miễn cưỡng" thay cho stashing. Thay vì stash, họ tạo commit tạm với thông điệp như "WIP - not ready" rồi amend hoặc reset sau. Cách này hữu ích nếu bạn không thoải mái với stash hoặc muốn công việc được theo dõi trong lịch sử nhánh. Điểm trừ là bạn có thể để lại lịch sử commit lộn xộn nếu quên dọn.
Tích hợp với công cụ phát triển
Hầu hết GUI Git hiển thị stash trực quan và cho phép pop hoặc apply chỉ bằng một cú nhấp.
Các công cụ như GitKraken, Sourcetree, và GitHub Desktop liệt kê stash trong thanh bên. Bạn có thể xem thông điệp, xem diff, và apply hoặc drop stash mà không cần gõ lệnh. Điều này hữu ích khi bạn có nhiều stash và muốn so sánh chúng cạnh nhau.
Phần mở rộng Git của VS Code hiển thị stash trong bảng điều khiển source control. Bạn có thể nhấp phải để pop, apply, hoặc drop ngay trong trình soạn thảo.
Alias shell giúp stash nhanh hơn nếu bạn thích dòng lệnh. Thêm các lệnh này vào
.bashrchoặc.zshrc:Giờ đây gst sẽ stash công việc của bạn,
gstppop nó,gstlliệt kê các stash, vàgstshiển thị diff. Bạn tiết kiệm được vài lần gõ mỗi lần.Vệ sinh stash và cân nhắc cho nhóm
Stash là cục bộ trên máy bạn - chúng không bao giờ được push lên kho từ xa.
Điều này có nghĩa đồng đội không thể thấy stash của bạn, và bạn cũng không thể truy cập chúng từ máy khác. Nếu cần chia sẻ công việc đang làm, đừng stash. Hãy dùng patch hoặc nhánh tạm.
Để chia sẻ công việc qua patch, chạy:
Giờ hãy gửi tệp patch cho đồng đội, và họ sẽ áp dụng bằng cách chạy
git apply my-work.patch.Để chia sẻ công việc qua nhánh tạm, chạy:
Đồng đội có thể pull nhánh, xem xét công việc, và tiếp tục từ đó.
Dù bạn chọn cách nào làm mặc định, luôn duy trì vệ sinh stash tốt. Điều này sẽ tránh nhầm lẫn và giúp ngăn xếp cục bộ dễ quản lý. Dưới đây là vài thực hành tốt:
Dùng tên mô tả cho mỗi stash. "Thêm logic xác thực người dùng" cho biết bên trong có gì. "WIP on feature-branch" thì không.
Dọn stash hàng tuần. Chạy
git stash listvà drop mọi thứ cũ hơn một tuần. Nếu bảy ngày rồi bạn chưa cần, có lẽ sẽ không cần nữa.Đừng để số lượng stash vượt quá năm. Nhiều hơn năm stash nghĩa là bạn đang dùng chúng như kho lưu trữ dài hạn thay vì tạm thời. Hãy pop, commit công việc, hoặc drop.
Nếu bạn làm việc theo nhóm và ai đó hỏi, "Đoạn mã bạn đang làm đâu?", đừng bao giờ trả lời, "Trong stash của tôi." Stash là riêng tư và tạm thời - không dùng để chia sẻ hay lưu trữ công việc quan trọng.
Kết luận
Giờ bạn đã biết
git stash pophoạt động thế nào và khi nào nên dùng.Cốt lõi, stashing rất đơn giản: lưu công việc chưa commit, chuyển ngữ cảnh, và khôi phục sau. Nhưng chi tiết mới quan trọng. Biết khi nào dùng
popso vớiapply, cách xử lý xung đột, và khi nào tạo nhánh từ stash sẽ giúp bạn tiết kiệm hàng giờ bực bội.Điều quan trọng nhất cần nhớ là stash là lưu trữ tạm thời, không phải sao lưu vĩnh viễn. Hãy dùng thông điệp mô tả, dọn dẹp thường xuyên, và đừng để ngăn xếp vượt quá năm mục. Nếu cần chia sẻ công việc hoặc giữ lâu dài, hãy commit lên một nhánh.
Nếu bạn thấy hữu ích và muốn giỏi Git hơn, điểm dừng tiếp theo nên là các khóa Intermediate Git và Intermediate GitHub Concepts của chúng tôi.