Subinformes de Git

Soy miembro de un pequeño equipo de firmware y utilizamos un server privado de Git para el control de versiones. Nuestra base de código generalmente tiene carpetas para código específico de plataforma, código común utilizado por múltiples plataforms y un SDK proporcionado por el fabricante del microprocesador que desarrollamos.

Actualmente nuestros repositorys se centran en códigos comunes; cada plataforma tiene una carpeta en el repository. Esto tiene al less dos consecuencias graves;

  1. Cuando promocionamos cambios para una plataforma, es visible para todas las demás plataforms que comparten el mismo código común. Esto complica el historial de confirmaciones con lanzamientos para múltiples plataforms y en el pasado ha generado confusión sobre la plataforma para la que estamos revisando los cambios.

  2. Los cambios en el código común deben verificarse para todas las plataforms en el repository antes de que puedan comprometerse, causando un daño innecesario. (Alguien no hizo esto ayer e hizo cambios que causaron que algunas de nuestras plataforms anteriores fallaran en su construcción. Este repository en particular tiene 5 plataforms)

Estoy presionando para tener un repository para cada plataforma, de modo que podamos realizar cambios en el código común y actualizar el SDK periódicamente sin tener que actualizar y verificar todas las plataforms que estamos respaldando. Debido a que somos un equipo de cinco personas y estos problemas generalmente se retrasan durante el time de crisis que conduce a un lanzamiento, esto nos ahorraría una tonelada de daño y time innecesarios en el cerebro. Naturalmente, la parte más difícil está en la implementación.

En este momento estoy imaginando un sistema en el que cada plataforma tiene su propio repository, cada base de código común tiene su propio repository y cada uno de los SDK que utilizamos tiene su propio repository. Los repositorys de la plataforma se vincularían o harían reference al código común y al SDK que utilizan como "sub-repositorys".

He leído sobre los submodules, pero creo que causarían más problemas de los que solucionarían; Recientemente tuvimos que depurar firmware de hace tres años, que requería restablecer nuestra base de código local al lanzamiento del problema para hacer un análisis estático. Como entiendo, la versión local del submodule está separada del repository en el que reside, lo que significa que restablecer el repository a una confirmación anterior dejará el submodule en el "futuro" con respecto al rest del repository. En el context de la debugging del código antiguo, este comportamiento es 100% inaceptable.

Aquí hay una list con viñetas de lo que quiero lograr; (en order de importancia)

  1. Rompe el código específico de la plataforma, alejándolo del código común, de modo que los cambios en el código común y / o el SDK no tengan consecuencias imprevistas en otras plataforms.

  2. Cree nuevos repositorys para cada plataforma, cada base de código común y cada SDK.

  3. La clonación de un repository remoto en una máquina local debe ser un process de un solo paso; los nuevos usuarios no deberían verse forzados a extraer cada sub repository antes de que la plataforma se genere.

    • En adición; la restauración del código anterior, incluido el código común y el SDK que se utilizó para comstackr la versión XXX-YYY de cualquier plataforma dada, debe ser posible.

    • Editar: La última vez que tuve que "restaurar" el código, utilicé un restablecimiento completo de la compilation que estaba depurando y un restablecimiento parcial a una compilation un año más antiguo de lo que sabía que era bueno, pero solo el plugin de Git en mi syntax marcador resaltaría los cambios entre los conocidos-buenos y conocidos-malos para mí.

      Incidentalmente, esta plataforma en particular es monolítica y esta pregunta no se aplica a ella, pero en aras de la argumentación, diremos que sí se aplica.

  4. La modificación del código común no debería afectar a las plataforms hasta que el mantenedor de la plataforma obtenga el nuevo código común. (Creo que esto es posible con los subtreees agregando uno de los commits labeldos del código común en lugar del maestro del código común)

  5. Un sub-repository de solo lectura es una limitación aceptable. (es decir, el repository secundario no se puede modificar en el repository de la plataforma o los cambios en el repository secundario no se pueden enviar desde el repository de la plataforma)

  6. El soporte de SmartGit / HG es deseable ya que todos less uno de nuestros miembros lo usan.

  7. La creación de scripts de tareas de una sola vez es aceptable, pero no quiero contaminar las plataforms con scripts que hacen el trabajo de Git.

También he leído sobre los subtreees, pero en este momento no estoy seguro de si permitirían intuitivamente el comportamiento que deseo. Mi pregunta principal es esta: ¿Git admite este tipo de funcionalidad? En caso afirmativo, ¿esa funcionalidad está implementada por subtreees u otro método del que aún no soy consciente?

Creo que causarían más problemas de los que solucionarían; Recientemente tuvimos que depurar firmware de hace tres años, que requería restablecer nuestra base de código local al lanzamiento del problema para hacer un análisis estático. Como entiendo, la versión local del submodule está separada del repository en el que reside, lo que significa que restablecer el repository a una confirmación anterior dejará el submodule en el "futuro" con respecto al rest del repository.

Absolutamente no.
El submodule es exactamente lo que necesitas.

Y si necesita restablecer un repository principal a una confirmación pasada, también restablecería la carpeta raíz del submodule, llamada gitlink , gitlink a la SHA1 (la que se reescribió en ese momento). Para eso es un gitlink .

Un clone --recursive un repository padre y su submodule en un command.

Si es necesario, puede configurar un submodule para seguir los últimos commits de una bifurcación .

Y puede enviar desde su repository padre tanto dicho repository padre como sus submodules, nuevamente en un command .

Solo estoy sonando aquí porque creo que la respuesta de @VonC no explica completamente por qué los submodules abordan las preocupaciones de @JacaByte.

Creo que causarían más problemas de los que solucionarían; Recientemente tuvimos que depurar firmware de hace tres años, que requería restablecer nuestra base de código local al lanzamiento del problema para hacer un análisis estático. Como entiendo, la versión local del submodule está separada del repository en el que reside, lo que significa que restablecer el repository a una confirmación anterior dejará el submodule en el "futuro" con respecto al rest del repository.

Esto no es completamente incorrecto Sin embargo, es incorrecto decir que los submodules no le permiten verificar una versión anterior de su base de código . Esta confusión surge del hecho de que git checkout no actualiza los treees de trabajo de los submodules, sino que te deja ese trabajo (la git submodule update --init --recursive lo hará por ti).

Los submodules son herramientas fantásticas para controlar las dependencies del repository. De hecho, hacen específicamente lo que usted quiere: asociar una versión específica de su código con una versión específica de la dependencia . Específicamente, un "submodule" es realmente solo un file de text que contiene el hash SHA-1 correspondiente a una confirmación en el repository del submodule (Git almacena metainformación sobre el submodule remoto en .gitmodules , que es cómo sabe dónde get una copy del repository de submodules desde).

Sin embargo, trabajar con submodules puede ser espinoso. Requiere que ambos comprendan bien el model de Git (commits & working tree / staging / repo) y comprendan el sistema de submodules en sí. Pero si se asegura de que la gente sepa lo que está haciendo (y esto es algo muy grande si), puede evitar dispararse en el pie.


Pareces estar muy específicamente preocupado por tu capacidad de retrotraer a una versión anterior de tu código base, y las respuestas de @VonC no parecen haber aliviado tus preocupaciones, así que te daré un tutorial sobre cómo hacerlo:

Usaré mi file .dotfiles personal como ejemplo (busco extensiones de Vim como submodules; en el momento de escribir esto, HEAD es d9c0a797ad45a0d2fd92a07d3c3802528ed7b82a ):

 $ git clone https://github.com/sxlijin/.dotfiles dotfiles Cloning into 'dotfiles'... remote: Counting objects: 350, done. remote: Compressing objects: 100% (31/31), done. remote: Total 350 (delta 12), reused 0 (delta 0), pack-reused 318 Receiving objects: 100% (350/350), 86.61 KiB | 0 bytes/s, done. Resolving deltas: 100% (176/176), done. $ cd dotfiles/ $ git submodule update --init --recursive Submodule 'bundle/jedi-vim' (http://github.com/davidhalter/jedi-vim) registenetworking for path 'vim/bundle/jedi-vim' Submodule 'bundle/nerdtree' (https://github.com/scrooloose/nerdtree.git) registenetworking for path 'vim/bundle/nerdtree' Submodule 'bundle/supertab' (https://github.com/ervandew/supertab.git) registenetworking for path 'vim/bundle/supertab' Submodule 'vim/bundle/vim-flake8' (https://github.com/nvie/vim-flake8.git) registenetworking for path 'vim/bundle/vim-flake8' Submodule 'bundle/vim-pathogen' (https://github.com/tpope/vim-pathogen.git) registenetworking for path 'vim/bundle/vim-pathogen' Cloning into '/home/pockets/dotfiles/vim/bundle/jedi-vim'... warning: networkingirecting to https://github.com/davidhalter/jedi-vim/ Cloning into '/home/pockets/dotfiles/vim/bundle/nerdtree'... Cloning into '/home/pockets/dotfiles/vim/bundle/supertab'... Cloning into '/home/pockets/dotfiles/vim/bundle/vim-flake8'... Cloning into '/home/pockets/dotfiles/vim/bundle/vim-pathogen'... Submodule path 'vim/bundle/jedi-vim': checked out '8cf616b0887276e026aefdf68bc0311b83eec381' Submodule 'jedi' (https://github.com/davidhalter/jedi.git) registenetworking for path 'vim/bundle/jedi-vim/jedi' Cloning into '/home/pockets/dotfiles/vim/bundle/jedi-vim/jedi'... Submodule path 'vim/bundle/jedi-vim/jedi': checked out 'f05c0714c701ab784bd344aa063acd216fb45ec0' Submodule path 'vim/bundle/nerdtree': checked out '281701021c5001332a862da80175bf585d24e2e8' Submodule path 'vim/bundle/supertab': checked out 'cdaa5c27c5a7f8b08a43d0b2e65929512299e33a' Submodule path 'vim/bundle/vim-flake8': checked out '91818a7d5f5a0af5139e9adfedc9d00fa963e699' Submodule path 'vim/bundle/vim-pathogen': checked out '7ba2e1b67a8f8bcbafedaf6763580390dfd93436' 

Ese último command git submodule update --init --recursive miró los hashes del submodule almacenados en HEAD , y actualizó mi tree de trabajo ( no los actualiza a los commits más recientes en sus respectivos repositorys, eso es git submodule update --remote ) , agregando los contenidos de los repositorys correspondientes en las routes correspondientes, de forma recursiva (por lo que si alguno de mis submodules tiene submodules, lo cual hacen, los contenidos de esos repositorys también se agregan a mi tree de trabajo).

Ahora, sucede que actualicé mis plugins de Vim en HEAD~2 :

 $ git show HEAD~2 -- vim/bundle/* commit 27bfe76851991026bd026b4bf2ab10d6ecbc6f74 Author: First Last <first.last@email.domain> Date: Thu Feb 2 13:33:30 2017 -0600 update dependencies diff --git a/vim/bundle/jedi-vim b/vim/bundle/jedi-vim index f191ccd..8cf616b 160000 --- a/vim/bundle/jedi-vim +++ b/vim/bundle/jedi-vim @@ -1 +1 @@ -Subproject commit f191ccd6fb7f3bc2272a34d6230487caf64face7 +Subproject commit 8cf616b0887276e026aefdf68bc0311b83eec381 diff --git a/vim/bundle/nerdtree b/vim/bundle/nerdtree index eee431d..2817010 160000 --- a/vim/bundle/nerdtree +++ b/vim/bundle/nerdtree @@ -1 +1 @@ -Subproject commit eee431dbd44111c858c6d33ffd366cae1f17f8b3 +Subproject commit 281701021c5001332a862da80175bf585d24e2e8 diff --git a/vim/bundle/supertab b/vim/bundle/supertab index 6651177..cdaa5c2 160000 --- a/vim/bundle/supertab +++ b/vim/bundle/supertab @@ -1 +1 @@ -Subproject commit 66511772a430a5eaad7f7d03dbb02e8f33c4a641 +Subproject commit cdaa5c27c5a7f8b08a43d0b2e65929512299e33a 

Digamos que algo parece ser raro con mis complementos de Vim en este momento, y sospecho que el compromiso anterior es responsable de esta rareza, por lo que quiero volver mis complementos a lo que fueran antes de actualizarlos.

 $ git checkout -b testing HEAD~2^ M vim/bundle/jedi-vim M vim/bundle/nerdtree M vim/bundle/supertab Switched to a new branch 'testing' $ git status On branch testing Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: vim/bundle/jedi-vim (new commits) modified: vim/bundle/nerdtree (new commits) modified: vim/bundle/supertab (new commits) no changes added to commit (use "git add" and/or "git commit -a") 

Bien, ahora las cosas parecen un poco raras. No tuve ningún cambio en mi tree de trabajo cuando hice este pago, por lo que parece que el process de pago está introduciendo cambios en mi tree de trabajo. ¿Que está pasando aqui?

 $ git diff diff --git a/vim/bundle/jedi-vim b/vim/bundle/jedi-vim index f191ccd..8cf616b 160000 --- a/vim/bundle/jedi-vim +++ b/vim/bundle/jedi-vim @@ -1 +1 @@ -Subproject commit f191ccd6fb7f3bc2272a34d6230487caf64face7 +Subproject commit 8cf616b0887276e026aefdf68bc0311b83eec381 diff --git a/vim/bundle/nerdtree b/vim/bundle/nerdtree index eee431d..2817010 160000 --- a/vim/bundle/nerdtree +++ b/vim/bundle/nerdtree @@ -1 +1 @@ -Subproject commit eee431dbd44111c858c6d33ffd366cae1f17f8b3 +Subproject commit 281701021c5001332a862da80175bf585d24e2e8 diff --git a/vim/bundle/supertab b/vim/bundle/supertab index 6651177..cdaa5c2 160000 --- a/vim/bundle/supertab +++ b/vim/bundle/supertab @@ -1 +1 @@ -Subproject commit 66511772a430a5eaad7f7d03dbb02e8f33c4a641 +Subproject commit cdaa5c27c5a7f8b08a43d0b2e65929512299e33a 

Huh, OK, entonces esto es interesante. Por alguna razón, git diff dice que las versiones de los submodules revisados ​​en mi tree de trabajo actual no coinciden, pero esta diferencia se parece mucho al git show que hice anteriormente. Me pregunto qué submodules están realmente en HEAD

 $ git ls-tree HEAD -- vim/bundle/ 160000 commit f191ccd6fb7f3bc2272a34d6230487caf64face7 vim/bundle/jedi-vim 160000 commit eee431dbd44111c858c6d33ffd366cae1f17f8b3 vim/bundle/nerdtree 160000 commit 66511772a430a5eaad7f7d03dbb02e8f33c4a641 vim/bundle/supertab 160000 commit 91818a7d5f5a0af5139e9adfedc9d00fa963e699 vim/bundle/vim-flake8 160000 commit 7ba2e1b67a8f8bcbafedaf6763580390dfd93436 vim/bundle/vim-pathogen 

Aha! Ahí vamos – ¡ git checkout simplemente no actualizó la versión del submodule en el tree de trabajo! Sin embargo, Git aún sabe a qué hash se deben prestar estos submodules. Resulta que hay un command que hará esto por usted:

 $ git submodule update --init --recursive Submodule path 'vim/bundle/jedi-vim': checked out 'f191ccd6fb7f3bc2272a34d6230487caf64face7' Submodule path 'vim/bundle/jedi-vim/jedi': checked out '2ba78ab725f1e02dfef8bc50b0204cf656e8ee23' Submodule path 'vim/bundle/nerdtree': checked out 'eee431dbd44111c858c6d33ffd366cae1f17f8b3' Submodule path 'vim/bundle/supertab': checked out '66511772a430a5eaad7f7d03dbb02e8f33c4a641' 

Para abordar por separado sus preocupaciones:

  1. Rompe el código específico de la plataforma, alejándolo del código común, de modo que los cambios en el código común y / o el SDK no tengan consecuencias imprevistas en otras plataforms.

    Sí. Submodules.

  2. Cree nuevos repositorys para cada plataforma, cada base de código común y cada SDK.

    Esto va a depender mucho de cómo haya establecido su base de código actual. Es posible que el git subtree tenga lo que usted desee (específicamente git subtree split permite extraer files en un subtree en un repository Git separado, repleto de historial de compromisos, pero no sé qué tan bien funcionará con un repository tan grande y tan antiguo como parezca estar describiendo – vea el man git subtree de man git subtree para más detalles).

  3. La clonación de un repository remoto en una máquina local debe ser un process de un solo paso; los usuarios nuevos no deberían verse forzados a extraer cada sub repository antes de que se construya la plataforma.

    Nop. Los submodules, por layout, no rastrean los contenidos de un sub-repository: ese es el trabajo del sub-repository. Todo lo que hacen es mantener un puntero a un compromiso específico en el sub-repo.

  4. En adición; la restauración del código anterior, incluido el código común y el SDK que se utilizó para comstackr la versión XXX-YYY de cualquier plataforma dada, debe ser posible. La modificación del código común no debería afectar a las plataforms hasta que el mantenedor de la plataforma obtenga el nuevo código común. (Creo que esto es posible con los subtreees agregando uno de los commits labeldos del código común en lugar del maestro del código común)

    Los submodules hacen esto por layout. Es por eso que apuntan a confirmaciones específicas en lugar de a un control remoto.

  5. Un sub-repository de solo lectura es una limitación aceptable. (es decir, el repository secundario no se puede modificar en el repository de la plataforma o los cambios en el repository secundario no se pueden enviar desde el repository de la plataforma)

    Los submodules generalmente se deben tratar como sub-repositorys de solo lectura. Es posible enviar actualizaciones desde los submodules, pero le da más carga al usuario para asegurarse de que no arruine la versión del submodule con el que está trabajando.

  6. El soporte de SmartGit / HG es deseable ya que todos less uno de nuestros miembros lo usan.

    Sin garantías aquí. Probablemente tendrá que comunicarse con las 3 comunidades de desarrollo (Git, SmartGit, Mercurial) para resolver esto.

  7. La creación de scripts de tareas de una sola vez es aceptable, pero no quiero contaminar las plataforms con scripts que hacen el trabajo de Git.

    Depende de lo complicado que estés hablando. He mostrado anteriormente que revisar una versión anterior de su código es solo dos commands: checkout y submodule update --init --recursive , pero no está claro lo que está pidiendo.