Agregue commits antes de la confirmación de root en Git?

Nueva pregunta

Dos preguntas:

  1. Estoy tratando de poner una confirmación antes de que TODOS se comprometan.
    La confirmación inferior tiene 660fb2a76211f36ec9a67d0454a90eab469e9fd0 como SHA. Cuando git rebase -i 660fb2a76211f36ec9a67d0454a90eab469e9fd0 cada confirmación, pero la última aparece en la list.
    Realmente necesito este compromiso para aparecer, así que puedo poner el primer compromiso como el último!

  2. Cuando pongo el primer commit como primero en la list (es decir, segundo commit en total, porque el primero no está en la list como se mencionó anteriormente) me sale un error: error: could not apply b722c76... v1.4.3 BEAT release
    ¡Simplemente lo corté del final de la list y lo puse en la cima! ¡No cambié el número!
    También intenté esto varias veces. El mismo resultado.

Eso es todo hasta ahora. Si tiene preguntas, ¡adelante y pregunte!

Pregunta original

Acabo de descubrir viejas copys de security de mi proyecto. Estas copys de security se crearon antes de usar git.
Ahora me gustaría agregarlos a mi repository como commits antiguos. Eso significaría que tengo que poner estos commit en frente de todos los commits.

Ahora hay varios problemas con esto:

  1. ¿Cómo, en general, pongo una confirmación antes que otras?
  2. ¿Cómo podría hacer esto rápido? (Tengo muchas copys de security!)
  3. ¿Cómo configuro una date para estas confirmaciones "antiguas" ? (¡Sé las dates de las copys de security!)

Si algo no está claro, por favor mencionarlo. ¡Solucionaré el problema entonces!

Una última cosa:

Lo publiqué en GitHub. Y utilicé principalmente su software para comprometer compromisos. Entonces, ¿cómo puedo volver a enviar esto a GitHub?

Actualizar

Encontré otra manera, un poco más simple de hacer esto, usando la bandera --root de git rebase . Lo probé con un repository mío, así que sé que funciona (al less para una historia completamente lineal , más sobre eso al final).

Paso 1: crea una copy de respaldo de tu repos

Vamos a jugar seguro y hacer una copy de security, en caso de que terminemos haciendo algo desastroso y perdiendo sus datos:

 git clone original-repo backup-repo 

Paso 2: crea una twig huérfana (esta será tu nueva raíz)

Verifica la sucursal huérfana. Especificar una confirmación / bifurcación de punto de inicio es opcional, si deja ese argumento fuera, entonces Git utilizará por defecto su confirmación actual como punto de inicio (sigue el patrón de la syntax de bifurcación estándar):

 git checkout --orphan new-master firstCommitOfOldMaster 

Especifiqué la raíz del antiguo maestro como punto de inicio, porque probablemente hará que el siguiente paso sea más rápido (eliminando los files del directory de trabajo).

Paso 3: eliminar los files del directory de trabajo

La creación de la twig huérfana new-master de su antiguo maestro podría dejar atrás los files en su directory e índice de trabajo, dependiendo de cuál era el estado de los files en la confirmación de la cual participó:

El índice y el tree de trabajo se ajustan como si previamente hubiera ejecutado git checkout <start_point> . Esto le permite iniciar un nuevo historial que registra un set de routes similares a <start_point> ejecutando git commit -a para realizar la confirmación de raíz. – Documentos de pago de git

Lo que querrás hacer ahora es borrar por completo el estado de la twig, para que realmente comiences de nuevo desde cero (ejecuta desde la carpeta de nivel superior):

 git rm -rf . 

Esta es la explicación de los documentos:

Si desea iniciar un historial desconectado que registra un set de routes que es totalmente diferente de la de <start_point> , entonces debe borrar el índice y el tree de trabajo inmediatamente después de crear la twig huérfana ejecutando git rm -rf . desde el nivel superior del tree de trabajo. Después, estará listo para preparar sus nuevos files, repoblar el tree de trabajo, copyrlos de otro lugar, extraer un tarball, etc.

Paso 4: vuelva a enviar el trabajo anterior a new-master

Ahora querrá comenzar a comprometer su trabajo anterior en el new-master . Cuando termines, volverás a ubicar tu antiguo maestro en la parte superior.

No estoy exactamente seguro de cómo están organizadas las carpetas de respaldo, pero supongo que cada una de ellas es solo una copy dateda de la carpeta de su proyecto, nombrada en YYYY-MM-DD , por ejemplo, 2013-01-30 . Puede agregar los contenidos de cada carpeta como una nueva confirmación manualmente, o puede escribir una secuencia de commands para automatizar el process.

Supongamos que tiene todas sus carpetas de respaldo en una carpeta superior llamada backup que se encuentra en el mismo directory que la carpeta principal del proyecto. Luego, aquí hay un pseudocódigo para una secuencia de commands para automatizar el process de confirmación de cada carpeta:

 # Get backups and sort them from oldest to newest backups = open("backups").toList().sort("date ascending") for each (backup in backups) copy files from backup to project folder execute `git add "*"` execute `git commit --date="#{backup.date}" --message="#{backup.date}"` 

El script anterior solo agregará y modificará files entre commits. Si cualquiera de sus copys de security elimina, mueve o cambia el nombre de los files, el script no registrará eso. Tendrá que escribir un script más inteligente para hacer eso (tal vez algo que haga uso de git diff u otra herramienta diferente) o grabar esos cambios manualmente.

Paso 5: rebase el antiguo master en el new-master

¡HE AQUÍ EL IMPRESIONANTE PODER QUE ES GIT! ¡Ahora vamos a REESCRIBIR TU HISTORIA COMPLETA! Recita estas arcanas palabras de poder y observa cómo sucede la magia !:

 git rebase --onto new-master --root master 

TA-DA! Puede que tenga que resolver conflictos entre la última confirmación de new-master y la primera confirmación de master , pero aparte de eso, ¡debería ser!

El indicador --root to rebase soluciona el problema que teníamos antes sobre el hecho de que, normalmente, rebase no funcionará en la primera confirmación (raíz) de un repository de Git. La bandera --root básicamente le dice a Git que la incluya en la rebase :

Rebase todos los commits accesibles desde <branch> , en lugar de limitarlos con un <upstream> . Esto le permite volver a establecer la base de la (s) confirmación (es) raíz (es) en una twig. Cuando se utiliza con --onto , omitirá los cambios que ya están contenidos en <newbase> (en lugar de <upstream> ) mientras que sin --onto funcionará en cada cambio. – Rebase docs

Paso 6: verifica que la confirmación final sigue siendo la misma

Solo para asegurarnos de no desorderar el código, querremos comparar el estado actual y final del master con su estado antes de hacer la rebase . Cualquiera de los siguientes commands funcionará (son idénticos). Mientras estás en la twig master :

 git diff orig_head # "Original" head git diff master@{1} # Master at its 1st prior position 

Si no obtienes salida del diff , significa que el estado final de tu master rebasado es idéntico a lo que era antes de la rebase . ¡Buen trabajo!

NOTA: no estoy seguro de qué ocurre con las asignaciones de fusión …

Ahora los pasos anteriores funcionarán bien si tienes un historial perfectamente lineal , es decir, no tienes ningún commit de fusión. No estoy seguro de si funcionará si lo hace. En mi respuesta anterior a continuación, mencioné que usar el --preserve-merges con rebase podría ayudarlo a mantener esas fusiones, pero los documentos mencionan que ese indicador también interactúa con los --onto y --root :

Cuando [ --root es] utilizado junto con --onto y --preserve-merges , todas las confirmaciones de raíz se reescribirán para tener <newbase> como principal en su lugar. – Rebase docs

No estoy exactamente seguro de lo que eso significa en este momento … Podría tener que probarlo y ver qué pasa. ¿Significa que si tienes más de 1 confirmación raíz (como 10, por ejemplo), entonces 9 de esas confirmaciones raíz terminarán siendo reorderadas en la última que actúa como la nueva raíz? Eso no parece el comportamiento que quisiéramos. Solo queremos preservar las confluencias de fusión para que una raíz se vuelva a basar en otra.


Respuesta anterior

MGA tuvo la idea correcta con rebase . No estoy seguro de si esto solucionará tu problema, pero tal vez necesites hacer una nueva confirmación de raíz en tu repository, agregar tus files de copy de security como nuevos commits encima, y ​​luego networkingistribuir tu antiguo gráfico de commit en la parte superior.

Por ejemplo, el git checkout tiene una bandera --orphan según la documentation :

--orphan <new_branch>
Cree una nueva sucursal huérfana, denominada <new_branch> , iniciada desde <start_point> y cambie a ella. El primer compromiso realizado en esta nueva twig no tendrá padres y será la raíz de una nueva historia totalmente desconectada de todas las otras twigs y compromisos.

Entonces quizás puedas probar

 git checkout --orphan <temp_branch> 

Luego, envíe sus files de respaldo a él. Luego, con temp_branch desprotegido, hazlo

 git cherry-pick <first commit from master> git rebase --onto temp_branch <first commit from master> master 

Creo que probablemente necesites cherry-pick el primer commit porque el segundo argumento para rebase --onto es la antigua base de la twig que quieres volver a establecer (en este caso, master ), y la base anterior no está incluida. Así que es por eso que creo que debes cherry-pick para getlo, ya que no tiene una base de compromiso, por lo que no puedes especificar uno en la base de rebase .

También tenga en count que si su historial de compromisos no es lineal (es decir, tiene compromisos de fusión), entonces la rebase normalmente no los conservará. Tiene una bandera --preserve-merges , pero nunca la he usado antes, así que no estoy seguro de cómo funcionará. De los documentos :

-p
--preserve-merges
En lugar de ignorar las fusiones, intente recrearlas.

Esto utiliza la maquinaria --interactive internamente, pero combinarla con la opción --interactive explícita generalmente no es una buena idea a less que sepa lo que está haciendo (consulte los ERRORES a continuación).

Entonces, ¿quizás todo eso funcionará?

1) Puedes usar git rebase . En este caso, podrías hacer lo siguiente:

Lo primero es lo primero, cometer los cambios anteriores. Entonces:

 $ git rebase --interactive master 

Esto abrirá un file con sus confirmaciones en un editor de text. Simplemente cambie el order de los commits (corte / pegue sus últimos commits para ser los primeros, incluido el command "pick" a la izquierda), guarde y cierre el editor. En este punto comenzará la rebase. Para continuar cuando le soliciten confirmación, escriba:

 $ git rebase --continue 

Hasta que todo esté hecho. Más información aquí .

2) No conozco ningún método para hacerlo más rápido, pero ya debería ser bastante rápido.

3) Para cambiar la date de una confirmación, debe cambiar GIT_AUTHOR_DATE y GIT_COMMITTER_DATE. Para esto, hay un bonito ejemplo en la respuesta aceptada para esta pregunta de StackOverflow .

¡Espero eso ayude!