Chỉ lưu một tệp trong số nhiều tệp đã thay đổi bằng Git?


3071

Làm cách nào tôi chỉ có thể bỏ một trong nhiều tệp đã thay đổi trên nhánh của mình?


109
Tôi không nghĩ câu trả lời được chấp nhận của @ bukzor là câu trả lời chính xác cho câu hỏi khi được hỏi. git stash --keep-indexkhông giữ chỉ mục, nhưng nó làm hỏng mọi thứ - cả trong chỉ mục và ngoài.
Raman

@Antonio Dường như với tôi, tiền thưởng của bạn thực sự nên là một câu hỏi riêng biệt, vì câu hỏi ban đầu không liên quan gì đến TortoiseGit.
JesusFreke

1
@JesusFreke Yep, đưa ra kết quả tôi có thể bỏ qua 50 rep :) Chỉ là đây là câu hỏi mà bạn được chuyển hướng đến nếu bạn cố gắng tìm kiếm "stash tortoisegit một phần". Tortoisegit dường như không phải là một chủ đề phổ biến ở đây stackoverflow.com/questions/tagged/tortoisegit
Antonio

7
>>>>>>>>> git diff -- *filename* > ~/patchsau đó git checkout -- *filename*và sau này bạn có thể áp dụng lại bản vá vớigit apply ~/patch
neaumusic

36
Hầu hết các câu trả lời hiện có dưới đây đã lỗi thời. Kể từ Git 2.13 (quý 2 năm 2017), nó được hỗ trợ git stash push [--] [<pathspec>...].
Ohad Schneider

Câu trả lời:


1372

Disclaimer : câu trả lời sau đây là dành cho git trước git 2.13. Đối với git 2.13 trở lên, hãy xem thêm câu trả lời khác .


Cảnh báo

Như đã lưu ý trong các bình luận, điều này đặt mọi thứ vào stash, cả được dàn dựng và không được dàn dựng. --Keep-index chỉ để lại chỉ mục một mình sau khi stash được thực hiện. Điều này có thể gây ra xung đột hợp nhất khi bạn bật stash sau đó.


Điều này sẽ bỏ qua mọi thứ mà bạn chưa thêm trước đó. Chỉ cần git addnhững thứ bạn muốn giữ, sau đó chạy nó.

git stash --keep-index

Ví dụ: nếu bạn muốn tách một cam kết cũ thành nhiều thay đổi, bạn có thể sử dụng quy trình này:

  1. git rebase -i <last good commit>
  2. Đánh dấu một số thay đổi là edit.
  3. git reset HEAD^
  4. git add <files you want to keep in this change>
  5. git stash --keep-index
  6. Sửa chữa mọi thứ khi cần thiết. Đừng quên git addbất kỳ thay đổi.
  7. git commit
  8. git stash pop
  9. Lặp lại, từ số 5, khi cần thiết.
  10. git rebase --continue

47
Tôi thấy cách tiếp cận này đơn giản hơn nhiều: stackoverflow.com/a/5506483/457268
k0pernikus

561
Tôi không chắc tại sao điều này đang được nâng cấp. Mọi người phải có một kỳ vọng khác với tôi. Bài viết gốc đang hỏi "làm thế nào để tôi bỏ bớt một phần của những thay đổi không được cam kết?" Khi tôi sử dụng git stash save -k, có, chỉ mục (màu xanh lá cây git stat) được giữ nguyên, nhưng toàn bộ thay đổi (cả màu xanh lá cây và màu đỏ) đi vào ngăn chứa. Điều này vi phạm yêu cầu của OP, "chỉ thực hiện một số thay đổi". Tôi muốn bỏ bớt một số màu đỏ (để sử dụng trong tương lai).
Pistos

70
Nếu bạn quan tâm hơn đến câu trả lời cho câu hỏi được đặt ra bởi @Pistos (như tôi), thì hãy xem tại đây: stackoverflow.com/questions/5506339/
Raman

27
@Raman: Tuyệt vời! git stash -pchính xác là những gì tôi đang tìm kiếm. Tôi tự hỏi nếu chuyển đổi này chỉ được thêm gần đây.
Pistos

14
CẢNH BÁO: git stash --keep-indexbị hỏng. Nếu bạn thực hiện nhiều thay đổi hơn, sau đó cố gắng để git stash popsau đó bạn nhận được xung đột hợp nhất vì ngăn chứa bao gồm các tệp đã thay đổi mà bạn giữ, không chỉ các tệp bạn không giữ. Ví dụ: Tôi thay đổi tệp A và B, sau đó bỏ B, vì tôi muốn kiểm tra các thay đổi trong A; Tôi tìm thấy một vấn đề với A mà sau đó tôi sửa chữa; Tôi cam kết A; Bây giờ tôi không thể hủy bỏ vì một phiên bản cũ của A không có lý do chính đáng gây ra xung đột hợp nhất. Trong thực tế A và B có thể là nhiều tệp, thậm chí có thể là hình ảnh nhị phân hoặc thứ gì đó, vì vậy về cơ bản tôi phải từ bỏ và mất B.
rjmunro

3015

Bạn cũng có thể dùng git stash save -p "my commit message" . Bằng cách này, bạn có thể chọn những người hunk nên được thêm vào stash, toàn bộ tập tin cũng có thể được chọn.

Bạn sẽ được nhắc nhở với một vài hành động cho mỗi hunk:

   y - stash this hunk
   n - do not stash this hunk
   q - quit; do not stash this hunk or any of the remaining ones
   a - stash this hunk and all later hunks in the file
   d - do not stash this hunk or any of the later hunks in the file
   g - select a hunk to go to
   / - search for a hunk matching the given regex
   j - leave this hunk undecided, see next undecided hunk
   J - leave this hunk undecided, see next hunk
   k - leave this hunk undecided, see previous undecided hunk
   K - leave this hunk undecided, see previous hunk
   s - split the current hunk into smaller hunks
   e - manually edit the current hunk
   ? - print help

5
Nó không phải là. Nó đã được mượn từ Darcs, khoảng 7 năm sau khi thực tế.
Tên của

6
Tôi là một người nghiện TortoiseGit. Tuy nhiên TortoiseGit không hỗ trợ stash -p. Tôi trao giải cho câu trả lời này vì nó vẫn thân thiện với người dùng / tương tác nhất.
Antonio

27
bạn có thể muốn thêm : git stash save -p my stash message; vì thứ tự của argumenst không trực quan lắm ...
Chris Maes

15
Giữa cái này và git log -p, tôi nghĩ -plá cờ phải có nghĩa là "làm điều tuyệt vời mà tôi muốn nhưng không biết cách thể hiện."
Kyle Strand

2
Tại sao trên trái đất câu trả lời tuyệt vời này là ở vị trí thứ 12 ?? sau tất cả những câu trả lời 0, +1, +2 ??????
DenisFLASH

550

Vì git về cơ bản là quản lý tất cả nội dung và chỉ mục của kho lưu trữ (chứ không phải một hoặc một số tệp),git stash , nên không có gì đáng ngạc nhiên,với tất cả các thư mục làm việc.

Trên thực tế, kể từ Git 2.13 (quý 2 năm 2017), bạn có thể bỏ các tệp riêng lẻ, với git stash push:

git stash push [--] [<pathspec>...]

Khi pathspecđược trao cho ' git stash push', stash mới chỉ ghi lại các trạng thái đã sửa đổi cho các tệp khớp với đường dẫn Xem " Thay đổi Stash cho các tệp cụ thể " để biết thêm.

Ví dụ đơn giản:

 git stash push path/to/file

Trường hợp thử nghiệm cho tính năng này hiển thị thêm một vài tùy chọn:

test_expect_success 'stash with multiple pathspec arguments' '
    >foo &&
    >bar &&
    >extra &&
    git add foo bar extra &&

    git stash push -- foo bar &&   

    test_path_is_missing bar &&
    test_path_is_missing foo &&
    test_path_is_file extra &&

    git stash pop &&
    test_path_is_file foo &&
    test_path_is_file bar &&
    test_path_is_file extra

Câu trả lời ban đầu (bên dưới, tháng 6 năm 2010) là về cách chọn thủ công những gì bạn muốn bỏ.

Bình luận của Casebash :

Điều này ( stash --patchgiải pháp ban đầu) là tốt, nhưng thường tôi đã sửa đổi rất nhiều tệp nên sử dụng bản vá rất khó chịu

Câu trả lời của bukzor (được nâng cấp, tháng 11 năm 2011) cho thấy một giải pháp thiết thực hơn, dựa trên
git add+git stash --keep-index .
Đi xem và nâng cao câu trả lời của anh ấy, nên là câu trả lời chính thức (thay vì của tôi).

Về tùy chọn đó, chhh chỉ ra một quy trình công việc thay thế trong các bình luận:

bạn nên " git reset --soft" sau một cú ném như vậy để lấy lại giai đoạn rõ ràng của bạn:
Để trở về trạng thái ban đầu - đó là khu vực tổ chức rõ ràng và chỉ với một số sửa đổi không theo giai đoạn chọn, người ta có thể nhẹ nhàng đặt lại chỉ mục để nhận (mà không cần cam kết bất cứ điều gì như bạn - bukzor - đã làm).


(Câu trả lời gốc tháng 6 năm 2010: stash thủ công)

Tuy nhiên, git stash save --patchcó thể cho phép bạn đạt được một phần của bạn sau:

Với --patch, bạn có thể tương tác chọn những người đi săn trong khoảng khác nhau giữa CHÍNH và cây làm việc được cất.
Mục nhập stash được xây dựng sao cho trạng thái chỉ mục của nó giống với trạng thái chỉ mục của kho lưu trữ của bạn và bảng công việc của nó chỉ chứa các thay đổi bạn đã chọn tương tác. Các thay đổi đã chọn sau đó được khôi phục từ bàn làm việc của bạn.

Tuy nhiên, điều đó sẽ lưu chỉ mục đầy đủ (có thể không phải là điều bạn muốn vì nó có thể bao gồm các tệp khác đã được lập chỉ mục) và một bàn làm việc một phần (có thể trông giống như tệp bạn muốn bỏ).

git stash --patch --no-keep-index

có thể là một phù hợp tốt hơn.


Nếu --patchkhông hoạt động, một quy trình thủ công có thể:

Đối với một hoặc một số tệp, một giải pháp trung gian sẽ là:

  • sao chép chúng bên ngoài repo Git
    (Trên thực tế, eleotlecram đề xuất một giải pháp thay thế thú vị )
  • git stash
  • sao chép chúng trở lại
  • git stash # lần này, chỉ các tệp bạn muốn được lưu trữ
  • git stash pop stash@{1} # áp dụng lại tất cả các sửa đổi tệp của bạn
  • git checkout -- afile # đặt lại tệp về nội dung CHÍNH, trước khi sửa đổi cục bộ

Khi kết thúc quá trình khá rườm rà đó, bạn sẽ chỉ có một hoặc một vài tệp được lưu trữ.


3
Điều này thật tuyệt, nhưng thường thì tôi đã sửa đổi rất nhiều tệp nên việc sử dụng bản vá rất khó chịu
Casebash

6
@VonC: Đó là phong cách tốt khi chỉ có một câu trả lời cho mỗi câu trả lời. Ngoài ra, sao chép câu trả lời của người khác vào câu trả lời của bạn là cách cư xử tệ.
bukzor

3
@bukzor: Tôi xin lỗi nếu câu trả lời được chỉnh sửa của tôi có vẻ không đúng. Mục đích duy nhất của tôi là cung cấp cho câu trả lời của bạn rõ hơn. Tôi đã chỉnh sửa lại bài viết của mình, để làm cho ý định đó rõ ràng hơn.
VonC

1
@Kal: đúng, stackoverflow.com/a/13941132/6309 gợi ý một git reset(hỗn hợp)
VonC

3
git is fundamentally about managing a all repository content and index and not one or several files- đó là việc thực hiện làm lu mờ vấn đề đang được giải quyết; đó là một lời giải thích, nhưng không phải là một lời biện minh. Bất kỳ hệ thống kiểm soát nguồn IS nào về "quản lý một số tệp". Chỉ cần nhìn những gì bình luận được nâng cao nhất.
Victor Sergienko

90

Khi git stash -p(hoặc git add -pvới stash --keep-index) sẽ là quá cồng kềnh, tôi tìm thấy nó dễ dàng hơn để sử dụng diff, checkoutapply:

Để "stash" một tệp / thư mục cụ thể:

git diff path/to/dir > stashed.diff
git checkout path/to/dir

Sau đó sau đó

git apply stashed.diff

1
Thay thế thú vị cho git add -ptôi đã đề cập trong câu trả lời của riêng tôi ở trên. +1.
VonC

11
Lưu ý rằng nếu bạn có tệp nhị phân (như PNG) thì chúng sẽ không được xuất ra tệp khác. Vì vậy, đây không phải là một giải pháp 100%.
void.pulum

1
@RobertDailey: Đó là một điểm thú vị đối với tôi, git diff > file.diffgit applycũng là công cụ stash một phần thông thường của tôi. Tôi có thể phải xem xét chuyển sang git stash -pcho những thay đổi lớn hơn.
thekingoftruth

1
@thekingoftruth Dưới đây là bí danh tôi sử dụng để tạo ra các file vá, và nó không binaries hỗ trợ: patch = log --pretty=email --patch-with-stat --reverse --full-index --binary. Lưu ý, tuy nhiên, điều này đòi hỏi những thay đổi của bạn để bản vá được cam kết.
void.pulum

2
Điều này đã không làm việc sạch sẽ cho tôi nếu tập tin để stash là một cái gì đó như ../../foo/bar.txt. Bản vá tạo ra OK, nhưng sau đó tôi cần chuyển đến thư mục gốc của kho để lấy bản vá để áp dụng. Vì vậy, nếu bạn gặp rắc rối với điều này - chỉ cần đảm bảo rằng bạn đang thực hiện nó từ thư mục gốc của kho lưu trữ.
Michael Anderson

86

Sử dụng git stash push, như thế này:

git stash push [--] [<pathspec>...]

Ví dụ:

git stash push -- my/file.sh

Điều này có sẵn kể từ Git 2.13, được phát hành vào mùa xuân năm 2017.


1
Nhưng tôi git stash pushđã đề cập đến trong câu trả lời của tôi ở trên vào tháng 3 năm ngoái, 5 tháng trước. Và tôi đã nêu chi tiết lệnh Git 2.13 mới ở đây: stackoverflow.com/a/42963606/6309 .
VonC

Tôi rất vui vì Git đang tiến bộ rất nhanh, trong một thời gian dài điều này là không thể và sau đó 2.13 được phát hành và đột nhiên có một giải pháp đơn giản có sẵn!
Sandstrom

1
@VonC bạn nói đúng, bạn cũng đề cập đến câu trả lời đúng, tuy nhiên, giữa hai câu trả lời, câu này dễ đọc hơn (không có văn bản khó hiểu và cũng có một ví dụ). Có lẽ họ nên chỉnh sửa câu trả lời của bạn thay vào đó
Utopik

@Utopik Bạn đã cho tôi tại "bạn đúng" ... nhưng vâng, tôi đã chỉnh sửa câu trả lời của mình để đưa ra một ví dụ.
VonC

Có một sau đó sử dụng git stash applyđể phục hồi các thay đổi stash?
Chad

49

Giả sử bạn có 3 tệp

a.rb
b.rb
c.rb

và bạn chỉ muốn stash b.rb và c.rb chứ không phải a.rb

bạn có thể làm một cái gì đó như thế này

# commit the files temporarily you don't want to stash
git add a.rb
git commit -m "temp" 

# then stash the other files
git stash save "stash message"

# then undo the previous temp commit
git reset --soft HEAD^
git reset

Và bạn đã hoàn thành! HTH.


29

Một cách khác để làm điều này:

# Save everything
git stash 

# Re-apply everything, but keep the stash
git stash apply

git checkout <"files you don't want in your stash">

# Save only the things you wanted saved
git stash

# Re-apply the original state and drop it from your stash
git stash apply stash@{1}
git stash drop stash@{1}

git checkout <"files you put in your stash">

Tôi đã nghĩ ra điều này sau khi tôi (một lần nữa) đến trang này và không thích hai câu trả lời đầu tiên (câu trả lời đầu tiên không trả lời câu hỏi và tôi không thích làm việc với -p chế độ tương tác).

Ý tưởng giống như những gì @VonC đã đề xuất khi sử dụng các tệp bên ngoài kho lưu trữ, bạn lưu các thay đổi bạn muốn ở đâu đó, xóa các thay đổi bạn không muốn trong ngăn chứa của mình và sau đó áp dụng lại các thay đổi bạn đã thực hiện. Tuy nhiên, tôi đã sử dụng git stash như là "một nơi nào đó" (và kết quả là, có thêm một bước nữa: loại bỏ các cahng bạn đặt trong stash, bởi vì bạn cũng di chuyển chúng ra khỏi đường đi).


1
tôi thích cách tiếp cận này nhất. Nó cung cấp một quy trình làm việc dễ dàng trong tortoisegit chỉ bằng các lệnh stash và Revert.
Đánh dấu

Đề cập đến câu trả lời về SO sử dụng các vị trí là không nên. Vị trí thay đổi khi xếp hạng thay đổi.
Bryan Ash

2
@BryanAsh Chà, nó không giống như vấn đề ở đây. Tôi đang đưa ra một giai thoại hơn là thực sự đề cập đến các câu trả lời khác. Thông điệp là tôi không thích câu trả lời mà cộng đồng thích và không phải những câu trả lời này thực sự chứa gì. Bên cạnh đó, khoảng cách 900 phiếu giữa câu trả lời thứ hai và thứ ba khiến điều này khó có thể thay đổi trong tương lai gần, và nếu nó cần thay đổi, tôi luôn có thể chỉnh sửa nó để nói "từ đầu đến lúc trả lời". Thực sự, tôi không thấy đây là vấn đề như thế nào trong tình huống này.
Jasper

23

Cập nhật (14/2/2015) - Tôi đã viết lại tập lệnh một chút, để xử lý tốt hơn các trường hợp xung đột, giờ đây sẽ được trình bày dưới dạng xung đột chưa được xử lý thay vì các tệp .rej.


Tôi thường thấy trực quan hơn khi thực hiện nghịch đảo phương pháp của @ bukzor. Đó là, để tạo ra một số thay đổi, và sau đó chỉ thực hiện những thay đổi được dàn dựng đó.

Thật không may, git không cung cấp một git stash --only-index hoặc tương tự, vì vậy tôi đã tạo ra một kịch bản để làm điều này.

#!/bin/sh

# first, go to the root of the git repo
cd `git rev-parse --show-toplevel`

# create a commit with only the stuff in staging
INDEXTREE=`git write-tree`
INDEXCOMMIT=`echo "" | git commit-tree $INDEXTREE -p HEAD`

# create a child commit with the changes in the working tree
git add -A
WORKINGTREE=`git write-tree`
WORKINGCOMMIT=`echo "" | git commit-tree $WORKINGTREE -p $INDEXCOMMIT`

# get back to a clean state with no changes, staged or otherwise
git reset -q --hard

# Cherry-pick the index changes back to the index, and stash.
# This cherry-pick is guaranteed to succeed
git cherry-pick -n $INDEXCOMMIT
git stash

# Now cherry-pick the working tree changes. This cherry-pick may fail
# due to conflicts
git cherry-pick -n $WORKINGCOMMIT

CONFLICTS=`git ls-files -u`
if test -z "$CONFLICTS"; then
    # If there are no conflicts, it's safe to reset, so that
    # any previously unstaged changes remain unstaged
    #
    # However, if there are conflicts, then we don't want to reset the files
    # and lose the merge/conflict info.
    git reset -q
fi

Bạn có thể lưu tập lệnh trên như git-stash-indexmột nơi nào đó trên đường dẫn của mình và sau đó có thể gọi nó dưới dạng git stash-index

# <hack hack hack>
git add <files that you want to stash>
git stash-index

Bây giờ, stash chứa một mục mới chỉ chứa các thay đổi bạn đã dàn dựng và cây làm việc của bạn vẫn chứa bất kỳ thay đổi chưa được phân loại nào.

Trong một số trường hợp, thay đổi cây làm việc có thể phụ thuộc vào thay đổi chỉ mục, vì vậy khi bạn thay đổi chỉ số thay đổi, cây thay đổi sẽ có xung đột. Trong trường hợp này, bạn sẽ nhận được các xung đột chưa được xử lý thông thường mà bạn có thể giải quyết bằng git merge / git mergetool / vv.


Đề nghị pushdthay vì cdpopdở cuối tập lệnh để nếu tập lệnh thành công, người dùng sẽ kết thúc trong cùng thư mục như trước khi chạy tập lệnh.
Nate

1
@Nate: theo như tôi biết, nó chỉ nên thay đổi thư mục cho người dùng nếu họ có nguồn gốc tập lệnh. Nếu bạn chạy tập lệnh một cách bình thường (~ / bin / git-stash-index) hoặc thông qua git (git stash-index), nó sẽ được chạy trong một phiên cuối riêng biệt và mọi thay đổi thư mục làm việc trong phiên đó sẽ không ảnh hưởng đến thư mục làm việc trong phiên cuối của người dùng. Bạn có biết về một trường hợp sử dụng phổ biến khi điều này không đúng? (ngoài việc tìm nguồn cung cấp kịch bản mà tôi không coi là "phổ biến")
JesusFreke

20

Nếu bạn không muốn chỉ định một thông báo với các thay đổi được lưu của mình, hãy chuyển tên tệp sau dấu gạch ngang kép.

$ git stash -- filename.ext

Nếu đó là một tệp chưa được đóng gói / mới, bạn sẽ phải xử lý nó trước.

Phương pháp này hoạt động trong phiên bản git 2.13+


Câu trả lời đó dài dòng, đây là súc tích. Nếu nó giúp được ai đó, tôi sẽ rời bỏ nó. Không ai trên trang này đề cập đến cú pháp và kết quả này - thay vào đó họ đề cập đến 'git stash push`.
niêm phong

Đây là câu trả lời tôi đang tìm kiếm. Cảm ơn! +1
nicodp

19

Vì việc tạo các nhánh trong Git là không đáng kể, bạn chỉ có thể tạo một nhánh tạm thời và kiểm tra các tệp riêng lẻ vào nó.


2
Bạn không thể tạo một nhánh với các chỉnh sửa chưa được chỉnh sửa. Bạn có thể dễ dàng di chuyển tất cả các chỉnh sửa sang một nhánh mới (stash / stash pop) nhưng sau đó bạn quay lại quảng trường: làm thế nào để bạn kiểm tra chi nhánh của mình chỉ với một số chỉnh sửa đó mà không mất các chỉnh sửa khác?
bukzor

7
Bạn không thể chuyển chi nhánh nếu bạn có thay đổi cục bộ. Tuy nhiên, bạn có thể tạo một nhánh mới và thêm / cam kết các tệp một cách chọn lọc, sau đó tạo một nhánh khác và thực hiện đệ quy tương tự ... sau đó kiểm tra nhánh ban đầu và chọn lọc hợp nhất trở lại. Tôi vừa thực hiện. Nó thực sự có vẻ là cách tự nhiên để làm mọi thứ, vì về cơ bản bạn đang tạo các nhánh tính năng.
Iain

3
@iain bạn có thể chuyển đổi chi nhánh nếu bạn có thay đổi cục bộ, miễn là chúng không yêu cầu hợp nhất. Xem ví dụ Gist . Điều này đúng với Git v2.7.0 ít nhất.
Colin D Bennett

18

Bạn chỉ có thể làm điều này:

git stash push "filename"

hoặc với một tin nhắn tùy chọn

git stash push -m "Some message" "filename"

1
Điều này không có gì mới. Git stash đẩy đã được đề cập trong nhiều câu trả lời
JesusFreke

12

Lưu mã sau vào một tệp, ví dụ, được đặt tên stash. Cách sử dụng là stash <filename_regex>. Đối số là biểu thức chính quy cho đường dẫn đầy đủ của tệp. Ví dụ: để bỏ a / b / c.txt, stash a/b/c.txthoặc stash .*/c.txt, v.v.

$ chmod +x stash
$ stash .*.xml
$ stash xyz.xml

Mã để sao chép vào tập tin:

#! /usr/bin/expect --
log_user 0
set filename_regexp [lindex $argv 0]

spawn git stash -p

for {} 1 {} {
  expect {
    -re "diff --git a/($filename_regexp) " {
      set filename $expect_out(1,string)
    }
    "diff --git a/" {
      set filename ""
    }
    "Stash this hunk " {
      if {$filename == ""} {
        send "n\n"
      } else {
        send "a\n"
        send_user "$filename\n"
      }
    }
    "Stash deletion " {
      send "n\n"
    }
    eof {
      exit
    }
  }
}

2
Phương pháp tuyệt vời. Tôi đã chọn đây là câu trả lời. Mẹo cho độc giả tương lai: bạn phải phù hợp trên đường dẫn đầy đủ. ví dụ: stash
subir

12

Chỉ trong trường hợp bạn thực sự muốn loại bỏ thay đổi bất cứ khi nào bạn sử dụng git stash(và không thực sự sử dụng git stash để tạm thời xóa nó), trong trường hợp đó bạn có thể sử dụng

git checkout -- <file>

[ LƯU Ý ]

Đó git stashchỉ là một sự thay thế nhanh chóng và đơn giản để phân nhánh và làm công cụ.


8

Vấn đề với giải pháp sao chép tệp 'trung gian' của VonC ra bên ngoài repo Git là bạn mất thông tin đường dẫn, điều này khiến việc sao chép một loạt các tệp trở lại sau đó có phần rắc rối.

Tìm thấy dễ dàng hơn để sử dụng tar (công cụ tương tự có thể sẽ làm) thay vì sao chép:

  • tar cvf /tmp/stash.tar đường dẫn / đến / some / đường dẫn tệp / đến / some / other / file (... vv)
  • đường dẫn kiểm tra git / đến / some / đường dẫn tệp / đến / some / other / file
  • git stash
  • tar xvf /tmp/stash.tar
  • v.v. (xem gợi ý 'trung gian' của VonC)

checkout -fkhông cần thiết, checkout(không có -f) là đủ, tôi đã cập nhật câu trả lời.
eleotlecram

8

Đôi khi tôi đã thực hiện một thay đổi không liên quan đến chi nhánh của mình trước khi tôi cam kết và tôi muốn chuyển nó sang chi nhánh khác và cam kết riêng rẽ (như chủ). Tôi làm việc này:

git stash
git checkout master
git stash pop
git add <files that you want to commit>
git commit -m 'Minor feature'
git stash
git checkout topic1
git stash pop
...<resume work>...

Lưu ý đầu tiên stash& stash popcó thể được loại bỏ, bạn có thể thực hiện tất cả các thay đổi của mình đối vớimaster chi nhánh khi bạn thanh toán, nhưng chỉ khi không có xung đột. Ngoài ra nếu bạn đang tạo một nhánh mới cho các thay đổi một phần, bạn sẽ cần stash.

Bạn có thể đơn giản hóa nó với giả định không có xung đột và không có chi nhánh mới:

git checkout master
git add <files that you want to commit>
git commit -m 'Minor feature'
git checkout topic1
...<resume work>...

Stash thậm chí không cần thiết ...


8

Điều này có thể được thực hiện dễ dàng trong 3 bước bằng SourceTree.

  1. Tạm thời cam kết mọi thứ bạn không muốn cất giấu.
  2. Git thêm mọi thứ khác, sau đó stash nó.
  3. Bật cam kết tạm thời của bạn bằng cách chạy thiết lập lại git, nhắm mục tiêu cam kết trước khi tạm thời.

Tất cả điều này có thể được thực hiện trong vài giây trong SourceTree, nơi bạn chỉ cần nhấp vào các tệp (hoặc thậm chí từng dòng riêng lẻ) mà bạn muốn thêm. Sau khi thêm, chỉ cần cam kết chúng với một cam kết tạm thời. Tiếp theo, nhấp vào hộp kiểm để thêm tất cả các thay đổi, sau đó nhấp vào stash để bỏ tất cả mọi thứ. Với các thay đổi được sắp xếp sẵn, hãy lướt qua danh sách cam kết của bạn và lưu ý hàm băm cho cam kết trước khi cam kết tạm thời của bạn, sau đó chạy 'git reset hash_b4_temp_commit', về cơ bản giống như "bật" cam kết bằng cách đặt lại chi nhánh của bạn vào cam kết ngay trước khi nó. Bây giờ, bạn chỉ còn lại những thứ bạn không muốn cất.


8

Tôi sẽ sử dụng git stash save --patch. Tôi không thấy tính tương tác gây khó chịu vì có các tùy chọn trong đó để áp dụng thao tác mong muốn cho toàn bộ tệp.


3
Thật ngạc nhiên khi có rất ít sự ủng hộ cho câu trả lời này, đó là giải pháp tốt nhất mà không cần một bài luận.
robstarbuck

Chắc chắn là câu trả lời tốt, git stash -pcho phép bạn nhanh chóng lấy toàn bộ tệp và thoát ra sau đó.
Richard Dally

7

Mọi câu trả lời ở đây rất phức tạp ...

Điều gì về điều này để "stash":

git diff /dir/to/file/file_to_stash > /tmp/stash.patch
git checkout -- /dir/to/file/file_to_stash

Điều này để bật lại tập tin thay đổi:

git apply /tmp/stash.patch

Chính xác hành vi tương tự như nhét một tập tin và đưa nó trở lại.


Tôi đã thử nó nhưng không có gì xảy ra. Khi tôi git applykhông có lỗi nhưng những thay đổi cũng không được đưa trở lại
ClementWalter

Tệp bản vá bạn tạo trong / tmp có thể đã bị xóa. Bạn có thể đã khởi động lại giữa diff và áp dụng. Hãy thử một vị trí lâu dài hơn. Nó không hoạt động. Cũng kiểm tra nội dung của tập tin vá.
Barshe Fondacci

4

Tôi đã xem xét câu trả lời và nhận xét cho điều này và một số chủ đề tương tự. Xin lưu ý rằng không có lệnh nào sau đây là chính xác cho mục đích có thể lưu trữ bất kỳ tệp được theo dõi / không bị theo dõi cụ thể nào :

  • git stash -p (--patch): chọn hunk theo cách thủ công, ngoại trừ các tệp không bị theo dõi
  • git stash -k (--keep-index): stash tất cả các tệp được theo dõi / không bị theo dõi và giữ chúng trong thư mục làm việc
  • git stash -u (--include-untracked): stash tất cả các tệp được theo dõi / không bị theo dõi
  • git stash -p (--patch) -u (--include-untracked): lệnh không khả thi

Hiện tại, phương pháp hợp lý nhất để có thể lưu trữ bất kỳ tệp được theo dõi / không bị theo dõi cụ thể nào là:

  • Tạm thời cam kết các tệp bạn không muốn lưu trữ
  • Thêm và stash
  • Pop cam kết tạm thời

Tôi đã viết một tập lệnh đơn giản cho thủ tục này để trả lời cho một câu hỏi khác và có các bước để thực hiện quy trình trong SourceTree tại đây .


4

Giải pháp

Thay đổi cục bộ:

  • file_A (đã sửa đổi) không được dàn dựng
  • file_B (đã sửa đổi) không được dàn dựng
  • file_C (đã sửa đổi) không được dàn dựng

Để tạo một ngăn chứa "my_stash" chỉ với các thay đổi trên tệp_C :

1. git add file_C
2. git stash save --keep-index temp_stash
3. git stash save my_stash
4. git stash pop stash@#{1}

Làm xong.


Giải trình

  1. thêm file_C vào khu vực tổ chức
  2. tạo một ngăn tạm thời có tên là "temp_stash" và giữ các thay đổi trên file_C
  3. tạo stash mong muốn ("my_stash") chỉ với những thay đổi trên file_C
  4. áp dụng các thay đổi trong "temp_stash" (file_A và file_B) trên mã cục bộ của bạn và xóa stash

Bạn có thể sử dụng trạng thái git giữa các bước để xem điều gì đang xảy ra.


3

Khi bạn cố gắng chuyển đổi giữa hai nhánh, tình huống này xảy ra.

Cố gắng thêm các tệp bằng cách sử dụng "git add filepath ".

Sau đó thực hiện dòng này

git stash --keep-index


3

Để sử dụng một tệp duy nhất git stash --patch [file] .

Điều này sẽ nhắc : Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?. Chỉ cần gõ a(stash hunk này và tất cả các hunk sau này trong tệp) và bạn sẽ ổn.


Mất tích pushnhư tronggit stash push --patch [file]
Filipe Esperandio

@FilipeEsperandio pushchỉ hoạt động trong các phiên bản Git gần đây hơn , đã từng save. Trong cả hai trường hợp pushhoặc saveđược ngụ ý bằng cách gọi stash: "Gọi git stash mà không có bất kỳ đối số nào tương đương với git stash đẩy", docs
patrick

2

Tình hình tương tự. Đã cam kết và nhận ra nó không ổn.

git commit -a -m "message"
git log -p

Dựa trên các câu trả lời này đã giúp tôi.

# revert to previous state, keeping the files changed
git reset HEAD~
#make sure it's ok
git diff
git status
#revert the file we don't want to be within the commit
git checkout specs/nagios/nagios.spec
#make sure it's ok
git status
git diff
#now go ahead with commit
git commit -a -m "same|new message"
#eventually push tu remote
git push

2

Trong tình huống này, tôi git add -p(tương tác), git commit -m blahvà sau đó bỏ đi những gì còn lại nếu cần thiết.


2

Tôi không biết cách thực hiện trên dòng lệnh, chỉ sử dụng SourceTree. Hãy nói rằng bạn đã thay đổi tệp A và có hai khối thay đổi trong tệp B. Nếu bạn chỉ muốn xóa tệp hunk thứ hai trong tệp B và để mọi thứ khác không bị ảnh hưởng, hãy làm điều này:

  1. Giai đoạn mọi thứ
  2. Thực hiện các thay đổi đối với bản sao làm việc của bạn để hoàn tác tất cả các thay đổi trong tệp A. (ví dụ: khởi chạy công cụ tìm khác biệt bên ngoài và làm cho các tệp khớp với nhau.)
  3. Làm cho tệp B trông như thể chỉ thay đổi thứ hai được áp dụng cho nó. (ví dụ: khởi chạy công cụ tìm khác biệt bên ngoài và hoàn tác thay đổi đầu tiên.)
  4. Tạo một ngăn chứa bằng cách sử dụng "Giữ các thay đổi theo giai đoạn".
  5. Bỏ qua mọi thứ
  6. Làm xong!

2
git add .                           //stage all the files
git reset <pathToFileWillBeStashed> //unstage file which will be stashed
git stash                           //stash the file(s)
git reset .                         // unstage all staged files
git stash pop                       // unstash file(s)

1
Vâng, bạn không nên làm điều đó. Câu trả lời sẽ cung cấp một giải pháp cho câu hỏi. Bạn chỉ có thể đặt câu hỏi của riêng bạn.
L_J

giải pháp này là một trong những câu trả lời dễ nhất cho câu hỏi NÀY. đọc câu hỏi, so sánh tất cả các câu trả lời và của tôi sau đó nếu bạn có nghi ngờ rằng câu trả lời này không phải là giải pháp áp dụng cũng như không đủ thông tin về câu hỏi, thì chúng ta có thể nói lại.
celikz

Điều này sẽ không hoạt động, bởi vì lệnh thứ ba, "git stash" sẽ không tôn trọng các tập tin được dàn dựng. Cả hai, các tập tin được dàn dựng và không dàn dựng sẽ đi đến stash. Các câu hỏi đặc biệt hỏi làm thế nào để chỉ chứa một tệp
CyberProdigy

0

Một cách phức tạp sẽ là đầu tiên cam kết mọi thứ:

git add -u
git commit // creates commit with sha-1 A

Đặt lại về cam kết ban đầu nhưng kiểm tra the_one_file từ cam kết mới:

git reset --hard HEAD^
git checkout A path/to/the_one_file

Bây giờ bạn có thể stash the_one_file:

git stash

Dọn dẹp bằng cách lưu nội dung đã cam kết trong hệ thống tệp của bạn trong khi đặt lại về cam kết ban đầu:

git reset --hard A
git reset --soft HEAD^

Vâng, hơi khó xử ...


0

Tôi không tìm thấy câu trả lời nào là điều tôi cần và điều đó dễ như:

git add -A
git reset HEAD fileThatYouWantToStash
git commit -m "committing all but one file"
git stash

Điều này stash chính xác một tập tin.


0

Câu trả lời nhanh


Để hoàn nguyên một tệp đã thay đổi cụ thể trong git, bạn có thể thực hiện dòng sau:

git checkout <branch-name> -- <file-path>

Đây là một ví dụ thực tế:

git checkout master -- battery_monitoring/msg_passing.py


0

Nếu bạn muốn lưu trữ một số tệp đã thay đổi, chỉ cần

Thêm các tệp bạn không muốn bỏ vào, trong Giai đoạn , sau đó thực thigit stash save --keep-index

Nó sẽ giấu tất cả unstaged tập tin thay đổi

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.