Có thể chọn cherry một cam kết từ kho git khác không?


726

Tôi đang làm việc với một kho lưu trữ git cần một cam kết từ một kho lưu trữ git khác mà không biết gì về đầu tiên.

Thông thường tôi sẽ chọn cherry bằng cách sử dụng HEAD@{x}trong reflog, nhưng vì điều này .gitkhông biết gì về mục reflog này (thư mục vật lý khác nhau), làm thế nào tôi có thể chọn cherry này, hoặc tôi có thể?

Tôi đang sử dụng git-svn. Chi nhánh đầu tiên của tôi đang sử dụng git-svncủa trunkmột repo Subversion, và các chi nhánh tiếp theo được sử dụng git-svntrên một chi nhánh Subversion.


2
Đây là lý do được đưa ra bởi Ben Lee vì đã mở một tiền thưởng cho câu hỏi này: "Tôi sẽ trao phần thưởng cho câu trả lời đúng, thay vì câu trả lời được chấp nhận. Tôi chỉ phải đợi 24 [giờ] để làm như vậy." Tuy nhiên, tôi không hiểu câu nào trong số này được cho là "câu trả lời đúng" và tại sao câu trả lời được chấp nhận lại không "đúng".

1
Không rõ bản chất của vấn đề là gì. Làm thế nào là những repos khác nhau có liên quan, nếu có? Là một ngã ba của người khác? Hay họ thực sự là hai dự án hoàn toàn riêng biệt và không liên quan?

@Cupdding, câu trả lời được chấp nhận là tốt, và rõ ràng đã giúp OP, vì vậy nó nên được chấp nhận. Bởi "đúng" tôi thực sự chỉ có nghĩa là "phù hợp với tôi" (và đánh giá các bình luận, cũng đúng cho một số người khác). Tôi chỉ nghĩ rằng người mà tôi đã đưa tiền thưởng xứng đáng được nhiều đại diện như câu trả lời được chấp nhận.
Ben Lee

Câu trả lời:


557

Bạn sẽ cần thêm kho lưu trữ khác dưới dạng điều khiển từ xa, sau đó tìm nạp các thay đổi của nó. Từ đó bạn thấy cam kết và bạn có thể chọn nó.

Như thế

git remote add other https://example.link/repository.git
git fetch other

Bây giờ bạn có tất cả các thông tin để làm git cherry-pick.

Thông tin thêm về cách làm việc với điều khiển từ xa tại đây: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes


1
Nếu tôi đang sử dụng git-svn thì sao? Chi nhánh đầu tiên của tôi đang sử dụng git-svn của trung kế và tiếp theo là sử dụng git-svn trên một chi nhánh (cảm ơn vì đã trả lời nhanh)
gitcoder182

1
Khi bạn lần đầu tiên sao chép kho lưu trữ Subversion, hãy đảm bảo rằng bạn sao chép toàn bộ kho lưu trữ, không chỉ thân cây. Ngoài ra, hãy đảm bảo bạn sử dụng --stdlayouttùy chọn git-svn nếu bạn đang sử dụng bố cục trung kế / nhánh / thẻ tiêu chuẩn trong Subversion. Sau đó, nhánh Subversion sẽ chỉ là một nhánh git từ xa.
wilmustell

33
Nếu bạn đang sử dụng Github, bạn có thể kéo bản vá bằng cách thêm .patch vào URL cam kết, sau đó áp dụng nó với git am < d821j8djd2dj812.patch. Ngoài GH, các khái niệm tương tự có thể được thực hiện như được tham chiếu trong câu trả lời thay thế bên dưới.
radicand

2
@radicand câu trả lời nào dưới đây là câu "thay thế"? Vui lòng liên kết với nó.

7
Các bước chi tiết để chọn cherry từ một repo khác: coderwall.com/p/sgpksw/git-cherry-pick-from-another-reposeective
T. Kim Nguyen

854

Câu trả lời, như được đưa ra, là sử dụng định dạng vá nhưng vì câu hỏi là làm thế nào để chọn cherry từ một thư mục khác, đây là một đoạn mã để làm điều đó:

$ git --git-dir=../<some_other_repo>/.git \
format-patch -k -1 --stdout <commit SHA> | \
git am -3 -k

(giải thích từ @cong ma )

Các git format-patchlệnh tạo ra một bản vá từ some_other_repo's cam kết theo quy định của SHA của nó ( -1cho một cam kết duy nhất một mình). Bản vá này được dẫn đến git am, áp dụng bản vá cục bộ ( -3có nghĩa là thử hợp nhất ba chiều nếu bản vá không áp dụng sạch). Hy vọng rằng giải thích.


18
Đây là điểm nổi bật, nhưng sẽ rất tuyệt nếu bất cứ ai có thể mở rộng về điều này - một sự cố chính xác những gì đang diễn ra (đặc biệt là với những lá cờ đó) sẽ vô cùng hữu ích.
Nick F

46
@NickF, git format-patchlệnh tạo một bản vá từ some_other_repocam kết được chỉ định bởi SHA của nó (chỉ -1cho một cam kết duy nhất). Bản vá này được dẫn đến git am, áp dụng bản vá cục bộ ( -3có nghĩa là thử hợp nhất ba chiều nếu bản vá không áp dụng sạch). Hy vọng rằng giải thích.
Công Ma

3
lỗi: patch không thành công: somefile.cs: 85 error: somefile.cs: patch không áp dụng Bạn có chỉnh sửa bản vá của mình không? Nó không áp dụng cho các đốm màu được ghi trong chỉ mục của nó. Không thể quay lại hợp nhất ba chiều. Bản vá lỗi ở 0001 Đã thêm các phần GUI. Bản sao của bản vá không thành công được tìm thấy trong: <some_other_Vpo> /. Git / rebase-application / patch Khi bạn đã giải quyết vấn đề này, hãy chạy "git am --continue". Nếu bạn muốn bỏ qua bản vá này, hãy chạy "git am --skip". Để khôi phục nhánh ban đầu và dừng vá lỗi, hãy chạy "git am --abort".
Tom

8
@Tom thử dùng --ignore-whitespace. Toàn lệnh: git --git-dir=../<some_other_repo>/.git format-patch -k -1 --stdout <commit SHA> | git am -3 -k --ignore-whitespace
Jake Graham Arnold

7
@BoomShadow Bởi vì nó đơn giản hơn. Thêm điều khiển từ xa và tìm nạp mang lại tất cả các thay đổi của repo khác. Dòng lệnh này là một hành động một lần.
Jonathon Reinhart

152

Đây là một ví dụ về hợp nhất tìm nạp từ xa.

cd /home/you/projectA
git remote add projectB /home/you/projectB
git fetch projectB

Sau đó bạn có thể:

git cherry-pick <first_commit>..<last_commit>

hoặc thậm chí bạn có thể hợp nhất toàn bộ chi nhánh

git merge projectB/master

54
git merge projectB/master là rất, rất sai , bởi vì bạn đang không áp dụng các thay đổi từ một cam kết duy nhất (giống như một anh đào-pick sẽ), bạn đang thực sự sáp nhập trong tất cả các thay đổi trongprojectB/masterđó không chứa trong mìnhmasterchi nhánh.

4
Đó là giả định của tôi rằng đây là ý định ban đầu của người đăng. Mặt khác, vâng, đây không phải là lựa chọn phù hợp cho họ.
Brian

5
Điều này hoạt động rực rỡ khi hai kho lưu trữ có liên quan.
Ronny Ager-Bấc

1
Tôi đã tạo một bản sao từ kho git (chỉ để "chơi xung quanh" mà không phá vỡ repo gốc) và để cập nhật với nguồn của nó, câu trả lời từ Brian chính xác là những gì tôi cần, vì vậy, Cupcake, tôi phải nói rằng, nó không "sai", nhưng một trường hợp sử dụng khác. Nhưng thật tuyệt khi bạn chỉ ra thảm họa tiềm tàng: D
ferrari2k

6
IMO này cần phải là giải pháp được chấp nhận. Ngoài ra, nếu bạn muốn xóa điều khiển từ xa sau khi bạn chọn xong cherry, hãy sử dụng git remote rm projectB. Cũng sử dụng git tag -d tag-nameđể xóa bất kỳ thẻ nào được tìm nạp từ repo từ xa. Các cam kết từ xa sẽ không còn hiển thị trong lịch sử của bạn nữa và việc cắt tỉa sẽ loại bỏ chúng khỏi bộ lưu trữ.
ADTC

130

Bạn có thể làm điều đó, nhưng nó đòi hỏi hai bước. Đây là cách thực hiện:

git fetch <remote-git-url> <branch> && git cherry-pick FETCH_HEAD

Thay thế <remote-git-url>bằng url hoặc đường dẫn đến kho lưu trữ mà bạn muốn chọn.

Thay thế <branch>bằng tên nhánh hoặc thẻ bạn muốn chọn cherry từ kho lưu trữ từ xa.

Bạn có thể thay thế FETCH_HEADbằng một SHA git từ chi nhánh.

Đã cập nhật: sửa đổi dựa trên phản hồi của @ pkalinow.


8
Nó hoạt động với một tên chi nhánh, nhưng không phải với SHA. Nếu bạn muốn chọn một cam kết được biểu thị bằng hàm băm của nó, hãy sử dụng thay thế này : git fetch <repo-url> <branch> && git cherry-pick <sha>.
pkalinow

Cảm ơn. Đây chỉ là những gì tôi cần để chèn một số cam kết từ kho này sang kho khác, mà tôi đã tạo cho mục đích này.
wojciii

Đây chính xác là những gì tôi cần với nhiều triển khai mã tùy chỉnh của chúng tôi cho các khách hàng khác nhau (mỗi người có kho / dĩa riêng), chúng tôi cần một cách để có được các cam kết cụ thể vào cơ sở / trung kế của chúng tôi. CẢM ƠN!
RedSands

Đây phải là câu trả lời được chấp nhận cho một lượt chọn cherry một shot trên các repos. Tôi sử dụng nó mọi lúc khi chọn giữa các repos đã là cục bộ, URL từ xa sau đó chỉ là một đường dẫn hệ thống tệp cục bộ.
Amedee Van Gasse

61

Dưới đây là các bước để thêm một điều khiển từ xa, tìm nạp các nhánh và chọn một cam kết

# Cloning our fork
$ git clone git@github.com:ifad/rest-client.git

# Adding (as "endel") the repo from we want to cherry-pick
$ git remote add endel git://github.com/endel/rest-client.git

# Fetch their branches
$ git fetch endel

# List their commits
$ git log endel/master

# Cherry-pick the commit we need
$ git cherry-pick 97fedac

Nguồn: https://coderwall.com/p/sgpksw



11

Bạn có thể làm điều đó trong một dòng như sau. Hy vọng bạn đang ở trong kho git cần thay đổi anh đào và bạn đã kiểm tra để sửa chi nhánh.

git fetch ssh://git@stash.mycompany.com:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [URL nhánh] [Chi nhánh để chọn cherry] && git cherry-pick [ID xác nhận]


1
Chúc mừng, không cần ssh://phần, chỉ dành chohttps://
Leo

5

Đúng. Tìm nạp kho lưu trữ và sau đó chọn cherry từ nhánh từ xa.


1

Giả sử Alà repo bạn muốn chọn cherry, và Blà một trong những bạn muốn chọn cherry, bạn có thể làm điều này bằng cách thêm </path/to/repo/A/>/.git/objectsvào </path/to/repo/B>/.git/objects/info/alternates. Tạo alternatestập tin này nếu nó không tồn tại.

Điều này sẽ làm cho repo B truy cập tất cả các đối tượng git từ repo A, và sẽ làm cho cherry-pick hoạt động cho bạn.


0

Tình huống của tôi là tôi có một repo trần mà đội đẩy tới, và một bản sao của nó ngồi ngay bên cạnh. Tập hợp các dòng trong Makefile này hoạt động chính xác với tôi:

git reset --hard
git remote update --prune
git pull --rebase --all
git cherry-pick -n remotes/origin/$(BRANCH)

Bằng cách giữ cho chủ nhân của repo trần được cập nhật, chúng tôi có thể chọn ra một thay đổi được đề xuất được công bố cho repo trần. Chúng tôi cũng có một cách (phức tạp hơn) để chọn nhiều anh đào để xem xét và kiểm tra tổng hợp.

Nếu "không biết gì" có nghĩa là "không thể được sử dụng như một điều khiển từ xa", thì điều này không có ích, nhưng câu hỏi SO này xuất hiện khi tôi đang loay hoay tìm ra quy trình làm việc này vì vậy tôi nghĩ tôi sẽ đóng góp lại.


-n có nghĩa là không cam kết theo tài liệu git và tôi rất quan trọng để xem các thay đổi trước khi thực hiện cam kết
canbax

0

Nếu bạn muốn chọn nhiều cam kết cho một tệp nhất định cho đến khi bạn đạt được một cam kết nhất định, thì hãy sử dụng cách sau.

# Directory from which to cherry-pick
GIT_DIR=...
# Pick changes only for this file
FILE_PATH=...
# Apply changes from this commit
FIST_COMMIT=master
# Apply changes until you reach this commit
LAST_COMMIT=...

for sha in $(git --git-dir=$GIT_DIR log --reverse --topo-order --format=%H $LAST_COMMIT_SHA..master -- $FILE_PATH ) ; do 
  git --git-dir=$GIT_DIR  format-patch -k -1 --stdout $sha -- $FILE_PATH | 
    git am -3 -k
done
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.