Làm cách nào để tôi trích xuất một tệp duy nhất (hoặc thay đổi thành tệp) từ tệp git?


774

Tôi muốn biết liệu có thể trích xuất một tệp hoặc diff của một tệp từ một git stash mà không làm tắt các thay đổi của stash không.

Bất cứ ai cũng có thể cung cấp một số gợi ý / ý tưởng về điều này?

Câu trả lời:


1131

Trên trang chủ git stash, bạn có thể đọc (trong phần "Thảo luận", ngay sau phần mô tả "Tùy chọn"):

Stash được biểu diễn dưới dạng một xác nhận có cây ghi lại trạng thái của thư mục làm việc và cha mẹ đầu tiên của nó là xác nhận tại HEAD khi stash được tạo.

Vì vậy, bạn có thể coi stash (ví dụ: stash stash@{0}đầu tiên / trên cùng) như một cam kết hợp nhất và sử dụng:

$ git diff stash@{0}^1 stash@{0} -- <filename>

Giải thích: stash@{0}^1có nghĩa là cha mẹ đầu tiên của stash đã cho, như đã nêu trong phần giải thích ở trên là cam kết mà tại đó các thay đổi được bỏ đi. Chúng tôi sử dụng hình thức "git diff" này (với hai lần xác nhận) bởi vì stash@{0}/ refs/stashlà một cam kết hợp nhất và chúng tôi phải nói với git mà cha mẹ chúng tôi muốn chống lại. Khó hiểu hơn:

$ git diff stash@{0}^! -- <filename>

cũng nên hoạt động (xem trang chủ git rev-parse để giải thích rev^!cú pháp, trong phần "Chỉ định phạm vi").

Tương tự, bạn có thể sử dụng git checkout để kiểm tra một tệp duy nhất trong stash:

$ git checkout stash@{0} -- <filename>

hoặc để lưu nó dưới tên tệp khác:

$ git show stash@{0}:<full filename>  >  <newfile>

hoặc là

$ git show stash@{0}:./<relative filename> > <newfile>

( lưu ý rằng ở đây <tên tệp đầy đủ> là tên đường dẫn đầy đủ của một tệp liên quan đến thư mục trên cùng của dự án (nghĩ: liên quan đến stash@{0})).


Bạn có thể cần phải bảo vệ stash@{0}khỏi sự mở rộng vỏ, tức là sử dụng "stash@{0}"hoặc 'stash@{0}'.


8
Điều này khá tuyệt ... Tôi thực sự không hiểu stash hoạt động như thế nào cho đến khi tôi đọc câu trả lời của bạn (điều này dẫn tôi đến phần bổ sung kiểm tra git). Tôi thực sự không hiểu điều đó, khi bạn thực hiện stash, git lưu TWO cam kết - một cho trạng thái của chỉ mục và một cho trạng thái của bản sao làm việc là sự hợp nhất giữa chỉ mục và ĐẦU gốc. Điều này giải thích những cây kỳ lạ mà tôi đã thấy khi tôi hình dung kho lưu trữ với "gitk --all" khi có stash.
Pat Notz

4
Hầu hết tôi thấy ứng dụng kiểm tra git là cách tốt nhất để thực hiện những gì tôi muốn làm. Tuy nhiên tôi đã tò mò và kiểm tra lại git checkouttrang của người đàn ông. Nó không thể thả tập tin vào một vị trí khác. Có một tài liệu tham khảo về điều này trong: stackoverflow.com/questions/888414/ Kẻ
Danny

84
$ git checkout stash @ {0} - <tên tệp> rất hữu ích, cảm ơn
trọng lực

43
Lưu ý rằng git checkoutcách tiếp cận sao chép tệp chính xác từ stash - nó không hợp nhất nó với những gì trong thư mục làm việc của bạn như thế git stash applynào. (Vì vậy, nếu bạn có bất kỳ thay đổi nào từ cơ sở, stash đã được tạo, chúng sẽ bị mất).
peterflynn

4
Lưu ý rằng git stash applyđể hợp nhất các thay đổi trong tệp đã được sửa đổi trong cây công việc kể từ khi tệp được lưu, tệp đó trong cây công việc phải được tổ chức. Để tự động hợp nhất để hoạt động, các tệp tương tự có thể được sửa đổi cả trong bản sao làm việc và trong bản sao được sắp xếp hợp nhất. Cuối cùng, stash áp dụng không loại bỏ mục khỏi stash như mong git stash popmuốn.
Ville

46

Nếu bạn sử dụng git stash applychứ không phải git stash pop, nó sẽ áp dụng stash cho cây làm việc của bạn nhưng vẫn giữ stash.

Khi thực hiện xong, bạn có thể add/ committệp bạn muốn và sau đó đặt lại các thay đổi còn lại.


2
Để bật một stash cụ thể: git stash pop stash@{0}(liệt kê những thay đổi cất giấu: git stash list)
MrYoshiji

Nếu các tệp khác trong ngăn chứa gây ra xung đột hợp nhất, git không cho phép tôi cam kết với tệp tôi muốn :(
cambuncious 7/12/19

33

Có một cách dễ dàng để nhận các thay đổi từ bất kỳ chi nhánh nào, bao gồm cả stash:

$ git checkout --patch stash@{0} path/to/file

Bạn có thể bỏ qua thông số tệp nếu bạn muốn vá ở nhiều phần. Hoặc bỏ qua bản vá (nhưng không phải đường dẫn) để có được tất cả các thay đổi đối với một tệp. Thay thế 0bằng số stash từ git stash list, nếu bạn có nhiều hơn một. Lưu ý rằng điều này là như thế diff, và cung cấp để áp dụng tất cả sự khác biệt giữa các chi nhánh. Để nhận được các thay đổi chỉ từ một cam kết / stash duy nhất, hãy xem xét git cherry-pick --no-commit.


Điều này sao chép tập tin chính xác từ stash, hoặc nó hợp nhất? Trong trường hợp sao chép, nếu bạn có bất kỳ thay đổi nào kể từ khi stash được tạo, chúng sẽ bị mất.
Danijel

2
@Danijel Đọc git help checkout. --patchkhông hợp nhất tương tác, Nó áp dụng bất cứ thứ gì bạn chấp nhận trong vỏ (hoặc bất cứ thứ gì bạn lưu nếu bạn chọn để evá miếng vá). Đường dẫn một mình sẽ ghi đè lên tệp, như tôi đã viết, "tất cả thay đổi".
Walf

1
cải thiện nhẹ: git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' - sau đó thực hiện git applydiffat stash@{4}chỉ sử dụng các tệp đã thay đổi giữa stash và cha mẹ của nó.
Đánh dấu

25

Câu trả lời ngắn

Để xem toàn bộ tập tin: git show stash@{0}:<filename>

Để xem khác biệt: git diff stash@{0}^1 stash@{0} -- <filename>


1
Tôi không nghĩ rằng anh ấy / anh ấy quan tâm đến việc xem stash cho một tệp cụ thể - chỉ xuất hiện tệp đó.
Amalgovinus

1
Đây là những gì tôi đang tìm kiếm. Sau đó, bạn có thể thay thế diffbằng difftoolsử dụng yêu thích khác bên ngoài của bạn.
Peet Brits

19
$ git checkout stash@{0} -- <filename>

Ghi chú:

  1. Đảm bảo bạn đặt khoảng trắng sau "-" và tham số tên tệp

  2. Thay số 0 (0) bằng số stash cụ thể của bạn. Để có được danh sách stash, sử dụng:

    git stash list
    

Dựa trên câu trả lời của Jakub Narębski - Phiên bản ngắn hơn


11

Bạn có thể nhận được khác biệt cho một stash với " git show stash@{0}" (hoặc bất kể số lượng của stash là gì; xem "danh sách git stash"). Thật dễ dàng để trích xuất phần của diff cho một tệp.


2
Đơn giản hơn cho những người như tôi: sử dụng git show stashđể hiển thị stash trên cùng (thường là người duy nhất bạn có). Tương tự như vậy, bạn có thể hiển thị khác biệt giữa chi nhánh hiện tại của bạn và stash với git diff head stash.
Dizzley

5

Khái niệm đơn giản nhất để hiểu, mặc dù có thể không phải là tốt nhất, là bạn có ba tệp được thay đổi và bạn muốn bỏ một tệp.

Nếu bạn làm git stashđể bỏ tất cả chúng, git stash applyđể đưa chúng trở lại một lần nữa và sau đó git checkout f.cvào tập tin được đề cập để thiết lập lại nó một cách hiệu quả.

Khi bạn muốn hủy kích hoạt tệp đó, hãy thực hiện git reset --hardvà sau đó chạy git stash applylại, lợi dụng thực tế là git stash applykhông xóa khác biệt khỏi ngăn xếp.


1

Nếu các tệp được lưu trữ cần hợp nhất với phiên bản hiện tại, vì vậy hãy sử dụng các cách trước đó bằng cách sử dụng diff. Nếu không, bạn có thể sử dụng git popđể hủy bỏ chúng, git add fileWantToKeepđể dàn dựng tệp của bạn và thực hiện git stash save --keep-index, để xóa tất cả mọi thứ trừ những gì trên sân khấu. Hãy nhớ rằng sự khác biệt của cách này với các cách trước đó là nó "bật" tệp khỏi stash. Các câu trả lời trước giữ nó git checkout stash@{0} -- <filename>để nó đi theo nhu cầu của bạn.


0

Sử dụng cách sau để áp dụng các thay đổi cho tệp trong stash cho cây làm việc của bạn.

git diff stash^! -- <filename> | git apply

Điều này thường tốt hơn so với việc sử dụng git checkoutvì bạn sẽ không mất bất kỳ thay đổi nào bạn đã thực hiện đối với tệp kể từ khi bạn tạo stash.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.