Câu hỏi Chỉ lưu một tệp ra khỏi nhiều tệp đã thay đổi với Git?


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


2446
2018-06-14 20:52


gốc


Tôi không nghĩ rằng câu trả lời được chấp nhận của @ bukzor là một câu trả lời đúng cho câu hỏi khi nó được hỏi. git stash --keep-index giữ chỉ mục, nhưng nó dừng lại mọi điều - cả trong chỉ mục và ra ngoài. - Raman
@Antonio Có vẻ như với tôi như 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 có bất cứ điều gì để làm với TortoiseGit cụ thể. - JesusFreke
@ JesusFreke Yep, cho kết quả tôi có thể đã tha 50 đại diện :) Nó 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 "một phần stash tortoisegit". Tortoisegit dường như không phải là một chủ đề phổ biến ở đây stackoverflow.com/questions/tagged/tortoisegit - Antonio
>>>>>>>>> git diff -- *filename* > ~/patch sau đó git checkout -- *filename* và sau đó bạn có thể áp dụng lại bản vá git apply ~/patch - neaumusic
Hầu hết các câu trả lời hiện có bên dưới đều lỗi thời. Kể từ Git 2.13 (Q2 2017) nó được hỗ trợ với git stash push [--] [<pathspec>...]. - Ohad Schneider


Các câu trả lời:


Cảnh báo

Như đã lưu ý trong các ý kiến, điều này đặt tất cả mọi thứ vào stash, cả dàn dựng và unstaged. --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 sau đó bật stash.


Điều này sẽ stash tất cả mọi thứ mà bạn chưa từng được thêm vào. Chỉ git add những thứ bạn muốn giữ, sau đó chạy nó.

git stash --keep-index

Ví dụ, nếu bạn muốn chia một commit cũ thành nhiều hơn một changeset, bạn có thể sử dụng thủ tục 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 add bất kỳ thay đổi nào.
  7. git commit
  8. git stash pop
  9. Lặp lại, từ # 5, nếu cần.
  10. git rebase --continue

1218
2017-11-30 21:28



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
Tôi không chắc chắn tại sao điều này đang được upvoted. Mọi người đều phải có một kỳ vọng khác với tôi. Bài đăng gốc hỏi "làm thế nào để tôi chỉ là 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ỉ số (màu xanh lá cây trong git stat) được bảo tồn, nhưng toàn thể changeset (cả hai màu xanh lá cây và màu đỏ) đi vào stash. Điều này vi phạm yêu cầu của OP, "stash chỉ một số thay đổi". Tôi muốn để stash chỉ là một số màu đỏ (để sử dụng trong tương lai). - Pistos
Nếu bạn quan tâm nhiều hơn đến câu trả lời cho câu hỏi đặt ra bởi @Pistos (như tôi đã), thì hãy xem tại đây: stackoverflow.com/questions/5506339/… - Raman
@Raman: Tuyệt vời! git stash -p chí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ỉ mới được thêm vào gần đây. - Pistos
CẢNH BÁO: git stash --keep-index bị phá vỡ. Nếu bạn thực hiện nhiều thay đổi hơn, hãy thử git stash pop sau đó bạn nhận được xung đột hợp nhất vì stash bao gồm các tệp đã thay đổi mà bạn giữ lại, không chỉ những tệp bạn không lưu giữ. Ví dụ: tôi thay đổi tập tin A và B, sau đó stash B, bởi vì tôi muốn kiểm tra những 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ể unstash vì một phiên bản cũ của A là trong stash không có lý do chính đáng gây ra một cuộc xung đột hợp nhất. Trong thực tế A và B có thể là nhiều tập tin, có lẽ ngay cả hình ảnh nhị phân hoặc một cái gì đó, vì vậy tôi về cơ bản phải từ bỏ và mất B. - rjmunro


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 khối nào sẽ được thêm vào stash, toàn bộ các tệp 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

2619
2017-07-31 11:59



Điều này nên ở trên cùng, vì nó trực tiếp trả lời câu hỏi với cách tiếp cận đơn giản nhất. Tôi ước tôi đã thấy các tùy chọn "a" / "d" (và đọc đầy đủ câu trả lời này trước khi thử), vì tôi đã có toàn bộ một tệp để thêm vào stash và một tệp khác để loại trừ hoàn toàn. Tuy nhiên nó làm việc tốt cho tôi; Tôi không có quá nhiều người. (Có lẽ nó không được đề xuất bởi bất cứ ai trong năm 2010 khi câu hỏi ban đầu đã được đăng bởi vì tính năng này không phải là git tại thời điểm đó?) - Liam
Nó không phải là. Nó được mượn từ Darcs, khoảng 7 năm sau khi thực tế. - nomen
Tôi là một người nghiện TortoiseGit. Tuy nhiên TortoiseGit không hỗ trợ stash -p. Tôi giải thưởng câu trả lời này bởi vì nó vẫn là người dùng tương tác / thân thiện nhất. - Antonio
bạn có thể muốn thêm: git stash save -p my stash message; vì thứ tự của argumenst không phải là rất trực quan ... - Chris Maes
Giữa cái này và git log -p, Tôi nghĩ rằng -p 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 diễn đạt." - Kyle Strand


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

Trên thực tế, kể từ Git 2.13 (Q2 2017), bạn có thể stash các tệp riêng lẻ, với:

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

Xem "Stash thay đổi đối với các tệp cụ thể"để biết thêm.


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

Casebash bình luận:

Điều này ( stash --patch giải pháp ban đầu) là tốt đẹp, nhưng thường tôi đã sửa đổi rất nhiều tập tin để sử dụng vá là gây phiền nhiễu

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

Về tùy chọn đó, chhh chỉ ra một quy trình làm việc thay thế trong các nhận xét:

bạn nên "git reset --soft"sau khi một stash để có được dàn dựng rõ ràng của bạn trở lại:
  Để có được trạng thái ban đầu - đó là một khu vực dàn dựng rõ ràng và chỉ với một số sửa đổi chưa được dàn dựng, bạn có thể thiết lập lại chỉ mục một cách nhẹ nhàng (không cam kết bất cứ thứ gì như bạn - bukzor - đã làm).


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

Chưa, git stash save --patch có thể cho phép bạn đạt được phần stashing bạn đang có sau:

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

Tuy nhiên điều đó sẽ lưu chỉ mục đầy đủ (có thể không phải là những gì 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 worktree một phần (có thể trông giống như bạn muốn lưu trữ).

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

có thể phù hợp hơn.


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

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

  • sao chép chúng bên ngoài repo Git
    (Thực ra, eleotlecram đề xuất một thay thế thú vị)
  • git stash
  • sao chép chúng trở lại
  • git stash # lần này, chỉ những 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 cho nội dung HEAD, trước bất kỳ sửa đổi cục bộ nào

Vào cuối quá trình khá cồng kềnh, bạn sẽ chỉ có một hoặc nhiều tệp bị lưu trữ.


238
2018-06-14 21:23



Điều này là tốt đẹp, nhưng thường tôi đã sửa đổi rất nhiều tập tin để sử dụng vá là gây phiền nhiễu - Casebash
@ VonC: Đó là phong cách tốt để chỉ có một câu trả lời cho mỗi câu trả lời. Ngoài ra, sao chép các câu trả lời của người khác vào của riêng bạn là cách cư xử xấu. - bukzor
@bukzor: Tôi xin lỗi nếu câu trả lời đã chỉnh sửa của tôi có vẻ không đúng. Ý định duy nhất của tôi là đưa ra câu trả lời rõ ràng hơn. Tôi đã chỉnh sửa lại bài đăng của mình, để làm cho ý định đó rõ ràng hơn. - VonC
@Kal: đúng, stackoverflow.com/a/13941132/6309 gợi ý một git reset (hỗn hợp) - VonC
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 sự biện minh. Bất kỳ hệ thống kiểm soát nguồn nào về "quản lý một số tệp". Chỉ cần nhìn những gì bình luận nhận được upvoted nhất. - Victor Sergienko


Khi nào git stash -p (hoặc là git add -p với stash --keep-index) sẽ quá cồng kềnh, tôi thấy dễ sử dụng hơn diff, checkout và apply:

Để "chặn" một tệp / thư mục cụ thể chỉ:

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

Sau đó sau đó

git apply stashed.diff

76
2018-02-12 13:44



Thay thế thú vị cho git add -p Tôi đã đề cập trong câu trả lời của riêng tôi ở trên. +1. - VonC
Lưu ý rằng nếu bạn có các tệp nhị phân (như PNG), chúng sẽ không được xuất ra tệp khác. Đây không phải là giải pháp 100%. - void.pointer
@RobertDailey: Đó là một điểm thú vị đối với tôi, git diff > file.diff và git apply 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 -p cho những thay đổi lớn hơn. - thekingoftruth
@thekingoftruth Đây là bí danh tôi sử dụng để tạo tệp vá và làm hỗ trợ nhị phân: patch = log --pretty=email --patch-with-stat --reverse --full-index --binary. Lưu ý, tuy nhiên, điều này đòi hỏi thay đổi của bạn cho các bản vá được cam kết. - void.pointer
Đ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. Các miếng vá tạo ra OK, nhưng sau đó tôi cần phải di chuyển đến kho gốc để có được các bản vá để áp dụng. Vì vậy, nếu bạn đang gặp rắc rối với điều này - chỉ cần chắc chắn rằng bạn đang làm nó từ thư mục gốc của kho lưu trữ. - Michael Anderson


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 tất! HTH.


43
2017-10-31 07:10





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 từ Git 2.13, phát hành vào mùa xuân năm 2017.


34
2017-08-15 13:10



Nhưng tôi đề cập đến git stash push đã ở câu trả lời của tôi ở trên tháng 3 năm ngoái, 5 tháng trước. Và tôi đã trình bày chi tiết lệnh Git 2.13 mới ở đây: stackoverflow.com/a/42963606/6309. - VonC
Tôi vui vì Git đang tiến 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


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 đã đưa 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 này giống như những gì @VonC đề xuất sử dụng 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 stash của mình và sau đó áp dụng lại các thay đổi bạn đã di chuyể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 ở cuối: loại bỏ các cahnges bạn đặt trong stash, bởi vì bạn di chuyển chúng ra khỏi con đường là tốt).


25
2018-02-05 10:16



tôi thích phương pháp này nhất. Nó cung cấp một quy trình làm việc dễ dàng trong tortoisegit chỉ sử dụng các lệnh stash và revert. - Mark Ch
Đề cập đến câu trả lời về vị trí sử dụng SO là không nên. Vị trí thay đổi khi xếp hạng thay đổi. - Bryan Ash
@BryanAsh Vâng, nó không giống như nó quan trọng ở đây. Tôi đang đưa ra một giai thoại thay vì 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 thực sự chứa đựng. Bên cạnh đó, khoảng cách bỏ phiếu 900 giữa câu trả lời thứ hai và thứ ba khiến điều này không có khả năng thay đổi trong tương lai gần, và nếu nó thay đổi, tôi luôn có thể chỉnh sửa nó để nói "câu trả lời hàng đầu vào thời điểm đó". Thực sự, tôi không thấy đây là vấn đề gì trong tình huống này. - Jasper


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


Tôi thường thấy nó trực quan hơn để làm ngược lại cách tiếp cận của @ bukzor. Tức là, để giai đoạn một số thay đổi, và sau đó stash chỉ những thay đổi dàn dựng.

Thật không may, git không cung cấp một stit git stash --only-index hoặc tương tự, vì vậy tôi whipped lên 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 dưới dạng git-stash-index một nơi nào đó trên con đường của bạn, và sau đó có thể gọi nó là chỉ số stit-git

# <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 đã tổ chức và cây làm việc của bạn vẫn chứa bất kỳ thay đổi không được tổ chức nào.

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


22
2018-06-16 21:00



Giới thiệu pushd thay vì cd và popd ở cuối kịch bản để nếu kịch bản thành công, người dùng sẽ kết thúc trong cùng một thư mục như trước khi chạy nó. - Nate
@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 kịch bản. Nếu bạn chạy kịch bản thông thường (~ / bin / git-stash-index), hoặc thông qua git (git stash-index), nó được chạy trong một phiên đầu cuối riêng biệt và bất kỳ thay đổi thư mục làm việc nào trong phiên đó không ảnh hưởng đến thư mục làm việc trong phiên thiết bị đầu cuối của người dùng. Bạn có biết trường hợp sử dụng phổ biến khi điều này không đúng không? (ngoài việc tìm nguồn cung ứng kịch bản, mà tôi sẽ không xem xét "phổ biến") - JesusFreke