Stashing chỉ thay đổi không theo giai đoạn trong Git


229

Tôi muốn thực hiện các công việc sau đây:

  1. Thêm thay đổi vào giai đoạn.
  2. Stash tất cả các thay đổi khác mà không được dàn dựng.
  3. Làm một số thứ với những thứ trong giai đoạn (ví dụ: xây dựng, chạy thử nghiệm, v.v.)
  4. Áp dụng stash.

Có cách nào để làm bước 2 không?

Thí dụ

 echo "123" > foo
 git add foo # Assumes this is a git directory
 echo "456" >> foo
 git stash
 cat foo # Should yield 123

Tại sao không cam kết thay đổi của bạn sau khi dàn dựng chúng?
Shizzmo

3
IIRC --keepindex thực hiện chính xác điều đó
sehe

4
Bởi vì, nếu, nói, việc xây dựng thất bại tôi không muốn có một cam kết về điều này. Tôi biết tôi có thể xóa cam kết nhưng tôi muốn thực hiện việc này mà không cần cam kết nếu có thể.
Unapiedra

Sehe, cảm ơn. Tôi có thể xác nhận điều này hoạt động. Gee, tôi đã xem hướng dẫn tại linux.die.net/man/1/git-stash đã hết hạn. man git stashtốt hơn nhiều
Unapiedra

đó là --keep-index, fwiw.
jaf0

Câu trả lời:


288

git stash savecó một tùy chọn --keep-indexthực hiện chính xác những gì bạn cần.

Vì vậy, chạy git stash save --keep-index.


9
Thật. Tôi tiếp tục sử dụng savevới git stash. Có lẽ đó là lập trình viên trong tôi khăng khăng tôn vinh sự đối xứng với ứng dụng / pop. :)
vhallac

104
Lưu ý: điều này vẫn còn lưu lại tất cả các thay đổi của bạn; sự khác biệt duy nhất so với thông thường git stash savelà nó cũng để lại những thay đổi đã được dàn dựng trong bản sao làm việc của bạn. Trong quy trình làm việc ở trên, điều này sẽ hoạt động tốt vì bạn chỉ cần áp dụng stash trên một bản sao cục bộ đã có một nửa các thay đổi của stash (git đủ thông minh để bỏ qua). Nhưng nếu bạn chỉnh sửa mã trước khi áp dụng lại stash, bạn có thể thấy xung đột hợp nhất khi bạn đi áp dụng. Fyi.
peterflynn

2
@ytpete Điều đó đã cắn tôi rất nhiều lần. Tôi thực sự mong muốn có một cách để git chỉ cất giấu những thứ bạn không giữ ... Tôi thường cam kết, sau đó thực hiện một cú git đầy đủ, biết rằng tôi có thể git commit --ammendnếu có vấn đề trong những gì tôi đã cam kết.
rjmunro

1
--amend(chứ không phải --ammend)
Đại hoàng

19
Giải pháp này không hiệu quả với tôi vì những vấn đề được mô tả bởi peterflynn. Nó không phải là một câu trả lời tốt cho câu hỏi vì nó vẫn còn thay đổi các giai đoạn. Bất cứ ai cũng có một giải pháp tốt hơn?
dùng643011

43

Điều này có thể được thực hiện trong 3 bước: lưu các thay đổi theo giai đoạn, bỏ qua mọi thứ khác, khôi phục chỉ mục với các thay đổi theo giai đoạn. Về cơ bản là:

git commit -m 'Save index'
git stash push -u -m 'Unstaged changes and untracked files'
git reset --soft HEAD^

Điều này sẽ làm chính xác những gì bạn muốn.


3
Lưu ý: -ucũng lưu trữ các tệp không bị theo dõi.
ma11hew28

Cách tiếp cận này về cơ bản sao chép những gì git stash save --keep-indexlàm với nhiều công việc hơn. Tôi không thấy bất kỳ lợi thế.
Inigo

1
@vas Không, cách tiếp cận không trùng lặp điều đó. Xem bình luận của peterflynn cho câu trả lời được chấp nhận.
Alexander Klauer

28
git stash save --keep-index

Ngoài ra, Re:

Tại sao không cam kết thay đổi của bạn sau khi dàn dựng chúng? - Shin

Trả lời: Bởi vì bạn phải luôn kiểm tra mã đã kiểm tra :) Điều đó có nghĩa là, bạn cần chạy thử nghiệm chỉ với những thay đổi bạn sắp thực hiện

Tất cả điều này ngoài thực tế là, tất nhiên, là một lập trình viên có kinh nghiệm, bạn có sự thôi thúc bẩm sinh để kiểm tra và xem xét những thay đổi đó - chỉ một phần đùa


14

Với git version 2.7.4bạn có thể làm:

git stash save --patch

Các gitsẽ yêu cầu bạn thêm hoặc không thay đổi của bạn vào stash.
Và sau đó bạn chỉ cần trả lời yhoặcn

Bạn có thể khôi phục thư mục làm việc như bạn luôn làm điều đó:

git stash pop

hoặc, nếu bạn muốn giữ các thay đổi đã lưu trong stash:

git stash apply

Điều này thật tuyệt. Nó hơi tốn nhiều công sức, nhưng ít nhất bạn có thể bỏ qua và thêm toàn bộ tệp.
Dustin Oprea

5

Mở rộng các câu trả lời trước đây, đôi khi tôi có một tập hợp các thay đổi phức tạp được dàn dựng, nhưng trước tiên muốn thực hiện một thay đổi riêng biệt. Ví dụ: tôi có thể đã phát hiện ra một lỗi hoặc mã không chính xác mà tôi muốn sửa trước các thay đổi theo giai đoạn của mình. Một lộ trình có thể thực hiện là:

đầu tiên cất giấu mọi thứ, nhưng giữ nguyên các thay đổi theo giai đoạn

$ git stash save --keep-index [--incolee-unsracked]

bây giờ cũng bỏ qua các thay đổi theo giai đoạn

$ git stash tiết kiệm

thay đổi để sửa chữa; và kiểm tra; cam kết với họ:

$ git thêm [- tương tác] [--patch]

$ git commit -m "sửa ..."

bây giờ khôi phục các thay đổi theo giai đoạn trước:

$ git stash pop

giải quyết bất kỳ xung đột nào và lưu ý rằng nếu có xung đột, git sẽ áp dụng nhưng không bỏ mục nhập stash hàng đầu đó.

(... Sau đó, thực hiện các thay đổi theo giai đoạn và khôi phục lại tất cả các thay đổi khác và tiếp tục ...)


4

Để thêm các tệp không được gắn (không được thêm vào cam kết) vào stash, hãy chạy lệnh sau:

git stash -k

Sau đó, bạn có thể cam kết các tập tin dàn dựng. Sau đó, bạn có thể lấy lại các tệp được lưu cuối cùng bằng lệnh:

git stash pop

4

Stashing chỉ cây làm việc (thay đổi chưa được thực hiện) trong Git là khó khăn hơn nó nên được. Câu trả lời được chấp nhận sẽ loại bỏ những thay đổi không được nêu ra, nhưng cũng tạo ra những thay đổi được dàn dựng (và cũng để chúng được dàn dựng), đây là điều hiếm khi bạn muốn.

Bí danh này hoạt động tốt:

stash-working = "!f() { \
  git commit --quiet -m \"temp for stash-working\" && \
  git stash push \"$@\" && \
  git reset --quiet --soft HEAD~1; }; f"

Nó tạm thời thực hiện các thay đổi theo giai đoạn, tạo ra một ngăn từ các thay đổi còn lại (và cho phép các đối số bổ sung như --include-untracked--messageđược chuyển thành đối số bí danh), sau đó đặt lại cam kết tạm thời để lấy lại các thay đổi theo giai đoạn.

Nó tương tự như câu trả lời của @Simon Knapp , nhưng với một vài khác biệt nhỏ - nó sử dụng --quietcho các hành động tạm thời được thực hiện và nó chấp nhận bất kỳ số lượng tham số nào cho stash push, thay vì mã hóa cứng -m, và nó thêm --softvào cuối cùng thiết lập lại để chỉ mục vẫn như nó bắt đầu.

Đối với các vấn đề ngược lại của stashing chỉ các thay đổi theo giai đoạn (bí danh stash-index) xem câu trả lời này .


2

Một mẹo khác, liên quan đến câu hỏi:

Khi bạn thực hiện hiệu quả các thay đổi chưa được thực hiện của mình bằng cách sử dụng

$ git stash lưu --keep-index

bạn có thể muốn gửi cho stash một thông báo, để khi bạn thực hiện một git stash listđiều rõ ràng hơn những gì bạn đã cất trước đó, đặc biệt là nếu bạn thực hiện thao tác stash đó bằng cách tiết kiệm thêm. Ví dụ

$ git stash save --keep-index "những thay đổi chưa được tổ chức"

(mặc dù thực tế nó có chứa tất cả các thay đổi như được ghi chú trong các câu trả lời khác).

Ví dụ, ở trên có thể được theo sau bởi:

$ git stash lưu "thay đổi theo giai đoạn cho tính năng X"

Mặc dù vậy, hãy coi chừng rằng bạn không thể sử dụng

$ git stash áp dụng "stash @ {1}" ### không hoàn toàn làm những gì bạn muốn

để khôi phục chỉ những thay đổi chưa được tổ chức.


2

Git không có lệnh chỉ xử lý các thay đổi chưa được thực hiện của bạn.

Git, tuy nhiên, cho phép bạn chỉ định tệp nào bạn muốn lưu trữ.

git stash push --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

Nếu bạn chỉ muốn bỏ các thay đổi cụ thể trong các tệp đó, hãy thêm --patchtùy chọn.

git stash push --patch --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

Các --include-untrackedtùy chọn cho phép bạn giấu các file được theo dõi.

git stash push --include-untracked --message 'Untracked files' -- app/controllers/widgets_controller.rb test/controllers/widgets_controller_test.rb

Chạy git help stash(hoặc man git-stash) để biết thêm.

Lưu ý: Nếu những thay đổi không được sắp xếp của bạn khá không được thống nhất, câu trả lời của @ alesguzik có lẽ dễ dàng hơn.


0

Hình thức hiện đại của lệnh đó là git stash push [--] [<pathspec>...]vì Git 2.16+ ( git stash savekhông dùng nữa )

Bạn có thể kết hợp điều đó với một hình thức ký tự đại diện, ví dụ:

git stash push --all --keep-index ':(glob)**/*.testextension' 

Nhưng điều đó không hoạt động tốt với Git cho Windows, cho đến Git 2.22 (quý 2 năm 2019), xem vấn đề 2037 , xem xét git stashđã được triển khai lại trong C (thay vì tập lệnh shell)

Xem cam kết 7db9302 (11 tháng 3 năm 2019) của Thomas Gummerer ( tgummerer) .
Xem cam kết 1366c78 , cam kết 7b556aa (07 tháng 3 năm 2019) của tác giả Julian Schindelin ( dscho) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 0ba1ba4 , ngày 22 tháng 4 năm 2019)

dựng sẵn stash: xử lý :(glob)lại các pathspecs

Khi chuyển một danh sách các đường dẫn đến, hãy nói, git add chúng ta cần cẩn thận để sử dụng biểu mẫu gốc, chứ không phải dạng phân tích cú pháp của các pathspecs.

Điều này tạo ra sự khác biệt, ví dụ như khi gọi

git stash -- ':(glob)**/*.txt'

trong đó biểu mẫu gốc bao gồm :(glob)tiền tố trong khi biểu mẫu được phân tích cú pháp thì không.

Tuy nhiên, trong phần dựng sẵn git stash, chúng tôi đã chuyển biểu mẫu được phân tích cú pháp (nghĩa là không chính xác) và git addsẽ thất bại với thông báo lỗi:

fatal: pathspec '**/*.txt' did not match any files

ở giai đoạn git stashbỏ các thay đổi từ bàn làm việc, ngay cả khi refs/stashđã thực sự được cập nhật thành công.


0

Tôi sử dụng một bí danh, chấp nhận một chuỗi để sử dụng làm thông điệp cho mục nhập stash.

mystash = "!f() { git commit -m hold && git stash push -m \"$1\" && git reset HEAD^; }; f"

Mà:

  • cam kết mọi thứ trong chỉ mục,
  • stash những gì được thay đổi trong cây làm việc (tất nhiên có thể thêm -uhoặc-a ),
  • đặt lại cam kết cuối cùng trở lại thử làm việc (có thể muốn sử dụng --softđể giữ nó trong chỉ mục).
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.