Làm thế nào để áp dụng một bản vá git từ kho này sang kho khác?


80

Tôi có hai kho, một là kho chính cho một thư viện, và kho còn lại là một dự án sử dụng thư viện đó.

Nếu tôi thực hiện một bản sửa lỗi cho dự án trong subervient, tôi muốn một cách dễ dàng để áp dụng bản vá đó ngược dòng.

Vị trí của tệp khác nhau trong mỗi kho lưu trữ.

  • Repo chính: www.playdar.org/static/playdar.js
  • Dự án: playlick.com/lib/playdar.js

Tôi đã thử sử dụng git format-patch -- lib/playdar.jstrên dự án playlick và sau đó git amtrên repo playdar chính, nhưng các vị trí tệp khác nhau trong tệp vá đã gây ra lỗi.

Có cách nào dễ dàng để áp dụng bản vá từ một cam kết nhất định trên một tệp nhất định sang một tệp tùy ý khác ở nơi khác không?

Đối với điểm thưởng, điều gì sẽ xảy ra nếu tệp bạn muốn áp dụng bản vá không có trong kho lưu trữ git?


Câu trả lời:


116

Nếu việc tự chỉnh sửa các tập tin vá lỗi là ra câu hỏi hoặc không khả thi, điều này có thể được thực hiện với các tùy chọn tiêu chuẩn (trong có sẵn git apply, git format-patchvà GNU patch).

  1. -p<n>loại bỏ ncác thư mục hàng đầu khỏi các đường dẫn trong bản vá.

  2. Sau khi chế biến -p, --directory=<root>prepends rootcho mỗi đường dẫn trong bản vá trước khi áp dụng.

Thí dụ

Vì vậy, ví dụ của bạn, để lấy một bản vá ban đầu static/playdar.jsvà áp dụng nó lib/playdar.js, bạn sẽ chạy:

$ cat patch_file | git am     \ 
          -p1                 \ # remove 1 leading directory ('static/')
         --directory='lib/'     # prepend 'lib/'

1
Bất kỳ cơ hội để làm cho câu trả lời hàng đầu này? Điều này dễ dàng hơn nhiều so với việc chỉnh sửa thủ công một tệp vá.
weston

Chắc chắn, đây là một câu trả lời tốt hơn / dễ dàng hơn, mặc dù câu trả lời của @ araqnid vẫn tốt để biết.
James Wheare

Có liên quan đến việc điều chỉnh thư mục sau lần thử đầu tiên mà không có --directory: stackoverflow.com/questions/24121709/…
Ioannis Filippidis,

38

Bản vá được tạo ra git format-patchchỉ đơn giản là một tệp văn bản - bạn có thể chỉnh sửa các tiêu đề khác nhau để nó sửa đổi một đường dẫn khác.

Vì vậy, ví dụ, nó sẽ tạo ra một cái gì đó như thế này:

diff --git a/lib/playdar.js b/lib/playdar.js
index 1234567..89abcde
-- a/lib/playdar.js
++ b/lib/playdar.js

Tất cả những gì bạn phải làm là thay đổi lib/playdar.jsthành static/playdar.jsvà sau đó chạy bản vágit am"

Bản vá phải có thể đọc được bằng tiện ích bản vá GNU tiêu chuẩn cho những người không có git--- nhưng không chạy format-patchvới các tùy chọn -M, -Cv.v. để tạo ra các bản vá lỗi đổi tên trong trường hợp đó, vì hỗ trợ cho chúng không phổ biến.


1
Xem lại trang này sau… Đây là câu trả lời tốt hơn cho câu hỏi được hỏi so với "người chiến thắng" trước đó đã đề xuất các mô-đun con.
James Wheare

4

Giả sử cả hai dự án đều là dự án git, có vẻ như các mô-đun con sẽ phù hợp nhất với bạn. Điều này cho phép một dự án git liên kết động với một dự án git khác, về cơ bản là nướng một git repo ngay bên trong một git repo khác, cả hai đều có cuộc sống riêng biệt của chúng.

Nói cách khác, thêm "main repo" làm submodule trong "project". Bất cứ khi nào bạn commit / push nội dung mới trong "main repo", bạn chỉ git pullchúng trở lại "project".


Rất tiếc, sau khi đọc qua các tài liệu về mô-đun con, điều này nghe có vẻ không phải là "một cách dễ dàng" mặc dù nó có thể là cách tốt nhất. Dường như tôi sẽ phải tạo ra một submodule chỉ chứa các playdar.jstập tin sau đó bao gồm rằng trong cả hai dự án khác (tôi không muốn mọi thứ khác từ www.playdar.orgtrong playlick.comdự án) Tôi chỉ có thể nghỉ mát để tự chỉnh sửa các tập tin vá cho bây giờ phải trung thực . Hoặc tiếp tục sao chép dán giữa hai. Chúc mừng.
James Wheare

Dưới đây là một hướng dẫn rõ ràng và kỹ lưỡng và bắt đầu với submodule git cho bất cứ ai khác ngại khi câu hỏi này: book.git-scm.com/5_submodules.html
James Wheare

2

Để hoàn thành câu trả lời của Henrik và để nhận điểm thưởng

Điều gì sẽ xảy ra nếu tệp bạn muốn áp dụng bản vá không có trong kho lưu trữ git?

Nếu bạn có quyền truy cập vào các thư mục của ứng cử viên tệp cho bản vá đến từ kho lưu trữ git, trước tiên bạn có thể chuyển đổi cây thư mục / tệp đó thành chính kho lưu trữ git! (' git init': một kho lưu trữ git chỉ là .git trong thư mục gốc).
Sau đó, bạn sẽ đặt repo đó làm mô-đun con cho dự án chính của bạn.


2

Sử dụng --relativetùy chọn để format-patchcó thể cải thiện tính trừu tượng (ẩn các chi tiết không liên quan về kho lưu trữ mà từ đó bản vá được tạo).

[repository-with-changes]
git format-patch --relative=(path-to-library) (base-commit-for-patch) ## 'HEAD~1'

Tôi đã tìm thấy --3waytùy chọn được yêu cầu khi áp dụng bản vá (để tránh does not exist in indexlỗi) - số dặm của bạn có thể thay đổi. Việc sử dụng --directory=(...)có thể chỉ cần thiết nếu đường dẫn đích của bạn không phải là thư mục gốc của kho lưu trữ.

[repository-to-update]
git am --3way --directory=(path-to-library) (patch-file)

  • format-patch sẽ tạo một tệp vá cho mỗi lần cam kết đến chi nhánh hiện tại kể từ 'cơ sở'.

  • Tài liệu cho --relativetùy chọn dường như bị thiếu trong một số trường hợp , nhưng dường như nó vẫn hoạt động (kể từ phiên bản 2.7.4).



1

Bạn chỉ có thể xóa (đổi tên) tạm thời kho lưu trữ chính.

cd to/main/project
mv .git .git_
cd to/sub/project
git apply patchname
cd -
mv .git_ .git

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.