Làm cách nào để áp dụng bản vá Git cho một tệp có tên và đường dẫn khác?


100

Tôi có hai kho. Trong một, tôi thực hiện các thay đổi đối với tệp ./hello.test. Tôi cam kết các thay đổi và tạo một bản vá từ cam kết đó với git format-patch -1 HEAD. Bây giờ, tôi có một kho lưu trữ thứ hai có chứa một tập tin có nội dung tương tự như hello.test nhưng được đặt trong một thư mục khác nhau dưới một cái tên khác nhau: ./blue/red/hi.test. Tôi làm cách nào để áp dụng bản vá nói trên cho hi.testtệp? Tôi đã thử git am --directory='blue/red' < patch_filenhưng tất nhiên điều đó phàn nàn rằng các tệp không được đặt tên giống nhau (mà tôi nghĩ Git không quan tâm?). Tôi biết mình có thể chỉnh sửa sự khác biệt để áp dụng cho tệp cụ thể đó nhưng tôi đang tìm giải pháp lệnh.


Câu trả lời:


97

Bạn có thể tạo bản vá bằng cách sử dụng git diffvà sau đó áp dụng nó bằng patchtiện ích, cho phép bạn chỉ định tệp bạn muốn áp dụng sự khác biệt.

Ví dụ:

cd first-repo
git diff HEAD^ -- hello.test > ~/patch_file

cd ../second-repo
patch -p1 blue/red/hi.test ~/patch_file

7
Ah, tốt, không nghĩ về điều đó. Tuy nhiên, có cách nào để làm điều này với các lệnh Git để dữ liệu cam kết (ngày và giờ, tác giả cam kết, thông báo cam kết) được giữ nguyên không?
mart1n

2
Có thể có điều gì đó bạn có thể làm với amhoặc apply, nhưng tôi không thể tìm thấy nó. Nếu bạn thấy mình sao chép nhiều thay đổi, có thể có một giải pháp tốt hơn bằng cách sử dụng mô-đun con hoặc bất kỳ ngôn ngữ nào bạn chọn cung cấp để chia sẻ mã (ví dụ: trong Ruby, bạn có thể trích xuất mã trùng lặp dưới dạng đá quý).
georgebrock

1
Điều này thực sự liên quan đến tài liệu (các tệp nguồn là XML). Các mô-đun con không thực sự là một lựa chọn vì tôi sẽ phải tạo ra một trường hợp mạnh mẽ cho chúng trong cơ sở hạ tầng hiện có của chúng tôi.
mart1n

52

Có một giải pháp đơn giản không liên quan đến chỉnh sửa bản vá thủ công cũng như tập lệnh bên ngoài.

Trong kho lưu trữ đầu tiên (điều này cũng có thể xuất một loạt các cam kết, sử dụng -1nếu bạn chỉ muốn chọn một cam kết):

git format-patch --relative <committish> --stdout > ~/patch

Trong kho thứ hai:

git am --directory blue/red/ ~/patch

Thay vì sử dụng --relativetrong git format-patch, một giải pháp khác là sử dụng -p<n>tùy chọn trong git amđể tách các nthư mục khỏi đường dẫn của các bản vá, như đã đề cập trong câu trả lời cho một câu hỏi tương tự .

Nó cũng có thể chạy git format-patch --relative <committish>mà không có --stdout, và nó sẽ tạo ra một tập hợp các .patchtệp. Các tệp này sau đó có thể được cung cấp trực tiếp git amvới git am --directory blue/red/ path/to/*.patch.


9
Điều này vẫn dựa trên thực tế là các tên tệp giống nhau, phải không?
mart1n

3
Cần lưu ý rằng --directorytùy chọn này xuất hiện yêu cầu bạn chỉ định đường dẫn đầy đủ của thư mục liên quan đến thư mục gốc; một cái gì đó như --directory=./trong khi chdir'd vào một thư mục con trong repo sẽ không hoạt động.
Reid

1
Sử dụng --3waytrợ giúp với does not exist in index:git am --3way --directory (relative-path) (patch)
Brent Bradburn.

Sử dụng -kphím trong cả hai lệnh để không tách dòng đầu tiên của thông báo cam kết.
ruvim

Việc sử dụng --3waykhông chỉ giúp khắc phục lỗi "không tồn tại trong chỉ mục" (như được chỉ ra bởi @nobar) mà còn cho phép bạn xử lý rõ ràng các xung đột hợp nhất. Thay vì để nguyên các tệp xung đột, một khối xung đột được thêm vào mà sau đó có thể được giải quyết.
Daniel Wolf,

11

Trả lời câu hỏi của riêng tôi bằng tập lệnh thực hiện điều này: https://github.com/mprpic/apply-patch-to-file

Thay vì sửa đổi tệp vá theo cách thủ công, nó sẽ nhắc người dùng về tệp đích, sửa đổi bản vá và áp dụng nó cho repo bạn hiện đang sử dụng.


5

Dựa trên câu trả lời của @georgebrock, đây là một giải pháp tôi đã sử dụng:

Đầu tiên, tạo các tệp vá như bình thường (ví dụ: git format-patch commitA..commitB :).

Sau đó, đảm bảo rằng kho lưu trữ mục tiêu của bạn sạch sẽ (không có tệp đã thay đổi hoặc chưa được kiểm soát) và áp dụng các bản vá như sau:

cd second-repo
git am ~/00*.patch

Đối với mỗi tệp vá lỗi, bạn sẽ gặp lỗi như "error: XYZ không tồn tại trong chỉ mục". Bây giờ bạn có thể áp dụng tệp vá này theo cách thủ công:

patch --directory blue/red < ~/0001-*.patch
git add -a
git am --continue

Bạn phải thực hiện ba bước này cho mỗi tệp vá.

Điều này sẽ bảo toàn thông báo cam kết ban đầu, v.v. mà không yêu cầu bất kỳ git format-patchlệnh đặc biệt nào hoặc chỉnh sửa các tệp vá.


1
Câu trả lời tốt, tôi nghĩ đây là nền tảng tốt nhất cho bất kỳ loại thao tác vá "không chuẩn" nào. Tôi làm điều đó trong 3 bước. (1) Cam kết văn bản - git format-patch -1 commitA --stdout > thing.diff; (2) Chỉnh sửa tệp vá cho đến khi nó thực hiện những gì tôi cần; (3) Văn bản để cam kết git am --3way thing.diff có ưu điểm là bạn có thể chấp nhận các phần của bản vá áp dụng một cách sạch sẽ và sử dụng gitquy trình giải quyết xung đột tiêu chuẩn cho các phần không áp dụng.
We Are All Monica,

2

Tôi hiểu rằng hai tệp hoàn toàn giống nhau trong trường hợp của bạn, do đó, bản vá có khả năng thành công.

Tuy nhiên, trong trường hợp bạn muốn áp dụng một bản vá cho một tệp tương tự, nhưng không chính xác cùng một tệp hoặc bạn muốn thực hiện một bản vá tương tác, bạn sẽ sử dụng hợp nhất ba cách.

Giả sử bạn đã sửa đổi Tệp A, hãy biểu thị A~1là phiên bản trước và bạn muốn áp dụng sự khác biệt giữa A~1đối Avới Tệp B.

Mở công cụ hợp nhất ba cách, ví dụ: Beyond Compare, đường dẫn của bảng điều khiển bên trái là A, bảng điều khiển ở giữa là tổ tiên chung nên đường dẫn là A~1, đường dẫn của bảng điều khiển bên phải B. Sau đó, bảng điều khiển phía dưới hiển thị kết quả của việc áp dụng sự khác biệt giữa A~1to Avới File B.

Hình sau minh họa ý tưởng.

nhập mô tả hình ảnh ở đây


0

FYI: Gần đây, tôi đã gặp sự cố khi cố gắng tải xuống bản vá từ Github và áp dụng nó vào một tệp cục bộ (bị "ghi đè" ở một vị trí mới).

git amcũng sẽ không áp dụng bản vá vì tệp "không có trong chỉ mục" hoặc "bẩn". Tuy nhiên, tôi thấy rằng patchlệnh đơn giản có thể áp dụng bản vá. Nó đã nhắc tôi tên của tệp cần được vá.

Dù sao thì cũng đã hoàn thành công việ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.