Truy xuất cam kết cụ thể từ kho lưu trữ Git từ xa


189

Có cách nào để chỉ lấy một cam kết cụ thể từ repo Git từ xa mà không cần sao chép nó trên PC của tôi không? Cấu trúc của repo từ xa hoàn toàn giống với cấu trúc của tôi và do đó sẽ không có bất kỳ xung đột nào nhưng tôi không biết làm thế nào để làm điều này và tôi không muốn sao chép kho lưu trữ khổng lồ đó.

Tôi mới dùng git, có cách nào không?


1
Là repo hiện tại của bạn đã là một bản sao của điều khiển từ xa, hoặc nó hoàn toàn khác nhau?
CharlesB

Chà, repo là nguồn nhân Linux, và nó khá giống nhau
Varun Chitre

vậy nó có phải là bản sao hay không?
CharlesB

1
Không chính xác. Hãy xem xét điều này, Hãy để repo từ xa ở đầu D và của tôi ở đầu A và đứng sau B, C, D cam kết. Tôi muốn hợp nhất cam kết B từ một repo và C từ một repo khác và D từ một repo khác như B, C, D cam kết trong các repos này khác với các đặc sản riêng của họ
Varun Chitre

1
@VarunChitre bạn có thể chấp nhận câu trả lời khác từ VonC không?
CharlesB

Câu trả lời:


108

Bắt đầu với phiên bản Git 2.5+ (quý 2 năm 2015), việc tìm nạp một cam kết duy nhất (không nhân bản toàn bộ repo) là thực sự có thể.

Xem cam kết 68ee628 của Fredrik Medley ( moroten) , ngày 21 tháng 5 năm 2015.
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết a9d3493 , ngày 01 tháng 6 năm 2015)

Bây giờ bạn có một cấu hình mới (về phía máy chủ)

uploadpack.allowReachableSHA1InWant

Cho phép upload-packchấp nhận yêu cầu tìm nạp yêu cầu một đối tượng có thể truy cập từ bất kỳ mẹo tham chiếu nào. Tuy nhiên, lưu ý rằng tính toán khả năng tiếp cận đối tượng là tính toán tốn kém.
Mặc định cho false.

Nếu bạn kết hợp cấu hình phía máy chủ đó với bản sao nông ( git fetch --depth=1), bạn có thể yêu cầu một cam kết duy nhất (xem t/t5516-fetch-push.sh:

git fetch --depth=1 ../testrepo/.git $SHA1

Bạn có thể sử dụng git cat-filelệnh để thấy rằng cam kết đã được tìm nạp:

git cat-file commit $SHA1

" git upload-pack" phục vụ " git fetch" có thể được yêu cầu phục vụ các cam kết không nằm trong đầu của bất kỳ ref nào, miễn là chúng có thể truy cập được từ một ref, với uploadpack.allowReachableSHA1InWant biến cấu hình.


Tài liệu đầy đủ là:

upload-pack: tùy chọn cho phép tìm nạp sha1 có thể truy cập

Với uploadpack.allowReachableSHA1InWanttùy chọn cấu hình được đặt ở phía máy chủ, " git fetch" có thể đưa ra yêu cầu với dòng "muốn" đặt tên cho một đối tượng chưa được quảng cáo (có thể đã được lấy ra khỏi băng tần hoặc từ một con trỏ mô hình con).
Chỉ các đối tượng có thể truy cập từ các mẹo nhánh, tức là sự kết hợp của các nhánh và nhánh được quảng cáo ẩn bởi transfer.hideRefs, sẽ được xử lý.
Lưu ý rằng có một chi phí liên quan đến việc phải quay lại lịch sử để kiểm tra khả năng tiếp cận.

Tính năng này có thể được sử dụng khi có được nội dung của một cam kết nhất định, mà sha1 được biết đến, mà không cần phải sao chép toàn bộ kho lưu trữ, đặc biệt nếu sử dụng tìm nạp nông .

Trường hợp hữu ích là ví dụ

  • kho chứa các tệp lớn trong lịch sử,
  • chỉ tìm nạp dữ liệu cần thiết cho kiểm tra mô hình con,
  • khi chia sẻ sha1 mà không cho biết chính xác nó thuộc về nhánh nào và trong Gerrit, nếu bạn nghĩ về các cam kết thay vì thay đổi số.
    (Trường hợp Gerrit đã được giải quyết thông qua allowTipSHA1InWantvì mọi thay đổi của Gerrit đều có tham chiếu.)

Git 2.6 (quý 3 năm 2015) sẽ cải thiện mô hình đó.
Xem cam kết 2bc31d1 , cam kết cc118a6 (28 tháng 7 năm 2015) của Jeff King ( peff) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 824a0be , ngày 19 tháng 8 năm 2015)

refs: hỗ trợ tiêu cực transfer.hideRefs

Nếu bạn ẩn một hệ thống phân cấp của ref bằng cách sử dụng transfer.hideRefscấu hình, không có cách nào để ghi đè cấu hình đó để "bỏ ẩn" nó.
Bản vá này thực hiện ẩn "tiêu cực" khiến các trận đấu ngay lập tức được đánh dấu là không bị cấm, ngay cả khi một trận đấu khác sẽ ẩn nó.
Chúng tôi cẩn thận áp dụng các trận đấu theo thứ tự ngược từ cách chúng được cung cấp cho chúng tôi bởi máy cấu hình, vì điều đó cho phép cấu hình ưu tiên "lần cuối cùng thắng" thông thường của chúng tôi ( .git/configví dụ: các mục trong sẽ ghi đè lên /etc/gitconfig).

Vì vậy, bây giờ bạn có thể làm:

git config --system transfer.hideRefs refs/secret
git config transfer.hideRefs '!refs/secret/not-so-secret'

để ẩn refs/secrettrong tất cả các repos, ngoại trừ một bit công khai trong một repo cụ thể.


Git 2.7 (tháng 11/12/2015) sẽ cải thiện trở lại:

Xem cam kết 948bfa2 , cam kết 00b293e (5 tháng 11 năm 2015), cam kết 78a766a , cam kết 92cab49 , cam kết 92cab49 , cam kết 92cab49 (3 tháng 11 năm 2015), cam kết 00b293e , cam kết 00b293e (5 tháng 11 năm 2015), và cam kết 92cab49 , cam kết 92cab49 , cam kết 92cab49 , cam kết 92cab49 (03 tháng 11 năm 2015) bởi Lukas Fleischer ( lfos) .
Được giúp đỡ: Eric Sunshine ( sunshineco) .
(Được hợp nhất bởi Jeff King - peff- trong bản cam kết dbba85e , ngày 20 tháng 11 năm 2015)

config.txt: ghi lại ngữ nghĩa của hideRefsvới không gian tên

Ngay bây giờ, không có định nghĩa rõ ràng về cách transfer.hideRefsứng xử khi không gian tên được đặt.
Giải thích rằng hideRefstiền tố khớp với tên bị tước trong trường hợp đó. Đây là cách hideRefscác mẫu hiện đang được xử lý trong gói nhận.

hideRefs: thêm hỗ trợ để phù hợp với giới thiệu đầy đủ

Ngoài việc so sánh các tham chiếu bị tước, giờ đây người ta có thể thêm hideRefscác mẫu mà tham chiếu đầy đủ (chưa được xử lý) được khớp với.
Để phân biệt giữa khớp bị tước và khớp hoàn toàn, các mẫu mới đó phải được thêm tiền tố với dấu mũ ( ^).

Do đó tài liệu mới :

transfer.hideRefs:

Nếu một không gian tên được sử dụng, tiền tố không gian tên bị tước khỏi mỗi tham chiếu trước khi nó được khớp với transfer.hiderefscác mẫu.
Ví dụ, nếu refs/heads/masterđược quy định trong transfer.hideRefsvà không gian tên hiện tại foo, sau đó refs/namespaces/foo/refs/heads/master được bỏ qua từ quảng cáo nhưng refs/heads/masterrefs/namespaces/bar/refs/heads/mastervẫn đang được quảng cáo như cái gọi là "có" dòng.
Để khớp với ref trước khi tước, hãy thêm ^vào trước tên ref. Nếu bạn kết hợp !^, !phải được chỉ định đầu tiên.


R .. đề cập trong các ý kiến cấu hình uploadpack.allowAnySHA1InWant, cho phép upload-packchấp nhận một fetchyêu cầu yêu cầu bất kỳ đối tượng nào. (Mặc định là false).

Xem cam kết f8edeaa (tháng 11 năm 2016, Git v2.11.1) của David "novalis" Turner ( novalis) :

upload-pack: tùy chọn cho phép tìm nạp bất kỳ sha1

Có vẻ hơi ngớ ngẩn khi thực hiện kiểm tra khả năng tiếp cận trong trường hợp chúng tôi tin tưởng người dùng truy cập hoàn toàn mọi thứ trong kho lưu trữ.

Ngoài ra, nó không phù hợp trong một hệ thống phân tán - có lẽ một máy chủ quảng cáo một ref, nhưng một máy chủ khác đã bị ép buộc với ref đó, và có lẽ hai yêu cầu HTTP cuối cùng được chuyển đến các máy chủ khác nhau này.


4
Bạn có thể đưa ra một ví dụ đầy đủ hơn về cách tạo bản sao repo chỉ với cam kết duy nhất này không? Tôi đã thử nhưng thất bại .. Cảm ơn!
Lars Bilke

1
Tôi muốn đẩy đến GitHub. Có lẽ họ không cho phép điều này.
Lars Bilke

2
@LarsBilke chúng ta đang nói về bản sao hoặc kéo ở đây, không phải đẩy. Và tôi khá chắc chắn rằng GitHub chưa có Git 2.5 ở phía máy chủ.
VonC

2
Bây giờ thậm chí còn tốt hơn, không có uploadpack.allowAnySHA1InWanthình phạt tính toán khả năng tiếp cận (và vectơ DoS).
R .. GitHub DỪNG GIÚP ICE

1
Cảm ơn! Tôi thấy buồn cười khi họ mô tả nó là "tin tưởng người dùng truy cập" thay vì "tin tưởng các tác giả repo không đẩy những thứ tào lao ngẫu nhiên mà họ không có ý định công khai".
R .. GitHub DỪNG GIÚP ICE

97

Bạn chỉ sao chép một lần, vì vậy nếu bạn đã có một bản sao của kho lưu trữ từ xa, kéo từ đó sẽ không tải xuống mọi thứ một lần nữa. Chỉ cần chỉ ra nhánh nào bạn muốn kéo hoặc tìm nạp các thay đổi và kiểm tra cam kết bạn muốn.

Tìm nạp từ kho lưu trữ mới rất rẻ về băng thông, vì nó sẽ chỉ tải xuống những thay đổi bạn không có. Hãy suy nghĩ về Git làm điều đúng đắn, với tải tối thiểu.

Git lưu trữ mọi thứ trong .gitthư mục. Một cam kết không thể được tìm nạp và lưu trữ trong sự cô lập, nó cần tất cả tổ tiên của nó. Chúng có liên quan với nhau .


Tuy nhiên, để giảm kích thước tải xuống, bạn có thể yêu cầu git chỉ tìm nạp các đối tượng liên quan đến một nhánh hoặc cam kết cụ thể:

git fetch origin refs/heads/branch:refs/remotes/origin/branch

Điều này sẽ chỉ tải xuống các cam kết có trong chi nhánh từ xa branch (và chỉ những cam kết mà bạn bỏ lỡ) và lưu trữ nó origin/branch. Sau đó bạn có thể hợp nhất hoặc thanh toán.

Bạn cũng có thể chỉ định một cam kết SHA1:

git fetch origin 96de5297df870:refs/remotes/origin/foo-commit

Điều này sẽ chỉ tải xuống cam kết của SHA-1 96de5297df870 được chỉ định (và tổ tiên của nó mà bạn bỏ lỡ) và lưu trữ dưới dạng nhánh từ xa (không tồn tại) origin/foo-commit.


3
Có vẻ như bạn đang nhầm lẫn về ý nghĩa của bản sao. Khi bạn tìm nạp các thay đổi từ một repo từ xa mà bạn không sao chép nó, bạn chỉ nhận được các cam kết trong lịch sử của mình. Sau đó, bạn chọn cam kết nào bạn muốn kiểm tra hoặc hợp nhất nó trong lịch sử của bạn
CharlesB

1
Nó vẫn tải rất nhiều dữ liệu (430mb) với git fetch. Các cam kết cần thiết chỉ là vài kbs. Không có lệnh đặc biệt để làm điều này thực sự? Và nếu tôi muốn xóa repo 'git fetched' thì sao? nó được lưu trữ ở đâu?
Varun Chitre

9
Điều này là khá lỗi thời bây giờ. Chúng tôi có cả khả năng thực hiện một bản sao nông , cũng như tìm nạp một cam kết duy nhất . Bản sao nông bây giờ được phép đẩy và tìm nạp bình thường, mà không cần phải biết toàn bộ lịch sử của dự án, do đó không còn đúng khi nói rằng một cam kết không thể tồn tại một mình mà không có tổ tiên. Những gì bạn nói về việc tìm nạp sau bản sao ban đầu là rất đúng, nhưng chúng tôi thậm chí còn có các tùy chọn thậm chí rẻ hơn.
Theodore Murdock

6
Lệnh cuối cùng (sử dụng cam kết SHA1) không hoạt động đối với tôi. Lệnh âm thầm thực hiện "một cái gì đó" trong một thời gian, và sau đó thoát ra mà không có thông báo hoặc tác dụng phụ rõ ràng.
HRJ

1
@HRJ Vâng, tôi cũng gặp phải điều này, trên Ubuntu 16.04 với Git 2.7.4-0ubuntu1.3. Tuy nhiên, khi sử dụng 2.16.2-0ppa1~ubuntu16.04.1từ PPA git-core, điều này hoạt động như bình thường. Âm thanh như một lỗi đã được sửa. Không thể tìm thấy một tài liệu tham khảo đến đó với một tìm kiếm nhanh. Nếu ai đó có thể đưa cho tôi một con trỏ về điều đó, tôi rất muốn nhận bản sửa lỗi này.
gertvdijk

62

Tôi đã kéo một repo git của tôi:

git pull --rebase <repo> <branch>

Cho phép git lấy tất cả mã cho chi nhánh và sau đó tôi đã thực hiện thiết lập lại cho cam kết mà tôi quan tâm.

git reset --hard <commit-hash>

Hi vọng điêu nay co ich.


1
Không có câu trả lời nào hiệu quả, dù vậy, câu trả lời này đã cứu mạng tôi! Cảm ơn nhiều!
michaeltintiuc

Việc thiết lập lại - đã làm việc cho tôi sau khi nhân bản! Cảm ơn.
Nick-ACNB

3
-1: Các lệnh "phá hoại" như git reset --hard, khi được chia sẻ trong các giải pháp tổng quát, có thể dẫn mọi người vào bẫy khi họ mất dữ liệu (hoặc trong trường hợp này: trong trạng thái lấy lại dữ liệu của họ là không cần thiết).
yaauie

54

Bạn chỉ có thể tìm nạp một cam kết của một repo từ xa với

git fetch <repo> <commit>

Ở đâu,

  • <repo>có thể là tên repo từ xa (ví dụ origin) hoặc thậm chí là URL repo từ xa (ví dụ https://git.foo.com/myrepo.git)
  • <commit> có thể là cam kết SHA1

ví dụ

git fetch https://git.foo.com/myrepo.git 0a071603d87e0b89738599c160583a19a6d95545

sau khi bạn lấy cam kết (và tổ tiên bị mất), bạn chỉ cần kiểm tra nó với

git checkout FETCH_HEAD

Lưu ý rằng điều này sẽ đưa bạn vào trạng thái "tách rời".


10
Khi tôi cố gắng fetchquay vòng cụ thể như bạn làm ở đó, git không thành công với mã lỗi 1 và không có đầu ra. Đây có phải là một cái gì đó đã từng làm việc trong các phiên bản trước? (Tôi là v2.0.2.)
Jack O'Connor

2
Chỉnh sửa: Nó hoạt động nếu tôi đã có cam kết cục bộ, giống như nếu tôi đã thực hiện đầy đủ fetch, mặc dù trong trường hợp đó tôi không chắc việc sử dụng là gì.
Jack O'Connor

2
Thật vậy, điều này dường như không còn hiệu quả với tôi nữa với git 2.0.2. :(
Lưu lượng

2
git checkout FETCH_HEADgiúp.
lzl124631x

1
Phương pháp này sẽ không hoạt động với tìm nạp nông (ví dụ --depth=1)!
kingmakerking

16

Bạn chỉ có thể tìm nạp repo từ xa bằng:

git fetch <repo>

Ở đâu,

  • <repo>có thể là tên repo từ xa (ví dụ origin) hoặc thậm chí là URL repo từ xa (ví dụ https://git.foo.com/myrepo.git)

ví dụ:

git fetch https://git.foo.com/myrepo.git 

sau khi bạn tìm nạp các repos, bạn có thể hợp nhất các xác nhận mà bạn muốn (vì câu hỏi là về lấy một cam kết, thay vào đó, bạn có thể sử dụng cherry-pick để chọn chỉ một cam kết):

git merge <commit>
  • <commit> có thể là cam kết SHA1

ví dụ:

git cherry-pick 0a071603d87e0b89738599c160583a19a6d95545

hoặc là

git merge 0a071603d87e0b89738599c160583a19a6d95545

nếu là cam kết mới nhất mà bạn muốn hợp nhất, bạn cũng có thể sử dụng biến FETCH_HEAD:

git cherry-pick (or merge) FETCH_HEAD

Điều này đòi hỏi phải thiết lập tài khoản Git trên máy. Nó không hoạt động dưới một tài khoản thử nghiệm. Bạn có một cái gì đó hoạt động dưới một tài khoản thử nghiệm?
ngày

ý bạn là gì ? bạn không thể làm git lấy?
Sérgio

Ummm vậy lệnh sẽ là git config set uploadpack.allowReachableSHA1InWant gì?
Alexander Mills

2

Điều này hoạt động tốt nhất:

git fetch origin specific_commit
git checkout -b temp FETCH_HEAD

tên "temp" bất cứ điều gì bạn muốn ... chi nhánh này có thể mồ côi


Rõ ràng KHÔNG với các phiên bản git cũ hơn như 1.8.x
sorin

1

Cuối cùng tôi tìm thấy một cách để sao chép cam kết cụ thể bằng git cherry-pick . Giả sử bạn không có bất kỳ kho lưu trữ nào tại địa phương và bạn đang thực hiện cam kết cụ thể từ xa,

1) tạo kho lưu trữ trống trong local và git init

2) git từ xa thêm nguồn gốc " url-of-repository "

3) git fetch origin [điều này sẽ không di chuyển các tệp của bạn đến không gian làm việc cục bộ của bạn trừ khi bạn hợp nhất]

4) git cherry-pick " Enter-long-commit-hash-that-you-need "

Xong. Bằng cách này, bạn sẽ chỉ có các tệp từ cam kết cụ thể đó trong địa phương của bạn.

Enter-long-commit-hash:

Bạn có thể lấy cái này bằng cách sử dụng -> git log --pretty = oneline



0

Nếu cam kết được yêu cầu nằm trong yêu cầu kéo của repo từ xa, bạn có thể lấy nó bằng ID của nó:

# Add the remote repo path, let's call it 'upstream':
git remote add upstream https://github.com/repo/project.git

# checkout the pull ID, for example ID '60':
git fetch upstream pull/60/head && git checkout FETCH_HEAD
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.