2012-10-11 155 views
9

Deseo recuperar todos versión anterior de un archivo específico en un repositorio de git.git - obteniendo TODA la versión anterior de un archivo/carpeta específico

Veo que es posible obtener una versión específica con el comando de finalización, pero las quiero todas. Y el comando git clone con la opción de profundidad no parece permitirme clonar la subcarpeta ("nombre de depósito no válido").

¿Sabes si es posible y cómo?

Gracias

Respuesta

9

OP quería recuperar todas las versiones de, pero las respuestas no respondían. Especialmente si el archivo tiene cientos de revisiones (todas las sugerencias son demasiado manuales).La única solución a medias fue propuesta por @Tobias en los comentarios, pero sugirió que bash loop generaría los archivos en orden aleatorio y generaría cientos de archivos vacíos cuando se utilizaran contra nuestros repositorios. Una de las razones fue que "rev-list --all --objects" mostraría diferentes objetos (árboles incluidos) pero inútiles para nuestro propósito.

Comencé con la solución de Tobias, agregué contadores, limpié un poco y terminé reinventando la rueda en forma del script bash que se muestra a continuación.

La secuencia de comandos sería:
- extraer todos versiones de archivos a/tmp/all_versions_exported
- tome 1 argumento - ruta relativa al archivo dentro repositorio git
- dar resultado nombres de archivo prefijo numérico (ordenable)
- mención inspeccionado nombre de archivo en archivos de resultados (para contar las manzanas, aparte de las naranjas :)
- Aviso fecha de comprometerse en el nombre del archivo resultado (véase el ejemplo de salida por debajo)
- no crear archivos de resultados vacíos

cat///bin/git_export_all_file_versions locales usr

#!/bin/bash 

# we'll write all git versions of the file to this folder: 
EXPORT_TO=/tmp/all_versions_exported 

# take relative path to the file to inspect 
GIT_PATH_TO_FILE=$1 

# ---------------- don't edit below this line -------------- 

USAGE="Please cd to the root of your git proj and specify path to file you with to inspect (example: $0 some/path/to/file)" 

# check if got argument 
if [ "${GIT_PATH_TO_FILE}" == "" ]; then 
    echo "error: no arguments given. ${USAGE}" >&2 
    exit 1 
fi 

# check if file exist 
if [ ! -f ${GIT_PATH_TO_FILE} ]; then 
    echo "error: File '${GIT_PATH_TO_FILE}' does not exist. ${USAGE}" >&2 
    exit 1 
fi 

# extract just a filename from given relative path (will be used in result file names) 
GIT_SHORT_FILENAME=$(basename $GIT_PATH_TO_FILE) 

# create folder to store all revisions of the file 
if [ ! -d ${EXPORT_TO} ]; then 
    echo "creating folder: ${EXPORT_TO}" 
    mkdir ${EXPORT_TO} 
fi 

## uncomment next line to clear export folder each time you run script 
#rm ${EXPORT_TO}/* 

# reset coutner 
COUNT=0 

# iterate all revisions 
git rev-list --all --objects -- ${GIT_PATH_TO_FILE} | \ 
    cut -d ' ' -f1 | \ 
while read h; do \ 
    COUNT=$((COUNT + 1)); \ 
    COUNT_PRETTY=$(printf "%04d" $COUNT); \ 
    COMMIT_DATE=`git show $h | head -3 | grep 'Date:' | awk '{print $4"-"$3"-"$6}'`; \ 
    if [ "${COMMIT_DATE}" != "" ]; then \ 
     git cat-file -p ${h}:${GIT_PATH_TO_FILE} > ${EXPORT_TO}/${COUNT_PRETTY}.${COMMIT_DATE}.${h}.${GIT_SHORT_FILENAME};\ 
    fi;\ 
done  

# return success code 
echo "result stored to ${EXPORT_TO}" 
exit 0 


Ejemplo de uso:

cd /home/myname/my-git-repo 

git_export_all_file_versions docs/howto/readme.txt 
    result stored to /tmp/all_versions_exported 

ls /tmp/all_versions_exported 
    0001.17-Oct-2016.ee0a1880ab815fd8f67bc4299780fc0b34f27b30.readme.txt 
    0002.3-Oct-2016.d305158b94bedabb758ff1bb5e1ad74ed7ccd2c3.readme.txt 
    0003.29-Sep-2016.7414a3de62529bfdd3cb1dd20ebc1a977793102f.readme.txt 
    0004.28-Sep-2016.604cc0a34ec689606f7d3b2b5bbced1eece7483d.readme.txt 
    0005.28-Sep-2016.198043c219c81d776c6d8a20e4f36bd6d8a57825.readme.txt 
    0006.9-Sep-2016.5aea5191d4b86aec416b031cb84c2b78603a8b0f.readme.txt 
    <and so on and on . . .> 

de edición: Si ve errores como este:

fatal: No es un nombre de objeto válido 3e93eba38b31b8b81905ceaa95eb47bba ed46494: readme.txt

significa que ha iniciado el script no desde la carpeta raíz de su proyecto git.

+0

La respuesta aceptada previamente (@sehe) no realizó directamente la recuperación de TODAS las versiones a la vez. Como mencioné en el comentario, utilicé los dos comandos para construir un programa java (no una solución general que pudiera cargarse como está) que lo hizo. Su solución es mejor, ya que da el resultado final de mi pasado programa de Java. – max152

+0

Este script funciona, pero hay algunos problemas y comportamientos posiblemente inesperados. Consulte [mi respuesta] (http://stackoverflow.com/a/43747334/1132502) para obtener detalles y un script actualizado. –

+0

@Nathan, increíble! me alegro de que lo haya encontrado útil +1 –

-2

Todas las versiones de un archivo ya están en el repositorio git git clone cuando él. Se puede crear ramas asociadas con la comprobación de un particular, se compromete:

git checkout -b branchname {commit#} 

Esto podría ser suficiente para una comparación manual rápido y sucio de cambios:

  • caja para ramas
  • copia a un buffer del editor

Esto podría estar bien, si solo tiene unas pocas versiones que preocuparse y no le molesta un poco de comandos manuales, aunque estén incorporados.

Para las soluciones con guiones, ya hay un par de otras soluciones que se proporcionaron en otras respuestas.

+0

¡Gracias! No lo sabía (la primera vez que uso git). Ahora puedo recuperar todas las versiones. – max152

4
git rev-list --all --objects -- path/to/file.txt 

listas que todas las manchas asociadas con la ruta de recompra

Para obtener una versión específica de un archivo

git cat-file -p commitid:path/to/file.txt 

(commitid puede ser cualquier cosa

  • ref simbólica (sucursal, nombres de etiquetas; remoto también)
  • a commit hash
  • una especificación de la revisión como la cabeza ~ 3, BRANCH1 @ {4} etc.
+0

Ok, ¡gracias! Me llevó tiempo entenderlo (es la primera vez que uso git). Ahora puedo hacer un script que reconstruya todas las versiones. – max152

+0

Buena expansión de los detalles de mi respuesta generalizada – gview

+2

@ user1739644 ¿Está tratando de convertir repositorios por casualidad? Eche un vistazo a 'git fast-export --all errata.html', que tiene un formato de archivo sencillo y bien documentado, respaldado por muchos otros VCS-es. – sehe

0

versiones antiguas de veces un archivo sólo están disponibles a través git reflog. Recientemente tuve una situación en la que tuve que investigar todas las confirmaciones, incluso aquellas que ya no formaban parte del registro debido a una sobreescritura accidental durante el reajuste interactivo.

Escribí este script de Ruby para mostrar todas las versiones anteriores del archivo para encontrar el compromiso huérfano. Fue fácil agilizar el resultado de esto para rastrear mi archivo perdido. Espero que ayude a alguien.

#!/usr/bin/env ruby 
path_to_file = "" 
`git reflog`.split("\n").each do |log| 
    puts commit = log.split(" ").first 
    puts `git show #{commit}:#{path_to_file}` 
    puts 
end 

Lo mismo podría hacerse con git log.

4

El script proporcionado por Dmitry realmente resuelve el problema, pero tenía algunos problemas que me llevaron a adaptarlo para que fuera más adecuado para mis necesidades. Específicamente:

  1. El uso de git show se rompió debido a mi configuración predeterminada de formato de fecha.
  2. Quería que los resultados se ordenaran por orden de fecha, no por orden de fecha inversa.
  3. Quería poder ejecutarlo en un archivo que se había eliminado del repositorio.
  4. No quería todas las revisiones en todas las ramas; Solo quería que las revisiones fueran accesibles desde HEAD.
  5. Quería que fuera un error si no estaba en un repositorio git.
  6. No quería tener que editar la secuencia de comandos para ajustar ciertas opciones.
  7. La forma en que funcionó fue ineficiente.
  8. No necesité la numeración en los nombres de archivo de salida. (Una fecha con el formato adecuado tiene el mismo propósito).)
  9. yo quería "caminos con espacios" seguros de manipulación

Se puede ver la versión más reciente de mis modificaciones in my github repo o aquí está la versión de este escrito:

#!/bin/sh 

# based on script provided by Dmitry Shevkoplyas at http://stackoverflow.com/questions/12850030/git-getting-all-previous-version-of-a-specific-file-folder 

set -e 

if ! git rev-parse --show-toplevel >/dev/null 2>&1 ; then 
    echo "Error: you must run this from within a git working directory" >&2 
    exit 1 
fi 

if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then 
    echo "Usage: $0 <relative path to file> [<output directory>]" >&2 
    exit 2 
fi 

FILE_PATH="$1" 

EXPORT_TO=/tmp/all_versions_exported 
if [ -n "$2" ]; then 
    EXPORT_TO="$2" 
fi 

FILE_NAME="$(basename "$FILE_PATH")" 

if [ ! -d "$EXPORT_TO" ]; then 
    echo "Creating directory '$EXPORT_TO'" 
    mkdir -p "$EXPORT_TO" 
fi 

echo "Writing files to '$EXPORT_TO'" 
git log --diff-filter=d --date-order --reverse --format="%ad %H" --date=iso-strict "$FILE_PATH" | grep -v '^commit' | \ 
    while read LINE; do \ 
     COMMIT_DATE=`echo $LINE | cut -d ' ' -f 1`; \ 
     COMMIT_SHA=`echo $LINE | cut -d ' ' -f 2`; \ 
     printf '.' ; \ 
     git cat-file -p "$COMMIT_SHA:$FILE_PATH" > "$EXPORT_TO/$COMMIT_DATE.$COMMIT_SHA.$FILE_NAME" ; \ 
    done 
echo 

exit 0 

Un ejemplo de la salida :

$ git_export_all_file_versions bin/git_export_all_file_versions /tmp/stackoverflow/demo 
Creating directory '/tmp/stackoverflow/demo' 
Writing files to '/tmp/stackoverflow/demo' 
... 

$ ls -1 /tmp/stackoverflow/demo/ 
2017-05-02T15:52:52-04:00.c72640ed968885c3cc86812a2e1aabfbc2bc3b2a.git_export_all_file_versions 
2017-05-02T16:58:56-04:00.bbbcff388d6f75572089964e3dc8d65a3bdf7817.git_export_all_file_versions 
2017-05-02T17:05:50-04:00.67cbdeab97cd62813cec58d8e16d7c386c7dae86.git_export_all_file_versions 
Cuestiones relacionadas