strategy - git branch, fork, fetch, merge, rebase y clon, ¿cuáles son las diferencias?
github what is a branch (5)
¿Puede alguien ayudarme a entender la diferencia entre una rama, un tenedor y un clon en Git?
Del mismo modo, ¿qué significa cuando hago un git fetch
en lugar de un git pull
?
Además, ¿qué significa rebase
en comparación con la merge
?
¿Cómo puedo aplastar los compromisos individuales?
¿Cómo se usan, por qué se usan y qué representan?
¿Cómo figura GitHub en?
Git
Mi respuesta incluye github, ya que muchas personas han preguntado sobre eso también.
Repositorios locales
git (localmente) tiene un directorio (.git) en el que confirma sus archivos y este es su "repositorio local". Esto es diferente de los sistemas como svn donde se agrega y confirma inmediatamente en el repositorio remoto.
git almacena cada versión de un archivo que cambia al guardar el archivo completo. También es diferente de svn a este respecto, ya que podría ir a cualquier versión individual sin ''recrearla'' a través de cambios delta.
git no ''bloquea'' archivos en absoluto y, por lo tanto, evita la funcionalidad ''bloqueo exclusivo'' para una edición (los sistemas más antiguos como pvcs vienen a la mente), por lo que todos los archivos siempre pueden editarse, incluso cuando están fuera de línea. En realidad, hace un trabajo increíble al combinar los cambios de archivos (¡dentro del mismo archivo!) Durante las extracciones o las recuperaciones / empujes a un repositorio remoto como github. La única vez que necesita hacer cambios manuales (en realidad, editar un archivo) es si dos cambios involucran la misma línea (s) de código.
Ramas
Las sucursales le permiten conservar el código principal (la rama ''maestra''), hacer una copia (una nueva rama) y luego trabajar dentro de esa nueva rama. Si el trabajo toma un tiempo o el maestro recibe muchas actualizaciones desde que se realizó la sucursal, se debe realizar la fusión o la rebasación (a menudo preferible para un mejor historial y una resolución más sencilla de los conflictos) con la rama maestra. Cuando haya terminado, vuelva a combinar los cambios realizados en la rama en el repositorio principal. Muchas organizaciones usan sucursales para cada trabajo, ya sea una característica, un error o un elemento de tarea. Otras organizaciones solo usan sucursales para cambios importantes como las actualizaciones de versión. Bifurcación: con una rama, usted controla y administra la rama, mientras que con una bifurcación, otra persona controla el aceptar el código nuevamente.
En términos generales, hay dos enfoques principales para hacer ramas. La primera es mantener la mayoría de los cambios en la rama maestra, solo usar ramas para cosas más grandes y de mayor ejecución, como los cambios de versión, donde desea tener dos sucursales disponibles para diferentes necesidades. La segunda es que básicamente hace una rama para cada solicitud de función, corrección de errores o tarea y luego decide manualmente cuándo fusionar esas ramas en la rama principal principal. Aunque esto suena tedioso, este es un enfoque común y es el que actualmente utilizo y recomiendo porque esto mantiene a la rama maestra más limpia y es la maestra que promovemos a la producción, por lo que solo queremos el código completo y probado, a través de la rebasación y fusión de ramas.
La forma estándar de llevar una rama "en" al maestro es hacer una merge
. Las ramas también se pueden rebase
para "limpiar" la historia. No afecta el estado actual y se hace para dar un historial "más limpio". Básicamente, la idea es que bifurcaste desde un cierto punto (generalmente desde el maestro). Desde que se ramificó el ''maestro'' mismo ha avanzado. Así que sería más limpio si todos los cambios que hiciste en una rama se jugaran contra el maestro más reciente con todos sus cambios. Entonces el proceso es: guardar los cambios; obtén el "nuevo" maestro, y luego vuelve a aplicar los cambios contra eso. Tenga en cuenta que la rebase, al igual que la fusión, puede dar lugar a conflictos que debe resolver (editar) manualmente.
Una ''directriz'' a tener en cuenta: ¡ Rebase solo si la sucursal es local y aún no la ha movido al control remoto! Esto se debe principalmente a que la reorganización puede alterar la historia que otras personas ven, lo que puede incluir sus propios compromisos.
Rastreo de sucursales
Estas son las ramas que se denominan origin / branch_name (a diferencia de solo branch_name). Cuando está presionando y tirando del código a / desde repositorios remotos, este es realmente el mecanismo a través del cual sucede. Por ejemplo, cuando git push
una rama llamada ''building_groups'', tu rama va primero a origin / building_groups y luego va al repositorio remoto (en realidad eso es una simplificación excesiva, pero es suficiente por ahora). De manera similar, si realiza un git fetch building_groups
el archivo que se recupera se colocará en su rama origin / building_groups. Luego puede elegir fusionar esta rama en su copia local. Nuestra práctica es hacer siempre una búsqueda de git y una combinación manual en lugar de solo una extracción de git (que hace las dos cosas en un solo paso).
Fetch
nuevas ramas.
Obtención de nuevas ramas: En el punto inicial de un clon tendrás todas las ramas. Sin embargo, si otros desarrolladores agregan sucursales y las empujan al control remoto, debe haber una forma de "saber" sobre esas sucursales y sus nombres para poder derribarlas localmente. Esto se realiza a través de un git fetch
que obtendrá todas las ramas nuevas y modificadas en el repositorio local utilizando las ramas de seguimiento (por ejemplo, origen /). Una vez fetch
, se puede git branch --remote
para enumerar las ramas de seguimiento y git checkout [branch]
para cambiar realmente a una determinada.
Fusionando
Fusionar es el proceso de combinar cambios de código de diferentes sucursales, o de diferentes versiones de la misma rama (por ejemplo, cuando una rama local y remota no están sincronizadas). Si uno ha desarrollado un trabajo en una rama y el trabajo está completo, listo y probado, entonces se puede fusionar en la rama master
. Esto se realiza mediante git checkout master
para cambiar a la rama master
, luego git merge your_branch
. La fusión traerá todos los archivos diferentes e incluso diferentes cambios a los mismos archivos juntos. Esto significa que realmente cambiará el código dentro de los archivos para fusionar todos los cambios. Al realizar la checkout
del master
, también se recomienda hacer un git pull origin master
para obtener la última versión del maestro remoto fusionado en su maestro local. Si el maestro remoto cambió, es decir, si moved forward
, verá información que refleja eso durante ese git pull
. Si ese es el caso (maestro cambiado), se le recomienda que git checkout your_branch
y luego lo rebase
al maestro para que sus cambios se "repitan" en la parte superior del maestro "nuevo". Luego continuaría con la actualización del master como se muestra en el siguiente párrafo.
Si no hay conflictos, entonces el maestro tendrá los nuevos cambios agregados. Si hay conflictos, esto significa que los mismos archivos tienen cambios alrededor de líneas de código similares que no pueden fusionarse automáticamente. En este caso, git merge new_branch
informará que hay conflictos que resolver. Los "resuelve" editando los archivos (que tendrán ambos cambios), seleccionando los cambios que desea, eliminando literalmente las líneas de los cambios que no desea y luego guardando el archivo. Los cambios están marcados con separadores como ========
y <<<<<<<<
Una vez que haya resuelto cualquier conflicto, una vez más git add
y git commit
esos cambios para continuar la fusión (obtendrá comentarios de git durante este proceso para guiarlo). Cuando el proceso no funciona bien, encontrarás que git merge --abort
es muy útil para restablecer las cosas.
Rebasado interactivo y aplastamiento / reordenamiento / eliminación de compromisos
Si ha trabajado en muchos pasos pequeños, por ejemplo, si confirma el código como ''trabajo en progreso'' todos los días, es posible que desee "aplastar" esas muchas y pequeñas confirmaciones en unas pocas confirmaciones más grandes. Esto puede ser particularmente útil cuando desea hacer revisiones de código con colegas. No desea volver a reproducir todos los ''pasos'' que tomó (a través de confirmaciones), solo quiere decir que aquí está el efecto final (dif) de todos mis cambios para este trabajo en una confirmación. El factor clave a evaluar cuando se considera si hacer esto es si las confirmaciones múltiples son contra el mismo archivo o archivos más de una vez (es mejor aplastar las confirmaciones en ese caso). Esto se hace con la herramienta interactiva de rebasado. Esta herramienta le permite aplastar confirmaciones, eliminar confirmaciones, reformular mensajes, etc. Por ejemplo, git rebase -i HEAD~10
Tenga en cuenta que ~
NO a -
muestra lo siguiente:
Tenga cuidado y use esta herramienta ''cautelosamente''. Haga un squash / delete / reordenar a la vez, salga y guarde ese commit, luego vuelva a ingresar a la herramienta. Si los compromisos no son contiguos, puede reordenarlos (y luego aplastarlos según sea necesario). En realidad, también puede eliminar las confirmaciones aquí, ¡pero realmente necesita estar seguro de lo que está haciendo cuando hace eso!
tenedores
Hay dos enfoques principales para la colaboración en los repositorios git. El primero, detallado anteriormente, es directamente a través de las sucursales que las personas tiran y empujan desde / hacia. Estos colaboradores tienen sus claves ssh registradas en el repositorio remoto. Esto les permitirá empujar directamente a ese repositorio. El inconveniente es que tienes que mantener la lista de usuarios. El otro enfoque, el de bifurcar, le permite a cualquiera "bifurcar" el repositorio, básicamente haciendo una copia local en su propia cuenta del repositorio git. Luego, pueden realizar cambios y, cuando terminen, envían una "solicitud de extracción" (en realidad, se trata más bien de una "inserción" de ellos y de una solicitud de "extracción" para el mantenedor del repositorio real) para que el código sea aceptado.
Este segundo método, mediante el uso de bifurcaciones, no requiere que alguien mantenga una lista de usuarios para el repositorio.
Github
github (un repositorio remoto) es una fuente remota a la que normalmente presiona y extrae los cambios confirmados si tiene (o se agrega a) dicho repositorio, por lo que local y remoto son realmente distintos. Otra forma de pensar en un repositorio remoto es que es una estructura de directorio .git que vive en un servidor remoto.
Cuando ''bifurca'' - en la interfaz gráfica de usuario de github puede hacer clic en - creas una copia (''clon'') del código en tu cuenta de github. Puede ser un poco sutil la primera vez que lo haces, así que asegúrate de ver en qué repositorio se encuentra una base de código, ya sea el propietario original o ''bifurcado de'' y tú, por ejemplo
Una vez que tenga la copia local, puede hacer los cambios que desee (tirando de ellos y empujándolos hacia una máquina local). Cuando haya terminado, envíe una ''solicitud de extracción'' al propietario / administrador del repositorio original (suena elegante, pero en realidad simplemente hace clic en esto: - ) y lo "tiran".
Más común para un equipo que trabaja en código juntos es "clonar" el repositorio (haga clic en el icono "copiar" en la pantalla principal del repositorio). Luego, escriba localmente git clone [pegar]. Esto lo configurará localmente y también puede empujar y jalar a la ubicación github (compartida).
Clones
Como se indica en la sección sobre github, un clon es una copia de un repositorio. Cuando tiene un repositorio remoto, emite el comando git clone contra su URL y luego termina con una copia local o clon del repositorio. Este clon tiene todo , los archivos, la rama maestra, las otras ramas, todas las confirmaciones existentes, todo el shebang. Es este clon el que hace sus agregados y compromisos contra, y luego el repositorio remoto en sí mismo es a lo que usted presiona esos compromisos. Es este concepto local / remoto el que hace de git (y sistemas similares a este, como Mercurial) un DVCS (Sistema de Control de Versiones Distribuidas ) en lugar de los CVS más tradicionales (Sistemas de Control de Versiones de Códigos) como SVN, PVCS, CVS, etc. te comprometes directamente al repositorio remoto.
Visualización
La visualización de los conceptos centrales se puede ver en
http://marklodato.github.com/visual-git-guide/index-en.html y
http://ndpsoftware.com/git-cheatsheet.html#loc=index
Si desea una visualización de cómo funcionan los cambios, no puede vencer a la herramienta visual gitg (gitx para mac) con una interfaz gráfica de usuario que llamo ''el mapa del metro'' (especialmente el metro de Londres), excelente para mostrar quién lo hizo. Qué, cómo cambian las cosas, divergen y se fusionan, etc.
¡También puedes usarlo para agregar, confirmar y administrar tus cambios!
Aunque gitg / gitx es bastante mínimo, en los últimos 2-3 años (2009-2012) el número de herramientas de GUI continúa aumentando. Muchos usuarios de Mac usan la bifurcación de Brotherbard de gitx y para Linux una gran opción es smart-git con una interfaz intuitiva pero potente:
Tenga en cuenta que incluso con una herramienta de interfaz gráfica de usuario, probablemente hará muchos comandos en la línea de comandos.
Para esto tengo los siguientes alias en mi archivo ~ / .bash_aliases (que se llama desde mi archivo ~ / .bashrc para cada sesión de terminal:
# git
alias gst=''git status'' # Warning: gst conflicts with gnu-smalltalk (when used).
alias gb=''git branch''
alias gco=''git checkout''
alias gcob=''git checkout -b ''
alias ga=''git add ''
alias gc=''git commit''
alias gg=''git grep '' # A great very FAST search option, easier then `find`
Finalmente, 6 salvavidas clave:
1) Usted arruina su sucursal local y simplemente desea volver a lo que tuvo la última vez que hizo un truco de git:
git reset --hard origin/master # You will need to be comfortable doing this!
2) Comienzas a hacer cambios localmente, editas media docena de archivos y luego, oh mierda, todavía estás en la rama maestra (u otra):
git checkout -b new_branch_name # just create a new branch
git add . # add the changes files
git commit -m"your message" # and commit them
3) Usted arruina un archivo en particular en su rama actual y básicamente quiere "restablecer" ese archivo (perder cambios) a cómo fue la última vez que lo extrajo del repositorio remoto: git checkout your/directories/filename
Esto realmente restablece el archivo (como muchos otros comandos de git, no está bien nombrado por lo que hace aquí).
4) Realiza algunos cambios a nivel local, desea asegurarse de no perderlos mientras realiza un restablecimiento o rebase de git: a menudo hago una copia manual de todo el proyecto ( cp -r ../my_project ~/
) cuando No estoy seguro de si podría estropearme en Git o perder cambios importantes.
5) Estás rebasando pero las cosas se complican:
git rebase --abort # To abandon interactive rebase and merge issues
6) Agregue su rama git a su indicador de PS1 (consulte https://unix.stackexchange.com/a/127800/10043 ), por ejemplo
La rama es selenium_rspec_conversion
Aquí está la imagen de Oliver Steele de cómo encaja todo:
Solo para agregar a los demás, una nota específica para forking.
Es bueno darse cuenta de que, técnicamente, clonar el repositorio y forking el repositorio son lo mismo. Hacer:
git clone $some_other_repo
y puedes hacer tapping en la parte posterior --- acabas de bifurcar algún otro repo.
Git, como VCS, en realidad se trata de clonar la bifurcación. Aparte de "solo navegar" con una interfaz de usuario remota como cgit, hay muy poco que ver con el repositorio de git que no implica la clonación del repositorio en algún momento.
Sin embargo,
cuando alguien dice que bifurcé el repositorio X , significa que han creado un clon del repositorio en otro lugar con la intención de exponerlo a otros, por ejemplo, para mostrar algunos experimentos, o para aplicar diferentes mecanismos de control de acceso (por ejemplo, para permitir que las personas sin Acceso a Github pero con cuenta interna de la empresa para colaborar).
Hechos que: el repositorio es probablemente creado con otro comando que no sea
git clone
, que probablemente esté alojado en algún lugar en un servidor en lugar de la computadora portátil de alguien, y probablemente tenga un formato ligeramente diferente (es un "repositorio simple", es decir, sin trabajar árbol) son todos detalles técnicos.El hecho de que probablemente contenga diferentes conjuntos de ramas, etiquetas o confirmaciones es, probablemente, la razón por la que lo hicieron en primer lugar.
(Lo que Github hace cuando hace clic en "bifurcación", es simplemente la clonación con azúcar agregada: clona el repositorio por usted, lo coloca en su cuenta, registra el "bifurcado de" en algún lugar, agrega el control remoto llamado "upstream", y lo más importante, juega la bonita animación.)
Cuando alguien dice que cloné el repositorio X , significa que han creado un clon del repositorio localmente en su computadora portátil o computadora de escritorio con la intención de estudiarlo, jugar con él, contribuir con él o construir algo a partir del código fuente.
La belleza de Git es que hace que todo se ajuste perfectamente: todos estos repos comparten la parte común de la cadena de confirmación de bloque , por lo que es posible fusionar los cambios de manera segura entre todos estos repos cuando lo considere oportuno.
Nota: "de forma segura" siempre que no reescribas la parte común de la cadena, y siempre que los cambios no sean conflictivos.
Un clon es simplemente una copia de un repositorio. En la superficie, su resultado es equivalente a svn checkout
, donde se descarga el código fuente de otro repositorio. La diferencia entre VCS centralizado como Subversion y DVCS como Git es que en Git, cuando clonas, en realidad estás copiando todo el repositorio fuente, incluyendo todo el historial y las ramas. Ahora tienes un nuevo repositorio en tu máquina y cualquier confirmación que hagas entra en ese repositorio. Nadie verá ningún cambio hasta que empuje esos compromisos a otro repositorio (o al original) o hasta que alguien saque los compromisos de su repositorio, si es de acceso público.
Una rama es algo que está dentro de un repositorio. Conceptualmente, representa un hilo de desarrollo. Por lo general, tiene una rama maestra, pero también puede tener una rama en la que está trabajando en alguna característica xyz, y otra para corregir el error abc. Cuando haya retirado una sucursal, cualquier confirmación que realice permanecerá en esa sucursal y no se compartirá con otras sucursales hasta que las fusione o las vuelva a colocar en la sucursal en cuestión. Por supuesto, Git parece un poco extraño cuando se trata de sucursales hasta que se observa el modelo subyacente de cómo se implementan las sucursales. En lugar de explicarlo yo mismo (ya lo he dicho demasiado, me parece), lo vincularé a la explicación de "informática" de cómo Git modela las ramas y los compromisos, tomada del sitio web de Git:
http://eagain.net/articles/git-for-computer-scientists/
Un tenedor no es realmente un concepto de Git, es más una idea política / social. Es decir, si algunas personas no están contentas con la forma en que se está desarrollando un proyecto, pueden tomar el código fuente y trabajar en él por separado de los desarrolladores originales. Eso sería considerado un tenedor. Git facilita el bifurcación porque todos ya tienen su propia copia "maestra" del código fuente, por lo que es tan simple como cortar lazos con los desarrolladores del proyecto original y no requiere exportar el historial desde un repositorio compartido como usted podría tener que ver con SVN .
EDITAR: ya que no estaba al tanto de la definición moderna de "fork" utilizada por sitios como GitHub, por favor, mire los comentarios y también la respuesta de Michael Durrant debajo de la mía para obtener más información.
Tenedor Vs. Clon - dos palabras que significan copia
Por favor vea este diagram. (Originalmente de http://www.dataschool.io/content/images/2014/Mar/github1.png ).
.-------------------------. 1. Fork .-------------------------.
| Your GitHub repo | <-------------- | Joe''s GitHub repo |
| github.com/you/coolgame | | github.com/joe/coolgame |
| ----------------------- | 7. Pull Request | ----------------------- |
| master -> c224ff7 | --------------> | master -> c224ff7 (c) |
| anidea -> 884faa1 (a) | | anidea -> 884faa1 (b) |
''-------------------------'' ''-------------------------''
| ^
| 2. Clone |
| |
| |
| |
| |
| | 6. Push (anidea => origin/anidea)
v |
.-------------------------.
| Your computer | 3. Create branch ''anidea''
| $HOME/coolgame |
| ----------------------- | 4. Update a file
| master -> c224ff7 |
| anidea -> 884faa1 | 5. Commit (to ''anidea'')
''-------------------------''
(a) - after you have pushed it
(b) - after Joe has accepted it
(c) - eventually Joe might merge ''anidea'' (make ''master -> 884faa1'')
Tenedor
- Una copia a su repositorio remoto (nube) que lo vincula a Joe''s
- A continuación, puede copiar una copia a su repositorio local y F *% $ - hasta
- Cuando hayas terminado, puedes retroceder hasta tu control remoto.
- Luego puede preguntarle a Joe si quiere usarlo en su proyecto haciendo clic en la solicitud de extracción
Clon
- una copia a su repositorio local (disco duro)