Cómo usar JGit para administrar submódulos de Git
JGit proporciona una API que implementa la mayoría de los comandos del submódulo de Git. Aquí les presentaré estas API.
Construcción
Los fragmentos de código utilizados en este artículo se utilizarán como programa de prueba de aprendizaje. Un proceso de prueba simple ayuda a comprender cómo funcionan las bibliotecas de terceros y cómo utilizar nuevas API. Puede considerar estos programas de prueba como experimentos controlados que pueden ayudarlo a descubrir de manera más intuitiva cómo se ejecuta el código de terceros.
Además, si ha estado escribiendo programas de prueba, puede ayudarle a comprobar nuevas versiones de código de terceros. Si su programa de prueba cubre cómo llamar a estas bibliotecas, los cambios incompatibles en el código de terceros aparecerán lo más rápido posible.
Volviendo al tema anterior, todos los programas de prueba * * * comparten la misma configuración. Consulte el código fuente para obtener más detalles. Ahora hay un repositorio vacío llamado padre y otro repositorio llamado biblioteca. En el programa de prueba, la biblioteca se agregará como un submódulo al repositorio principal. El almacén de la biblioteca inicializa y envía un archivo readme.txt. Existe un método de configuración en el programa de prueba para crear estos dos repositorios, como sigue:
1
Git git = Git.init(). establecer directorio ("/tmp/ruta/a/repo"). call();
Estos dos repositorios están representados por variables principales y variables de biblioteca de tipo Git. Esta clase encapsula un repositorio y permite el acceso a todas las instrucciones disponibles de JGit. Como mencioné anteriormente, cada clase Commnad corresponde a una directiva local de Git pocelain. Se requiere el modo generador para llamar instrucciones. Por ejemplo, el resultado de ejecutar Git.commit() es en realidad equivalente a un CommitCommand. Puede proporcionar algunos parámetros necesarios para llamar a su método call() para ejecutar las instrucciones correspondientes.
Agregar submódulos
Por supuesto, el primer paso es agregar un submódulo a un repositorio existente. Con los pasos de configuración mencionados anteriormente, el repositorio de la biblioteca debe agregarse como un submódulo al directorio de módulos/bibliotecas del repositorio principal.
1
2
Tres
Cuatro
Cinco
Seis p>
p>
Siete
Ocho
Nueve
10
11
12
13
14
15
16
@test
Público void testAddSubmodule() genera una excepción {
String uri
= biblioteca.getRepository(). obtenerDirectorio(). getCanonicalPath();
submuleaddcommand agregar comando = parent . submuleadd();
agregar comando seturi
addCommand.setPath("módulo/. biblioteca");
repositorio repositorio = agregar comando . call();
repositorio . close();
f? archivo workDir = padre . obtener repositorio().
getwork árbol();
f? archivo Léame = nuevo F? ile( workDir, " módulos/biblioteca/léame . txt ");
f? archivo gitmodules = nueva F? ile(directorio de trabajo.módulos git");
assertTrue( readme.isF?ile());
assertTrue( gitmodules.isF?ile());
}
El objeto SubmoduleAddCommand necesita saber dos cosas. La primera es la ubicación donde se clonó el submódulo y la segunda es la ubicación donde debe almacenarse. El atributo URI indica la dirección de clonación. del repositorio. La dirección se pasará al comando de clonación. El atributo de ruta especifica la ruta relativa al directorio de trabajo raíz del repositorio principal donde se almacenará el submódulo. Después de ejecutar el comando, se almacenará el directorio de trabajo del repositorio principal. tiene este aspecto:
El repositorio de la biblioteca se almacena en el directorio módulos/bibliotecas y su árbol de directorios de trabajo está desprotegido. El método call() devuelve un objeto de repositorio que puede usar como un repositorio normal. También significa que debe usarlo en su programa. Cierre explícitamente el repositorio devuelto para evitar perder el identificador del archivo. Como puede ver en la imagen de arriba, SubmoduleAddCommand hace una cosa: crea un .git en el directorio de trabajo raíz del padre. repositorio. archivo del módulo y agréguelo al índice
1
2
三
[submódulo "módulo/biblioteca".
Path=module/library
URL = git@example.com:path/to/lib.git
Si ha abierto el archivo de configuración de Git, Encontrará la sintaxis anterior. Este archivo enumera todos los submódulos del repositorio actual. Para cada módulo, la dirección URL del repositorio y la ruta local se enumeran en el archivo. Una vez que el archivo se confirma y se envía, el repositorio se clona. sabrá dónde obtener el submódulo correspondiente (se explica en detalle más adelante)
Lista de submódulos
Cuando agregamos un submódulo, podemos preguntarnos si es un repositorio principal. En la primera prueba, hicimos una prueba básica para verificar la existencia de algunos archivos y directorios. También podemos usar la API para listar los submódulos del repositorio de la siguiente manera:
1
Tres
Cuatro
Cinco
Seis
Siete
Ocho
Nueve
10
11
@test
public void testListSubmodules() lanza una excepción { p>
addLibrarySubmodule();
Mapa<String, SubmoduleStatus> submódulo
= parent.submoduleStatus(). call();
assertEquals(1, submodules . size());
Estado del submodule = submodules get("Módulo/Biblioteca");
afirmarEquals(INITIALIZED, status. gettype());
}
El comando SubmoduleStatus devuelve una colección de mapeo de submódulos, donde la clave es la ruta al submódulo y el valor es el Valor de estado del módulo. Con el código anterior, podemos verificar que el submódulo efectivamente se haya agregado y su estado se haya inicializado. Este comando también le permite agregar una o más rutas para restringir el estado del submódulo.
Hablando de estado, StatusCommand de JGit no es un comando nativo de Git.
Si se agrega la opción "ignore-submodules=dirty" al ejecutar la directiva, se ignorarán todas las modificaciones en el directorio de trabajo de los submódulos.
Actualización de submódulos
Los submódulos generalmente apuntan a una confirmación específica en su repositorio. Si alguien luego clona el repositorio principal, obtendrá el mismo estado de submódulo, incluso si hay nuevas confirmaciones en sentido ascendente del submódulo.
Para modificar un submódulo, debe actualizarlo explícitamente como el código:
1
2
三
Cuatro
Cinco
Seis
Siete
Ocho
Nueve
10
11
12
13
14
@prueba
Public void testUpdateSubmodule() arroja una excepción {
addLibrarySubmodule();
ObjectId newHead = biblioteca.commit(). setMessage("mensaje"). call();
Archivo workDir = parent.getRepository(). getwork tree();
Git libModule = Git.open(new F?ile(workDir, "Módulo/Biblioteca");
libModule.pull().call();
módulo lib. close();
parent.add(). addF?ilepattern("módulo/biblioteca");
parent .commit(). .setMessage("Update Submodule");
assertEquals(newHead, getSubmoduleHead("Module/Library"));
}
En este fragmento de código largo , lo primero que debe hacer es enviar algo al repositorio de la biblioteca (línea 4) y luego actualizar el submódulo a la última confirmación.
Para que la actualización sea persistente, el submódulo debe confirmarse. (líneas 10, 11). Esta confirmación guarda este ID de confirmación actualizado bajo el nombre del submódulo (módulos/biblioteca en este ejemplo). Finalmente, generalmente es necesario enviar los cambios para que estén disponibles para otros repositorios. p>
Actualizar modificaciones a los submódulos en el repositorio principal
Incorporar confirmaciones ascendentes al repositorio principal también modificará la configuración del submódulo. Sin embargo, el submódulo en sí no se actualizará automáticamente. p>
SubmoduleUpdateCommand se usa para resolver este problema. No se requieren otros parámetros para usar este comando, que actualizará todos los submódulos registrados y verificará su configuración especificada en. Al igual que otros comandos de submódulos, también hay un addPath(. ) para garantizar que solo se actualice el submódulo en la ruta dada
< A estas alturas, es posible que haya descubierto que todas las operaciones del submódulo son manuales. De forma predeterminada, clonar un repositorio con una configuración de submódulo no clonará sus submódulos. Sin embargo, el comando CloneCommand tiene el atributo cloneSubmodules verdadero, todos los submódulos configurados se clonarán internamente, después de clonar el repositorio principal, los comandos SubmoduleInitCommand y SubmoduleUpdateCommand se ejecutarán de forma recursiva y se extraerá el directorio de trabajo del repositorio principal. >Si desea eliminar un submódulo, debe escribir:
1
setpath(...).call() ;
Antes de eso, teníamos que eliminar manualmente el submódulo. Si se desplaza hasta el método removeSubmodule(), verá que esto no es nada complicado.
Primero, convierta cada submódulo de . submódulos de git y . archivo de configuración git/config. En segundo lugar, la entrada del submódulo se eliminará del índice. Finalmente, revisa. Los archivos y el índice de gitsubmodules se confirmarán y el contenido del submódulo se eliminará del directorio de trabajo.
Submódulos transversales
Git nativo proporciona el submódulo Git para cada comando, que ejecuta un comando de shell para cada submódulo. JGit no admite directamente dichas instrucciones, pero proporciona SubmoduleWalk. Esta clase se puede utilizar para iterar sobre submódulos en un repositorio. El siguiente programa de ejemplo obtiene confirmaciones ascendentes para todos los submódulos.
1
2
Tres
Cuatro
Cinco
Seis p>
p>
Siete
Ocho
Nueve
10
11
12
13
14
15
16
17
@prueba
public void testSubmoduleWalk() arroja una excepción {
addLibrarySubmodule();
int submoduleCount = 0;
Repositorio principal de la base de conocimientos = padre . obtener repositorio( );
SubmoduleWalk walk = SubmoduleWalk para index(repositorio principal);
while( walk.next() ) {
repositorio. submoduleRepository = caminar. obtener repositorio();
Git.wrap(submoduleRepository). conseguir(). call();
submodulerepository. close();
submodulecount++;
}
liberación();
assertEquals(1, submoduleCount);
}
El objeto walk puede apuntar al siguiente submódulo a través del método next() Si no hay más submódulos, esto. El método devolverá falso. Al utilizar SubmoduleWalk, puede liberar recursos relacionados con el submódulo llamando al método release(). Del mismo modo, si obtiene una instancia de repositorio de un submódulo, no olvide cerrarla.
El recorrido de submódulos también se puede utilizar para obtener información detallada sobre los submódulos. Puede acceder a las propiedades del submódulo actual a través de la mayoría de sus métodos getter, como ruta, encabezado, URL remota, etc.
Sincronizar URL remota
De lo anterior sabemos que la configuración del submódulo se guarda en. El archivo gitsubmodules en el directorio de trabajo raíz del repositorio principal. Al menos, en. git/config, podemos reescribir la URL remota que cubre el submódulo. Para cada submódulo, tienen un archivo de configuración. Entonces, cada submódulo puede tener otra URL remota. El comando SubmoduleSyncCommand se puede utilizar para restablecer todas las URL remotas a la configuración en . gitmodules.
En resumen, el soporte de JGit para submódulos es casi el mismo que el de Git nativo. La mayoría de los comandos de Git se implementan en JGit o se pueden emular de alguna manera. Si descubre que falta algo o no se puede implementar, puede buscar ayuda de la amigable y servicial comunidad JGit.