Git
Chapters ▾ 2nd Edition

9.2 Git y Otros Sistemas - Migración a Git

Migración a Git

Si tiene una base de código existente en otro VCS pero ha decidido comenzar a usar Git, debe migrar su proyecto de una forma u otra. Esta sección revisa algunos importadores para sistemas comunes y luego demuestra cómo desarrollar su propio importador personalizado. Aprenderá a importar datos de varios de los sistemas SCM profesionales más grandes, ya que conforman la mayoría de los usuarios que están cambiando, y porque las herramientas de alta calidad para ellos son fáciles de conseguir.

Subversión

Si lee la sección anterior sobre el uso de git svn, usted puede usar fácilmente esas instrucciones para clonar un repositorio; luego, deje de usar el servidor de Subversión, presione en un nuevo servidor de Git y comience a usarlo. Si desea ver el historial, puede lograrlo tan rápido como pueda extraer los datos del servidor de Subversión (lo que puede llevar un tiempo).

Sin embargo, la importación no es perfecta; y porque tomará tanto tiempo, también puedes hacerlo bien. El primer problema es la información del autor. En Subversión, cada persona comprometida tiene un usuario en el sistema que está registrado en la información de confirmación. Los ejemplos en la sección anterior muestran schacon en algunos lugares, como la salida de culpa y el registro de git svn. Si desea asignar esto a mejores datos de autor de Git, necesita una asignación de los usuarios de Subversión a los autores de Git. Cree un archivo llamado users.txt que tenga esta asignación en un formato como este:

schacon = Scott Chacon <schacon@geemail.com>
selse = Someo Nelse <selse@geemail.com>

Para obtener una lista de los nombres de autor que utilizan SVN, puede ejecutar esto:

$ svn log --xml | grep author | sort -u | \
  perl -pe 's/.*>(.*?)<.*/$1 = /'

Eso genera la salida del registro en formato XML, luego mantiene solo las líneas con la información del autor, descarta los duplicados y elimina las etiquetas XML. (Obviamente, esto solo funciona en una máquina con grep, sort y perl instalados). Luego, redirija esa salida a su archivo users.txt para que pueda agregar los datos de usuario equivalentes de Git al lado de cada entrada.

Puede proporcionar este archivo a git svn para ayudarlo a mapear los datos del autor con mayor precisión. También puede indicarle a git svn que no incluya los metadatos que normalmente importa Subversión, pasando --no-metadata al comando clone o init. Esto hace que su comando de importación se vea así:

$ git svn clone http://my-project.googlecode.com/svn/ \
      --authors-file=users.txt --no-metadata -s my_project

Ahora debería tener una importación de Subversión más agradable en su directorio my_project. En lugar de commits que se ven así

commit 37efa680e8473b615de980fa935944215428a35a
Author: schacon <schacon@4c93b258-373f-11de-be05-5f7a86268029>
Date:   Sun May 3 00:12:22 2009 +0000

    fixed install - go to trunk

    git-svn-id: https://my-project.googlecode.com/svn/trunk@94 4c93b258-373f-11de-
    be05-5f7a86268029

se ven así:

commit 03a8785f44c8ea5cdb0e8834b7c8e6c469be2ff2
Author: Scott Chacon <schacon@geemail.com>
Date:   Sun May 3 00:12:22 2009 +0000

    fixed install - go to trunk

No solo el campo Autor se ve mucho mejor, sino que el git-svn-id ya no está allí.

También debería hacer un poco de limpieza posterior a la importación. Por un lado, debe limpiar las referencias raras que git svn configuró. Primero moverá las etiquetas para que sean etiquetas reales en lugar de ramas remotas extrañas, y luego moverá el resto de las ramas para que sean locales.

Para mover las etiquetas para que sean etiquetas Git correctas, ejecuta

$ cp -Rf .git/refs/remotes/origin/tags/* .git/refs/tags/
$ rm -Rf .git/refs/remotes/origin/tags

Esto toma las referencias que eran ramas remotas que comenzaron con controles remotos / origen / etiquetas / y las convierte en etiquetas reales (ligeras).

A continuación, mueva el resto de las referencias en refs / remotes para que sean ramas locales:

$ cp -Rf .git/refs/remotes/* .git/refs/heads/
$ rm -Rf .git/refs/remotes

Ahora todas las ramas antiguas son ramas reales de Git y todas las etiquetas antiguas son etiquetas Git reales. Lo último que debe hacer es agregar su nuevo servidor Git como un control remoto y pulsarlo. Aquí hay un ejemplo de cómo agregar su servidor como un control remoto:

$ git remote add origin git@my-git-server:myrepository.git

Como quiere que todas sus ramas y etiquetas suban, ahora puede ejecutar esto:

$ git push origin --all

Todas sus ramas y etiquetas deben estar en su nuevo servidor Git en una importación agradable y limpia..

Mercurial

Since Mercurial and Git have fairly similar models for representing versions, and since Git is a bit more flexible, converting a repository from Mercurial to Git is fairly straightforward, using a tool called "hg-fast-export", which you’ll need a copy of:

$ git clone http://repo.or.cz/r/fast-export.git /tmp/fast-export

The first step in the conversion is to get a full clone of the Mercurial repository you want to convert:

$ hg clone <remote repo URL> /tmp/hg-repo

The next step is to create an author mapping file. Mercurial is a bit more forgiving than Git for what it will put in the author field for changesets, so this is a good time to clean house. Generating this is a one-line command in a bash shell:

$ cd /tmp/hg-repo
$ hg log | grep user: | sort | uniq | sed 's/user: *//' > ../authors

This will take a few seconds, depending on how long your project’s history is, and afterwards the /tmp/authors file will look something like this:

bob
bob@localhost
bob <bob@company.com>
bob jones <bob <AT> company <DOT> com>
Bob Jones <bob@company.com>
Joe Smith <joe@company.com>

In this example, the same person (Bob) has created changesets under four different names, one of which actually looks correct, and one of which would be completely invalid for a Git commit. Hg-fast-export lets us fix this by adding ={new name and email address} at the end of every line we want to change, and removing the lines for any usernames that we want to leave alone. If all the usernames look fine, we won’t need this file at all. In this example, we want our file to look like this:

bob=Bob Jones <bob@company.com>
bob@localhost=Bob Jones <bob@company.com>
bob jones <bob <AT> company <DOT> com>=Bob Jones <bob@company.com>
bob <bob@company.com>=Bob Jones <bob@company.com>

The next step is to create our new Git repository, and run the export script:

$ git init /tmp/converted
$ cd /tmp/converted
$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors

The -r flag tells hg-fast-export where to find the Mercurial repository we want to convert, and the -A flag tells it where to find the author-mapping file. The script parses Mercurial changesets and converts them into a script for Git’s "fast-import" feature (which we’ll discuss in detail a bit later on). This takes a bit (though it’s much faster than it would be over the network), and the output is fairly verbose:

$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors
Loaded 4 authors
master: Exporting full revision 1/22208 with 13/0/0 added/changed/removed files
master: Exporting simple delta revision 2/22208 with 1/1/0 added/changed/removed files
master: Exporting simple delta revision 3/22208 with 0/1/0 added/changed/removed files
[…]
master: Exporting simple delta revision 22206/22208 with 0/4/0 added/changed/removed files
master: Exporting simple delta revision 22207/22208 with 0/2/0 added/changed/removed files
master: Exporting thorough delta revision 22208/22208 with 3/213/0 added/changed/removed files
Exporting tag [0.4c] at [hg r9] [git :10]
Exporting tag [0.4d] at [hg r16] [git :17]
[…]
Exporting tag [3.1-rc] at [hg r21926] [git :21927]
Exporting tag [3.1] at [hg r21973] [git :21974]
Issued 22315 commands
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects:     120000
Total objects:       115032 (    208171 duplicates                  )
      blobs  :        40504 (    205320 duplicates      26117 deltas of      39602 attempts)
      trees  :        52320 (      2851 duplicates      47467 deltas of      47599 attempts)
      commits:        22208 (         0 duplicates          0 deltas of          0 attempts)
      tags   :            0 (         0 duplicates          0 deltas of          0 attempts)
Total branches:         109 (         2 loads     )
      marks:        1048576 (     22208 unique    )
      atoms:           1952
Memory total:          7860 KiB
       pools:          2235 KiB
     objects:          5625 KiB
---------------------------------------------------------------------
pack_report: getpagesize()            =       4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit      = 8589934592
pack_report: pack_used_ctr            =      90430
pack_report: pack_mmap_calls          =      46771
pack_report: pack_open_windows        =          1 /          1
pack_report: pack_mapped              =  340852700 /  340852700
---------------------------------------------------------------------

$ git shortlog -sn
   369  Bob Jones
   365  Joe Smith

That’s pretty much all there is to it. All of the Mercurial tags have been converted to Git tags, and Mercurial branches and bookmarks have been converted to Git branches. Now you’re ready to push the repository up to its new server-side home:

$ git remote add origin git@my-git-server:myrepository.git
$ git push origin --all

Perforce

El siguiente sistema que verá importando es Perforce Como mencionamos anteriormente, hay dos formas de que Git y Perforce hablen entre sí: git-p4 y Perforce Git Fusion.

Perforce Git Fusion

Git Fusion hace que este proceso sea bastante sencillo. Simplemente elija la configuración de su proyecto, las asignaciones de usuario y las ramas con un archivo de configuración (como se explica en << _ p4_git_fusion >>) y clone el repositorio. Git Fusion te deja con lo que parece ser un repositorio nativo de Git, que luego está listo para enviar a un host nativo de Git si lo deseas. Incluso puede usar Perforce como su host Git si gusta.

Git-p4

Git-p4 también puede actuar como una herramienta de importación. Como ejemplo, importaremos el proyecto Jam desde Perforce Public Depot. Para configurar su cliente, debe exportar la variable de entorno P4PORT para que se dirija al depósito de Perforce:

$ export P4PORT=public.perforce.com:1666
Note

Para poder seguir, necesitarás un depósito de Perforce para conectarte. Utilizaremos el depósito público en public.perforce.com para ver nuestros ejemplos, pero puede usar cualquier depósito al que tenga acceso.

Ejecute el comando git p4 clone para importar el proyecto Jam desde el servidor Perforce, proporcionando la ruta de depósito y proyecto y la ruta en la que desea importar el proyecto:

$ git-p4 clone //guest/perforce_software/jam@all p4import
Importación desde //guest/perforce_software/jam@all into p4import
Inicializó el repositorio vacío de Git en /private/tmp/p4import/.git/
Destino de importación: refs/remotes/p4/master
Importando revisión 9957 (100%)

Este proyecto en particular tiene solo una rama, pero esta configurado con vistas de ramificaciones (o simplemente un conjunto de directorios), y puede usar el indicador --detect-branches en` git p4 clone` para importar todas las ramas del proyecto. Ver << _ git_p4_branches >> para un poco más de detalle sobre esto.

En este punto, casi has terminado. Si va al directorio p4import y ejecuta` git log`, puede ver su trabajo importado:

$ git log -2
commit e5da1c909e5db3036475419f6379f2c73710c4e6
Autor: giles <giles@giles@perforce.com>
Información:   Wed Feb 8 03:13:27 2012 -0800

   Corrección a línea 355; change </UL> to </OL>.

    [git-p4: depot-paths = "//public/jam/src/": change = 8068]

commit aa21359a0a135dda85c50a7f7cf249e4f7b8fd98
Autor: kwirth <kwirth@perforce.com>
Información:   Tue Jul 7 01:35:51 2009 -0800

    Corrige el error de ortografía en la página Jam doc (cummulative -> cumulative).

    [git-p4: depot-paths = "//public/jam/src/": change = 7304]

Puede ver que git-p4 ha dejado un identificador en cada mensaje de confirmación. Está bien mantener ese identificador allí, en caso de que necesite hacer referencia al número de cambio Perforce más adelante. Sin embargo, si desea eliminar el identificador, ahora es el momento de hacerlo, antes de comenzar a trabajar en el nuevo repositorio. Puede usar git filter-branch para eliminar las cadenas de identificador en masa:

$ git filter-branch --msg-filter 'sed -e "/^\[git-p4:/d"'
Rewrite e5da1c909e5db3036475419f6379f2c73710c4e6 (125/125)
Ref 'refs/heads/master' was rewritten

Si ejecuta git log, puede ver que todas las sumas de comprobación SHA-1 para las confirmaciones han cambiado, pero las cadenas` git-p4` ya no se encuentran en los mensajes de confirmación:

$ git log -2
commit b17341801ed838d97f7800a54a6f9b95750839b7
Autor: giles <giles@giles@perforce.com>
Información:   Wed Feb 8 03:13:27 2012 -0800

    Corrección a linea 355; change </UL> to </OL>.

commit 3e68c2e26cd89cb983eb52c024ecdfba1d6b3fff
Autor: kwirth <kwirth@perforce.com>
Información:   Tue Jul 7 01:35:51 2009 -0800

    Corrige el error de ortografía en la página Jam doc (cummulative -> cumulative).

Su importación está lista para subir a su nuevo servidor Git.

TFS

Si su equipo está convirtiendo su control de código fuente de TFVC a Git, querrá la conversión de mayor fidelidad que pueda obtener. Esto significa que mientras cubrimos git-tfs y git-tf para la sección de interoperabilidad, sólo cubriremos git-tfs para esta parte, porque git-tfs soporta ramificaciones, y esto es prohibitivamente difícil usando git-tf.

Note

Se trata de una conversión unidireccional. El repositorio Git resultante no podrá conectarse con el proyecto TFVC original.

The first thing to do is map usernames. TFVC is fairly liberal with what goes into the author field for changesets, but Git wants a human-readable name and email address. You can get this information from the tf command-line client, like so:

PS> tf history $/myproject -recursive > AUTHORS_TMP

Esto agarra todos los conjuntos de cambios de la historia del proyecto y lo coloca en el archivo AUTHORS_TMP que procesaremos para extraer los datos de la columna Usuario (el segundo). Abre el archivo y busca en qué caracteres comienzan y terminan la columna y reemplazan, en la línea de comandos siguiente, los parámetros 11-20 del comando` cut` con los que se encuentran:

PS> cat AUTHORS_TMP | cut -b 11-20 | tail -n+3 | uniq | sort > AUTHORS

El comando cut mantiene sólo los caracteres entre 11 y 20 de cada línea. El comando tail omite las dos primeras líneas, que son cabeceras de campo y subrayados ASCII-art. El resultado de todo esto se canaliza a uniq para eliminar duplicados y se guarda en un archivo llamado` AUTHORS`. El siguiente paso es manual; Para que git-tfs haga un uso efectivo de este archivo, cada línea debe estar en este formato:

DOMAIN\username = User Name <email@address.com>

La parte de la izquierda es el campo “Usuario” de TFVC, y la porción en el lado derecho del signo de iguales es el nombre de usuario que se utilizará para los compromisos de Git.

Una vez que tengas este archivo, lo siguiente que debes hacer es hacer un clon completo del proyecto TFVC en el que estás interesado:

PS> git tfs clone --with-branches --authors=AUTHORS https://username.visualstudio.com/DefaultCollection $/project/Trunk project_git

A continuación, deseará limpiar las secciones git-tfs-id desde la parte inferior de los mensajes de confirmación. El siguiente comando hará lo siguiente:

PS> git filter-branch -f --msg-filter 'sed "s/^git-tfs-id:.*$//g"' -- --all

Que utiliza el comando sed desde el entorno Git-bash para reemplazar cualquier línea que empiece por “git-tfs-id:” con vacío, que Git luego ignorará.

Una vez que todo está hecho, estás listo para añadir un nuevo mando a distancia, empujar todas sus ramas hacia arriba, y hacer que su equipo comience a trabajar desde Git.

Un proveedor individual

Si su sistema no es uno de los arriba mencionados, usted debe buscar un importador online - importadores de calidad están disponibles para muchos otros sistemas, incluido el CVS, Clear Case, Visual Source Safe, incluso un directorio de archivos. Si ninguna de estas herramientas funciona para usted, tiene una herramienta más obsoleta o necesita un método de importación más personalizado, debería usar ‘git fast-import’.. Este comando lee instrucciones simples de stdin para escribir datos Git específicos. Es mucho más fácil crear objetos Git de esta manera que ejecutar los comandos raw Git o intentar escribir los objetos raw (ver Los entresijos internos de Git para más información). De esta manera, puede escribir un script de importación que lee la documentación necesaria del sistema desde el que está cargando e imprime instrucciones directas a stdout. A continuación, puede ejecutar este programa y canalizar su resultado mediante `git fast-import

Para demostrar rápidamente, podrá escribir un simple mensaje Supongamos que trabajas en current, haces una copia de seguridad de tu proyecto copiando el directorio ocasionalmente en un directorio de copia de seguridad con el código ‘back_YYYY_MM_DD" directorio de copia de seguridad y desea importar esta en Git. Tu Estructura del directorio se ve así:

$ ls /opt/import_from
back_2014_01_02
back_2014_01_04
back_2014_01_14
back_2014_02_03
current

Para poder importar un directorio Git, necesitas revisar cómo Git almacena sus datos. Como recordará, Git es fundamentalmente una listado enlazado de objetos commit que apuntan a una imágen de contenido. Todo lo que tienes por hacer es indicarle a `fast-import`qué son las snapshots de contenido, cuáles son los puntos de datos de confirmación y el orden en que van a entrar. Su estrategia será para ir a través de snapshots Uno a la vez y crear commits con el contenido de cada directorio, vinculando cada commit al anterior.

Como hicimos en Un ejemplo de implantación de una determinada política en Git, scribiremos esto en Ruby, porque es con lo que generalmente trabajamos y tiende a ser fácilmente legible.Usted puede escribir este ejemplo con bastante facilidad en cualquier elemento con el que esté familiarizado - sólo tiene que escribir la información apropiada a "stdout"., si se está ejecutando en Windows, esto significa que usted tendrá que tener especial cuidado de no introducir porte devoluciones al final de sus líneas - Importación rápida de git es muy particular acerca de que sólo quieren saltos de línea (LF) salto de línea (CRLF) usando windows.

Para empezar, cambiará al directorio de destino e identificará cada subdirectorio, cada uno de los cuales es snapshot que desea importar como un commit. Cambiará a cada subdirectorio e imprimirán los comandos necesarios para exportarlo. Tu loop principal básico se ve así:

last_mark = nil

# loop through the directories
Dir.chdir(ARGV[0]) do
  Dir.glob("*").each do |dir|
    next if File.file?(dir)

    # move into the target directory
    Dir.chdir(dir) do
      last_mark = print_export(dir, last_mark)
    end
  end
end

Si ejecuta print_export dentro del directorio, que toma el registro y la señal de la instantánea anterior y devuelve el registro y la señal de ésta; de esa manera, se pueden enlazar correctamente.“Mark” is the fast-import para un código de identificación que se da a un commit; mientras crea commits,dar a cada uno de ellos una anotación que se puede utilizar para vincular al mismo desde otro commits. Por lo tanto, lo primero que debe hacer en el método ‘print_export’ es generar una etiqueta a partir del nombre del directorio:

mark = convert_dir_to_mark(dir)

Para ello, creará una matriz de directorios y utilizará el valor índice como punto, ya que una línea debe ser un código entero. Tu sistema se ve así:

$marks = []
def convert_dir_to_mark(dir)
  if !$marks.include?(dir)
    $marks << dir
  end
  ($marks.index(dir) + 1).to_s
end

Ahora que tiene una representación entera de su commit, necesita una dirección para los metadatos de commit. Como la información está expresada en el nombre del directorio, la analizarás. La siguiente línea del archivo print_export es

date = convert_dir_to_date(dir)

Donde`convert_dir_to_date` esta definido como

def convert_dir_to_date(dir)
  if dir == 'current'
    return Time.now().to_i
  else
    dir = dir.gsub('back_', '')
    (year, month, day) = dir.split('_')
    return Time.local(year, month, day).to_i
  end
end

Esto devuelve un valor entero para la data de cada directorio. La última parte de la meta-información que necesita para cada committer son los datos del committer, que usted codifica en una variable global:

$author = 'John Doe <john@example.com>'

Ahora está listo para empezar a publicar los datos de validación para su importador.: La información inicial indica que está definiendo un objeto de commit y en qué rama está activado, seguido de la línea que ha generado, la información de committer y el mensaje de committer y, a continuación, la línea anterior, si la hay. El código se ve así:

# print the import information
puts 'commit refs/heads/master'
puts 'mark :' + mark
puts "committer #{$author} #{date} -0700"
export_data('imported from ' + dir)
puts 'from :' + last_mark if last_mark

Usted codifica la zona horaria (-0700) porque hacerlo es fácil.

Si está importando desde otro sistema, debe especificar el uso horario como un intervalo de tiempo. El mensaje de confirmación debe expresarse en un formato especial:

data (size)\n(contents)

El formato consiste en los datos de la palabra, el tamaño de los datos a leer, una nueva línea, y finalmente los datos. Puesto que necesita utilizar el mismo formato para especificar el contenido del archivo más tarde, cree un sistema de ayuda,"export_data":[source,ruby]

def export_data(string)
  print "data #{string.size}\n#{string}"
end

Todo lo que queda es especificar el contenido del archivo para cada uno de ellos. snapshot. Esto es fácil, porque tiene cada uno de ellos en un directorio - puede crear el comando borrar todo seguido del contenido de cada archivo en el directorio. Git entonces grabará cada instantánea apropiadamente:

puts 'deleteall'
Dir.glob("**/*").each do |file|
  next if !File.file?(file)
  inline_data(file)
end

Nota: Porque muchos sistemas piensan que sus modificaciones son cambios de una confirmación a otra, fast-import también puede tomar comandos con cada confirmación para especificar qué archivos se han agregado, eliminado o modificado y cuáles son los nuevos archivos. Podrías calcular las diferencias entre snapshots y proporcionar sólo estos archivos, pero hacerlo es más complejo - también puedes darle a Git todos los datos y dejar que lo resuelva. Si esto se adapta mejor a sus archivos, consulte la página de manual "Importación rápida" para obtener más detalles sobre cómo proporcionar sus archivos de esta manera. El formato para listar el nuevo contenido del archivo o especificar un archivo modificado con el nuevo contenido es el siguiente:

M 644 inline path/to/file
data (size)
(file contents)

Aquí, 644 es el modulo (si tiene archivos ejecutables, necesita detectar y especificar 755 en su lugar), e inline dice que listará el archivo inmediatamente después de esta línea. Su método de "datos_inline" se ve así:

def inline_data(file, code = 'M', mode = '644')
  content = File.read(file)
  puts "#{code} #{mode} inline #{file}"
  export_data(content)
end

Se reutiliza el modo export_data que definió anteriormente, porque es el mismo que el de los datos del mensaje de confirmación. Lo último que necesita hacer es devolver la línea actual para que pueda pasar a la siguiente edición:

return mark
Note

Si se está ejecutando en Windows, deberá asegurarse de añadir un paso más. Como se ha dicho antes, Windows utiliza CRLF para nuevos carácteres de línea, mientras que git fast-import sólo espera LF. Para solucionar este problema y hacer git fast-importar feliz, necesita decirle a ruby para utilizar LF en lugar de CRLF:

$stdout.binmode

Eso es todo. Aquí está el script en su totalidad:

#!/usr/bin/env ruby

$stdout.binmode
$author = "John Doe <john@example.com>"

$marks = []
def convert_dir_to_mark(dir)
    if !$marks.include?(dir)
        $marks << dir
    end
    ($marks.index(dir)+1).to_s
end


def convert_dir_to_date(dir)
    if dir == 'current'
        return Time.now().to_i
    else
        dir = dir.gsub('back_', '')
        (year, month, day) = dir.split('_')
        return Time.local(year, month, day).to_i
    end
end

def export_data(string)
    print "data #{string.size}\n#{string}"
end

def inline_data(file, code='M', mode='644')
    content = File.read(file)
    puts "#{code} #{mode} inline #{file}"
    export_data(content)
end

def print_export(dir, last_mark)
    date = convert_dir_to_date(dir)
    mark = convert_dir_to_mark(dir)

    puts 'commit refs/heads/master'
    puts "mark :#{mark}"
    puts "committer #{$author} #{date} -0700"
    export_data("imported from #{dir}")
    puts "from :#{last_mark}" if last_mark

    puts 'deleteall'
    Dir.glob("**/*").each do |file|
        next if !File.file?(file)
        inline_data(file)
    end
    mark
end


# Loop through the directories
last_mark = nil
Dir.chdir(ARGV[0]) do
    Dir.glob("*").each do |dir|
        next if File.file?(dir)

        # move into the target directory
        Dir.chdir(dir) do
            last_mark = print_export(dir, last_mark)
        end
    end
end

If you run this script, you’ll get content that looks something like this:

$ ruby import.rb /opt/import_from
commit refs/heads/master
mark :1
committer John Doe <john@example.com> 1388649600 -0700
data 29
imported from back_2014_01_02deleteall
M 644 inline README.md
data 28
# Hello

This is my readme.
commit refs/heads/master
mark :2
committer John Doe <john@example.com> 1388822400 -0700
data 29
imported from back_2014_01_04from :1
deleteall
M 644 inline main.rb
data 34
#!/bin/env ruby

puts "Hey there"
M 644 inline README.md
(...)

Para ejecutar el importador, se debe pasar esta señal a través de git fast-import mientras que en el directorio Git se desea copiar. Puede crear un nuevo directorio y luego ejecutar git init en él para un punto de partida, y luego ejecutar su script:

$ git init
Initialized empty Git repository in /opt/import_to/.git/
$ ruby import.rb /opt/import_from | git fast-import
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects:       5000
Total objects:           13 (         6 duplicates                  )
      blobs  :            5 (         4 duplicates          3 deltas of          5 attempts)
      trees  :            4 (         1 duplicates          0 deltas of          4 attempts)
      commits:            4 (         1 duplicates          0 deltas of          0 attempts)
      tags   :            0 (         0 duplicates          0 deltas of          0 attempts)
Total branches:           1 (         1 loads     )
      marks:           1024 (         5 unique    )
      atoms:              2
Memory total:          2344 KiB
       pools:          2110 KiB
     objects:           234 KiB
---------------------------------------------------------------------
pack_report: getpagesize()            =       4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit      = 8589934592
pack_report: pack_used_ctr            =         10
pack_report: pack_mmap_calls          =          5
pack_report: pack_open_windows        =          2 /          2
pack_report: pack_mapped              =       1457 /       1457
---------------------------------------------------------------------

Como puedes ver, cuando se completa con éxito, te da un conjunto de estadísticas sobre lo que logró. En este caso, ha importado un total de 13 objetos para 4 confirmaciones en 1 rama. Ahora, puedes ejecutar git log para ver tu nueva historial:

$ git log -2
commit 3caa046d4aac682a55867132ccdfbe0d3fdee498
Author: John Doe <john@example.com>
Date:   Tue Jul 29 19:39:04 2014 -0700

    imported from current

commit 4afc2b945d0d3c8cd00556fbe2e8224569dc9def
Author: John Doe <john@example.com>
Date:   Mon Feb 3 01:00:00 2014 -0700

    imported from back_2014_02_03

Ahí tienes, un buen y limpio depósito de Git. Es importante tener en cuenta que nada está comprobado - no tiene archivos en su directorio de trabajo al principio. Para obtenerlos, debe reajustar su rama a donde "maestro" está ahora:

$ ls
$ git reset --hard master
HEAD is now at 3caa046 imported from current
$ ls
README.md main.rb

Puedes hacer mucho más con la herramienta "Importación rápida": maneja diferentes modos, datos binarios, múltiples ramas y fusiones, etiquetas, indicadores de progreso y mucho más. Varios ejemplos de escenarios más complejos están disponibles en el directorio ‘contrib/fast-import’ del código fuente Git.