6 puntos por GN⁺ 2023-11-03 | 1 comentarios | Compartir por WhatsApp
  • Incluso usando Git durante mucho tiempo, hay mucha superposición y reutilización de términos que confunden, así que memorizar comandos no basta para predecir cómo va a comportarse realmente
  • Palabras y símbolos como HEAD, heads, detached HEAD, ours/theirs, ../... cambian de significado según el contexto
  • index, staged y cached están todos conectados con .git/index, pero reset, revert y restore, pese a tener nombres parecidos, afectan de forma distinta al historial de commits, al árbol de trabajo y a los punteros de ramas
  • Que main haga tracking de un remoto y una remote-tracking branch como origin/main son cosas distintas, y checkout mete en un solo comando tanto el cambio de rama como la restauración de archivos
  • Para entender Git, más que mirar comandos individuales, hay que ver también el modelo interno en el que se acoplan ramas, referencias, commits, el índice y el estado de seguimiento remoto

HEAD, ramas y detached HEAD

  • En Git, heads se refiere a las ramas, y a nivel interno las ramas se guardan en el directorio .git/refs/heads
    • El glosario oficial de Git distingue entre branch como todos los commits sobre ella y head como el commit más reciente, pero puede verse como dos formas de mirar el mismo objeto
  • HEAD apunta a la rama actual y se guarda en .git/HEAD
    • La frase “head es una rama y HEAD es la rama actual” muestra bastante bien lo confusa que puede ser la terminología de Git
  • El estado detached HEAD es cuando HEAD no apunta a una rama sino directamente a un ID de commit
    • Si haces checkout de una etiqueta, como una etiqueta no es una rama, puedes terminar en detached HEAD
    • En este estado git pull no funciona, y git push tampoco salvo que se use de una forma especial
    • git commit, git merge, git rebase y git cherry-pick sí se pueden usar, pero los nuevos commits pueden quedar desconectados de cualquier rama y volverse difíciles de encontrar
    • Puedes salir del estado detached HEAD creando una rama nueva o cambiando a una rama existente

ours y theirs cambian entre merge y rebase

  • Al resolver conflictos, git checkout --ours file.txt elige el archivo del lado “ours”, pero el punto de referencia en merge y rebase no es el mismo
  • En merge, la rama actual es ours y la rama que se incorpora es theirs
    • Ejemplo: si ejecutas git checkout merge-into-ours y luego git merge from-theirs, la rama actual será ours
  • En rebase, la rama actual es theirs y la rama objetivo del rebase es ours
    • Ejemplo: si ejecutas git checkout theirs y luego git rebase ours, la rama objetivo será ours
  • Esta diferencia está relacionada con que git rebase main internamente va fusionando repetidamente los commits de la rama actual sobre una copia de la rama main
  • ourstheirs explica brevemente la terminología ours y theirs
    • En VSCode, “current change” e “incoming change” también pueden confundir de la misma manera

Mensajes de estado remoto y fast-forward

  • Your branch is up to date with 'origin/main' no significa que main esté al día con el estado más reciente del remoto
    • Significa que tu rama local y origin/main son iguales según el último git fetch o git pull
    • Si el último fetch fue hace 5 días, entonces está “actualizada” según lo que sabías hace 5 días
  • Git guarda en el reflog información sobre cuándo se hizo el fetch más reciente, pero el mensaje de estado no muestra el tiempo “según el último fetch”
  • can be fast-forwarded significa que la rama remota va por delante de la local y que en local no hay commits adicionales, así que solo hace falta mover el puntero hacia adelante
    • Ejemplo: si main es A-B-C y origin/main es A-B-C-D-E, después de git pull ambas quedan en A-B-C-D-E
    • En este caso no puede haber conflictos de merge
  • Cuando no se puede hacer fast-forward es porque ambas ramas se han bifurcado
    • Ejemplo: si main tiene un commit X que no existe en origin/main, y origin/main tiene D y E que no están en main, entonces no se puede hacer fast-forward
    • En ese caso Git muestra que las dos ramas están diverged y que cada una tiene una cantidad distinta de commits

Sintaxis para seleccionar commits: ^, ~, .., ...

  • HEAD^ y HEAD~ apuntan ambos al commit inmediatamente anterior
    • HEAD^^^, HEAD~~~ y HEAD~3 apuntan todos al commit de hace 3 pasos
  • En commits de merge, donde hay varios padres, el significado de HEAD^2 y HEAD^3 cambia
    • HEAD^ es el primer padre
    • HEAD^2 es el segundo padre
    • HEAD^3 es el tercer padre
    • HEAD~3 significa padre del padre del padre, así que no es lo mismo que HEAD^3
  • git log main..test y git log main...test también funcionan de manera distinta
    • main..test muestra los commits que solo están en test
    • test..main muestra los commits que solo están en main
    • main...test muestra los commits exclusivos de ambos lados
  • En git diff, .. y ... se interpretan distinto que en git log
    • git diff test..main compara incluyendo tanto los cambios del lado de test como los del lado de main
    • git diff test...main compara el ancestro común con la punta de main, así que muestra un diff de un solo lado
  • La confusión con la notación de puntos también se trata con más detalle en pain in dots

reference, refspec, tree-ish

  • En Git, reference se usa con varios significados
    • Ramas y etiquetas como main, v0.2
    • HEAD, que apunta a la rama actual
    • Expresiones como HEAD^^^, que se interpretan como IDs de commit
  • La documentación de Git llama estrictamente “revision parameters” a expresiones como HEAD^^^, pero en el uso diario pueden tratarse como referencias
  • Una symbolic reference es una referencia que apunta a otra referencia, como HEAD
    • HEAD es un concepto central que influye mucho en cómo se comportan los comandos principales de Git
  • La configuración del remoto en .git/config incluye un refspec
    • Ejemplo: +refs/heads/main:refs/remotes/origin/main
    • Muchas veces se usa tal cual el valor que crean por defecto git clone o git remote add
  • tree-ish se refiere a lo que puede ir en THING dentro de git checkout THING .
    • Un ID de commit
    • Una referencia a commit como main, HEAD^^, v0.3.2
    • Un subdirectorio dentro de un commit, como main:./docs
    • En la práctica, muchas veces basta con entenderlo como “un commit o una referencia a commit”

index, staged, cached

  • index, staged y cached están todos relacionados con .git/index
    • .git/index es el archivo que se usa cuando haces stage de cambios con git add
  • Hay varias expresiones para la misma cosa repartidas entre distintos comandos
    • git diff --cached
    • git rm --cached
    • git diff --staged
    • .git/index
  • Pero las banderas --index y --cached no siempre significan lo mismo
    • Este texto del mantenedor principal de Git, Junio Hamano, explica las diferencias en detalle
  • Por razones de rendimiento, el index también lista archivos untracked, pero por lo general staging area no se entiende como algo que incluya archivos untracked

reset, revert, restore

  • reset, revert y restore son palabras parecidas, pero en Git afectan cosas distintas
  • git revert COMMIT crea un commit nuevo en la rama actual que hace lo contrario de COMMIT
    • Si COMMIT agregó 3 líneas, el nuevo commit elimina esas 3 líneas
  • git reset --hard COMMIT fuerza a que la rama actual vuelva al estado de COMMIT
    • Es una operación muy peligrosa que elimina los cambios nuevos posteriores a COMMIT
  • git restore --source=COMMIT PATH restaura los archivos de PATH al estado que tenían en COMMIT
    • No cambia otros archivos ni el historial de commits
  • git reset --hard y git restore . suelen comportarse de forma parecida si se usan solos, pero git reset --hard COMMIT y git restore --source COMMIT . se comportan de manera completamente distinta

track, remote-tracking branch, untracked files

  • Git usa la palabra track de tres maneras distintas
    • Untracked files: en git status se refiere a archivos que Git no gestiona y que no están incluidos en un commit
    • Una remote-tracking branch como origin/main es una referencia local que guarda el ID del commit al que apuntaba main en el remoto origin en el momento del último git pull o git fetch
    • Se puede configurar que una rama local haga track de una rama remota, como en “branch foo set up to track remote branch bar from origin”
  • Decir que main es una rama que hace track de un remoto y decir que origin/main es una remote-tracking branch no es lo mismo
  • main es una rama real, así que puedes crear commits y hacer merge sobre ella
    • Si en .git/config está configurada para hacer track del main remoto, git pull y git push se vuelven más cómodos de usar
  • origin/main, pese al nombre “remote-tracking branch”, no es una rama normal
    • No puedes hacer commits directamente sobre ella
    • Solo se actualiza cuando traes el estado más reciente de main desde el remoto con git pull o git fetch

checkout, reflog, merge/rebase/cherry-pick

  • git checkout mete dos tareas distintas en un solo comando
    • git checkout BRANCH cambia de rama
    • git checkout file.txt descarta los cambios sin stage de file.txt
  • Para reducir esta confusión, Git separó esas funciones en git switch y git restore, aunque checkout sigue pudiéndose usar
  • reflog significa reference log, y es el registro de a qué apuntó una referencia en el pasado
    • reference es un término amplio que incluye ramas, etiquetas y HEAD
    • El reflog puede ayudarte a salir de situaciones muy malas en Git, como borrar por accidente una rama importante
  • merge, rebase y cherry-pick combinan commits de maneras diferentes
    • merge crea un commit nuevo que une dos ramas
    • rebase copia uno por uno los commits de la rama actual encima de la rama objetivo
    • cherry-pick se parece a rebase, pero con otra sintaxis, y copia commits a la rama actual
  • git rebase --onto main otherbranch mybranch puede usarse para mover solo algunos commits de mybranch encima de main
    • En la estructura de ejemplo, serviría si quisieras rebasear solo F y G sobre main
    • Es una sintaxis difícil de recordar porque incluye tres nombres de ramas

commit y otros términos confusos

  • commit en Git se usa tanto como verbo como como sustantivo
    • Verbo: “haz commit con frecuencia”
    • Sustantivo: el commit más reciente de main
  • Un commit de Git puede verse de tres maneras
    • Como una instantánea del estado actual de todos los archivos
    • Como un diff respecto al commit padre
    • Como el historial de todos los commits anteriores
  • Cada comando trata el commit de forma distinta
    • git show trata el commit como si fuera un diff
    • git log trata el commit como historial
    • git restore trata el commit como una instantánea
  • blob, tree, origin, upstream, downstream, la relación entre fetch y pull, stash, worktree, subtree y submodule también forman parte de la terminología confusa de Git
  • Entre los términos de GitHub, “pull request”, “squash and merge” y “rebase and merge” se consideran casos confusos

Los tres ejes de la confusión repetida

  • La terminología de Git que más confunde puede resumirse en tres puntos
    • head es una rama, y HEAD es la rama actual
    • “remote tracking branch” y “branch that tracks a remote” son cosas diferentes
    • index, staged y cached apuntan todos a la misma cosa
  • the most confusing git terminology de 2012 también habla de cómo la terminología de Git se conecta con la de CVS y Subversion
  • La confusión terminológica de Git no aparece solo en funciones raras, sino que se repite a lo largo de sus funciones centrales
  • Sobre todo al hablar de ramas, “tracking” se usa de varias maneras y al principio es difícil notar las diferencias
  • Algunas explicaciones incluyen rincones poco comunes de Git, así que queda la advertencia de que podría haber errores en algunos detalles

1 comentarios

 
GN⁺ 2023-11-03
Opiniones de Hacker News
  • Me costó memorizar la mayoría de estos términos, pero la clave que hizo que todo encajara fue entender que muchas cosas en Git, al final, son punteros a commits.
    Los nombres de ramas, HEAD y las etiquetas son todos punteros. HEAD apunta al commit que estás viendo en este momento, y un nombre de rama como my-feature apunta al commit más reciente de esa rama. Si haces git checkout -b my-feature desde main, main, my-feature y HEAD terminan apuntando todos al commit más reciente de main.
    Cada vez que haces un commit en my-branch, HEAD y my-branch se mueven para apuntar al nuevo commit. detached HEAD significa que ningún branch apunta al commit al que apunta HEAD. La diferencia entre una etiqueta y una rama es que la etiqueta apunta a un commit específico y no se mueve.
    Otra cosa que me confundía era que muchos comandos parecen inconsistentes porque Git asume argumentos predeterminados. git checkout file.txt es lo mismo que git checkout HEAD -- file.txt, y cuando estás en my-branch, git rebase main es lo mismo que git rebase main my-branch. Aunque esta última forma también se puede ejecutar desde otra rama.
    Por último, cuando todo se enreda, el comando que te permite salir de casi cualquier estado extraño es git reflog. Muestra todos los commits a los que HEAD apuntó. Aun así, me alegra que Git reconozca esta confusión y esté creando comandos con una interfaz menos sorpresiva y más simple.
    • Usando el nombre que Git le da a este concepto, los “punteros a commits” son refs. De ahí viene el nombre reflog.
      Otra cosa que muchas personas que usan Git no tienen muy presente es que las refs de ramas o etiquetas remotas que trajiste también son todas refs, así que puedes referenciarlas en cualquier lugar donde se pueda usar un nombre de ref.
      Por ejemplo, si quieres decir “no me importa qué haya en esta rama; no hagas fast-forward, ni merge, ni rebase, simplemente sobrescribe la rama local con el contenido remoto”, puedes hacer esto: git checkout foo, git reset --hard origin/foo.
    • Para ser precisos, el puntero HEAD no apunta directamente a un commit; normalmente apunta a un puntero de rama como my-branch, y ese puntero de rama apunta al commit. El estado detached HEAD es la excepción.
      Cuando haces un commit en my-branch, no es que HEAD y my-branch se muevan ambos al nuevo commit; HEAD sigue apuntando al puntero my-branch, y solo my-branch se mueve para apuntar al nuevo commit. Claro que, si sigues HEAD a través de my-branch hasta el commit, llegas al nuevo commit.
      detached HEAD es el estado en el que HEAD apunta directamente a un commit en vez de a un puntero de rama. Incluso en detached HEAD, HEAD y un puntero de rama pueden apuntar ambos al commit más reciente. Si miras git log --decorate, suele mostrarse como (HEAD, my-branch) en el commit más reciente, en lugar del habitual (HEAD -> my-branch).
    • Me gusta esta explicación. Aunque una parte aún más confusa con la que uno se topa a veces es que hay dos tipos de etiquetas. La mayoría de las etiquetas son, como se dijo, etiquetas ligeras que apuntan a un objeto commit, y nada más.
      En cambio, las etiquetas anotadas pueden contener un mensaje, una marca de tiempo, un SHA, etc. Son objetos Git propiamente dichos y se comportan de forma bastante parecida a los objetos commit, aunque normalmente siguen referenciando otro objeto Git, por lo general un commit.
    • Si eres excesivamente cuidadoso como yo, también conviene ejecutar git rev-parse HEAD antes de empezar un procedimiento delicado con muchos conflictos o varios movimientos, y copiar esa cadena en un lugar seguro.
      Te da la tranquilidad de haber marcado exactamente el último estado que sabes que estaba bien. Normalmente puedes volver al último estado correcto, no a algún punto varios pasos dentro del caos. Claro, siempre que no hayas usado sin cuidado cosas como git gc o git filter-branch.
    • Esta explicación también muestra bien que la estructura de árbol interna de Git lo domina todo.
      Suena a broma, pero no lo es: no es del todo falso decir que para usar Git realmente necesitas un título en ciencias de la computación. Estoy de acuerdo en que los argumentos predeterminados de Git generan una experiencia de uso muy inconsistente.
      git checkout ., git reset --hard/soft y git cleanup parecen todos muy parecidos, pero en realidad son muy distintos. Aun así, sigo prefiriendo Git antes que Perforce o SVN. Antes me gustaba un poco más Mercurial, aunque no sé si seguiría siendo así hoy.
      git reflog es el rey y muestra la verdad.
  • Hace unos 10 años que Git “ganó” la guerra del control de versiones gracias a otra moda tecnológica sin mucho fundamento, y todavía seguimos teniendo dificultades con tareas que deberían ser triviales.
    Recuerdo haber leído que a Linus Torvalds le sorprendía que la gente empezara a usar Git directamente, sin ponerle encima una capa más amable. Si la industria fuera capaz de hacer autocrítica, admitiría que elegir Git fue un error y se habría pasado a otro sistema de control de versiones. Sin desperdiciar cantidades enormes de tiempo en una herramienta que, al final, solo guarda texto.
    • No veo Git como una herramienta para guardar texto. Es una herramienta para coordinar, con bastante precisión y estabilidad, los cambios que varias personas hacen sobre el mismo “texto”, sin bloquear el avance de nadie. Pruébalo con Word y la diferencia es enorme.
      Claro que podría mejorar. Aun así, siempre me sorprende el odio que recibe Git. Git es una herramienta extraordinaria y está muy por delante de herramientas como Word o Google Docs, hechas para no desarrolladores.
      Quizá sea porque tengo edad suficiente para recordar cuando Subversion era el rey.
    • Totalmente de acuerdo.
      Cada semana veo a compañeros confundirse por Git, veo publicaciones pidiendo ayuda en línea, y vuelvo a ver artículos como este intentando explicar otra vez algo que debería ser simple.
      No recuerdo a gente desperdiciando horas revirtiendo los desastres que habían creado en SVN, TFVC, Perforce, etc., mientras programaban.
      Las herramientas existen para hacer la vida más fácil. Si no lo logran, no valen el tiempo que exigen.
    • Incluso en 2013 no estaba nada claro que Git fuera a ganar. Había bastantes usuarios de darcs, Mercurial, svn e incluso cvs, y las herramientas de esa época normalmente tenían plugins para soportarlos a todos.

Todavía me gustaría que existiera esa diversidad. La monocultura de Git también significa que cualquier intento de reemplazar Git primero tiene que volver a implementar Git. Así que quedamos atados a Git casi para siempre, como con ASCII o la tecla Scroll Lock.

  • Git ganó por buenas razones y claramente era mejor que lo anterior. Hoy quizá esté de moda criticar a Git como a jQuery, pero cuando apareció fue una mejora clara.
  • Hace poco escribí un artículo sobre un problema similar: por qué podríamos quedar atrapados en Git.
    La preocupación central es que GitHub es tan bueno que, a menos que GitHub separe a Git del motor de gestión de texto y permita otros motores, quedaremos atados a Git.
    https://trolololo.xyz/github
    https://news.ycombinator.com/item?id=38098109
  • La terminología de Git parece un caso clínico: muchos términos tienen sentido una vez que ya entiendes cómo funciona, pero casi no tienen sentido si no conoces los detalles de implementación o si los pones junto a otros términos.
    Son términos como abstracciones con fugas.
    • En parte es cierto, pero también se debe a que distintas partes de Git fueron creadas por distintas personas y les pusieron nombres por separado. Linus originalmente lo llamaba cache, que era el término más de ciencias de la computación.
      Luego parece que Junio lo cambió a index, más específico para un sistema de control de versiones distribuido, y la mayoría de los usuarios lo llamaban staging area. Ahora la evolución de ese término quedó fosilizada en la UI y en las partes internas de Git.
    • No es que tenga sentido; es simplemente mala nomenclatura. Poner buenos nombres requiere esfuerzo, y los primeros desarrolladores de Git no lo hicieron.
    • Si imaginas que para el uso básico tuvieras que conocer las partes internas del sistema operativo, del IDE o del compilador, eso en la práctica sería un mal diseño de API.
  • “Your branch is up to date with origin/master” es la mentira más grande que escucho todos los días. Por eso siempre hago simplemente pull.
    • Estrictamente hablando, es verdad. origin/master no es el master que está en origin, sino el commit al que apuntaba el último origin/master conocido. Este valor se actualiza cuando haces fetch, y pull hace fetch automáticamente.
      Si miras ls -l .git/refs/remotes/origin/master, verás que origin/master no es más que un archivo en tu sistema. También puedes ver cuándo cambió. No se actualiza mágicamente.
      Si hubo cambios cuando ejecutaste git fetch origin, cambiarán tanto la marca de tiempo como el contenido. Puedes comprobarlo con cat .git/refs/remotes/origin/master.
      Los fundamentos de Git son muy simples, al punto de que puedes implementar sus estructuras de datos principales y unas cuantas operaciones en un día. Vale mucho la pena saberlo. De alguna manera, Git logró construir una interfaz de usuario muy compleja sobre un núcleo bastante simple.
    • Ese mensaje solo significa que Git no se conecta a internet ni al repositorio remoto para buscar actualizaciones a menos que se lo indiques explícitamente. Esa propiedad en sí me parece deseable. Eso sí, el mensaje podría ser más claro.
    • Debería haber sido algo como “Your branch is up to date with the local copy of origin/master, last updated on XXXX-XX-XX:XX:XX:XX”.
    • Yo elimino la rama local master. Normalmente no puedo hacer push a master, o de todos modos no quiero trabajar directamente en master. Entonces no hay razón para tener una rama local master modificable.
      Así que solo necesito actualizar origin/master, y con fetch basta.
    • git fetch && git pull
      Estoy esperando jubilarme dentro de 3 años y lavarme las manos de esta basura rota.
  • He usado Git prácticamente desde sus inicios, y recién esta semana me enteré de porcelain. Tengo un proyecto que parsea la salida de git status, y agregar la bandera --porcelain ayudó muchísimo. Produce una salida más concisa y fácil de parsear programáticamente.
    Me dio curiosidad saber cuántos comandos más tenían salidas más legibles por máquina, y terminé llegando a la página “Git Internals - Plumbing and Porcelain” de git-scm. En resumen, Git no fue escrito desde el principio tanto como un sistema de control de versiones pulido, sino como una colección de herramientas para manejar control de versiones.
    Muchas personas que usaron Git desde el principio aprendieron tareas de control de versiones con esos comandos de bajo nivel, y propagaron ese flujo de trabajo a otros. Esa es la capa de plumbing. Más tarde Git creó una capa más refinada, a la que llama porcelain.
    Todavía no sé del todo qué comandos pertenecen a qué capa, pero me ayudó a entender los nuevos flujos de trabajo recomendados en los últimos años. También me permite juzgar mejor cuándo cambiar mi propio flujo de trabajo.
    https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Po...
    • Es una señal clara de que Linus estaba satisfecho con la estructura interna, el plumbing, pero consideraba que la UI, el porcelain, necesitaba trabajo. Originalmente todo el porcelain eran scripts que llamaban al plumbing.
      Lamentablemente, para hacerlo más rápido, hardcodearon esa UI, pero no la mejoraron.
  • La voz de Julia al escribir es realmente muy buena. Escribe contenido muy valioso incluso para desarrolladores veteranos, mientras mantiene un tono cercano y no excluyente para quienes recién entran en este campo.
  • Creo que tengo “síndrome de Estocolmo de Git”. Estos términos no me confunden tanto, pero creo que se debe en gran medida a que llevo profundamente atado a Git desde más o menos 2011, casi sin aprender otros sistemas.
    Mirando hacia atrás, al principio seguramente me resultó extremadamente confuso, pero creo que fingía que no para parecer cool.
    • Me di cuenta de que tenía síndrome de Estocolmo después de ver la CLI del sistema de control de versiones Fossil. Era demasiado intuitiva.
    • Antes de usar Git usé cvs y svn, y comparado con svn, Git me resultó mucho más fácil de entender.
    • El único otro control de versiones que he usado es Plastic SCM, y, con síndrome de Estocolmo o no, Git es mucho mejor.
  • Cosas relacionadas para ver: Git staging area es literalmente un término en el que todos están de acuerdo.

https://news.ycombinator.com/item?id=28143078
“Your branch is up to date with ‘origin/main’” en realidad es un poco engañoso. Se puede interpretar como que la rama main está actualizada, pero en realidad no es así.
Aunque tampoco hace falta ponerse demasiado “técnicamente hablando” con esto. ¿No aplica aquí el problema de los dos generales? Si uno se pone realmente meticuloso, no se puede saber si está “actualizado” en este preciso instante. Lo mismo ocurre aunque hagas fetch antes de status.
Entonces, ¿cuál sería una expectativa razonable? Algo así como que la ref en la base de datos de objetos de mi computadora era igual, la última vez que se comprobó, a la ref de otra base de datos de objetos allá lejos.
Una simple llamada a status no puede hacer un fetch de red ni recordarte cada vez los principios básicos de la herramienta que estás usando. Personalmente, así lo veo. Pero, sorprendentemente, muchos comentarios en la respuesta de StackOverflow consideran que hacen falta justamente esas dos cosas.
Una frase como “is up to date with the origin’s main as of your last fetch 5 days ago” sería más razonable, porque solo te dice cuánto tiempo pasó desde tu último fetch.
[1] https://stackoverflow.com/questions/27828404/why-does-git-st...
Otra cosa: pensaba que ORIG_HEAD, igual que FETCH_HEAD, tenía que ver con el “head de origin”. Pero no era así. Esta “pseudoref” parece usarse como punto de guardado antes de reescrituras más complejas como rebase, y se implementó antes de que existiera el reflog. Probablemente signifique “original head”.

  • Soy bastante favorable a Git, pero estoy de acuerdo con el autor respecto a la redacción de ese mensaje. Eso sí, no estoy de acuerdo con la alternativa propuesta.
    “Your branch is up to date with ‘origin/main’” es técnicamente correcto, pero la expresión up to date, leída por encima, sugiere dos cosas: que main es igual a origin/main, y que origin/main también está actualizado; es decir, da la sensación de que se actualizó durante el comando, o que se mantiene actualizado automáticamente y que la sincronización reciente fue exitosa.
    Esto no es una señal legible por máquina que deba ser verdadera durante un ciclo de CPU, sino un mensaje de estado visible para el usuario. No hace falta llegar hasta la teoría de redes para que esa interpretación sea razonable.
    “Up to date” se parece más a estar al día en el tiempo que a una cuestión de espacio. La posición de la rama local se acerca más al espacio de “a dónde apunta esta rama”, mientras que el estado de la ref remota se acerca más al tiempo de “cuándo actualicé por última vez la ref remota”. Claro que esto es muy subjetivo y ambos pueden entenderse en los dos sentidos.
    Una mejor redacción podría ser algo como “Your branch matches origin/main”, “Your branch’s head is the same as origin/main” o “Your branch is pointing to the same commit as origin/main”. Es un compromiso entre claridad y verbosidad. También se podría agregar entre paréntesis, como sugiere el autor, “remote ref last updated 5 days ago”.
  • No estoy de acuerdo con que sea molesto que una llamada a status haga un fetch de red. Creo que las operaciones de red deben ser explícitas, no implícitas. Cuando hago git status, quiero saber el estado de mi repositorio en el sistema de archivos.
    Si quiero saber qué está pasando en otro remoto, puedo hacer fetch yo mismo y luego comparar.
  • Lo que uno espera es obtener información actualizada al momento en que se inicia el comando status. Puede haber una condición de carrera mientras se imprime la información en la terminal, pero es una ventana de tiempo muy pequeña.
    En general, eso significa que se quiere un fetch. El problema de los dos generales solo aplica del lado remoto. Si el remoto no recibe confirmación de que el cliente recibió los datos, puede seguir retransmitiendo durante un tiempo. Ese no es problema del cliente.
    Si el cliente no recibe datos del servidor, el comportamiento correcto sería quedarse esperando y, tras un timeout, imprimir un error; probablemente eso es lo que ya hace fetch.
  • El paso más valioso para aprender Git es tener el modelo mental correcto. Todo es un grafo.
    Esta herramienta se comparte con frecuencia y encaja muy bien aquí. Visualiza el modelo interno de Git y el efecto de varios comandos.
    https://learngitbranching.js.org/
    Aprendí más usando esta herramienta durante 10 minutos que en los casi 10 años anteriores de experiencia con Git. La recomiendo muchísimo.
  • No quiero echar más leña al fuego, pero también es un problema que la gente de Bitbucket haya acuñado el término pull request.
    “pull” es la acción de fusionar cambios remotos en un repositorio local. Lo que el usuario realmente está pidiendo es que el servidor fusione sus cambios remotos en alguna rama. El “merge request” de GitLab es el término correcto.
    He visto a alguien hacer fetch y que desaparecieran commits. Quedaron ocultos porque el repositorio retrocedió en el tiempo. Git oculta esos detalles en status, y si no usas git-prompt o powerline-shell, es como trabajar a oscuras.
    • La idea original que queda en git-request-pull(1) era que todos tuviéramos nuestros propios repositorios Git en lugares como kernel.org/git o redhat.com/git, y pidiéramos por email que otros hicieran pull desde repositorios ubicados en servidores, organizaciones y dominios distintos.
      GitHub se inspiró en el comando request-pull de Git, pero lo reinterpretó como fusionar de un repositorio de GitHub a otro repositorio de GitHub.
    • Desde el punto de vista del servidor, el usuario es el remoto y el servidor es el local. Por eso el usuario le pide al servidor que haga pull desde su lado.
      Al menos yo siempre lo leí así.
    • El libro de Git explica el origen de este término y por qué tiene sentido.
      En resumen, no es una solicitud al servidor, sino a otra persona. Es pedirle a la otra persona que haga pull de tu rama para revisar los cambios con los que quieres contribuir al proyecto.

[0] https://git-scm.com/book/en/v2/Distributed-Git-Contributing-...

  • “pull request” fue popularizado por GitHub, y me parece un término razonable. No es tan interesante la distinción entre si realmente haces pull desde otro repositorio o si haces una “merge request” dentro del mismo repositorio. “merge request” se siente como un término propio de GitLab.
  • Esto siempre me resultó de lo más difícil de entender. Naturalmente, me parece que debería ser una push request o una merge request, no una pull request.