Cómo y por qué robar árboles en git

arboles


En este artículo hablaré sobre un truco útil pero poco conocido de trabajar con git: cómo crear fácilmente una confirmación utilizando un árbol de otra confirmación. En pocas palabras, cómo obtener el estado deseado del proyecto en cualquier rama, si este estado ya ha estado en algún lugar y en algún lugar del repositorio antes. Se darán varios ejemplos de cómo esto hace posible resolver con elegancia algunos problemas prácticos. Y en particular, hablaré sobre el método que encontré, que puede simplificar en gran medida la corrección de múltiples conflictos durante el rebase. Además, este artículo es una excelente manera de comprender en la práctica lo que constituye un commit en git.


Contenido


La parte teórica. Sobre commits y árboles
git commit-tree
Parte práctica
1. Sincronización con otra rama
2. Comparación de dos ramas
3. Rama inversa
4. Parcial reverso
5. Fusión artificial
6a. Método de rebase mediante combinación - descripción
6b. Método de rebase a través de fusión - script
7. Alias
Conclusión



La parte teórica. Sobre commits y árboles


Comprometerse es probablemente el concepto más básico en git, veamos en qué consiste. Cada confirmación tiene su propio identificador único en forma de hash, por ejemplo 5e45ecb . Y con el siguiente comando, conociendo el hash, podemos ver su contenido.


git cat-file -p 5e45ecb 

 tree 8640790949c12690fc71f9abadd7b57ec0539376 parent 930741d1f5fd2a78258aa1999bb4be897ba3d015 author Mark Tareshawty <tareby...@github.com> 1542718283 -0500 committer Mark Tareshawty <tareby...@github.com> 1542718283 -0500 gpgsig -----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE----- Fix scoping so that we don't break the naming convention 

Estas pocas líneas son el contenido completo de la confirmación:


  • árbol: un enlace a un estado de proyecto específico
  • parent - enlace a commit padre
  • author - autor del commit + date original
  • committer - creador de esta fecha commit +
  • gpgsig: firma digital (si está disponible)
  • mensaje - confirmar texto

Permítame recordarle que el commit en git (a diferencia de otros VCS) no describe los cambios realizados. Es lo contrario: cada confirmación describe el estado específico del proyecto en su conjunto, y lo que vemos como los cambios que realiza es en realidad una diferencia calculada dinámicamente en comparación con el estado anterior. También vale la pena señalar que todas las confirmaciones son inmutables (es decir, inmutables), es decir, con rebase / cherry-pick / modify, se crean confirmaciones absolutamente nuevas.


árbol (árbol): de hecho, es solo una carpeta con contenido específico inmutable. Un objeto de tipo árbol contiene una lista de archivos con contenido específico (blobs) y subcarpetas (árboles). Y el árbol al que apunta cada confirmación es la carpeta raíz del proyecto, o más bien su estado específico.


ver el contenido del árbol

Esto se puede hacer exactamente de la misma manera para cualquier otro objeto (commit / tree / blob), y es suficiente para tomar los primeros caracteres hash únicos: 8640790949c12690fc71f9abadd7b57ec0539376 -> 8640790.


 git cat-file -p 8640790 

 100644 blob 7ab08294a46f158c51460be3e7df6a190e15023b .env.example 100644 blob 0a1a4d1ad9ff3f35b67678ca893811e91b423af5 .gemset 040000 tree 033aa38ce0eab11fe229067c14ccce95e2b8b601 .github 100644 blob ca49bb7ffa6273b0be4ce7ba1accba456032fb11 .gitignore 100644 blob c99d2e7396e14ac072c63ec8419d9b8fede28d86 .rspec 100644 blob 65e77a2f59f635a8f24eb4714e8e43745c5c0eb9 .rubocop.yml 100644 blob 8e8299dcc068356889b365e23c948b92c6dfcd78 .ruby-version 100644 blob 19028f9885948aca2ba61f9d062e9dc21c21ad03 .stylelintrc.json 100644 blob 2f7a032fbc3f4f7195bfd91cb33889a684b572b9 .travis.yml 100644 blob 121615722a6c206a9fe24b9a1c9b647662a460d2 ARCHITECTURE.md 100644 blob 898195daeea0bbf8c5930deeaf1020ba8abab34a Gemfile 100644 blob de7ca707f9fe9172db941b65cdacaba7e024fc06 Gemfile.lock 100644 blob e6ff62fefd071b1a8ca279bae94ddbc4dd17b7a3 Gruntfile.js 100644 blob 0cac5b30fb32d36cce2aeb7d936be7b6207d68c7 MIT-LICENSE.txt 100644 blob c2c566e8cc3d440d3ee8041b79cded416db28136 Procfile 100644 blob d1fb2f575380e1e093a4d82e3f19e51f0b99a0a1 Procfile.dev 100644 blob 3a88e138f10fa65bd2cfe1a1d3292348205508b5 README.md 100644 blob 5366e6e073cc426518894cc379d3a07cf3c9cfb3 Rakefile 100644 blob e6d3d2d3e9d5122c5f75bbeee8ed0917ad38c131 app.json 040000 tree 94f83cf03bd6f1cf14672034877b14604744b7a2 app 040000 tree d4d859e82564250b4c4f2047de21e089e7555475 bin 100644 blob 1f71007621f17334fd6f2dd71c87b7a16867119c config.ru 040000 tree 9e8e4bf5ec44541aefff544672b94ca8a9d07bbf config 040000 tree 31b8d0e1fa2bb789dbd6319e04fc9f115952cf2a db 040000 tree 38e7a13e0e772c2a13e46d2007e239f679045bee doc 040000 tree a6e35ded8b35837660cf786e637912377f845515 lib 040000 tree d564d0bc3dd917926892c55e3706cc116d5b165e log 100644 blob 843523565ddee5e00f580d9c4e37fc2478fdaecc package-lock.json 100644 blob 791ee833ad316d75b1d2c83a64a3053fc952d254 package.json 040000 tree 4645317c52675d9889f89b26f4dd4d2ae1d8cbad public 040000 tree 31d3f8ae4a4ffe62787134642743ed32a35dbae2 resources 040000 tree 807ffa29868ef9c25ddb4b4126a4bb7f1b041bf0 script 040000 tree 4c3bf9a7f3679ba059b0f1c214a500d197546462 spec 040000 tree 136c8174412345531a9542cafef25ce558d2664f test 040000 tree e6524eafe066819e4181bc56c503320548d8009b vendor 

Esta es en realidad la característica más importante de cómo funciona git, el identificador de confirmación es realmente un hash de su contenido. Al igual que los hashes de objetos incrustados en él (árboles, manchas).


Ahora veamos qué pasa cuando lo hacemos


 git commit -m "Fixed bug" 

Este comando crea una nueva confirmación que captura lo siguiente:


  • estado del proyecto de preparación (guardado como un nuevo objeto de árbol y su hash tomado)
  • enlace a la confirmación actual (principal)
  • autor + committer + dos fechas
  • comprometer texto

Todo esto se guarda, se procesa y se obtiene un nuevo objeto de confirmación. Y el equipo levanta automáticamente el puntero de la rama actual.


un poco sobre terminología

Como ya sabemos, el árbol es un objeto que contiene el estado del proyecto en un momento determinado en el pasado, cuando se creó una confirmación con este árbol.


La carpeta de trabajo se llama árbol de trabajo / copia de trabajo / directorio de trabajo, lo cual es bastante lógico.


También tenemos - área de preparación / índice - el área de cambios preparados. Pero lógicamente, esto también es un árbol , o más bien, el estado que se guarda al comprometerse como un árbol. Por lo tanto, me parece que sería más lógico llamar a un árbol en escena.



git commit-tree


Finalmente, podemos pasar a describir el comando git commit-tree que necesitamos. Formalmente, este es uno de los comandos de bajo nivel, por lo que rara vez se menciona y se usa. No consideraremos otros comandos de bajo nivel asociados con él (como git write-tree, git-update-index, también se conocen como comandos de plomería). Solo nos interesa una consecuencia particular: con este comando podemos copiar (reutilizar) fácilmente el árbol de estado del proyecto desde cualquier otra confirmación.


Mira su reto


 git commit-tree 4c835c2 -m "Fixed bug" -p a8fc5e3 

 d9aded78bf57ca906322e26883644f5f36cfdca5 

El comando git commit-tree también se compromete, pero de una manera de bajo nivel. Aquí debe especificar explícitamente el árbol (árbol) 4c835c2 ya existente y un enlace al compromiso principal a8fc5e3. Y devuelve el hash del nuevo commit d9aded7, y la posición de la rama no cambia (por lo tanto, este commit parece congelarse en el aire).



Parte práctica


En el siguiente repositorio simple se muestran ejemplos del uso de este comando.



Contiene tres ramas:


maestro - rama principal
alfa: la rama en la que trabajamos y somos
beta: una rama que anteriormente estaba detenida en master


Todas las acciones son fáciles de repetir localmente, para esto es suficiente clonar el repositorio, subir a la rama alfa y luego ejecutar los comandos de los ejemplos. Este estado inicial es común a todos los ejemplos.


 git clone https://github.com/capslocky/git-commit-tree-example.git cd ./git-commit-tree-example/ git checkout alpha 

debajo de ventanas

Todos los comandos, incluido el script, también funcionan en Windows. Solo necesita abrir el terminal bash en la carpeta del proyecto, por ejemplo, así


 "C:\Program Files\Git\git-bash.exe" --cd="D:\path\project" 


1. Sincronización con otra rama


Desafío:
Sincronice el estado del proyecto en la rama alfa con la rama beta . Es decir, debe crear una nueva confirmación en la rama alfa para que el estado del proyecto sea exactamente el mismo que en la rama beta .


Específicamente, es improbable que tal tarea surja, pero este es el caso más adecuado para demostrar el enfoque.


La solución más simple es tomar el árbol existente al que apunta la rama beta y solo señalarlo desde el nuevo commit para la rama alfa. Como este es el primer ejemplo, toda su lógica se considera con suficiente detalle.


Primero, encuentre el hash de confirmación señalado por la rama beta:


 git rev-parse origin/beta 

 280c30ff81a574f8dd41721726cf60b22fb2eced 

280c30f - solo toma los primeros caracteres


Ahora encuentre el hash de su árbol mostrando el contenido del commit a través de git cat-file:


 git cat-file -p 280c30f 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 560b449675513bc8f8f4d6cda56a922d4e36917a author Baur <atanov...@gmail.com> 1540619512 +0600 committer Baur <atanov...@gmail.com> 1540619512 +0600 Added info about windows 

3c1afe7 : este es el árbol que necesitamos


Y ahora crearemos una confirmación que apunte a este árbol, y con la confirmación principal indicaremos la confirmación actual:


 git commit-tree 3c1afe7 -m "Synced with branch 'beta'" -p HEAD 

 eb804d403d4ec0dbeee36aa09da706052a7cc687 

Eso es todo, el commit fue creado, el equipo consiguió su hash. Además, este valor siempre será único, ya que se calcula no solo desde el árbol, sino también desde el autor y el tiempo. El commit en sí está congelado en el aire, siempre que no entre en ninguna de las ramas. Es suficiente para nosotros tomar los primeros caracteres: eb804d4 , este valor , único para cada caso, lo designaré como xxxxxxx . Veamos su contenido:


 git cat-file -p xxxxxxx 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 64fafc79e8f6d22f5226490daa5023062299fd6c author Peter <peter...@gmail.com> 1545230299 +0600 committer Peter <peter...@gmail.com> 1545230299 +0600 Synced with branch 'beta' 

Genial, tiene el mismo árbol que el commit en la rama de origen / beta. Y dado que este commit es un descendiente directo de la rama actual, para incluirlo en la rama, simplemente haga una fusión de avance rápido


 git merge --ff xxxxxxx 

 Updating 64fafc7..xxxxxxx Fast-forward Azure.txt | 3 --- Bill.txt | 6 +----- Linus.txt | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) 

Listo Ahora el estado del proyecto en la rama alfa es exactamente el mismo que en la rama beta. [actualización] Y si observa lo que cambió este commit después de todo, veremos: invirtió todos sus propios commit (cambios) de la rama alfa y agregó todos los commit (cambios) únicos de la rama beta, en relación con su commit ancestral común.




2. Comparación de dos ramas


Desafío:
Compara la rama alfa con la rama beta .


El primer ejemplo muestra que la confirmación creada muestra todos los cambios que son la diferencia real entre las dos ramas. Esta propiedad facilita la comparación de una rama con otra. Es suficiente crear una tercera rama temporal y hacer una confirmación similar en ella.


Entonces, primero, devuelva la rama alfa a su estado original


 git reset --hard origin/alpha 

Creemos una rama temporal en la actual y párese sobre ella


 git checkout -b temp 

Y nos queda hacer lo mismo que en el ejemplo anterior. Pero esta vez nos encontraremos con una línea. Para hacer esto, usamos la sintaxis especial para acceder al árbol de confirmación origen / beta ^ {árbol} o al mismo 280c30f ^ {árbol} .


 git merge --ff $(git commit-tree origin/beta^{tree} -m "Diff with branch 'beta'" -p HEAD) 

Hecho, esencialmente nos materializamos como un commit diff entre dos ramas


 git show 

 git diff alpha origin/beta 

Por supuesto, podemos crear una confirmación "comparativa" para dos confirmaciones (estados) en el repositorio.




3. Rama inversa


Desafío:
Revierta las últimas confirmaciones.


Volvamos a la rama alfa y eliminemos la rama temporal


 git checkout alpha git branch -D temp 

Supongamos que necesitamos revertir las dos últimas confirmaciones en la rama alfa. Hay dos formas clásicas de hacer esto:


  1. Ejecute git revert dos veces - por confirmación
  2. git reset, es decir, restablecer la posición de la rama

Pero puedes hacer esto de una tercera manera:


 git merge --ff $(git commit-tree 7a714bf^{tree} -m "Reverted to commit 7a714bf" -p HEAD) 

Esto agregará una nueva confirmación que revierte los cambios de las dos confirmaciones anteriores. A diferencia del primer método, solo se crea una confirmación, incluso si necesita revertir las últimas diez confirmaciones. Y la diferencia entre el método con git reset es que no lanzamos estos commits desde la propia rama.


Además, si necesita devolver el estado original de la rama, esto se puede hacer de la misma manera


 git merge --ff $(git commit-tree 64fafc7^{tree} -m "Reverted back to commit 64fafc7" -p HEAD) 

Al mismo tiempo, estos dos commits permanecerán en la historia de la rama, de acuerdo con lo cual se verá que fue revertida y devuelta.




4. Parcial reverso


Desafío:
Revierta los cambios en algunos archivos en las últimas confirmaciones.


Nuevamente, devuelva la rama alfa a su estado original.


 git reset --hard origin/alpha 

La rama alfa contiene 3 confirmaciones, en cada una de las cuales se realizan cambios en el archivo Bill.txt, en la última confirmación, también se agrega el archivo Azure.txt. Supongamos que necesitamos revertir los cambios en el archivo Bill.txt para las últimas 2 confirmaciones, sin tocar ningún otro archivo.


Primero, revierta todos los archivos 2 confirma


 git merge --ff $(git commit-tree 7a714bf^{tree} -m "any text" -p HEAD) 

Luego, regrese la rama a la confirmación anterior, pero sin tocar el estado del proyecto en el disco


 git reset HEAD~1 

Y ahora es suficiente zasteydit archivos necesarios y confirmar, y otros cambios pueden descartarse.


 git add Bill.txt git commit -m "Reverted file Bill.txt to 7a714bf" git reset --hard HEAD 



5. Fusión artificial


Desafío:
Surge una rama en otra, obteniendo un resultado predeterminado.


Imagina esta situación. Se detectó un error crítico en la producción y, como de costumbre, debe repararse con urgencia. Sin embargo, no está claro cuánto tiempo llevará estudiarlo y realizar la revisión correcta, por lo que se realizó rápidamente una revisión temporal, que aisló la interacción con el módulo del problema. Por lo tanto, en la rama maestra, aparece una confirmación con este parche temporal, y después de un tiempo en lugar de hacerlo en la maestra, debe pisotear una revisión ya completa.


Por lo tanto, debemos fusionar la rama alfa en el maestro, pero esto no debería ser una fusión tradicional cuando todos los cambios únicos de la rama alfa se agregan al maestro desde arriba y hay un conflicto, y debemos sobrescribir completamente el maestro con la rama alfa.


Para comenzar, recordemos de qué se trata la confirmación de fusión: en realidad es la misma confirmación ordinaria, pero solo tiene dos confirmaciones principales, esto es claramente visible si observa su contenido (cómo se forma su árbol es un tema separado) . Y quién está determinado por quién es simple: el primer compromiso principal se considera el principal.


 git cat-file -p 7229df8 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a parent fd54ab7dde87593b9892b6d1ffbf1afd39ba6f9e parent 280c30ff81a574f8dd41721726cf60b22fb2eced author Baur <atanov...@gmail.com> 1540619579 +0600 committer Baur <atanov...@gmail.com> 1540619592 +0600 Merge branch 'beta' into 'master' 

Restablezca la rama alfa actual y cambie a maestro


 git reset --hard origin/alpha git checkout master 

Y ahora el mismo equipo, pero con dos padres comprometidos


 git merge --ff $(git commit-tree alpha^{tree} -m "Merge 'alpha' into 'master', but take 'alpha' tree" -p HEAD -p alpha) 

Hecho, organizamos la rama alfa en master, y no tuvimos que eliminar el código temporal y resolver conflictos, ya que en este caso solo tuvimos que reescribir los últimos cambios.



En realidad, no es tan extraño crear una fusión con un árbol que se copia de otra confirmación. Tales situaciones pueden surgir porque git es una herramienta muy flexible que le permite implementar una variedad de enfoques para trabajar con sucursales y repositorios. Pero aún así, el ejemplo más común estuvo en nuestro repositorio desde el principio: intente analizarlo usted mismo o abra un spoiler para leer la explicación.


spoiler

Prestemos atención a cómo la rama beta fue estrangulada de nuevo a master. Durante el tiempo en que aparecieron dos commits, no hubo nuevos commits en la rama maestra misma. Esto significa que con la fusión beta en master, cualquier conflicto se excluye debido a cambios simultáneos.




Si hiciéramos git merge beta, se produciría una fusión de avance rápido (comportamiento predeterminado ), es decir, la rama maestra simplemente estaría en el mismo commit que la rama beta, y no habría commit de fusión. Sería así:



Pero aquí no se realizó una fusión de avance rápido utilizando el comando git merge beta --no-ff. Es decir, forzamos la creación del commit de fusión, aunque no fue necesario. Y dado que se conocía el estado final deseado del proyecto para la futura fusión: este es un árbol beta, git simplemente copió el enlace a este árbol en una nueva confirmación:


 git cat-file -p origin/beta 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 560b449675513bc8f8f4d6cda56a922d4e36917a author Baur <atanov...@gmail.com> 1540619512 +0600 committer Baur <atanov...@gmail.com> 1540619512 +0600 Added info about windows 

 git cat-file -p 7229df8 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent fd54ab7dde87593b9892b6d1ffbf1afd39ba6f9e parent 280c30ff81a574f8dd41721726cf60b22fb2eced author Baur <atanov...@gmail.com> 1540619579 +0600 committer Baur <atanov...@gmail.com> 1540619592 +0600 Merge branch 'beta' into 'master' 


6a. Método de rebase mediante combinación - descripción


Desafío:
Es necesario hacer una rama de rebase "pesada" (muchos conflictos en diferentes commits).


Hay un tema holivar tan clásico en git: rebase vs merge. Pero no voy a holivarit. Por el contrario, hablaré sobre cómo pueden hacerse amigos en el contexto de esta tarea.


En general, git ha sido diseñado específicamente para que podamos fusionarnos de manera efectiva. Y cuando llegué al proyecto donde el flujo de trabajo se basa en rebase, la primera vez me sentí incómodo e inusual, hasta que desarrollé técnicas que simplificaron mi trabajo diario con git. Uno de ellos es mi método original para hacer rebase pesado.


Por lo tanto, tenemos que cambiar la base de la rama alfa en el desarrollo, para que luego se tiñe tan bien como la rama beta. Si comenzamos a rebase como de costumbre, la primera y la última confirmación producirán dos conflictos diferentes en dos lugares diferentes. Pero si en lugar de rebase hiciéramos una fusión, solo habría un conflicto en un lugar en una confirmación de fusión.


Si quieres asegurarte de esto, ofrezco equipos listos bajo el spoiler.


Texto oculto

Devolver las ramas a su estado original.


 git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha 

Cree y párese en la rama de conflictos alfa-rebase y rebase en maestro


 git checkout -b alpha-rebase-conflicts git rebase master 

Habrá conflictos en varios commits, incluido un conflicto fantasma.


Ahora intentemos la fusión, regresemos a la rama alfa y eliminemos la rama para el rebase.


 git checkout alpha git branch -D alpha-rebase-conflicts 

Cambiar a maestro y hacer fusión


 git checkout master git merge alpha 

Solo habrá un conflicto simple, lo corregimos y hacemos


 git add Bill.txt git commit -m "Merge branch 'alpha' into 'master'" 

Marge completó con éxito.


Los conflictos de Git son una parte natural de nuestras vidas, y este simple ejemplo muestra que la fusión es definitivamente más conveniente que la rebase en este sentido. En un proyecto real, esta diferencia se mide por una cantidad mucho mayor de tiempo y nervios invertidos. Por lo tanto, por ejemplo, hay una recomendación ambigua de aplastar todas las confirmaciones de una rama de características en una confirmación antes de la fusión.


La idea de este método es hacer una fusión oculta temporal en la que resolveremos todos los conflictos a la vez. Recuerda el resultado (árbol). A continuación, ejecute el rebase habitual, pero con la opción "resolver conflictos automáticamente, eligiendo nuestros cambios". Y al final, agregue una confirmación adicional a la rama, que restaurará el árbol correcto.


Empecemos Nuevamente, devuelva ambas ramas a su estado original.


 git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha 

Creemos una rama temporal temporal en la que haremos una fusión.


 git checkout -b temp git merge origin/master 

El conflicto


Resolvamos un conflicto simple en el archivo Bill.txt como de costumbre (en cualquier editor).
Tenga en cuenta que solo hay un conflicto, y no dos, como con rebase.


 git add Bill.txt git commit -m "Merge branch 'origin/master' into 'temp'" 

Regresamos a la rama alfa, realizamos un rebase con resolución automática de todos los conflictos a nuestro favor, llevamos la rama temporal al estado y eliminamos la rama temporal en sí.


 git checkout alpha git rebase origin/master -X theirs git merge --ff $(git commit-tree temp^{tree} -m "Fix after rebase" -p HEAD) git branch -D temp 


Finalmente, bellamente mergim alpha en master.


 git checkout master git merge alpha --no-ff --no-edit 


Tenga en cuenta que master, alpha y la rama temporal remota los tres apuntan al mismo árbol, aunque estos son tres commits diferentes.


Contras de este método:


  • No hay corrección manual de cada confirmación de conflicto: los conflictos se resuelven automáticamente. Tal confirmación intermedia puede no compilarse.
  • Se agregó (pero no siempre) un compromiso adicional en cada rebase

Pros:


  • Solo arreglamos conflictos reales (sin conflictos fantasmas)
  • Todos los conflictos se arreglan solo una vez.
  • Los dos primeros puntos ahorran tiempo
  • Se guarda un historial completo de confirmaciones y todos los cambios (por ejemplo, puede hacer una selección de cereza)
  • El método se implementa en forma de secuencia de comandos y siempre se puede utilizar para volver a crear una base si es necesario (no requiere ningún conocimiento sobre árboles, etc.)


6b. Método de rebase a través de fusión - script


El script se publica aquí: https://github.com/capslocky/git-rebase-via-merge


Vamos a ver su trabajo en nuestro ejemplo. Nuevamente, devuelva ambas ramas a su estado original.


 git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha 

Descargue el script y hágalo ejecutable


 curl -L https://git.io/rebase-via-merge -o ~/git-rebase-via-merge.sh chmod +x ~/git-rebase-via-merge.sh 

ventanas

El archivo aparecerá aquí: C: \ Users \ user-name \ git-rebase-via-merge.sh


Cambie la rama predeterminada para la que necesita rebase, en nuestro caso necesitamos origen / maestro


 nano ~/git-rebase-via-merge.sh 

 default_base_branch='origin/master' 

También creemos y nos paremos en una rama temporal para no tocar la rama alfa misma


 git checkout -b alpha-rebase-test 

Y ahora puede ejecutar el script (en lugar del tradicional git rebase origin / master)


 ~/git-rebase-via-merge.sh 


resultado del guion
 $ ~/git-rebase-via-merge.sh This script will perform rebase via merge. Current branch: alpha-rebase-test (64fafc7) Base branch: origin/master (9c6b60a) Continue (c) / Abort (a) c Auto-merging Bill.txt CONFLICT (content): Merge conflict in Bill.txt Automatic merge failed; fix conflicts and then commit the result. You have at least one merge conflict. Fix all conflicts in the following files, stage them up and type 'c': Bill.txt Continue (c) / Abort (a) c [detached HEAD 785d49e] Hidden temp commit to save result of merging 'origin/master' into 'alpha-rebase-test' as detached head. Merge succeeded on hidden commit: 785d49e Starting rebase automatically resolving any conflicts in favor of current branch. First, rewinding head to replay your work on top of it... Auto-merging Bill.txt [detached HEAD a680316] Added history of windows Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 11:45:50 2018 +0600 1 file changed, 6 insertions(+), 3 deletions(-) Committed: 0001 Added history of windows Auto-merging Bill.txt [detached HEAD dcd34a8] Replaced history of windows Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 11:55:42 2018 +0600 1 file changed, 4 insertions(+), 5 deletions(-) Committed: 0002 Replaced history of windows Auto-merging Bill.txt [detached HEAD 8d6d82c] Added file about Azure and info about Windows 10 Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 12:06:27 2018 +0600 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Azure.txt Committed: 0003 Added file about Azure and info about Windows 10 All done. Restoring project state from hidden merge with single additional commit. Updating 8d6d82c..268b320 Fast-forward Bill.txt | 4 ++++ 1 file changed, 4 insertions(+) Done. 


 ~/git-rebase-via-merge.sh origin/develop 

, ours / theirs :


ours — (HEAD)
theirs — (, origin/develop)


rebase — .



7.


git .


.


 git config alias.copy '!git merge --ff $(git commit-tree ${1}^{tree} -p HEAD -m "Tree copy from ${1}")' 

git copy xxx, xxx — .


 git copy xxx 


 git merge --ff $(git commit-tree xxx^{tree} -p HEAD -m "Tree copy from xxx") 


 git copy a8fc5e3 

 git copy origin/beta 

 git copy HEAD~3 

git amend.


 git commit --amend -m "Just for test" 

:


 git commit --amend 



, , . , . — . , , . . " " " " . ( , devops), , .

Source: https://habr.com/ru/post/es433748/


All Articles