Cách chọn cherry chỉ thay đổi cho một tệp, không phải toàn bộ cam kết


108

Tôi cần áp dụng các thay đổi được giới thiệu trong một nhánh này cho một nhánh khác. Tôi có thể sử dụng quả anh đào để làm điều đó. Tuy nhiên, trong trường hợp của tôi, tôi muốn áp dụng các thay đổi chỉ liên quan đến một tệp, tôi không cần phải chọn toàn bộ cam kết. Làm thế nào để làm điều đó?


Câu trả lời:


137

Bạn có các tùy chọn khác nhau dựa trên những gì bạn muốn đạt được:

Nếu bạn muốn nội dung của tệp giống như trên nhánh đích, bạn có thể sử dụng git checkout <branch> -- <filename>. Tuy nhiên, điều này sẽ không "chọn anh đào" những thay đổi đã xảy ra trong một cam kết duy nhất, mà chỉ lấy trạng thái kết quả của tệp đã nói. Vì vậy, nếu bạn đã thêm một dòng trong một cam kết, nhưng các cam kết trước đó đã thay đổi nhiều hơn và bạn chỉ muốn thêm dòng đó mà không có những thay đổi khác, thì thanh toán không phải là điều bạn muốn.

Mặt khác, nếu bạn muốn áp dụng bản vá được giới thiệu trong cam kết chỉ cho một tệp duy nhất, bạn có nhiều tùy chọn. Bạn có thể chạy git cherry-pick -n, tức là không cần cam kết, chỉnh sửa cam kết (ví dụ: đặt lại tất cả các tệp bằng cách sử dụng git reset -- .và chỉ thêm tệp bạn thực sự muốn thay đổi bằng cách sử dụng git add <filename>). Hoặc bạn có thể tạo khác biệt cho tệp và áp dụng khác biệt sau đó:

git diff <branch>^..<branch> -- <filename> | git apply

22

Tạo một patch filevà áp dụng nó.

git diff branchname -- filename > patchfile
git apply patchfile

BIÊN TẬP:

Vì bạn cần thực hiện các thay đổi từ một cam kết, hãy tạo bản vá như sau:

git show sha1 -- filename > patchfile

1
git diff sha1(hoặc git diff branch- nó giống nhau nếu nhánh trỏ đến cùng một hàm băm) sẽ chỉ tạo ra sự khác biệt của thư mục làm việc hiện tại liên quan đến hàm băm đó, nhưng không thay đổi điều gì làm thay đổi cam kết được giới thiệu.
poke

Chính xác. Đã chỉnh sửa câu trả lời. Cảm ơn.
Sailesh

1
-1 git checkoutvới tên tệp là búa phù hợp cho móng này. Cả hai tùy chọn này đều không cần thiết phải phức tạp.
Rein Henrichs

7
Đối với trường hợp cụ thể này, có. Nhưng nói chung, nếu bạn muốn chọn các thay đổi từ một cam kết được thực hiện cho một tệp cụ thể, thì checkoutsẽ không hoạt động, vì nó có thể liên quan đến các thay đổi không mong muốn khác trước đó và có thể không chứa các thay đổi được thực hiện trong nhánh hiện tại.
Sailesh

11

Một điều hữu ích khác cần làm là tải bản vá cục bộ và sau đó sử dụng:

git checkout {<name_of_branch>, commit's SHA} <path to the file> 

Đó không phải là hái anh đào.


2
Cảnh báo: như @poke đã nói trong câu trả lời của anh ấy, điều này không sao chép các thay đổi; nó sao chép toàn bộ trạng thái của tệp. Vì vậy, nếu bạn muốn thêm các thay đổi của cam kết vào tệp, thì bằng cách kiểm tra như thế này, bạn sẽ ghi đè bất kỳ thay đổi mới hơn nào không tốt.
Alexander Bird,

7

Git đã sẵn sàng mọi thứ :)

Chỉ dùng git checkout <sha> <path-to-file>


4
Đó không phải là một lựa chọn anh đào - mà kiểm tra toàn bộ tệp. Mục tiêu là thực hiện một thay đổi cụ thể từ một cam kết. Thường thì đó là những điều giống nhau, nhưng đôi khi không phải vậy.
AndrewF

6
git checkout the_branch_with_the_change the/path/to/the/file/you/want.extension

điều này hoạt động nếu bạn muốn một tệp từ một nhánh khác được sao chép vào nhánh làm việc hiện tại


1
Hãy cẩn thận, các thay đổi được thực hiện trong tệp không có trong phiên bản từ nhánh khác sẽ bị mất.
Patrick Schlüter

Đồng ý với điều đó. điều này hữu ích nếu bạn chỉ cần một bản sao của tệp và bạn muốn thay đổi nó trên nhánh hiện tại
Ismail Iqbal

1
Người ta có thể sử dụng các globs (đường dẫn / *) và chỉ định nhiều hơn một đường dẫn / tệp
Todd

1

Đây là những gì bạn đang tìm kiếm:

git checkout target-branch sha1 path/to/file

sha1 là tùy chọn


11
không, "chọn các thay đổi trong cam kết" không phải là "chọn toàn bộ tệp"
Abyx

1

Những gì tôi có xu hướng làm là sử dụng git ls-tree

cứ làm đi:

git ls-tree -r <commit-id> |grep 'your filename'
# there will be output that shows a SHA1 of your file
git show ${SHA1 of your file} > 'your filename'

Thao tác này sẽ in tất cả các tên tệp phù hợp với grep của bạn và cung cấp khóa SHA1 của các tệp trong cam kết.

Git show cũng có thể được sử dụng trên các tệp bên ngoài chi nhánh của bạn. sử dụng >từ shell của bạn để chuyển kết quả đầu ra thành một tệp sẽ mang lại cho bạn kết quả mà bạn đang tìm kiếm.


0

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

git show COMMIT_ID -- path/to/specific-file | git apply

Ví dụ:

git show 3feaf20 -- app/views/home/index.html | git apply

-9
git reset HEAD~1

chuyển các tệp sang giai đoạn tiền cam kết

git stash

xóa khỏi bộ nhớ

Bây giờ chi nhánh của bạn khá sạch sẽ (hoàn nguyên về cam kết trướ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.