¿Cómo clonar el repositorio de git con una revisión / conjunto de cambios específico?

393

¿Cómo puedo clonar el repositorio de git con una revisión específica, algo como lo hago habitualmente en Mercurial:

hg clone -r 3 /path/to/repository
Juan
fuente
3
No es específico para conjuntos de cambios o revisiones, pero clonar lo último en una rama específica puede ser tan efectivo, es decir git clone -b 10.1 https://github.com/MariaDB/server.git --depth=1 mariadb-server-src
MrMesees
Posible duplicado de Descargar una etiqueta específica con Git
SlightlyCuban
¿Desea que el historial sea poco profundo, es decir, que solo contenga la revisión 3 en su ejemplo, o que también sean padres?
sschuberth
Si el repositorio en cuestión se está clonando desde dentro de otro repositorio y desea clonar ese repositorio interno en un sha específico, entonces los submódulos git hacen exactamente eso de forma automática.
J0hnG4lt

Respuestas:

203

ACTUALIZACIÓN 2 Dado que Git 2.5.0, la función que se describe a continuación se puede habilitar en el lado del servidor con la variable de configuración uploadpack.allowReachableSHA1InWant, aquí la solicitud de la función GitHub y el compromiso de GitHub habilitan esta función . Tenga en cuenta que algunos servidores Git activan esta opción de forma predeterminada, por ejemplo, Bitbucket Server la habilitó desde la versión 5.5+ . Consulte esta respuesta en Stackexchange para ver un ejemplo de cómo activar la opción de configuración.

ACTUALIZACIÓN 1 Para las versiones de Git, 1.7 < v < 2.5use git clone y git reset, como se describe en la respuesta de Vaibhav Bajpai

Si no desea obtener el repositorio completo, entonces probablemente no debería estar usando clone. Siempre puede usar fetch para elegir la rama que desea buscar. No soy un experto en hg, así que no conozco los detalles, -rpero en git puedes hacer algo como esto.

# 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
CB Bailey
fuente
32
No creo que git fetch origin <sha1>funcione; parece que necesita pasar una referencia con nombre, como una etiqueta o un nombre de rama. Ver kerneltrap.org/mailarchive/git/2009/1/13/4707444
artur
48
@artur: ¿No crees que funciona o lo has probado y no funciona?
CB Bailey
37
Con git 1.4, descubrí que podía usar el git fetch origin <SHA1>para cambiar a cualquier revisión que quisiera después de buscar el maestro desde el control remoto y realizar la reset --hardinstancia local de la rama. No pude obtener las revisiones individuales directamente. Con git 1.7, git fetch origin <SHA1>no funcionó, según lo informado por @artur; necesitas usar git checkout <SHA1>seguido de a reset --hard.
Joe McMahon
66
La obtención por SHA-1 solo funcionará con los protocolos http y rsync. Ver kerneltrap.org/mailarchive/git/2009/1/14/4716044/…
CharlesB
23
Esta respuesta está desactualizada. Esto no funciona con git 1.7 ni git 1.8, ni con https: // ni con el protocolo ssh. ("No se pudo encontrar la referencia remota df44398762393c67af487edeb0831ad9579df4aa" - no es una referencia, es una confirmación.)
Paŭlo Ebermann
839
$ git clone $URL
$ cd $PROJECT_NAME
$ git reset --hard $SHA1

Para volver de nuevo a la confirmación más reciente

$ git pull
Vaibhav Bajpai
fuente
13
Esto funciona solo si el commit está en la rama maestra, si no, va a estropear la referencia local. ¿Por qué git reset y no git checkout en primer lugar?
Joky
72
Esta no es una buena opción para repositorios grandes, ya que tira de todo.
Incógnito
1
Esta solución debería estar en la parte superior. A nadie le importa que "no sea óptimo", es lo que pidió el OP. Específicamente: "¿Cómo clono el repositorio de git con una revisión específica"?
Florian Segginger
20
@FlorianSegginger Si estoy buscando clonar una revisión específica, es probable que no quiera clonar todo, sino solo esa revisión. Para mí esa fue la pregunta que se hizo. Esta solución responde a una pregunta diferente: "¿Cómo veo una revisión específica en mi repositorio?". Obtener todo el repositorio es exactamente lo que mucha gente aquí quiere evitar.
Renato
1
No aborda la pregunta real en mi humilde opinión, ya que poder especificar una revisión durante el clon también me permite usar, lo --depthcual es muy importante para repositorios grandes. Esta solución requiere extraer todos los objetos y luego restablecerlos a una revisión anterior. Esto consume mucho tiempo y desperdicia el ancho de banda de la red.
void.pointer
54

Clonar un repositorio git, acertadamente, clona todo el repositorio: no hay una manera de seleccionar solo una revisión para clonar. Sin embargo, una vez que realice git clone, puede realizar una revisión específica haciendo checkout <rev>.


fuente
44
No quiero clonar solo una revisión. Solo quiero especificar el límite de clonación. En otras palabras, quiero clonar todo hasta la revisión especificada.
John
66
No puedes hacer eso. git cloneagarra todo el repositorio. Una vez que lo tenga, puede pagar una revisión específica.
44
Una cosa a tener en cuenta; Git es generalmente bastante eficiente para almacenar el historial, por lo que no es como si ahorraras grandes cantidades de espacio solo clonando la mitad de las revisiones.
Ámbar
No se trata de "ahorrar espacio", se trata solo de llegar a una revisión específica, como si un nuevo cambio introdujera un error, por lo que no quiero ese cambio más nuevo, estás diciendo que Git no puede hacer ¿esta? Eso no puede ser correcto: ¿por qué tener el control de la fuente si no puede volver a una versión anterior?
BrainSlugs83
1
"no hay una manera de seleccionar solo una revisión para clonar" - sí, la hay:git clone --single-branch ...
morxa
33

Para clonar solo una confirmación específica en una rama o etiqueta en particular, use:

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

Desafortunadamente, NAMEsolo puede ser el nombre de la sucursal o el nombre de la etiqueta (no comprometer SHA).

Omita la --depthbandera para descargar el historial completo y luego revise esa rama o etiqueta:

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

Esto funciona con la versión reciente de git (lo hice con la versión 2.18.0).

Peter Kovac
fuente
pero no en la versión anterior 2.17.1
RzR
44
Esto necesita más votos a favor. Esto es mucho mejor que otras respuestas obsoletas.
Étienne
32

Si quiere decir que quiere buscar todo desde el principio hasta un punto en particular, la respuesta de Charles Bailey es perfecta. Si desea hacer lo contrario y recuperar un subconjunto del historial desde la fecha actual, puede usar git clone --depth [N] donde N es el número de revoluciones del historial que desea. Sin embargo:

--profundidad

Cree un clon superficial con un historial truncado al número especificado de revisiones. Un repositorio poco profundo tiene una serie de limitaciones (no puede clonarlo ni extraerlo, ni empujarlo ni entrar en él), pero es adecuado si solo está interesado en la historia reciente de un gran proyecto con una larga historia y desea enviar arreglos como parches.

Walter Mundt
fuente
44
La versión más nueva de git tiene clones poco profundos mejorados, y puedes tirar y empujar desde ella.
orion78fr
26

Solo para resumir las cosas (git v. 1.7.2.1):

  1. haz un regular git clonedonde quieras el repositorio (pone todo a la fecha, lo sé, no lo que se quiere, estamos llegando allí)
  2. git checkout <sha1 rev> de la revolución que quieres
  3. git reset --hard
  4. git checkout -b master
phill
fuente
66
¿Qué hacen los pasos 3 y 4?
BrainSlugs83
El paso 4 no funcionó para mí, pero hasta el paso 3 funcionó - Gracias
Gene Bo
@ BrainSlugs83: el paso 4 crea una rama local llamada mastery cambia a ella.
LarsH
3
@phill: ¿Por qué git reset --hard? Los documentos para eso dicen "Restablece el índice y el árbol de trabajo. Cualquier cambio en los archivos rastreados en el árbol de trabajo desde <commitir> [que por defecto es HEAD, que ahora es <sha1 rev>] se descarta". Pero en este momento no hemos realizado ningún cambio desde la clonación, entonces, ¿cuál es el propósito? ¿Trunca la rama actual en <sha1 rev>?
LarsH
19

TL; DR: simplemente cree una etiqueta en el repositorio de origen contra la confirmación que desea clonar y use la etiqueta en el comando fetch. Puede eliminar la etiqueta del repositorio original más adelante para limpiar.

Bueno, es 2014 y parece que la respuesta aceptada de Charles Bailey de 2010 está bastante desactualizada ahora y la mayoría (¿todas?) De las otras respuestas involucran clonación, lo que muchas personas esperan evitar.

La siguiente solución logra lo que el OP y muchos otros buscan, que es una forma de crear una copia de un repositorio, incluido el historial, pero solo hasta cierto compromiso.

Estos son los comandos que utilicé con git versión 2.1.2 para clonar un repositorio local (es decir, un repositorio en otro directorio) hasta cierto punto:

# 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

¡Esperemos que esta solución siga funcionando durante algunos años más! :-)

JamesG
fuente
2
Esta es una idea buena de usted es el propietario de la cesión temporal, no está seguro de si se trabaja con repositorios públicos que no mantienen
Suhaib
18

Puedes usar simplemente git checkout <commit hash>

en esta secuencia

bash git clone [URLTORepository] git checkout [commithash]

commit hash se parece a esto "45ef55ac20ce2389c9180658fdba35f4a663d204"

M.Othman
fuente
como el anterior: ¿por qué pagar después de clonar? Una vez que clones, tienes toda la historia en el repositorio local. ¿Por qué esta respuesta tiene demasiados votos a favor?
Dmitry Perfilyev
2

El uso de 2 de las respuestas anteriores ( ¿Cómo clonar el repositorio de git con una revisión / conjunto de cambios específico? Y ¿Cómo clonar el repositorio de git con una revisión / conjunto de cambios específico? ) Me ayudó a llegar a un definitivo. Si desea clonar hasta un punto, ese punto debe ser una etiqueta / rama, no simplemente un SHA o el FETCH_HEAD se confunde. Siguiendo el conjunto git fetch, si usa una rama o nombre de etiqueta, obtiene una respuesta, si simplemente usa un SHA-1 no obtiene respuesta.
Esto es lo que hice: crear un clon de trabajo completo del repositorio completo, desde el origen real

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

Luego cree una sucursal local, en el punto que sea interesante

git checkout 2050c8829c67f04b0db81e6247bb589c950afb14
git checkout -b origin_point

Luego cree mi nuevo repositorio en blanco, con mi copia local como origen

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

En ese momento recibí esta respuesta. Lo noto porque si usa un SHA-1 en lugar de la rama anterior, no sucede nada, por lo que la respuesta significa que funcionó

/ var / www / html / ui-hacking $ git fetch local_copy origin_point
control remoto: recuento de objetos: 45493, hecho.
remoto: Comprimir objetos: 100% (15928/15928), hecho.
remoto: Total 45493 (delta 27508), reutilizado 45387 (delta 27463)
Recepción de objetos: 100% (45493/45493), 53.64 MiB | 50.59 MiB / s, hecho.
Resolviendo deltas: 100% (27508/27508), hecho.
Desde / var / www / html / ui
 * rama origin_point -> FETCH_HEAD
 * [nueva rama] origin_point -> origin / origin_point

Ahora en mi caso, necesitaba volver a poner eso en gitlab, como un nuevo repositorio, así que lo hice

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

Lo que significaba que podía reconstruir mi repositorio desde el punto de origen usando git --git-dir=../ui/.git format-patch -k -1 --stdout <sha1> | git am -3 -kCherry Pick de forma remota y luego usarlo git push originpara cargar todo de nuevo en su nuevo hogar.

Espero que ayude a alguien

sibaz
fuente
¿Puedes explicar a qué te refieres con "FETCH_HEAD se confunde"? ¿Y en qué se git fetch local_copy origin_pointdiferencia de JamesGs git fetch origin refs/tags/tmptag?
not2qubit
La git fetch local_copy origin_pointdejo en un estado con un vacío reduced-repode directorio, que contiene una única .git. Hay algo más que falta en estas instrucciones ...
not2qubit
2

Mi versión era una combinación de respuestas aceptadas y más votadas. Pero es un poco diferente, porque todos usan SHA1 pero nadie te dice cómo obtenerlo

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

ahora puedes ver todas las ramas y confirmaciones

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

Finalmente sabes SHA1 de commit deseado

git reset --hard <sha1>
vladkras
fuente
1

Utilizo este fragmento con GNU make para cerrar cualquier etiqueta de revisión, rama o hash

fue probado en git versión 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 $@




RzR
fuente
0

git clone https://github.com/ORGANIZATION/repository.git (clonar el repositorio)

cd repository (navigate to the repository)

git fetch origin 2600f4f928773d79164964137d514b85400b09b2

git checkout FETCH_HEAD

JeffDropsIT
fuente
2
¿Por qué buscar después de clonar? Una vez que clones, tienes toda la historia en el repositorio local. ¿Por qué esta respuesta tiene dos votos a favor?
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> 

no puede obtener una revisión sin historiales si no se configura uploadpack.allowReachableSHA1InWant=trueen el lado del servidor, mientras que puede crear una etiqueta y clonar la etiqueta especial en su lugar.

wongoo
fuente
-3

Es simple. Solo tiene que configurar el flujo ascendente para la rama actual

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

Eso es todo

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

gitusa la palabra originen lugar de popularmente conocidorevision

Lo siguiente es un fragmento del manual. $ git help clone

--origin <name>, -o <name>
    Instead of using the remote name origin to keep track of the upstream repository, use <name>.
hell_ical_vortex
fuente
44
No tengo idea de por qué te están rechazando aquí; esto era exactamente lo que esperaba ver para mi caso de uso: obtener una versión particular del kernel de Linux de una versión que no tenían el sentido común de etiquetar como lanzamiento (parece ser un problema con la gente de RPi), sin descargando toda la historia de varios gigabytes de Linux. Por cierto, funcionó de maravilla.
Fordi
1
--depth=1no se menciona en la respuesta, entonces, ¿por qué diría que esta respuesta funcionó si agrega más cosas que no se mencionan aquí? Estoy feliz de que te haya funcionado, pero esta respuesta es engañosa y no responde la pregunta, incluso en parte. De ahí los votos negativos.
Emil Styrke
55
@Fordi: No. Usar esta respuesta literalmente te da exactamente el mismo árbol que obtendrías de una vainilla git clone <url> <local_dir_name>, solo pruébalo por ti mismo. La única diferencia es que el control remoto (que se muestra usando git remote) se llamará una secuencia críptica sha1 en lugar del nombre "origen" que es habitual. En otras palabras, lo <sha1-of-the-commit>mencionado en esta respuesta no tiene ninguna relación con las revisiones que se obtienen del servidor o qué rama se extraerá.
Emil Styrke
66
@ Fordi: acabo de hacerlo git clone -o 896066ee1cf4d653057dac4e952f49c96ad16fa7 https://github.com/torvalds/linux.git linux --depth=1. Esto me da una revisión 8a28d674y no 896066ee como tú y esta respuesta afirman.
Emil Styrke
44
haciendo hincapié en que "origen" no tiene nada que ver con "revisión" y esta respuesta es completamente incorrecta.
Eevee