2012-04-27 5 views
14

Tengo dos ramas de desarrollo en git y con frecuencia necesito cambiar entre las dos. Sin embargo, lo realmente frustrante es que cada vez que cambio ramas en git, todo el proyecto se reconstruye porque las marcas de tiempo del sistema de archivos de algunos archivos cambiarán.Evite la recompilación con git y make

Ofc, los makefiles están configurados para construir el proyecto en dos directorios de compilación diferentes.

¿Hay alguna forma de evitar esto? La compilación es un proceso muy largo y lento ...

Editar: - Esta es una explicación un poco más detallada de la pregunta ... Digamos que tengo un encabezado de archivos Basic.h que está incluido en una serie de otros archivos. Basic.h es diferente entre la rama 1 y la rama 2.

Ahora digamos que he compilado la rama 1 en build_branch1 y la rama 2 en build_branch2. Digamos que tengo la rama 2 actualmente prestada. Ahora comprobo la rama 1 y cambio File1.cpp y vuelvo a compilar. Idealmente, dado que File1.cpp solo ha cambiado desde que lo compilé por última vez, este es el único archivo que debe recompilarse.

Sin embargo, como Basic.h ha cambiado su marca de tiempo debido a la finalización de la compra, todos los archivos que incluyen Basic.h se volverán a compilar. Quiero evitar esto.

+1

Pensé que git solo cambia las marcas de tiempo en los archivos que realmente han cambiado. En ese caso, debe reconstruir de todos modos para obtener resultados correctos. ¿Qué comportamiento estás buscando? – sinelaw

+1

Ver [este] (http://kerneltrap.org/mailarchive/git/2007/3/1/240167) tema relacionado. Básicamente, hacer algo como esto no es recomendable. – Job

+0

@sinelaw: - a.cpp incluye Basic.h. Tengo dos copias de a.o en branch1_build/a.o y branch2_build/a.o. Ahora cuando cambio las ramas de branch1 a branch2, recompilará branch2_build/ao aunque esté actualizado – owagh

Respuesta

13

Git solo cambia los archivos que se actualizan entre las ramas. Pero si su compilador realiza una reconstrucción completa incluso si se modificó un único archivo, siempre puede clonar y verificar sus diferentes ramas en directorios diferentes. Es como:

/your-repo-name.branch1 
/your-repo-name.branch2 

Esto ocupa más espacio en disco pero es mucho más conveniente que cambiar ramas divergentes en un gran repositorio.

+6

También puede usar '--shared' para guardar la mayor parte de ese espacio en disco: elija uno de esos clones como su" principal " "almacenamiento, y haga el resto con' git clone --shared' refiriéndose al clon de almacenamiento principal. Simplemente no elimine las ramas en el repositorio "principal" (o elimine las que no se están compartiendo) y estará a salvo allí. – torek

+0

Hola, torek. ¿Puedes ampliar tu respuesta sobre los clones compartidos? ¿No creará eso un repositorio compartido que sea de escritura grupal? – owagh

+1

No, '--shared' solo afecta al nuevo clon. De hecho, ni siquiera necesitas '--shared' la mayor parte del tiempo ya que git es (si no muy antiguo) lo suficientemente inteligente como para darse cuenta de que es un clon local y usa enlaces duros. (Me imagino que '-shared' se requiere en Windows) – torek

3

Si sabe qué archivos realmente necesitan compilación, y los hace manualmente, GNU Make (al menos, no sé sobre otras implementaciones) tiene una marca: -t, que básicamente ejecuta su Makefile y cambia las marcas de tiempo en su lugar de ejecutar comandos.

No obstante, deberá actualizar los archivos que necesidad de actualización antes de usar esta bandera, o que va a terminar con ficheros de objetos que son legítimamente fuera de fecha, pero mirada actualizada. Consulte el documento vinculado para obtener más detalles.

La opción -o también podría interesarle, dependiendo de la cantidad de cambios cuando cambie de ramas.

2

No hay una buena manera de conservar las marcas de tiempo y no meterse en problemas en su entorno de compilación. Utilice git clone/git checkout branchB para crear un segundo directorio de trabajo para compilar y trabajar con la rama B. No tenga su compilación Makefile, haga que cada compilación se cree en su propio directorio de compilación.

2

Si Basic.h realmente difiere entre las ramas, entonces la única solución es dividirlo en archivos más pequeños con dependencias más finas, para que se reconstruyan menos cosas cuando cambie.

Pero supongamos que Basic.h es exactamente el mismo entre las ramas, pero git está cambiando su marca de tiempo. Este es un desencadenador falso, como hacer touch Basic.h, que revela una limitación de los sistemas de compilación basados ​​en la fecha y hora. Idealmente, queremos un sistema de compilación para reconstruir cuando los contenidos cambian, no cuando las marcas de tiempo cambian. Las marcas de tiempo se utilizan porque son un sustituto barato para detectar un cambio de contenido.El método superior es que el sistema de compilación mantenga hashes de todos los archivos y detecte modificaciones reales, sin tener en cuenta la marca de tiempo. Esto también soluciona problemas como "reloj sesgado detectado, su construcción puede estar incompleta".

No obtendrá este tipo de sistema de compilación de Make; pero es posible que pueda trabajar algunos aspectos con respecto a ciertos archivos. Por ejemplo, puede escribir sus reglas de Make para que sus archivos de objeto no dependan directamente de Basic.h, sino de Basic.h.sha, que es un archivo de sello. Ahora, ¿qué hay en Basic.h.sha? Este archivo contiene un hash SHA256 de Basic.h.

Cada vez que ejecuta Make, la lógica en el Makefile calcula el hash en Basic.h y lo compara con el hash almacenado en Basic.h.sha. Si difieren, entonces se sobrescribe Basic.h.sha con el nuevo hash. Por lo tanto, su sello de tiempo se golpea, lo que provoca una reconstrucción.

BASIC_H_SHA := $(shell sha256sum Basic.h) 
BASIC_H_SHA_OLD := $(shell cat Basic.h.sha) 

ifneq ($(BASIC_H_SHA),$(BASIC_H_SHA_OLD)) 
$(info Basic.h has changed!) 
DUMMY := $(shell echo "$(BASIC_H_SHA)" > Basic.h.sha) 
endif 

He implementado lógica a lo largo de estas líneas para hacer dependiente de módulos sobre los cambios a su respectiva CFLAGS. Básicamente, podemos convertir un cambio en cualquier cosa en un toque de un archivo de marca de tiempo, que controla lo que está construido.

+2

Espero que se den cuenta de la ridiculez de su responder.Lo que he dado es el subconjunto más pequeño que ilustra adecuadamente el problema en cuestión. – owagh

+0

Obviamente, usted cree que aunque se compilan numerosos archivos porque 'Basic.h' cambió, en realidad no tienen que serlo. Esto significa que usted cree que los archivos tienen algunas * dependencias falsas * en 'Basic.h' (además de las reales). La única forma de cambiar eso es dividir 'Basic.h', o bien introducir un tipo completamente diferente de sistema de compilación que pueda administrar dependencias de grano fino como" argumento 3 de la función 'foo' cambiado; recompilar todo lo que llame foo ". – Kaz

+2

La segunda parte de su respuesta es un punto completamente válido acerca de las técnicas de programación general con las que estoy de acuerdo, pero se ha perdido por completo el objetivo de mi pregunta y respondió algo que ni siquiera pedí. Gracias de todos modos ... – owagh

8

Otra respuesta parcial: caché del compilador.

Al volver a la rama original y reconstruir, aunque las dependencias dicen que se deben reconstruir numerosos archivos dependientes de Basic.h, los archivos del objeto se pueden extraer de una memoria caché del compilador.

ccache (http://ccache.samba.org/) todavía tiene que hacer un trabajo bastante caro (procesar la unidad de traducción preprocesada, ya que una unidad de traducción completa se usa una clave hash) pero es mucho más barato que compilar.

En algunos casos ccache puede eliminar una compilación frente a un cambio que no lo afecta, como algunos cambios en el espacio en blanco. Por ejemplo, si cambia un comentario en un archivo dependiente (encabezado o fuente), eso no invalida el archivo del objeto en caché.

Por lo tanto, puede ayudar incluso si hace un git pull y elige un cambio nuevo en Basic.h que no haya visto antes.

+0

Hola, gracias por el enlace. Lo comprobaré. – owagh

Cuestiones relacionadas