Làm cách nào để hợp nhất các thay đổi vào một tệp, thay vì hợp nhất các cam kết?


383

Tôi có hai nhánh (A và B) và tôi muốn hợp nhất một tệp từ nhánh A với một tệp tương ứng từ Nhánh B.


2
Đã thảo luận ở đây stackoverflow.com/questions/449541/ từ
positron

27
Hầu hết các phản hồi cho bài đăng khác là về cách hợp nhất có chọn lọc các cam kết , không phải các tệp . Điều này làm cho câu trả lời được chọn không chính xác. Câu hỏi vẫn chưa được trả lời.


Câu trả lời này là con đường để đi, IMO. git diff branch_name > patch git apply patch. stackoverflow.com/a/9473543/1091853
blamb

Câu trả lời:


631

Tôi đã gặp vấn đề tương tự. Nói chính xác, tôi có hai nhánh ABcó cùng tệp nhưng giao diện lập trình khác nhau trong một số tệp. Bây giờ các phương thức của tệp f, độc lập với sự khác biệt về giao diện trong hai nhánh, đã được thay đổi trong nhánh B, nhưng sự thay đổi rất quan trọng đối với cả hai nhánh. Vì vậy, tôi cần hợp nhất chỉ tập tin fcủa chi nhánh Bvào tập tin fcủa chi nhánh A.

Một lệnh đơn giản đã giải quyết vấn đề cho tôi nếu tôi cho rằng tất cả các thay đổi được cam kết trong cả hai nhánh AB:

git checkout A

git checkout --patch B f

Lệnh đầu tiên chuyển sang nhánh A, vào nơi tôi muốn hợp nhất Bphiên bản của tệp f. Lệnh thứ hai bản vá lỗi tập tin fvới fcác HEADsố B. Bạn thậm chí có thể chấp nhận / loại bỏ các phần duy nhất của bản vá. Thay vì Bbạn có thể chỉ định bất kỳ cam kết nào ở đây, nó không phải như vậy HEAD.

Chỉnh sửa cộng đồng : Nếu tệp ftrên Bchưa tồn tại A, thì bỏ qua --patchtùy chọn. Nếu không, bạn sẽ nhận được "Không thay đổi." thông điệp.


10
Điều này chỉ hoạt động nếu bạn muốn cập nhật một tập tin. Nếu tôi muốn thêm một tệp mới từ nhánh B sang nhánh A thì sao?
Umair A.

25
@UmairAshraf bạn sẽ có thể thêm một tệp mới từ B đến A bằng cách xóa tùy chọn --patch.
bbak

9
Hmmm ... khi tôi thử điều này, tôi nhận được thông báo "không thay đổi", nhưng rõ ràng có những thay đổi. OK, tôi cần phải ở trong thư mục chứa tập tin liên quan. Chỉnh sửa: Đây hoàn toàn có thể là giải pháp yêu thích của tôi cho một vấn đề tôi đã thấy trên stackoverflow :-D
bot_bot

2
Tôi đã phải sử dụng git checkout --patch B -- fđể có được điều này để làm việc.
dùng545424

8
Chỉ cần thêm rằng nếu bạn có nhiều thay đổi (hunk) trong tệp và bạn muốn xử lý tất cả chúng , bạn có thể nhấn atrong giai đoạn tương tác, thay vì nhấn ymỗi lần. Hoặc sử dụng git checkout B -- flệnh thay thế.
Dmitry Gonchar

17

Đây là những gì tôi làm trong những tình huống này. Đó là một loại bùn nhưng nó hoạt động tốt với tôi.

  1. Tạo một chi nhánh khác dựa trên chi nhánh làm việc của bạn.
  2. git pull / git hợp nhất bản sửa đổi (SHA1) có chứa tệp bạn muốn sao chép. Vì vậy, điều này sẽ hợp nhất tất cả các thay đổi của bạn, nhưng chúng tôi chỉ sử dụng nhánh này để lấy một tệp.
  3. Khắc phục mọi xung đột, vv điều tra tệp của bạn.
  4. kiểm tra chi nhánh làm việc của bạn
  5. Kiểm tra các tập tin cam kết từ hợp nhất của bạn.
  6. Cam kết nó.

Tôi đã thử vá và tình hình của tôi quá xấu cho nó. Vì vậy, trong ngắn hạn, nó sẽ trông như thế này:

Chi nhánh hoạt động: Chi nhánh thử nghiệm: B (chứa file.txt có các thay đổi tôi muốn gấp lại.)

git checkout A

Tạo chi nhánh mới dựa trên A:

git checkout -b tempAB

Hợp nhất B vào tempAB

git merge B

Sao chép băm sha1 của hợp nhất:

git log

commit 8dad944210dfb901695975886737dc35614fa94e
Merge: ea3aec1 0f76e61
Author: matthewe <matthewe@matthewe.com>
Date:   Wed Oct 3 15:13:24 2012 -0700

Merge branch 'B' into tempAB

Kiểm tra chi nhánh làm việc của bạn:

git checkout A

Kiểm tra tập tin cố định của bạn:

git checkout 7e65b5a52e5f8b1979d75dffbbe4f7ee7dad5017 file.txt

Và ở đó bạn nên có nó. Cam kết kết quả của bạn.


3
Vì vậy, chúng ta phải làm tất cả điều này chỉ để hợp nhất một tập tin duy nhất? Sẽ không dễ dàng hơn để sao chép và dán tệp vào nhánh khác
Robin

1
@Robin có thể không, vì việc hợp nhất giữ các thay đổi trên tệp, khác nhau giữa nhánh A và B. sao chép tệp sẽ ghi đè lên bất kỳ sự khác biệt bổ sung nào giữa nhánh A làm việc của bạn và những gì bạn muốn đưa vào từ B, có thể không chứa những mục / chỉnh sửa. ví dụ nghi ngờ Ađã chuyển hướng từ Bđể bắt đầu, theo những cách khác. Sao chép sẽ ghi đè lên những khác biệt.
blamb

14

Điều này sử dụng Difftool nội bộ của git. Có thể một chút việc phải làm nhưng thẳng tiến.

#First checkout the branch you want to merge into
git checkout <branch_to_merge_into>

#Then checkout the file from the branch you want to merge from
git checkout <branch_to_merge_from> -- <file> 

#Then you have to unstage that file to be able to use difftool
git reset HEAD <file> 

#Now use difftool to chose which lines to keep. Click on the mergebutton in difftool
git difftool

#Save the file in difftool and you should be done.

1
Để làm rõ việc sử dụng --(nhãn đối số trống), tài liệu kiểm tra git: ARGUMENT DISAMBIGUATION nói: "sử dụng git checkout -- <pathspec>nếu bạn muốn kiểm tra các đường dẫn này ra khỏi chỉ mục." Điều này là do bạn có thể có cả nhánh và tệp / đường dẫn cùng tên. Trong các trường hợp như vậy, thay vì yêu cầu bạn định hướng xem chi nhánh hoặc đường dẫn nên được kiểm tra khi cả hai tồn tại, git sẽ chọn kiểm tra chi nhánh theo mặc định. Tuy nhiên, nếu ưu tiên --git sẽ kiểm tra tệp / đường dẫn thay thế.
SherylHohman

8

Tôi thấy cách tiếp cận này đơn giản và hữu ích: Cách "hợp nhất" các tệp cụ thể từ một nhánh khác

Hóa ra, chúng tôi đang cố gắng quá sức. Người bạn tốt của chúng tôi kiểm tra git là công cụ phù hợp cho công việc.

git checkout source_branch <paths>...

Chúng tôi chỉ đơn giản có thể cung cấp cho git checkout tên của nhánh tính năng A và các đường dẫn đến các tệp cụ thể mà chúng tôi muốn thêm vào nhánh chính của chúng tôi.

Xin vui lòng đọc toàn bộ bài viết để hiểu thêm


2
Điều này ghi đè lên các tệp, nó không hợp nhất chúng
Alex G

Đối với bạn nó có thể, nó phụ thuộc vào những gì bạn đang làm và những gì bạn đang cố gắng để đạt được. Ý tưởng ở đây là nhánh B là ngã ba của A, bạn sửa đổi 4 tệp trong B, nhưng muốn hợp nhất chỉ 2 từ B thành A. Hợp nhất thông thường sẽ hợp nhất cả 4, ở đây bạn có thể chọn. Điều này có thể trông như bị ghi đè vì B chứa các tệp mới hơn. Bạn cần hỗ trợ kinh nghiệm của bạn với một số bằng chứng.
Pawel Cioch

Tôi đồng ý rằng nó ghi đè lên. Tôi nghĩ bạn có nghĩa là sử dụng -ptùy chọn trong lệnh đó. Sau đó, ghi đè lên bất kỳ phần nào trên tệp worktree của bạn trước đây đã chuyển hướng khỏi chi nhánh mà bạn đã kiểm tra, trước khi thay đổi bản vá, thật không may.
blamb

Ý tưởng là từ năm 2009, rất có thể phiên bản mới của git hoạt động khác đi và cần -p hoặc bất cứ thứ gì khác nhưng khi tôi đăng nó thì nó hoạt động với tôi, nhưng một lần nữa tôi có thể không quan tâm đến các tệp bị ghi đè, như phiên bản mới nhất là những gì tôi cần
Pawel Cioch 22/11/19


3

Lệnh sau sẽ (1) so sánh tệp của nhánh chính xác, với chủ (2) tương tác hỏi bạn những áp dụng sửa đổi nào.

kiểm tra git - chủ hàng


0

Chỉnh sửa của tôi đã bị từ chối, vì vậy tôi đang đính kèm cách xử lý các thay đổi hợp nhất từ ​​một chi nhánh ở đây.

Nếu bạn phải làm điều này sau khi hợp nhất không chính xác, bạn có thể làm một cái gì đó như thế này:

# If you did a git pull and it broke something, do this first
# Find the one before the merge, copy the SHA1
git reflog
git reset --hard <sha1>

# Get remote updates but DONT auto merge it
git fetch github 

# Checkout to your mainline so your branch is correct.
git checkout develop 

# Make a new branch where you'll be applying matches
git checkout -b manual-merge-github-develop

# Apply your patches
git checkout --patch github/develop path/to/file
...

# Merge changes back in
git checkout develop
git merge manual-merge-github-develop # optionally add --no-ff

# You'll probably have to
git push -f # make sure you know what you're doing.

0

Giả sử B là nhánh hiện tại:

$ git diff A <file-path> > patch.tmp
$ git apply patch.tmp -R

Lưu ý rằng điều này chỉ áp dụng thay đổi cho tệp cục bộ. Bạn sẽ cần phải cam kết sau đó.


Đối với tôi, điều này tạo ra mộterror: <file-path>: already exists in working directory
kontur

Bạn nên tập tin cụ thể hoặc đường dẫn tập tin tại thư mục hiện tại. Tôi đang sử dụnggit diff Branch_A <file-path, filename> -- hash_commit > file_name.temp
R.Chatsiri

0

Bạn có thể kiểm tra phiên bản cũ của tệp để hợp nhất, lưu nó dưới một tên khác, sau đó chạy bất cứ công cụ hợp nhất nào của bạn trên hai tệp.

ví dụ.

git show B:src/common/store.ts > /tmp/store.ts (trong đó B là tên chi nhánh / cam kết / thẻ)

meld src/common/store.ts /tmp/store.ts


0

Tôi sẽ làm như

git format-patch branch_old..branch_new file

điều này sẽ tạo ra một bản vá cho tập tin.

Áp dụng bản vá tại mục tiêu Branch_old

git am blahblah.patch


Bạn có thể dễ dàng nhìn vào các bản vá cho an toàn hơn?
XavierStuvw
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.