Làm cách nào để sao chép kho git với sửa đổi / thay đổi cụ thể?


393

Làm cách nào tôi có thể sao chép kho git với sửa đổi cụ thể, một cái gì đó giống như tôi thường làm trong Mercurial:

hg clone -r 3 /path/to/repository

3
Không cụ thể đối với các thay đổi hoặc sửa đổi, nhưng nhân bản mới nhất trong một chi nhánh cụ thể có thể có hiệu quả tức là git clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-src
MrMesees


Bạn có muốn lịch sử nông cạn, tức là chỉ chứa phiên bản 3 trong ví dụ của bạn, hoặc cũng là cha mẹ?
sschuberth

Nếu kho lưu trữ được đề cập đang được sao chép từ bên trong một kho lưu trữ khác và bạn muốn sao chép repo nội bộ đó tại một sha cụ thể, thì các mô đun con git thực hiện chính xác điều đó theo cách tự động.
J0hnG4lt

Câu trả lời:


202

CẬP NHẬT 2Git 2.5.0 , tính năng được mô tả bên dưới có thể được bật ở phía máy chủ với biến cấu hình uploadpack.allowReachableSHA1InWant, ở đây yêu cầu tính năng GitHubcam kết GitHub kích hoạt tính năng này . Lưu ý rằng một số máy chủ Git kích hoạt tùy chọn này theo mặc định, ví dụ: Máy chủ Bitbucket đã bật tùy chọn này kể từ phiên bản 5.5+ . Xem câu trả lời này trên Stackexchange để biết cách kích hoạt tùy chọn cấu hình.

CẬP NHẬT 1 Đối với các phiên bản Git, 1.7 < v < 2.5sử dụng git clone và git reset, như được mô tả trong câu trả lời của Vaibhav Bajpai

Nếu bạn không muốn tìm nạp kho đầy đủ thì có lẽ bạn không nên sử dụng clone. Bạn luôn có thể chỉ sử dụng tìm nạp để chọn nhánh mà bạn muốn tìm nạp. Tôi không phải là một chuyên gia hg vì vậy tôi không biết chi tiết về -rnhưng trong git bạn có thể làm một cái gì đó như thế này.

# make a new blank repository in the current directory
git init

# add a remote
git remote add origin url://to/source/repository

# fetch a commit (or branch or tag) of interest
# Note: the full history up to this commit will be retrieved unless 
#       you limit it with '--depth=...' or '--shallow-since=...'
git fetch origin <sha1-of-commit-of-interest>

# reset this repository's master branch to the commit of interest
git reset --hard FETCH_HEAD

32
Tôi không nghĩ rằng git fetch origin <sha1>công việc; có vẻ như bạn cần phải vượt qua một tham chiếu có tên như thẻ hoặc tên chi nhánh. Xem kerneltrap.org/mailarchive/git/2009/1/13/4707444
artur

48
@artur: Bạn không nghĩ rằng nó hoạt động, hoặc bạn đã thử nó và nó không hoạt động?
CB Bailey

37
Với git 1.4, tôi thấy rằng tôi có thể sử dụng git fetch origin <SHA1>để chuyển sang bất kỳ sửa đổi nào tôi muốn sau khi tôi lấy chủ từ điều khiển từ xa và thực hiện reset --hardđể khởi tạo chi nhánh thực tế tại địa phương. Tôi đã không thể lấy các bản sửa đổi trực tiếp. Với git 1.7, git fetch origin <SHA1>không hoạt động, như báo cáo của @artur; bạn cần sử dụng git checkout <SHA1>theo sau a reset --hard.
Joe McMahon

6
Tìm nạp bởi SHA-1 sẽ chỉ hoạt động với các giao thức http và rsync. Xem kerneltrap.org/mailarchive/git/2009/1/14/4716044/ Kẻ
CharlesB

23
Câu trả lời này đã lỗi thời. Điều này không hoạt động với git 1.7 hay git 1.8, với giao thức https: // hay ssh. ( "Không thể tìm ref df44398762393c67af487edeb0831ad9579df4aa từ xa" - nó không phải là một ref, nó là một cam kết.)
Paulo Ebermann

839
$ git clone $URL
$ cd $PROJECT_NAME
$ git reset --hard $SHA1

Để một lần nữa quay trở lại cam kết gần đây nhất

$ git pull

13
Điều này chỉ hoạt động nếu cam kết nằm trong nhánh chính, nếu không nó sẽ gây rối cho tham chiếu cục bộ. Tại sao git thiết lập lại và không kiểm tra git ở nơi đầu tiên?
Joky

72
Đây không phải là một lựa chọn tốt cho các repos lớn, vì nó kéo mọi thứ.
Ẩn danh

1
Giải pháp này nên được đặt lên hàng đầu. Không ai quan tâm rằng nó "không tối ưu", đó là những gì OP yêu cầu. Cụ thể: "làm cách nào để sao chép kho git với sửa đổi cụ thể"?
Florian Segginger 18/03/2016

20
@FlorianSegginger Nếu tôi muốn sao chép một bản sửa đổi cụ thể thì có lẽ tôi không muốn sao chép mọi thứ, mà chỉ là bản sửa đổi đó. Đối với tôi đó là câu hỏi. Giải pháp này trả lời một câu hỏi khác: "Làm cách nào để tôi xem bản sửa đổi cụ thể trong repo của tôi?". Lấy toàn bộ repo là chính xác những gì nhiều người ở đây muốn tránh.
Renato

1
Không giải quyết câu hỏi thực tế IMHO, vì có thể chỉ định sửa đổi trong khi sao chép cũng cho phép tôi sử dụng --depth, điều này rất quan trọng đối với các repos lớn. Giải pháp này yêu cầu kéo tất cả các đối tượng, và sau đó đặt lại để sửa đổi trước đó. Điều này rất tốn thời gian và lãng phí băng thông mạng.
void.pulum

54

Nhân bản một kho lưu trữ git, thông minh, nhân bản toàn bộ kho lưu trữ: không có cách nào để chỉ chọn một bản sửa đổi để sao chép. Tuy nhiên, một khi bạn thực hiện git clone, bạn có thể kiểm tra một bản sửa đổi cụ thể bằng cách thực hiện checkout <rev>.


4
Tôi không muốn chỉ sao chép một bản sửa đổi. Tôi chỉ muốn chỉ định giới hạn của nhân bản. Nói cách khác, tôi muốn sao chép mọi thứ theo bản sửa đổi được chỉ định.
Giăng

6
Bạn không thể làm điều đó. git clonelấy toàn bộ kho lưu trữ. Khi bạn đã có nó, sau đó bạn có thể kiểm tra một phiên bản cụ thể.

4
Một điều cần lưu ý; Git nói chung khá hiệu quả trong việc lưu trữ lịch sử, vì vậy không phải là bạn sẽ tiết kiệm được một lượng lớn không gian bằng cách chỉ nhân bản một nửa các phiên bản.
Amber

Đó không phải là về "tiết kiệm không gian" - đó là về việc chỉ sửa đổi một bản sửa đổi cụ thể - như nếu một thay đổi mới gây ra lỗi và vì vậy tôi không muốn thay đổi mới nhất đó - bạn đang nói Git không thể làm điều này? Điều đó không thể đúng - tại sao lại có quyền kiểm soát nguồn nếu bạn không thể quay lại phiên bản cũ hơn?
BrainSlugs83

1
"không có cách nào để chỉ chọn một bản sửa đổi để sao chép" - vâng, có:git clone --single-branch ...
morxa

33

Để sao chép chỉ một cam kết cụ thể duy nhất trên một chi nhánh hoặc thẻ cụ thể, hãy sử dụng:

git clone --depth=1 --branch NAME https://github.com/your/repo.git

Thật không may, NAMEchỉ có thể là tên chi nhánh hoặc tên thẻ (không cam kết SHA).

Bỏ --depthcờ để tải xuống toàn bộ lịch sử và sau đó kiểm tra chi nhánh hoặc thẻ đó:

git clone --branch NAME https://github.com/your/repo.git

Điều này hoạt động với phiên bản gần đây của git (tôi đã làm nó với phiên bản 2.18.0).


nhưng không phải trên phiên bản cũ hơn 2.17.1
RzR

4
Điều này cần nhiều upvote. Điều này tốt hơn nhiều so với các câu trả lời lỗi thời khác.
Étienne

32

Nếu bạn có nghĩa là bạn muốn tìm nạp mọi thứ từ đầu đến một điểm cụ thể, câu trả lời của Charles Bailey là hoàn hảo. Nếu bạn muốn làm ngược lại và truy xuất một tập hợp con của lịch sử trở lại từ ngày hiện tại, bạn có thể sử dụng git clone --depth [N] trong đó N là số vòng quay của lịch sử bạn muốn. Tuy nhiên:

--chiều sâu

Tạo một bản sao nông với một lịch sử được cắt ngắn theo số lần sửa đổi được chỉ định. Kho lưu trữ nông có một số hạn chế (bạn không thể sao chép hoặc tìm nạp từ nó, cũng không được đẩy từ đó vào), nhưng là đủ nếu bạn chỉ quan tâm đến lịch sử gần đây của một dự án lớn có lịch sử lâu dài và muốn gửi các bản sửa lỗi như các bản vá.


4
Phiên bản mới hơn của git đã cải thiện các bản sao nông, và bạn có thể kéo và đẩy từ nó.
orion78fr

26

Chỉ cần tổng hợp mọi thứ (git v. 1.7.2.1):

  1. làm thường xuyên git clonenơi bạn muốn repo (mọi thứ đều được cập nhật - tôi biết, không phải những gì đang muốn, chúng tôi đang đến đó)
  2. git checkout <sha1 rev> của Rev bạn muốn
  3. git reset --hard
  4. git checkout -b master

6
bước 3 và 4 làm gì?
BrainSlugs83

Bước 4 không hiệu quả với tôi, nhưng đến bước 3 đã thực hiện thủ thuật - Cảm ơn
Gene Bo

@ BrainSlugs83: Bước 4 tạo một nhánh cục bộ được gọi mastervà chuyển sang nó.
LarsH

3
@phill: Tại sao git reset --hard? Các tài liệu cho biết "Đặt lại chỉ mục và cây làm việc. Mọi thay đổi đối với các tệp được theo dõi trong cây làm việc kể từ <commit> [mặc định là CHÍNH, hiện tại <sha1 rev>] đều bị loại bỏ." Nhưng tại thời điểm này, chúng tôi chưa thực hiện bất kỳ thay đổi nào kể từ khi nhân bản, vậy mục đích là gì? Nó cắt ngắn chi nhánh hiện tại <sha1 rev>?
LarsH

19

TL; DR - Chỉ cần tạo một thẻ trong kho lưu trữ nguồn dựa trên cam kết bạn muốn sao chép và sử dụng thẻ trong lệnh tìm nạp. Bạn có thể xóa thẻ từ repo ban đầu sau để dọn sạch.

Chà, năm 2014 và có vẻ như câu trả lời được chấp nhận của Charles Bailey từ năm 2010 là rất tốt và thực sự lỗi thời bởi bây giờ và hầu hết (tất cả?) Các câu trả lời khác liên quan đến nhân bản, điều mà nhiều người đang hy vọng tránh.

Giải pháp sau đây đạt được những gì OP và nhiều người khác đang tìm kiếm, đó là một cách để tạo một bản sao của một kho lưu trữ, bao gồm cả lịch sử, nhưng chỉ theo một cam kết nhất định.

Dưới đây là các lệnh tôi đã sử dụng với phiên bản git 2.1.2 để sao chép một repo cục bộ (tức là một kho lưu trữ trong thư mục khác) cho đến một điểm nhất định:

# in the source repository, create a tag against the commit you want to check out
git tag -m "Temporary tag" tmptag <sha1>

# create a new directory and change into that directory
cd somewhere_else;mkdir newdir;cd newdir

# ...and create a new repository
git init

# add the source repository as a remote (this can be a URL or a directory)
git remote add origin /path/to/original/repo

# fetch the tag, which will include the entire repo and history up to that point
git fetch origin refs/tags/tmptag

# reset the head of the repository
git reset --hard FETCH_HEAD

# you can now change back to the original repository and remove the temporary tag
cd original_repo
git tag -d tmptag

Hy vọng giải pháp này tiếp tục hoạt động trong một vài năm nữa! :-)


2
Đây là một ý tưởng tốt về bạn là chủ sở hữu của repo, không chắc nó có hoạt động với các repos công cộng mà bạn không duy trì
Suhaib

18

Bạn có thể sử dụng đơn giản git checkout <commit hash>

trong chuỗi này

bash git clone [URLTORepository] git checkout [commithash]

cam kết băm trông như thế này "45ef55ac20ce2389c9180658fdba35f4a663d204"


như trước đây - tại sao kiểm tra sau khi bạn nhân bản. Khi bạn nhân bản, bạn có toàn bộ lịch sử trong repo địa phương. Tại sao câu trả lời này có quá nhiều upvote?
Dmitry Perfilyev

2

Sử dụng 2 trong số các câu trả lời trên ( Cách sao chép kho lưu trữ git với sửa đổi / thay đổi cụ thể?Cách sao chép kho lưu trữ git với sửa đổi / thay đổi cụ thể? ) Giúp tôi đưa ra một định nghĩa cụ thể. Nếu bạn muốn sao chép đến một điểm, thì điểm đó phải là thẻ / nhánh không chỉ đơn giản là SHA hoặc FETCH_HEAD bị nhầm lẫn. Theo bộ getch fetch, nếu bạn sử dụng tên nhánh hoặc thẻ, bạn sẽ nhận được phản hồi, nếu bạn chỉ cần sử dụng SHA-1, bạn sẽ không nhận được phản hồi.
Đây là những gì tôi đã làm: - tạo một bản sao hoạt động đầy đủ của repo đầy đủ, từ nguồn gốc thực tế

cd <path to create repo>
git clone git@<our gitlab server>:ui-developers/ui.git 

Sau đó, tạo một chi nhánh địa phương, tại điểm đó thật thú vị

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

Sau đó tạo repo trống mới của tôi, với bản sao cục bộ của tôi là nguồn gốc của nó

cd <path to create repo>
mkdir reduced-repo
cd reduced-repo
git init
git remote add local_copy <path to create repo>/ui
git fetch local_copy origin_point

Tại thời điểm đó tôi đã nhận được phản hồi này. Tôi lưu ý điều đó bởi vì nếu bạn sử dụng SHA-1 thay cho nhánh trên, không có gì xảy ra, vì vậy phản hồi, có nghĩa là nó hoạt động

/ var / www / html / ui-hack $ git tìm nạp local_copy origin_point
từ xa: Đếm các đối tượng: 45493, xong.
từ xa: Nén các đối tượng: 100% (15928/15928), đã hoàn tất.
từ xa: Tổng 45493 (delta 27508), tái sử dụng 45387 (delta 27463)
Đối tượng nhận: 100% (45493/45493), 53,64 MiB | 50,59 MiB / s, xong.
Giải quyết deltas: 100% (27508/27508), đã hoàn tất.
Từ / var / www / html / ui
 * nhánh origin_point -> FETCH_HEAD
 * [chi nhánh mới] origin_point -> origin / origin_point

Bây giờ trong trường hợp của tôi, sau đó tôi cần phải đưa nó trở lại gitlab, như một repo mới vì vậy tôi đã làm

git remote add origin git@<our gitlab server>:ui-developers/new-ui.git

Điều đó có nghĩa là tôi có thể xây dựng lại repo của mình từ origin_point bằng cách sử dụng git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -kcherry cherry từ xa sau đó sử dụng git push originđể tải toàn bộ lô trở lại ngôi nhà mới của nó.

Mong rằng sẽ giúp được ai đó


Bạn có thể giải thích ý của bạn với "FETCH_HEAD bị nhầm lẫn" không? Và bạn git fetch local_copy origin_pointkhác với JamesGs git fetch origin refs/tags/tmptagnhư thế nào?
not2qubit

Việc git fetch local_copy origin_pointđể bạn trong một trạng thái với một reduced-repothư mục trống , chỉ chứa một .git. Có một cái gì đó còn thiếu cho các hướng dẫn này ...
not2qubit

2

Phiên bản của tôi là sự kết hợp của các câu trả lời được chấp nhận và được đánh giá cao nhất. Nhưng nó hơi khác một chút, vì mọi người đều sử dụng SHA1 nhưng không ai nói cho bạn biết làm thế nào để có được nó

$ git init
$ git remote add <remote_url>
$ git fetch --all

bây giờ bạn có thể thấy tất cả các chi nhánh và cam kết

$ git branch -a
$ git log remotes/origin/master <-- or any other branch

Cuối cùng, bạn biết SHA1 của cam kết mong muốn

git reset --hard <sha1>

1

Tôi sử dụng đoạn mã này với GNU make để đóng bất kỳ thẻ sửa đổi, nhánh hoặc hàm băm nào

nó đã được thử nghiệm trên phiên bản git 2.17.1

${dir}:
    mkdir -p ${@D}
    git clone --recursive --depth 1 --branch ${revison} ${url} ${@} \
 || git clone --recursive --branch ${revison} ${url} ${@} \
 || git clone ${url} ${@}
    cd ${@} && git reset --hard ${revison}
    ls $@





0

git clone https://github.com/ORGANIZATION/repository.git (sao chép kho lưu trữ)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD


2
Tại sao lấy sau khi bạn nhân bản. Khi bạn nhân bản, bạn có toàn bộ lịch sử trong repo địa phương. Tại sao câu trả lời này có hai upvote?
madhairsilence

0
# clone special tag/branch without history
git clone  --branch=<tag/branch> --depth=1 <repository>


# clone special revision with minimal histories
git clone --branch <branch> <repository> --shallow-since=yyyy-MM-ddTHH:mm:ss  # get the commit time
cd <dir>
git reset --hard <revision> 

bạn không thể nhận bản sửa đổi mà không có lịch sử nếu không được đặt uploadpack.allowReachableSHA1InWant=trueở phía máy chủ, trong khi bạn có thể tạo thẻ cho nó và sao chép thẻ đặc biệt thay thế.


-3

Nó đơn giản. Bạn chỉ cần đặt ngược dòng cho nhánh hiện tại

$ git clone repo
$ git checkout -b newbranch
$ git branch --set-upstream-to=origin/branch newbranch
$ git pull

Đó là tất cả


-4
git clone -o <sha1-of-the-commit> <repository-url> <local-dir-name>

git sử dụng từ origin thay cho phổ biến được biết đếnrevision

Sau đây là một đoạn trích từ hướng dẫn $ git help clone

--origin <name>, -o <name>
    Instead of using the remote name origin to keep track of the upstream repository, use <name>.

4
Không biết tại sao bạn lại bị hạ thấp ở đây; đây chính xác là những gì tôi đã hy vọng nhìn thấy trong trường hợp sử dụng của mình: Nhận một phiên bản hạt nhân Linux cụ thể từ một phiên bản mà họ không có ý thức tốt để gắn thẻ như một bản phát hành (dường như là một vấn đề với người RPi), mà không có tải về toàn bộ lịch sử nhiều gigabyte của Linux. Ngẫu nhiên, nó đã làm việc một điều trị.
Fordi

1
--depth=1không được đề cập trong câu trả lời, vậy tại sao bạn lại nói câu trả lời này có hiệu quả nếu bạn thêm nhiều thứ không được đề cập ở đây? Tôi rất vui vì nó đã giúp ích cho bạn, nhưng câu trả lời này là sai lệch và không trả lời câu hỏi ngay cả một phần. Do đó các downvote.
Emil Styrke

5
@Fordi: Không. Sử dụng câu trả lời này nguyên văn giúp bạn có được chính xác cùng một cây như bạn nhận được từ một vani git clone <url> <local_dir_name>, chỉ cần tự mình thử nó. Sự khác biệt duy nhất là điều khiển từ xa (hiển thị bằng cách sử dụng git remote) sẽ được gọi là một chuỗi sha1 khó hiểu thay vì tên "origin" là thông lệ. Nói cách khác, <sha1-of-the-commit>câu trả lời được đề cập trong câu trả lời này không có liên quan gì đến việc sửa đổi được lấy từ máy chủ hoặc chi nhánh nào sẽ được kiểm tra.
Emil Styrke

6
@Fordi: Tôi vừa làm git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1. Điều này cho tôi sửa đổi 8a28d674không 896066ee như bạn và câu trả lời này yêu cầu.
Emil Styrke

4
nhấn mạnh rằng "nguồn gốc" không liên quan gì đến "sửa đổi" và câu trả lời này là hoàn toàn sai.
Eevee
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.