Error de Git al actualizar un repository

Estoy tratando de actualizar mi repository Github.

OS / config : utilizando OS X 10.10.5 (Yosemite) en MacBook Air

Después de hacer estos commands:

$ git init $ git add $ git commit -m "added new stuff" $ git remote add origin https://github.com/user/repo.git $ git push -u origin master 

Tengo este error:

 To https://github.com/user/repo.git ! [rejected] master -> master (fetch first) error: failed to push some refs to 'https://github.com/user/repo.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (eg, 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. 

Entonces lo intenté …

 $ git pull --commit https://github.com/user/repo.git 

Y tengo …

 Merge https://github.com/user/repo # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # Lines starting with '#' will be ignonetworking, and an empty message aborts # the commit. 

Pregunta

¿Qué significan estos errores en inglés? ¿Y qué debo hacer ahora?

¿Hay alguna manera de simplemente "volcar" lo que está en la queue (sin intentar "tirar" de él) para poder continuar con los nuevos commits? Estoy completamente confundido sobre qué hacer a continuación.

Primero, déjame sugerirte que leas el libro de Pro Git , porque la mayoría de la documentation que viene con git es bastante mala, especialmente para los novatos. (Mejorado desde hace más de 5 años, pero todavía deja mucho que desear).

Dicho esto, permítame intentar una introducción rápida a "lo que necesita saber" aquí.

Cosas introductorias

  1. Cuando trabajas con otras personas (incluido github, que se considera "otras personas" aquí), haces que tu git invoque su git a través del teléfono por Internet y exhcange el trabajo. Estas otras personas son iguales , es decir, tienen exactamente la misma capacidad de hacer un nuevo trabajo que tú, al less en el caso general (github no realizará un trabajo nuevo por sí mismo). Lo que esto significa es que durante un intercambio, puede tener cosas que "ellos" (sean quienes sean) no lo hacen, pero también pueden tener cosas que usted no tiene.
  2. Git intercambia trabajo con commits individuales. 1 Exactamente qué compromisos y cómo se vuelven un poco más complicados, así que esperemos un momento.
  3. Lo contrario de git push no es git pull , es en realidad git fetch . Creo que el post de error que recibe no debe referirse directamente a git pull ; veremos más sobre esto un poco también.
  4. Git realiza un seguimiento interno de las confirmaciones mediante sus identidades SHA-1 de "nombre verdadero", que son las cosas largas de 40 caracteres hexadecimales que se ven en la salida de git log , por ejemplo. Cada confirmación tiene un set de confirmaciones "principales" identificadas por las ID de SHA-1. Puede usar identidades SHA-1 usted mismo, pero son extremadamente antipáticas, nunca recordaría si debe comenzar con f13c9ab o 0e1d227 o lo que sea (¡y estas son identificaciones abreviadas !).
  5. Entonces, git le proporciona a usted, el usuario, nombres de twigs como master . Un nombre de sucursal es simplemente un nombre que le indica a git que use para realizar un seguimiento de la confirmación más reciente que haya realizado en esa twig.
  6. El compromiso más reciente tiene, como elemento primario, el compromiso que "solía ser el más nuevo", que tiene un "más reciente" aún más antiguo que el padre, y así sucesivamente. (La forma en que git lo logra es notablemente simple: cuando haces un nuevo compromiso, su padre es "el compromiso actual", y una vez que el compromiso se almacena de manera segura en el repository, git reemplaza el ID almacenado en la sucursal con el ID del nuevo compromiso recién hecho.)

Teniendo en count los últimos tres elementos, dibujemos un fragment de gráfico de compromiso:

 ... <- 1f3a33c <- 98ab102 <-- branch 

Aquí, la punta de la twig es commit 98ab102 y su principal es 1f3a33c . Podemos decir que la branch nombre "apunta a" 98ab102 , que apunta a su padre, y así sucesivamente.

Cuando crea un nuevo repository ( git init , suponiendo que esto realmente lo haga 2 ) está completamente vacío de confirmaciones, por lo que el primer commit no tiene padre. Es el segundo y el tercero y así sucesivamente confirma ese punto a los commits previos.

Cuando haces una "fusión", le dices a git que tome dos (o más, 3 pero digamos dos, por ahora) confirmaciones existentes y crea una nueva confirmación que tenga a ambas como padres, combinando todos los cambios de algunas punto común. Las fusiones no son tan complicadas, pero son algo que generalmente debes hacer después de dividir deliberadamente el trabajo en líneas de desarrollo separadas.

Ahora, de vuelta a search, empujar y tirar

Ha creado un nuevo repository ( git init ), ha puesto al less un commit ( git commit ) y ha añadido un "remote" ( git remote add origin ... ). Este último paso dice "Tengo un git de compañeros al que quiero llamar origin , así que restring la URL bajo ese nombre".

Luego, le pediste a tu git que llamara "origen" ( git push ... origin ) y le dieras tus commits como se encuentra debajo de tu nombre de twig "master" ( git push ... master ). Aquí es donde se vuelve un poco complicado. Cuando tu idiota habla con su git, ¿qué nombre debería usar su git? La respuesta corta aquí es que su git usará el nombre master también. Esto es modificable, pero cambiarlo no es lo que quieres aquí.

(También pediste, a través de la bandera -u , que tu git registre este intercambio en tu configuration de git. Por ahora lo dejaremos de lado).

Cuando tu git llamó a su git, tu git dijo "aquí, mira estos nuevos compromisos shinys" (y lo hizo), y luego tu git dijo: "¿Por qué no agregar estos nuevos commits exactamente como están en tu repository, 4 y haga que su punto master la punta, ¿la mayoría de esos compromisos? " Su respuesta fue: "Bueno, podría hacer eso, pero luego perdería algunos compromisos que tengo que no tiene". Aquí es donde ves el post rejected .

Tal vez quieras que olviden sus cosas … hasta ahora. Si es así, puedes pedir un "empujón de la fuerza", donde tu git les diga que configuren su master incluso si eso "pierde" algunas confirmaciones. Depende de ellos hacer esto, pero a menudo no es lo que quieres.

Tal vez quiera recoger lo que tiene y agregarlo a su colección, o recoger lo que tiene y descartar su propio trabajo hasta ahora. Aquí es donde quieres que git fetch .

Lo que hace git fetch , simplificado tanto como sea posible, 5 es llamar al par sobre el teléfono de Internet y descubrir qué tienen que no. Trae todos estos commits (recuerde, los intercambios pasan por commits) y los agrega, como Borg, a su repository. Entonces, esta es la parte crucial, cambia sus nombres de twig para que no interfieran con sus nombres de twig.

Los nombres que git fetch utiliza para sincronizar con sus pares se denominan "twigs de seguimiento remoto" o, a veces, "sucursales remotas". Una cosa extraña acerca de "sucursales remotas" es que ¡en realidad no están en el control remoto! Están guardados en tu propio repository. La razón es simple: son una instantánea de lo que estaba en el control remoto, la última vez que su git habló con ese control remoto. Después de que los dos gits cuelguen el teléfono de Internet, el control remoto podría cambiarse. (La velocidad con la que realmente cambia un control remoto depende, por supuesto, de cuán ocupado está ese git remoto).

El patrón de cambio de nombre aquí es simple: tome el nombre de la twig del control remoto (como master ) y agregue el nombre del control remoto ( origin ) al frente: su origin/master "rastrea" el master origin . (Hay un formulario de nombre completo que puede usar si accidentalmente nombra uno de sus propios origin/oops por ejemplo, sucursales locales, no de seguimiento remoto, pero la mejor opción es no hacer eso en primer lugar. )

Espera, ¿dónde entra git pull ?

Tenga en count que hasta ahora, ha sido todo git push y git fetch . Pero supongamos que has hecho una git fetch y has recogido su trabajo. Ahora tienes un pequeño problema: tienes tu trabajo, y tienes su trabajo, y estos dos han divergido.

Si ambos comenzaron desde una base común, podemos dibujar su gráfico de compromiso de esta manera:

 ... base <- yours <-- HEAD -> master \ theirs <-- origin/master 

Le puse HEAD -> esta vez para mostrar en qué twig estás (ejecuta el git status y deberías ver "en la twig principal" en su salida).

Una manera fácil de unir estos dos pedazos divergentes de trabajo es usar git merge . Si quieres hacer eso, simplemente ejecuta git merge origin/master (ten en count la barra diagonal: quieres que tu git encuentre tu origin/master , que recogió durante la git fetch , y lo fusiona en tu master , haciendo un nuevo commit en tu master ). El resultado es así:

 ... base <- yours <- merge <-- HEAD -> master \ / theirs <-- origin/master 

Otra forma de manejar esto -normalmente la mejor manera, de hecho- es usar git rebase , que no entraré en detalle aquí; hay muchas respuestas sobre StackOverflow sobre el uso de rebase . Si lo haces, terminas con:

 ... base <- theirs <- yours <-- HEAD -> master \ .......... <-- origin/master 

(Tenga en count que en todos los casos, el origin/master aún apunta a la confirmación de la "mayoría de sus").

El punto principal a tener en count en este momento es que hagas lo que hagas, si quieres que su git acepte tus commits sin forzarlo, debes hacer que tu trabajo sea un complemento al de ellos, para que tu los nuevos commits "apuntan hacia" el suyo. No importa el process de push si su trabajo tiene el suyo como un "segundo padre" de una confirmación de fusión, o simplemente crea directamente sobre su (s) compromiso (s); solo necesita apuntar a sus commits, por sus identificadores de commit. (Pero, de nuevo, ¡rebase suele ser mejor que fusionarse!)

Entonces, git pull (¡finalmente!) …

Lo que hace git pull , simplificado, es simplemente ejecutar git fetch y luego git merge . En resumen, se trata de un script de conveniencia: siempre está buscando y luego fusionándose, por lo que le daremos un script que recuperará y luego se fusionará.

Por supuesto, la git merge suele ser incorrecta. Realmente debería usar git rebase por defecto.

Puedes hacer que git pull use git rebase , 6 pero creo que es más git rebase , al less (o especialmente) para los novatos, usar los dos pasos por separado, en parte porque si algo sale mal, la forma en que te recuperas de esto es diferente para las dos acciones diferentes. Para salir de una fusión fallida, usa git merge --abort . Para salir de una rebase fallida, usas git rebase --abort . (Esto solía ser aún más diferente, ahora solo es "abortar lo que está fallando", lo cual es una gran mejora. Pero necesita saber qué hacer, y eso es muchísimo más claro si comenzó con git merge o git rebase ).

La línea de background

Al final, la acción que debe realizar aquí depende de lo que desea que suceda y de lo que el control remoto le permitirá hacer. Si quieres soltar sus cosas, usa git push -f (force), siendo consciente de que las estás causando (sean quienes sean) duela de esta manera, y que pueden prohibirlo por completo. Si quieres conservar sus cosas, primero usa git fetch y luego guarda sus cosas como prefieras (fusionar, rebase, rehacer, lo que sea).


1 O con parches, que puede intercambiar con sus compañeros por correo electrónico. También es posible agrupar confirmaciones y transferirlas por otros methods. Pero en este caso estamos haciendo intercambios basados ​​en commits a través del teléfono de Internet.

2 Puede ejecutar git init manera segura en un repository existente. Tiene un efecto menor, pero para nuestros propósitos aquí básicamente no hace nada, de ahí la necesidad de decir "suponiendo que realmente lo haga".

3 Git llama a esto una combinación de "pulpo", incluso si solo hay 3 o 4 padres en lugar de 8.

4 Git casi siempre solo agrega "más cosas". Me gusta referirme a esto como el "Git Borg" , donde git agrega su distinción tecnológica a su colección existente.

5 Un tema común en git es "¿No era exactamente lo que querías? De acuerdo, saveemos las cosas existentes pero las haremos más complicadas para que puedas hacer lo que quieras también".

6 Véase la nota a pie de página 5.

Esta respuesta SO sugiere:

 git fetch --all git reset --hard origin/master 

Pero aún no lo he probado, así que no puedo decir con certeza si resuelve el problema. Pero es, al less, una dirección para intentar.

GIT te dice que busques primero. Puedes ver en el logging

 $ git fetch -all 

Probablemente alguien más haya empujado a dominarlo, y tu compromiso está atrasado. Por lo tanto, debe search, fusionar el set de cambios y luego podrá volver a presionar.

Si dice que hay cambios en el control remoto, realice una extracción que actualizará su directory de trabajo.

 $ git pull 

Luego empujas tus cambios al control remoto

 $ git push -u origin master 

Espero que esto te ayude a impulsar tus cambios al maestro